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 Janusz 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)
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 		{
512 			bool hit = (_sprK1->_seqPtr + _sprK2->_seqPtr + _sprK3->_seqPtr == 15);
513 			if (hit) {
514 				if (spr->_ref == 1) {
515 					_commandHandler->addCommand(kCmdSay,       1, 20003, NULL);       // hurray!
516 					_commandHandler->addCommand(kCmdSeq,   20011,     2, NULL);       // Camera away
517 					_commandHandler->addCommand(kCmdSend,  20701,    -1, NULL);       // move dice1 to scene -1
518 					_commandHandler->addCommand(kCmdSend,  20702,    -1, NULL);       // move dice2 to scene -1
519 					_commandHandler->addCommand(kCmdSend,  20703,    -1, NULL);       // move dice3 to scene -1
520 					_commandHandler->addCommand(kCmdSend,  20700,    -1, NULL);       // move TV to scene -1
521 					_commandHandler->addCommand(kCmdKeep,  20007,     0, NULL);       // to pocket
522 					_commandHandler->addCommand(kCmdSend,  20006,    20, NULL);       // Move Coin to scene 20
523 					_commandHandler->addCommand(kCmdSound, 20006, 20002, NULL);       // Play Coin sound
524 					_commandHandler->addCommand(kCmdSay,   20002, 20004, NULL);	      // Say "Luck guy..."
525 					_commandHandler->addCommand(kCmdSend,  20010,    20, NULL);       // Move Paper to scene 20
526 					_commandHandler->addCommand(kCmdSound, 20010, 20003, NULL);       // Play "ksh" sound! (fx20003.wav)
527 					_commandHandler->addCommand(kCmdSay,   20001, 20005, NULL);       // Say "Congratulations"
528 					_game = false;
529 					return;
530 				} else {
531 					_sprK3->step(newRandom(5));
532 				}
533 			}
534 		}
535 
536 		if (_gameCase2Cpt < 100) {
537 			switch (_gameCase2Cpt) {
538 			case 15:
539 				// Give hint about ALTered dice
540 				_commandHandler->addCommand(kCmdSay, 20003, 20021, NULL);
541 				break;
542 			case 30:
543 			case 45:
544 			case 60:
545 			case 75:
546 				// Tell to use ALT key
547 				_commandHandler->addCommand(kCmdSay, 20003, 20022, NULL);
548 				break;
549 			default:
550 				break;
551 			}
552 			_gameCase2Cpt++;
553 		}
554 
555 		switch (spr->_ref) {
556 		case 1:
557 			_commandHandler->addCommand(kCmdSay,   20001, 20011, NULL);        // Say "It'a my turn"
558 			_commandHandler->addCommand(kCmdSeq,   20001,     1, NULL);        // Throw dice
559 			_commandHandler->addCommand(kCmdWait,  20001,     1, NULL);        // wait
560 			_commandHandler->addCommand(kCmdSetZ,  20700,     2, NULL);        // hide dice
561 			_commandHandler->addCommand(kCmdHide,  20007,     1, NULL);        // hide dice
562 			_commandHandler->addCommand(kCmdWait,  20001,    16, NULL);        // wait
563 			_commandHandler->addCommand(kCmdSeq,   20007,     1, NULL);        // Start dice animation (20kosci)
564 			_commandHandler->addCommand(kCmdHide,  20007,     0, NULL);        // unhide
565 			_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL);        // Play Dice sound
566 			_commandHandler->addCommand(kCmdWait,  20007,    -1, NULL);        // the end
567 			_commandHandler->addCommand(kCmdGame,  20001,     2, NULL);        // again!
568 			break;
569 
570 		case 20001:
571 			_commandHandler->addCommand(kCmdSay,   20002, 20012, NULL);        // Say "Now it's mine"
572 			_commandHandler->addCommand(kCmdSeq,   20002,     1, NULL);        // Throw dice
573 			_commandHandler->addCommand(kCmdWait,  20002,     3, NULL);        // wait
574 			_commandHandler->addCommand(kCmdSetZ,  20700,     2, NULL);        // hide dice
575 			_commandHandler->addCommand(kCmdHide,  20007,     1, NULL);        // hide dice
576 			_commandHandler->addCommand(kCmdWait,  20002,    10, NULL);        // wait
577 			_commandHandler->addCommand(kCmdSeq,   20007,     2, NULL);        // Start dice animation (20kosci)
578 			_commandHandler->addCommand(kCmdHide,  20007,     0, NULL);        // unhide
579 			_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL);        // Play Dice sound
580 			_commandHandler->addCommand(kCmdWait,  20007,    -1, NULL);        // the end
581 			_commandHandler->addCommand(kCmdGame,  20002,     2, NULL);        // again!
582 			break;
583 
584 		case 20002:
585 			_commandHandler->addCommand(kCmdSay,   20002, 20010, NULL);        // "Roll the bones!"
586 			_commandHandler->addCommand(kCmdWalk,  20005,    -1, NULL);        // Walk to table
587 			_commandHandler->addCommand(kCmdWait,      1,    -1, NULL);        // Wait
588 			_commandHandler->addCommand(kCmdCover,     1, 20101, NULL);        // grasol ??
589 			_commandHandler->addCommand(kCmdSeq,   20101,     1, NULL);        // Start Chief animation (20solgra)
590 			_commandHandler->addCommand(kCmdWait,  20101,     5, NULL);        // Wait
591 			_commandHandler->addCommand(kCmdSetZ,  20700,     2, NULL);        // Hide dice
592 			_commandHandler->addCommand(kCmdHide,  20007,     1, NULL);        // Hide dice
593 			_commandHandler->addCommand(kCmdWait,  20101,    15, NULL);        // wait
594 			_commandHandler->addCommand(kCmdSeq,   20007,     1, NULL);        // Start dice animation (20kosci)
595 			_commandHandler->addCommand(kCmdHide,  20007,     0, NULL);        // Unhide
596 			_commandHandler->addCommand(kCmdSound, 20007, 20001, NULL);        // Play Dice sound
597 			_commandHandler->addCommand(kCmdWait,  20101,    -1, NULL);        // the end
598 			_commandHandler->addCommand(kCmdUncover,   1, 20101, NULL);        // SDS ??
599 			_commandHandler->addCommand(kCmdGame,      1,     2, NULL);        // again!
600 			break;
601 
602 		default:
603 			break;
604 		}
605 
606 	default:
607 		break;
608 	}
609 }
610 
611 void CGEEngine::expandSprite(Sprite *spr) {
612 	debugC(5, kCGEDebugEngine, "CGEEngine::expandSprite(spr)");
613 
614 	if (spr)
615 		_vga->_showQ->insert(_vga->_spareQ->remove(spr));
616 }
617 
618 void CGEEngine::contractSprite(Sprite *spr) {
619 	debugC(1, kCGEDebugEngine, "CGEEngine::contractSprite(spr)");
620 
621 	if (spr)
622 		_vga->_spareQ->append(_vga->_showQ->remove(spr));
623 }
624 
625 /**
626  * Check if an item is in the inventory, and returns its position
627  * @param spr			Sprite pointer
628  * @return -1			if not found, else index.
629  */
630 int CGEEngine::findPocket(Sprite *spr) {
631 	debugC(1, kCGEDebugEngine, "CGEEngine::findPocket(spr)");
632 
633 	for (int i = 0; i < kPocketNX; i++)
634 		if (_pocket[i] == spr)
635 			return i;
636 	return -1;
637 }
638 
639 /**
640  * Check if an item is in the inventory, and returns its position
641  * @param Inventory slot number		Sprite pointer
642  */
643 void CGEEngine::selectPocket(int n) {
644 	debugC(1, kCGEDebugEngine, "CGEEngine::selectPocket(%d)", n);
645 
646 	if (n < 0 || (_pocLight->_seqPtr && _pocPtr == n)) {
647 		// If no slot specified, or another slot already selected
648 		// stop the blinking animation
649 		_pocLight->step(0);
650 		n = findPocket(NULL);
651 		if (n >= 0)
652 			_pocPtr = n;
653 	} else {
654 		// If slot specified, check if the slot if used.
655 		// Is so, start the blinking animation
656 		if (_pocket[n] != NULL) {
657 			_pocPtr = n;
658 			_pocLight->step(1);
659 		}
660 	}
661 	_pocLight->gotoxy(kPocketX + _pocPtr * kPocketDX + kPocketSX, kPocketY + kPocketSY);
662 }
663 
664 /**
665  * Logic used when all the inventory slots are full and the user tries to pick
666  * another object.
667  * @param Inventory slot number		Sprite pointer
668  */
669 void CGEEngine::pocFul() {
670 	debugC(1, kCGEDebugEngine, "CGEEngine::pocFul()");
671 
672 	if (!_hero)
673 		error("pocFul - Unexpected null _hero");
674 
675 	_hero->park();
676 	_commandHandler->addCommand(kCmdWait, -1, -1, _hero);
677 	_commandHandler->addCommand(kCmdSeq, -1, kSeqPocketFull, _hero);
678 	_commandHandler->addCommand(kCmdSound, -1, 2, _hero); // Play the 'hum-hum" sound (fx00002)
679 	_commandHandler->addCommand(kCmdWait, -1, -1, _hero);
680 	_commandHandler->addCommand(kCmdSay,  1, kPocketFull, _hero);
681 }
682 
683 void CGEEngine::hide1(Sprite *spr) {
684 	debugC(1, kCGEDebugEngine, "CGEEngine::hide1(spr)");
685 
686 	_commandHandlerTurbo->addCommand(kCmdGhost, -1, 0, spr->ghost());
687 }
688 
689 void CGEEngine::snGhost(Bitmap *bmp) {
690 	debugC(1, kCGEDebugEngine, "CGEEngine::snGhost(bmp)");
691 
692 	bmp->hide(bmp->_map & 0xFFFF, bmp->_map >> 16);
693 	bmp->_m = NULL;
694 	bmp->_map = 0;
695 	delete bmp;
696 }
697 
698 void CGEEngine::feedSnail(Sprite *spr, SnList snq) {
699 	debugC(1, kCGEDebugEngine, "CGEEngine::feedSnail(spr, snq)");
700 
701 	if (!spr || !spr->active())
702 		return;
703 
704 	uint8 ptr = (snq == kTake) ? spr->_takePtr : spr->_nearPtr;
705 
706 	if (ptr == kNoPtr)
707 		return;
708 
709 	CommandHandler::Command *comtab = spr->snList(snq);
710 	CommandHandler::Command *c = comtab + ptr;
711 
712 	if (findPocket(NULL) < 0) {                 // no empty pockets?
713 		CommandHandler::Command *p;
714 		for (p = c; p->_commandType != kCmdNext; p++) {     // find KEEP command
715 			if (p->_commandType == kCmdKeep) {
716 				pocFul();
717 				return;
718 			}
719 			if (p->_spritePtr)
720 				break;
721 		}
722 	}
723 	while (true) {
724 		if (c->_commandType == kCmdTalk) {
725 			if ((_commandHandler->_talkEnable = (c->_val != 0)) == false)
726 				killText();
727 		}
728 		if (c->_commandType == kCmdNext) {
729 			Sprite *s = (c->_ref < 0) ? spr : locate(c->_ref);
730 			if (s) {
731 				uint8 *idx = (snq == kTake) ? &s->_takePtr : &s->_nearPtr;
732 				if (*idx != kNoPtr) {
733 					int v;
734 					switch (c->_val) {
735 					case -1 :
736 						v = c - comtab + 1;
737 						break;
738 					case -2 :
739 						v = c - comtab;
740 						break;
741 					case -3 :
742 						v = -1;
743 						break;
744 					default :
745 						v = c->_val;
746 						break;
747 					}
748 					if (v >= 0)
749 						*idx = v;
750 				}
751 			}
752 			if (s == spr)
753 				break;
754 		}
755 		if (c->_commandType == kCmdIf) {
756 			Sprite *s = (c->_ref < 0) ? spr : locate(c->_ref);
757 			if (s) { // sprite extsts
758 				if (! s->seqTest(-1))
759 					c = comtab + c->_val;                // not parked
760 				else
761 					++c;
762 			} else
763 				++c;
764 		} else {
765 			_commandHandler->addCommand(c->_commandType, c->_ref, c->_val, spr);
766 			if (c->_spritePtr)
767 				break;
768 			else
769 				c++;
770 		}
771 	}
772 }
773 
774 void CGEEngine::snNNext(Sprite *spr, int p) {
775 	debugC(1, kCGEDebugEngine, "CGEEngine::snNNext(spr, %d)", p);
776 
777 	if (spr)
778 		if (spr->_nearPtr != kNoPtr)
779 			spr->_nearPtr = p;
780 }
781 
782 void CGEEngine::snTNext(Sprite *spr, int p) {
783 	debugC(1, kCGEDebugEngine, "CGEEngine::snTNext(spr, %d)", p);
784 
785 	if (spr)
786 		if (spr->_takePtr != kNoPtr)
787 			spr->_takePtr = p;
788 }
789 
790 void CGEEngine::snRNNext(Sprite *spr, int p) {
791 	debugC(1, kCGEDebugEngine, "CGEEngine::snRNNext(spr, %d)", p);
792 
793 	if (spr)
794 		if (spr->_nearPtr != kNoPtr)
795 			spr->_nearPtr += p;
796 }
797 
798 
799 void CGEEngine::snRTNext(Sprite *spr, int p) {
800 	debugC(1, kCGEDebugEngine, "CGEEngine::snRTNext(spr, %d)", p);
801 
802 	if (spr)
803 		if (spr->_takePtr != kNoPtr)
804 			spr->_takePtr += p;
805 }
806 
807 void CGEEngine::snZTrim(Sprite *spr) {
808 	debugC(4, kCGEDebugEngine, "CGEEngine::snZTrim(spr)");
809 
810 	if (!spr || !spr->active())
811 		return;
812 
813 	Sprite *s = (spr->_flags._shad) ? spr->_prev : NULL;
814 	_vga->_showQ->insert(_vga->_showQ->remove(spr));
815 	if (s) {
816 		s->_z = spr->_z;
817 		_vga->_showQ->insert(_vga->_showQ->remove(s), spr);
818 	}
819 }
820 
821 void CGEEngine::snHide(Sprite *spr, int val) {
822 	debugC(1, kCGEDebugEngine, "CGEEngine::snHide(spr, %d)", val);
823 
824 	if (spr) {
825 		spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide);
826 		if (spr->_flags._shad)
827 			spr->_prev->_flags._hide = spr->_flags._hide;
828 	}
829 }
830 
831 void CGEEngine::snRmNear(Sprite *spr) {
832 	debugC(1, kCGEDebugEngine, "CGEEngine::snRmNear(spr)");
833 
834 	if (spr)
835 		spr->_nearPtr = kNoPtr;
836 }
837 
838 void CGEEngine::snRmTake(Sprite *spr) {
839 	debugC(1, kCGEDebugEngine, "CGEEngine::snRmTake(spr)");
840 
841 	if (spr)
842 		spr->_takePtr = kNoPtr;
843 }
844 
845 void CGEEngine::snSeq(Sprite *spr, int val) {
846 	debugC(1, kCGEDebugEngine, "CGEEngine::snSeq(spr, %d)", val);
847 
848 	if (spr) {
849 		if (spr == _hero && val == 0)
850 			_hero->park();
851 		else
852 			spr->step(val);
853 	}
854 }
855 
856 void CGEEngine::snRSeq(Sprite *spr, int val) {
857 	debugC(1, kCGEDebugEngine, "CGEEngine::snRSeq(spr, %d)", val);
858 
859 	if (spr)
860 		snSeq(spr, spr->_seqPtr + val);
861 }
862 
863 void CGEEngine::snSend(Sprite *spr, int val) {
864 	debugC(1, kCGEDebugEngine, "CGEEngine::snSend(spr, %d)", val);
865 
866 	if (!spr)
867 		return;
868 
869 	int was = spr->_scene;
870 	bool was1 = (was == 0 || was == _now);
871 	bool val1 = (val == 0 || val == _now);
872 	spr->_scene = val;
873 	if (val1 != was1) {
874 		if (was1) {
875 			if (spr->_flags._kept) {
876 				int n = findPocket(spr);
877 				if (n >= 0)
878 					_pocket[n] = NULL;
879 			}
880 			hide1(spr);
881 			contractSprite(spr);
882 			spr->_flags._slav = false;
883 		} else {
884 			if (spr->_ref % 1000 == 0)
885 				_bitmapPalette = _vga->_sysPal;
886 			if (spr->_flags._back)
887 				spr->backShow(true);
888 			else
889 				expandSprite(spr);
890 			_bitmapPalette = NULL;
891 		}
892 	}
893 }
894 
895 void CGEEngine::snSwap(Sprite *spr, int xref) {
896 	debugC(1, kCGEDebugEngine, "CGEEngine::snSwap(spr, %d)", xref);
897 
898 	Sprite *xspr = locate(xref);
899 	if (!spr || !xspr)
900 		return;
901 
902 	int was = spr->_scene;
903 	int xwas = xspr->_scene;
904 	bool was1 = (was == 0 || was == _now);
905 	bool xwas1 = (xwas == 0 || xwas == _now);
906 
907 	SWAP(spr->_scene, xspr->_scene);
908 	SWAP(spr->_x, xspr->_x);
909 	SWAP(spr->_y, xspr->_y);
910 	SWAP(spr->_z, xspr->_z);
911 	if (spr->_flags._kept) {
912 		int n = findPocket(spr);
913 		if (n >= 0)
914 			_pocket[n] = xspr;
915 		xspr->_flags._kept = true;
916 		xspr->_flags._port = false;
917 	}
918 	if (xwas1 != was1) {
919 		if (was1) {
920 			hide1(spr);
921 			contractSprite(spr);
922 		} else
923 			expandSprite(spr);
924 		if (xwas1) {
925 			hide1(xspr);
926 			contractSprite(xspr);
927 		} else
928 			expandSprite(xspr);
929 	}
930 }
931 
932 void CGEEngine::snCover(Sprite *spr, int xref) {
933 	debugC(1, kCGEDebugEngine, "CGEEngine::snCover(spr, %d)", xref);
934 
935 	Sprite *xspr = locate(xref);
936 	if (!spr || !xspr)
937 		return;
938 
939 	spr->_flags._hide = true;
940 	xspr->_z = spr->_z;
941 	xspr->_scene = spr->_scene;
942 	xspr->gotoxy(spr->_x, spr->_y);
943 	expandSprite(xspr);
944 	if ((xspr->_flags._shad = spr->_flags._shad) == 1) {
945 		_vga->_showQ->insert(_vga->_showQ->remove(spr->_prev), xspr);
946 		spr->_flags._shad = false;
947 	}
948 	feedSnail(xspr, kNear);
949 }
950 
951 void CGEEngine::snUncover(Sprite *spr, Sprite *xspr) {
952 	debugC(1, kCGEDebugEngine, "CGEEngine::snUncover(spr, xspr)");
953 
954 	if (!spr || !xspr)
955 		return;
956 
957 	spr->_flags._hide = false;
958 	spr->_scene = xspr->_scene;
959 	spr->gotoxy(xspr->_x, xspr->_y);
960 	if ((spr->_flags._shad = xspr->_flags._shad) == 1) {
961 		_vga->_showQ->insert(_vga->_showQ->remove(xspr->_prev), spr);
962 		xspr->_flags._shad = false;
963 	}
964 	spr->_z = xspr->_z;
965 	snSend(xspr, -1);
966 	if (spr->_time == 0)
967 		spr->_time++;
968 }
969 
970 void CGEEngine::snSetX0(int scene, int x0) {
971 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetX0(%d, %d)", scene, x0);
972 
973 	_heroXY[scene - 1].x = x0;
974 }
975 
976 void CGEEngine::snSetY0(int scene, int y0) {
977 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetY0(%d, %d)", scene, y0);
978 
979 	_heroXY[scene - 1].y = y0;
980 }
981 
982 void CGEEngine::snSetXY(Sprite *spr, uint16 xy) {
983 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetXY(spr, %d)", xy);
984 
985 	if (spr)
986 		spr->gotoxy(xy % kScrWidth, xy / kScrWidth);
987 }
988 
989 void CGEEngine::snRelX(Sprite *spr, int x) {
990 	debugC(1, kCGEDebugEngine, "CGEEngine::snRelX(spr, %d)", x);
991 
992 	if (spr && _hero)
993 		spr->gotoxy(_hero->_x + x, spr->_y);
994 }
995 
996 void CGEEngine::snRelY(Sprite *spr, int y) {
997 	debugC(1, kCGEDebugEngine, "CGEEngine::snRelY(spr, %d)", y);
998 
999 	if (spr && _hero)
1000 		spr->gotoxy(spr->_x, _hero->_y + y);
1001 }
1002 
1003 void CGEEngine::snRelZ(Sprite *spr, int z) {
1004 	debugC(1, kCGEDebugEngine, "CGEEngine::snRelZ(spr, %d)", z);
1005 
1006 	if (spr && _hero) {
1007 		spr->_z = _hero->_z + z;
1008 		snZTrim(spr);
1009 	}
1010 }
1011 
1012 void CGEEngine::snSetX(Sprite *spr, int x) {
1013 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetX(spr, %d)", x);
1014 
1015 	if (spr)
1016 		spr->gotoxy(x, spr->_y);
1017 }
1018 
1019 void CGEEngine::snSetY(Sprite *spr, int y) {
1020 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetY(spr, %d)", y);
1021 
1022 	if (spr)
1023 		spr->gotoxy(spr->_x, y);
1024 }
1025 
1026 void CGEEngine::snSetZ(Sprite *spr, int z) {
1027 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetZ(spr, %d)", z);
1028 
1029 	if (spr) {
1030 		spr->_z = z;
1031 		snZTrim(spr);
1032 	}
1033 }
1034 
1035 void CGEEngine::snSlave(Sprite *spr, int ref) {
1036 	debugC(1, kCGEDebugEngine, "CGEEngine::snSlave(spr, %d)", ref);
1037 
1038 	Sprite *slv = locate(ref);
1039 	if (spr && slv) {
1040 		if (spr->active()) {
1041 			snSend(slv, spr->_scene);
1042 			slv->_flags._slav = true;
1043 			slv->_z = spr->_z;
1044 			_vga->_showQ->insert(_vga->_showQ->remove(slv), spr->_next);
1045 		}
1046 	}
1047 }
1048 
1049 void CGEEngine::snTrans(Sprite *spr, int trans) {
1050 	debugC(1, kCGEDebugEngine, "CGEEngine::snTrans(spr, %d)", trans);
1051 
1052 	if (spr)
1053 		spr->_flags._tran = (trans < 0) ? !spr->_flags._tran : (trans != 0);
1054 }
1055 
1056 void CGEEngine::snPort(Sprite *spr, int port) {
1057 	debugC(1, kCGEDebugEngine, "CGEEngine::snPort(spr, %d)", port);
1058 
1059 	if (spr)
1060 		spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0);
1061 }
1062 
1063 void CGEEngine::snKill(Sprite *spr) {
1064 	debugC(1, kCGEDebugEngine, "CGEEngine::snKill(spr)");
1065 
1066 	if (!spr)
1067 		return;
1068 
1069 	if (spr->_flags._kept) {
1070 		int n = findPocket(spr);
1071 		if (n >= 0)
1072 			_pocket[n] = NULL;
1073 	}
1074 	Sprite *nx = spr->_next;
1075 	hide1(spr);
1076 	_vga->_showQ->remove(spr);
1077 	_eventManager->clearEvent(spr);
1078 	if (spr->_flags._kill) {
1079 		delete spr;
1080 	} else {
1081 		spr->_scene = -1;
1082 		_vga->_spareQ->append(spr);
1083 	}
1084 	if (nx) {
1085 		if (nx->_flags._slav)
1086 			snKill(nx);
1087 	}
1088 }
1089 
1090 /**
1091  * Play a FX sound
1092  * @param spr			Sprite pointer
1093  * @param wav			FX index
1094  */
1095 void CGEEngine::snSound(Sprite *spr, int wav) {
1096 	debugC(1, kCGEDebugEngine, "CGEEngine::snSound(spr, %d)", wav);
1097 
1098 	if (wav == -1)
1099 		_sound->stop();
1100 	else
1101 		_sound->play((*_fx)[wav], (spr) ? ((spr->_x + spr->_w / 2) / (kScrWidth / 16)) : 8);
1102 
1103 	_sound->setRepeat(1);
1104 }
1105 
1106 void CGEEngine::snKeep(Sprite *spr, int stp) {
1107 	debugC(1, kCGEDebugEngine, "CGEEngine::snKeep(spr, %d)", stp);
1108 
1109 	selectPocket(-1);
1110 	if (spr && ! spr->_flags._kept && _pocket[_pocPtr] == NULL) {
1111 		int16 oldRepeat = _sound->getRepeat();
1112 		_sound->setRepeat(1);
1113 		snSound(spr, 3);
1114 		_sound->setRepeat(oldRepeat);
1115 		_pocket[_pocPtr] = spr;
1116 		spr->_scene = 0;
1117 		spr->_flags._kept = true;
1118 		spr->gotoxy(kPocketX + kPocketDX * _pocPtr + kPocketDX / 2 - spr->_w / 2,
1119 		          kPocketY + kPocketDY / 2 - spr->_h / 2);
1120 		if (stp >= 0)
1121 			spr->step(stp);
1122 	}
1123 	selectPocket(-1);
1124 }
1125 
1126 /**
1127  * Remove an object from the inventory and (if specified) trigger an animation
1128  * @param spr			Inventory item
1129  * @param stp			Animation
1130  */
1131 void CGEEngine::snGive(Sprite *spr, int stp) {
1132 	debugC(1, kCGEDebugEngine, "CGEEngine::snGive(spr, %d)", stp);
1133 
1134 	if (spr) {
1135 		int p = findPocket(spr);
1136 		if (p >= 0) {
1137 			_pocket[p] = NULL;
1138 			spr->_scene = _now;
1139 			spr->_flags._kept = false;
1140 			if (stp >= 0)
1141 				spr->step(stp);
1142 		}
1143 	}
1144 	selectPocket(-1);
1145 }
1146 
1147 void CGEEngine::snBackPt(Sprite *spr, int stp) {
1148 	debugC(1, kCGEDebugEngine, "CGEEngine::snBackPt(spr, %d)", stp);
1149 
1150 	if (spr) {
1151 		if (stp >= 0)
1152 			spr->step(stp);
1153 		spr->backShow(true);
1154 	}
1155 }
1156 
1157 void CGEEngine::snLevel(Sprite *spr, int lev) {
1158 	debugC(1, kCGEDebugEngine, "CGEEngine::snLevel(spr, %d)", lev);
1159 
1160 	assert((lev >= 0) && (lev < 5));
1161 
1162 	for (int i = 0; i < 5; i++) {
1163 		spr = _vga->_spareQ->locate(100 + i);
1164 		if (spr) {
1165 			if (i <= lev) {
1166 				spr->backShow(true);
1167 				spr->_scene = 0;
1168 				spr->_flags._hide = false;
1169 			} else {
1170 				spr->_flags._hide = true;
1171 				spr->_scene = -1;
1172 			}
1173 		} else {
1174 			warning("SPR not found! ref: %d", 100 + i);
1175 		}
1176 	}
1177 
1178 	_lev = lev;
1179 	_maxScene = _maxSceneArr[_lev];
1180 }
1181 
1182 /**
1183  * Set a flag to a value
1184  * @param indx			Flag index
1185  * @param val			Flag value
1186  */
1187 void CGEEngine::snFlag(int indx, bool val) {
1188 	_flag[indx] = val;
1189 }
1190 
1191 void CGEEngine::snSetRef(Sprite *spr, int nr) {
1192 	debugC(1, kCGEDebugEngine, "CGEEngine::snSetRef(spr, %d)", nr);
1193 
1194 	if (spr)
1195 		spr->_ref = nr;
1196 }
1197 
1198 void CGEEngine::snFlash(bool on) {
1199 	debugC(1, kCGEDebugEngine, "CGEEngine::snFlash(%s)", on ? "true" : "false");
1200 
1201 	if (on) {
1202 		Dac *pal = (Dac *)malloc(sizeof(Dac) * kPalCount);
1203 		if (pal) {
1204 			memcpy(pal, _vga->_sysPal, kPalSize);
1205 			for (int i = 0; i < kPalCount; i++) {
1206 				int c;
1207 				c = pal[i]._r << 1;
1208 				pal[i]._r = (c < 64) ? c : 63;
1209 				c = pal[i]._g << 1;
1210 				pal[i]._g = (c < 64) ? c : 63;
1211 				c = pal[i]._b << 1;
1212 				pal[i]._b = (c < 64) ? c : 63;
1213 			}
1214 			_vga->setColors(pal, 64);
1215 		}
1216 
1217 		free(pal);
1218 	} else
1219 		_vga->setColors(_vga->_sysPal, 64);
1220 	_dark = false;
1221 }
1222 
1223 void CGEEngine::snLight(bool in) {
1224 	debugC(1, kCGEDebugEngine, "CGEEngine::snLight(%s)", in ? "true" : "false");
1225 
1226 	if (in)
1227 		_vga->sunrise(_vga->_sysPal);
1228 	else
1229 		_vga->sunset();
1230 	_dark = !in;
1231 }
1232 
1233 /**
1234  * Set an horizontal boundary
1235  * @param scene			Scene number
1236  * @param barX			Horizontal boundary value
1237  */
1238 void CGEEngine::snHBarrier(const int scene, const int barX) {
1239 	debugC(1, kCGEDebugEngine, "CGEEngine::snHBarrier(%d, %d)", scene, barX);
1240 
1241 	_barriers[(scene > 0) ? scene : _now]._horz = barX;
1242 }
1243 
1244 /**
1245  * Set a vertical boundary
1246  * @param scene			Scene number
1247  * @param barY			Vertical boundary value
1248  */
1249 void CGEEngine::snVBarrier(const int scene, const int barY) {
1250 	debugC(1, kCGEDebugEngine, "CGEEngine::snVBarrier(%d, %d)", scene, barY);
1251 
1252 	_barriers[(scene > 0) ? scene : _now]._vert = barY;
1253 }
1254 
1255 void CGEEngine::snWalk(Sprite *spr, int x, int y) {
1256 	debugC(1, kCGEDebugEngine, "CGEEngine::snWalk(spr, %d, %d)", x, y);
1257 
1258 	if (_hero) {
1259 		if (spr && y < 0)
1260 			_hero->findWay(spr);
1261 		else
1262 			_hero->findWay(XZ(x, y));
1263 	}
1264 }
1265 
1266 void CGEEngine::snReach(Sprite *spr, int mode) {
1267 	debugC(1, kCGEDebugEngine, "CGEEngine::snReach(spr, %d)", mode);
1268 
1269 	if (_hero)
1270 		_hero->reach(spr, mode);
1271 }
1272 
1273 void CGEEngine::snMouse(bool on) {
1274 	debugC(1, kCGEDebugEngine, "CGEEngine::snMouse(%s)", on ? "true" : "false");
1275 
1276 	if (on)
1277 		_mouse->on();
1278 	else
1279 		_mouse->off();
1280 }
1281 
1282 } // End of namespace CGE
1283