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 Mortville Manor DOS source code
25 * Copyright (c) 1987-1989 Lankhor
26 */
27
28 #include "mortevielle/mortevielle.h"
29
30 #include "mortevielle/dialogs.h"
31 #include "mortevielle/menu.h"
32 #include "mortevielle/mouse.h"
33 #include "mortevielle/outtext.h"
34
35 #include "common/scummsys.h"
36 #include "graphics/cursorman.h"
37
38 namespace Mortevielle {
39
40 /**
41 * Check is a key was pressed
42 * It also delays the engine and check if the screen has to be updated
43 * @remarks Originally called 'keypressed'
44 */
keyPressed()45 bool MortevielleEngine::keyPressed() {
46 // Check for any pending key presses
47 handleEvents();
48
49 // Check if it's time to draw the next frame
50 if (g_system->getMillis() > (_lastGameFrame + GAME_FRAME_DELAY)) {
51 _lastGameFrame = g_system->getMillis();
52
53 _screenSurface->updateScreen();
54
55 _debugger->onFrame();
56 }
57
58 // Delay briefly to keep CPU usage down
59 g_system->delayMillis(5);
60
61 // Return if there are any pending key presses
62 return !_keypresses.empty();
63 }
64
65 /**
66 * Wait for a keypress
67 * @remarks Originally called 'get_ch'
68 */
getChar()69 int MortevielleEngine::getChar() {
70 bool end = false;
71 // If there isn't any pending keypress, wait until there is
72 while (!shouldQuit() && !end) {
73 end = keyPressed();
74 }
75
76 // Return the top keypress
77 return shouldQuit() ? 0 : _keypresses.pop();
78 }
79
80 /**
81 * Handle pending events
82 * @remarks Since the ScummVM screen surface is double height to handle 640x200 using 640x400,
83 * the mouse Y position is divided by 2 to keep the game thinking the Y goes from 0 - 199
84 */
handleEvents()85 bool MortevielleEngine::handleEvents() {
86 Common::Event event;
87 if (!g_system->getEventManager()->pollEvent(event))
88 return false;
89
90 switch (event.type) {
91 case Common::EVENT_LBUTTONDOWN:
92 case Common::EVENT_LBUTTONUP:
93 case Common::EVENT_MOUSEMOVE:
94 _mousePos = Common::Point(event.mouse.x, event.mouse.y / 2);
95 _mouse->_pos.x = event.mouse.x;
96 _mouse->_pos.y = event.mouse.y / 2;
97
98 if (event.type == Common::EVENT_LBUTTONDOWN)
99 _mouseClick = true;
100 else if (event.type == Common::EVENT_LBUTTONUP)
101 _mouseClick = false;
102
103 break;
104 case Common::EVENT_KEYDOWN:
105 addKeypress(event);
106 break;
107 default:
108 break;
109 }
110
111 return true;
112 }
113
114 /**
115 * Add the specified key to the pending keypress stack
116 */
addKeypress(Common::Event & evt)117 void MortevielleEngine::addKeypress(Common::Event &evt) {
118 // Character to add
119 char ch = evt.kbd.ascii;
120
121 // Check for debugger
122 if ((evt.kbd.keycode == Common::KEYCODE_d) && (evt.kbd.flags & Common::KBD_CTRL)) {
123 // Attach to the debugger
124 _debugger->attach();
125 _debugger->onFrame();
126 } else if ((evt.kbd.keycode >= Common::KEYCODE_a) && (evt.kbd.keycode <= Common::KEYCODE_z)) {
127 // Handle alphabetic keys
128 if (evt.kbd.hasFlags(Common::KBD_CTRL))
129 ch = evt.kbd.keycode - Common::KEYCODE_a + 1;
130 else
131 ch = evt.kbd.keycode - Common::KEYCODE_a + 'A';
132 } else if ((evt.kbd.keycode >= Common::KEYCODE_F1) && (evt.kbd.keycode <= Common::KEYCODE_F12)) {
133 // Handle function keys
134 ch = 59 + evt.kbd.keycode - Common::KEYCODE_F1;
135 } else {
136 // Series of special cases
137 switch (evt.kbd.keycode) {
138 case Common::KEYCODE_KP4:
139 case Common::KEYCODE_LEFT:
140 ch = '4';
141 break;
142 case Common::KEYCODE_KP2:
143 case Common::KEYCODE_DOWN:
144 ch = '2';
145 break;
146 case Common::KEYCODE_KP6:
147 case Common::KEYCODE_RIGHT:
148 ch = '6';
149 break;
150 case Common::KEYCODE_KP8:
151 case Common::KEYCODE_UP:
152 ch = '8';
153 break;
154 case Common::KEYCODE_KP7:
155 ch = '7';
156 break;
157 case Common::KEYCODE_KP1:
158 ch = '1';
159 break;
160 case Common::KEYCODE_KP9:
161 ch = '9';
162 break;
163 case Common::KEYCODE_KP3:
164 ch = '3';
165 break;
166 case Common::KEYCODE_KP5:
167 ch = '5';
168 break;
169 case Common::KEYCODE_RETURN:
170 ch = '\13';
171 break;
172 case Common::KEYCODE_ESCAPE:
173 ch = '\33';
174 break;
175 default:
176 break;
177 }
178 }
179
180 if (ch != 0)
181 _keypresses.push(ch);
182 }
183
184
185 static const byte CURSOR_ARROW_DATA[16 * 16] = {
186 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
187 0x0f, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
188 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
189 0x0f, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
190 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
191 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
192 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
193 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
194 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
195 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff,
196 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
197 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
198 0x0f, 0x0f, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
199 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
200 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
201 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
202 };
203
204 /**
205 * Initialize the mouse
206 */
initMouse()207 void MortevielleEngine::initMouse() {
208 CursorMan.replaceCursor(CURSOR_ARROW_DATA, 16, 16, 0, 0, 0xff);
209 CursorMan.showMouse(true);
210
211 _mouse->initMouse();
212 }
213
214 /**
215 * Sets the mouse position
216 * @remarks Since the ScummVM screen surface is double height to handle 640x200 using 640x400,
217 * the mouse Y position is doubled to convert from 0-199 to 0-399
218 */
setMousePos(const Common::Point & pt)219 void MortevielleEngine::setMousePos(const Common::Point &pt) {
220 // Adjust the passed position from simulated 640x200 to 640x400 co-ordinates
221 Common::Point newPoint(pt.x, (pt.y == 199) ? 399 : pt.y * 2);
222
223 if (newPoint != _mousePos)
224 // Warp the mouse to the new position
225 g_system->warpMouse(newPoint.x, newPoint.y);
226
227 // Save the new position
228 _mousePos = newPoint;
229 }
230
231 /**
232 * Delay by a given amount
233 */
delay(int amount)234 void MortevielleEngine::delay(int amount) {
235 uint32 endTime = g_system->getMillis() + amount;
236
237 g_system->showMouse(false);
238 while (g_system->getMillis() < endTime) {
239 if (g_system->getMillis() > (_lastGameFrame + GAME_FRAME_DELAY)) {
240 _lastGameFrame = g_system->getMillis();
241 _screenSurface->updateScreen();
242
243 _debugger->onFrame();
244 }
245
246 g_system->delayMillis(10);
247 }
248 g_system->showMouse(true);
249 }
250
251 /**
252 * Waits for the user to select an action, and then handles it
253 * @remarks Originally called tecran
254 */
handleAction()255 void MortevielleEngine::handleAction() {
256 const int lim = 20000;
257 int temps = 0;
258 char inkey = '\0';
259 bool funct = false;
260
261 clearVerbBar();
262
263 _controlMenu = 0;
264 if (!_keyPressedEsc) {
265 _menu->drawMenu();
266 _menu->_menuDisplayed = true;
267 temps = 0;
268 _key = 0;
269 funct = false;
270 inkey = '.';
271
272 _inMainGameLoop = true;
273 do {
274 _menu->updateMenu();
275 prepareRoom();
276 _mouse->moveMouse(funct, inkey);
277 if (shouldQuit())
278 return;
279 ++temps;
280 if (keyPressed() || _mouseClick) {
281 _soundManager->_mixer->stopHandle(_soundManager->_soundHandle);
282 }
283 } while (!((_menu->_menuSelected) || (temps > lim) || (funct) || (_anyone)));
284 _inMainGameLoop = false;
285
286 _menu->eraseMenu();
287 _menu->_menuDisplayed = false;
288 if (_menu->_menuSelected && (_currMenu == MENU_SAVE)) {
289 Common::String saveName = Common::String::format("Savegame #%d", _currAction & 15);
290 _savegameManager->saveGame(_currAction & 15, saveName);
291 }
292 if (_menu->_menuSelected && (_currMenu == MENU_LOAD))
293 _savegameManager->loadGame((_currAction & 15) - 1);
294 if (inkey == '\103') { /* F9 */
295 temps = _dialogManager->show(_hintPctMessage);
296 return;
297 } else if (inkey == '\77') {
298 if ((_menuOpcode != OPCODE_NONE) && ((_currMenu == MENU_ACTION) || (_currMenu == MENU_SELF))) {
299 _currAction = _menuOpcode;
300 displayTextInVerbBar(getEngineString(S_IDEM));
301 } else
302 return;
303 } else if (inkey == '\104') {
304 if ((_x != 0) && (_y != 0))
305 _num = 9999;
306 return;
307 }
308 }
309 if (inkey == '\73') {
310 _quitGame = true;
311 hourToChar();
312 } else {
313 if ((funct) && (inkey != '\77'))
314 return;
315 if (temps > lim) {
316 handleDescriptionText(2, 141);
317 if (_num == 9999)
318 _num = 0;
319 } else {
320 _menuOpcode = _currMenu;
321 if ((_currMenu == MENU_ACTION) || (_currMenu == MENU_SELF))
322 _menuOpcode = _currAction;
323 bool handledOpcodeFl = false;
324 if (!_anyone) {
325 if ((_heroSearching) || (_obpart)) {
326 if (_mouse->_pos.y < 12)
327 return;
328
329 if ((_currAction == _menu->_opcodeSound) || (_currAction == _menu->_opcodeLift)) {
330 handledOpcodeFl = true;
331 if ((_currAction == _menu->_opcodeLift) || (_obpart)) {
332 endSearch();
333 _caff = _coreVar._currPlace;
334 _crep = 998;
335 } else
336 prepareNextObject();
337 menuUp();
338 }
339 }
340 }
341 do {
342 if (!handledOpcodeFl)
343 handleOpcode();
344
345 if ((_controlMenu == 0) && (! _loseGame) && (! _endGame)) {
346 _text->taffich();
347 if (_destinationOk) {
348 _destinationOk = false;
349 drawPicture();
350 }
351 if ((!_syn) || (_col))
352 handleDescriptionText(2, _crep);
353 }
354 } while (_syn);
355 if (_controlMenu != 0)
356 displayControlMenu();
357 }
358 }
359 }
360
361 /**
362 * Engine function - Init Places
363 * @remarks Originally called 'init_lieu'
364 */
loadPlaces()365 void MortevielleEngine::loadPlaces() {
366 Common::File f;
367
368 if (!f.open("MXX.mor"))
369 if (!f.open("MFXX.mor"))
370 error("Missing file - MXX.mor");
371
372 for (int i = 0; i < 7; ++i) {
373 for (int j = 0; j < 25; ++j)
374 _destinationArray[i][j] = f.readByte();
375 }
376
377 f.close();
378 }
379
380 /**
381 * Set Text Color
382 * @remarks Originally called 'text_color'
383 */
setTextColor(int col)384 void MortevielleEngine::setTextColor(int col) {
385 _textColor = col;
386 }
387
388 /**
389 * Prepare screen - Type 1!
390 * @remarks Originally called 'ecrf1'
391 */
prepareScreenType1()392 void MortevielleEngine::prepareScreenType1() {
393 // Large drawing
394 _screenSurface->drawBox(0, 11, 512, 163, 15);
395 }
396
397 /**
398 * Prepare room - Type 2!
399 * @remarks Originally called 'ecrf2'
400 */
prepareScreenType2()401 void MortevielleEngine::prepareScreenType2() {
402 setTextColor(5);
403 }
404
405 /**
406 * Prepare room - Type 3!
407 * @remarks Originally called 'ecrf7'
408 */
prepareScreenType3()409 void MortevielleEngine::prepareScreenType3() {
410 setTextColor(4);
411 }
412
413 /**
414 * Engine function - Update hour
415 * @remarks Originally called 'calch'
416 */
updateHour(int & day,int & hour,int & minute)417 void MortevielleEngine::updateHour(int &day, int &hour, int &minute) {
418 int newTime = readclock();
419 int th = _currentHourCount + ((newTime - _currentTime) / _inGameHourDuration);
420 minute = ((th % 2) + _currHalfHour) * 30;
421 hour = ((uint)th >> 1) + _currHour;
422 if (minute == 60) {
423 minute = 0;
424 ++hour;
425 }
426 day = (hour / 24) + _currDay;
427 hour = hour - ((day - _currDay) * 24);
428 }
429
430 /**
431 * Engine function - Convert character index to bit index
432 * @remarks Originally called 'conv'
433 */
convertCharacterIndexToBitIndex(int characterIndex)434 int MortevielleEngine::convertCharacterIndexToBitIndex(int characterIndex) {
435 return 128 >> (characterIndex - 1);
436 }
437
438 /**
439 * Engine function - Convert bit index to character index
440 * @remarks Originally called 'tip'
441 */
convertBitIndexToCharacterIndex(int bitIndex)442 int MortevielleEngine::convertBitIndexToCharacterIndex(int bitIndex) {
443 int retVal = 0;
444
445 if (bitIndex == 128)
446 retVal = 1;
447 else if (bitIndex == 64)
448 retVal = 2;
449 else if (bitIndex == 32)
450 retVal = 3;
451 else if (bitIndex == 16)
452 retVal = 4;
453 else if (bitIndex == 8)
454 retVal = 5;
455 else if (bitIndex == 4)
456 retVal = 6;
457 else if (bitIndex == 2)
458 retVal = 7;
459 else if (bitIndex == 1)
460 retVal = 8;
461
462 return retVal;
463 }
464
465 /**
466 * Engine function - Reset presence in other rooms
467 * @remarks Originally called 't5'
468 */
resetPresenceInRooms(int roomId)469 void MortevielleEngine::resetPresenceInRooms(int roomId) {
470 if (roomId == DINING_ROOM)
471 _outsideOnlyFl = false;
472
473 if (roomId != GREEN_ROOM) {
474 _roomPresenceLuc = false;
475 _roomPresenceIda = false;
476 }
477
478 if (roomId != PURPLE_ROOM)
479 _purpleRoomPresenceLeo = false;
480
481 if (roomId != DARKBLUE_ROOM) {
482 _roomPresenceGuy = false;
483 _roomPresenceEva = false;
484 }
485
486 if (roomId != BLUE_ROOM)
487 _roomPresenceMax = false;
488 if (roomId != RED_ROOM)
489 _roomPresenceBob = false;
490 if (roomId != GREEN_ROOM2)
491 _roomPresencePat = false;
492 if (roomId != TOILETS)
493 _toiletsPresenceBobMax = false;
494 if (roomId != BATHROOM)
495 _bathRoomPresenceBobMax = false;
496 if (roomId != JULIA_ROOM)
497 _juliaRoomPresenceLeo = false;
498 }
499
500 /**
501 * Engine function - Show the people present in the given room
502 * @remarks Originally called 'affper'
503 */
showPeoplePresent(int bitIndex)504 void MortevielleEngine::showPeoplePresent(int bitIndex) {
505 int xp = 580 - (_screenSurface->getStringWidth("LEO") / 2);
506
507 for (int i = 1; i <= 8; ++i)
508 _menu->disableMenuItem(_menu->_discussMenu[i]);
509
510 clearUpperRightPart();
511 if ((bitIndex & 128) == 128) {
512 _screenSurface->putxy(xp, 24);
513 _screenSurface->drawString("LEO", 4);
514 _menu->enableMenuItem(_menu->_discussMenu[1]);
515 }
516 if ((bitIndex & 64) == 64) {
517 _screenSurface->putxy(xp, 32);
518 _screenSurface->drawString("PAT", 4);
519 _menu->enableMenuItem(_menu->_discussMenu[2]);
520 }
521 if ((bitIndex & 32) == 32) {
522 _screenSurface->putxy(xp, 40);
523 _screenSurface->drawString("GUY", 4);
524 _menu->enableMenuItem(_menu->_discussMenu[3]);
525 }
526 if ((bitIndex & 16) == 16) {
527 _screenSurface->putxy(xp, 48);
528 _screenSurface->drawString("EVA", 4);
529 _menu->enableMenuItem(_menu->_discussMenu[4]);
530 }
531 if ((bitIndex & 8) == 8) {
532 _screenSurface->putxy(xp, 56);
533 _screenSurface->drawString("BOB", 4);
534 _menu->enableMenuItem(_menu->_discussMenu[5]);
535 }
536 if ((bitIndex & 4) == 4) {
537 _screenSurface->putxy(xp, 64);
538 _screenSurface->drawString("LUC", 4);
539 _menu->enableMenuItem(_menu->_discussMenu[6]);
540 }
541 if ((bitIndex & 2) == 2) {
542 _screenSurface->putxy(xp, 72);
543 _screenSurface->drawString("IDA", 4);
544 _menu->enableMenuItem(_menu->_discussMenu[7]);
545 }
546 if ((bitIndex & 1) == 1) {
547 _screenSurface->putxy(xp, 80);
548 _screenSurface->drawString("MAX", 4);
549 _menu->enableMenuItem(_menu->_discussMenu[8]);
550 }
551 _currBitIndex = bitIndex;
552 }
553
554 /**
555 * Engine function - Select random characters
556 * @remarks Originally called 'choix'
557 */
selectCharacters(int min,int max)558 int MortevielleEngine::selectCharacters(int min, int max) {
559 bool invertSelection = false;
560 int rand = getRandomNumber(min, max);
561
562 if (rand > 4) {
563 rand = 8 - rand;
564 invertSelection = true;
565 }
566
567 int i = 0;
568 int retVal = 0;
569 while (i < rand) {
570 int charIndex = getRandomNumber(1, 8);
571 int charBitIndex = convertCharacterIndexToBitIndex(charIndex);
572 if ((retVal & charBitIndex) != charBitIndex) {
573 ++i;
574 retVal |= charBitIndex;
575 }
576 }
577 if (invertSelection)
578 retVal = 255 - retVal;
579
580 return retVal;
581 }
582
583 /**
584 * Engine function - Get Presence Statistics - Green Room
585 * @remarks Originally called 'cpl1'
586 */
getPresenceStatsGreenRoom()587 int MortevielleEngine::getPresenceStatsGreenRoom() {
588 int day, hour, minute;
589 int retVal = 0;
590
591 updateHour(day, hour, minute);
592 // The original uses an || instead of an &&, resulting
593 // in an always true condition. Based on the other tests,
594 // and on other scenes, we use an && instead.
595 if ((hour > 7) && (hour < 11))
596 retVal = 25;
597 else if ((hour > 10) && (hour < 14))
598 retVal = 35;
599 else if ((hour > 13) && (hour < 16))
600 retVal = 50;
601 else if ((hour > 15) && (hour < 18))
602 retVal = 5;
603 else if ((hour > 17) && (hour < 22))
604 retVal = 35;
605 else if ((hour > 21) && (hour < 24))
606 retVal = 50;
607 else if ((hour >= 0) && (hour < 8))
608 retVal = 70;
609
610 _menu->updateMenu();
611
612 return retVal;
613 }
614 /**
615 * Engine function - Get Presence Statistics - Purple Room
616 * @remarks Originally called 'cpl2'
617 */
getPresenceStatsPurpleRoom()618 int MortevielleEngine::getPresenceStatsPurpleRoom() {
619 int day, hour, minute;
620 int retVal = 0;
621
622 updateHour(day, hour, minute);
623 if ((hour > 7) && (hour < 11))
624 retVal = -2;
625 else if (hour == 11)
626 retVal = 100;
627 else if ((hour > 11) && (hour < 23))
628 retVal = 10;
629 else if (hour == 23)
630 retVal = 20;
631 else if ((hour >= 0) && (hour < 8))
632 retVal = 50;
633
634 return retVal;
635 }
636
637 /**
638 * Engine function - Get Presence Statistics - Toilets
639 * @remarks Originally called 'cpl3'
640 */
getPresenceStatsToilets()641 int MortevielleEngine::getPresenceStatsToilets() {
642 int day, hour, minute;
643 int retVal = 0;
644
645 updateHour(day, hour, minute);
646 if (((hour > 8) && (hour < 10)) || ((hour > 19) && (hour < 24)))
647 retVal = 34;
648 else if (((hour > 9) && (hour < 20)) || ((hour >= 0) && (hour < 9)))
649 retVal = 0;
650
651 return retVal;
652 }
653
654 /**
655 * Engine function - Get Presence Statistics - Blue Room
656 * @remarks Originally called 'cpl5'
657 */
getPresenceStatsBlueRoom()658 int MortevielleEngine::getPresenceStatsBlueRoom() {
659 int day, hour, minute;
660 int retVal = 0;
661
662 updateHour(day, hour, minute);
663 if ((hour > 6) && (hour < 10))
664 retVal = 0;
665 else if (hour == 10)
666 retVal = 100;
667 else if ((hour > 10) && (hour < 24))
668 retVal = 15;
669 else if ((hour >= 0) && (hour < 7))
670 retVal = 50;
671
672 return retVal;
673 }
674
675 /**
676 * Engine function - Get Presence Statistics - Red Room
677 * @remarks Originally called 'cpl6'
678 */
getPresenceStatsRedRoom()679 int MortevielleEngine::getPresenceStatsRedRoom() {
680 int day, hour, minute;
681 int retVal = 0;
682
683 updateHour(day, hour, minute);
684 if (((hour > 7) && (hour < 13)) || ((hour > 17) && (hour < 20)))
685 retVal = -2;
686 else if (((hour > 12) && (hour < 17)) || ((hour > 19) && (hour < 24)))
687 retVal = 35;
688 else if (hour == 17)
689 retVal = 100;
690 else if ((hour >= 0) && (hour < 8))
691 retVal = 60;
692
693 return retVal;
694 }
695
696 /**
697 * Shows the "you are alone" message in the status area
698 * on the right hand side of the screen
699 * @remarks Originally called 'person'
700 */
displayAloneText()701 void MortevielleEngine::displayAloneText() {
702 for (int i = 1; i <= 8; ++i)
703 _menu->disableMenuItem(_menu->_discussMenu[i]);
704
705 Common::String sYou = getEngineString(S_YOU);
706 Common::String sAre = getEngineString(S_ARE);
707 Common::String sAlone = getEngineString(S_ALONE);
708
709 clearUpperRightPart();
710 _screenSurface->putxy(560, 30);
711 _screenSurface->drawString(sYou, 4);
712 _screenSurface->putxy(560, 50);
713 _screenSurface->drawString(sAre, 4);
714 _screenSurface->putxy(560, 70);
715 _screenSurface->drawString(sAlone, 4);
716
717 _currBitIndex = 0;
718 }
719
720 /**
721 * Engine function - Get Presence Statistics - Room Bureau
722 * @remarks Originally called 'cpl10'
723 */
getPresenceStatsDiningRoom(int & hour)724 int MortevielleEngine::getPresenceStatsDiningRoom(int &hour) {
725 int day, minute;
726
727 int retVal = 0;
728 updateHour(day, hour, minute);
729 if (((hour > 7) && (hour < 11)) || ((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21)))
730 retVal = 100;
731 else if ((hour == 11) || ((hour > 20) && (hour < 24)))
732 retVal = 45;
733 else if (((hour > 13) && (hour < 17)) || (hour == 18))
734 retVal = 35;
735 else if (hour == 17)
736 retVal = 60;
737 else if ((hour >= 0) && (hour < 8))
738 retVal = 5;
739
740 return retVal;
741 }
742
743 /**
744 * Engine function - Get Presence Statistics - Room Bureau
745 * @remarks Originally called 'cpl11'
746 */
getPresenceStatsBureau(int & hour)747 int MortevielleEngine::getPresenceStatsBureau(int &hour) {
748 int day, minute;
749 int retVal = 0;
750
751 updateHour(day, hour, minute);
752 if (((hour > 8) && (hour < 12)) || ((hour > 20) && (hour < 24)))
753 retVal = 25;
754 else if (((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21)))
755 retVal = 5;
756 else if ((hour > 13) && (hour < 17))
757 retVal = 55;
758 else if ((hour > 16) && (hour < 19))
759 retVal = 45;
760 else if ((hour >= 0) && (hour < 9))
761 retVal = 0;
762
763 return retVal;
764 }
765
766 /**
767 * Engine function - Get Presence Statistics - Room Kitchen
768 * @remarks Originally called 'cpl12'
769 */
getPresenceStatsKitchen()770 int MortevielleEngine::getPresenceStatsKitchen() {
771 int day, hour, minute;
772 int retVal = 0;
773
774 updateHour(day, hour, minute);
775 if (((hour > 8) && (hour < 15)) || ((hour > 16) && (hour < 22)))
776 retVal = 55;
777 else if (((hour > 14) && (hour < 17)) || ((hour > 21) && (hour < 24)))
778 retVal = 25;
779 else if ((hour >= 0) && (hour < 5))
780 retVal = 0;
781 else if ((hour > 4) && (hour < 9))
782 retVal = 15;
783
784 return retVal;
785 }
786
787 /**
788 * Engine function - Get Presence Statistics - Room Attic
789 * @remarks Originally called 'cpl13'
790 */
getPresenceStatsAttic()791 int MortevielleEngine::getPresenceStatsAttic() {
792 return 0;
793 }
794
795 /**
796 * Engine function - Get Presence Statistics - Room Landing
797 * @remarks Originally called 'cpl15'
798 */
getPresenceStatsLanding()799 int MortevielleEngine::getPresenceStatsLanding() {
800 int day, hour, minute;
801 int retVal = 0;
802
803 updateHour(day, hour, minute);
804 if ((hour > 7) && (hour < 12))
805 retVal = 25;
806 else if ((hour > 11) && (hour < 14))
807 retVal = 0;
808 else if ((hour > 13) && (hour < 18))
809 retVal = 10;
810 else if ((hour > 17) && (hour < 20))
811 retVal = 55;
812 else if ((hour > 19) && (hour < 22))
813 retVal = 5;
814 else if ((hour > 21) && (hour < 24))
815 retVal = 15;
816 else if ((hour >= 0) && (hour < 8))
817 retVal = -15;
818
819 return retVal;
820 }
821
822 /**
823 * Engine function - Get Presence Statistics - Room Chapel
824 * @remarks Originally called 'cpl20'
825 */
getPresenceStatsChapel(int & hour)826 int MortevielleEngine::getPresenceStatsChapel(int &hour) {
827 int day, minute;
828 int retVal = 0;
829
830 updateHour(day, hour, minute);
831 if (hour == 10)
832 retVal = 65;
833 else if ((hour > 10) && (hour < 21))
834 retVal = 5;
835 else if ((hour > 20) && (hour < 24))
836 retVal = -15;
837 else if ((hour >= 0) && (hour < 5))
838 retVal = -300;
839 else if ((hour > 4) && (hour < 10))
840 retVal = -5;
841
842 return retVal;
843 }
844
845 /**
846 * Engine function - Check who is in the Green Room
847 * @remarks Originally called 'quelq1'
848 */
setPresenceGreenRoom(int roomId)849 void MortevielleEngine::setPresenceGreenRoom(int roomId) {
850 int rand = getRandomNumber(1, 2);
851 if (roomId == GREEN_ROOM) {
852 if (rand == 1)
853 _roomPresenceLuc = true;
854 else
855 _roomPresenceIda = true;
856 } else if (roomId == DARKBLUE_ROOM) {
857 if (rand == 1)
858 _roomPresenceGuy = true;
859 else
860 _roomPresenceEva = true;
861 }
862
863 _currBitIndex = 10;
864 }
865
866 /**
867 * Engine function - Check who is in the Purple Room
868 * @remarks Originally called 'quelq2'
869 */
setPresencePurpleRoom()870 void MortevielleEngine::setPresencePurpleRoom() {
871 if (_place == PURPLE_ROOM)
872 _purpleRoomPresenceLeo = true;
873 else
874 _juliaRoomPresenceLeo = true;
875
876 _currBitIndex = 10;
877 }
878
879 /**
880 * Engine function - Check who is in the Blue Room
881 * @remarks Originally called 'quelq5'
882 */
setPresenceBlueRoom()883 void MortevielleEngine::setPresenceBlueRoom() {
884 _roomPresenceMax = true;
885 _currBitIndex = 10;
886 }
887
888 /**
889 * Engine function - Check who is in the Red Room
890 * @remarks Originally called 'quelq6'
891 */
setPresenceRedRoom(int roomId)892 void MortevielleEngine::setPresenceRedRoom(int roomId) {
893 if (roomId == RED_ROOM)
894 _roomPresenceBob = true;
895 else if (roomId == GREEN_ROOM2)
896 _roomPresencePat = true;
897
898 _currBitIndex = 10;
899 }
900
901 /**
902 * Engine function - Check who is in the Dining Room
903 * @remarks Originally called 'quelq10'
904 */
setPresenceDiningRoom(int hour)905 int MortevielleEngine::setPresenceDiningRoom(int hour) {
906 int retVal = 0;
907
908 if ((hour >= 0) && (hour < 8))
909 retVal = checkLeoMaxRandomPresence();
910 else {
911 int min = 0, max = 0;
912 if ((hour > 7) && (hour < 10)) {
913 min = 5;
914 max = 7;
915 } else if ((hour > 9) && (hour < 12)) {
916 min = 1;
917 max = 4;
918 } else if (((hour > 11) && (hour < 15)) || ((hour > 18) && (hour < 21))) {
919 min = 6;
920 max = 8;
921 } else if (((hour > 14) && (hour < 19)) || ((hour > 20) && (hour < 24))) {
922 min = 1;
923 max = 5;
924 }
925 retVal = selectCharacters(min, max);
926 }
927 showPeoplePresent(retVal);
928
929 return retVal;
930 }
931
932 /**
933 * Engine function - Check who is in the Bureau
934 * @remarks Originally called 'quelq11'
935 */
setPresenceBureau(int hour)936 int MortevielleEngine::setPresenceBureau(int hour) {
937 int retVal = 0;
938
939 if ((hour >= 0) && (hour < 8))
940 retVal = checkLeoMaxRandomPresence();
941 else {
942 int min = 0, max = 0;
943 if (((hour > 7) && (hour < 10)) || ((hour > 20) && (hour < 24))) {
944 min = 1;
945 max = 3;
946 } else if (((hour > 9) && (hour < 12)) || ((hour > 13) && (hour < 19))) {
947 min = 1;
948 max = 4;
949 } else if (((hour > 11) && (hour < 14)) || ((hour > 18) && (hour < 21))) {
950 min = 1;
951 max = 2;
952 }
953 retVal = selectCharacters(min, max);
954 }
955 showPeoplePresent(retVal);
956
957 return retVal;
958 }
959
960 /**
961 * Engine function - Check who is in the Kitchen
962 * @remarks Originally called 'quelq12'
963 */
setPresenceKitchen()964 int MortevielleEngine::setPresenceKitchen() {
965 int retVal = checkLeoMaxRandomPresence();
966 showPeoplePresent(retVal);
967
968 return retVal;
969 }
970
971 /**
972 * Engine function - Check who is in the Landing
973 * @remarks Originally called 'quelq15'
974 */
setPresenceLanding()975 int MortevielleEngine::setPresenceLanding() {
976 bool test = false;
977 int rand = 0;
978 do {
979 rand = getRandomNumber(1, 8);
980 test = (((rand == 1) && (_purpleRoomPresenceLeo || _juliaRoomPresenceLeo)) ||
981 ((rand == 2) && _roomPresencePat) ||
982 ((rand == 3) && _roomPresenceGuy) ||
983 ((rand == 4) && _roomPresenceEva) ||
984 ((rand == 5) && _roomPresenceBob) ||
985 ((rand == 6) && _roomPresenceLuc) ||
986 ((rand == 7) && _roomPresenceIda) ||
987 ((rand == 8) && _roomPresenceMax));
988 } while (test);
989
990 int retVal = convertCharacterIndexToBitIndex(rand);
991 showPeoplePresent(retVal);
992
993 return retVal;
994 }
995
996 /**
997 * Engine function - Check who is in the chapel
998 * @remarks Originally called 'quelq20'
999 */
setPresenceChapel(int hour)1000 int MortevielleEngine::setPresenceChapel(int hour) {
1001 int retVal = 0;
1002
1003 if (((hour >= 0) && (hour < 10)) || ((hour > 18) && (hour < 24)))
1004 retVal = checkLeoMaxRandomPresence();
1005 else {
1006 int min = 0, max = 0;
1007 if ((hour > 9) && (hour < 12)) {
1008 min = 3;
1009 max = 7;
1010 } else if ((hour > 11) && (hour < 18)) {
1011 min = 1;
1012 max = 2;
1013 } else if (hour == 18) {
1014 min = 2;
1015 max = 4;
1016 }
1017 retVal = selectCharacters(min, max);
1018 }
1019 showPeoplePresent(retVal);
1020
1021 return retVal;
1022 }
1023
1024 /**
1025 * Engine function - Get the answer after you known a door
1026 * @remarks Originally called 'frap'
1027 */
getKnockAnswer()1028 void MortevielleEngine::getKnockAnswer() {
1029 int day, hour, minute;
1030
1031 updateHour(day, hour, minute);
1032 if ((hour >= 0) && (hour < 8))
1033 _crep = 190;
1034 else {
1035 if (getRandomNumber(1, 100) > 70)
1036 _crep = 190;
1037 else
1038 _crep = 147;
1039 }
1040 }
1041
1042 /**
1043 * Engine function - Get Room Presence Bit Index
1044 * @remarks Originally called 'nouvp'
1045 */
getPresenceBitIndex(int roomId)1046 int MortevielleEngine::getPresenceBitIndex(int roomId) {
1047 int bitIndex = 0;
1048 if (roomId == GREEN_ROOM) {
1049 if (_roomPresenceLuc)
1050 bitIndex = 4; // LUC
1051 if (_roomPresenceIda)
1052 bitIndex = 2; // IDA
1053 } else if ( ((roomId == PURPLE_ROOM) && (_purpleRoomPresenceLeo))
1054 || ((roomId == JULIA_ROOM) && (_juliaRoomPresenceLeo)))
1055 bitIndex = 128; // LEO
1056 else if (roomId == DARKBLUE_ROOM) {
1057 if (_roomPresenceGuy)
1058 bitIndex = 32; // GUY
1059 if (_roomPresenceEva)
1060 bitIndex = 16; // EVA
1061 } else if ((roomId == BLUE_ROOM) && (_roomPresenceMax))
1062 bitIndex = 1; // MAX
1063 else if ((roomId == RED_ROOM) && (_roomPresenceBob))
1064 bitIndex = 8; // BOB
1065 else if ((roomId == GREEN_ROOM2) && (_roomPresencePat))
1066 bitIndex = 64; // PAT
1067 else if ( ((roomId == TOILETS) && (_toiletsPresenceBobMax))
1068 || ((roomId == BATHROOM) && (_bathRoomPresenceBobMax)) )
1069 bitIndex = 9; // BOB + MAX
1070
1071 if (bitIndex != 9)
1072 showPeoplePresent(bitIndex);
1073
1074 return bitIndex;
1075 }
1076
1077 /**
1078 * Engine function - initGame
1079 * @remarks Originally called 'dprog'
1080 */
initGame()1081 void MortevielleEngine::initGame() {
1082 _place = MANOR_FRONT;
1083 _currentHourCount = 0;
1084 if (!_coreVar._alreadyEnteredManor)
1085 _outsideOnlyFl = true;
1086 _inGameHourDuration = kTime1;
1087 _currentTime = readclock();
1088 }
1089
1090 /**
1091 * Engine function - Set Random Presence - Green Room
1092 * @remarks Originally called 'pl1'
1093 */
setRandomPresenceGreenRoom(int faithScore)1094 void MortevielleEngine::setRandomPresenceGreenRoom(int faithScore) {
1095 if ( ((_place == GREEN_ROOM) && (!_roomPresenceLuc) && (!_roomPresenceIda))
1096 || ((_place == DARKBLUE_ROOM) && (!_roomPresenceGuy) && (!_roomPresenceEva)) ) {
1097 int p = getPresenceStatsGreenRoom();
1098 p += faithScore;
1099 if (getRandomNumber(1, 100) > p)
1100 displayAloneText();
1101 else
1102 setPresenceGreenRoom(_place);
1103 }
1104 }
1105
1106 /**
1107 * Engine function - Set Random Presence - Purple Room
1108 * @remarks Originally called 'pl2'
1109 */
setRandomPresencePurpleRoom(int faithScore)1110 void MortevielleEngine::setRandomPresencePurpleRoom(int faithScore) {
1111 if (!_purpleRoomPresenceLeo) {
1112 int p = getPresenceStatsPurpleRoom();
1113 p += faithScore;
1114 if (getRandomNumber(1, 100) > p)
1115 displayAloneText();
1116 else
1117 setPresencePurpleRoom();
1118 }
1119 }
1120
1121 /**
1122 * Engine function - Set Random Presence - Blue Room
1123 * @remarks Originally called 'pl5'
1124 */
setRandomPresenceBlueRoom(int faithScore)1125 void MortevielleEngine::setRandomPresenceBlueRoom(int faithScore) {
1126 if (!_roomPresenceMax) {
1127 int p = getPresenceStatsBlueRoom();
1128 p += faithScore;
1129 if (getRandomNumber(1, 100) > p)
1130 displayAloneText();
1131 else
1132 setPresenceBlueRoom();
1133 }
1134 }
1135
1136 /**
1137 * Engine function - Set Random Presence - Red Room
1138 * @remarks Originally called 'pl6'
1139 */
setRandomPresenceRedRoom(int faithScore)1140 void MortevielleEngine::setRandomPresenceRedRoom(int faithScore) {
1141 if ( ((_place == RED_ROOM) && (!_roomPresenceBob))
1142 || ((_place == GREEN_ROOM2) && (!_roomPresencePat)) ) {
1143 int p = getPresenceStatsRedRoom();
1144 p += faithScore;
1145 if (getRandomNumber(1, 100) > p)
1146 displayAloneText();
1147 else
1148 setPresenceRedRoom(_place);
1149 }
1150 }
1151
1152 /**
1153 * Engine function - Set Random Presence - Room 9
1154 * @remarks Originally called 'pl9'
1155 */
setRandomPresenceJuliaRoom(int faithScore)1156 void MortevielleEngine::setRandomPresenceJuliaRoom(int faithScore) {
1157 if (!_juliaRoomPresenceLeo) {
1158 faithScore = -10;
1159 if (getRandomNumber(1, 100) > faithScore) // always true?
1160 displayAloneText();
1161 else
1162 setPresencePurpleRoom();
1163 }
1164 }
1165
1166 /**
1167 * Engine function - Set Random Presence - Dining Room
1168 * @remarks Originally called 'pl10'
1169 */
setRandomPresenceDiningRoom(int faithScore)1170 void MortevielleEngine::setRandomPresenceDiningRoom(int faithScore) {
1171 int h;
1172 int p = getPresenceStatsDiningRoom(h);
1173 p += faithScore;
1174 if (getRandomNumber(1, 100) > p)
1175 displayAloneText();
1176 else
1177 setPresenceDiningRoom(h);
1178 }
1179
1180 /**
1181 * Engine function - Set Random Presence - Bureau
1182 * @remarks Originally called 'pl11'
1183 */
setRandomPresenceBureau(int faithScore)1184 void MortevielleEngine::setRandomPresenceBureau(int faithScore) {
1185 int h;
1186
1187 int p = getPresenceStatsBureau(h);
1188 p += faithScore;
1189 if (getRandomNumber(1, 100) > p)
1190 displayAloneText();
1191 else
1192 setPresenceBureau(h);
1193 }
1194
1195 /**
1196 * Engine function - Set Random Presence - Kitchen
1197 * @remarks Originally called 'pl12'
1198 */
setRandomPresenceKitchen(int faithScore)1199 void MortevielleEngine::setRandomPresenceKitchen(int faithScore) {
1200
1201 int p = getPresenceStatsKitchen();
1202 p += faithScore;
1203 if (getRandomNumber(1, 100) > p)
1204 displayAloneText();
1205 else
1206 setPresenceKitchen();
1207 }
1208
1209 /**
1210 * Engine function - Set Random Presence - Attic / Cellar
1211 * @remarks Originally called 'pl13'
1212 */
setRandomPresenceAttic(int faithScore)1213 void MortevielleEngine::setRandomPresenceAttic(int faithScore) {
1214 int p = getPresenceStatsAttic();
1215 p += faithScore;
1216 if (getRandomNumber(1, 100) > p)
1217 displayAloneText();
1218 else
1219 setPresenceKitchen();
1220 }
1221
1222 /**
1223 * Engine function - Set Random Presence - Landing
1224 * @remarks Originally called 'pl15'
1225 */
setRandomPresenceLanding(int faithScore)1226 void MortevielleEngine::setRandomPresenceLanding(int faithScore) {
1227 int p = getPresenceStatsLanding();
1228 p += faithScore;
1229 if (getRandomNumber(1, 100) > p)
1230 displayAloneText();
1231 else
1232 setPresenceLanding();
1233 }
1234
1235 /**
1236 * Engine function - Set Random Presence - Chapel
1237 * @remarks Originally called 'pl20'
1238 */
setRandomPresenceChapel(int faithScore)1239 void MortevielleEngine::setRandomPresenceChapel(int faithScore) {
1240 int h;
1241
1242 int p = getPresenceStatsChapel(h);
1243 p += faithScore;
1244 if (getRandomNumber(1, 100) > p)
1245 displayAloneText();
1246 else
1247 setPresenceChapel(h);
1248 }
1249
1250 /**
1251 * Start music or speech
1252 * @remarks Originally called 'musique'
1253 */
startMusicOrSpeech(int so)1254 void MortevielleEngine::startMusicOrSpeech(int so) {
1255 if (so == 0) {
1256 /* musik(0) */
1257 ;
1258 } else if ((!_introSpeechPlayed) && (!_coreVar._alreadyEnteredManor)) {
1259 // Type 1: Speech
1260 _soundManager->startSpeech(10, 1, 1);
1261 _introSpeechPlayed = true;
1262 } else {
1263 if (((_coreVar._currPlace == MOUNTAIN) || (_coreVar._currPlace == MANOR_FRONT) || (_coreVar._currPlace == MANOR_BACK)) && (getRandomNumber(1, 3) == 2))
1264 // Type 1: Speech
1265 _soundManager->startSpeech(9, getRandomNumber(2, 4), 1);
1266 else if ((_coreVar._currPlace == CHAPEL) && (getRandomNumber(1, 2) == 1))
1267 // Type 1: Speech
1268 _soundManager->startSpeech(8, 1, 1);
1269 else if ((_coreVar._currPlace == WELL) && (getRandomNumber(1, 2) == 2))
1270 // Type 1: Speech
1271 _soundManager->startSpeech(12, 1, 1);
1272 else if (_coreVar._currPlace == INSIDE_WELL)
1273 // Type 1: Speech
1274 _soundManager->startSpeech(13, 1, 1);
1275 else
1276 // Type 2 : music
1277 _soundManager->startSpeech(getRandomNumber(1, 17), 1, 2);
1278 }
1279 }
1280
1281 /**
1282 * Engine function - You lose!
1283 * @remarks Originally called 'tperd'
1284 */
loseGame()1285 void MortevielleEngine::loseGame() {
1286 resetOpenObjects();
1287 _roomDoorId = OWN_ROOM;
1288 _curSearchObjId = 0;
1289 _menu->unsetSearchMenu();
1290 if (!_outsideOnlyFl)
1291 getPresence(MANOR_FRONT);
1292
1293 _loseGame = true;
1294 clearUpperLeftPart();
1295 _screenSurface->drawBox(60, 35, 400, 50, 15);
1296 handleDescriptionText(9, _crep);
1297 clearDescriptionBar();
1298 clearVerbBar();
1299 _col = false;
1300 _syn = false;
1301 _destinationOk = false;
1302 }
1303
1304 /**
1305 * Engine function - Check inventory for a given object
1306 * @remarks Originally called 'cherjer'
1307 */
checkInventory(int objectId)1308 bool MortevielleEngine::checkInventory(int objectId) {
1309 bool retVal = false;
1310 for (int i = 1; i <= 6; ++i)
1311 retVal = (retVal || (_coreVar._inventory[i] == objectId));
1312
1313 if (_coreVar._selectedObjectId == objectId)
1314 retVal = true;
1315
1316 return retVal;
1317 }
1318
1319 /**
1320 * Engine function - Display Dining Room
1321 * @remarks Originally called 'st1sama'
1322 */
displayDiningRoom()1323 void MortevielleEngine::displayDiningRoom() {
1324 _coreVar._currPlace = DINING_ROOM;
1325 prepareDisplayText();
1326 }
1327
1328 /**
1329 * Engine function - Start non interactive Dialog
1330 * @remarks Originally called 'sparl'
1331 */
startDialog(int16 rep)1332 void MortevielleEngine::startDialog(int16 rep) {
1333 int key;
1334
1335 assert(rep >= 0);
1336
1337 _mouse->hideMouse();
1338 Common::String dialogStr = getString(rep + kDialogStringIndex);
1339 _text->displayStr(dialogStr, 230, 4, 65, 26, 5);
1340 _dialogManager->drawF3F8();
1341
1342 key = 0;
1343 do {
1344 _soundManager->startSpeech(rep, _caff - 69, 0);
1345 key = _dialogManager->waitForF3F8();
1346 if (shouldQuit())
1347 return;
1348 } while (key != 66);
1349 clearScreen();
1350 _mouse->showMouse();
1351 }
1352
1353 /**
1354 * Engine function - End of Search: reset globals
1355 * @remarks Originally called 'finfouill'
1356 */
endSearch()1357 void MortevielleEngine::endSearch() {
1358 _heroSearching = false;
1359 _obpart = false;
1360 _searchCount = 0;
1361 _is = 0;
1362 _menu->unsetSearchMenu();
1363 }
1364
1365 /**
1366 * Engine function - Go to Dining room
1367 * @remarks Originally called 't1sama'
1368 */
gotoDiningRoom()1369 void MortevielleEngine::gotoDiningRoom() {
1370 int day, hour, minute;
1371
1372 updateHour(day, hour, minute);
1373 if ((hour < 5) && (_coreVar._currPlace > ROOM18)) {
1374 if (!checkInventory(137)) { //You don't have the keys, and it's late
1375 _crep = 1511;
1376 loseGame();
1377 } else
1378 displayDiningRoom();
1379 } else if (!_coreVar._alreadyEnteredManor) { //Is it your first time?
1380 _currBitIndex = 255; // Everybody is present
1381 showPeoplePresent(_currBitIndex);
1382 _caff = 77;
1383 drawPictureWithText();
1384 _screenSurface->drawBox(223, 47, 155, 91, 15);
1385 handleDescriptionText(2, 33);
1386 testKey(false);
1387 menuUp();
1388 _mouse->hideMouse();
1389 clearScreen();
1390 drawDiscussionBox();
1391 startDialog(140);
1392 drawRightFrame();
1393 drawClock();
1394 _mouse->showMouse();
1395 _coreVar._currPlace = OWN_ROOM;
1396 prepareDisplayText();
1397 resetPresenceInRooms(DINING_ROOM);
1398 if (!_outsideOnlyFl)
1399 getPresence(OWN_ROOM);
1400 _currBitIndex = 0;
1401 _savedBitIndex = 0;
1402 _coreVar._alreadyEnteredManor = true;
1403 } else
1404 displayDiningRoom();
1405 }
1406
1407 /**
1408 * Engine function - Check Manor distance (in the mountains)
1409 * @remarks Originally called 't1neig'
1410 */
checkManorDistance()1411 void MortevielleEngine::checkManorDistance() {
1412 ++_manorDistance;
1413 if (_manorDistance > 2) {
1414 _crep = 1506;
1415 loseGame();
1416 } else {
1417 _destinationOk = true;
1418 _coreVar._currPlace = MOUNTAIN;
1419 prepareDisplayText();
1420 }
1421 }
1422
1423 /**
1424 * Engine function - Go to Manor front
1425 * @remarks Originally called 't1deva'
1426 */
gotoManorFront()1427 void MortevielleEngine::gotoManorFront() {
1428 _manorDistance = 0;
1429 _coreVar._currPlace = MANOR_FRONT;
1430 prepareDisplayText();
1431 }
1432
1433 /**
1434 * Engine function - Go to Manor back
1435 * @remarks Originally called 't1derr'
1436 */
gotoManorBack()1437 void MortevielleEngine::gotoManorBack() {
1438 _coreVar._currPlace = MANOR_BACK;
1439 prepareDisplayText();
1440 }
1441
1442 /**
1443 * Engine function - Dead : Flooded in Well
1444 * @remarks Originally called 't1deau'
1445 */
floodedInWell()1446 void MortevielleEngine::floodedInWell() {
1447 _crep = 1503;
1448 loseGame();
1449 }
1450
1451 /**
1452 * Called when a savegame has been loaded.
1453 * @remarks Originally called 'antegame'
1454 */
gameLoaded()1455 void MortevielleEngine::gameLoaded() {
1456 _mouse->hideMouse();
1457 _menu->_menuDisplayed = false;
1458 _loseGame = true;
1459 _anyone = false;
1460 _destinationOk = true;
1461 _col = false;
1462 _hiddenHero = false;
1463 _uptodatePresence = false;
1464 _maff = 68;
1465 _menuOpcode = OPCODE_NONE;
1466 _introSpeechPlayed = false;
1467 _x = 0;
1468 _y = 0;
1469 _num = 0;
1470 _startTime = 0;
1471 _endTime = 0;
1472 _is = 0;
1473 _searchCount = 0;
1474 _roomDoorId = OWN_ROOM;
1475 _syn = true;
1476 _heroSearching = true;
1477 _curSearchObjId = 0;
1478 _manorDistance = 0;
1479 resetOpenObjects();
1480 _takeObjCount = 0;
1481 prepareDisplayText();
1482 _hintPctMessage = getString(580);
1483
1484 _destinationOk = false;
1485 _endGame = true;
1486 _loseGame = false;
1487 _heroSearching = false;
1488
1489 displayAloneText();
1490 prepareRoom();
1491 drawClock();
1492 drawPictureWithText();
1493 handleDescriptionText(2, _crep);
1494 clearVerbBar();
1495 _endGame = false;
1496 _menu->setDestinationText(_coreVar._currPlace);
1497 _menu->setInventoryText();
1498 if (_coreVar._selectedObjectId != 0)
1499 displayItemInHand(_coreVar._selectedObjectId + 400);
1500 _mouse->showMouse();
1501 }
1502
1503 /**
1504 * Engine function - Handle OpCodes
1505 * @remarks Originally called 'tsitu'
1506 */
handleOpcode()1507 void MortevielleEngine::handleOpcode() {
1508 if (!_col)
1509 clearDescriptionBar();
1510 _syn = false;
1511 _keyPressedEsc = false;
1512 if (!_anyone) {
1513 if (_uptodatePresence) {
1514 if ((_currMenu == MENU_MOVE) || (_currAction == _menu->_opcodeLeave) || (_currAction == _menu->_opcodeSleep) || (_currAction == _menu->_opcodeEat)) {
1515 _controlMenu = 4;
1516 menuUp();
1517 return;
1518 }
1519 }
1520
1521 if (_currMenu == MENU_MOVE)
1522 fctMove();
1523 else if (_currMenu == MENU_DISCUSS)
1524 fctDiscuss();
1525 else if (_currMenu == MENU_INVENTORY)
1526 fctInventoryTake();
1527 else if (_currAction == _menu->_opcodeAttach)
1528 fctAttach();
1529 else if (_currAction == _menu->_opcodeWait)
1530 fctWait();
1531 else if (_currAction == _menu->_opcodeForce)
1532 fctForce();
1533 else if (_currAction == _menu->_opcodeSleep)
1534 fctSleep();
1535 else if (_currAction == _menu->_opcodeListen)
1536 fctListen();
1537 else if (_currAction == _menu->_opcodeEnter)
1538 fctEnter();
1539 else if (_currAction == _menu->_opcodeClose)
1540 fctClose();
1541 else if (_currAction == _menu->_opcodeSearch)
1542 fctSearch();
1543 else if (_currAction == _menu->_opcodeKnock)
1544 fctKnock();
1545 else if (_currAction == _menu->_opcodeScratch)
1546 fctScratch();
1547 else if (_currAction == _menu->_opcodeRead)
1548 fctRead();
1549 else if (_currAction == _menu->_opcodeEat)
1550 fctEat();
1551 else if (_currAction == _menu->_opcodePlace)
1552 fctPlace();
1553 else if (_currAction == _menu->_opcodeOpen)
1554 fctOpen();
1555 else if (_currAction == _menu->_opcodeTake)
1556 fctTake();
1557 else if (_currAction == _menu->_opcodeLook)
1558 fctLook();
1559 else if (_currAction == _menu->_opcodeSmell)
1560 fctSmell();
1561 else if (_currAction == _menu->_opcodeSound)
1562 fctSound();
1563 else if (_currAction == _menu->_opcodeLeave)
1564 fctLeave();
1565 else if (_currAction == _menu->_opcodeLift)
1566 fctLift();
1567 else if (_currAction == _menu->_opcodeTurn)
1568 fctTurn();
1569 else if (_currAction == _menu->_opcodeSSearch)
1570 fctSelfSearch();
1571 else if (_currAction == _menu->_opcodeSRead)
1572 fctSelfRead();
1573 else if (_currAction == _menu->_opcodeSPut)
1574 fctSelfPut();
1575 else if (_currAction == _menu->_opcodeSLook)
1576 fctSelftLook();
1577
1578 _hiddenHero = false;
1579
1580 if (_currAction == _menu->_opcodeSHide)
1581 fctSelfHide();
1582 } else if (_anyone) {
1583 interactNPC();
1584 _anyone = false;
1585 menuUp();
1586 return;
1587 }
1588 int hour, day, minute;
1589 updateHour(day, hour, minute);
1590 if ((((hour == 12) || (hour == 13) || (hour == 19)) && (_coreVar._currPlace != DINING_ROOM)) ||
1591 ((hour > 0) && (hour < 6) && (_coreVar._currPlace != OWN_ROOM)))
1592 ++_coreVar._faithScore;
1593 if (((_coreVar._currPlace < CRYPT) || (_coreVar._currPlace > MOUNTAIN)) && (_coreVar._currPlace != INSIDE_WELL)
1594 && (_coreVar._currPlace != OWN_ROOM) && (_coreVar._selectedObjectId != 152) && (!_loseGame)) {
1595 if ((_coreVar._faithScore > 99) && (hour > 8) && (hour < 16)) {
1596 _crep = 1501;
1597 loseGame();
1598 } else if ((_coreVar._faithScore > 99) && (hour > 0) && (hour < 9)) {
1599 _crep = 1508;
1600 loseGame();
1601 } else if ((day > 1) && (hour > 8) && (!_loseGame)) {
1602 _crep = 1502;
1603 loseGame();
1604 }
1605 }
1606 menuUp();
1607 }
1608
1609 /**
1610 * Engine function - Transform time into a char
1611 * @remarks Originally called 'tmaj3'
1612 */
hourToChar()1613 void MortevielleEngine::hourToChar() {
1614 int day, hour, minute;
1615
1616 updateHour(day, hour, minute);
1617 if (minute == 30)
1618 minute = 1;
1619 hour += day * 24;
1620 minute += hour * 2;
1621 _coreVar._fullHour = (unsigned char)minute;
1622 }
1623
1624 /**
1625 * Engine function - extract time from a char
1626 * @remarks Originally called 'theure'
1627 */
charToHour()1628 void MortevielleEngine::charToHour() {
1629 int fullHour = _coreVar._fullHour;
1630 int tmpHour = fullHour % 48;
1631 _currDay = fullHour / 48;
1632 _currHalfHour = tmpHour % 2;
1633 _currHour = tmpHour / 2;
1634 _hour = _currHour;
1635 if (_currHalfHour == 1)
1636 _minute = 30;
1637 else
1638 _minute = 0;
1639 }
1640
1641 /**
1642 * Engine function - Clear upper left part of Screen - Type 1
1643 * @remarks Originally called 'clsf1'
1644 */
clearUpperLeftPart()1645 void MortevielleEngine::clearUpperLeftPart() {
1646 _mouse->hideMouse();
1647 _screenSurface->fillRect(0, Common::Rect(0, 11, 514, 175));
1648 _mouse->showMouse();
1649 }
1650
1651 /**
1652 * Engine function - Clear low bar used by description
1653 * @remarks Originally called 'clsf2'
1654 */
clearDescriptionBar()1655 void MortevielleEngine::clearDescriptionBar() {
1656 _mouse->hideMouse();
1657 if (_largestClearScreen) {
1658 _screenSurface->fillRect(0, Common::Rect(1, 176, 633, 199));
1659 _screenSurface->drawBox(0, 175, 634, 24, 15);
1660 _largestClearScreen = false;
1661 } else {
1662 _screenSurface->fillRect(0, Common::Rect(1, 176, 633, 190));
1663 _screenSurface->drawBox(0, 175, 634, 15, 15);
1664 }
1665 _mouse->showMouse();
1666 }
1667
1668 /**
1669 * Engine function - Clear lowest bar used by verbs
1670 * @remarks Originally called 'clsf3'
1671 */
clearVerbBar()1672 void MortevielleEngine::clearVerbBar() {
1673 _mouse->hideMouse();
1674 _screenSurface->fillRect(0, Common::Rect(1, 192, 633, 199));
1675 _screenSurface->drawBox(0, 191, 634, 8, 15);
1676 _mouse->showMouse();
1677 }
1678
1679 /**
1680 * Engine function - Clear upper right part of the screen
1681 * @remarks Originally called 'clsf10'
1682 */
clearUpperRightPart()1683 void MortevielleEngine::clearUpperRightPart() {
1684 Common::String st;
1685
1686 _mouse->hideMouse();
1687
1688 // Clear ambiance description
1689 _screenSurface->fillRect(15, Common::Rect(544, 93, 600, 98));
1690 if (_coreVar._faithScore < 33)
1691 st = getEngineString(S_COOL);
1692 else if (_coreVar._faithScore < 66)
1693 st = getEngineString(S_LOURDE);
1694 else if (_coreVar._faithScore > 65)
1695 st = getEngineString(S_MALSAINE);
1696
1697 int x1 = 574 - (_screenSurface->getStringWidth(st) / 2);
1698 _screenSurface->putxy(x1, 92);
1699 _screenSurface->drawString(st, 4);
1700
1701 // Clear person list
1702 _screenSurface->fillRect(15, Common::Rect(560, 24, 610, 86));
1703 _mouse->showMouse();
1704 }
1705
1706 /**
1707 * Engine function - Get a random number between two values
1708 * @remarks Originally called 'get_random_number' and 'hazard'
1709 */
getRandomNumber(int minval,int maxval)1710 int MortevielleEngine::getRandomNumber(int minval, int maxval) {
1711 return _randomSource.getRandomNumber(maxval - minval) + minval;
1712 }
1713
1714 /**
1715 * Engine function - Show alert "use move menu"
1716 * @remarks Originally called 'aldepl'
1717 */
showMoveMenuAlert()1718 void MortevielleEngine::showMoveMenuAlert() {
1719 _dialogManager->show(getEngineString(S_USE_DEP_MENU));
1720 }
1721
1722 /**
1723 * The original engine used this method to display a starting text screen letting the player
1724 * select the graphics mode to use
1725 * @remarks Originally called 'dialpre'
1726 */
showConfigScreen()1727 void MortevielleEngine::showConfigScreen() {
1728 // FIXME: need a DOS palette, index 9 (light blue). Also we should show DOS font here
1729 Common::String tmpStr;
1730 int cy = 0;
1731 clearScreen();
1732 do {
1733 ++cy;
1734 tmpStr = getString(cy + kStartingScreenStringIndex);
1735 int width = _screenSurface->getStringWidth(tmpStr);
1736 _text->displayStr(tmpStr, 320 - width / 2, cy * 8, 80, 1, 2);
1737 } while (cy != 20);
1738
1739 int ix = 0;
1740 do {
1741 ++ix;
1742 } while (!(keyPressed() || ix == 0x5e5));
1743
1744 _crep = 998;
1745 }
1746
1747 /**
1748 * Decodes a number of 64 byte blocks
1749 * @param pStart Start of data
1750 * @param count Number of 64 byte blocks
1751 * @remarks Originally called 'zzuul'
1752 */
decodeNumber(byte * pStart,int count)1753 void MortevielleEngine::decodeNumber(byte *pStart, int count) {
1754 while (count-- > 0) {
1755 for (int idx = 0; idx < 64; ++pStart, ++idx) {
1756 uint16 v = ((*pStart - 0x80) << 1) + 0x80;
1757
1758 if (v & 0x8000)
1759 *pStart = 0;
1760 else if (v & 0xff00)
1761 *pStart = 0xff;
1762 else
1763 *pStart = (byte)v;
1764 }
1765 }
1766 }
1767
1768 const byte cryptoArrDefaultFr[32] = {
1769 32, 101, 115, 97, 114, 105, 110,
1770 117, 116, 111, 108, 13, 100, 99,
1771 112, 109, 46, 118, 130, 39, 102,
1772 98, 44, 113, 104, 103, 33, 76,
1773 85, 106, 30, 31
1774 };
1775
1776 const byte cryptoArr30Fr[32] = {
1777 69, 67, 74, 138, 133, 120, 77, 122,
1778 121, 68, 65, 63, 73, 80, 83, 82,
1779 156, 45, 58, 79, 49, 86, 78, 84,
1780 71, 81, 64, 66, 135, 34, 136, 91
1781 };
1782
1783 const byte cryptoArr31Fr[32]= {
1784 93, 47, 48, 53, 50, 70, 124, 75,
1785 72, 147, 140, 150, 151, 57, 56, 51,
1786 107, 139, 55, 89, 131, 37, 54, 88,
1787 119, 0, 0, 0, 0, 0, 0, 0
1788 };
1789
1790 const byte cryptoArrDefaultDe[32] = {
1791 0x20, 0x65, 0x6E, 0x69, 0x73, 0x72, 0x74,
1792 0x68, 0x61, 0x75, 0x0D, 0x63, 0x6C, 0x64,
1793 0x6D, 0x6F, 0x67, 0x2E, 0x62, 0x66, 0x53,
1794 0x2C, 0x77, 0x45, 0x7A, 0x6B, 0x44, 0x76,
1795 0x9C, 0x47, 0x1E, 0x1F
1796 };
1797
1798 const byte cryptoArr30De[32] = {
1799 0x49, 0x4D, 0x21, 0x42, 0x4C, 0x70, 0x41, 0x52,
1800 0x57, 0x4E, 0x48, 0x3F, 0x46, 0x50, 0x55, 0x4B,
1801 0x5A, 0x4A, 0x54, 0x31, 0x4F, 0x56, 0x79, 0x3A,
1802 0x6A, 0x5B, 0x5D, 0x40, 0x22, 0x2F, 0x30, 0x35
1803 };
1804
1805 const byte cryptoArr31De[32]= {
1806 0x78, 0x2D, 0x32, 0x82, 0x43, 0x39, 0x33, 0x38,
1807 0x7C, 0x27, 0x37, 0x3B, 0x25, 0x28, 0x29, 0x36,
1808 0x51, 0x59, 0x71, 0x81, 0x87, 0x88, 0x93, 0,
1809 0, 0, 0, 0, 0, 0, 0, 0
1810 };
1811
1812 const byte *cryptoArrDefault, *cryptoArr30, *cryptoArr31;
1813 uint16 ctrlChar;
1814
1815 /**
1816 * Decrypt the next character
1817 * @param c OUT, next decrypted char
1818 * @param idx IN/OUT, current buffer index
1819 * @param pt IN/OUT, current encryption point
1820 * @return a boolean specifying if a stop character has been encountered
1821 * @remarks Originally called 'cinq_huit'
1822 */
decryptNextChar(char & c,int & idx,byte & pt)1823 bool MortevielleEngine::decryptNextChar(char &c, int &idx, byte &pt) {
1824 uint16 oct, ocd;
1825
1826 /* 5-8 */
1827 oct = _dialogIndexArray[idx];
1828 oct = ((uint16)(oct << (16 - pt))) >> (16 - pt);
1829 if (pt < 6) {
1830 ++idx;
1831 oct = oct << (5 - pt);
1832 pt += 11;
1833 oct = oct | ((uint)_dialogIndexArray[idx] >> pt);
1834 } else {
1835 pt -= 5;
1836 oct = (uint)oct >> pt;
1837 }
1838
1839 if (oct == ctrlChar) {
1840 c = '$';
1841 return true;
1842 } else if (oct == 30 || oct == 31) {
1843 ocd = _dialogIndexArray[idx];
1844 ocd = (uint16)(ocd << (16 - pt)) >> (16 - pt);
1845 if (pt < 6) {
1846 ++idx;
1847 ocd = ocd << (5 - pt);
1848 pt += 11;
1849 ocd = ocd | ((uint)_dialogIndexArray[idx] >> pt);
1850 } else {
1851 pt -= 5;
1852 ocd = (uint)ocd >> pt;
1853 }
1854
1855 if (oct == 30)
1856 c = (unsigned char)cryptoArr30[ocd];
1857 else
1858 c = (unsigned char)cryptoArr31[ocd];
1859
1860 if (c == '\0') {
1861 c = '#';
1862 return true;
1863 }
1864 } else {
1865 c = (unsigned char)cryptoArrDefault[oct];
1866 }
1867 return false;
1868 }
1869
1870 /**
1871 * Decode and extract the line with the given Id
1872 * @remarks Originally called 'deline'
1873 */
getString(int num)1874 Common::String MortevielleEngine::getString(int num) {
1875 Common::String wrkStr = "";
1876
1877 if (num < 0) {
1878 warning("getString(%d): num < 0! Skipping", num);
1879 } else if (!_txxFileFl) {
1880 wrkStr = getGameString(num);
1881 } else {
1882 int hint = _dialogHintArray[num]._hintId;
1883 byte point = _dialogHintArray[num]._point;
1884 int length = 0;
1885 bool endFl = false;
1886 char let;
1887 do {
1888 endFl = decryptNextChar(let, hint, point);
1889 wrkStr += let;
1890 ++length;
1891 } while (!endFl);
1892 }
1893
1894 while (wrkStr.lastChar() == '$')
1895 // Remove trailing '$'s
1896 wrkStr.deleteLastChar();
1897
1898 return wrkStr;
1899 }
1900
1901 /**
1902 * Reset object place
1903 * @remarks Originally called 'copcha'
1904 */
resetObjectPlace()1905 void MortevielleEngine::resetObjectPlace() {
1906 for (int i = kAcha; i < kAcha + 390; i++)
1907 _tabdon[i] = _tabdon[i + 390];
1908 }
1909
resetCoreVar()1910 void MortevielleEngine::resetCoreVar() {
1911 _saveStruct._alreadyEnteredManor = _coreVar._alreadyEnteredManor = false;
1912 _saveStruct._selectedObjectId = _coreVar._selectedObjectId = 0;
1913 _saveStruct._cellarObjectId = _coreVar._cellarObjectId = 0;
1914 _saveStruct._atticBallHoleObjectId = _coreVar._atticBallHoleObjectId = 0;
1915 _saveStruct._atticRodHoleObjectId = _coreVar._atticRodHoleObjectId = 0;
1916 _saveStruct._wellObjectId = _coreVar._wellObjectId = 0;
1917 _saveStruct._secretPassageObjectId = _coreVar._secretPassageObjectId = 0;
1918 _saveStruct._purpleRoomObjectId = _coreVar._purpleRoomObjectId = 136;
1919 _saveStruct._cryptObjectId = _coreVar._cryptObjectId = 141;
1920 _saveStruct._faithScore = _coreVar._faithScore = getRandomNumber(4, 10);
1921 _saveStruct._currPlace = _coreVar._currPlace = MANOR_FRONT;
1922
1923 for (int i = 2; i <= 6; ++i)
1924 _coreVar._inventory[i] = 0;
1925
1926 // Only object in inventory: a gun
1927 _coreVar._inventory[1] = 113;
1928
1929 _saveStruct._fullHour = _coreVar._fullHour = (unsigned char)20;
1930
1931 for (int i = 1; i <= 10; ++i)
1932 _coreVar._pctHintFound[i] = ' ';
1933
1934 for (int i = 1; i <= 6; ++i)
1935 _coreVar._availableQuestion[i] = '*';
1936
1937 for (int i = 7; i <= 9; ++i)
1938 _coreVar._availableQuestion[i] = ' ';
1939
1940 for (int i = 10; i <= 28; ++i)
1941 _coreVar._availableQuestion[i] = '*';
1942
1943 for (int i = 29; i <= 42; ++i)
1944 _coreVar._availableQuestion[i] = ' ';
1945
1946 _coreVar._availableQuestion[33] = '*';
1947 }
1948 /**
1949 * Engine function - When restarting the game, reset the main variables used by the engine
1950 * @remarks Originally called 'inzon'
1951 */
resetVariables()1952 void MortevielleEngine::resetVariables() {
1953 resetObjectPlace();
1954 resetCoreVar();
1955
1956 for (int i = 1; i <= 8; ++i)
1957 _charAnswerCount[i] = 0;
1958
1959 initMaxAnswer();
1960 }
1961
1962 /**
1963 * Engine function - Set the palette
1964 * @remarks Originally called 'writepal'
1965 */
setPal(int n)1966 void MortevielleEngine::setPal(int n) {
1967 for (int i = 1; i <= 16; ++i) {
1968 _curPict[(2 * i)] = _stdPal[n][i].x;
1969 _curPict[(2 * i) + 1] = _stdPal[n][i].y;
1970 }
1971 }
1972
1973 /**
1974 * Engine function - Load Palette from File
1975 * @remarks Originally called 'charpal'
1976 */
loadPalette()1977 void MortevielleEngine::loadPalette() {
1978 Common::File f;
1979
1980 if (!f.open("fxx.mor")) {
1981 if (f.open("mfxx.mor"))
1982 f.seek(7 * 25);
1983 else
1984 error("Missing file - fxx.mor");
1985 }
1986
1987 for (int i = 0; i < 108; ++i)
1988 _drawingSizeArr[i] = f.readSint16LE();
1989 f.close();
1990
1991 if (!f.open("plxx.mor"))
1992 error("Missing file - plxx.mor");
1993 for (int i = 0; i <= 90; ++i) {
1994 for (int j = 1; j <= 16; ++j) {
1995 _stdPal[i][j].x = f.readByte();
1996 _stdPal[i][j].y = f.readByte();
1997 }
1998 }
1999 f.close();
2000
2001 if (!f.open("cxx.mor"))
2002 error("Missing file - cxx.mor");
2003
2004 // Skip CGA Palette and Patterns
2005
2006 f.close();
2007 }
2008
2009 /**
2010 * Engine function - Load Texts from File
2011 * @remarks Originally called 'chartex'
2012 */
loadTexts()2013 void MortevielleEngine::loadTexts() {
2014 Common::File inpFile;
2015 Common::File ntpFile;
2016
2017 _txxFileFl = false;
2018 if (!useOriginalData()) {
2019 warning("Using improved translation from DAT file");
2020 return;
2021 }
2022
2023 if (!inpFile.open("TXX.INP")) {
2024 if (!inpFile.open("TXX.MOR")) {
2025 warning("Missing file - TXX.INP or .MOR - Switching to DAT file");
2026 return;
2027 }
2028 }
2029 if (ntpFile.open("TXX.NTP")) {
2030 cryptoArr30 = cryptoArr30Fr;
2031 cryptoArr31 = cryptoArr31Fr;
2032 cryptoArrDefault = cryptoArrDefaultFr;
2033 ctrlChar = 11;
2034 } else if (ntpFile.open("TXX.IND")) {
2035 cryptoArr30 = cryptoArr30De;
2036 cryptoArr31 = cryptoArr31De;
2037 cryptoArrDefault = cryptoArrDefaultDe;
2038 ctrlChar = 10;
2039 } else {
2040 warning("Missing file - TXX.NTP or .IND - Switching to DAT file");
2041 return;
2042 }
2043
2044 if ((inpFile.size() > (kMaxDialogIndex * 2)) || (ntpFile.size() > (kMaxDialogHint * 3))) {
2045 warning("TXX file - Unexpected format - Switching to DAT file");
2046 return;
2047 }
2048
2049 for (int i = 0; i < inpFile.size() / 2; ++i)
2050 _dialogIndexArray[i] = inpFile.readUint16LE();
2051
2052 inpFile.close();
2053 _txxFileFl = true;
2054
2055 for (int i = 0; i < (ntpFile.size() / 3); ++i) {
2056 _dialogHintArray[i]._hintId = ntpFile.readSint16LE();
2057 _dialogHintArray[i]._point = ntpFile.readByte();
2058 }
2059
2060 ntpFile.close();
2061
2062 }
2063
loadCFIEC()2064 void MortevielleEngine::loadCFIEC() {
2065 Common::File f;
2066
2067 if (!f.open("cfiec.mor")) {
2068 if (!f.open("alcfiec.mor"))
2069 error("Missing file - *cfiec.mor");
2070 }
2071
2072 _cfiecBufferSize = ((f.size() / 128) + 1) * 128;
2073 int32 fileSize = f.size();
2074
2075 if (!_reloadCFIEC)
2076 _cfiecBuffer = (byte *)malloc(sizeof(byte) * _cfiecBufferSize);
2077
2078 for (int32 i = 0; i < fileSize; ++i)
2079 _cfiecBuffer[i] = f.readByte();
2080
2081 for (int i = fileSize; i < _cfiecBufferSize; i++)
2082 _cfiecBuffer[i] = 0;
2083
2084 f.close();
2085
2086 _reloadCFIEC = false;
2087 }
2088
2089
loadCFIPH()2090 void MortevielleEngine::loadCFIPH() {
2091 Common::File f;
2092
2093 if (!f.open("cfiph.mor")) {
2094 if (!f.open("alcfiph.mor"))
2095 error("Missing file - *cfiph.mor");
2096 }
2097
2098 _soundManager->_cfiphBuffer = (uint16 *)malloc(sizeof(uint16) * (f.size() / 2));
2099
2100 for (int i = 0; i < (f.size() / 2); ++i)
2101 _soundManager->_cfiphBuffer[i] = f.readUint16BE();
2102
2103 f.close();
2104 }
2105
2106 /**
2107 * Engine function - Play Music
2108 * @remarks Originally called 'music'
2109 */
music()2110 void MortevielleEngine::music() {
2111 if (_soundOff)
2112 return;
2113
2114 _reloadCFIEC = true;
2115
2116 Common::File f;
2117 if (!f.open("mort.img")) {
2118 // Some DOS versions use MORTP2 instead of MORT.IMG
2119 // Some have both and they are identical
2120 if (!f.open("mortp2"))
2121 error("Missing file - mort.img");
2122 }
2123
2124 int size = f.size();
2125 byte *compMusicBuf = (byte *)malloc(sizeof(byte) * size);
2126 byte *musicBuf = (byte *)malloc(sizeof(byte) * size * 2);
2127 f.read(compMusicBuf, size);
2128 f.close();
2129
2130 int musicSize = _soundManager->decodeMusic(compMusicBuf, musicBuf, size);
2131 free(compMusicBuf);
2132
2133 _soundManager->playSong(musicBuf, musicSize, 5);
2134 while (keyPressed())
2135 getChar();
2136
2137 free(musicBuf);
2138 }
2139
2140 /**
2141 * Engine function - Show title screen
2142 * @remarks Originally called 'suite'
2143 */
showTitleScreen()2144 void MortevielleEngine::showTitleScreen() {
2145 clearScreen();
2146 handleDescriptionText(7, 2035);
2147 _caff = 51;
2148 _text->taffich();
2149 testKeyboard();
2150 delay(DISK_ACCESS_DELAY);
2151 clearScreen();
2152 draw(0, 0);
2153
2154 // FIXME: should be a DOS font here
2155 Common::String cpr = "COPYRIGHT 1989 : LANKHOR";
2156 _screenSurface->putxy(104 + 72 * kResolutionScaler, 185);
2157 _screenSurface->drawString(cpr, 0);
2158 }
2159
2160 /**
2161 * Draw picture
2162 * @remarks Originally called 'dessine'
2163 */
draw(int x,int y)2164 void MortevielleEngine::draw(int x, int y) {
2165 _mouse->hideMouse();
2166 setPal(_numpal);
2167 displayPicture(_curPict, x, y);
2168 _mouse->showMouse();
2169 }
2170
2171 /**
2172 * Draw right frame
2173 * @remarks Originally called 'dessine_rouleau'
2174 */
drawRightFrame()2175 void MortevielleEngine::drawRightFrame() {
2176 setPal(89);
2177 _mouse->hideMouse();
2178 displayPicture(_rightFramePict, 0, 0);
2179 _mouse->showMouse();
2180 }
2181
2182 /**
2183 * Read the current system time
2184 */
readclock()2185 int MortevielleEngine::readclock() {
2186 return (int)(g_system->getMillis() / 1000);
2187 }
2188
2189 /**
2190 * Engine function - Prepare room and hint string
2191 * @remarks Originally called 'tinke'
2192 */
prepareRoom()2193 void MortevielleEngine::prepareRoom() {
2194 int day, hour, minute;
2195
2196 _anyone = false;
2197 updateHour(day, hour, minute);
2198 if (day != _day) {
2199 _day = day;
2200 for (int i = 0; i < 9; i++) {
2201 if (_charAnswerMax[i] > 0)
2202 --_charAnswerMax[i];
2203 _charAnswerCount[i] = 0;
2204 }
2205 }
2206 if ((hour > _hour) || ((hour == 0) && (_hour == 23))) {
2207 _hour = hour;
2208 _minute = 0;
2209 drawClock();
2210 int hintCount = 0;
2211 for (int i = 1; i <= 10; ++i) {
2212 if (_coreVar._pctHintFound[i] == '*')
2213 ++hintCount;
2214 }
2215
2216 Common::String pctStr;
2217 if (hintCount == 10)
2218 pctStr = "10";
2219 else
2220 pctStr = (unsigned char)(hintCount + 48);
2221
2222 _hintPctMessage = "[1][";
2223 _hintPctMessage += getEngineString(S_SHOULD_HAVE_NOTICED);
2224 _hintPctMessage += pctStr;
2225 _hintPctMessage += '0';
2226 _hintPctMessage += getEngineString(S_NUMBER_OF_HINTS);
2227 _hintPctMessage += "][";
2228 _hintPctMessage += getEngineString(S_OKAY);
2229 _hintPctMessage += ']';
2230 }
2231 if (minute > _minute) {
2232 _minute = 30;
2233 drawClock();
2234 }
2235 if (_mouse->_pos.y < 12)
2236 return;
2237
2238 if (!_outsideOnlyFl) {
2239 if ((hour == 12) || ((hour > 18) && (hour < 21)) || ((hour >= 0) && (hour < 7)))
2240 _inGameHourDuration = kTime2;
2241 else
2242 _inGameHourDuration = kTime1;
2243 if ((_coreVar._faithScore > 33) && (_coreVar._faithScore < 66))
2244 _inGameHourDuration -= (_inGameHourDuration / 3);
2245
2246 if (_coreVar._faithScore > 65)
2247 _inGameHourDuration -= ((_inGameHourDuration / 3) * 2);
2248
2249 int newTime = readclock();
2250 if ((newTime - _currentTime) > _inGameHourDuration) {
2251 bool activeMenu = _menu->_menuActive;
2252 _menu->eraseMenu();
2253 _currentHourCount += ((newTime - _currentTime) / _inGameHourDuration);
2254 _currentTime = newTime;
2255 switch (_place) {
2256 case GREEN_ROOM:
2257 case DARKBLUE_ROOM:
2258 setRandomPresenceGreenRoom(_coreVar._faithScore);
2259 break;
2260 case PURPLE_ROOM:
2261 setRandomPresencePurpleRoom(_coreVar._faithScore);
2262 break;
2263 case BLUE_ROOM:
2264 setRandomPresenceBlueRoom(_coreVar._faithScore);
2265 break;
2266 case RED_ROOM:
2267 case GREEN_ROOM2:
2268 setRandomPresenceRedRoom(_coreVar._faithScore);
2269 break;
2270 case JULIA_ROOM:
2271 setRandomPresenceJuliaRoom(_coreVar._faithScore);
2272 break;
2273 case DINING_ROOM:
2274 setRandomPresenceDiningRoom(_coreVar._faithScore);
2275 break;
2276 case BUREAU:
2277 setRandomPresenceBureau(_coreVar._faithScore);
2278 break;
2279 case KITCHEN:
2280 setRandomPresenceKitchen(_coreVar._faithScore);
2281 break;
2282 case ATTIC:
2283 case CELLAR:
2284 setRandomPresenceAttic(_coreVar._faithScore);
2285 break;
2286 case LANDING:
2287 case ROOM26:
2288 setRandomPresenceLanding(_coreVar._faithScore);
2289 break;
2290 case CHAPEL:
2291 setRandomPresenceChapel(_coreVar._faithScore);
2292 break;
2293 }
2294 if ((_savedBitIndex != 0) && (_currBitIndex != 10))
2295 _savedBitIndex = _currBitIndex;
2296
2297 if ((_savedBitIndex == 0) && (_currBitIndex > 0)) {
2298 if ((_coreVar._currPlace == ATTIC) || (_coreVar._currPlace == CELLAR)) {
2299 initCaveOrCellar();
2300 } else if (_currBitIndex == 10) {
2301 _currBitIndex = 0;
2302 if (!_uptodatePresence) {
2303 _uptodatePresence = true;
2304 _startTime = readclock();
2305 if (getRandomNumber(1, 5) < 5) {
2306 clearVerbBar();
2307 prepareScreenType2();
2308 displayTextInVerbBar(getEngineString(S_HEAR_NOISE));
2309 int rand = (getRandomNumber(0, 4)) - 2;
2310 _soundManager->startSpeech(1, rand, 1);
2311 _soundManager->waitSpeech();
2312 clearVerbBar();
2313 }
2314 }
2315 }
2316 }
2317
2318 if (activeMenu)
2319 _menu->drawMenu();
2320 }
2321 }
2322 _endTime = readclock();
2323 if ((_uptodatePresence) && ((_endTime - _startTime) > 17)) {
2324 getPresenceBitIndex(_place);
2325 _uptodatePresence = false;
2326 _startTime = 0;
2327 if ((_coreVar._currPlace > OWN_ROOM) && (_coreVar._currPlace < DINING_ROOM))
2328 _anyone = true;
2329 }
2330 }
2331
2332 /**
2333 * Engine function - Draw Clock
2334 * @remarks Originally called 'pendule'
2335 */
drawClock()2336 void MortevielleEngine::drawClock() {
2337 const int cv[2][12] = {
2338 { 5, 8, 10, 8, 5, 0, -5, -8, -10, -8, -5, 0 },
2339 { -5, -3, 0, 3, 5, 6, 5, 3, 0, -3, -5, -6 }
2340 };
2341 const int x = 580;
2342 const int y = 123;
2343 const int rg = 9;
2344
2345 _mouse->hideMouse();
2346
2347 _screenSurface->drawRectangle(570, 118, 20, 10);
2348 _screenSurface->drawRectangle(578, 114, 6, 18);
2349
2350 if (_minute == 0)
2351 _screenSurface->drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)x >> 1) * kResolutionScaler, (y - rg), 1);
2352 else
2353 _screenSurface->drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)x >> 1) * kResolutionScaler, (y + rg), 1);
2354
2355 int hour12 = _hour;
2356 if (hour12 > 12)
2357 hour12 -= 12;
2358 if (hour12 == 0)
2359 hour12 = 12;
2360
2361 _screenSurface->drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)(x + cv[0][hour12 - 1]) >> 1) * kResolutionScaler, y + cv[1][hour12 - 1], 1);
2362 _mouse->showMouse();
2363 _screenSurface->putxy(568, 154);
2364
2365 if (_hour > 11)
2366 _screenSurface->drawString("PM ", 1);
2367 else
2368 _screenSurface->drawString("AM ", 1);
2369
2370 _screenSurface->putxy(550, 160);
2371 if ((_day >= 0) && (_day <= 8)) {
2372 Common::String tmp = getEngineString(S_DAY);
2373 tmp.insertChar((char)(_day + 49), 0);
2374 _screenSurface->drawString(tmp, 1);
2375 }
2376 }
2377
palette(int v1)2378 void MortevielleEngine::palette(int v1) {
2379 warning("TODO: palette");
2380 }
2381
2382 /**
2383 * Returns a substring of the given string
2384 * @param s Source string
2385 * @param idx Starting index (1 based)
2386 * @param size Number of characters to return
2387 */
2388
copy(const Common::String & s,int idx,size_t size)2389 Common::String MortevielleEngine::copy(const Common::String &s, int idx, size_t size) {
2390 assert(idx + size < s.size());
2391
2392 // Copy the substring into a temporary buffer
2393 char *tmp = new char[size + 1];
2394 Common::strlcpy(tmp, s.c_str() + idx - 1, size + 1);
2395
2396 Common::String result(tmp);
2397 delete[] tmp;
2398 return result;
2399 }
2400
2401 /**
2402 * Clear Screen
2403 * @remarks Originally called 'hirs'
2404 */
clearScreen()2405 void MortevielleEngine::clearScreen() {
2406 _screenSurface->clearScreen();
2407 }
2408
2409 /**
2410 * Init room : Cave or Cellar
2411 * @remarks Originally called 'cavegre'
2412 */
initCaveOrCellar()2413 void MortevielleEngine::initCaveOrCellar() {
2414 _coreVar._faithScore += 2;
2415 if (_coreVar._faithScore > 69)
2416 _coreVar._faithScore += (_coreVar._faithScore / 10);
2417 clearVerbBar();
2418 prepareScreenType2();
2419 displayTextInVerbBar(getEngineString(S_SOMEONE_ENTERS));
2420 int rand = (getRandomNumber(0, 4)) - 2;
2421 _soundManager->startSpeech(2, rand, 1);
2422 _soundManager->waitSpeech();
2423 // The original was doing here a useless loop.
2424 // It has been removed
2425
2426 clearVerbBar();
2427 displayAloneText();
2428 }
2429
2430 /**
2431 * Display control menu string
2432 * @remarks Originally called 'tctrm'
2433 */
displayControlMenu()2434 void MortevielleEngine::displayControlMenu() {
2435 handleDescriptionText(2, (3000 + _controlMenu));
2436 _controlMenu = 0;
2437 }
2438
2439 /**
2440 * Display picture at a given coordinate
2441 * @remarks Originally called 'pictout'
2442 */
displayPicture(const byte * pic,int x,int y)2443 void MortevielleEngine::displayPicture(const byte *pic, int x, int y) {
2444 GfxSurface surface;
2445 surface.decode(pic);
2446 _screenSurface->drawPicture(surface, x, y);
2447 }
2448
adzon()2449 void MortevielleEngine::adzon() {
2450 Common::File f;
2451
2452 if (!f.open("don.mor"))
2453 error("Missing file - don.mor");
2454
2455 f.read(_tabdon, 7 * 256);
2456 f.close();
2457
2458 if (!f.open("bmor.mor"))
2459 error("Missing file - bmor.mor");
2460
2461 f.read(&_tabdon[kFleche], 1916);
2462 f.close();
2463
2464 // Read Right Frame Drawing
2465 if (!f.open("dec.mor"))
2466 error("Missing file - dec.mor");
2467
2468 free(_rightFramePict);
2469 _rightFramePict = (byte *)malloc(sizeof(byte) * f.size());
2470 f.read(_rightFramePict, f.size());
2471 f.close();
2472 }
2473
2474 /**
2475 * Returns the offset within the compressed image data resource of the desired image
2476 * @remarks Originally called 'animof'
2477 */
getAnimOffset(int frameNum,int animNum)2478 int MortevielleEngine::getAnimOffset(int frameNum, int animNum) {
2479 int animCount = _curAnim[1];
2480 int aux = animNum;
2481 if (frameNum != 1)
2482 aux += animCount;
2483
2484 return (animCount << 2) + 2 + READ_BE_UINT16(&_curAnim[aux << 1]);
2485 }
2486
2487 /**
2488 * Display text in description bar
2489 * @remarks Originally called 'text1'
2490 */
displayTextInDescriptionBar(int x,int y,int nb,int mesgId)2491 void MortevielleEngine::displayTextInDescriptionBar(int x, int y, int nb, int mesgId) {
2492 Common::String tmpStr = getString(mesgId);
2493 if ((y == 182) && ((int)tmpStr.size() > nb))
2494 y = 176;
2495 _text->displayStr(tmpStr, x, y, nb, 20, _textColor);
2496 }
2497
2498 /**
2499 * Display description text
2500 * @remarks Originally called 'repon'
2501 */
handleDescriptionText(int f,int mesgId)2502 void MortevielleEngine::handleDescriptionText(int f, int mesgId) {
2503 if ((mesgId > 499) && (mesgId < 563)) {
2504 Common::String tmpStr = getString(mesgId - 501 + kInventoryStringIndex);
2505
2506 if ((int)tmpStr.size() > ((58 + (kResolutionScaler - 1) * 37) << 1))
2507 _largestClearScreen = true;
2508 else
2509 _largestClearScreen = false;
2510
2511 clearDescriptionBar();
2512 _text->displayStr(tmpStr, 8, 176, 85, 3, 5);
2513 } else {
2514 mapMessageId(mesgId);
2515 switch (f) {
2516 case 2:
2517 case 8:
2518 clearDescriptionBar();
2519 prepareScreenType2();
2520 displayTextInDescriptionBar(8, 182, 103, mesgId);
2521 if ((mesgId == 68) || (mesgId == 69))
2522 _coreVar._availableQuestion[40] = '*';
2523 else if ((mesgId == 104) && (_caff == CELLAR)) {
2524 _coreVar._availableQuestion[36] = '*';
2525 if (_coreVar._availableQuestion[39] == '*') {
2526 _coreVar._pctHintFound[3] = '*';
2527 _coreVar._availableQuestion[38] = '*';
2528 }
2529 }
2530 break;
2531 case 1:
2532 case 6:
2533 case 9: {
2534 int i;
2535 if ((f == 1) || (f == 6))
2536 i = 4;
2537 else
2538 i = 5;
2539
2540 Common::String tmpStr = getString(mesgId);
2541 _text->displayStr(tmpStr, 80, 40, 60, 25, i);
2542
2543 if (mesgId == 180)
2544 _coreVar._pctHintFound[6] = '*';
2545 else if (mesgId == 179)
2546 _coreVar._pctHintFound[10] = '*';
2547 }
2548 break;
2549 case 7: {
2550 prepareScreenType3();
2551 Common::String tmpStr = getString(mesgId);
2552 // CHECKME: original code seems to consider one extra character
2553 // See text position in the 3rd intro screen
2554 int size = tmpStr.size() + 1;
2555 if (size < 40)
2556 _text->displayStr(tmpStr, 252 - size * 3, 86, 50, 3, 5);
2557 else
2558 _text->displayStr(tmpStr, 144, 86, 50, 3, 5);
2559 }
2560 break;
2561 default:
2562 break;
2563 }
2564 }
2565 }
2566
2567 /**
2568 * Recompute message Id
2569 * @remarks Originally called 'modif'
2570 */
mapMessageId(int & mesgId)2571 void MortevielleEngine::mapMessageId(int &mesgId) {
2572 if (mesgId == 26)
2573 mesgId = 25;
2574 else if ((mesgId > 29) && (mesgId < 36))
2575 mesgId -= 4;
2576 else if ((mesgId > 69) && (mesgId < 78))
2577 mesgId -= 37;
2578 else if ((mesgId > 99) && (mesgId < 194))
2579 mesgId -= 59;
2580 else if ((mesgId > 996) && (mesgId < 1000))
2581 mesgId -= 862;
2582 else if ((mesgId > 1500) && (mesgId < 1507))
2583 mesgId -= 1363;
2584 else if ((mesgId > 1507) && (mesgId < 1513))
2585 mesgId -= 1364;
2586 else if ((mesgId > 1999) && (mesgId < 2002))
2587 mesgId -= 1851;
2588 else if (mesgId == 2010)
2589 mesgId = 151;
2590 else if ((mesgId > 2011) && (mesgId < 2025))
2591 mesgId -= 1860;
2592 else if (mesgId == 2026)
2593 mesgId = 165;
2594 else if ((mesgId > 2029) && (mesgId < 2037))
2595 mesgId -= 1864;
2596 else if ((mesgId > 3000) && (mesgId < 3005))
2597 mesgId -= 2828;
2598 else if (mesgId == 4100)
2599 mesgId = 177;
2600 else if (mesgId == 4150)
2601 mesgId = 178;
2602 else if ((mesgId > 4151) && (mesgId < 4156))
2603 mesgId -= 3973;
2604 else if (mesgId == 4157)
2605 mesgId = 183;
2606 else if ((mesgId == 4160) || (mesgId == 4161))
2607 mesgId -= 3976;
2608 }
2609
2610 /**
2611 * Initialize open objects array
2612 * @remarks Originally called 'initouv'
2613 */
resetOpenObjects()2614 void MortevielleEngine::resetOpenObjects() {
2615 for (int i = 1; i <= 6; ++i)
2616 _openObjects[i] = 0;
2617 _openObjCount = 0;
2618 }
2619
2620 /**
2621 * Display Text Block
2622 * @remarks Originally called 'ecr2'
2623 */
displayTextBlock(Common::String text)2624 void MortevielleEngine::displayTextBlock(Common::String text) {
2625 // Some dead code was present in the original: removed
2626 _screenSurface->putxy(8, 177);
2627 int tlig = 59 + (kResolutionScaler - 1) * 36;
2628
2629 if ((int)text.size() < tlig)
2630 _screenSurface->drawString(text, 5);
2631 else if ((int)text.size() < (tlig << 1)) {
2632 _screenSurface->putxy(8, 176);
2633 _screenSurface->drawString(copy(text, 1, (tlig - 1)), 5);
2634 _screenSurface->putxy(8, 182);
2635 _screenSurface->drawString(copy(text, tlig, tlig << 1), 5);
2636 } else {
2637 _largestClearScreen = true;
2638 clearDescriptionBar();
2639 _screenSurface->putxy(8, 176);
2640 _screenSurface->drawString(copy(text, 1, (tlig - 1)), 5);
2641 _screenSurface->putxy(8, 182);
2642 _screenSurface->drawString(copy(text, tlig, ((tlig << 1) - 1)), 5);
2643 _screenSurface->putxy(8, 190);
2644 _screenSurface->drawString(copy(text, tlig << 1, tlig * 3), 5);
2645 }
2646 }
2647
displayTextInVerbBar(Common::String text)2648 void MortevielleEngine::displayTextInVerbBar(Common::String text) {
2649 clearVerbBar();
2650 _screenSurface->putxy(8, 192);
2651 _screenSurface->drawString(text, 5);
2652 }
2653
2654 /**
2655 * Display item in hand
2656 * @remarks Originally called 'modobj'
2657 */
displayItemInHand(int objId)2658 void MortevielleEngine::displayItemInHand(int objId) {
2659 Common::String strp = Common::String(' ');
2660
2661 if (objId != 500)
2662 strp = getString(objId - 501 + kInventoryStringIndex);
2663
2664 _menu->setText(_menu->_inventoryMenu[8], strp);
2665 _menu->disableMenuItem(_menu->_inventoryMenu[8]);
2666 }
2667
2668 /**
2669 * Display empty hand
2670 * @remarks Originally called 'maivid'
2671 */
displayEmptyHand()2672 void MortevielleEngine::displayEmptyHand() {
2673 _coreVar._selectedObjectId = 0;
2674 displayItemInHand(500);
2675 }
2676
2677 /**
2678 * Set a random presence: Leo or Max
2679 * @remarks Originally called 'chlm'
2680 */
checkLeoMaxRandomPresence()2681 int MortevielleEngine::checkLeoMaxRandomPresence() {
2682 int retval = getRandomNumber(1, 2);
2683 if (retval == 2)
2684 retval = 128;
2685
2686 return retval;
2687 }
2688
2689 /**
2690 * Reset room variables
2691 * @remarks Originally called 'debloc'
2692 */
resetRoomVariables(int roomId)2693 void MortevielleEngine::resetRoomVariables(int roomId) {
2694 _num = 0;
2695 _x = 0;
2696 _y = 0;
2697 if ((roomId != ROOM26) && (roomId != LANDING))
2698 resetPresenceInRooms(roomId);
2699 _savedBitIndex = _currBitIndex;
2700 }
2701
2702 /**
2703 * Compute presence stats
2704 * @remarks Originally called 'ecfren'
2705 */
getPresenceStats(int & rand,int faithScore,int roomId)2706 int MortevielleEngine::getPresenceStats(int &rand, int faithScore, int roomId) {
2707 if (roomId == OWN_ROOM)
2708 displayAloneText();
2709 int retVal = -500;
2710 rand = 0;
2711 if ( ((roomId == GREEN_ROOM) && (!_roomPresenceLuc) && (!_roomPresenceIda))
2712 || ((roomId == DARKBLUE_ROOM) && (!_roomPresenceGuy) && (!_roomPresenceEva)) )
2713 retVal = getPresenceStatsGreenRoom();
2714 if ((roomId == PURPLE_ROOM) && (!_purpleRoomPresenceLeo) && (!_juliaRoomPresenceLeo))
2715 retVal = getPresenceStatsPurpleRoom();
2716 if ( ((roomId == TOILETS) && (!_toiletsPresenceBobMax))
2717 || ((roomId == BATHROOM) && (!_bathRoomPresenceBobMax)) )
2718 retVal = getPresenceStatsToilets();
2719 if ((roomId == BLUE_ROOM) && (!_roomPresenceMax))
2720 retVal = getPresenceStatsBlueRoom();
2721 if ( ((roomId == RED_ROOM) && (!_roomPresenceBob))
2722 || ((roomId == GREEN_ROOM2) && (!_roomPresencePat)))
2723 retVal = getPresenceStatsRedRoom();
2724 if ((roomId == JULIA_ROOM) && (!_juliaRoomPresenceLeo) && (!_purpleRoomPresenceLeo))
2725 retVal = 10;
2726 if ( ((roomId == PURPLE_ROOM) && (_juliaRoomPresenceLeo))
2727 || ((roomId == JULIA_ROOM) && (_purpleRoomPresenceLeo)))
2728 retVal = -400;
2729 if (retVal != -500) {
2730 retVal += faithScore;
2731 rand = getRandomNumber(1, 100);
2732 }
2733
2734 return retVal;
2735 }
2736
2737 /**
2738 * Set presence flags
2739 * @remarks Originally called 'becfren'
2740 */
setPresenceFlags(int roomId)2741 void MortevielleEngine::setPresenceFlags(int roomId) {
2742 if ((roomId == GREEN_ROOM) || (roomId == DARKBLUE_ROOM)) {
2743 int rand = getRandomNumber(1, 2);
2744 if (roomId == GREEN_ROOM) {
2745 if (rand == 1)
2746 _roomPresenceLuc = true;
2747 else
2748 _roomPresenceIda = true;
2749 } else { // roomId == DARKBLUE_ROOM
2750 if (rand == 1)
2751 _roomPresenceGuy = true;
2752 else
2753 _roomPresenceEva = true;
2754 }
2755 } else if (roomId == PURPLE_ROOM)
2756 _purpleRoomPresenceLeo = true;
2757 else if (roomId == TOILETS)
2758 _toiletsPresenceBobMax = true;
2759 else if (roomId == BLUE_ROOM)
2760 _roomPresenceMax = true;
2761 else if (roomId == RED_ROOM)
2762 _roomPresenceBob = true;
2763 else if (roomId == BATHROOM)
2764 _bathRoomPresenceBobMax = true;
2765 else if (roomId == GREEN_ROOM2)
2766 _roomPresencePat = true;
2767 else if (roomId == JULIA_ROOM)
2768 _juliaRoomPresenceLeo = true;
2769 }
2770
2771 /**
2772 * Initialize max answers per character
2773 * @remarks Originally called 'init_nbrepm'
2774 */
initMaxAnswer()2775 void MortevielleEngine::initMaxAnswer() {
2776 static const byte maxAnswer[9] = { 0, 4, 5, 6, 7, 5, 6, 5, 8 };
2777
2778 for (int idx = 0; idx < 9; ++idx) {
2779 _charAnswerMax[idx] = maxAnswer[idx];
2780 _charAnswerCount[idx] = 0;
2781 }
2782 }
2783
2784 /**
2785 * Get Presence
2786 * @remarks Originally called 't11'
2787 */
getPresence(int roomId)2788 int MortevielleEngine::getPresence(int roomId) {
2789 int retVal = 0;
2790 int rand;
2791
2792 int pres = getPresenceStats(rand, _coreVar._faithScore, roomId);
2793 _place = roomId;
2794 if ((roomId > OWN_ROOM) && (roomId < DINING_ROOM)) {
2795 if (pres != -500) {
2796 if (rand > pres) {
2797 displayAloneText();
2798 retVal = 0;
2799 } else {
2800 setPresenceFlags(_place);
2801 retVal = getPresenceBitIndex(_place);
2802 }
2803 } else
2804 retVal = getPresenceBitIndex(_place);
2805 }
2806
2807 if (roomId > JULIA_ROOM) {
2808 if ((roomId > LANDING) && (roomId != CHAPEL) && (roomId != ROOM26))
2809 displayAloneText();
2810 else {
2811 int h = 0;
2812 switch (roomId) {
2813 case DINING_ROOM:
2814 pres = getPresenceStatsDiningRoom(h);
2815 break;
2816 case BUREAU:
2817 pres = getPresenceStatsBureau(h);
2818 break;
2819 case KITCHEN:
2820 pres = getPresenceStatsKitchen();
2821 break;
2822 case ATTIC:
2823 case CELLAR:
2824 pres = getPresenceStatsAttic();
2825 break;
2826 case LANDING:
2827 case ROOM26:
2828 pres = getPresenceStatsLanding();
2829 break;
2830 case CHAPEL:
2831 pres = getPresenceStatsChapel(h);
2832 break;
2833 }
2834 pres += _coreVar._faithScore;
2835 rand = getRandomNumber(1, 100);
2836 if (rand > pres) {
2837 displayAloneText();
2838 retVal = 0;
2839 } else {
2840 switch (roomId) {
2841 case DINING_ROOM:
2842 pres = setPresenceDiningRoom(h);
2843 break;
2844 case BUREAU:
2845 pres = setPresenceBureau(h);
2846 break;
2847 case KITCHEN:
2848 case ATTIC:
2849 case CELLAR:
2850 pres = setPresenceKitchen();
2851 break;
2852 case LANDING:
2853 case ROOM26:
2854 pres = setPresenceLanding();
2855 break;
2856 case CHAPEL:
2857 pres = setPresenceChapel(h);
2858 break;
2859 }
2860 retVal = pres;
2861 }
2862 }
2863 }
2864
2865 return retVal;
2866 }
2867
2868 /**
2869 * Display Question String
2870 * @remarks Originally called 'writetp'
2871 */
displayQuestionText(Common::String s,int cmd)2872 void MortevielleEngine::displayQuestionText(Common::String s, int cmd) {
2873 _screenSurface->drawString(s, cmd);
2874 }
2875
2876 /**
2877 * Display animation frame
2878 * @remarks Originally called 'aniof'
2879 */
displayAnimFrame(int frameNum,int animId)2880 void MortevielleEngine::displayAnimFrame(int frameNum, int animId) {
2881 if ((_caff == BATHROOM) && ((animId == 4) || (animId == 5)))
2882 return;
2883
2884 if ((_caff == DINING_ROOM) && (animId == 7))
2885 animId = 6;
2886 else if (_caff == KITCHEN) {
2887 if (animId == 3)
2888 animId = 4;
2889 else if (animId == 4)
2890 animId = 3;
2891 }
2892
2893 int offset = getAnimOffset(frameNum, animId);
2894
2895 GfxSurface surface;
2896 surface.decode(&_curAnim[offset]);
2897 _screenSurface->drawPicture(surface, 0, 12);
2898
2899 prepareScreenType1();
2900 }
2901
2902 /**
2903 * Draw Picture
2904 * @remarks Originally called 'dessin'
2905 */
drawPicture()2906 void MortevielleEngine::drawPicture() {
2907 clearUpperLeftPart();
2908 if (_caff > 99) {
2909 draw(60, 33);
2910 _screenSurface->drawBox(118, 32, 291, 121, 15); // Medium box
2911 } else if (_caff > 69) {
2912 draw(112, 48); // Heads
2913 _screenSurface->drawBox(222, 47, 155, 91, 15);
2914 } else {
2915 draw(0, 12);
2916 prepareScreenType1();
2917 if ((_caff < 30) || (_caff > 32)) {
2918 for (int i = 1; i <= 6; ++i) {
2919 if (_openObjects[i] != 0)
2920 displayAnimFrame(1, _openObjects[i]);
2921 }
2922
2923 switch (_caff) {
2924 case ATTIC:
2925 if (_coreVar._atticBallHoleObjectId == 141)
2926 displayAnimFrame(1, 7);
2927
2928 if (_coreVar._atticRodHoleObjectId == 159)
2929 displayAnimFrame(1, 6);
2930 break;
2931 case CELLAR:
2932 if (_coreVar._cellarObjectId == 151)
2933 displayAnimFrame(1, 2);
2934 break;
2935 case SECRET_PASSAGE:
2936 if (_coreVar._secretPassageObjectId == 143)
2937 displayAnimFrame(1, 1);
2938 break;
2939 case WELL:
2940 if (_coreVar._wellObjectId != 0)
2941 displayAnimFrame(1, 1);
2942 break;
2943 }
2944 }
2945
2946 if (_caff < ROOM26)
2947 startMusicOrSpeech(1);
2948 }
2949 }
2950
2951 /**
2952 * @remarks Originally called 'afdes'
2953 */
drawPictureWithText()2954 void MortevielleEngine::drawPictureWithText() {
2955 _text->taffich();
2956 drawPicture();
2957 _destinationOk = false;
2958 }
2959
2960 /**
2961 * Engine function - Place
2962 * @remarks Originally called 'tkey1'
2963 */
testKey(bool d)2964 void MortevielleEngine::testKey(bool d) {
2965 bool quest = false;
2966 int x, y;
2967 bool click;
2968
2969 _mouse->hideMouse();
2970 displayStatusInDescriptionBar('K');
2971
2972 // Wait for release from any key or mouse button
2973 while (keyPressed())
2974 _key = gettKeyPressed();
2975
2976 do {
2977 _mouse->getMousePosition(x, y, click);
2978 quest = keyPressed();
2979 if (quest && shouldQuit())
2980 return;
2981 } while (click);
2982
2983 // Event loop
2984 do {
2985 if (d)
2986 prepareRoom();
2987 quest = keyPressed();
2988 _mouse->getMousePosition(x, y, click);
2989 if (shouldQuit())
2990 return;
2991 } while (!(quest || (click) || (d && _anyone)));
2992 if (quest)
2993 gettKeyPressed();
2994 setMouseClick(false);
2995 _mouse->showMouse();
2996 }
2997
2998 /**
2999 * Display Narrative Picture
3000 * @remarks Originally called 'tlu'
3001 */
displayNarrativePicture(int af,int ob)3002 void MortevielleEngine::displayNarrativePicture(int af, int ob) {
3003 _caff = 32;
3004 drawPictureWithText();
3005 handleDescriptionText(6, ob + 4000);
3006 handleDescriptionText(2, 999);
3007 testKey(true);
3008 _caff = af;
3009 _currMenu = OPCODE_NONE;
3010 _crep = 998;
3011 }
3012
3013 /**
3014 * Display a message switching from a screen to another.
3015 * @remarks Originally called 'messint'
3016 */
displayInterScreenMessage(int mesgId)3017 void MortevielleEngine::displayInterScreenMessage(int mesgId) {
3018 clearUpperLeftPart();
3019 clearDescriptionBar();
3020 clearVerbBar();
3021
3022 GfxSurface surface;
3023 surface.decode(_rightFramePict + 1008);
3024 surface._offset.x = 80;
3025 surface._offset.y = 40;
3026 setPal(90);
3027 _screenSurface->drawPicture(surface, 0, 0);
3028 _screenSurface->drawPicture(surface, 0, 70);
3029 handleDescriptionText(7, mesgId);
3030 delay(DISK_ACCESS_DELAY);
3031 }
3032
3033 /**
3034 * Prepare Display Text
3035 * @remarks Originally called 'affrep'
3036 */
prepareDisplayText()3037 void MortevielleEngine::prepareDisplayText() {
3038 _caff = _coreVar._currPlace;
3039 _crep = _coreVar._currPlace;
3040 }
3041
3042 /**
3043 * Exit room
3044 * @remarks Originally called 'tsort'
3045 */
exitRoom()3046 void MortevielleEngine::exitRoom() {
3047 if ((_openObjCount > 0) && (_coreVar._currPlace != OWN_ROOM)) {
3048 if (_coreVar._faithScore < 50)
3049 _coreVar._faithScore += 2;
3050 else
3051 _coreVar._faithScore += (_coreVar._faithScore / 10);
3052 }
3053
3054 resetOpenObjects();
3055
3056 _roomDoorId = OWN_ROOM;
3057 _curSearchObjId = 0;
3058 resetRoomVariables(_coreVar._currPlace);
3059 }
3060
3061 /**
3062 * get 'read' description
3063 * @remarks Originally called 'st4'
3064 */
getReadDescription(int objId)3065 void MortevielleEngine::getReadDescription(int objId) {
3066 _crep = 997;
3067
3068 switch (objId) {
3069 case 114 :
3070 _crep = 109;
3071 break;
3072 case 110 :
3073 _crep = 107;
3074 break;
3075 case 158 :
3076 _crep = 113;
3077 break;
3078 case 152:
3079 case 153:
3080 case 154:
3081 case 155:
3082 case 156:
3083 case 150:
3084 case 100:
3085 case 157:
3086 case 160:
3087 case 161 :
3088 displayNarrativePicture(_caff, objId);
3089 break;
3090 default:
3091 break;
3092 }
3093 }
3094
3095 /**
3096 * get 'search' description
3097 * @remarks Originally called 'st7'
3098 */
getSearchDescription(int objId)3099 void MortevielleEngine::getSearchDescription(int objId) {
3100 switch (objId) {
3101 case 116:
3102 case 144:
3103 _crep = 104;
3104 break;
3105 case 126:
3106 case 111:
3107 _crep = 108;
3108 break;
3109 case 132:
3110 _crep = 111;
3111 break;
3112 case 142:
3113 _crep = 112;
3114 break;
3115 default:
3116 _crep = 183;
3117 getReadDescription(objId);
3118 }
3119 }
3120
3121 /**
3122 * Menu up
3123 * @remarks Originally called 'mennor'
3124 */
menuUp()3125 void MortevielleEngine::menuUp() {
3126 _menu->menuUp(_currMenu);
3127 }
3128
3129 /**
3130 * Draw discussion box
3131 * @remarks Originally called 'premtet'
3132 */
drawDiscussionBox()3133 void MortevielleEngine::drawDiscussionBox() {
3134 draw(10, 80);
3135 _screenSurface->drawBox(18, 79, 155, 91, 15);
3136 }
3137
3138 /**
3139 * Try to put an object somewhere
3140 * @remarks Originally called 'ajchai'
3141 */
putObject()3142 void MortevielleEngine::putObject() {
3143 int putId = kAcha + ((_curSearchObjId - 1) * 10) - 1;
3144 int i;
3145 for (i = 1; (i <= 9) && (_tabdon[putId + i] != 0); i++)
3146 ;
3147
3148 if (_tabdon[putId + i] == 0)
3149 _tabdon[putId + i] = _coreVar._selectedObjectId;
3150 else
3151 _crep = 192;
3152 }
3153
3154 /**
3155 * Check if inventory is full and, if not, add object in it.
3156 * @remarks Originally called 'ajjer'
3157 */
addObjectToInventory(int objectId)3158 void MortevielleEngine::addObjectToInventory(int objectId) {
3159 int i;
3160
3161 for (i = 1; (i <= 5) && (_coreVar._inventory[i] != 0); i++)
3162 ;
3163
3164 if (_coreVar._inventory[i] == 0) {
3165 _coreVar._inventory[i] = objectId;
3166 _menu->setInventoryText();
3167 } else
3168 // Inventory is full
3169 _crep = 139;
3170 }
3171
3172 /**
3173 * Interact with NPC
3174 * @remarks Originally called 'quelquun'
3175 */
interactNPC()3176 void MortevielleEngine::interactNPC() {
3177 if (_menu->_menuDisplayed)
3178 _menu->eraseMenu();
3179
3180 endSearch();
3181 _crep = 997;
3182 L1:
3183 if (!_hiddenHero) {
3184 if (_crep == 997)
3185 _crep = 138;
3186 handleDescriptionText(2, _crep);
3187 if (_crep == 138)
3188 _soundManager->startSpeech(5, 2, 1);
3189 else
3190 _soundManager->startSpeech(4, 4, 1);
3191
3192 if (_openObjCount == 0)
3193 _coreVar._faithScore += 2;
3194 else if (_coreVar._faithScore < 50)
3195 _coreVar._faithScore += 4;
3196 else
3197 _coreVar._faithScore += 3 * (_coreVar._faithScore / 10);
3198 exitRoom();
3199 _menu->setDestinationText(LANDING);
3200 int charIdx = convertBitIndexToCharacterIndex(_currBitIndex);
3201 _caff = 69 + charIdx;
3202 _crep = _caff;
3203 _currMenu = MENU_DISCUSS;
3204 _currAction = (_menu->_discussMenu[charIdx]._menuId << 8) | _menu->_discussMenu[charIdx]._actionId;
3205 _syn = true;
3206 _col = true;
3207 } else {
3208 if (getRandomNumber(1, 3) == 2) {
3209 _hiddenHero = false;
3210 _crep = 137;
3211 goto L1;
3212 } else {
3213 handleDescriptionText(2, 136);
3214 int rand = (getRandomNumber(0, 4)) - 2;
3215 _soundManager->startSpeech(3, rand, 1);
3216 clearDescriptionBar();
3217 displayAloneText();
3218 resetRoomVariables(MANOR_FRONT);
3219 prepareDisplayText();
3220 }
3221 }
3222 if (_menu->_menuDisplayed)
3223 _menu->drawMenu();
3224 }
3225
3226 /**
3227 * Search - Prepare next object
3228 * @remarks Originally called 'tsuiv'
3229 */
prepareNextObject()3230 void MortevielleEngine::prepareNextObject() {
3231 int objId;
3232 int tabIdx = kAcha + ((_curSearchObjId - 1) * 10) - 1;
3233 int localSeearchCount = 0;
3234 do {
3235 ++localSeearchCount;
3236 ++_searchCount;
3237 objId = _tabdon[tabIdx + _searchCount];
3238 } while ((objId == 0) && (_searchCount <= 9));
3239
3240 if ((objId != 0) && (_searchCount < 11)) {
3241 _is++;
3242 _caff = objId;
3243 _crep = _caff + 400;
3244 if (_currBitIndex != 0)
3245 // Someone is present in the room
3246 _coreVar._faithScore += 2;
3247 } else {
3248 prepareDisplayText();
3249 endSearch();
3250 if (localSeearchCount > 9)
3251 _crep = 131;
3252 }
3253 }
3254
3255 /**
3256 * Display Arrow status
3257 * @remarks Originally called 'tfleche'
3258 */
displayStatusArrow()3259 void MortevielleEngine::displayStatusArrow() {
3260 bool qust;
3261 char touch;
3262
3263 if (_num == 9999)
3264 return;
3265
3266 displayStatusInDescriptionBar((unsigned char)152);
3267 bool inRect = false;
3268 do {
3269 touch = '\0';
3270
3271 do {
3272 _mouse->moveMouse(qust, touch);
3273 if (shouldQuit())
3274 return;
3275
3276 if (getMouseClick())
3277 inRect = (_mouse->_pos.x < 256 * kResolutionScaler) && (_mouse->_pos.y < 176) && (_mouse->_pos.y > 12);
3278 prepareRoom();
3279 } while (!(qust || inRect || _anyone));
3280
3281 if (qust && (touch == '\103'))
3282 _dialogManager->show(_hintPctMessage);
3283 } while (!((touch == '\73') || ((touch == '\104') && (_x != 0) && (_y != 0)) || (_anyone) || (inRect)));
3284
3285 if (touch == '\73')
3286 _keyPressedEsc = true;
3287
3288 if (inRect) {
3289 _x = _mouse->_pos.x;
3290 _y = _mouse->_pos.y;
3291 }
3292 }
3293
3294 /**
3295 * Set coordinates
3296 * @remarks Originally called 'tcoord'
3297 */
setCoordinates(int sx)3298 void MortevielleEngine::setCoordinates(int sx) {
3299 int sy, ix, iy;
3300 int ib;
3301
3302
3303 _num = 0;
3304 _crep = 999;
3305 int a = 0;
3306 int atdon = kAmzon + 3;
3307 int cy = 0;
3308 while (cy < _caff) {
3309 a += _tabdon[atdon];
3310 atdon += 4;
3311 ++cy;
3312 }
3313
3314 if (_tabdon[atdon] == 0) {
3315 _crep = 997;
3316 return;
3317 }
3318
3319 a += kFleche;
3320 int cb = 0;
3321 for (cy = 0; cy <= (sx - 2); ++cy) {
3322 ib = (_tabdon[a + cb] << 8) + _tabdon[(a + cb + 1)];
3323 cb += (ib * 4) + 2;
3324 }
3325 ib = (_tabdon[a + cb] << 8) + _tabdon[(a + cb + 1)];
3326 if (ib == 0) {
3327 _crep = 997;
3328 return;
3329 }
3330
3331 cy = 1;
3332 do {
3333 cb += 2;
3334 sx = _tabdon[a + cb] * kResolutionScaler;
3335 sy = _tabdon[(a + cb + 1)];
3336 cb += 2;
3337 ix = _tabdon[a + cb] * kResolutionScaler;
3338 iy = _tabdon[(a + cb + 1)];
3339 ++cy;
3340 } while (!(((_x >= sx) && (_x <= ix) && (_y >= sy) && (_y <= iy)) || (cy > ib)));
3341
3342 if ((_x >= sx) && (_x <= ix) && (_y >= sy) && (_y <= iy)) {
3343 _num = cy - 1;
3344 return;
3345 }
3346
3347 _crep = 997;
3348 }
3349
3350 /**
3351 * Display LOOK Screen
3352 * @remarks Originally called 'treg'
3353 */
displayLookScreen(int objId)3354 void MortevielleEngine::displayLookScreen(int objId) {
3355 int mdes = _caff;
3356 _caff = objId;
3357
3358 if (((_caff > 29) && (_caff < 33)) || (_caff == 144) || (_caff == 147) || (_caff == 149) || (_currAction == _menu->_opcodeSLook)) {
3359 drawPictureWithText();
3360 if ((_caff > 29) && (_caff < 33))
3361 handleDescriptionText(2, _caff);
3362 else
3363 handleDescriptionText(2, _caff + 400);
3364 testKey(true);
3365 _caff = mdes;
3366 _currMenu = MENU_NONE;
3367 _crep = 998;
3368 } else {
3369 _obpart = true;
3370 _crep = _caff + 400;
3371 _menu->setSearchMenu();
3372 }
3373 }
3374
3375 /**
3376 * Engine function - Put in hand
3377 * @remarks Originally called 'avpoing'
3378 */
putInHand(int & objId)3379 void MortevielleEngine::putInHand(int &objId) {
3380 _crep = 999;
3381 if (_coreVar._selectedObjectId != 0)
3382 addObjectToInventory(_coreVar._selectedObjectId);
3383
3384 // If inventory wasn't full
3385 if (_crep != 139) {
3386 displayItemInHand(objId + 400);
3387 _coreVar._selectedObjectId = objId;
3388 objId = 0;
3389 }
3390 }
3391
3392 /**
3393 * Search - Get the first object
3394 * @remarks Originally called 'rechai'
3395 */
getFirstObject()3396 int MortevielleEngine::getFirstObject() {
3397 int tmpPlace = _coreVar._currPlace;
3398
3399 if (_coreVar._currPlace == CRYPT)
3400 tmpPlace = CELLAR;
3401
3402 return _tabdon[kAsearch + (tmpPlace * 7) + _num - 1];
3403 }
3404
3405 /**
3406 * Check before leaving the secret passage
3407 * @remarks Originally called 't23coul'
3408 */
checkLeaveSecretPassage()3409 int MortevielleEngine::checkLeaveSecretPassage() {
3410 if (!checkInventory(143)) {
3411 _crep = 1512;
3412 loseGame();
3413 }
3414
3415 return CELLAR;
3416 }
3417
3418 /**
3419 * Display status character in description bar
3420 * @remarks Originally called 'fenat'
3421 */
displayStatusInDescriptionBar(char stat)3422 void MortevielleEngine::displayStatusInDescriptionBar(char stat) {
3423 _mouse->hideMouse();
3424 _screenSurface->writeCharacter(Common::Point(306, 193), stat, 12);
3425 _screenSurface->drawBox(300, 191, 16, 8, 15);
3426 _mouse->showMouse();
3427 }
3428
3429 /**
3430 * Test Keyboard
3431 * @remarks Originally called 'teskbd'
3432 */
testKeyboard()3433 void MortevielleEngine::testKeyboard() {
3434 if (keyPressed())
3435 gettKeyPressed();
3436 }
3437
3438 /**
3439 * Test Key Pressed
3440 * @remarks Originally called 'testou'
3441 */
gettKeyPressed()3442 int MortevielleEngine::gettKeyPressed() {
3443 char ch = getChar();
3444
3445 switch (ch) {
3446 case '\23' :
3447 _soundOff = !_soundOff;
3448 break;
3449 case '\26' :
3450 if ((_x26KeyCount == 1) || (_x26KeyCount == 2)) {
3451 decodeNumber(&_cfiecBuffer[161 * 16], (_cfiecBufferSize - (161 * 16)) / 64);
3452 ++_x26KeyCount;
3453
3454 return 61;
3455 }
3456 break;
3457 case '\33' :
3458 if (keyPressed())
3459 ch = getChar();
3460 break;
3461 default:
3462 break;
3463 }
3464
3465 return (int)ch;
3466 }
3467
3468 } // End of namespace Mortevielle
3469