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