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 #include "common/config-manager.h"
24 #include "common/rect.h"
25 #include "tsage/graphics.h"
26 #include "tsage/scenes.h"
27 #include "tsage/tsage.h"
28 #include "tsage/staticres.h"
29 #include "tsage/ringworld2/ringworld2_logic.h"
30 #include "tsage/ringworld2/ringworld2_dialogs.h"
31 #include "tsage/ringworld2/ringworld2_scenes0.h"
32 #include "tsage/ringworld2/ringworld2_scenes1.h"
33 #include "tsage/ringworld2/ringworld2_scenes2.h"
34 #include "tsage/ringworld2/ringworld2_scenes3.h"
35 #include "tsage/ringworld2/ringworld2_airduct.h"
36 #include "tsage/ringworld2/ringworld2_outpost.h"
37 #include "tsage/ringworld2/ringworld2_vampire.h"
38
39 namespace TsAGE {
40
41 namespace Ringworld2 {
42
createScene(int sceneNumber)43 Scene *Ringworld2Game::createScene(int sceneNumber) {
44 switch (sceneNumber) {
45 /* Scene group #0 */
46 case 50:
47 // Waking up cutscene
48 return new Scene50();
49 case 100:
50 // Quinn's room
51 return new Scene100();
52 case 125:
53 // Computer console
54 return new Scene125();
55 case 150:
56 // Empty Bedroom #1
57 return new Scene150();
58 case 160:
59 // Credits
60 return new Scene160();
61 case 175:
62 // Empty Bedroom #2
63 return new Scene175();
64 case 180:
65 // Title Screen
66 return new Scene180();
67 case 200:
68 // Deck #2 - By Lift
69 return new Scene200();
70 case 205:
71 if (g_vm->getFeatures() & GF_DEMO)
72 // End of Demo
73 return new Scene205Demo();
74 else
75 // Star-field Credits
76 return new Scene205();
77 case 250:
78 // Lift
79 return new Scene250();
80 case 300:
81 // Bridge
82 return new Scene300();
83 case 325:
84 // Bridge Console
85 return new Scene325();
86 case 400:
87 // Science Lab
88 return new Scene400();
89 case 500:
90 // Lander Bay 2 Storage
91 return new Scene500();
92 case 525:
93 // Cutscene - Walking in hall
94 return new Scene525();
95 case 600:
96 // Drive Room
97 return new Scene600();
98 case 700:
99 // Lander Bay 2
100 return new Scene700();
101 case 800:
102 // Sick bay
103 return new Scene800();
104 case 825:
105 // Autodoc
106 return new Scene825();
107 case 850:
108 // Deck #5 - By Lift
109 return new Scene850();
110 case 900:
111 // Lander Bay 2 - Crane Controls
112 return new Scene900();
113 /* Scene group #1 */
114 //
115 case 1000:
116 // Cutscene scene
117 return new Scene1000();
118 case 1010:
119 // Cutscene - trip in space
120 return new Scene1010();
121 case 1020:
122 // Cutscene - trip in space 2
123 return new Scene1020();
124 case 1100:
125 // Canyon
126 return new Scene1100();
127 case 1200:
128 // ARM Base - Air Ducts Maze
129 return new Scene1200();
130 case 1337:
131 case 1330:
132 // Card Game
133 return new Scene1337();
134 case 1500:
135 // Cutscene: Ship landing
136 return new Scene1500();
137 case 1525:
138 // Cutscene - Ship
139 return new Scene1525();
140 case 1530:
141 // Cutscene - Crashing on Rimwall
142 return new Scene1530();
143 case 1550:
144 // Spaceport
145 return new Scene1550();
146 case 1575:
147 // Spaceport - unused ship scene
148 return new Scene1575();
149 case 1580:
150 // Inside wreck
151 return new Scene1580();
152 case 1625:
153 // Miranda being questioned
154 return new Scene1625();
155 case 1700:
156 // Rim
157 return new Scene1700();
158 case 1750:
159 // Rim Transport Vechile
160 return new Scene1750();
161 case 1800:
162 // Rim Lift Exterior
163 return new Scene1800();
164 case 1850:
165 // Rim Lift Interior
166 return new Scene1850();
167 case 1875:
168 // Rim Lift Computer
169 return new Scene1875();
170 case 1900:
171 // Spill Mountains Elevator Exit
172 return new Scene1900();
173 case 1925:
174 // Spill Mountains Elevator Shaft
175 return new Scene1925();
176 case 1945:
177 // Spill Mountains Shaft Bottom
178 return new Scene1945();
179 case 1950:
180 // Flup Tube Corridor Maze
181 return new Scene1950();
182 /* Scene group #2 */
183 case 2000:
184 // Spill Mountains
185 return new Scene2000();
186 case 2350:
187 // Spill Mountains: Balloon Launch Platform
188 return new Scene2350();
189 case 2400:
190 // Spill Mountains: Unused large empty room
191 return new Scene2400();
192 case 2425:
193 // Spill Mountains: The Hall of Records
194 return new Scene2425();
195 case 2430:
196 // Spill Mountains: Bedroom
197 return new Scene2430();
198 case 2435:
199 // Spill Mountains: Throne room
200 return new Scene2435();
201 case 2440:
202 // Spill Mountains: Another bedroom
203 return new Scene2440();
204 case 2445:
205 // Spill Mountains:
206 return new Scene2445();
207 case 2450:
208 // Spill Mountains: Another bedroom
209 return new Scene2450();
210 case 2455:
211 // Spill Mountains: Inside crevasse
212 return new Scene2455();
213 case 2500:
214 // Spill Mountains: Large Ledge
215 return new Scene2500();
216 case 2525:
217 // Spill Mountains: Furnace room
218 return new Scene2525();
219 case 2530:
220 // Spill Mountains: Well
221 return new Scene2530();
222 case 2535:
223 // Spill Mountains: Tannery
224 return new Scene2535();
225 case 2600:
226 // Spill Mountains: Exit
227 return new Scene2600();
228 case 2700:
229 // Outer Forest
230 return new Scene2700();
231 case 2750:
232 // Inner Forest
233 return new Scene2750();
234 case 2800:
235 // Guard post
236 return new Scene2800();
237 case 2900:
238 // Balloon Cutscene
239 return new Scene2900();
240
241 /* Scene group #3 */
242 // ARM Base Hanager
243 case 3100:
244 return new Scene3100();
245 case 3125:
246 // Ghouls dormitory
247 return new Scene3125();
248 case 3150:
249 // Jail
250 return new Scene3150();
251 case 3175:
252 // Autopsy room
253 return new Scene3175();
254 case 3200:
255 // Cutscene : Guards - Discussion
256 return new Scene3200();
257 case 3210:
258 // Cutscene : Captain and Private - Discussion
259 return new Scene3210();
260 case 3220:
261 // Cutscene : Guards in cargo zone
262 return new Scene3220();
263 case 3230:
264 // Cutscene : Guards on duty
265 return new Scene3230();
266 case 3240:
267 // Cutscene : Teal monolog
268 return new Scene3240();
269 case 3245:
270 // Cutscene : Discussions with Dr. Tomko
271 return new Scene3245();
272 case 3250:
273 // Room with large stasis field negator
274 return new Scene3250();
275 case 3255:
276 // Guard Post
277 return new Scene3255();
278 case 3260:
279 // ARM Base - Computer room
280 return new Scene3260();
281 case 3275:
282 // ARM Base - Hall
283 return new Scene3275();
284 case 3350:
285 // Cutscene - Ship landing
286 return new Scene3350();
287 case 3375:
288 // Circular Walkway
289 return new Scene3375();
290 case 3385:
291 // Corridor
292 return new Scene3385();
293 case 3395:
294 // Walkway
295 return new Scene3395();
296 case 3400:
297 // Confrontation
298 return new Scene3400();
299 case 3500:
300 // Flub tube maze
301 return new Scene3500();
302 case 3600:
303 // Cutscene - walking at gunpoint
304 return new Scene3600();
305 case 3700:
306 // Cutscene - Teleport outside
307 return new Scene3700();
308 case 3800:
309 // Desert
310 return new Scene3800();
311 case 3900:
312 // Forest Entrance
313 return new Scene3900();
314 default:
315 error("Unknown scene number - %d", sceneNumber);
316 break;
317 }
318 }
319
320 /**
321 * Returns true if it is currently okay to restore a game
322 */
canLoadGameStateCurrently()323 bool Ringworld2Game::canLoadGameStateCurrently() {
324 // Don't allow a game to be loaded if a dialog is active
325 return g_globals->_gfxManagers.size() == 1;
326 }
327
328 /**
329 * Returns true if it is currently okay to save the game
330 */
canSaveGameStateCurrently()331 bool Ringworld2Game::canSaveGameStateCurrently() {
332 // Don't allow a game to be saved if a dialog is active, or if an animation
333 // is playing, or if an active scene prevents it
334 return g_globals->_gfxManagers.size() == 1 && R2_GLOBALS._animationCtr == 0 &&
335 (!R2_GLOBALS._sceneManager._scene ||
336 !((SceneExt *)R2_GLOBALS._sceneManager._scene)->_preventSaving);
337 }
338
339 /*--------------------------------------------------------------------------*/
340
SceneExt()341 SceneExt::SceneExt(): Scene() {
342 _stripManager._onBegin = SceneExt::startStrip;
343 _stripManager._onEnd = SceneExt::endStrip;
344
345 for (int i = 0; i < 256; i++)
346 _shadowPaletteMap[i] = 0;
347
348 _savedPlayerEnabled = false;
349 _savedUiEnabled = false;
350 _savedCanWalk = false;
351 _preventSaving = false;
352
353 // Reset screen clipping area
354 R2_GLOBALS._screen._clipRect = Rect();
355
356 // WORKAROUND: In the original, playing animations don't reset the global _animationCtr
357 // counter as scene changes unless the playing animation explicitly finishes. For now,
358 // to make inter-scene debugging easier, I'm explicitly resetting the _animationCtr
359 // on scene start, since scene objects aren't drawn while it's non-zero
360 R2_GLOBALS._animationCtr = 0;
361
362 // WORKAROUND: We had a case where at some point the number of modal dialogs
363 // open became incorrect. So reset it on scene changes to fix the problem if
364 // it ever happens
365 R2_GLOBALS._insetUp = 0;
366 }
367
synchronize(Serializer & s)368 void SceneExt::synchronize(Serializer &s) {
369 Scene::synchronize(s);
370
371 s.syncBytes(&_shadowPaletteMap[0], 256);
372 _sceneAreas.synchronize(s);
373 }
374
postInit(SceneObjectList * OwnerList)375 void SceneExt::postInit(SceneObjectList *OwnerList) {
376 Scene::postInit(OwnerList);
377
378 // Exclude the bottom area of the screen to allow room for the UI
379 T2_GLOBALS._interfaceY = UI_INTERFACE_Y;
380
381 // Initialize fields
382 _action = NULL;
383 _sceneMode = 0;
384
385 static_cast<SceneHandlerExt *>(R2_GLOBALS._sceneHandler)->setupPaletteMaps();
386
387 int prevScene = R2_GLOBALS._sceneManager._previousScene;
388 int sceneNumber = R2_GLOBALS._sceneManager._sceneNumber;
389 if (g_vm->getFeatures() & GF_DEMO) {
390 if (prevScene == 0 && sceneNumber == 180) {
391 // Very start of the demo, title & intro about to be shown
392 R2_GLOBALS._uiElements._active = false;
393 R2_GLOBALS._uiElements.hide();
394 } else if (((prevScene == -1) && (sceneNumber != 180) && (sceneNumber != 205) && (sceneNumber != 50))
395 || (prevScene == 0) || (sceneNumber == 600)
396 || ((prevScene == 205 || prevScene == 180 || prevScene == 50) && (sceneNumber == 100))) {
397 R2_GLOBALS._uiElements._active = true;
398 R2_GLOBALS._uiElements.show();
399 } else {
400 R2_GLOBALS._uiElements.updateInventory();
401 }
402 } else if (((prevScene == -1) && (sceneNumber != 180) && (sceneNumber != 205) && (sceneNumber != 50))
403 || (sceneNumber == 50)
404 || ((sceneNumber == 100) && (prevScene == 0 || prevScene == 180 || prevScene == 205))) {
405 R2_GLOBALS._uiElements._active = true;
406 R2_GLOBALS._uiElements.show();
407 } else {
408 R2_GLOBALS._uiElements.updateInventory();
409 }
410 }
411
remove()412 void SceneExt::remove() {
413 _sceneAreas.clear();
414 Scene::remove();
415 R2_GLOBALS._uiElements._active = true;
416
417 if (R2_GLOBALS._events.getCursor() >= EXITCURSOR_N &&
418 R2_GLOBALS._events.getCursor() <= SHADECURSOR_DOWN)
419 R2_GLOBALS._events.setCursor(CURSOR_WALK);
420 }
421
process(Event & event)422 void SceneExt::process(Event &event) {
423 if (!event.handled)
424 Scene::process(event);
425 }
426
dispatch()427 void SceneExt::dispatch() {
428 Scene::dispatch();
429 }
430
display(CursorType action,Event & event)431 bool SceneExt::display(CursorType action, Event &event) {
432 switch (action) {
433 case CURSOR_CROSSHAIRS:
434 case CURSOR_WALK:
435 return false;
436 case CURSOR_LOOK:
437 SceneItem::display2(1, R2_GLOBALS._randomSource.getRandomNumber(4));
438 break;
439 case CURSOR_USE:
440 SceneItem::display2(1, R2_GLOBALS._randomSource.getRandomNumber(4) + 5);
441 break;
442 case CURSOR_TALK:
443 SceneItem::display2(1, R2_GLOBALS._randomSource.getRandomNumber(4) + 10);
444 break;
445 case R2_NEGATOR_GUN:
446 if (R2_GLOBALS.getFlag(1))
447 SceneItem::display2(2, action);
448 else
449 SceneItem::display2(5, 0);
450 break;
451 case R2_SONIC_STUNNER:
452 if ((R2_GLOBALS._scannerFrequencies[R2_QUINN] == 2)
453 || ((R2_GLOBALS._scannerFrequencies[R2_QUINN] == 1) &&
454 (R2_GLOBALS._scannerFrequencies[R2_SEEKER] == 2) &&
455 (R2_GLOBALS._sceneManager._previousScene == 300))) {
456 R2_GLOBALS._sound4.stop();
457 R2_GLOBALS._sound3.play(46);
458 SceneItem::display2(5, 15);
459
460 R2_GLOBALS._sound4.play(45);
461 } else {
462 R2_GLOBALS._sound3.play(43, 0);
463 SceneItem::display2(2, R2_SONIC_STUNNER);
464 }
465 break;
466 case R2_COM_SCANNER:
467 case R2_COM_SCANNER_2:
468 R2_GLOBALS._sound3.play(44);
469 SceneItem::display2(2, action);
470 R2_GLOBALS._sound3.stop();
471 break;
472 case R2_PHOTON_STUNNER:
473 R2_GLOBALS._sound3.play(99);
474 SceneItem::display2(2, action);
475 break;
476 default:
477 SceneItem::display2(2, action);
478 break;
479 }
480
481 event.handled = true;
482 return true;
483 }
484
fadeOut()485 void SceneExt::fadeOut() {
486 uint32 black = 0;
487 R2_GLOBALS._scenePalette.fade((const byte *)&black, false, 100);
488 }
489
startStrip()490 void SceneExt::startStrip() {
491 SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene;
492 scene->_savedPlayerEnabled = R2_GLOBALS._player._enabled;
493
494 if (scene->_savedPlayerEnabled) {
495 scene->_savedUiEnabled = R2_GLOBALS._player._uiEnabled;
496 scene->_savedCanWalk = R2_GLOBALS._player._canWalk;
497 R2_GLOBALS._player.disableControl();
498 /*
499 if (!R2_GLOBALS._v50696 && R2_GLOBALS._uiElements._active)
500 R2_GLOBALS._uiElements.hide();
501 */
502 }
503 }
504
endStrip()505 void SceneExt::endStrip() {
506 SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene;
507
508 if (scene->_savedPlayerEnabled) {
509 R2_GLOBALS._player.enableControl();
510 R2_GLOBALS._player._uiEnabled = scene->_savedUiEnabled;
511 R2_GLOBALS._player._canWalk = scene->_savedCanWalk;
512 /*
513 if (!R2_GLOBALS._v50696 && R2_GLOBALS._uiElements._active)
514 R2_GLOBALS._uiElements.show();
515 */
516 }
517 }
518
clearScreen()519 void SceneExt::clearScreen() {
520 R2_GLOBALS._screen.fillRect(R2_GLOBALS._screen.getBounds(), 0);
521 }
522
refreshBackground(int xAmount,int yAmount)523 void SceneExt::refreshBackground(int xAmount, int yAmount) {
524 switch (_activeScreenNumber) {
525 case 700:
526 case 1020:
527 case 1100:
528 case 1700:
529 case 2600:
530 case 2950:
531 case 3100:
532 case 3101:
533 case 3275:
534 case 3600:
535 // Use traditional style sectioned screen loading
536 Scene::refreshBackground(xAmount, yAmount);
537 return;
538 default:
539 // Break out to new style screen loading
540 break;
541 }
542
543 /* New style background loading */
544
545 // Get the screen data
546 byte *dataP = g_resourceManager->getResource(RT18, _activeScreenNumber, 0);
547 int screenSize = g_vm->_memoryManager.getSize(dataP);
548
549 // Lock the background for update
550 assert(screenSize == (_backSurface.w * _backSurface.h));
551 Graphics::Surface s = _backSurface.getSubArea(Common::Rect(0, 0, _backSurface.w, _backSurface.h));
552
553 // Copy the data into the surface
554 byte *destP = (byte *)s.getPixels();
555 Common::copy(dataP, dataP + (s.w * s.h), destP);
556
557 // Free the resource data
558 DEALLOCATE(dataP);
559 }
560
561 /**
562 * Saves the current player position and view in the details for the specified character index
563 */
saveCharacter(int characterIndex)564 void SceneExt::saveCharacter(int characterIndex) {
565 R2_GLOBALS._player._characterPos[characterIndex] = R2_GLOBALS._player._position;
566 R2_GLOBALS._player._characterStrip[characterIndex] = R2_GLOBALS._player._strip;
567 R2_GLOBALS._player._characterFrame[characterIndex] = R2_GLOBALS._player._frame;
568 }
569
scalePalette(int RFactor,int GFactor,int BFactor)570 void SceneExt::scalePalette(int RFactor, int GFactor, int BFactor) {
571 byte *tmpPal = R2_GLOBALS._scenePalette._palette;
572 byte newR, newG, newB;
573 int tmp, varD = 0;
574
575 for (int i = 0; i < 256; i++) {
576 newR = (RFactor * tmpPal[(3 * i)]) / 100;
577 newG = (GFactor * tmpPal[(3 * i) + 1]) / 100;
578 newB = (BFactor * tmpPal[(3 * i) + 2]) / 100;
579
580 int varC = 769;
581 for (int j = 255; j >= 0; j--) {
582 tmp = abs(tmpPal[(3 * j)] - newR);
583 if (tmp >= varC)
584 continue;
585
586 tmp += abs(tmpPal[(3 * j) + 1] - newG);
587 if (tmp >= varC)
588 continue;
589
590 tmp += abs(tmpPal[(3 * j) + 2] - newB);
591 if (tmp >= varC)
592 continue;
593
594 varC = tmp;
595 varD = j;
596 }
597 this->_shadowPaletteMap[i] = varD;
598 }
599 }
600
loadBlankScene()601 void SceneExt::loadBlankScene() {
602 _backSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT * 3 / 2);
603 _backSurface.fillRect(_backSurface.getBounds(), 0);
604
605 R2_GLOBALS._screen.fillRect(R2_GLOBALS._screen.getBounds(), 0);
606 }
607
608 /*--------------------------------------------------------------------------*/
609
postInit(SceneObjectList * OwnerList)610 void SceneHandlerExt::postInit(SceneObjectList *OwnerList) {
611 SceneHandler::postInit(OwnerList);
612
613 if (!R2_GLOBALS._playStream.setFile("SND4K.RES"))
614 warning("Could not find SND4K.RES voice file");
615 }
616
process(Event & event)617 void SceneHandlerExt::process(Event &event) {
618 if (T2_GLOBALS._uiElements._active && R2_GLOBALS._player._uiEnabled) {
619 T2_GLOBALS._uiElements.process(event);
620 if (event.handled)
621 return;
622 }
623
624 SceneExt *scene = static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene);
625 if (scene && R2_GLOBALS._player._uiEnabled) {
626 // Handle any scene areas that have been registered
627 SynchronizedList<EventHandler *>::iterator saIter;
628 for (saIter = scene->_sceneAreas.begin(); saIter != scene->_sceneAreas.end() && !event.handled; ++saIter) {
629 (*saIter)->process(event);
630 }
631 }
632
633 if (!event.handled)
634 SceneHandler::process(event);
635 }
636
dispatch()637 void SceneHandlerExt::dispatch() {
638 R2_GLOBALS._playStream.dispatch();
639 SceneHandler::dispatch();
640 }
641
postLoad(int priorSceneBeforeLoad,int currentSceneBeforeLoad)642 void SceneHandlerExt::postLoad(int priorSceneBeforeLoad, int currentSceneBeforeLoad) {
643 // Set up the shading maps used for showing the player in shadows
644 setupPaletteMaps();
645
646 if (currentSceneBeforeLoad == 2900) {
647 R2_GLOBALS._gfxFontNumber = 50;
648 R2_GLOBALS._gfxColors.background = 0;
649 R2_GLOBALS._gfxColors.foreground = 59;
650 R2_GLOBALS._fontColors.background = 4;
651 R2_GLOBALS._fontColors.foreground = 15;
652 R2_GLOBALS._frameEdgeColor = 2;
653
654 R2_GLOBALS._scenePalette.loadPalette(0);
655 R2_GLOBALS._scenePalette.setEntry(255, 0xff, 0xff, 0xff);
656 R2_GLOBALS._fadePaletteFlag = false;
657 setupPaletteMaps();
658 }
659 }
660
setupPaletteMaps()661 void SceneHandlerExt::setupPaletteMaps() {
662 byte *palP = &R2_GLOBALS._scenePalette._palette[0];
663
664 // Set up the mapping table for giving faded versions of pixels at different fade percentages
665 if (!R2_GLOBALS._fadePaletteFlag) {
666 R2_GLOBALS._fadePaletteFlag = true;
667
668 for (int idx = 0; idx < 10; ++idx) {
669 for (int palIndex = 0; palIndex < 224; ++palIndex) {
670 int r, g, b;
671
672 // Get adjusted RGB values
673 switch (idx) {
674 case 7:
675 r = palP[palIndex * 3] * 85 / 100;
676 g = palP[palIndex * 3 + 1] * 7 / 10;
677 b = palP[palIndex * 3 + 2] * 7 / 10;
678 break;
679 case 8:
680 r = palP[palIndex * 3] * 7 / 10;
681 g = palP[palIndex * 3 + 1] * 85 / 100;
682 b = palP[palIndex * 3 + 2] * 7 / 10;
683 break;
684 case 9:
685 r = palP[palIndex * 3] * 8 / 10;
686 g = palP[palIndex * 3 + 1] * 5 / 10;
687 b = palP[palIndex * 3 + 2] * 9 / 10;
688 break;
689 default:
690 r = palP[palIndex * 3] * (10 - idx) / 10;
691 g = palP[palIndex * 3 + 1] * (10 - idx) / 12;
692 b = palP[palIndex * 3 + 2] * (10 - idx) / 10;
693 break;
694 }
695
696 // Scan for the palette index with the closest matching color
697 int threshold = 769;
698 int foundIndex = -1;
699 for (int pIndex2 = 223; pIndex2 >= 0; --pIndex2) {
700 int diffSum = ABS(palP[pIndex2 * 3] - r);
701 if (diffSum >= threshold)
702 continue;
703
704 diffSum += ABS(palP[pIndex2 * 3 + 1] - g);
705 if (diffSum >= threshold)
706 continue;
707
708 diffSum += ABS(palP[pIndex2 * 3 + 2] - b);
709 if (diffSum >= threshold)
710 continue;
711
712 threshold = diffSum;
713 foundIndex = pIndex2;
714 }
715
716 R2_GLOBALS._fadePaletteMap[idx][palIndex] = foundIndex;
717 }
718 }
719 }
720
721 for (int palIndex = 0; palIndex < 224; ++palIndex) {
722 int r = palP[palIndex * 3] >> 4;
723 int g = palP[palIndex * 3 + 1] >> 4;
724 int b = palP[palIndex * 3 + 2] >> 4;
725
726 int v = (r << 8) | (g << 4) | b;
727 assert(v < 0x1000);
728 R2_GLOBALS._paletteMap[v] = palIndex;
729 }
730
731 int vdx = 0;
732 int idx = 0;
733 int palIndex = 224;
734
735 for (int vIndex = 0; vIndex < 4096; ++vIndex) {
736 int v = R2_GLOBALS._paletteMap[vIndex];
737 if (!v) {
738 R2_GLOBALS._paletteMap[vIndex] = idx;
739 } else {
740 idx = v;
741 }
742
743 if (!palIndex) {
744 vdx = palIndex;
745 } else {
746 int idxTemp = palIndex;
747 palIndex = (palIndex + vdx) / 2;
748 vdx = idxTemp;
749 }
750 }
751 }
752
753 /*--------------------------------------------------------------------------*/
754
DisplayHotspot(int regionId,...)755 DisplayHotspot::DisplayHotspot(int regionId, ...) {
756 _sceneRegionId = regionId;
757
758 // Load up the actions
759 va_list va;
760 va_start(va, regionId);
761
762 int param = va_arg(va, int);
763 while (param != LIST_END) {
764 _actions.push_back(param);
765 param = va_arg(va, int);
766 }
767
768 va_end(va);
769 }
770
performAction(int action)771 bool DisplayHotspot::performAction(int action) {
772 for (uint i = 0; i < _actions.size(); i += 3) {
773 if (_actions[i] == action) {
774 display(_actions[i + 1], _actions[i + 2], SET_WIDTH, 200, SET_EXT_BGCOLOR, 7, LIST_END);
775 return true;
776 }
777 }
778
779 return false;
780 }
781
782 /*--------------------------------------------------------------------------*/
783
DisplayObject(int firstAction,...)784 DisplayObject::DisplayObject(int firstAction, ...) {
785 // Load up the actions
786 va_list va;
787 va_start(va, firstAction);
788
789 int param = firstAction;
790 while (param != LIST_END) {
791 _actions.push_back(param);
792 param = va_arg(va, int);
793 }
794
795 va_end(va);
796 }
797
performAction(int action)798 bool DisplayObject::performAction(int action) {
799 for (uint i = 0; i < _actions.size(); i += 3) {
800 if (_actions[i] == action) {
801 display(_actions[i + 1], _actions[i + 2], SET_WIDTH, 200, SET_EXT_BGCOLOR, 7, LIST_END);
802 return true;
803 }
804 }
805
806 return false;
807 }
808
809 /*--------------------------------------------------------------------------*/
810
Ringworld2InvObjectList()811 Ringworld2InvObjectList::Ringworld2InvObjectList():
812 _none(1, 1),
813 _optoDisk(1, 2),
814 _reader(1, 3),
815 _negatorGun(1, 4),
816 _steppingDisks(1, 5),
817 _attractorUnit(1, 6),
818 _sensorProbe(1, 7),
819 _sonicStunner(1, 8),
820 _cableHarness(1, 9),
821 _comScanner(1, 10),
822 _spentPowerCapsule(1, 11), // 10
823 _chargedPowerCapsule(1, 12),
824 _aerosol(1, 13),
825 _remoteControl(1, 14),
826 _opticalFiber(1, 15),
827 _clamp(1, 16),
828 _attractorHarness(1, 17),
829 _fuelCell(2, 2),
830 _gyroscope(2, 3),
831 _airbag(2, 4),
832 _rebreatherTank(2, 5), // 20
833 _reserveTank(2, 5),
834 _guidanceModule(2, 6),
835 _thrusterValve(2, 7),
836 _balloonBackpack(2, 8),
837 _radarMechanism(2, 9),
838 _joystick(2, 10),
839 _ignitor(2, 11),
840 _diagnosticsDisplay(2, 12),
841 _glassDome(2, 13),
842 _wickLamp(2, 14), // 30
843 _scrithKey(2, 15),
844 _tannerMask(2, 16),
845 _pureGrainAlcohol(3, 2),
846 _blueSapphire(3, 3),
847 _ancientScrolls(3, 4),
848 _flute(3, 5),
849 _gunpowder(3, 6),
850 _unused(3, 7),
851 _comScanner2(1, 10),
852 _superconductorWire(3, 8), // 40
853 _pillow(3, 9),
854 _foodTray(3, 10),
855 _laserHacksaw(3, 11),
856 _photonStunner(3, 12),
857 _battery(3, 13),
858 _soakedFaceMask(2, 17),
859 _lightBulb(3, 14),
860 _alcoholLamp1(2, 14),
861 _alcoholLamp2(3, 15),
862 _alocholLamp3(3, 15), // 50
863 _brokenDisplay(3, 17),
864 _toolbox(4, 2) {
865
866 // Add the items to the list
867 _itemList.push_back(&_none);
868 _itemList.push_back(&_optoDisk);
869 _itemList.push_back(&_reader);
870 _itemList.push_back(&_negatorGun);
871 _itemList.push_back(&_steppingDisks);
872 _itemList.push_back(&_attractorUnit);
873 _itemList.push_back(&_sensorProbe);
874 _itemList.push_back(&_sonicStunner);
875 _itemList.push_back(&_cableHarness);
876 _itemList.push_back(&_comScanner);
877 _itemList.push_back(&_spentPowerCapsule); // 10
878 _itemList.push_back(&_chargedPowerCapsule);
879 _itemList.push_back(&_aerosol);
880 _itemList.push_back(&_remoteControl);
881 _itemList.push_back(&_opticalFiber);
882 _itemList.push_back(&_clamp);
883 _itemList.push_back(&_attractorHarness);
884 _itemList.push_back(&_fuelCell);
885 _itemList.push_back(&_gyroscope);
886 _itemList.push_back(&_airbag);
887 _itemList.push_back(&_rebreatherTank); // 20
888 _itemList.push_back(&_reserveTank);
889 _itemList.push_back(&_guidanceModule);
890 _itemList.push_back(&_thrusterValve);
891 _itemList.push_back(&_balloonBackpack);
892 _itemList.push_back(&_radarMechanism);
893 _itemList.push_back(&_joystick);
894 _itemList.push_back(&_ignitor);
895 _itemList.push_back(&_diagnosticsDisplay);
896 _itemList.push_back(&_glassDome);
897 _itemList.push_back(&_wickLamp); // 30
898 _itemList.push_back(&_scrithKey);
899 _itemList.push_back(&_tannerMask);
900 _itemList.push_back(&_pureGrainAlcohol);
901 _itemList.push_back(&_blueSapphire);
902 _itemList.push_back(&_ancientScrolls);
903 _itemList.push_back(&_flute);
904 _itemList.push_back(&_gunpowder);
905 _itemList.push_back(&_unused);
906 _itemList.push_back(&_comScanner2);
907 _itemList.push_back(&_superconductorWire); // 40
908 _itemList.push_back(&_pillow);
909 _itemList.push_back(&_foodTray);
910 _itemList.push_back(&_laserHacksaw);
911 _itemList.push_back(&_photonStunner);
912 _itemList.push_back(&_battery);
913 _itemList.push_back(&_soakedFaceMask);
914 _itemList.push_back(&_lightBulb);
915 _itemList.push_back(&_alcoholLamp1);
916 _itemList.push_back(&_alcoholLamp2);
917 _itemList.push_back(&_alocholLamp3); // 50
918 _itemList.push_back(&_brokenDisplay);
919 _itemList.push_back(&_toolbox);
920
921 _selectedItem = NULL;
922 }
923
reset()924 void Ringworld2InvObjectList::reset() {
925 // Reset all object scene numbers
926 SynchronizedList<InvObject *>::iterator i;
927 for (i = _itemList.begin(); i != _itemList.end(); ++i) {
928 (*i)->_sceneNumber = 0;
929 }
930
931 // Set up default inventory
932 setObjectScene(R2_OPTO_DISK, 800);
933 setObjectScene(R2_READER, 400);
934 setObjectScene(R2_NEGATOR_GUN, 100);
935 setObjectScene(R2_STEPPING_DISKS, 100);
936 setObjectScene(R2_ATTRACTOR_UNIT, 400);
937 setObjectScene(R2_SENSOR_PROBE, 400);
938 setObjectScene(R2_SONIC_STUNNER, 500);
939 setObjectScene(R2_CABLE_HARNESS, 700);
940 setObjectScene(R2_COM_SCANNER, 800);
941 setObjectScene(R2_SPENT_POWER_CAPSULE, 100);
942 setObjectScene(R2_CHARGED_POWER_CAPSULE, 400);
943 setObjectScene(R2_AEROSOL, 500);
944 setObjectScene(R2_REMOTE_CONTROL, 1550);
945 setObjectScene(R2_OPTICAL_FIBER, 850);
946 setObjectScene(R2_CLAMP, 850);
947 setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 0);
948 setObjectScene(R2_FUEL_CELL, 1550);
949 setObjectScene(R2_GYROSCOPE, 1550);
950 setObjectScene(R2_AIRBAG, 1550);
951 setObjectScene(R2_REBREATHER_TANK, 500);
952 setObjectScene(R2_RESERVE_REBREATHER_TANK, 500);
953 setObjectScene(R2_GUIDANCE_MODULE, 1550);
954 setObjectScene(R2_THRUSTER_VALVE, 1580);
955 setObjectScene(R2_BALLOON_BACKPACK, 9999);
956 setObjectScene(R2_RADAR_MECHANISM, 1550);
957 setObjectScene(R2_JOYSTICK, 1550);
958 setObjectScene(R2_IGNITOR, 1580);
959 setObjectScene(R2_DIAGNOSTICS_DISPLAY, 1550);
960 setObjectScene(R2_GLASS_DOME, 2525);
961 setObjectScene(R2_WICK_LAMP, 2440);
962 setObjectScene(R2_SCRITH_KEY, 2455);
963 setObjectScene(R2_TANNER_MASK, 2535);
964 setObjectScene(R2_PURE_GRAIN_ALCOHOL, 2530);
965 setObjectScene(R2_SAPPHIRE_BLUE, 1950);
966 setObjectScene(R2_ANCIENT_SCROLLS, 1950);
967 setObjectScene(R2_FLUTE, 9999);
968 setObjectScene(R2_GUNPOWDER, 2430);
969 setObjectScene(R2_NONAME, 9999);
970 setObjectScene(R2_COM_SCANNER_2, 2);
971 setObjectScene(R2_SUPERCONDUCTOR_WIRE, 9999);
972 setObjectScene(R2_PILLOW, 3150);
973 setObjectScene(R2_FOOD_TRAY, 0);
974 setObjectScene(R2_LASER_HACKSAW, 3260);
975 setObjectScene(R2_PHOTON_STUNNER, 2);
976 setObjectScene(R2_BATTERY, 1550);
977 setObjectScene(R2_SOAKED_FACEMASK, 0);
978 setObjectScene(R2_LIGHT_BULB, 3150);
979 setObjectScene(R2_ALCOHOL_LAMP, 2435);
980 setObjectScene(R2_ALCOHOL_LAMP_2, 2440);
981 setObjectScene(R2_ALCOHOL_LAMP_3, 2435);
982 setObjectScene(R2_BROKEN_DISPLAY, 1580);
983 setObjectScene(R2_TOOLBOX, 3260);
984
985 // Set up the select item handler method
986 T2_GLOBALS._onSelectItem = SelectItem;
987 }
988
setObjectScene(int objectNum,int sceneNumber)989 void Ringworld2InvObjectList::setObjectScene(int objectNum, int sceneNumber) {
990 // Find the appropriate object
991 int num = objectNum;
992 SynchronizedList<InvObject *>::iterator i = _itemList.begin();
993 while (num-- > 0) ++i;
994 (*i)->_sceneNumber = sceneNumber;
995
996 // If the item is the currently active one, default back to the use cursor
997 if (R2_GLOBALS._events.getCursor() == objectNum)
998 R2_GLOBALS._events.setCursor(CURSOR_USE);
999
1000 // Update the user interface if necessary
1001 T2_GLOBALS._uiElements.updateInventory(
1002 (sceneNumber == R2_GLOBALS._player._characterIndex) ? objectNum : 0);
1003 }
1004
1005 /**
1006 * When an inventory item is selected, in Return to Ringworld two objects can be combined
1007 */
SelectItem(int objectNumber)1008 bool Ringworld2InvObjectList::SelectItem(int objectNumber) {
1009 // If no existing item selected, don't go any further
1010 int currentItem = R2_GLOBALS._events.getCursor();
1011 if (currentItem >= 256)
1012 return false;
1013
1014 switch (objectNumber) {
1015 case R2_NEGATOR_GUN:
1016 switch (currentItem) {
1017 case R2_SENSOR_PROBE:
1018 if (R2_GLOBALS.getFlag(1))
1019 SceneItem::display2(5, 1);
1020 else if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) != 100)
1021 SceneItem::display2(5, 3);
1022 else {
1023 R2_GLOBALS._sound3.play(48);
1024 SceneItem::display2(5, 2);
1025 R2_INVENTORY.setObjectScene(R2_SPENT_POWER_CAPSULE, 1);
1026 }
1027 break;
1028 case R2_COM_SCANNER:
1029 R2_GLOBALS._sound3.play(44);
1030 if (R2_GLOBALS.getFlag(1))
1031 SceneItem::display2(5, 9);
1032 else if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) == 100)
1033 SceneItem::display2(5, 8);
1034 else
1035 SceneItem::display2(5, 10);
1036
1037 R2_GLOBALS._sound3.stop();
1038 break;
1039 case R2_CHARGED_POWER_CAPSULE:
1040 if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) == 1) {
1041 R2_GLOBALS._sound3.play(49);
1042 R2_INVENTORY.setObjectScene(R2_CHARGED_POWER_CAPSULE, 100);
1043 R2_GLOBALS.setFlag(1);
1044 SceneItem::display2(5, 4);
1045 } else {
1046 SceneItem::display2(5, 5);
1047 }
1048 break;
1049 default:
1050 selectDefault(objectNumber);
1051 break;
1052 }
1053 break;
1054 case R2_STEPPING_DISKS:
1055 switch (currentItem) {
1056 case R2_SENSOR_PROBE:
1057 if (R2_INVENTORY.getObjectScene(R2_CHARGED_POWER_CAPSULE) == 400) {
1058 R2_GLOBALS._sound3.play(48);
1059 SceneItem::display2(5, 6);
1060 R2_INVENTORY.setObjectScene(R2_CHARGED_POWER_CAPSULE, 1);
1061 } else {
1062 SceneItem::display2(5, 7);
1063 }
1064 break;
1065 case R2_COM_SCANNER:
1066 R2_GLOBALS._sound3.play(44);
1067 if (R2_INVENTORY.getObjectScene(R2_CHARGED_POWER_CAPSULE) == 400)
1068 SceneItem::display2(5, 16);
1069 else
1070 SceneItem::display2(5, 17);
1071 R2_GLOBALS._sound3.stop();
1072 break;
1073 default:
1074 selectDefault(objectNumber);
1075 break;
1076 }
1077 break;
1078 case R2_ATTRACTOR_UNIT:
1079 case R2_CABLE_HARNESS:
1080 if (currentItem == R2_CABLE_HARNESS ||
1081 currentItem == R2_ATTRACTOR_UNIT) {
1082 R2_INVENTORY.setObjectScene(R2_CABLE_HARNESS, 0);
1083 R2_INVENTORY.setObjectScene(R2_ATTRACTOR_UNIT, 0);
1084 R2_INVENTORY.setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 1);
1085 } else {
1086 selectDefault(objectNumber);
1087 }
1088 break;
1089 case R2_TANNER_MASK:
1090 case R2_PURE_GRAIN_ALCOHOL:
1091 if (currentItem == R2_TANNER_MASK ||
1092 currentItem == R2_PURE_GRAIN_ALCOHOL) {
1093 R2_INVENTORY.setObjectScene(R2_TANNER_MASK, 0);
1094 R2_INVENTORY.setObjectScene(R2_PURE_GRAIN_ALCOHOL, 0);
1095 R2_INVENTORY.setObjectScene(R2_SOAKED_FACEMASK, R2_SEEKER);
1096 } else {
1097 selectDefault(objectNumber);
1098 }
1099 break;
1100 default:
1101 // Standard item selection
1102 return false;
1103 }
1104
1105 return true;
1106 }
1107
selectDefault(int objectNumber)1108 void Ringworld2InvObjectList::selectDefault(int objectNumber) {
1109 Common::String msg1 = g_resourceManager->getMessage(4, 53);
1110 Common::String msg2 = g_resourceManager->getMessage(4, R2_GLOBALS._events.getCursor());
1111 Common::String msg3 = g_resourceManager->getMessage(4, 54);
1112 Common::String msg4 = g_resourceManager->getMessage(4, objectNumber);
1113 Common::String line = Common::String::format("%.5s%.5s%.5s%.5s%s %s %s %s.",
1114 msg1.c_str(), msg2.c_str(), msg3.c_str(), msg4.c_str(),
1115 msg1.c_str() + 5, msg2.c_str() + 5, msg3.c_str() + 5, msg4.c_str() + 5);
1116
1117 SceneItem::display(-1, -1, line.c_str(),
1118 SET_WIDTH, 280,
1119 SET_X, 160,
1120 SET_Y, 20,
1121 SET_POS_MODE, 1,
1122 SET_EXT_BGCOLOR, 7,
1123 LIST_END);
1124 }
1125
1126 /*--------------------------------------------------------------------------*/
1127
start()1128 void Ringworld2Game::start() {
1129 int slot = -1;
1130
1131 if (ConfMan.hasKey("save_slot")) {
1132 slot = ConfMan.getInt("save_slot");
1133 Common::String file = g_vm->generateSaveName(slot);
1134 Common::InSaveFile *in = g_vm->_system->getSavefileManager()->openForLoading(file);
1135 if (in)
1136 delete in;
1137 else
1138 slot = -1;
1139 }
1140
1141 if (slot >= 0)
1142 R2_GLOBALS._sceneHandler->_loadGameSlot = slot;
1143 else {
1144 // Switch to the first title screen
1145 R2_GLOBALS._uiElements._active = true;
1146 R2_GLOBALS._sceneManager.setNewScene(180);
1147 }
1148
1149 g_globals->_events.showCursor();
1150 }
1151
restartGame()1152 void Ringworld2Game::restartGame() {
1153 if (MessageDialog::show(Ringworld2::R2_RESTART_MSG, CANCEL_BTN_STRING, YES_MSG) == 1)
1154 restart();
1155 }
1156
restart()1157 void Ringworld2Game::restart() {
1158 g_globals->_scenePalette.clearListeners();
1159 g_globals->_soundHandler.stop();
1160
1161 // Reset the globals
1162 g_globals->reset();
1163
1164 // Clear save/load slots
1165 g_globals->_sceneHandler->_saveGameSlot = -1;
1166 g_globals->_sceneHandler->_loadGameSlot = -1;
1167
1168 // Change to the first game scene
1169 g_globals->_sceneManager.changeScene(100);
1170 }
1171
endGame(int resNum,int lineNum)1172 void Ringworld2Game::endGame(int resNum, int lineNum) {
1173 g_globals->_events.setCursor(CURSOR_WALK);
1174 Common::String msg = g_resourceManager->getMessage(resNum, lineNum);
1175 bool savesExist = g_saver->savegamesExist();
1176
1177 if (!savesExist) {
1178 // No savegames exist, so prompt the user to restart or quit
1179 if (MessageDialog::show(msg, QUIT_BTN_STRING, RESTART_BTN_STRING) == 0)
1180 g_vm->quitGame();
1181 else
1182 restart();
1183 } else {
1184 // Savegames exist, so prompt for Restore/Restart
1185 bool breakFlag;
1186 do {
1187 if (g_vm->shouldQuit()) {
1188 breakFlag = true;
1189 } else if (MessageDialog::show(msg, RESTART_BTN_STRING, RESTORE_BTN_STRING) == 0) {
1190 restart();
1191 breakFlag = true;
1192 } else {
1193 handleSaveLoad(false, g_globals->_sceneHandler->_loadGameSlot, g_globals->_sceneHandler->_saveName);
1194 breakFlag = g_globals->_sceneHandler->_loadGameSlot >= 0;
1195 }
1196 } while (!breakFlag);
1197 }
1198
1199 g_globals->_events.setCursorFromFlag();
1200 }
1201
processEvent(Event & event)1202 void Ringworld2Game::processEvent(Event &event) {
1203 if (event.eventType == EVENT_KEYPRESS) {
1204 switch (event.kbd.keycode) {
1205 case Common::KEYCODE_F1:
1206 // F1 - Help
1207 HelpDialog::show();
1208 break;
1209
1210 case Common::KEYCODE_F2:
1211 // F2 - Sound Options
1212 SoundDialog::execute();
1213 break;
1214
1215 case Common::KEYCODE_F3:
1216 // F3 - Quit
1217 quitGame();
1218 event.handled = false;
1219 break;
1220
1221 case Common::KEYCODE_F4:
1222 // F4 - Restart
1223 restartGame();
1224 R2_GLOBALS._events.setCursorFromFlag();
1225 break;
1226
1227 case Common::KEYCODE_F5:
1228 // F5 - Save
1229 saveGame();
1230 R2_GLOBALS._events.setCursorFromFlag();
1231 event.handled = true;
1232 break;
1233
1234 case Common::KEYCODE_F7:
1235 // F7 - Restore
1236 restoreGame();
1237 R2_GLOBALS._events.setCursorFromFlag();
1238 break;
1239
1240 case Common::KEYCODE_F8:
1241 // F8 - Credits
1242 if (R2_GLOBALS._sceneManager._sceneNumber != 205)
1243 R2_GLOBALS._sceneManager.changeScene(205);
1244 break;
1245
1246 case Common::KEYCODE_F10:
1247 // F10 - Pause
1248 GfxDialog::setPalette();
1249 MessageDialog::show(GAME_PAUSED_MSG, OK_BTN_STRING);
1250 R2_GLOBALS._events.setCursorFromFlag();
1251 break;
1252
1253 default:
1254 break;
1255 }
1256 }
1257 }
1258
rightClick()1259 void Ringworld2Game::rightClick() {
1260 RightClickDialog *dlg = new RightClickDialog();
1261 int option = dlg->execute();
1262 delete dlg;
1263
1264 if (option == 0)
1265 CharacterDialog::show();
1266 else if (option == 1)
1267 HelpDialog::show();
1268 }
1269
1270 /*--------------------------------------------------------------------------*/
1271
NamedHotspot()1272 NamedHotspot::NamedHotspot() : SceneHotspot() {
1273 _resNum = 0;
1274 _lookLineNum = _useLineNum = _talkLineNum = -1;
1275 }
1276
startAction(CursorType action,Event & event)1277 bool NamedHotspot::startAction(CursorType action, Event &event) {
1278 switch (action) {
1279 case CURSOR_WALK:
1280 // Nothing
1281 return false;
1282 case CURSOR_LOOK:
1283 if (_lookLineNum == -1)
1284 return SceneHotspot::startAction(action, event);
1285
1286 SceneItem::display2(_resNum, _lookLineNum);
1287 return true;
1288 case CURSOR_USE:
1289 if (_useLineNum == -1)
1290 return SceneHotspot::startAction(action, event);
1291
1292 SceneItem::display2(_resNum, _useLineNum);
1293 return true;
1294 case CURSOR_TALK:
1295 if (_talkLineNum == -1)
1296 return SceneHotspot::startAction(action, event);
1297
1298 SceneItem::display2(_resNum, _talkLineNum);
1299 return true;
1300 default:
1301 return SceneHotspot::startAction(action, event);
1302 }
1303 }
1304
1305 /*--------------------------------------------------------------------------*/
1306
postInit(SceneObjectList * OwnerList)1307 void SceneActor::postInit(SceneObjectList *OwnerList) {
1308 _lookLineNum = _talkLineNum = _useLineNum = -1;
1309 SceneObject::postInit();
1310 }
1311
remove()1312 void SceneActor::remove() {
1313 R2_GLOBALS._sceneItems.remove(this);
1314 _shadowMap = NULL;
1315 _linkedActor = NULL;
1316
1317 SceneObject::remove();
1318 }
1319
startAction(CursorType action,Event & event)1320 bool SceneActor::startAction(CursorType action, Event &event) {
1321 bool handled = true;
1322
1323 switch (action) {
1324 case CURSOR_LOOK:
1325 if (_lookLineNum == -1)
1326 handled = false;
1327 else
1328 SceneItem::display2(_resNum, _lookLineNum);
1329 break;
1330 case CURSOR_USE:
1331 if (_useLineNum == -1)
1332 handled = false;
1333 else
1334 SceneItem::display2(_resNum, _useLineNum);
1335 break;
1336 case CURSOR_TALK:
1337 if (_talkLineNum == -1)
1338 handled = false;
1339 else
1340 SceneItem::display2(_resNum, _talkLineNum);
1341 break;
1342 default:
1343 handled = false;
1344 break;
1345 }
1346
1347 if (!handled)
1348 handled = ((SceneExt *)R2_GLOBALS._sceneManager._scene)->display(action, event);
1349 return handled;
1350 }
1351
getFrame()1352 GfxSurface SceneActor::getFrame() {
1353 GfxSurface frame = SceneObject::getFrame();
1354
1355 return frame;
1356 }
1357
1358 /*--------------------------------------------------------------------------*/
1359
SceneArea()1360 SceneArea::SceneArea(): SceneItem() {
1361 _enabled = true;
1362 _insideArea = false;
1363 _savedCursorNum = CURSOR_NONE;
1364 _cursorState = 0;
1365 _cursorNum = CURSOR_NONE;
1366 }
1367
synchronize(Serializer & s)1368 void SceneArea::synchronize(Serializer &s) {
1369 EventHandler::synchronize(s);
1370
1371 _bounds.synchronize(s);
1372 s.syncAsSint16LE(_enabled);
1373 s.syncAsSint16LE(_insideArea);
1374 s.syncAsSint32LE(_cursorNum);
1375 s.syncAsSint32LE(_savedCursorNum);
1376 s.syncAsSint16LE(_cursorState);
1377 }
1378
remove()1379 void SceneArea::remove() {
1380 static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.remove(this);
1381 }
1382
process(Event & event)1383 void SceneArea::process(Event &event) {
1384 Common::Point mousePos = event.mousePos;
1385 mousePos.x += R2_GLOBALS._sceneManager._scene->_sceneBounds.left;
1386
1387 if (!R2_GLOBALS._insetUp && _enabled && R2_GLOBALS._events.isCursorVisible()) {
1388 CursorType cursor = R2_GLOBALS._events.getCursor();
1389
1390 if (_bounds.contains(mousePos)) {
1391 // Cursor moving in bounded area
1392 if (cursor != _cursorNum) {
1393 _savedCursorNum = cursor;
1394 _cursorState = 0;
1395 R2_GLOBALS._events.setCursor(_cursorNum);
1396 }
1397 _insideArea = true;
1398 } else if ((mousePos.y < 171) && _insideArea && (_cursorNum == cursor) &&
1399 (_savedCursorNum != CURSOR_NONE)) {
1400 // Cursor moved outside bounded area
1401 R2_GLOBALS._events.setCursor(_savedCursorNum);
1402 }
1403 }
1404 }
1405
setDetails(const Rect & bounds,CursorType cursor)1406 void SceneArea::setDetails(const Rect &bounds, CursorType cursor) {
1407 _bounds = bounds;
1408 _cursorNum = cursor;
1409
1410 static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this);
1411 }
1412
1413 /*--------------------------------------------------------------------------*/
1414
SceneExit()1415 SceneExit::SceneExit(): SceneArea() {
1416 _moving = false;
1417 _destPos = Common::Point(-1, -1);
1418
1419 _sceneNumber = 0;
1420 }
1421
synchronize(Serializer & s)1422 void SceneExit::synchronize(Serializer &s) {
1423 SceneArea::synchronize(s);
1424
1425 s.syncAsSint16LE(_moving);
1426 s.syncAsSint16LE(_destPos.x);
1427 s.syncAsSint16LE(_destPos.y);
1428 }
1429
setDetails(const Rect & bounds,CursorType cursor,int sceneNumber)1430 void SceneExit::setDetails(const Rect &bounds, CursorType cursor, int sceneNumber) {
1431 _sceneNumber = sceneNumber;
1432 SceneArea::setDetails(bounds, cursor);
1433 }
1434
changeScene()1435 void SceneExit::changeScene() {
1436 R2_GLOBALS._sceneManager.setNewScene(_sceneNumber);
1437 }
1438
process(Event & event)1439 void SceneExit::process(Event &event) {
1440 Common::Point mousePos = event.mousePos;
1441 mousePos.x += R2_GLOBALS._sceneManager._scene->_sceneBounds.left;
1442
1443 if (!R2_GLOBALS._insetUp) {
1444 SceneArea::process(event);
1445
1446 if (_enabled && R2_GLOBALS._player._enabled) {
1447 if (event.eventType == EVENT_BUTTON_DOWN) {
1448 if (!_bounds.contains(mousePos))
1449 _moving = false;
1450 else if (!R2_GLOBALS._player._canWalk) {
1451 _moving = false;
1452 changeScene();
1453 event.handled = true;
1454 } else {
1455 Common::Point dest((_destPos.x == -1) ? mousePos.x : _destPos.x,
1456 (_destPos.y == -1) ? mousePos.y : _destPos.y);
1457 ADD_PLAYER_MOVER(dest.x, dest.y);
1458
1459 _moving = true;
1460 event.handled = true;
1461 }
1462 }
1463
1464 if (_moving && (_bounds.contains(R2_GLOBALS._player._position) || (R2_GLOBALS._player._position == _destPos)))
1465 changeScene();
1466 }
1467 }
1468 }
1469
1470 /*--------------------------------------------------------------------------*/
1471
remove()1472 void SceneAreaObject::remove() {
1473 R2_GLOBALS._sceneItems.remove(this);
1474 _object1.remove();
1475 SceneArea::remove();
1476 --R2_GLOBALS._insetUp;
1477 }
1478
process(Event & event)1479 void SceneAreaObject::process(Event &event) {
1480 if (_insetCount == R2_GLOBALS._insetUp) {
1481 CursorType cursor = R2_GLOBALS._events.getCursor();
1482
1483 if (_object1._bounds.contains(event.mousePos)) {
1484 // Cursor moving in bounded area
1485 if (cursor == _cursorNum) {
1486 R2_GLOBALS._events.setCursor(_savedCursorNum);
1487 }
1488 } else if (event.mousePos.y < 168) {
1489 if (_cursorNum != cursor) {
1490 // Cursor moved outside bounded area
1491 _savedCursorNum = R2_GLOBALS._events.getCursor();
1492 R2_GLOBALS._events.setCursor(CURSOR_INVALID);
1493 }
1494
1495 if (event.eventType == EVENT_BUTTON_DOWN) {
1496 event.handled = true;
1497 R2_GLOBALS._events.setCursor(_savedCursorNum);
1498 remove();
1499 }
1500 }
1501 }
1502 }
1503
setDetails(int visage,int strip,int frameNumber,const Common::Point & pt)1504 void SceneAreaObject::setDetails(int visage, int strip, int frameNumber, const Common::Point &pt) {
1505 _object1.postInit();
1506 _object1.setup(visage, strip, frameNumber);
1507 _object1.setPosition(pt);
1508 _object1.fixPriority(250);
1509
1510 _cursorNum = CURSOR_INVALID;
1511 Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene;
1512 scene->_sceneAreas.push_front(this);
1513
1514 _insetCount = ++R2_GLOBALS._insetUp;
1515 }
1516
setDetails(int resNum,int lookLineNum,int talkLineNum,int useLineNum)1517 void SceneAreaObject::setDetails(int resNum, int lookLineNum, int talkLineNum, int useLineNum) {
1518 _object1.setDetails(resNum, lookLineNum, talkLineNum, useLineNum,
1519 2, (SceneItem *)NULL);
1520 }
1521
1522 /*****************************************************************************/
1523
MazeUI()1524 MazeUI::MazeUI() {
1525 _mapData = NULL;
1526 _cellsVisible.x = _cellsVisible.y = 0;
1527 _mapCells.x = _mapCells.y = 0;
1528 _cellSize.x = _cellSize.y = 0;
1529 _mapOffset.x = _mapOffset.y = 0;
1530 _resNum = _cellsResNum = 0;
1531 _frameCount = _resCount = _mapImagePitch = 0;
1532 }
1533
~MazeUI()1534 MazeUI::~MazeUI() {
1535 DEALLOCATE(_mapData);
1536 }
1537
synchronize(Serializer & s)1538 void MazeUI::synchronize(Serializer &s) {
1539 SceneObject::synchronize(s);
1540
1541 s.syncAsSint16LE(_resNum);
1542 if (s.isLoading())
1543 load(_resNum);
1544
1545 s.syncAsSint16LE(_mapOffset.x);
1546 s.syncAsSint16LE(_mapOffset.y);
1547
1548 int dummy = 0;
1549 s.syncAsSint16LE(dummy);
1550 }
1551
load(int resNum)1552 void MazeUI::load(int resNum) {
1553 clear();
1554 _resNum = resNum;
1555
1556 const byte *header = g_resourceManager->getResource(RT17, resNum, 0);
1557
1558 _cellsResNum = resNum + 1000;
1559 _mapCells.x = READ_LE_UINT16(header + 2);
1560 _mapCells.y = READ_LE_UINT16(header + 4);
1561 _frameCount = 10;
1562 _resCount = _frameCount << 3;
1563
1564 Visage visage;
1565 visage.setVisage(_cellsResNum, 1);
1566
1567 GfxSurface frame = visage.getFrame(2);
1568 _cellSize.x = frame.getBounds().width();
1569 _cellSize.y = frame.getBounds().height();
1570
1571 _mapData = g_resourceManager->getResource(RT17, resNum, 1);
1572
1573 _mapOffset.y = _mapOffset.x = 0;
1574 _cellsVisible.x = (_bounds.width() + _cellSize.x - 1) / _cellSize.x;
1575 _cellsVisible.y = (_bounds.height() + _cellSize.y - 1) / _cellSize.y;
1576
1577 _mapImagePitch = (_cellsVisible.x + 1) * _cellSize.x;
1578 _mapImage.create(_mapImagePitch, _cellSize.y);
1579
1580 _mapBounds = Rect(0, 0, _cellSize.x * _mapCells.x, _cellSize.y * _mapCells.y);
1581 }
1582
clear()1583 void MazeUI::clear() {
1584 if (!_resNum)
1585 _resNum = 1;
1586
1587 if (_mapData)
1588 DEALLOCATE(_mapData);
1589 _mapData = NULL;
1590
1591 _mapImage.clear();
1592 }
1593
setMazePosition(const Common::Point & pt)1594 bool MazeUI::setMazePosition(const Common::Point &pt) {
1595 bool retval = false;
1596
1597 _mapOffset = pt;
1598
1599 if (_mapOffset.x < _mapBounds.top) {
1600 _mapOffset.x = _mapBounds.top;
1601 retval = true;
1602 }
1603
1604 if (_mapOffset.y < _mapBounds.left) {
1605 _mapOffset.y = _mapBounds.left;
1606 retval = true;
1607 }
1608
1609 if (_mapOffset.x + _bounds.width() > _mapBounds.right) {
1610 _mapOffset.x = _mapBounds.right - _bounds.width();
1611 retval = true;
1612 }
1613
1614 if (_mapOffset.y + _bounds.height() > _mapBounds.bottom) {
1615 _mapOffset.y = _mapBounds.bottom - _bounds.height();
1616 retval = true;
1617 }
1618
1619 return retval;
1620 }
1621
reposition()1622 void MazeUI::reposition() {
1623 }
1624
draw()1625 void MazeUI::draw() {
1626 int yPos = 0;
1627 int ySize;
1628 Visage visage;
1629
1630 _cellsVisible.y = ((_mapOffset.y % _cellSize.y) + _bounds.height() +
1631 (_cellSize.y - 1)) / _cellSize.y;
1632
1633 // Loop to handle the cell rows of the visible display area one at a time
1634 for (int yCtr = 0; yCtr <= _cellsVisible.y; ++yCtr, yPos += ySize) {
1635 int cellY = _mapOffset.y / _cellSize.y + yCtr;
1636
1637 // Loop to iterate through the horizontal visible cells to build up
1638 // an entire cell high horizontal slice of the map, plus one extra cell
1639 // to allow for partial cell scrolling on-screen on the left/right sides
1640 for (int xCtr = 0; xCtr <= _cellsVisible.x; ++xCtr) {
1641 int cellX = _mapOffset.x / _cellSize.x + xCtr;
1642
1643 // Get the type of content to display in the cell
1644 int cell = getCellFromCellXY(Common::Point(cellX, cellY)) - 1;
1645 if (cell >= 0) {
1646 int frameNum = (cell % _frameCount) + 1;
1647 int rlbNum = (cell % _resCount) / _frameCount + 1;
1648 int resNum = _cellsResNum + (cell / _resCount);
1649
1650 visage.setVisage(resNum, rlbNum);
1651 GfxSurface frame = visage.getFrame(frameNum);
1652
1653 _mapImage.copyFrom(frame, xCtr * _cellSize.x, 0);
1654 } else {
1655 GfxSurface emptyRect;
1656 emptyRect.create(_cellSize.x, _cellSize.y);
1657
1658 _mapImage.copyFrom(emptyRect, xCtr * _cellSize.x, 0);
1659 }
1660 }
1661
1662 if (yPos == 0) {
1663 // First line of the map to be displayed - only the bottom portion of that
1664 // first cell row may be visible
1665 yPos = _bounds.top;
1666 ySize = _cellSize.y - (_mapOffset.y % _cellSize.y);
1667
1668 Rect srcBounds(_mapOffset.x % _cellSize.x, _mapOffset.y % _cellSize.y,
1669 (_mapOffset.x % _cellSize.x) + _bounds.width(), _cellSize.y);
1670 Rect destBounds(_bounds.left, yPos, _bounds.right, yPos + ySize);
1671
1672 R2_GLOBALS.gfxManager().copyFrom(_mapImage, srcBounds, destBounds);
1673 } else {
1674 if ((yPos + _cellSize.y) < _bounds.bottom) {
1675 ySize = _cellSize.y;
1676 } else {
1677 ySize = _bounds.bottom - yPos;
1678 }
1679
1680 Rect srcBounds(_mapOffset.x % _cellSize.x, 0,
1681 (_mapOffset.x % _cellSize.x) + _bounds.width(), ySize);
1682 Rect destBounds(_bounds.left, yPos, _bounds.right, yPos + ySize);
1683
1684 R2_GLOBALS.gfxManager().copyFrom(_mapImage, srcBounds, destBounds);
1685 }
1686 }
1687 }
1688
getCellFromPixelXY(const Common::Point & pt)1689 int MazeUI::getCellFromPixelXY(const Common::Point &pt) {
1690 if (!_bounds.contains(pt))
1691 return -1;
1692
1693 int cellX = (pt.x - _bounds.left + _mapOffset.x) / _cellSize.x;
1694 int cellY = (pt.y - _bounds.top + _mapOffset.y) / _cellSize.y;
1695
1696 if ((cellX >= 0) && (cellY >= 0) && (cellX < _mapCells.x) && (cellY < _mapCells.y))
1697 return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * cellY + cellX) * 2);
1698
1699 return -1;
1700 }
1701
getCellFromCellXY(const Common::Point & p)1702 int MazeUI::getCellFromCellXY(const Common::Point &p) {
1703 if (p.x < 0 || p.y < 0 || p.x >= _mapCells.x || p.y >= _mapCells.y) {
1704 return -1;
1705 } else {
1706 return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * p.y + p.x) * 2);
1707 }
1708 }
1709
pixelToCellXY(Common::Point & pt)1710 int MazeUI::pixelToCellXY(Common::Point &pt) {
1711 pt.x /= _cellSize.x;
1712 pt.y /= _cellSize.y;
1713
1714 if ((pt.x >= 0) && (pt.y >= 0) && (pt.x < _mapCells.x) && (pt.y < _mapCells.y)) {
1715 return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * pt.y + pt.x) * 2);
1716 }
1717
1718 return -1;
1719 }
1720
setDisplayBounds(const Rect & r)1721 void MazeUI::setDisplayBounds(const Rect &r) {
1722 _bounds = r;
1723 _bounds.clip(g_globals->gfxManager()._bounds);
1724 }
1725
1726 /*--------------------------------------------------------------------------*/
1727
load(Common::File & f)1728 void AnimationSlice::load(Common::File &f) {
1729 f.skip(2);
1730 _sliceOffset = f.readUint16LE();
1731 f.skip(6);
1732 _drawMode = f.readByte();
1733 _secondaryIndex = f.readByte();
1734 }
1735
1736 /*--------------------------------------------------------------------------*/
1737
AnimationSlices()1738 AnimationSlices::AnimationSlices() {
1739 _pixelData = NULL;
1740
1741 _dataSize = 0;
1742 _dataSize2 = 0;
1743 _slices->_sliceOffset = 0;
1744 _slices->_drawMode = 0;
1745 _slices->_secondaryIndex = 0;
1746 }
1747
~AnimationSlices()1748 AnimationSlices::~AnimationSlices() {
1749 delete[] _pixelData;
1750 }
1751
load(Common::File & f)1752 void AnimationSlices::load(Common::File &f) {
1753 f.skip(4);
1754 _dataSize = f.readUint32LE();
1755 f.skip(8);
1756 _dataSize2 = f.readUint32LE();
1757 f.skip(28);
1758
1759 // Load the four slice indexes
1760 for (int idx = 0; idx < 4; ++idx)
1761 _slices[idx].load(f);
1762 }
1763
loadPixels(Common::File & f,int slicesSize)1764 int AnimationSlices::loadPixels(Common::File &f, int slicesSize) {
1765 delete[] _pixelData;
1766 _pixelData = new byte[slicesSize];
1767 return f.read(_pixelData, slicesSize);
1768 }
1769
1770 /*--------------------------------------------------------------------------*/
1771
load(Common::File & f)1772 void AnimationPlayerSubData::load(Common::File &f) {
1773 uint32 posStart = f.pos();
1774
1775 f.skip(6);
1776 _duration = f.readUint32LE();
1777 _frameRate = f.readUint16LE();
1778 _framesPerSlices = f.readUint16LE();
1779 _drawType = f.readUint16LE();
1780 f.skip(2);
1781 _sliceSize = f.readUint16LE();
1782 _ySlices = f.readUint16LE();
1783 _field16 = f.readUint32LE();
1784 f.skip(2);
1785 _palStart = f.readUint16LE();
1786 _palSize = f.readUint16LE();
1787 f.read(_palData, 768);
1788 _totalSize = f.readSint32LE();
1789 f.skip(12);
1790 _slices.load(f);
1791
1792 uint32 posEnd = f.pos();
1793 assert((posEnd - posStart) == 0x390);
1794 }
1795
1796 /*--------------------------------------------------------------------------*/
1797
AnimationPlayer()1798 AnimationPlayer::AnimationPlayer(): EventHandler() {
1799 _endAction = NULL;
1800
1801 _animData1 = NULL;
1802 _animData2 = NULL;
1803
1804 _screenBounds = R2_GLOBALS._gfxManagerInstance._bounds;
1805 _rect1 = R2_GLOBALS._gfxManagerInstance._bounds;
1806 _paletteMode = ANIMPALMODE_REPLACE_PALETTE;
1807 _canSkip = true;
1808 _sliceHeight = 1;
1809 _endAction = NULL;
1810
1811 _sliceCurrent = nullptr;
1812 _sliceNext = nullptr;
1813 _animLoaded = false;
1814 _objectMode = ANIMOBJMODE_1;
1815 _dataNeeded = 0;
1816 _playbackTick = 0;
1817 _playbackTickPrior = 0;
1818 _position = 0;
1819 _nextSlicesPosition = 0;
1820 _frameDelay = 0;
1821 _gameFrame = 0;
1822 }
1823
~AnimationPlayer()1824 AnimationPlayer::~AnimationPlayer() {
1825 if (!isCompleted())
1826 close();
1827 }
1828
synchronize(Serializer & s)1829 void AnimationPlayer::synchronize(Serializer &s) {
1830 EventHandler::synchronize(s);
1831
1832 // TODO: Implement saving for animation player state. Currently, I disable saving
1833 // when an animation is active, so saving it's state would a "nice to have".
1834 }
1835
remove()1836 void AnimationPlayer::remove() {
1837 if (_endAction)
1838 _endAction->signal();
1839
1840 _endAction = NULL;
1841 }
1842
process(Event & event)1843 void AnimationPlayer::process(Event &event) {
1844 if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE) && _canSkip) {
1845 // Move the current position to the end
1846 _position = _subData._duration;
1847 }
1848 }
1849
dispatch()1850 void AnimationPlayer::dispatch() {
1851 uint32 gameFrame = R2_GLOBALS._events.getFrameNumber();
1852 uint32 gameDiff = gameFrame - _gameFrame;
1853
1854 if (gameDiff >= _frameDelay) {
1855 drawFrame(_playbackTick % _subData._framesPerSlices);
1856 ++_playbackTick;
1857 _position = _playbackTick / _subData._framesPerSlices;
1858
1859 if (_position == _nextSlicesPosition)
1860 nextSlices();
1861
1862 _playbackTickPrior = _playbackTick;
1863 _gameFrame = gameFrame;
1864 }
1865 }
1866
load(int animId,Action * endAction)1867 bool AnimationPlayer::load(int animId, Action *endAction) {
1868 // Open up the main resource file for access
1869 TLib &libFile = g_resourceManager->first();
1870 if (!_resourceFile.open(libFile.getFilename()))
1871 error("Could not open resource");
1872
1873 // Get the offset of the given resource and seek to it in the player's file reference
1874 ResourceEntry entry;
1875 uint32 fileOffset = libFile.getResourceStart(RES_IMAGE, animId, 0, entry);
1876 _resourceFile.seek(fileOffset);
1877
1878 // At this point, the file is pointing to the start of the resource data
1879
1880 // Set the end action
1881 _endAction = endAction;
1882
1883 // Load the sub data block
1884 _subData.load(_resourceFile);
1885
1886 // Set other properties
1887 _playbackTickPrior = -1;
1888 _playbackTick = 0;
1889
1890 _frameDelay = (60 / _subData._frameRate);
1891 _gameFrame = R2_GLOBALS._events.getFrameNumber();
1892
1893 // WORKAROUND: Slow down the title sequences to better match the original
1894 if (animId <= 4 || animId == 15)
1895 _frameDelay *= 8;
1896
1897 if (_subData._totalSize) {
1898 _dataNeeded = _subData._totalSize;
1899 } else {
1900 int v = (_subData._sliceSize + 2) * _subData._ySlices * _subData._framesPerSlices;
1901 _dataNeeded = (_subData._field16 / _subData._framesPerSlices) + v + 96;
1902 }
1903
1904 debugC(1, ktSageDebugGraphics, "Data needed %d", _dataNeeded);
1905
1906 // Set up animation data objects
1907 _animData1 = new AnimationData();
1908 _sliceCurrent = _animData1;
1909
1910 if (_subData._framesPerSlices <= 1) {
1911 _animData2 = NULL;
1912 _sliceNext = _sliceCurrent;
1913 } else {
1914 _animData2 = new AnimationData();
1915 _sliceNext = _animData2;
1916 }
1917
1918 _position = 0;
1919 _nextSlicesPosition = 1;
1920
1921 // Load up the first slices set
1922 _sliceCurrent->_dataSize = _subData._slices._dataSize;
1923 _sliceCurrent->_slices = _subData._slices;
1924 int slicesSize = _sliceCurrent->_dataSize - 96;
1925 int readSize = _sliceCurrent->_slices.loadPixels(_resourceFile, slicesSize);
1926 _sliceCurrent->_animSlicesSize = readSize + 96;
1927
1928 if (_sliceNext != _sliceCurrent) {
1929 getSlices();
1930 }
1931
1932 // Handle starting palette
1933 switch (_paletteMode) {
1934 case ANIMPALMODE_REPLACE_PALETTE:
1935 // Use the palette provided with the animation directly
1936 _palette.getPalette();
1937 for (int idx = _subData._palStart; idx < (_subData._palStart + _subData._palSize); ++idx) {
1938 byte r = _subData._palData[idx * 3];
1939 byte g = _subData._palData[idx * 3 + 1];
1940 byte b = _subData._palData[idx * 3 + 2];
1941
1942 R2_GLOBALS._scenePalette.setEntry(idx, r, g, b);
1943 }
1944
1945 R2_GLOBALS._sceneManager._hasPalette = true;
1946 break;
1947 case ANIMPALMODE_NONE:
1948 break;
1949
1950 default:
1951 // ANIMPALMODE_CURR_PALETTE
1952 // Use the closest matching colors in the currently active palette to those specified in the animation
1953 for (int idx = _subData._palStart; idx < (_subData._palStart + _subData._palSize); ++idx) {
1954 byte r = _subData._palData[idx * 3];
1955 byte g = _subData._palData[idx * 3 + 1];
1956 byte b = _subData._palData[idx * 3 + 2];
1957
1958 int palIndex = R2_GLOBALS._scenePalette.indexOf(r, g, b);
1959 _palIndexes[idx] = palIndex;
1960 }
1961 break;
1962 }
1963
1964 ++R2_GLOBALS._animationCtr;
1965 _animLoaded = true;
1966 return true;
1967 }
1968
drawFrame(int sliceIndex)1969 void AnimationPlayer::drawFrame(int sliceIndex) {
1970 assert(sliceIndex < 4);
1971 AnimationSlices &slices = _sliceCurrent->_slices;
1972 AnimationSlice &slice = _sliceCurrent->_slices._slices[sliceIndex];
1973
1974 byte *sliceDataStart = &slices._pixelData[slice._sliceOffset - 96];
1975 byte *sliceData1 = sliceDataStart;
1976
1977 Rect playerBounds = _screenBounds;
1978
1979 Graphics::Surface dest = R2_GLOBALS._screen.getSubArea(playerBounds);
1980 int y = 0;
1981
1982 // Handle different drawing modes
1983 switch (slice._drawMode) {
1984 case 0:
1985 // Draw from uncompressed source
1986 for (int sliceNum = 0; sliceNum < _subData._ySlices; ++sliceNum) {
1987 for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex, ++y) {
1988 // TODO: Check of _subData._drawType was done for two different kinds of
1989 // line slice drawing in original
1990 const byte *pSrc = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
1991 byte *pDest = (byte *)dest.getBasePtr(0, y);
1992
1993 Common::copy(pSrc, pSrc + _subData._sliceSize, pDest);
1994 }
1995 }
1996 break;
1997
1998 case 1:
1999 switch (slice._secondaryIndex) {
2000 case 0xfe:
2001 // Draw from uncompressed source with optional skipped rows
2002 for (int sliceNum = 0; sliceNum < _subData._ySlices; ++sliceNum) {
2003 for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex, ++y) {
2004 int offset = READ_LE_UINT16(sliceData1 + sliceNum * 2);
2005
2006 if (offset) {
2007 const byte *pSrc = (const byte *)sliceDataStart + offset;
2008 byte *pDest = (byte *)dest.getBasePtr(0, y);
2009
2010 //Common::copy(pSrc, pSrc + playerBounds.width(), pDest);
2011 rleDecode(pSrc, pDest, playerBounds.width());
2012 }
2013 }
2014 }
2015 break;
2016 case 0xff:
2017 // Draw from RLE compressed source
2018 for (int sliceNum = 0; sliceNum < _subData._ySlices; ++sliceNum) {
2019 for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex, ++y) {
2020 // TODO: Check of _subData._drawType was done for two different kinds of
2021 // line slice drawing in original
2022 const byte *pSrc = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
2023 byte *pDest = (byte *)dest.getBasePtr(0, y);
2024
2025 rleDecode(pSrc, pDest, _subData._sliceSize);
2026 }
2027 }
2028 break;
2029 default: {
2030 // Draw from two slice sets simultaneously
2031 AnimationSlice &slice2 = _sliceCurrent->_slices._slices[slice._secondaryIndex];
2032 byte *sliceData2 = &slices._pixelData[slice2._sliceOffset - 96];
2033
2034 for (int sliceNum = 0; sliceNum < _subData._ySlices; ++sliceNum) {
2035 for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex, ++y) {
2036 const byte *pSrc1 = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData2 + sliceNum * 2);
2037 const byte *pSrc2 = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
2038 byte *pDest = (byte *)dest.getBasePtr(0, y);
2039
2040 if (slice2._drawMode == 0) {
2041 // Uncompressed background, foreground compressed
2042 Common::copy(pSrc1, pSrc1 + _subData._sliceSize, pDest);
2043 rleDecode(pSrc2, pDest, _subData._sliceSize);
2044 } else {
2045 // Both background and foreground is compressed
2046 rleDecode(pSrc1, pDest, _subData._sliceSize);
2047 rleDecode(pSrc2, pDest, _subData._sliceSize);
2048 }
2049 }
2050 }
2051 break;
2052 }
2053 }
2054 default:
2055 break;
2056 }
2057
2058 if (_objectMode == ANIMOBJMODE_42) {
2059 _screenBounds.expandPanes();
2060
2061 // Copy the drawn frame to the back surface
2062 Rect srcRect = R2_GLOBALS._screen.getBounds();
2063 Rect destRect = srcRect;
2064 destRect.translate(-g_globals->_sceneOffset.x, -g_globals->_sceneOffset.y);
2065 R2_GLOBALS._sceneManager._scene->_backSurface.copyFrom(R2_GLOBALS._screen,
2066 srcRect, destRect);
2067
2068 // Draw any objects into the scene
2069 R2_GLOBALS._sceneObjects->draw();
2070 } else {
2071 if (R2_GLOBALS._sceneManager._hasPalette) {
2072 R2_GLOBALS._sceneManager._hasPalette = false;
2073 R2_GLOBALS._scenePalette.refresh();
2074 }
2075 }
2076 }
2077
2078 /**
2079 * Read the next frame's slice set
2080 */
nextSlices()2081 void AnimationPlayer::nextSlices() {
2082 _position = _nextSlicesPosition++;
2083 _playbackTick = _position * _subData._framesPerSlices;
2084 _playbackTickPrior = _playbackTick - 1;
2085
2086 if (_sliceNext == _sliceCurrent) {
2087 int dataSize = _sliceCurrent->_slices._dataSize2;
2088 _sliceCurrent->_dataSize = dataSize;
2089 debugC(1, ktSageDebugGraphics, "Next frame size = %xh", dataSize);
2090 if (dataSize == 0)
2091 return;
2092
2093 dataSize -= 96;
2094 assert(dataSize >= 0);
2095 _sliceCurrent->_slices.load(_resourceFile);
2096 _sliceCurrent->_animSlicesSize = _sliceCurrent->_slices.loadPixels(_resourceFile, dataSize);
2097 } else {
2098 SWAP(_sliceCurrent, _sliceNext);
2099 getSlices();
2100 }
2101 }
2102
isCompleted()2103 bool AnimationPlayer::isCompleted() {
2104 return (_position >= _subData._duration);
2105 }
2106
close()2107 void AnimationPlayer::close() {
2108 if (_animLoaded) {
2109 switch (_paletteMode) {
2110 case 0:
2111 R2_GLOBALS._scenePalette.replace(&_palette);
2112 changePane();
2113 R2_GLOBALS._sceneManager._hasPalette = true;
2114 break;
2115 case 2:
2116 closing();
2117 break;
2118 default:
2119 changePane();
2120 break;
2121 }
2122 }
2123
2124 // Close the resource file
2125 _resourceFile.close();
2126
2127 if (_objectMode != ANIMOBJMODE_42) {
2128 // flip screen in original
2129 }
2130
2131 // Free animation objects
2132 delete _animData1;
2133 delete _animData2;
2134 _animData1 = NULL;
2135 _animData2 = NULL;
2136
2137 _animLoaded = false;
2138 if (g_globals != NULL)
2139 R2_GLOBALS._animationCtr = MAX(R2_GLOBALS._animationCtr - 1, 0);
2140 }
2141
rleDecode(const byte * pSrc,byte * pDest,int size)2142 void AnimationPlayer::rleDecode(const byte *pSrc, byte *pDest, int size) {
2143 while (size > 0) {
2144 byte v = *pSrc++;
2145 if (!(v & 0x80)) {
2146 // Following uncompressed set of bytes
2147 Common::copy(pSrc, pSrc + v, pDest);
2148 pSrc += v;
2149 pDest += v;
2150 size -= v;
2151 } else {
2152 int count = v & 0x3F;
2153 size -= count;
2154
2155 if (!(v & 0x40)) {
2156 // Skip over a number of bytes
2157 pDest += count;
2158 } else {
2159 // Replicate a number of bytes
2160 Common::fill(pDest, pDest + count, *pSrc++);
2161 pDest += count;
2162 }
2163 }
2164 }
2165 }
2166
getSlices()2167 void AnimationPlayer::getSlices() {
2168 assert((_sliceNext == _animData1) || (_sliceNext == _animData2));
2169 assert((_sliceCurrent == _animData1) || (_sliceCurrent == _animData2));
2170
2171 _sliceNext->_dataSize = _sliceCurrent->_slices._dataSize2;
2172 if (_sliceNext->_dataSize) {
2173 if (_sliceNext->_dataSize >= _dataNeeded)
2174 error("Bogus dataNeeded == %d / %d", _sliceNext->_dataSize, _dataNeeded);
2175 }
2176
2177 int dataSize = _sliceNext->_dataSize - 96;
2178 _sliceNext->_slices.load(_resourceFile);
2179 _sliceNext->_animSlicesSize = _sliceNext->_slices.loadPixels(_resourceFile, dataSize);
2180 }
2181
2182 /*--------------------------------------------------------------------------*/
2183
AnimationPlayerExt()2184 AnimationPlayerExt::AnimationPlayerExt(): AnimationPlayer() {
2185 _isActive = false;
2186 _canSkip = false;
2187 }
2188
synchronize(Serializer & s)2189 void AnimationPlayerExt::synchronize(Serializer &s) {
2190 AnimationPlayer::synchronize(s);
2191 s.syncAsSint16LE(_isActive);
2192 }
2193
2194 /*--------------------------------------------------------------------------*/
2195
ModalWindow()2196 ModalWindow::ModalWindow() {
2197 _insetCount = 0;
2198 }
2199
remove()2200 void ModalWindow::remove() {
2201 R2_GLOBALS._sceneItems.remove(&_object1);
2202 _object1.remove();
2203
2204 SceneArea::remove();
2205
2206 --R2_GLOBALS._insetUp;
2207 }
2208
synchronize(Serializer & s)2209 void ModalWindow::synchronize(Serializer &s) {
2210 SceneArea::synchronize(s);
2211
2212 s.syncAsByte(_insetCount);
2213 }
2214
process(Event & event)2215 void ModalWindow::process(Event &event) {
2216 if (_insetCount != R2_GLOBALS._insetUp)
2217 return;
2218
2219 CursorType cursor = R2_GLOBALS._events.getCursor();
2220
2221 if (_object1._bounds.contains(event.mousePos.x + g_globals->gfxManager()._bounds.left , event.mousePos.y)) {
2222 if (cursor == _cursorNum) {
2223 R2_GLOBALS._events.setCursor(_savedCursorNum);
2224 }
2225 } else if (event.mousePos.y < 168) {
2226 if (cursor != _cursorNum) {
2227 _savedCursorNum = cursor;
2228 R2_GLOBALS._events.setCursor(CURSOR_INVALID);
2229 }
2230 if (event.eventType == EVENT_BUTTON_DOWN) {
2231 event.handled = true;
2232 R2_GLOBALS._events.setCursor(_savedCursorNum);
2233 remove();
2234 }
2235 }
2236 }
2237
setup2(int visage,int stripFrameNum,int frameNum,int posX,int posY)2238 void ModalWindow::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY) {
2239 Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene;
2240
2241 _object1.postInit();
2242 _object1.setup(visage, stripFrameNum, frameNum);
2243 _object1.setPosition(Common::Point(posX, posY));
2244 _object1.fixPriority(250);
2245 _cursorNum = CURSOR_INVALID;
2246 scene->_sceneAreas.push_front(this);
2247 ++R2_GLOBALS._insetUp;
2248 _insetCount = R2_GLOBALS._insetUp;
2249 }
2250
setup3(int resNum,int lookLineNum,int talkLineNum,int useLineNum)2251 void ModalWindow::setup3(int resNum, int lookLineNum, int talkLineNum, int useLineNum) {
2252 _object1.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL);
2253 }
2254
2255 /*--------------------------------------------------------------------------*/
2256
Button()2257 ScannerDialog::Button::Button() {
2258 _buttonId = 0;
2259 _buttonDown = false;
2260 }
2261
setup(int buttonId)2262 void ScannerDialog::Button::setup(int buttonId) {
2263 _buttonId = buttonId;
2264 _buttonDown = false;
2265 SceneActor::postInit();
2266
2267 SceneObject::setup(4, 2, 2);
2268 fixPriority(255);
2269
2270 if (_buttonId == 1)
2271 setPosition(Common::Point(141, 99));
2272 else if (_buttonId == 2)
2273 setPosition(Common::Point(141, 108));
2274
2275 static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this);
2276 }
2277
synchronize(Serializer & s)2278 void ScannerDialog::Button::synchronize(Serializer &s) {
2279 SceneActor::synchronize(s);
2280 s.syncAsSint16LE(_buttonId);
2281 }
2282
process(Event & event)2283 void ScannerDialog::Button::process(Event &event) {
2284 if (event.eventType == EVENT_BUTTON_DOWN && R2_GLOBALS._events.getCursor() == CURSOR_USE
2285 && _bounds.contains(event.mousePos) && !_buttonDown) {
2286 setFrame(3);
2287 _buttonDown = true;
2288 event.handled = true;
2289 }
2290
2291 if (event.eventType == EVENT_BUTTON_UP && _buttonDown) {
2292 setFrame(2);
2293 _buttonDown = false;
2294 event.handled = true;
2295
2296 reset();
2297 }
2298 }
2299
startAction(CursorType action,Event & event)2300 bool ScannerDialog::Button::startAction(CursorType action, Event &event) {
2301 if (action == CURSOR_USE)
2302 return false;
2303
2304 return startAction(action, event);
2305 }
2306
reset()2307 void ScannerDialog::Button::reset() {
2308 Scene *scene = R2_GLOBALS._sceneManager._scene;
2309 ScannerDialog &scanner = *R2_GLOBALS._scannerDialog;
2310
2311 switch (_buttonId) {
2312 case 1:
2313 // Talk button
2314 switch (R2_GLOBALS._sceneManager._sceneNumber) {
2315 case 1550:
2316 scene->_sceneMode = 80;
2317 scene->signal();
2318 break;
2319 case 1700:
2320 scene->_sceneMode = 30;
2321 scene->signal();
2322 remove();
2323 break;
2324 default:
2325 break;
2326 }
2327 break;
2328 case 2:
2329 // Scan button
2330 switch (R2_GLOBALS._sceneManager._sceneNumber) {
2331 case 1550:
2332 scanner._obj4.setup(4, 3, 1);
2333
2334 scanner._obj5.postInit();
2335 scanner._obj5.setup(4, 4, 1);
2336 scanner._obj5.setPosition(Common::Point(R2_GLOBALS._s1550PlayerArea[R2_QUINN].x + 145,
2337 R2_GLOBALS._s1550PlayerArea[R2_QUINN].y + 59));
2338 scanner._obj5.fixPriority(257);
2339
2340 scanner._obj6.postInit();
2341 scanner._obj6.setup(4, 4, 2);
2342 scanner._obj6.setPosition(Common::Point(R2_GLOBALS._s1550PlayerArea[R2_SEEKER].x + 145,
2343 R2_GLOBALS._s1550PlayerArea[R2_SEEKER].y + 59));
2344 scanner._obj6.fixPriority(257);
2345 break;
2346 case 1700:
2347 case 1800:
2348 if (R2_GLOBALS._rimLocation < 1201)
2349 scanner._obj4.setup(4, 3, 3);
2350 else if (R2_GLOBALS._rimLocation > 1201)
2351 scanner._obj4.setup(4, 3, 4);
2352 else
2353 scanner._obj4.setup(4, 3, 5);
2354 break;
2355 case 3800:
2356 case 3900:
2357 if ((R2_GLOBALS._desertWrongDirCtr + 1) == 0 && R2_GLOBALS._desertCorrectDirection == 0) {
2358 do {
2359 R2_GLOBALS._desertCorrectDirection = R2_GLOBALS._randomSource.getRandomNumber(3) + 1;
2360 } while (R2_GLOBALS._desertCorrectDirection == R2_GLOBALS._desertPreviousDirection);
2361 }
2362
2363 scanner._obj4.setup(4, 7, R2_GLOBALS._desertCorrectDirection);
2364 if (!R2_GLOBALS.getFlag(46))
2365 R2_GLOBALS.setFlag(46);
2366 break;
2367 default:
2368 scanner._obj4.setup(4, 3, 2);
2369 break;
2370 }
2371 break;
2372 default:
2373 break;
2374 }
2375 }
2376
2377 /*--------------------------------------------------------------------------*/
2378
Slider()2379 ScannerDialog::Slider::Slider() {
2380 _initial = _xStart = _yp = 0;
2381 _width = _xInc = 0;
2382 _sliderDown = false;
2383 }
2384
synchronize(Serializer & s)2385 void ScannerDialog::Slider::synchronize(Serializer &s) {
2386 SceneActor::synchronize(s);
2387
2388 s.syncAsSint16LE(_initial);
2389 s.syncAsSint16LE(_xStart);
2390 s.syncAsSint16LE(_yp);
2391 s.syncAsSint16LE(_width);
2392 s.syncAsSint16LE(_xInc);
2393 }
2394
remove()2395 void ScannerDialog::Slider::remove() {
2396 static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.remove(this);
2397 SceneActor::remove();
2398 }
2399
process(Event & event)2400 void ScannerDialog::Slider::process(Event &event) {
2401 if (event.eventType == EVENT_BUTTON_DOWN && R2_GLOBALS._events.getCursor() == CURSOR_USE
2402 && _bounds.contains(event.mousePos)) {
2403 _sliderDown = true;
2404 }
2405
2406 if (event.eventType == EVENT_BUTTON_UP && _sliderDown) {
2407 _sliderDown = false;
2408 event.handled = true;
2409 update();
2410 }
2411
2412 if (_sliderDown) {
2413 event.handled = true;
2414 if (event.mousePos.x < _xStart) {
2415 setPosition(Common::Point(_xStart, _yp));
2416 } else if (event.mousePos.x >= (_xStart + _width)) {
2417 setPosition(Common::Point(_xStart + _width, _yp));
2418 } else {
2419 setPosition(Common::Point(event.mousePos.x, _yp));
2420 }
2421 }
2422 }
2423
startAction(CursorType action,Event & event)2424 bool ScannerDialog::Slider::startAction(CursorType action, Event &event) {
2425 if (action == CURSOR_USE)
2426 return false;
2427
2428 return startAction(action, event);
2429 }
2430
update()2431 void ScannerDialog::Slider::update() {
2432 int incHalf = (_width / (_xInc - 1)) / 2;
2433 int newFrequency = ((_position.x - _xStart + incHalf) * _xInc) / (_width + incHalf * 2);
2434 setPosition(Common::Point(_xStart + ((_width * newFrequency) / (_xInc - 1)), _yp));
2435
2436 R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex] = newFrequency + 1;
2437
2438 switch (newFrequency) {
2439 case 0:
2440 R2_GLOBALS._sound4.stop();
2441 break;
2442 case 1:
2443 R2_GLOBALS._sound4.play(45);
2444 break;
2445 case 2:
2446 R2_GLOBALS._sound4.play(4);
2447 break;
2448 case 3:
2449 R2_GLOBALS._sound4.play(5);
2450 break;
2451 case 4:
2452 R2_GLOBALS._sound4.play(6);
2453 break;
2454 default:
2455 break;
2456 }
2457 }
2458
setup(int initial,int xStart,int yp,int width,int xInc)2459 void ScannerDialog::Slider::setup(int initial, int xStart, int yp, int width, int xInc) {
2460 _initial = initial;
2461 _xStart = xStart;
2462 _yp = yp;
2463 _width = width;
2464 _xInc = xInc;
2465 _sliderDown = false;
2466 SceneActor::postInit();
2467 SceneObject::setup(4, 2, 1);
2468 fixPriority(255);
2469 setPosition(Common::Point(_width * (_initial - 1) / (_xInc - 1) + _xStart, yp));
2470
2471 static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this);
2472 }
2473
2474 /*--------------------------------------------------------------------------*/
2475
ScannerDialog()2476 ScannerDialog::ScannerDialog() {
2477 }
2478
remove()2479 void ScannerDialog::remove() {
2480 switch (R2_GLOBALS._sceneManager._sceneNumber) {
2481 case 1550:
2482 case 1700:
2483 R2_GLOBALS._events.setCursor(R2_GLOBALS._player._canWalk ? CURSOR_WALK : CURSOR_USE);
2484 break;
2485 case 3800:
2486 case 3900: {
2487 Scene *scene = R2_GLOBALS._sceneManager._scene;
2488 scene->_sceneMode = 3806;
2489 scene->signal();
2490 break;
2491 }
2492 default:
2493 break;
2494 }
2495
2496 SceneExt *scene = static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene);
2497 scene->_sceneAreas.remove(&_talkButton);
2498 scene->_sceneAreas.remove(&_scanButton);
2499 _talkButton.remove();
2500 _scanButton.remove();
2501 _slider.remove();
2502 _obj4.remove();
2503 _obj5.remove();
2504 _obj6.remove();
2505 _obj7.remove();
2506
2507 ModalWindow::remove();
2508 }
2509
setup2(int visage,int stripFrameNum,int frameNum,int posX,int posY)2510 void ScannerDialog::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY) {
2511 // Stop player moving if currently doing so
2512 if (R2_GLOBALS._player._mover)
2513 R2_GLOBALS._player.addMover(NULL);
2514
2515 R2_GLOBALS._events.setCursor(CURSOR_USE);
2516 ModalWindow::setup2(visage, stripFrameNum, frameNum, posX, posY);
2517
2518 setup3(100, -1, -1, -1);
2519 _talkButton.setup(1);
2520 _scanButton.setup(2);
2521 _slider.setup(R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex], 142, 124, 35, 5);
2522
2523 _obj4.postInit();
2524 _obj4.setup(4, 3, 2);
2525 _obj4.setPosition(Common::Point(160, 83));
2526 _obj4.fixPriority(256);
2527
2528 if (R2_GLOBALS._sceneManager._sceneNumber == 3800 || R2_GLOBALS._sceneManager._sceneNumber == 3900) {
2529 Scene *scene = R2_GLOBALS._sceneManager._scene;
2530 scene->_sceneMode = 3805;
2531 scene->signal();
2532 }
2533 }
2534
2535 /*--------------------------------------------------------------------------*/
2536
2537 } // End of namespace Ringworld2
2538
2539 } // End of namespace TsAGE
2540