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 Tony Tough source code
25 *
26 * Copyright (c) 1997-2003 Nayma Software
27 */
28
29 #include "common/savefile.h"
30 #include "tony/mpal/lzo.h"
31 #include "tony/mpal/mpalutils.h"
32 #include "tony/custom.h"
33 #include "tony/gfxengine.h"
34 #include "tony/tony.h"
35
36 namespace Tony {
37
38 /****************************************************************************\
39 * RMGfxEngine Methods
40 \****************************************************************************/
41
exitAllIdles(CORO_PARAM,const void * param)42 void exitAllIdles(CORO_PARAM, const void *param) {
43 CORO_BEGIN_CONTEXT;
44 CORO_END_CONTEXT(_ctx);
45
46 int nCurLoc = *(const int *)param;
47
48 CORO_BEGIN_CODE(_ctx);
49
50 // Closes idle
51 GLOBALS._bSkipSfxNoLoop = true;
52
53 CORO_INVOKE_2(mpalEndIdlePoll, nCurLoc, NULL);
54
55 GLOBALS._bIdleExited = true;
56 GLOBALS._bSkipSfxNoLoop = false;
57
58 CORO_END_CODE;
59 }
60
RMGfxEngine()61 RMGfxEngine::RMGfxEngine() {
62 // Create big buffer where the frame will be rendered
63 _bigBuf.create(RM_BBX, RM_BBY, 16);
64 _bigBuf.offsetY(RM_SKIPY);
65 _bigBuf.setTrackDirtyRects(true);
66
67 _nCurLoc = 0;
68 _curAction = TA_GOTO;
69 _curActionObj = 0;
70 _nWipeType = 0;
71 _hWipeEvent = 0;
72 _nWipeStep = 0;
73 _bMustEnterMenu = false;
74 _bWiping = false;
75 _bGUIOption = false;
76 _bGUIInterface = false;
77 _bGUIInventory = false;
78 _bAlwaysDrawMouse = false;
79 _bOption = false;
80 _bLocationLoaded = false;
81 _bInput = false;
82 }
83
~RMGfxEngine()84 RMGfxEngine::~RMGfxEngine() {
85 // Close the buffer
86 _bigBuf.destroy();
87 }
88
openOptionScreen(CORO_PARAM,int type)89 void RMGfxEngine::openOptionScreen(CORO_PARAM, int type) {
90 CORO_BEGIN_CONTEXT;
91 bool bRes;
92 CORO_END_CONTEXT(_ctx);
93
94 CORO_BEGIN_CODE(_ctx);
95
96 _ctx->bRes = false;
97
98 if (type == 0)
99 CORO_INVOKE_2(_opt.init, _bigBuf, _ctx->bRes);
100 else if (type == 1)
101 CORO_INVOKE_3(_opt.initLoadMenuOnly, _bigBuf, true, _ctx->bRes);
102 else if (type == 2)
103 CORO_INVOKE_2(_opt.initNoLoadSave, _bigBuf, _ctx->bRes);
104 else if (type == 3)
105 CORO_INVOKE_3(_opt.initLoadMenuOnly, _bigBuf, false, _ctx->bRes);
106 else if (type == 4)
107 CORO_INVOKE_3(_opt.initSaveMenuOnly, _bigBuf, false, _ctx->bRes);
108
109 if (_ctx->bRes) {
110 g_vm->pauseSound(true);
111
112 disableInput();
113 _inv.endCombine();
114 _curActionObj = 0;
115 _curAction = TA_GOTO;
116 _point.setAction(_curAction);
117 _point.setSpecialPointer(RMPointer::PTR_NONE);
118 _point.setCustomPointer(NULL);
119 enableMouse();
120 g_vm->grabThumbnail();
121
122 // Exists the IDLE to avoid premature death in loading
123 _bMustEnterMenu = true;
124 if (type == 1 || type == 2) {
125 GLOBALS._bIdleExited = true;
126 } else {
127 CORO_INVOKE_0(_tony.stopNoAction);
128
129 GLOBALS._bIdleExited = false;
130
131 CoroScheduler.createProcess(exitAllIdles, &_nCurLoc, sizeof(int));
132 }
133 }
134
135 CORO_END_CODE;
136 }
137
doFrame(CORO_PARAM,bool bDrawLocation)138 void RMGfxEngine::doFrame(CORO_PARAM, bool bDrawLocation) {
139 CORO_BEGIN_CONTEXT;
140 CORO_END_CONTEXT(_ctx);
141
142 CORO_BEGIN_CODE(_ctx);
143
144 // Poll of input devices
145 _input.poll();
146
147 if (_bMustEnterMenu && GLOBALS._bIdleExited) {
148 _bOption = true;
149 _bMustEnterMenu = false;
150 GLOBALS._bIdleExited = false;
151 }
152
153 if (_bOption) {
154 CORO_INVOKE_1(_opt.doFrame, &_input);
155 _bOption = !_opt.isClosing();
156 if (!_bOption) {
157 disableMouse();
158 enableInput();
159 mpalStartIdlePoll(_nCurLoc);
160 g_vm->pauseSound(false);
161 }
162 }
163
164 if (bDrawLocation && _bLocationLoaded) {
165 // Location and objects
166 _loc.doFrame(&_bigBuf);
167
168 // Check the mouse input
169 if (_bInput && !_tony.inAction()) {
170 // If we are on the inventory, it is it who controls all input
171 if (_inv.haveFocus(_input.mousePos()) && !_inter.active()) {
172 // Left Click
173 // **********
174 if (_input.mouseLeftClicked()/* && m_itemName.IsItemSelected()*/) {
175 // Left click activates the combine, if we are on an object
176 if (_inv.leftClick(_input.mousePos(), _curActionObj)) {
177 _curAction = TA_COMBINE;
178 _point.setAction(_curAction);
179 }
180 } else
181
182 // Right Click
183 // ***********
184 if (_input.mouseRightClicked()) {
185 if (_itemName.isItemSelected()) {
186 _curActionObj = 0;
187 _inv.rightClick(_input.mousePos());
188 } else
189 _inv.rightClick(_input.mousePos());
190 } else
191
192 // Right Release
193 // *************
194 if (_input.mouseRightReleased()) {
195 if (_inv.rightRelease(_input.mousePos(), _curAction)) {
196 CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _curAction);
197
198 _curAction = TA_GOTO;
199 _point.setAction(_curAction);
200 }
201 }
202 } else {
203 // Options Menu
204 // ************
205 if (_bGUIOption) {
206 if (!_tony.inAction() && _bInput) {
207 if ((_input.mouseLeftClicked() && _input.mousePos()._x < 3 && _input.mousePos()._y < 3)) {
208 CORO_INVOKE_1(openOptionScreen, 0);
209 goto SKIPCLICKSINISTRO;
210 } else if (_input.getAsyncKeyState(Common::KEYCODE_ESCAPE))
211 CORO_INVOKE_1(openOptionScreen, 0);
212 else if (!g_vm->getIsDemo()) {
213 if (_input.getAsyncKeyState(Common::KEYCODE_F3) || _input.getAsyncKeyState(Common::KEYCODE_F5))
214 // Save game screen
215 CORO_INVOKE_1(openOptionScreen, 4);
216 else if (_input.getAsyncKeyState(Common::KEYCODE_F2) || _input.getAsyncKeyState(Common::KEYCODE_F7))
217 // Load game screen
218 CORO_INVOKE_1(openOptionScreen, 3);
219 }
220 }
221 }
222
223 // Left Click
224 // **************
225 if (_input.mouseLeftClicked() && !_inter.active()) {
226
227 if (_curAction != TA_COMBINE)
228 CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _point.curAction());
229 else if (_itemName.getSelectedItem() != NULL)
230 CORO_INVOKE_4(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), TA_COMBINE, _curActionObj);
231
232 if (_curAction == TA_COMBINE) {
233 _inv.endCombine();
234 _point.setSpecialPointer(RMPointer::PTR_NONE);
235 }
236
237 _curAction = TA_GOTO;
238 _point.setAction(_curAction);
239 }
240
241 SKIPCLICKSINISTRO:
242 // Right Click
243 // ************
244 if (_curAction == TA_COMBINE) {
245 // During a combine, it cancels it
246 if (_input.mouseRightClicked()) {
247 _inv.endCombine();
248 _curActionObj = 0;
249 _curAction = TA_GOTO;
250 _point.setAction(_curAction);
251 _point.setSpecialPointer(RMPointer::PTR_NONE);
252 }
253 } else if (_input.mouseRightClicked() && _itemName.isItemSelected() && _point.getSpecialPointer() == RMPointer::PTR_NONE) {
254 if (_bGUIInterface) {
255 // Before opening the interface, replaces GOTO
256 _curAction = TA_GOTO;
257 _curActionObj = 0;
258 _point.setAction(_curAction);
259 _inter.clicked(_input.mousePos());
260 }
261 }
262
263 // Right Release
264 // *************
265 if (_input.mouseRightReleased()) {
266 if (_bGUIInterface) {
267 if (_inter.released(_input.mousePos(), _curAction)) {
268 _point.setAction(_curAction);
269 CORO_INVOKE_3(_tony.moveAndDoAction, _itemName.getHotspot(), _itemName.getSelectedItem(), _curAction);
270
271 _curAction = TA_GOTO;
272 _point.setAction(_curAction);
273 }
274 }
275 }
276 }
277
278 // Update the name under the mouse pointer
279 _itemName.setMouseCoord(_input.mousePos());
280 if (!_inter.active() && !_inv.miniActive())
281 CORO_INVOKE_4(_itemName.doFrame, _bigBuf, _loc, _point, _inv);
282 }
283
284 // Interface & Inventory
285 _inter.doFrame(_bigBuf, _input.mousePos());
286 _inv.doFrame(_bigBuf, _point, _input.mousePos(), (!_tony.inAction() && !_inter.active() && _bGUIInventory));
287 }
288
289 // Animate Tony
290 CORO_INVOKE_2(_tony.doFrame, &_bigBuf, _nCurLoc);
291
292 // Update screen scrolling to keep Tony in focus
293 if (_tony.mustUpdateScrolling() && _bLocationLoaded) {
294 RMPoint showThis = _tony.position();
295 showThis._y -= 60;
296 _loc.updateScrolling(showThis);
297 }
298
299 if (_bLocationLoaded)
300 _tony.setScrollPosition(_loc.scrollPosition());
301
302 if ((!_tony.inAction() && _bInput) || _bAlwaysDrawMouse) {
303 _point.showCursor();
304 } else {
305 _point.hideCursor();
306 }
307 _point.doFrame();
308
309 // **********************
310 // Draw the list in the OT
311 // **********************
312 CORO_INVOKE_0(_bigBuf.drawOT);
313
314 #define FSTEP (480/32)
315
316 // Wipe
317 if (_bWiping) {
318 switch (_nWipeType) {
319 case 1:
320 if (!(_rcWipeEllipse.bottom - _rcWipeEllipse.top >= FSTEP * 2)) {
321 CoroScheduler.setEvent(_hWipeEvent);
322 _nWipeType = 3;
323 break;
324 }
325
326 _rcWipeEllipse.top += FSTEP;
327 _rcWipeEllipse.left += FSTEP;
328 _rcWipeEllipse.right -= FSTEP;
329 _rcWipeEllipse.bottom -= FSTEP;
330 break;
331
332 case 2:
333 if (!(_rcWipeEllipse.bottom - _rcWipeEllipse.top < 480 - FSTEP)) {
334 CoroScheduler.setEvent(_hWipeEvent);
335 _nWipeType = 3;
336 break;
337 }
338
339 _rcWipeEllipse.top -= FSTEP;
340 _rcWipeEllipse.left -= FSTEP;
341 _rcWipeEllipse.right += FSTEP;
342 _rcWipeEllipse.bottom += FSTEP;
343 break;
344 }
345 }
346
347 CORO_END_CODE;
348 }
349
initCustomDll()350 void RMGfxEngine::initCustomDll() {
351 setupGlobalVars(&_tony, &_point, &g_vm->_theBoxes, &_loc, &_inv, &_input);
352 }
353
itemIrq(uint32 dwItem,int nPattern,int nStatus)354 void RMGfxEngine::itemIrq(uint32 dwItem, int nPattern, int nStatus) {
355 assert(GLOBALS._gfxEngine);
356
357 if (GLOBALS._gfxEngine->_bLocationLoaded) {
358 RMItem *item = GLOBALS._gfxEngine->_loc.getItemFromCode(dwItem);
359 if (item != NULL) {
360 if (nPattern != -1) {
361 item->setPattern(nPattern, true);
362 }
363 if (nStatus != -1)
364 item->setStatus(nStatus);
365 }
366 }
367 }
368
initForNewLocation(int nLoc,RMPoint ptTonyStart,RMPoint start)369 void RMGfxEngine::initForNewLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
370 if (start._x == -1 || start._y == -1) {
371 start._x = ptTonyStart._x - RM_SX / 2;
372 start._y = ptTonyStart._y - RM_SY / 2;
373 }
374
375 _loc.setScrollPosition(start);
376
377 if (ptTonyStart._x == 0 && ptTonyStart._y == 0) {
378 } else {
379 _tony.setPosition(ptTonyStart, nLoc);
380 _tony.setScrollPosition(start);
381 }
382
383 _curAction = TA_GOTO;
384 _point.setCustomPointer(NULL);
385 _point.setSpecialPointer(RMPointer::PTR_NONE);
386 _point.setAction(_curAction);
387 _inter.reset();
388 _inv.reset();
389
390 mpalStartIdlePoll(_nCurLoc);
391 }
392
loadLocation(int nLoc,RMPoint ptTonyStart,RMPoint start)393 uint32 RMGfxEngine::loadLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
394 _nCurLoc = nLoc;
395
396 bool bLoaded = false;
397 for (int i = 0; i < 5; i++) {
398 // Try the loading of the location
399 RMRes res(_nCurLoc);
400 if (!res.isValid())
401 continue;
402
403 Common::SeekableReadStream *ds = res.getReadStream();
404 _loc.load(*ds);
405 delete ds;
406
407 initForNewLocation(nLoc, ptTonyStart, start);
408 bLoaded = true;
409 break;
410 }
411
412 if (!bLoaded)
413 error("Location was not loaded");
414
415 if (_bOption)
416 _opt.reInit(_bigBuf);
417
418 _bLocationLoaded = true;
419
420 // On entering the location
421 return CORO_INVALID_PID_VALUE; //mpalQueryDoAction(0, m_nCurLoc, 0);
422 }
423
unloadLocation(CORO_PARAM,bool bDoOnExit,uint32 * result)424 void RMGfxEngine::unloadLocation(CORO_PARAM, bool bDoOnExit, uint32 *result) {
425 CORO_BEGIN_CONTEXT;
426 uint32 h;
427 CORO_END_CONTEXT(_ctx);
428
429 CORO_BEGIN_CODE(_ctx);
430
431 // Release the location
432 CORO_INVOKE_2(mpalEndIdlePoll, _nCurLoc, NULL);
433
434 // On Exit?
435 if (bDoOnExit) {
436 _ctx->h = mpalQueryDoAction(1, _nCurLoc, 0);
437 if (_ctx->h != CORO_INVALID_PID_VALUE)
438 CORO_INVOKE_2(CoroScheduler.waitForSingleObject, _ctx->h, CORO_INFINITE);
439 }
440
441 _bLocationLoaded = false;
442
443 _bigBuf.clearOT();
444 _loc.unload();
445
446 if (result != NULL)
447 *result = CORO_INVALID_PID_VALUE;
448
449 CORO_END_CODE;
450 }
451
init()452 void RMGfxEngine::init() {
453 // Screen loading
454 RMGfxSourceBuffer16 *load = NULL;
455 RMResRaw *raw;
456 INIT_GFX16_FROMRAW(20038, load);
457 _bigBuf.addPrim(new RMGfxPrimitive(load));
458 _bigBuf.drawOT(Common::nullContext);
459 _bigBuf.clearOT();
460 delete load;
461
462 // Display 'Loading' screen
463 _bigBuf.addDirtyRect(Common::Rect(0, 0, RM_SX, RM_SY));
464 g_vm->_window.getNewFrame(*this, NULL);
465 g_vm->_window.repaint();
466
467 // Activate GUI
468 _bGUIOption = true;
469 _bGUIInterface = true;
470 _bGUIInventory = true;
471
472 GLOBALS._bSkipSfxNoLoop = false;
473 _bMustEnterMenu = false;
474 GLOBALS._bIdleExited = false;
475 _bOption = false;
476 _bWiping = false;
477 _hWipeEvent = CoroScheduler.createEvent(false, false);
478
479 // Initialize the IRQ function for items for MPAL
480 GLOBALS._gfxEngine = this;
481 mpalInstallItemIrq(itemIrq);
482
483 // Initialize the mouse pointer
484 _point.init();
485
486 // Initialize Tony
487 _tony.init();
488 _tony.linkToBoxes(&g_vm->_theBoxes);
489
490 // Initialize the inventory and the interface
491 _inv.init();
492 _inter.init();
493
494 // Download the location and set priorities @@@@@
495 _bLocationLoaded = false;
496
497 enableInput();
498
499 // Starting the game
500 _tony.executeAction(20, 1, 0);
501 }
502
close()503 void RMGfxEngine::close() {
504 _bigBuf.clearOT();
505
506 _inter.close();
507 _inv.close();
508 _tony.close();
509 _point.close();
510 }
511
enableInput()512 void RMGfxEngine::enableInput() {
513 _bInput = true;
514 }
515
disableInput()516 void RMGfxEngine::disableInput() {
517 _bInput = false;
518 _inter.reset();
519 }
520
enableMouse()521 void RMGfxEngine::enableMouse() {
522 _bAlwaysDrawMouse = true;
523 }
524
disableMouse()525 void RMGfxEngine::disableMouse() {
526 _bAlwaysDrawMouse = false;
527 }
528
529 #define TONY_SAVEGAME_VERSION 8
530
saveState(const Common::String & fn,byte * curThumb,const Common::String & name)531 void RMGfxEngine::saveState(const Common::String &fn, byte *curThumb, const Common::String &name) {
532 Common::OutSaveFile *f = g_system->getSavefileManager()->openForSaving(fn);
533 if (f == NULL)
534 return;
535
536 byte *state;
537 char buf[4];
538 RMPoint tp = _tony.position();
539
540 // Saving: MPAL variables, current location, and Tony inventory position
541
542 // For now, we only save the MPAL state
543 uint size = mpalGetSaveStateSize();
544 state = new byte[size];
545 mpalSaveState(state);
546
547 uint thumbsize = 160 * 120 * 2;
548
549 buf[0] = 'R';
550 buf[1] = 'M';
551 buf[2] = 'S';
552 buf[3] = TONY_SAVEGAME_VERSION;
553
554 f->write(buf, 4);
555 f->writeUint32LE(thumbsize);
556 f->write(curThumb, thumbsize);
557
558 // Difficulty level
559 int i = mpalQueryGlobalVar("VERSIONEFACILE");
560 f->writeByte(i);
561
562 i = strlen(name.c_str());
563 f->writeByte(i);
564 f->write(name.c_str(), i);
565 f->writeUint32LE(_nCurLoc);
566 f->writeUint32LE(tp._x);
567 f->writeUint32LE(tp._y);
568
569 f->writeUint32LE(size);
570 f->write(state, size);
571 delete[] state;
572
573 // Inventory
574 size = _inv.getSaveStateSize();
575 state = new byte[size];
576 _inv.saveState(state);
577 f->writeUint32LE(size);
578 f->write(state, size);
579 delete[] state;
580
581 // boxes
582 size = g_vm->_theBoxes.getSaveStateSize();
583 state = new byte[size];
584 g_vm->_theBoxes.saveState(state);
585 f->writeUint32LE(size);
586 f->write(state, size);
587 delete[] state;
588
589 // New Ver5
590 // Saves the state of the shepherdess and show yourself
591 bool bStat = _tony.getShepherdess();
592 f->writeByte(bStat);
593 bStat = _inter.getPerorate();
594 f->writeByte(bStat);
595
596 // Save the chars
597 charsSaveAll(f);
598
599 // Save the options
600 f->writeByte(GLOBALS._bCfgInvLocked);
601 f->writeByte(GLOBALS._bCfgInvNoScroll);
602 f->writeByte(GLOBALS._bCfgTimerizedText);
603 f->writeByte(GLOBALS._bCfgInvUp);
604 f->writeByte(GLOBALS._bCfgAnni30);
605 f->writeByte(GLOBALS._bCfgAntiAlias);
606 f->writeByte(GLOBALS._bShowSubtitles);
607 f->writeByte(GLOBALS._bCfgTransparence);
608 f->writeByte(GLOBALS._bCfgInterTips);
609 f->writeByte(GLOBALS._bCfgDubbing);
610 f->writeByte(GLOBALS._bCfgMusic);
611 f->writeByte(GLOBALS._bCfgSFX);
612 f->writeByte(GLOBALS._nCfgTonySpeed);
613 f->writeByte(GLOBALS._nCfgTextSpeed);
614 f->writeByte(GLOBALS._nCfgDubbingVolume);
615 f->writeByte(GLOBALS._nCfgMusicVolume);
616 f->writeByte(GLOBALS._nCfgSFXVolume);
617
618 // Save the hotspots
619 saveChangedHotspot(f);
620
621 // Save the music
622 saveMusic(f);
623
624 f->finalize();
625 delete f;
626 }
627
loadState(CORO_PARAM,const Common::String & fn)628 void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
629 // PROBLEM: You should change the location in a separate process to do the OnEnter
630 CORO_BEGIN_CONTEXT;
631 Common::InSaveFile *f;
632 byte *state, *statecmp;
633 uint32 size, sizecmp;
634 char buf[4];
635 RMPoint tp;
636 int loc;
637 int ver;
638 int i;
639 CORO_END_CONTEXT(_ctx);
640
641 CORO_BEGIN_CODE(_ctx);
642
643 _ctx->f = g_system->getSavefileManager()->openForLoading(fn);
644 if (_ctx->f == NULL)
645 return;
646 _ctx->f->read(_ctx->buf, 4);
647
648 if (_ctx->buf[0] != 'R' || _ctx->buf[1] != 'M' || _ctx->buf[2] != 'S') {
649 delete _ctx->f;
650 return;
651 }
652
653 _ctx->ver = _ctx->buf[3];
654
655 if (_ctx->ver == 0 || _ctx->ver > TONY_SAVEGAME_VERSION) {
656 delete _ctx->f;
657 return;
658 }
659
660 if (_ctx->ver >= 0x3) {
661 // There is a thumbnail. If the version is between 5 and 7, it's compressed
662 if ((_ctx->ver >= 0x5) && (_ctx->ver <= 0x7)) {
663 _ctx->i = 0;
664 _ctx->i = _ctx->f->readUint32LE();
665 _ctx->f->seek(_ctx->i);
666 } else {
667 if (_ctx->ver >= 8)
668 // Skip thumbnail size
669 _ctx->f->skip(4);
670
671 _ctx->f->seek(160 * 120 * 2, SEEK_CUR);
672 }
673 }
674
675 if (_ctx->ver >= 0x5) {
676 // Skip the difficulty level
677 _ctx->f->seek(1, SEEK_CUR);
678 }
679
680 if (_ctx->ver >= 0x4) { // Skip the savegame name, which serves no purpose
681 _ctx->i = _ctx->f->readByte();
682 _ctx->f->seek(_ctx->i, SEEK_CUR);
683 }
684
685 _ctx->loc = _ctx->f->readUint32LE();
686 _ctx->tp._x = _ctx->f->readUint32LE();
687 _ctx->tp._y = _ctx->f->readUint32LE();
688 _ctx->size = _ctx->f->readUint32LE();
689
690 if ((_ctx->ver >= 0x5) && (_ctx->ver <= 7)) {
691 // MPAL was packed!
692 _ctx->sizecmp = _ctx->f->readUint32LE();
693 _ctx->state = new byte[_ctx->size];
694 _ctx->statecmp = new byte[_ctx->sizecmp];
695 _ctx->f->read(_ctx->statecmp, _ctx->sizecmp);
696 lzo1x_decompress(_ctx->statecmp, _ctx->sizecmp, _ctx->state, &_ctx->size);
697 delete[] _ctx->statecmp;
698 } else {
699 // Read uncompressed MPAL data
700 _ctx->state = new byte[_ctx->size];
701 _ctx->f->read(_ctx->state, _ctx->size);
702 }
703
704 mpalLoadState(_ctx->state);
705 delete[] _ctx->state;
706
707 // Inventory
708 _ctx->size = _ctx->f->readUint32LE();
709 _ctx->state = new byte[_ctx->size];
710 _ctx->f->read(_ctx->state, _ctx->size);
711 _inv.loadState(_ctx->state);
712 delete[] _ctx->state;
713
714 if (_ctx->ver >= 0x2) { // Version 2: box please
715 _ctx->size = _ctx->f->readUint32LE();
716 _ctx->state = new byte[_ctx->size];
717 _ctx->f->read(_ctx->state, _ctx->size);
718 g_vm->_theBoxes.loadState(_ctx->state);
719 delete[] _ctx->state;
720 }
721
722 if (_ctx->ver >= 5) {
723 // Version 5
724 bool bStat = _ctx->f->readByte();
725 _tony.setShepherdess(bStat);
726 bStat = _ctx->f->readByte();
727 _inter.setPerorate(bStat);
728
729 charsLoadAll(_ctx->f);
730 }
731
732 if (_ctx->ver >= 6) {
733 // Load options
734 GLOBALS._bCfgInvLocked = _ctx->f->readByte();
735 GLOBALS._bCfgInvNoScroll = _ctx->f->readByte();
736 GLOBALS._bCfgTimerizedText = _ctx->f->readByte();
737 GLOBALS._bCfgInvUp = _ctx->f->readByte();
738 GLOBALS._bCfgAnni30 = _ctx->f->readByte();
739 GLOBALS._bCfgAntiAlias = _ctx->f->readByte();
740 GLOBALS._bShowSubtitles = _ctx->f->readByte();
741 GLOBALS._bCfgTransparence = _ctx->f->readByte();
742 GLOBALS._bCfgInterTips = _ctx->f->readByte();
743 GLOBALS._bCfgDubbing = _ctx->f->readByte();
744 GLOBALS._bCfgMusic = _ctx->f->readByte();
745 GLOBALS._bCfgSFX = _ctx->f->readByte();
746 GLOBALS._nCfgTonySpeed = _ctx->f->readByte();
747 GLOBALS._nCfgTextSpeed = _ctx->f->readByte();
748 GLOBALS._nCfgDubbingVolume = _ctx->f->readByte();
749 GLOBALS._nCfgMusicVolume = _ctx->f->readByte();
750 GLOBALS._nCfgSFXVolume = _ctx->f->readByte();
751
752 // Load hotspots
753 loadChangedHotspot(_ctx->f);
754 }
755
756 if (_ctx->ver >= 7) {
757 loadMusic(_ctx->f);
758 }
759
760 delete _ctx->f;
761
762 CORO_INVOKE_2(unloadLocation, false, NULL);
763 loadLocation(_ctx->loc, _ctx->tp, RMPoint(-1, -1));
764 _tony.setPattern(RMTony::PAT_STANDRIGHT);
765
766 // On older versions, need to an enter action
767 if (_ctx->ver < 5)
768 mpalQueryDoAction(0, _ctx->loc, 0);
769 else {
770 // In the new ones, we just reset the mcode
771 mCharResetCodes();
772 }
773
774 if (_ctx->ver >= 6)
775 reapplyChangedHotspot();
776
777 CORO_INVOKE_0(restoreMusic);
778
779 _bGUIInterface = true;
780 _bGUIInventory = true;
781 _bGUIOption = true;
782
783 CORO_END_CODE;
784 }
785
pauseSound(bool bPause)786 void RMGfxEngine::pauseSound(bool bPause) {
787 if (_bLocationLoaded)
788 _loc.pauseSound(bPause);
789 }
790
initWipe(int type)791 void RMGfxEngine::initWipe(int type) {
792 _bWiping = true;
793 _nWipeType = type;
794 _nWipeStep = 0;
795
796 if (_nWipeType == 1)
797 _rcWipeEllipse = Common::Rect(80, 0, 640 - 80, 480);
798 else if (_nWipeType == 2)
799 _rcWipeEllipse = Common::Rect(320 - FSTEP, 240 - FSTEP, 320 + FSTEP, 240 + FSTEP);
800 }
801
closeWipe()802 void RMGfxEngine::closeWipe() {
803 _bWiping = false;
804 }
805
waitWipeEnd(CORO_PARAM)806 void RMGfxEngine::waitWipeEnd(CORO_PARAM) {
807 CoroScheduler.waitForSingleObject(coroParam, _hWipeEvent, CORO_INFINITE);
808 }
809
canLoadSave()810 bool RMGfxEngine::canLoadSave() {
811 return _bInput && !_tony.inAction() && !g_vm->getIsDemo();
812 }
813
operator RMGfxTargetBuffer&()814 RMGfxEngine::operator RMGfxTargetBuffer &() {
815 return _bigBuf;
816 }
817
getInput()818 RMInput &RMGfxEngine::getInput() {
819 return _input;
820 }
821
getPointer()822 RMPointer &RMGfxEngine::getPointer() {
823 return _point;
824 }
825
826 /**
827 * Link to graphic task
828 */
linkGraphicTask(RMGfxTask * task)829 void RMGfxEngine::linkGraphicTask(RMGfxTask *task) {
830 _bigBuf.addPrim(new RMGfxPrimitive(task));
831 }
832
setPerorate(bool bpal)833 void RMGfxEngine::setPerorate(bool bpal) {
834 _inter.setPerorate(bpal);
835 }
836
837 } // End of namespace Tony
838