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  *              Originally written by Syn9 in FreeBASIC with SDL
23  *              http://syn9.thehideoutgames.com/index_backup.php
24  *
25  *            Ported to plain C for GCW-Zero handheld by Dmitry Smagin
26  *                http://github.com/dmitrysmagin/griffon_legend
27  *
28  *
29  *                 Programming/Graphics: Daniel "Syn9" Kennedy
30  *                     Music/Sound effects: David Turner
31  *
32  *                   Beta testing and gameplay design help:
33  *                    Deleter, Cha0s, Aether Fox, and Kiz
34  *
35  */
36 
37 #include "common/system.h"
38 #include "common/config-manager.h"
39 
40 #include "griffon/griffon.h"
41 
42 #include "common/text-to-speech.h"
43 
44 namespace Griffon {
45 
46 #define MINCURSEL 7
47 #define MAXCURSEL 16
48 #define SY 25
49 #define PI 3.141593
50 
title(int mode)51 void GriffonEngine::title(int mode) {
52 	const char *optionTitles[4] = {
53 		"new game/save/load",
54 		"options",
55 		"quit game",
56 		"return"
57 	};
58 
59 	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
60 
61 	float xofs = 0;
62 	_itemyloc = 0;
63 	bool exitTitle = false;
64 
65 	rcSrc.left = 0;
66 	rcSrc.top = 0;
67 	rcSrc.setWidth(320);
68 	rcSrc.setHeight(240);
69 
70 	_videoBuffer2->fillRect(rcSrc, 0);
71 	_videoBuffer3->fillRect(rcSrc, 0);
72 
73 	_ticks = g_system->getMillis();
74 
75 	_videoBuffer->blit(*_videoBuffer3);
76 	_videoBuffer->blit(*_videoBuffer2);
77 
78 	int cursel = 0;
79 	int ticks1 = _ticks;
80 
81 	if (config.music) {
82 		setChannelVolume(_musicChannel, 0);
83 		pauseSoundChannel(_musicChannel);
84 
85 		_menuChannel = playSound(_musicMenu, true);
86 		setChannelVolume(_menuChannel, config.musicVol);
87 		_pmenu = true;
88 	}
89 
90 	bool ldstop = false;
91 
92 	float ld = 0;
93 	do {
94 		Common::Rect rc;
95 
96 		ld += 4.0 * _fpsr;
97 		if (ld > config.musicVol)
98 			ld = config.musicVol;
99 		if (!ldstop) {
100 			setChannelVolume(_menuChannel, (int)ld);
101 			if ((int)ld == config.musicVol)
102 				ldstop = true;
103 		}
104 
105 		rc.left = -xofs;
106 		rc.top = 0;
107 
108 		_titleImg->blit(*_videoBuffer, rc.left, rc.top);
109 
110 		rc.left = -xofs + 320.0;
111 		rc.top = 0;
112 
113 		_titleImg->blit(*_videoBuffer, rc.left, rc.top);
114 
115 		rc.left = 0;
116 		rc.top = 0;
117 
118 		_titleImg2->blit(*_videoBuffer, rc.left, rc.top);
119 
120 		int y = 172;
121 		int x = 160 - 14 * 4;
122 
123 		drawString(_videoBuffer, optionTitles[0], x, y, 4);
124 		drawString(_videoBuffer, optionTitles[1], x, y + 16, 4);
125 		drawString(_videoBuffer, optionTitles[2], x, y + 32, 4);
126 
127 		if (mode == 1)
128 			drawString(_videoBuffer, optionTitles[3], x, y + 48, 4);
129 		else
130 			drawString(_videoBuffer, "(c) 2005 by Daniel 'Syn9' Kennedy", 28, 224, 4);
131 
132 		rc.left = (int16)(x - 16 - 4 * cos(2 * PI * _itemyloc / 16));
133 		rc.top = (int16)(y - 4 + 16 * cursel);
134 
135 		_itemImg[15]->blit(*_videoBuffer, rc.left, rc.top);
136 
137 		float yf = 255.0;
138 		if (_ticks < ticks1 + 1000) {
139 			yf = 255.0 * ((float)(_ticks - ticks1) / 1000.0);
140 			yf = CLIP<float>(yf, 0.0, 255.0);
141 		}
142 
143 		_videoBuffer->setAlpha((int)yf);
144 		g_system->copyRectToScreen(_videoBuffer->getPixels(), _videoBuffer->pitch, 0, 0, _videoBuffer->w, _videoBuffer->h);
145 		g_system->updateScreen();
146 
147 		_ticksPassed = _ticks;
148 		_ticks = g_system->getMillis();
149 
150 		_ticksPassed = _ticks - _ticksPassed;
151 		_fpsr = (float)_ticksPassed / 24.0;
152 
153 		_fp++;
154 		if (_ticks > _nextTicks) {
155 			_nextTicks = _ticks + 1000;
156 			_fps = _fp;
157 			_fp = 0;
158 		}
159 
160 		float add = 0.5 * _fpsr;
161 		if (add > 1)
162 			add = 1;
163 
164 		xofs += add;
165 		if (xofs >= 320.0)
166 			xofs -= 320.0;
167 
168 		_itemyloc += 0.75 * _fpsr;
169 
170 		while (_itemyloc >= 16)
171 			_itemyloc = _itemyloc - 16;
172 
173 		if (g_system->getEventManager()->pollEvent(_event)) {
174 			if (_event.type == Common::EVENT_QUIT || _event.type == Common::EVENT_RETURN_TO_LAUNCHER)
175 				_shouldQuit = true;
176 
177 			if (_event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START) {
178 
179 				switch(_event.customType) {
180 				case kGriffonMenu:
181 					if (mode == 1)
182 						exitTitle = true;
183 					break;
184 				case kGriffonUp:
185 					cursel--;
186 					if (cursel < 0)
187 						cursel = (mode == 1 ? 3 : 2);
188 					if (ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
189 						ttsMan->say(optionTitles[cursel]);
190 					break;
191 				case kGriffonDown:
192 					cursel++;
193 					if (cursel >= (mode == 1 ? 4 : 3))
194 						cursel = 0;
195 					if (ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
196 						ttsMan->say(optionTitles[cursel]);
197 					break;
198 				case kGriffonConfirm:
199 					if (ttsMan != nullptr)
200 							ttsMan->stop();
201 					switch(cursel) {
202 					case 0:
203 						_ticks = g_system->getMillis();
204 						ticks1 = _ticks;
205 
206 						saveLoadNew();
207 
208 						if (_gameMode == kGameModeNewGame || _gameMode == kGameModeLoadGame) {
209 							exitTitle = true;
210 						}
211 						break;
212 					case 1:
213 						configMenu();
214 						_ticks = g_system->getMillis();
215 						ticks1 = _ticks;
216 						break;
217 					case 2:
218 						_shouldQuit = true;
219 						break;
220 					case 3:
221 						exitTitle = true;
222 					default:
223 						break;
224 					}
225 					break;
226 				default:
227 					break;
228 				}
229 			}
230 		}
231 
232 		g_system->delayMillis(10);
233 	} while (!_shouldQuit && !exitTitle && _gameMode != kGameModeNewGame && _gameMode != kGameModeLoadGame);
234 
235 	_itemTicks = _ticks + 210;
236 
237 	if (config.music) {
238 		haltSoundChannel(_menuChannel);
239 		resumeSoundChannel(_musicChannel);
240 		setChannelVolume(_musicChannel, config.musicVol);
241 		_pmenu = false;
242 	}
243 }
244 
formatPercent(int val)245 static Common::String formatPercent(int val) {
246 	val = val / 2.55;
247 	return Common::String::format("%d percent", val - val % 10);
248 }
249 
speakMenuItem(int mapTitles,int mapValues,const char * mapTitleText[],const char * mapValueText[])250 static void speakMenuItem(int mapTitles, int mapValues, const char *mapTitleText[], const char *mapValueText[]) {
251 	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
252 	if (ttsMan != nullptr && ConfMan.getBool("tts_enabled")) {
253 		Common::TextToSpeechManager::Action valueAction = Common::TextToSpeechManager::INTERRUPT;
254 		if (mapTitles != 0) {
255 			ttsMan->say(mapTitleText[mapTitles]);
256 			valueAction = Common::TextToSpeechManager::QUEUE;
257 		}
258 		if (mapValues != 0)
259 			ttsMan->say(mapValueText[mapValues], valueAction);
260 	}
261 }
262 
configMenu()263 void GriffonEngine::configMenu() {
264 	static const char *optionTitles[25] = {
265 		"", "",
266 		"", "", "", "",
267 		"", "", "",
268 		"Music:", "", "",
269 		"Sound Effects:", "", "",
270 		"Text to Speech:", "", "",
271 		"Music Volume:", "",
272 		"Effects Volume:", "", "", "", ""
273 	};
274 	static const char *optionValues[25] = {
275 		"", "",
276 		"", "", "", "",
277 		"", "", "",
278 		"On", "Off", "",
279 		"On", "Off", "",
280 		"On", "Off", "",
281 		"[----------]", "",
282 		"[----------]", "",
283 		"Exit + Save", "",
284 		"Exit"
285 	};
286 	static const int curselMapTitles[MAXCURSEL+1] = {
287 		0, 0, 0, 0, 0,
288 		0, 0, 9, 9, 12,
289 		12, 15, 15, 18, 20,
290 		0, 0
291 	};
292 	static const int curselMapValues[MAXCURSEL+1] = {
293 		0, 0, 0, 0, 0,
294 		0, 0, 9, 10, 12,
295 		13, 15, 16, 0, 0,
296 		22, 24
297 	};
298 
299 	int cursel = MINCURSEL;
300 	bool exitMenu = false;
301 
302 	_ticks = g_system->getMillis();
303 
304 	Graphics::TransparentSurface *configwindow = loadImage("art/configwindow.bmp", true);
305 	configwindow->setAlpha(160, true);
306 
307 	int ticks1 = _ticks;
308 
309 	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
310 
311 	do {
312 		_videoBuffer->fillRect(Common::Rect(0, 0, _videoBuffer->w, _videoBuffer->h), 0);
313 		_videoBuffer2->fillRect(Common::Rect(0, 0, _videoBuffer2->w, _videoBuffer2->h), 0);
314 
315 		rcDest.left = 256 + 256 * cos(PI / 180 * _cloudAngle * 40);
316 		rcDest.top = 192 + 192 * sin(PI / 180 * _cloudAngle * 40);
317 		rcDest.setWidth(320);
318 		rcDest.setHeight(240);
319 
320 		_cloudImg->blit(*_videoBuffer, 0, 0, Graphics::FLIP_NONE, &rcDest, TS_ARGB(128, 255, 255, 255));
321 
322 		rcDest.left = 256;
323 		rcDest.top = 192;
324 		rcDest.setWidth(320);
325 		rcDest.setHeight(240);
326 
327 		_cloudImg->blit(*_videoBuffer, 0, 0, Graphics::FLIP_NONE, &rcDest, TS_ARGB(128, 255, 255, 255));
328 
329 		configwindow->blit(*_videoBuffer);
330 
331 		int sy = SY;
332 
333 		for (int i = 0; i <= 24; i++) {
334 			static char line[24];
335 
336 			int destColumn = 3;
337 			if (i == 9 && config.music)
338 				destColumn = 0;
339 			else if (i == 10 && !config.music)
340 				destColumn = 0;
341 			else if (i == 12 && config.effects)
342 				destColumn = 0;
343 			else if (i == 13 && !config.effects)
344 				destColumn = 0;
345 			else if (i == 15 && ConfMan.getBool("tts_enabled"))
346 				destColumn = 0;
347 			else if (i == 16 && !ConfMan.getBool("tts_enabled"))
348 				destColumn = 0;
349 			else if (i == 18|| i == 20) {
350 				int vol = (i ==18 ? config.musicVol : config.effectsVol) * 9 / 255;
351 				vol = CLIP(vol, 0, 9);
352 
353 				strcpy(line, "[----------]");
354 				line[vol + 1] = 'X';
355 				optionValues[i] = line;
356 			} else if (i > 21)
357 				destColumn = 0;
358 
359 			drawString(_videoBuffer, optionTitles[i], 156 - 8 * strlen(optionTitles[i]), sy + i * 8, 0);
360 			drawString(_videoBuffer, optionValues[i], 164, sy + i * 8, destColumn);
361 		}
362 
363 		int curselt = cursel + 2;
364 		if (cursel > 8)
365 			curselt += 1;
366 		if (cursel > 10)
367 			curselt += 1;
368 		if (cursel > 12)
369 			curselt += 1;
370 		if (cursel > 13)
371 			curselt += 1;
372 		if (cursel > 14)
373 			curselt += 1;
374 		if (cursel > 15)
375 			curselt += 1;
376 
377 		Common::Rect rc;
378 		rc.left = 148 + 3 * cos(2 * PI * _itemyloc / 16.0);
379 		rc.top = sy + 8 * curselt - 4;
380 
381 		_itemImg[15]->blit(*_videoBuffer, rc.left, rc.top);
382 
383 		if (_ticks < ticks1 + 1000) {
384 			float yy = 255.0 * ((float)(_ticks - ticks1) / 1000.0);
385 			yy = CLIP<float>(yy, 0.0, 255.0);
386 
387 			_videoBuffer->setAlpha((uint8)yy);
388 		}
389 
390 		_videoBuffer->blit(*_videoBuffer2);
391 		g_system->copyRectToScreen(_videoBuffer2->getPixels(), _videoBuffer2->pitch, 0, 0, _videoBuffer2->w, _videoBuffer2->h);
392 
393 		_ticksPassed = _ticks;
394 		_ticks = g_system->getMillis();
395 
396 		_ticksPassed = _ticks - _ticksPassed;
397 		_fpsr = (float)_ticksPassed / 24;
398 
399 		_fp++;
400 		if (_ticks > _nextTicks) {
401 			_nextTicks = _ticks + 1000;
402 			_fps = _fp;
403 			_fp = 0;
404 		}
405 
406 		_itemyloc += 0.75 * _fpsr;
407 		while (_itemyloc >= 16)
408 			_itemyloc -= 16;
409 
410 		while (g_system->getEventManager()->pollEvent(_event)) {
411 			switch (_event.type) {
412 			case Common::EVENT_QUIT:
413 			case Common::EVENT_RETURN_TO_LAUNCHER:
414 				_shouldQuit = true;
415 				break;
416 
417 			case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
418 				switch (_event.customType) {
419 				case kGriffonMenu:
420 					exitMenu = true;
421 					break;
422 
423 				case kGriffonLeft:
424 					if (cursel == 13) {
425 						config.musicVol = CLIP(config.musicVol - 25, 0, 255);
426 						setChannelVolume(_musicChannel, config.musicVol);
427 						setChannelVolume(_menuChannel, config.musicVol);
428 						if (ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
429 							ttsMan->say(formatPercent(config.musicVol));
430 					} else if (cursel == 14) {
431 						config.effectsVol = CLIP(config.effectsVol - 25, 0, 255);
432 
433 						setChannelVolume(-1, config.effectsVol);
434 						setChannelVolume(_musicChannel, config.musicVol);
435 						setChannelVolume(_menuChannel, config.musicVol);
436 						if (ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
437 							ttsMan->say(formatPercent(config.effectsVol));
438 
439 						if (config.effects) {
440 							int snd = playSound(_sfx[kSndDoor]);
441 							setChannelVolume(snd, config.effectsVol);
442 						}
443 					}
444 					break;
445 
446 				case kGriffonRight:
447 					if (cursel == 13) {
448 						config.musicVol = CLIP(config.musicVol + 25, 0, 255);
449 						setChannelVolume(_musicChannel, config.musicVol);
450 						setChannelVolume(_menuChannel, config.musicVol);
451 						if (ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
452 							ttsMan->say(formatPercent(config.musicVol));
453 					} else if (cursel == 14) {
454 						config.effectsVol = CLIP(config.effectsVol + 25, 0, 255);
455 						setChannelVolume(-1, config.effectsVol);
456 						setChannelVolume(_musicChannel, config.musicVol);
457 						setChannelVolume(_menuChannel, config.musicVol);
458 						if (ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
459 							ttsMan->say(formatPercent(config.effectsVol));
460 
461 						if (config.effects) {
462 							int snd = playSound(_sfx[kSndDoor]);
463 							setChannelVolume(snd, config.effectsVol);
464 						}
465 					}
466 					break;
467 
468 				case kGriffonUp:
469 					cursel--;
470 					if (cursel < MINCURSEL)
471 						cursel = MAXCURSEL;
472 					speakMenuItem(curselMapTitles[cursel], curselMapValues[cursel], optionTitles, optionValues);
473 					break;
474 
475 				case kGriffonDown:
476 					++cursel;
477 					if (cursel > MAXCURSEL)
478 						cursel = MINCURSEL;
479 					speakMenuItem(curselMapTitles[cursel], curselMapValues[cursel], optionTitles, optionValues);
480 					break;
481 
482 				case kGriffonConfirm:
483 					switch (cursel) {
484 					case 7:
485 						if (!config.music) {
486 							config.music = true;
487 							_menuChannel = playSound(_musicMenu, true);
488 							setChannelVolume(_menuChannel, config.musicVol);
489 						}
490 						break;
491 					case 8:
492 						if (config.music) {
493 							config.music = false;
494 							haltSoundChannel(_musicChannel);
495 							haltSoundChannel(_menuChannel);
496 						}
497 						break;
498 					case 9:
499 						if (!config.effects) {
500 							config.effects = true;
501 							int snd = playSound(_sfx[kSndDoor]);
502 							setChannelVolume(snd, config.effectsVol);
503 						}
504 						break;
505 					case 10:
506 						if (config.effects)
507 							config.effects = false;
508 						break;
509 					case 11:
510 						if (!ConfMan.getBool("tts_enabled")) {
511 							ConfMan.setBool("tts_enabled", true);
512 						}
513 						break;
514 					case 12:
515 						if (ConfMan.getBool("tts_enabled")) {
516 							ConfMan.setBool("tts_enabled", false);
517 						}
518 						break;
519 					case 15:
520 						saveConfig();
521 						// fall through
522 					case 16:
523 						if (ttsMan != nullptr)
524 							ttsMan->stop();
525 						exitMenu = true;
526 						break;
527 					default:
528 						break;
529 					}
530 					break;
531 
532 				default:
533 					break;
534 				}
535 
536 			default:
537 				break;
538 			}
539 		}
540 
541 		_cloudAngle += 0.01 * _fpsr;
542 		while (_cloudAngle >= 360)
543 			_cloudAngle -= 360;
544 
545 		g_system->updateScreen();
546 		g_system->delayMillis(10);
547 	} while (!_shouldQuit && !exitMenu && _gameMode != kGameModeNewGame && _gameMode != kGameModeLoadGame);
548 
549 
550 	configwindow->free();
551 	_itemTicks = _ticks + 210;
552 }
553 
renderSaveStates()554 void GriffonEngine::renderSaveStates() {
555 	_videoBuffer2->fillRect(Common::Rect(0, 0, _videoBuffer2->w, _videoBuffer2->h), 0);
556 
557 	for (int ff = 0; ff <= 3; ff++) {
558 		loadPlayer(ff);
559 
560 		if (_playera.level > 0) {
561 			int sx = 8;
562 			int sy = 57 + ff * 48;
563 
564 			// time
565 			int ase = _asecstart;
566 			int h = ((ase - (ase % 3600)) / 3600);
567 			ase = (ase - h * 3600);
568 			int m = ((ase - (ase % 60)) / 60);
569 			int s = (ase - m * 60);
570 
571 			char line[256];
572 			sprintf(line, "Game Time: %02i:%02i:%02i", h, m, s);
573 			drawString(_videoBuffer2, line, 160 - strlen(line) * 4, sy, 0);
574 
575 			sx = 12;
576 			sy += 11;
577 			int cc = 0;
578 
579 			sprintf(line, "Health: %i/%i", _playera.hp, _playera.maxHp);
580 			drawString(_videoBuffer2, line, sx, sy, cc);
581 
582 			if (_playera.level == 22)
583 				strcpy(line, "Level: MAX");
584 			else
585 				sprintf(line, "Level: %i", _playera.level);
586 
587 			drawString(_videoBuffer2, line, sx, sy + 11, 0);
588 
589 			rcSrc.left = sx + 15 * 8 + 24;
590 			rcSrc.top = sy + 1;
591 
592 			int ss = (_playera.sword - 1) * 3;
593 			if (_playera.sword == 3)
594 				ss = 18;
595 			_itemImg[ss]->blit(*_videoBuffer2, rcSrc.left, rcSrc.top);
596 
597 			rcSrc.left += 16;
598 			ss = (_playera.shield - 1) * 3 + 1;
599 			if (_playera.shield == 3)
600 				ss = 19;
601 			_itemImg[ss]->blit(*_videoBuffer2, rcSrc.left, rcSrc.top);
602 
603 			rcSrc.left += 16;
604 			ss = (_playera.armour - 1) * 3 + 2;
605 			if (_playera.armour == 3)
606 				ss = 20;
607 			_itemImg[ss]->blit(*_videoBuffer2, rcSrc.left, rcSrc.top);
608 
609 			int nx = rcSrc.left + 13 + 3 * 8;
610 			rcSrc.left = nx - 17;
611 
612 			if (_playera.foundSpell[0]) {
613 				for (int i = 0; i < 5; i++) {
614 					rcSrc.left += 17;
615 					if (_playera.foundSpell[i])
616 						_itemImg[7 + i]->blit(*_videoBuffer2, rcSrc.left, rcSrc.top);
617 				}
618 			}
619 		} else {
620 			int sy = 57 + ff * 48;
621 			drawString(_videoBuffer2, "Empty", 160 - 5 * 4, sy, 0);
622 		}
623 	}
624 }
625 
saveLoadNew()626 void GriffonEngine::saveLoadNew() {
627 	const char *optionTitles[4] = {
628 		"new game", "", "load", "return",
629 	};
630 
631 	float y = 0.0;
632 
633 	_cloudAngle = 0;
634 
635 	int curRow = 0;
636 	int curCol = 0;
637 
638 	bool lowerLock = false;
639 
640 	_ticks = g_system->getMillis();
641 	int ticks1 = _ticks;
642 	int tickPause = _ticks + 150;
643 
644 
645 	renderSaveStates();
646 
647 	delete _saveLoadImg;
648 
649 	_saveLoadImg = loadImage("art/saveloadnew.bmp", true);
650 	if (_gameMode == kGameModeIntro) {
651 		uint32 color = *(uint32 *)_saveLoadImg->getBasePtr(120, 10);
652 		_saveLoadImg->fillRect(Common::Rect(125, 15, 160, 33), color);
653 	}
654 	_saveLoadImg->setAlpha(192, true);
655 
656 	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
657 
658 	// Main menu loop
659 	do {
660 		_videoBuffer->fillRect(Common::Rect(0, 0, _videoBuffer->w, _videoBuffer->h), 0);
661 
662 		y += 1 * _fpsr;
663 
664 		rcDest.left = 256 + 256 * cos(PI / 180 * _cloudAngle * 40);
665 		rcDest.top = 192 + 192 * sin(PI / 180 * _cloudAngle * 40);
666 		rcDest.setWidth(320);
667 		rcDest.setHeight(240);
668 
669 		_cloudImg->blit(*_videoBuffer, 0, 0, Graphics::FLIP_NONE, &rcDest, TS_ARGB(128, 255, 255, 255));
670 
671 		rcDest.left = 256;
672 		rcDest.top = 192;
673 		rcDest.setWidth(320);
674 		rcDest.setHeight(240);
675 
676 		_cloudImg->blit(*_videoBuffer, 0, 0, Graphics::FLIP_NONE, &rcDest, TS_ARGB(128, 255, 255, 255));
677 
678 		_saveLoadImg->blit(*_videoBuffer);
679 
680 		if (g_system->getEventManager()->pollEvent(_event)) {
681 			if (_event.type == Common::EVENT_QUIT || _event.type == Common::EVENT_RETURN_TO_LAUNCHER) {
682 				_shouldQuit = true;
683 				return;
684 			}
685 
686 			if (tickPause < _ticks && _event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START) {
687 				_itemTicks = _ticks + 220;
688 
689 				if (_event.customType == kGriffonConfirm) {
690 					if (curRow == 0) {
691 						if (curCol == 0) {
692 							// NEW GAME
693 							if (ttsMan != nullptr)
694 								ttsMan->stop();
695 							_gameMode = kGameModeNewGame;
696 
697 							return;
698 						} else if (curCol == 1) {
699 							// SAVE GAME
700 							lowerLock = true;
701 							curRow = 1 + _saveSlot;
702 							tickPause = _ticks + 125;
703 						} else if (curCol == 2) {
704 							// LOAD GAME
705 							lowerLock = true;
706 							curRow = 1;
707 							tickPause = _ticks + 125;
708 						} else if (curCol == 3) {
709 							if (ttsMan != nullptr)
710 								ttsMan->stop();
711 							// RETURN
712 							return;
713 						} else if (curCol == 4) {
714 							// QUIT - non existent :)
715 							_shouldQuit = true;
716 							return;
717 						}
718 					}
719 					if (lowerLock && tickPause < _ticks) {
720 						if ((curCol == 1) && saveGameState(curRow - 1, "", false).getCode() == Common::kNoError) {
721 							_secStart += _secsInGame;
722 							_secsInGame = 0;
723 							lowerLock = false;
724 							_saveSlot = curRow - 1;
725 							curRow = 0;
726 
727 							renderSaveStates();
728 						} else if ((curCol == 2) && loadGameState(curRow - 1).getCode() == Common::kNoError) {
729 
730 							return;
731 						}
732 						tickPause = _ticks + 125;
733 					}
734 				}
735 
736 				switch (_event.customType) {
737 				case kGriffonMenu:
738 					if (curRow == 0)
739 						return;
740 					lowerLock = false;
741 					curRow = 0;
742 					tickPause = _ticks + 125;
743 					break;
744 				case kGriffonDown:
745 					if (lowerLock) {
746 						++curRow;
747 						if (curRow == 5)
748 							curRow = 1;
749 						tickPause = _ticks + 125;
750 					}
751 					break;
752 
753 				case kGriffonUp:
754 					if (lowerLock) {
755 						--curRow;
756 						if (curRow == 0)
757 							curRow = 4;
758 						tickPause = _ticks + 125;
759 					}
760 					break;
761 
762 				case kGriffonLeft:
763 					if (!lowerLock) {
764 						--curCol;
765 						if (curCol == -1)
766 							curCol = 3;
767 
768 						if (curCol == 1 && _gameMode == kGameModeIntro)
769 							curCol = 0;
770 
771 						tickPause = _ticks + 125;
772 					}
773 					if (ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
774 						ttsMan -> say(optionTitles[curCol]);
775 					break;
776 
777 				case kGriffonRight:
778 					if (!lowerLock) {
779 						++curCol;
780 						if (curCol == 4)
781 							curCol = 0;
782 
783 						if (curCol == 1 && _gameMode == kGameModeIntro)
784 							curCol = 2;
785 
786 						tickPause = _ticks + 125;
787 					}
788 					if (ttsMan != nullptr && ConfMan.getBool("tts_enabled"))
789 						ttsMan -> say(optionTitles[curCol]);
790 					break;
791 				default:
792 					;
793 				}
794 			}
795 		}
796 
797 		// Render savestates
798 		_videoBuffer2->blit(*_videoBuffer);
799 
800 		// ------------------------------------------
801 
802 		if (curRow == 0) {
803 			rcDest.top = 18;
804 			switch(curCol) {
805 				case 0:
806 					rcDest.left = 10;
807 					break;
808 				case 1:
809 					rcDest.left = 108;
810 					break;
811 				case 2:
812 					rcDest.left = 170;
813 					break;
814 				case 3:
815 					rcDest.left = 230;
816 				default:
817 					break;
818 			}
819 
820 			rcDest.left += (int16)(2 + 2 * sin(2 * PI * _itemyloc / 16));
821 		}
822 
823 		if (curRow > 0) {
824 			rcDest.left = (int16)(0 + 2 * sin(2 * PI * _itemyloc / 16));
825 			rcDest.top = (int16)(53 + (curRow - 1) * 48);
826 		}
827 
828 		_itemImg[15]->blit(*_videoBuffer, rcDest.left, rcDest.top);
829 
830 		if (curRow != 0) {
831 			rcDest.top = 18;
832 			if (curCol == 1)
833 				rcDest.left = 108;
834 			else if (curCol == 2)
835 				rcDest.left = 170;
836 
837 			_itemImg[15]->blit(*_videoBuffer, rcDest.left, rcDest.top);
838 		}
839 
840 		if (_ticks < ticks1 + 1000) {
841 			int yy = 255 * (_ticks - ticks1) / 1000;
842 			yy = CLIP(yy, 0, 255);
843 
844 			_videoBuffer->setAlpha((uint8)yy);
845 		}
846 
847 		_videoBuffer3->fillRect(Common::Rect(0, 0, _videoBuffer3->w, _videoBuffer3->h), 0);
848 		_videoBuffer->blit(*_videoBuffer3);
849 
850 		g_system->copyRectToScreen(_videoBuffer3->getPixels(), _videoBuffer3->pitch, 0, 0, _videoBuffer3->w, _videoBuffer3->h);
851 		g_system->updateScreen();
852 
853 		_ticksPassed = _ticks;
854 		_ticks = g_system->getMillis();
855 
856 		_ticksPassed = _ticks - _ticksPassed;
857 		_fpsr = (float)_ticksPassed / 24;
858 
859 		_fp++;
860 		if (_ticks > _nextTicks) {
861 			_nextTicks = _ticks + 1000;
862 			_fps = _fp;
863 			_fp = 0;
864 		}
865 
866 		_cloudAngle += 0.01 * _fpsr;
867 		while (_cloudAngle >= 360)
868 			_cloudAngle -= 360;
869 
870 		_itemyloc += 0.6 * _fpsr;
871 		while (_itemyloc >= 16)
872 			_itemyloc -= 16;
873 
874 		g_system->delayMillis(10);
875 	} while (!_shouldQuit);
876 
877 }
878 
879 
880 } // end of namespace Griffon
881