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 #include "common/error.h"
25 #include "common/events.h"
26 #include "common/system.h"
27 #include "queen/journal.h"
28 
29 #include "queen/bankman.h"
30 #include "queen/display.h"
31 #include "queen/graphics.h"
32 #include "queen/grid.h"
33 #include "queen/logic.h"
34 #include "queen/music.h"
35 #include "queen/queen.h"
36 #include "queen/resource.h"
37 #include "queen/sound.h"
38 
39 namespace Queen {
40 
Journal(QueenEngine * vm)41 Journal::Journal(QueenEngine *vm)
42 	: _vm(vm) {
43 	_currentSavePage = 0;
44 	_currentSaveSlot = 0;
45 }
46 
use()47 void Journal::use() {
48 	BobSlot *joe = _vm->graphics()->bob(0);
49 	_prevJoeX = joe->x;
50 	_prevJoeY = joe->y;
51 
52 	_panelMode = PM_NORMAL;
53 	_system = g_system;
54 
55 	_panelTextCount = 0;
56 	memset(_panelTextY, 0, sizeof(_panelTextY));
57 	memset(&_textField, 0, sizeof(_textField));
58 
59 	memset(_saveDescriptions, 0, sizeof(_saveDescriptions));
60 	_vm->findGameStateDescriptions(_saveDescriptions);
61 
62 	setup();
63 	redraw();
64 	update();
65 	_vm->display()->palFadeIn(ROOM_JOURNAL);
66 
67 	_quitMode = QM_LOOP;
68 	while (_quitMode == QM_LOOP) {
69 		Common::Event event;
70 		Common::EventManager *eventMan = _system->getEventManager();
71 		while (eventMan->pollEvent(event)) {
72 			switch (event.type) {
73 			case Common::EVENT_KEYDOWN:
74 				handleKeyDown(event.kbd.ascii, event.kbd.keycode);
75 				break;
76 			case Common::EVENT_LBUTTONDOWN:
77 				handleMouseDown(event.mouse.x, event.mouse.y);
78 				break;
79 			case Common::EVENT_WHEELUP:
80 				handleMouseWheel(-1);
81 				break;
82 			case Common::EVENT_WHEELDOWN:
83 				handleMouseWheel(1);
84 				break;
85 			case Common::EVENT_RTL:
86 			case Common::EVENT_QUIT:
87 				return;
88 			default:
89 				break;
90 			}
91 		}
92 		_system->delayMillis(20);
93 		_system->updateScreen();
94 	}
95 
96 	_vm->writeOptionSettings();
97 
98 	_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
99 	_vm->graphics()->putCameraOnBob(0);
100 	if (_quitMode == QM_CONTINUE) {
101 		continueGame();
102 	}
103 }
104 
continueGame()105 void Journal::continueGame() {
106 	_vm->display()->fullscreen(false);
107 	_vm->display()->forceFullRefresh();
108 
109 	_vm->logic()->joePos(_prevJoeX, _prevJoeY);
110 	_vm->logic()->joeCutFacing(_vm->logic()->joeFacing());
111 
112 	_vm->logic()->oldRoom(_vm->logic()->currentRoom());
113 	_vm->logic()->displayRoom(_vm->logic()->currentRoom(), RDM_FADE_JOE, 0, 0, false);
114 }
115 
setup()116 void Journal::setup() {
117 	_vm->display()->palFadeOut(_vm->logic()->currentRoom());
118 	_vm->display()->horizontalScroll(0);
119 	_vm->display()->fullscreen(true);
120 	_vm->graphics()->clearBobs();
121 	_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
122 	_vm->bankMan()->eraseFrames(false);
123 	_vm->display()->textCurrentColor(_vm->display()->getInkColor(INK_JOURNAL));
124 
125 	_vm->grid()->clear(GS_ROOM);
126 	for (int i = 0; i < MAX_ZONES; ++i) {
127 		const Zone *zn = &_zones[i];
128 		_vm->grid()->setZone(GS_ROOM, zn->num, zn->x1, zn->y1, zn->x2, zn->y2);
129 	}
130 
131 	_vm->display()->setupNewRoom("journal", ROOM_JOURNAL);
132 	_vm->bankMan()->load("journal.BBK", JOURNAL_BANK);
133 	for (int f = 1; f <= 20; ++f) {
134 		int frameNum = JOURNAL_FRAMES + f;
135 		_vm->bankMan()->unpack(f, frameNum, JOURNAL_BANK);
136 		BobFrame *bf = _vm->bankMan()->fetchFrame(frameNum);
137 		bf->xhotspot = 0;
138 		bf->yhotspot = 0;
139 		if (f == FRAME_INFO_BOX) { // adjust info box hot spot to put it always on top
140 			bf->yhotspot = 200;
141 		}
142 	}
143 	_vm->bankMan()->close(JOURNAL_BANK);
144 
145 	_textField.x = 136;
146 	_textField.y = 9;
147 	_textField.w = 146;
148 	_textField.h = 13;
149 }
150 
redraw()151 void Journal::redraw() {
152 	drawNormalPanel();
153 	drawConfigPanel();
154 	drawSaveDescriptions();
155 	drawSaveSlot();
156 }
157 
update()158 void Journal::update() {
159 	_vm->graphics()->sortBobs();
160 	_vm->display()->prepareUpdate();
161 	_vm->graphics()->drawBobs();
162 	if (_textField.enabled) {
163 		int16 x = _textField.x + _textField.posCursor;
164 		int16 y = _textField.y + _currentSaveSlot * _textField.h + 8;
165 		_vm->display()->drawBox(x, y, x + 6, y, _vm->display()->getInkColor(INK_JOURNAL));
166 	}
167 	_vm->display()->forceFullRefresh();
168 	_vm->display()->update();
169 	_system->updateScreen();
170 }
171 
showBob(int bobNum,int16 x,int16 y,int frameNum)172 void Journal::showBob(int bobNum, int16 x, int16 y, int frameNum) {
173 	BobSlot *bob = _vm->graphics()->bob(bobNum);
174 	bob->curPos(x, y);
175 	bob->frameNum = JOURNAL_FRAMES + frameNum;
176 }
177 
hideBob(int bobNum)178 void Journal::hideBob(int bobNum) {
179 	_vm->graphics()->bob(bobNum)->active = false;
180 }
181 
drawSaveDescriptions()182 void Journal::drawSaveDescriptions() {
183 	for (int i = 0; i < NUM_SAVES_PER_PAGE; ++i) {
184 		int n = _currentSavePage * 10 + i;
185 		char nb[4];
186 		sprintf(nb, "%d", n + 1);
187 		int y = _textField.y + i * _textField.h;
188 		_vm->display()->setText(_textField.x, y, _saveDescriptions[n], false);
189 		_vm->display()->setText(_textField.x - 27, y + 1, nb, false);
190 	}
191 	// highlight current page
192 	showBob(BOB_SAVE_PAGE, 300, 3 + _currentSavePage * 15, 6 + _currentSavePage);
193 }
194 
drawSaveSlot()195 void Journal::drawSaveSlot() {
196 	showBob(BOB_SAVE_DESC, 130, 6 + _currentSaveSlot * 13, 17);
197 }
198 
enterYesNoPanelMode(int16 prevZoneNum,int titleNum)199 void Journal::enterYesNoPanelMode(int16 prevZoneNum, int titleNum) {
200 	_panelMode = PM_YES_NO;
201 	_prevZoneNum = prevZoneNum;
202 	drawYesNoPanel(titleNum);
203 }
204 
exitYesNoPanelMode()205 void Journal::exitYesNoPanelMode() {
206 	_panelMode = PM_NORMAL;
207 	if (_prevZoneNum == ZN_MAKE_ENTRY) {
208 		closeTextField();
209 	}
210 	redraw();
211 }
212 
enterInfoPanelMode()213 void Journal::enterInfoPanelMode() {
214 	_panelMode = PM_INFO_BOX;
215 	_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
216 	drawInfoPanel();
217 }
218 
exitInfoPanelMode()219 void Journal::exitInfoPanelMode() {
220 	_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
221 	hideBob(BOB_INFO_BOX);
222 	redraw();
223 	_panelMode = PM_NORMAL;
224 }
225 
handleKeyDown(uint16 ascii,int keycode)226 void Journal::handleKeyDown(uint16 ascii, int keycode) {
227 	switch (_panelMode) {
228 	case PM_INFO_BOX:
229 		break;
230 	case PM_YES_NO:
231 		if (keycode == Common::KEYCODE_ESCAPE) {
232 			exitYesNoPanelMode();
233 		} else if (_textField.enabled) {
234 			updateTextField(ascii, keycode);
235 		}
236 		break;
237 	case PM_NORMAL:
238 		if (keycode == Common::KEYCODE_ESCAPE) {
239 			_quitMode = QM_CONTINUE;
240 		}
241 		break;
242 	}
243 }
244 
handleMouseWheel(int inc)245 void Journal::handleMouseWheel(int inc) {
246 	if (_panelMode == PM_NORMAL) {
247 		int curSave = _currentSavePage * NUM_SAVES_PER_PAGE + _currentSaveSlot + inc;
248 		if (curSave >= 0 && curSave < NUM_SAVES_PER_PAGE * 10) {
249 			_currentSavePage = curSave / NUM_SAVES_PER_PAGE;
250 			_currentSaveSlot = curSave % NUM_SAVES_PER_PAGE;
251 			drawSaveDescriptions();
252 			drawSaveSlot();
253 			update();
254 		}
255 	}
256 }
257 
handleMouseDown(int x,int y)258 void Journal::handleMouseDown(int x, int y) {
259 	int val;
260 	int16 zoneNum = _vm->grid()->findZoneForPos(GS_ROOM, x, y);
261 	switch (_panelMode) {
262 	case PM_INFO_BOX:
263 		exitInfoPanelMode();
264 		break;
265 	case PM_YES_NO:
266 		if (zoneNum == ZN_YES) {
267 			_panelMode = PM_NORMAL;
268 			int currentSlot = _currentSavePage * 10 + _currentSaveSlot;
269 			switch (_prevZoneNum) {
270 			case ZN_REVIEW_ENTRY:
271 				if (_saveDescriptions[currentSlot][0]) {
272 					_vm->graphics()->clearBobs();
273 					_vm->display()->palFadeOut(ROOM_JOURNAL);
274 					_vm->sound()->stopSong();
275 					_vm->loadGameState(currentSlot);
276 					_vm->display()->clearTexts(0, GAME_SCREEN_HEIGHT - 1);
277 					_quitMode = QM_RESTORE;
278 				} else {
279 					exitYesNoPanelMode();
280 				}
281 				break;
282 			case ZN_MAKE_ENTRY:
283 				if (_textField.text[0]) {
284 					closeTextField();
285 					_vm->saveGameState(currentSlot, _textField.text);
286 					_quitMode = QM_CONTINUE;
287 				} else {
288 					exitYesNoPanelMode();
289 				}
290 				break;
291 			case ZN_GIVEUP:
292 				_quitMode = QM_CONTINUE;
293 				_vm->quitGame();
294 				break;
295 			}
296 		} else if (zoneNum == ZN_NO) {
297 			exitYesNoPanelMode();
298 		}
299 		break;
300 	case PM_NORMAL:
301 		switch (zoneNum) {
302 		case ZN_REVIEW_ENTRY:
303 			enterYesNoPanelMode(zoneNum, TXT_REVIEW_ENTRY);
304 			break;
305 		case ZN_MAKE_ENTRY:
306 			initTextField(_saveDescriptions[_currentSavePage * 10 + _currentSaveSlot]);
307 			enterYesNoPanelMode(zoneNum, TXT_MAKE_ENTRY);
308 			break;
309 		case ZN_CLOSE:
310 			_quitMode = QM_CONTINUE;
311 			break;
312 		case ZN_GIVEUP:
313 			enterYesNoPanelMode(zoneNum, TXT_GIVE_UP);
314 			break;
315 		case ZN_TEXT_SPEED:
316 			val = (x - 136) * QueenEngine::MAX_TEXT_SPEED / (266 - 136);
317 			_vm->talkSpeed(val);
318 			drawConfigPanel();
319 			break;
320 		case ZN_SFX_TOGGLE:
321 			_vm->sound()->toggleSfx();
322 			drawConfigPanel();
323 			break;
324 		case ZN_MUSIC_VOLUME:
325 			val = (x - 136) * Audio::Mixer::kMaxMixerVolume / (266 - 136);
326 			_vm->sound()->setVolume(val);
327 			drawConfigPanel();
328 			break;
329 		case ZN_DESC_1:
330 		case ZN_DESC_2:
331 		case ZN_DESC_3:
332 		case ZN_DESC_4:
333 		case ZN_DESC_5:
334 		case ZN_DESC_6:
335 		case ZN_DESC_7:
336 		case ZN_DESC_8:
337 		case ZN_DESC_9:
338 		case ZN_DESC_10:
339 			_currentSaveSlot = zoneNum - ZN_DESC_1;
340 			drawSaveSlot();
341 			break;
342 		case ZN_PAGE_A:
343 		case ZN_PAGE_B:
344 		case ZN_PAGE_C:
345 		case ZN_PAGE_D:
346 		case ZN_PAGE_E:
347 		case ZN_PAGE_F:
348 		case ZN_PAGE_G:
349 		case ZN_PAGE_H:
350 		case ZN_PAGE_I:
351 		case ZN_PAGE_J:
352 			_currentSavePage = zoneNum - ZN_PAGE_A;
353 			drawSaveDescriptions();
354 			break;
355 		case ZN_INFO_BOX:
356 			enterInfoPanelMode();
357 			break;
358 		case ZN_MUSIC_TOGGLE:
359 			_vm->sound()->toggleMusic();
360 			if (_vm->sound()->musicOn()) {
361 				_vm->sound()->playLastSong();
362 			} else {
363 				_vm->sound()->stopSong();
364 			}
365 			drawConfigPanel();
366 			break;
367 		case ZN_VOICE_TOGGLE:
368 			_vm->sound()->toggleSpeech();
369 			drawConfigPanel();
370 			break;
371 		case ZN_TEXT_TOGGLE:
372 			_vm->subtitles(!_vm->subtitles());
373 			drawConfigPanel();
374 			break;
375 		}
376 		break;
377 	}
378 	update();
379 }
380 
removeLeadingAndTrailingSpaces(char * dst,size_t dstSize,const char * src)381 static void removeLeadingAndTrailingSpaces(char *dst, size_t dstSize, const char* src) {
382 	assert(dstSize > 0);
383 	size_t srcLen = strlen(src);
384 	if (0 == srcLen) {
385 		dst[0] = '\0';
386 		return;
387 	}
388 
389 	size_t firstNonSpaceIndex;
390 	for (firstNonSpaceIndex = 0; firstNonSpaceIndex < srcLen; ++firstNonSpaceIndex) {
391 		if (src[firstNonSpaceIndex] != ' ')
392 			break;
393 	}
394 	if (firstNonSpaceIndex == srcLen) {
395 		dst[0] = '\0';
396 		return;
397 	}
398 
399 	size_t lastNonSpaceIndex = srcLen - 1;
400 	while (src[lastNonSpaceIndex] == ' ')
401 		--lastNonSpaceIndex;
402 
403 	uint newLen = lastNonSpaceIndex - firstNonSpaceIndex + 1;
404 	assert(newLen < dstSize);
405 	for (size_t i = 0; i < newLen; ++i) {
406 		dst[i] = src[firstNonSpaceIndex + i];
407 	}
408 	dst[newLen] = '\0';
409 }
410 
drawPanelText(int y,const char * text)411 void Journal::drawPanelText(int y, const char *text) {
412 	debug(7, "Journal::drawPanelText(%d, '%s')", y, text);
413 
414 	char s[128];
415 	removeLeadingAndTrailingSpaces(s, 128, text); // necessary for spanish version
416 
417 	// draw the substrings
418 	char *p = strchr(s, ' ');
419 	if (!p) {
420 		int x = (128 - _vm->display()->textWidth(s)) / 2;
421 		_vm->display()->setText(x, y, s, false);
422 		assert(_panelTextCount < MAX_PANEL_TEXTS);
423 		_panelTextY[_panelTextCount++] = y;
424 	} else {
425 		*p++ = '\0';
426 		if (_vm->resource()->getLanguage() == Common::HE_ISR) {
427 			drawPanelText(y - 5, p);
428 			drawPanelText(y + 5, s);
429 		} else {
430 			drawPanelText(y - 5, s);
431 			drawPanelText(y + 5, p);
432 		}
433 	}
434 }
435 
drawCheckBox(bool active,int bobNum,int16 x,int16 y,int frameNum)436 void Journal::drawCheckBox(bool active, int bobNum, int16 x, int16 y, int frameNum) {
437 	if (active) {
438 		showBob(bobNum, x, y, frameNum);
439 	} else {
440 		hideBob(bobNum);
441 	}
442 }
443 
drawSlideBar(int value,int maxValue,int bobNum,int16 y,int frameNum)444 void Journal::drawSlideBar(int value, int maxValue, int bobNum, int16 y, int frameNum) {
445 	showBob(bobNum, 136 + value * (266 - 136) / maxValue, y, frameNum);
446 }
447 
drawPanel(const int * frames,const int * titles,int n)448 void Journal::drawPanel(const int *frames, const int *titles, int n) {
449 	for (int i = 0; i < _panelTextCount; ++i) {
450 		_vm->display()->clearTexts(_panelTextY[i], _panelTextY[i]);
451 	}
452 	_panelTextCount = 0;
453 	int bobNum = 1;
454 	int y = 8;
455 	while (n--) {
456 		showBob(bobNum++, 32, y, *frames++);
457 		drawPanelText(y + 12, _vm->logic()->joeResponse(*titles++));
458 		y += 48;
459 	}
460 }
461 
drawNormalPanel()462 void Journal::drawNormalPanel() {
463 	static const int frames[] = { FRAME_BLUE_1, FRAME_BLUE_2, FRAME_BLUE_1, FRAME_ORANGE };
464 	static const int titles[] = { TXT_REVIEW_ENTRY, TXT_MAKE_ENTRY, TXT_CLOSE, TXT_GIVE_UP };
465 	drawPanel(frames, titles, 4);
466 }
467 
drawYesNoPanel(int titleNum)468 void Journal::drawYesNoPanel(int titleNum) {
469 	static const int frames[] = { FRAME_GREY, FRAME_BLUE_1, FRAME_BLUE_2 };
470 	const int titles[] = { titleNum, TXT_YES, TXT_NO };
471 	drawPanel(frames, titles, 3);
472 
473 	hideBob(BOB_LEFT_RECT_4);
474 	hideBob(BOB_TALK_SPEED);
475 	hideBob(BOB_SFX_TOGGLE);
476 	hideBob(BOB_MUSIC_VOLUME);
477 	hideBob(BOB_SPEECH_TOGGLE);
478 	hideBob(BOB_TEXT_TOGGLE);
479 	hideBob(BOB_MUSIC_TOGGLE);
480 }
481 
drawConfigPanel()482 void Journal::drawConfigPanel() {
483 	_vm->checkOptionSettings();
484 
485 	drawSlideBar(_vm->talkSpeed(), QueenEngine::MAX_TEXT_SPEED, BOB_TALK_SPEED, 164, FRAME_BLUE_PIN);
486 	drawSlideBar(_vm->sound()->getVolume(), Audio::Mixer::kMaxMixerVolume, BOB_MUSIC_VOLUME, 177, FRAME_GREEN_PIN);
487 
488 	drawCheckBox(_vm->sound()->sfxOn(), BOB_SFX_TOGGLE, 221, 155, FRAME_CHECK_BOX);
489 	drawCheckBox(_vm->sound()->speechOn(), BOB_SPEECH_TOGGLE, 158, 155, FRAME_CHECK_BOX);
490 	drawCheckBox(_vm->subtitles(), BOB_TEXT_TOGGLE, 125, 167, FRAME_CHECK_BOX);
491 	drawCheckBox(_vm->sound()->musicOn(), BOB_MUSIC_TOGGLE, 125, 181, FRAME_CHECK_BOX);
492 }
493 
drawInfoPanel()494 void Journal::drawInfoPanel() {
495 	showBob(BOB_INFO_BOX, 72, 221, FRAME_INFO_BOX);
496 	const char *ver = _vm->resource()->getJASVersion();
497 	switch (ver[0]) {
498 	case 'P':
499 		_vm->display()->setTextCentered(132, "PC Hard Drive", false);
500 		break;
501 	case 'C':
502 		_vm->display()->setTextCentered(132, "PC CD-ROM", false);
503 		break;
504 	case 'a':
505 		_vm->display()->setTextCentered(132, "Amiga A500/600", false);
506 		break;
507 	}
508 	switch (ver[1]) {
509 	case 'E':
510 		_vm->display()->setTextCentered(144, "English", false);
511 		break;
512 	case 'F' :
513 		_vm->display()->setTextCentered(144, "Fran\x87""ais", false);
514 		break;
515 	case 'G':
516 		_vm->display()->setTextCentered(144, "Deutsch", false);
517 		break;
518 	case 'H':
519 		_vm->display()->setTextCentered(144, "Hebrew", false);
520 		break;
521 	case 'I':
522 		_vm->display()->setTextCentered(144, "Italiano", false);
523 		break;
524 	case 'S':
525 		_vm->display()->setTextCentered(144, "Espa\xA4""ol", false);
526 		break;
527 	}
528 	char versionId[13];
529 	sprintf(versionId, "Version %c.%c%c", ver[2], ver[3], ver[4]);
530 	_vm->display()->setTextCentered(156, versionId, false);
531 }
532 
initTextField(const char * desc)533 void Journal::initTextField(const char *desc) {
534 	_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
535 	_textField.enabled = true;
536 	_textField.posCursor = _vm->display()->textWidth(desc);
537 	_textField.textCharsCount = strlen(desc);
538 	memset(_textField.text, 0, sizeof(_textField.text));
539 	strcpy(_textField.text, desc);
540 }
541 
updateTextField(uint16 ascii,int keycode)542 void Journal::updateTextField(uint16 ascii, int keycode) {
543 	bool dirty = false;
544 	switch (keycode) {
545 	case Common::KEYCODE_BACKSPACE:
546 		if (_textField.textCharsCount > 0) {
547 			--_textField.textCharsCount;
548 			_textField.text[_textField.textCharsCount] = '\0';
549 			dirty = true;
550 		}
551 		break;
552 	case Common::KEYCODE_RETURN:
553 	case Common::KEYCODE_KP_ENTER:
554 		if (_textField.text[0]) {
555 			closeTextField();
556 			int currentSlot = _currentSavePage * 10 + _currentSaveSlot;
557 			_vm->saveGameState(currentSlot, _textField.text);
558 			_quitMode = QM_CONTINUE;
559 		}
560 		break;
561 	default:
562 		if (Common::isPrint((char)ascii) &&
563 			_textField.textCharsCount < (sizeof(_textField.text) - 1) &&
564 			_vm->display()->textWidth(_textField.text) < _textField.w) {
565 			_textField.text[_textField.textCharsCount] = (char)ascii;
566 			++_textField.textCharsCount;
567 			dirty = true;
568 		}
569 		break;
570 	}
571 	if (dirty) {
572 		_vm->display()->setText(_textField.x, _textField.y + _currentSaveSlot * _textField.h, _textField.text, false);
573 		_textField.posCursor = _vm->display()->textWidth(_textField.text);
574 		update();
575 	}
576 }
577 
closeTextField()578 void Journal::closeTextField() {
579 	_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
580 	_textField.enabled = false;
581 }
582 
583 const Journal::Zone Journal::_zones[] = {
584 	{ ZN_REVIEW_ENTRY,  32,   8,  96,  40 },
585 	{ ZN_MAKE_ENTRY,    32,  56,  96,  88 }, // == ZN_YES
586 	{ ZN_CLOSE,         32, 104,  96, 136 }, // == ZN_NO
587 	{ ZN_GIVEUP,        32, 152,  96, 184 },
588 	{ ZN_TEXT_SPEED,   136, 169, 265, 176 },
589 	{ ZN_SFX_TOGGLE,   197, 155, 231, 164 },
590 	{ ZN_MUSIC_VOLUME, 136, 182, 265, 189 },
591 	{ ZN_DESC_1,       131,   7, 290,  18 },
592 	{ ZN_DESC_2,       131,  20, 290,  31 },
593 	{ ZN_DESC_3,       131,  33, 290,  44 },
594 	{ ZN_DESC_4,       131,  46, 290,  57 },
595 	{ ZN_DESC_5,       131,  59, 290,  70 },
596 	{ ZN_DESC_6,       131,  72, 290,  83 },
597 	{ ZN_DESC_7,       131,  85, 290,  96 },
598 	{ ZN_DESC_8,       131,  98, 290, 109 },
599 	{ ZN_DESC_9,       131, 111, 290, 122 },
600 	{ ZN_DESC_10,      131, 124, 290, 135 },
601 	{ ZN_PAGE_A,       300,   4, 319,  17 },
602 	{ ZN_PAGE_B,       300,  19, 319,  32 },
603 	{ ZN_PAGE_C,       300,  34, 319,  47 },
604 	{ ZN_PAGE_D,       300,  49, 319,  62 },
605 	{ ZN_PAGE_E,       300,  64, 319,  77 },
606 	{ ZN_PAGE_F,       300,  79, 319,  92 },
607 	{ ZN_PAGE_G,       300,  94, 319, 107 },
608 	{ ZN_PAGE_H,       300, 109, 319, 122 },
609 	{ ZN_PAGE_I,       300, 124, 319, 137 },
610 	{ ZN_PAGE_J,       300, 139, 319, 152 },
611 	{ ZN_INFO_BOX,     273, 146, 295, 189 },
612 	{ ZN_MUSIC_TOGGLE, 109, 181, 135, 190 },
613 	{ ZN_VOICE_TOGGLE, 134, 155, 168, 164 },
614 	{ ZN_TEXT_TOGGLE,  109, 168, 135, 177 }
615 };
616 
617 } // End of namespace Queen
618