mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-04 09:56:30 +00:00
2539 lines
66 KiB
C++
2539 lines
66 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/config-manager.h"
|
|
#include "common/rect.h"
|
|
#include "tsage/graphics.h"
|
|
#include "tsage/scenes.h"
|
|
#include "tsage/tsage.h"
|
|
#include "tsage/staticres.h"
|
|
#include "tsage/ringworld2/ringworld2_logic.h"
|
|
#include "tsage/ringworld2/ringworld2_dialogs.h"
|
|
#include "tsage/ringworld2/ringworld2_scenes0.h"
|
|
#include "tsage/ringworld2/ringworld2_scenes1.h"
|
|
#include "tsage/ringworld2/ringworld2_scenes2.h"
|
|
#include "tsage/ringworld2/ringworld2_scenes3.h"
|
|
#include "tsage/ringworld2/ringworld2_airduct.h"
|
|
#include "tsage/ringworld2/ringworld2_outpost.h"
|
|
#include "tsage/ringworld2/ringworld2_vampire.h"
|
|
|
|
namespace TsAGE {
|
|
|
|
namespace Ringworld2 {
|
|
|
|
Scene *Ringworld2Game::createScene(int sceneNumber) {
|
|
switch (sceneNumber) {
|
|
/* Scene group #0 */
|
|
case 50:
|
|
// Waking up cutscene
|
|
return new Scene50();
|
|
case 100:
|
|
// Quinn's room
|
|
return new Scene100();
|
|
case 125:
|
|
// Computer console
|
|
return new Scene125();
|
|
case 150:
|
|
// Empty Bedroom #1
|
|
return new Scene150();
|
|
case 160:
|
|
// Credits
|
|
return new Scene160();
|
|
case 175:
|
|
// Empty Bedroom #2
|
|
return new Scene175();
|
|
case 180:
|
|
// Title Screen
|
|
return new Scene180();
|
|
case 200:
|
|
// Deck #2 - By Lift
|
|
return new Scene200();
|
|
case 205:
|
|
if (g_vm->getFeatures() & GF_DEMO)
|
|
// End of Demo
|
|
return new Scene205Demo();
|
|
else
|
|
// Star-field Credits
|
|
return new Scene205();
|
|
case 250:
|
|
// Lift
|
|
return new Scene250();
|
|
case 300:
|
|
// Bridge
|
|
return new Scene300();
|
|
case 325:
|
|
// Bridge Console
|
|
return new Scene325();
|
|
case 400:
|
|
// Science Lab
|
|
return new Scene400();
|
|
case 500:
|
|
// Lander Bay 2 Storage
|
|
return new Scene500();
|
|
case 525:
|
|
// Cutscene - Walking in hall
|
|
return new Scene525();
|
|
case 600:
|
|
// Drive Room
|
|
return new Scene600();
|
|
case 700:
|
|
// Lander Bay 2
|
|
return new Scene700();
|
|
case 800:
|
|
// Sick bay
|
|
return new Scene800();
|
|
case 825:
|
|
// Autodoc
|
|
return new Scene825();
|
|
case 850:
|
|
// Deck #5 - By Lift
|
|
return new Scene850();
|
|
case 900:
|
|
// Lander Bay 2 - Crane Controls
|
|
return new Scene900();
|
|
/* Scene group #1 */
|
|
//
|
|
case 1000:
|
|
// Cutscene scene
|
|
return new Scene1000();
|
|
case 1010:
|
|
// Cutscene - trip in space
|
|
return new Scene1010();
|
|
case 1020:
|
|
// Cutscene - trip in space 2
|
|
return new Scene1020();
|
|
case 1100:
|
|
// Canyon
|
|
return new Scene1100();
|
|
case 1200:
|
|
// ARM Base - Air Ducts Maze
|
|
return new Scene1200();
|
|
case 1337:
|
|
case 1330:
|
|
// Card Game
|
|
return new Scene1337();
|
|
case 1500:
|
|
// Cutscene: Ship landing
|
|
return new Scene1500();
|
|
case 1525:
|
|
// Cutscene - Ship
|
|
return new Scene1525();
|
|
case 1530:
|
|
// Cutscene - Crashing on Rimwall
|
|
return new Scene1530();
|
|
case 1550:
|
|
// Spaceport
|
|
return new Scene1550();
|
|
case 1575:
|
|
// Spaceport - unused ship scene
|
|
return new Scene1575();
|
|
case 1580:
|
|
// Inside wreck
|
|
return new Scene1580();
|
|
case 1625:
|
|
// Miranda being questioned
|
|
return new Scene1625();
|
|
case 1700:
|
|
// Rim
|
|
return new Scene1700();
|
|
case 1750:
|
|
// Rim Transport Vechile
|
|
return new Scene1750();
|
|
case 1800:
|
|
// Rim Lift Exterior
|
|
return new Scene1800();
|
|
case 1850:
|
|
// Rim Lift Interior
|
|
return new Scene1850();
|
|
case 1875:
|
|
// Rim Lift Computer
|
|
return new Scene1875();
|
|
case 1900:
|
|
// Spill Mountains Elevator Exit
|
|
return new Scene1900();
|
|
case 1925:
|
|
// Spill Mountains Elevator Shaft
|
|
return new Scene1925();
|
|
case 1945:
|
|
// Spill Mountains Shaft Bottom
|
|
return new Scene1945();
|
|
case 1950:
|
|
// Flup Tube Corridor Maze
|
|
return new Scene1950();
|
|
/* Scene group #2 */
|
|
case 2000:
|
|
// Spill Mountains
|
|
return new Scene2000();
|
|
case 2350:
|
|
// Spill Mountains: Balloon Launch Platform
|
|
return new Scene2350();
|
|
case 2400:
|
|
// Spill Mountains: Unused large empty room
|
|
return new Scene2400();
|
|
case 2425:
|
|
// Spill Mountains: The Hall of Records
|
|
return new Scene2425();
|
|
case 2430:
|
|
// Spill Mountains: Bedroom
|
|
return new Scene2430();
|
|
case 2435:
|
|
// Spill Mountains: Throne room
|
|
return new Scene2435();
|
|
case 2440:
|
|
// Spill Mountains: Another bedroom
|
|
return new Scene2440();
|
|
case 2445:
|
|
// Spill Mountains:
|
|
return new Scene2445();
|
|
case 2450:
|
|
// Spill Mountains: Another bedroom
|
|
return new Scene2450();
|
|
case 2455:
|
|
// Spill Mountains: Inside crevasse
|
|
return new Scene2455();
|
|
case 2500:
|
|
// Spill Mountains: Large Ledge
|
|
return new Scene2500();
|
|
case 2525:
|
|
// Spill Mountains: Furnace room
|
|
return new Scene2525();
|
|
case 2530:
|
|
// Spill Mountains: Well
|
|
return new Scene2530();
|
|
case 2535:
|
|
// Spill Mountains: Tannery
|
|
return new Scene2535();
|
|
case 2600:
|
|
// Spill Mountains: Exit
|
|
return new Scene2600();
|
|
case 2700:
|
|
// Outer Forest
|
|
return new Scene2700();
|
|
case 2750:
|
|
// Inner Forest
|
|
return new Scene2750();
|
|
case 2800:
|
|
// Guard post
|
|
return new Scene2800();
|
|
case 2900:
|
|
// Balloon Cutscene
|
|
return new Scene2900();
|
|
|
|
/* Scene group #3 */
|
|
// ARM Base Hanager
|
|
case 3100:
|
|
return new Scene3100();
|
|
case 3125:
|
|
// Ghouls dormitory
|
|
return new Scene3125();
|
|
case 3150:
|
|
// Jail
|
|
return new Scene3150();
|
|
case 3175:
|
|
// Autopsy room
|
|
return new Scene3175();
|
|
case 3200:
|
|
// Cutscene : Guards - Discussion
|
|
return new Scene3200();
|
|
case 3210:
|
|
// Cutscene : Captain and Private - Discussion
|
|
return new Scene3210();
|
|
case 3220:
|
|
// Cutscene : Guards in cargo zone
|
|
return new Scene3220();
|
|
case 3230:
|
|
// Cutscene : Guards on duty
|
|
return new Scene3230();
|
|
case 3240:
|
|
// Cutscene : Teal monolog
|
|
return new Scene3240();
|
|
case 3245:
|
|
// Cutscene : Discussions with Dr. Tomko
|
|
return new Scene3245();
|
|
case 3250:
|
|
// Room with large stasis field negator
|
|
return new Scene3250();
|
|
case 3255:
|
|
// Guard Post
|
|
return new Scene3255();
|
|
case 3260:
|
|
// ARM Base - Computer room
|
|
return new Scene3260();
|
|
case 3275:
|
|
// ARM Base - Hall
|
|
return new Scene3275();
|
|
case 3350:
|
|
// Cutscene - Ship landing
|
|
return new Scene3350();
|
|
case 3375:
|
|
// Circular Walkway
|
|
return new Scene3375();
|
|
case 3385:
|
|
// Corridor
|
|
return new Scene3385();
|
|
case 3395:
|
|
// Walkway
|
|
return new Scene3395();
|
|
case 3400:
|
|
// Confrontation
|
|
return new Scene3400();
|
|
case 3500:
|
|
// Flub tube maze
|
|
return new Scene3500();
|
|
case 3600:
|
|
// Cutscene - walking at gunpoint
|
|
return new Scene3600();
|
|
case 3700:
|
|
// Cutscene - Teleport outside
|
|
return new Scene3700();
|
|
case 3800:
|
|
// Desert
|
|
return new Scene3800();
|
|
case 3900:
|
|
// Forest Entrance
|
|
return new Scene3900();
|
|
default:
|
|
error("Unknown scene number - %d", sceneNumber);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if it is currently okay to restore a game
|
|
*/
|
|
bool Ringworld2Game::canLoadGameStateCurrently() {
|
|
// Don't allow a game to be loaded if a dialog is active
|
|
return g_globals->_gfxManagers.size() == 1;
|
|
}
|
|
|
|
/**
|
|
* Returns true if it is currently okay to save the game
|
|
*/
|
|
bool Ringworld2Game::canSaveGameStateCurrently() {
|
|
// Don't allow a game to be saved if a dialog is active, or if an animation
|
|
// is playing, or if an active scene prevents it
|
|
return g_globals->_gfxManagers.size() == 1 && R2_GLOBALS._animationCtr == 0 &&
|
|
(!R2_GLOBALS._sceneManager._scene ||
|
|
!((SceneExt *)R2_GLOBALS._sceneManager._scene)->_preventSaving);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
SceneExt::SceneExt(): Scene() {
|
|
_stripManager._onBegin = SceneExt::startStrip;
|
|
_stripManager._onEnd = SceneExt::endStrip;
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
_shadowPaletteMap[i] = 0;
|
|
|
|
_savedPlayerEnabled = false;
|
|
_savedUiEnabled = false;
|
|
_savedCanWalk = false;
|
|
_preventSaving = false;
|
|
|
|
// Reset screen clipping area
|
|
R2_GLOBALS._screen._clipRect = Rect();
|
|
|
|
// WORKAROUND: In the original, playing animations don't reset the global _animationCtr
|
|
// counter as scene changes unless the playing animation explicitly finishes. For now,
|
|
// to make inter-scene debugging easier, I'm explicitly resetting the _animationCtr
|
|
// on scene start, since scene objects aren't drawn while it's non-zero
|
|
R2_GLOBALS._animationCtr = 0;
|
|
|
|
// WORKAROUND: We had a case where at some point the number of modal dialogs
|
|
// open became incorrect. So reset it on scene changes to fix the problem if
|
|
// it ever happens
|
|
R2_GLOBALS._insetUp = 0;
|
|
}
|
|
|
|
void SceneExt::synchronize(Serializer &s) {
|
|
Scene::synchronize(s);
|
|
|
|
s.syncBytes(&_shadowPaletteMap[0], 256);
|
|
_sceneAreas.synchronize(s);
|
|
}
|
|
|
|
void SceneExt::postInit(SceneObjectList *OwnerList) {
|
|
Scene::postInit(OwnerList);
|
|
|
|
// Exclude the bottom area of the screen to allow room for the UI
|
|
T2_GLOBALS._interfaceY = UI_INTERFACE_Y;
|
|
|
|
// Initialize fields
|
|
_action = NULL;
|
|
_sceneMode = 0;
|
|
|
|
static_cast<SceneHandlerExt *>(R2_GLOBALS._sceneHandler)->setupPaletteMaps();
|
|
|
|
int prevScene = R2_GLOBALS._sceneManager._previousScene;
|
|
int sceneNumber = R2_GLOBALS._sceneManager._sceneNumber;
|
|
if (g_vm->getFeatures() & GF_DEMO) {
|
|
if (prevScene == 0 && sceneNumber == 180) {
|
|
// Very start of the demo, title & intro about to be shown
|
|
R2_GLOBALS._uiElements._active = false;
|
|
R2_GLOBALS._uiElements.hide();
|
|
} else if (((prevScene == -1) && (sceneNumber != 180) && (sceneNumber != 205) && (sceneNumber != 50))
|
|
|| (prevScene == 0) || (sceneNumber == 600)
|
|
|| ((prevScene == 205 || prevScene == 180 || prevScene == 50) && (sceneNumber == 100))) {
|
|
R2_GLOBALS._uiElements._active = true;
|
|
R2_GLOBALS._uiElements.show();
|
|
} else {
|
|
R2_GLOBALS._uiElements.updateInventory();
|
|
}
|
|
} else if (((prevScene == -1) && (sceneNumber != 180) && (sceneNumber != 205) && (sceneNumber != 50))
|
|
|| (sceneNumber == 50)
|
|
|| ((sceneNumber == 100) && (prevScene == 0 || prevScene == 180 || prevScene == 205))) {
|
|
R2_GLOBALS._uiElements._active = true;
|
|
R2_GLOBALS._uiElements.show();
|
|
} else {
|
|
R2_GLOBALS._uiElements.updateInventory();
|
|
}
|
|
}
|
|
|
|
void SceneExt::remove() {
|
|
_sceneAreas.clear();
|
|
Scene::remove();
|
|
R2_GLOBALS._uiElements._active = true;
|
|
|
|
if (R2_GLOBALS._events.getCursor() >= EXITCURSOR_N &&
|
|
R2_GLOBALS._events.getCursor() <= SHADECURSOR_DOWN)
|
|
R2_GLOBALS._events.setCursor(CURSOR_WALK);
|
|
}
|
|
|
|
void SceneExt::process(Event &event) {
|
|
if (!event.handled)
|
|
Scene::process(event);
|
|
}
|
|
|
|
void SceneExt::dispatch() {
|
|
Scene::dispatch();
|
|
}
|
|
|
|
bool SceneExt::display(CursorType action, Event &event) {
|
|
switch (action) {
|
|
case CURSOR_CROSSHAIRS:
|
|
case CURSOR_WALK:
|
|
return false;
|
|
case CURSOR_LOOK:
|
|
SceneItem::display2(1, R2_GLOBALS._randomSource.getRandomNumber(4));
|
|
break;
|
|
case CURSOR_USE:
|
|
SceneItem::display2(1, R2_GLOBALS._randomSource.getRandomNumber(4) + 5);
|
|
break;
|
|
case CURSOR_TALK:
|
|
SceneItem::display2(1, R2_GLOBALS._randomSource.getRandomNumber(4) + 10);
|
|
break;
|
|
case R2_NEGATOR_GUN:
|
|
if (R2_GLOBALS.getFlag(1))
|
|
SceneItem::display2(2, action);
|
|
else
|
|
SceneItem::display2(5, 0);
|
|
break;
|
|
case R2_SONIC_STUNNER:
|
|
if ((R2_GLOBALS._scannerFrequencies[R2_QUINN] == 2)
|
|
|| ((R2_GLOBALS._scannerFrequencies[R2_QUINN] == 1) &&
|
|
(R2_GLOBALS._scannerFrequencies[R2_SEEKER] == 2) &&
|
|
(R2_GLOBALS._sceneManager._previousScene == 300))) {
|
|
R2_GLOBALS._sound4.stop();
|
|
R2_GLOBALS._sound3.play(46);
|
|
SceneItem::display2(5, 15);
|
|
|
|
R2_GLOBALS._sound4.play(45);
|
|
} else {
|
|
R2_GLOBALS._sound3.play(43, 0);
|
|
SceneItem::display2(2, R2_SONIC_STUNNER);
|
|
}
|
|
break;
|
|
case R2_COM_SCANNER:
|
|
case R2_COM_SCANNER_2:
|
|
R2_GLOBALS._sound3.play(44);
|
|
SceneItem::display2(2, action);
|
|
R2_GLOBALS._sound3.stop();
|
|
break;
|
|
case R2_PHOTON_STUNNER:
|
|
R2_GLOBALS._sound3.play(99);
|
|
SceneItem::display2(2, action);
|
|
break;
|
|
default:
|
|
SceneItem::display2(2, action);
|
|
break;
|
|
}
|
|
|
|
event.handled = true;
|
|
return true;
|
|
}
|
|
|
|
void SceneExt::fadeOut() {
|
|
uint32 black = 0;
|
|
R2_GLOBALS._scenePalette.fade((const byte *)&black, false, 100);
|
|
}
|
|
|
|
void SceneExt::startStrip() {
|
|
SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene;
|
|
scene->_savedPlayerEnabled = R2_GLOBALS._player._enabled;
|
|
|
|
if (scene->_savedPlayerEnabled) {
|
|
scene->_savedUiEnabled = R2_GLOBALS._player._uiEnabled;
|
|
scene->_savedCanWalk = R2_GLOBALS._player._canWalk;
|
|
R2_GLOBALS._player.disableControl();
|
|
/*
|
|
if (!R2_GLOBALS._v50696 && R2_GLOBALS._uiElements._active)
|
|
R2_GLOBALS._uiElements.hide();
|
|
*/
|
|
}
|
|
}
|
|
|
|
void SceneExt::endStrip() {
|
|
SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene;
|
|
|
|
if (scene->_savedPlayerEnabled) {
|
|
R2_GLOBALS._player.enableControl();
|
|
R2_GLOBALS._player._uiEnabled = scene->_savedUiEnabled;
|
|
R2_GLOBALS._player._canWalk = scene->_savedCanWalk;
|
|
/*
|
|
if (!R2_GLOBALS._v50696 && R2_GLOBALS._uiElements._active)
|
|
R2_GLOBALS._uiElements.show();
|
|
*/
|
|
}
|
|
}
|
|
|
|
void SceneExt::clearScreen() {
|
|
R2_GLOBALS._screen.fillRect(R2_GLOBALS._screen.getBounds(), 0);
|
|
}
|
|
|
|
void SceneExt::refreshBackground(int xAmount, int yAmount) {
|
|
switch (_activeScreenNumber) {
|
|
case 700:
|
|
case 1020:
|
|
case 1100:
|
|
case 1700:
|
|
case 2600:
|
|
case 2950:
|
|
case 3100:
|
|
case 3101:
|
|
case 3275:
|
|
case 3600:
|
|
// Use traditional style sectioned screen loading
|
|
Scene::refreshBackground(xAmount, yAmount);
|
|
return;
|
|
default:
|
|
// Break out to new style screen loading
|
|
break;
|
|
}
|
|
|
|
/* New style background loading */
|
|
|
|
// Get the screen data
|
|
byte *dataP = g_resourceManager->getResource(RT18, _activeScreenNumber, 0);
|
|
int screenSize = g_vm->_memoryManager.getSize(dataP);
|
|
|
|
// Lock the background for update
|
|
assert(screenSize == (_backSurface.w * _backSurface.h));
|
|
Graphics::Surface s = _backSurface.getSubArea(Common::Rect(0, 0, _backSurface.w, _backSurface.h));
|
|
|
|
// Copy the data into the surface
|
|
byte *destP = (byte *)s.getPixels();
|
|
Common::copy(dataP, dataP + (s.w * s.h), destP);
|
|
|
|
// Free the resource data
|
|
DEALLOCATE(dataP);
|
|
}
|
|
|
|
/**
|
|
* Saves the current player position and view in the details for the specified character index
|
|
*/
|
|
void SceneExt::saveCharacter(int characterIndex) {
|
|
R2_GLOBALS._player._characterPos[characterIndex] = R2_GLOBALS._player._position;
|
|
R2_GLOBALS._player._characterStrip[characterIndex] = R2_GLOBALS._player._strip;
|
|
R2_GLOBALS._player._characterFrame[characterIndex] = R2_GLOBALS._player._frame;
|
|
}
|
|
|
|
void SceneExt::scalePalette(int RFactor, int GFactor, int BFactor) {
|
|
byte *tmpPal = R2_GLOBALS._scenePalette._palette;
|
|
byte newR, newG, newB;
|
|
int tmp, varD = 0;
|
|
|
|
for (int i = 0; i < 256; i++) {
|
|
newR = (RFactor * tmpPal[(3 * i)]) / 100;
|
|
newG = (GFactor * tmpPal[(3 * i) + 1]) / 100;
|
|
newB = (BFactor * tmpPal[(3 * i) + 2]) / 100;
|
|
|
|
int varC = 769;
|
|
for (int j = 255; j >= 0; j--) {
|
|
tmp = abs(tmpPal[(3 * j)] - newR);
|
|
if (tmp >= varC)
|
|
continue;
|
|
|
|
tmp += abs(tmpPal[(3 * j) + 1] - newG);
|
|
if (tmp >= varC)
|
|
continue;
|
|
|
|
tmp += abs(tmpPal[(3 * j) + 2] - newB);
|
|
if (tmp >= varC)
|
|
continue;
|
|
|
|
varC = tmp;
|
|
varD = j;
|
|
}
|
|
this->_shadowPaletteMap[i] = varD;
|
|
}
|
|
}
|
|
|
|
void SceneExt::loadBlankScene() {
|
|
_backSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT * 3 / 2);
|
|
_backSurface.fillRect(_backSurface.getBounds(), 0);
|
|
|
|
R2_GLOBALS._screen.fillRect(R2_GLOBALS._screen.getBounds(), 0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void SceneHandlerExt::postInit(SceneObjectList *OwnerList) {
|
|
SceneHandler::postInit(OwnerList);
|
|
|
|
if (!R2_GLOBALS._playStream.setFile("SND4K.RES"))
|
|
warning("Could not find SND4K.RES voice file");
|
|
}
|
|
|
|
void SceneHandlerExt::process(Event &event) {
|
|
if (T2_GLOBALS._uiElements._active && R2_GLOBALS._player._uiEnabled) {
|
|
T2_GLOBALS._uiElements.process(event);
|
|
if (event.handled)
|
|
return;
|
|
}
|
|
|
|
SceneExt *scene = static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene);
|
|
if (scene && R2_GLOBALS._player._uiEnabled) {
|
|
// Handle any scene areas that have been registered
|
|
SynchronizedList<EventHandler *>::iterator saIter;
|
|
for (saIter = scene->_sceneAreas.begin(); saIter != scene->_sceneAreas.end() && !event.handled; ++saIter) {
|
|
(*saIter)->process(event);
|
|
}
|
|
}
|
|
|
|
if (!event.handled)
|
|
SceneHandler::process(event);
|
|
}
|
|
|
|
void SceneHandlerExt::dispatch() {
|
|
R2_GLOBALS._playStream.dispatch();
|
|
SceneHandler::dispatch();
|
|
}
|
|
|
|
void SceneHandlerExt::postLoad(int priorSceneBeforeLoad, int currentSceneBeforeLoad) {
|
|
// Set up the shading maps used for showing the player in shadows
|
|
setupPaletteMaps();
|
|
|
|
if (currentSceneBeforeLoad == 2900) {
|
|
R2_GLOBALS._gfxFontNumber = 50;
|
|
R2_GLOBALS._gfxColors.background = 0;
|
|
R2_GLOBALS._gfxColors.foreground = 59;
|
|
R2_GLOBALS._fontColors.background = 4;
|
|
R2_GLOBALS._fontColors.foreground = 15;
|
|
R2_GLOBALS._frameEdgeColor = 2;
|
|
|
|
R2_GLOBALS._scenePalette.loadPalette(0);
|
|
R2_GLOBALS._scenePalette.setEntry(255, 0xff, 0xff, 0xff);
|
|
R2_GLOBALS._fadePaletteFlag = false;
|
|
setupPaletteMaps();
|
|
}
|
|
}
|
|
|
|
void SceneHandlerExt::setupPaletteMaps() {
|
|
byte *palP = &R2_GLOBALS._scenePalette._palette[0];
|
|
|
|
// Set up the mapping table for giving faded versions of pixels at different fade percentages
|
|
if (!R2_GLOBALS._fadePaletteFlag) {
|
|
R2_GLOBALS._fadePaletteFlag = true;
|
|
|
|
for (int idx = 0; idx < 10; ++idx) {
|
|
for (int palIndex = 0; palIndex < 224; ++palIndex) {
|
|
int r, g, b;
|
|
|
|
// Get adjusted RGB values
|
|
switch (idx) {
|
|
case 7:
|
|
r = palP[palIndex * 3] * 85 / 100;
|
|
g = palP[palIndex * 3 + 1] * 7 / 10;
|
|
b = palP[palIndex * 3 + 2] * 7 / 10;
|
|
break;
|
|
case 8:
|
|
r = palP[palIndex * 3] * 7 / 10;
|
|
g = palP[palIndex * 3 + 1] * 85 / 100;
|
|
b = palP[palIndex * 3 + 2] * 7 / 10;
|
|
break;
|
|
case 9:
|
|
r = palP[palIndex * 3] * 8 / 10;
|
|
g = palP[palIndex * 3 + 1] * 5 / 10;
|
|
b = palP[palIndex * 3 + 2] * 9 / 10;
|
|
break;
|
|
default:
|
|
r = palP[palIndex * 3] * (10 - idx) / 10;
|
|
g = palP[palIndex * 3 + 1] * (10 - idx) / 12;
|
|
b = palP[palIndex * 3 + 2] * (10 - idx) / 10;
|
|
break;
|
|
}
|
|
|
|
// Scan for the palette index with the closest matching color
|
|
int threshold = 769;
|
|
int foundIndex = -1;
|
|
for (int pIndex2 = 223; pIndex2 >= 0; --pIndex2) {
|
|
int diffSum = ABS(palP[pIndex2 * 3] - r);
|
|
if (diffSum >= threshold)
|
|
continue;
|
|
|
|
diffSum += ABS(palP[pIndex2 * 3 + 1] - g);
|
|
if (diffSum >= threshold)
|
|
continue;
|
|
|
|
diffSum += ABS(palP[pIndex2 * 3 + 2] - b);
|
|
if (diffSum >= threshold)
|
|
continue;
|
|
|
|
threshold = diffSum;
|
|
foundIndex = pIndex2;
|
|
}
|
|
|
|
R2_GLOBALS._fadePaletteMap[idx][palIndex] = foundIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int palIndex = 0; palIndex < 224; ++palIndex) {
|
|
int r = palP[palIndex * 3] >> 4;
|
|
int g = palP[palIndex * 3 + 1] >> 4;
|
|
int b = palP[palIndex * 3 + 2] >> 4;
|
|
|
|
int v = (r << 8) | (g << 4) | b;
|
|
assert(v < 0x1000);
|
|
R2_GLOBALS._paletteMap[v] = palIndex;
|
|
}
|
|
|
|
int vdx = 0;
|
|
int idx = 0;
|
|
int palIndex = 224;
|
|
|
|
for (int vIndex = 0; vIndex < 4096; ++vIndex) {
|
|
int v = R2_GLOBALS._paletteMap[vIndex];
|
|
if (!v) {
|
|
R2_GLOBALS._paletteMap[vIndex] = idx;
|
|
} else {
|
|
idx = v;
|
|
}
|
|
|
|
if (!palIndex) {
|
|
vdx = palIndex;
|
|
} else {
|
|
int idxTemp = palIndex;
|
|
palIndex = (palIndex + vdx) / 2;
|
|
vdx = idxTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
DisplayHotspot::DisplayHotspot(int regionId, ...) {
|
|
_sceneRegionId = regionId;
|
|
|
|
// Load up the actions
|
|
va_list va;
|
|
va_start(va, regionId);
|
|
|
|
int param = va_arg(va, int);
|
|
while (param != LIST_END) {
|
|
_actions.push_back(param);
|
|
param = va_arg(va, int);
|
|
}
|
|
|
|
va_end(va);
|
|
}
|
|
|
|
bool DisplayHotspot::performAction(int action) {
|
|
for (uint i = 0; i < _actions.size(); i += 3) {
|
|
if (_actions[i] == action) {
|
|
display(_actions[i + 1], _actions[i + 2], SET_WIDTH, 200, SET_EXT_BGCOLOR, 7, LIST_END);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
DisplayObject::DisplayObject(int firstAction, ...) {
|
|
// Load up the actions
|
|
va_list va;
|
|
va_start(va, firstAction);
|
|
|
|
int param = firstAction;
|
|
while (param != LIST_END) {
|
|
_actions.push_back(param);
|
|
param = va_arg(va, int);
|
|
}
|
|
|
|
va_end(va);
|
|
}
|
|
|
|
bool DisplayObject::performAction(int action) {
|
|
for (uint i = 0; i < _actions.size(); i += 3) {
|
|
if (_actions[i] == action) {
|
|
display(_actions[i + 1], _actions[i + 2], SET_WIDTH, 200, SET_EXT_BGCOLOR, 7, LIST_END);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
Ringworld2InvObjectList::Ringworld2InvObjectList():
|
|
_none(1, 1),
|
|
_optoDisk(1, 2),
|
|
_reader(1, 3),
|
|
_negatorGun(1, 4),
|
|
_steppingDisks(1, 5),
|
|
_attractorUnit(1, 6),
|
|
_sensorProbe(1, 7),
|
|
_sonicStunner(1, 8),
|
|
_cableHarness(1, 9),
|
|
_comScanner(1, 10),
|
|
_spentPowerCapsule(1, 11), // 10
|
|
_chargedPowerCapsule(1, 12),
|
|
_aerosol(1, 13),
|
|
_remoteControl(1, 14),
|
|
_opticalFiber(1, 15),
|
|
_clamp(1, 16),
|
|
_attractorHarness(1, 17),
|
|
_fuelCell(2, 2),
|
|
_gyroscope(2, 3),
|
|
_airbag(2, 4),
|
|
_rebreatherTank(2, 5), // 20
|
|
_reserveTank(2, 5),
|
|
_guidanceModule(2, 6),
|
|
_thrusterValve(2, 7),
|
|
_balloonBackpack(2, 8),
|
|
_radarMechanism(2, 9),
|
|
_joystick(2, 10),
|
|
_ignitor(2, 11),
|
|
_diagnosticsDisplay(2, 12),
|
|
_glassDome(2, 13),
|
|
_wickLamp(2, 14), // 30
|
|
_scrithKey(2, 15),
|
|
_tannerMask(2, 16),
|
|
_pureGrainAlcohol(3, 2),
|
|
_blueSapphire(3, 3),
|
|
_ancientScrolls(3, 4),
|
|
_flute(3, 5),
|
|
_gunpowder(3, 6),
|
|
_unused(3, 7),
|
|
_comScanner2(1, 10),
|
|
_superconductorWire(3, 8), // 40
|
|
_pillow(3, 9),
|
|
_foodTray(3, 10),
|
|
_laserHacksaw(3, 11),
|
|
_photonStunner(3, 12),
|
|
_battery(3, 13),
|
|
_soakedFaceMask(2, 17),
|
|
_lightBulb(3, 14),
|
|
_alcoholLamp1(2, 14),
|
|
_alcoholLamp2(3, 15),
|
|
_alocholLamp3(3, 15), // 50
|
|
_brokenDisplay(3, 17),
|
|
_toolbox(4, 2) {
|
|
|
|
// Add the items to the list
|
|
_itemList.push_back(&_none);
|
|
_itemList.push_back(&_optoDisk);
|
|
_itemList.push_back(&_reader);
|
|
_itemList.push_back(&_negatorGun);
|
|
_itemList.push_back(&_steppingDisks);
|
|
_itemList.push_back(&_attractorUnit);
|
|
_itemList.push_back(&_sensorProbe);
|
|
_itemList.push_back(&_sonicStunner);
|
|
_itemList.push_back(&_cableHarness);
|
|
_itemList.push_back(&_comScanner);
|
|
_itemList.push_back(&_spentPowerCapsule); // 10
|
|
_itemList.push_back(&_chargedPowerCapsule);
|
|
_itemList.push_back(&_aerosol);
|
|
_itemList.push_back(&_remoteControl);
|
|
_itemList.push_back(&_opticalFiber);
|
|
_itemList.push_back(&_clamp);
|
|
_itemList.push_back(&_attractorHarness);
|
|
_itemList.push_back(&_fuelCell);
|
|
_itemList.push_back(&_gyroscope);
|
|
_itemList.push_back(&_airbag);
|
|
_itemList.push_back(&_rebreatherTank); // 20
|
|
_itemList.push_back(&_reserveTank);
|
|
_itemList.push_back(&_guidanceModule);
|
|
_itemList.push_back(&_thrusterValve);
|
|
_itemList.push_back(&_balloonBackpack);
|
|
_itemList.push_back(&_radarMechanism);
|
|
_itemList.push_back(&_joystick);
|
|
_itemList.push_back(&_ignitor);
|
|
_itemList.push_back(&_diagnosticsDisplay);
|
|
_itemList.push_back(&_glassDome);
|
|
_itemList.push_back(&_wickLamp); // 30
|
|
_itemList.push_back(&_scrithKey);
|
|
_itemList.push_back(&_tannerMask);
|
|
_itemList.push_back(&_pureGrainAlcohol);
|
|
_itemList.push_back(&_blueSapphire);
|
|
_itemList.push_back(&_ancientScrolls);
|
|
_itemList.push_back(&_flute);
|
|
_itemList.push_back(&_gunpowder);
|
|
_itemList.push_back(&_unused);
|
|
_itemList.push_back(&_comScanner2);
|
|
_itemList.push_back(&_superconductorWire); // 40
|
|
_itemList.push_back(&_pillow);
|
|
_itemList.push_back(&_foodTray);
|
|
_itemList.push_back(&_laserHacksaw);
|
|
_itemList.push_back(&_photonStunner);
|
|
_itemList.push_back(&_battery);
|
|
_itemList.push_back(&_soakedFaceMask);
|
|
_itemList.push_back(&_lightBulb);
|
|
_itemList.push_back(&_alcoholLamp1);
|
|
_itemList.push_back(&_alcoholLamp2);
|
|
_itemList.push_back(&_alocholLamp3); // 50
|
|
_itemList.push_back(&_brokenDisplay);
|
|
_itemList.push_back(&_toolbox);
|
|
|
|
_selectedItem = NULL;
|
|
}
|
|
|
|
void Ringworld2InvObjectList::reset() {
|
|
// Reset all object scene numbers
|
|
SynchronizedList<InvObject *>::iterator i;
|
|
for (i = _itemList.begin(); i != _itemList.end(); ++i) {
|
|
(*i)->_sceneNumber = 0;
|
|
}
|
|
|
|
// Set up default inventory
|
|
setObjectScene(R2_OPTO_DISK, 800);
|
|
setObjectScene(R2_READER, 400);
|
|
setObjectScene(R2_NEGATOR_GUN, 100);
|
|
setObjectScene(R2_STEPPING_DISKS, 100);
|
|
setObjectScene(R2_ATTRACTOR_UNIT, 400);
|
|
setObjectScene(R2_SENSOR_PROBE, 400);
|
|
setObjectScene(R2_SONIC_STUNNER, 500);
|
|
setObjectScene(R2_CABLE_HARNESS, 700);
|
|
setObjectScene(R2_COM_SCANNER, 800);
|
|
setObjectScene(R2_SPENT_POWER_CAPSULE, 100);
|
|
setObjectScene(R2_CHARGED_POWER_CAPSULE, 400);
|
|
setObjectScene(R2_AEROSOL, 500);
|
|
setObjectScene(R2_REMOTE_CONTROL, 1550);
|
|
setObjectScene(R2_OPTICAL_FIBER, 850);
|
|
setObjectScene(R2_CLAMP, 850);
|
|
setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 0);
|
|
setObjectScene(R2_FUEL_CELL, 1550);
|
|
setObjectScene(R2_GYROSCOPE, 1550);
|
|
setObjectScene(R2_AIRBAG, 1550);
|
|
setObjectScene(R2_REBREATHER_TANK, 500);
|
|
setObjectScene(R2_RESERVE_REBREATHER_TANK, 500);
|
|
setObjectScene(R2_GUIDANCE_MODULE, 1550);
|
|
setObjectScene(R2_THRUSTER_VALVE, 1580);
|
|
setObjectScene(R2_BALLOON_BACKPACK, 9999);
|
|
setObjectScene(R2_RADAR_MECHANISM, 1550);
|
|
setObjectScene(R2_JOYSTICK, 1550);
|
|
setObjectScene(R2_IGNITOR, 1580);
|
|
setObjectScene(R2_DIAGNOSTICS_DISPLAY, 1550);
|
|
setObjectScene(R2_GLASS_DOME, 2525);
|
|
setObjectScene(R2_WICK_LAMP, 2440);
|
|
setObjectScene(R2_SCRITH_KEY, 2455);
|
|
setObjectScene(R2_TANNER_MASK, 2535);
|
|
setObjectScene(R2_PURE_GRAIN_ALCOHOL, 2530);
|
|
setObjectScene(R2_SAPPHIRE_BLUE, 1950);
|
|
setObjectScene(R2_ANCIENT_SCROLLS, 1950);
|
|
setObjectScene(R2_FLUTE, 9999);
|
|
setObjectScene(R2_GUNPOWDER, 2430);
|
|
setObjectScene(R2_NONAME, 9999);
|
|
setObjectScene(R2_COM_SCANNER_2, 2);
|
|
setObjectScene(R2_SUPERCONDUCTOR_WIRE, 9999);
|
|
setObjectScene(R2_PILLOW, 3150);
|
|
setObjectScene(R2_FOOD_TRAY, 0);
|
|
setObjectScene(R2_LASER_HACKSAW, 3260);
|
|
setObjectScene(R2_PHOTON_STUNNER, 2);
|
|
setObjectScene(R2_BATTERY, 1550);
|
|
setObjectScene(R2_SOAKED_FACEMASK, 0);
|
|
setObjectScene(R2_LIGHT_BULB, 3150);
|
|
setObjectScene(R2_ALCOHOL_LAMP, 2435);
|
|
setObjectScene(R2_ALCOHOL_LAMP_2, 2440);
|
|
setObjectScene(R2_ALCOHOL_LAMP_3, 2435);
|
|
setObjectScene(R2_BROKEN_DISPLAY, 1580);
|
|
setObjectScene(R2_TOOLBOX, 3260);
|
|
|
|
// Set up the select item handler method
|
|
T2_GLOBALS._onSelectItem = SelectItem;
|
|
}
|
|
|
|
void Ringworld2InvObjectList::setObjectScene(int objectNum, int sceneNumber) {
|
|
// Find the appropriate object
|
|
int num = objectNum;
|
|
SynchronizedList<InvObject *>::iterator i = _itemList.begin();
|
|
while (num-- > 0) ++i;
|
|
(*i)->_sceneNumber = sceneNumber;
|
|
|
|
// If the item is the currently active one, default back to the use cursor
|
|
if (R2_GLOBALS._events.getCursor() == objectNum)
|
|
R2_GLOBALS._events.setCursor(CURSOR_USE);
|
|
|
|
// Update the user interface if necessary
|
|
T2_GLOBALS._uiElements.updateInventory(
|
|
(sceneNumber == R2_GLOBALS._player._characterIndex) ? objectNum : 0);
|
|
}
|
|
|
|
/**
|
|
* When an inventory item is selected, in Return to Ringworld two objects can be combined
|
|
*/
|
|
bool Ringworld2InvObjectList::SelectItem(int objectNumber) {
|
|
// If no existing item selected, don't go any further
|
|
int currentItem = R2_GLOBALS._events.getCursor();
|
|
if (currentItem >= 256)
|
|
return false;
|
|
|
|
switch (objectNumber) {
|
|
case R2_NEGATOR_GUN:
|
|
switch (currentItem) {
|
|
case R2_SENSOR_PROBE:
|
|
if (R2_GLOBALS.getFlag(1))
|
|
SceneItem::display2(5, 1);
|
|
else if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) != 100)
|
|
SceneItem::display2(5, 3);
|
|
else {
|
|
R2_GLOBALS._sound3.play(48);
|
|
SceneItem::display2(5, 2);
|
|
R2_INVENTORY.setObjectScene(R2_SPENT_POWER_CAPSULE, 1);
|
|
}
|
|
break;
|
|
case R2_COM_SCANNER:
|
|
R2_GLOBALS._sound3.play(44);
|
|
if (R2_GLOBALS.getFlag(1))
|
|
SceneItem::display2(5, 9);
|
|
else if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) == 100)
|
|
SceneItem::display2(5, 8);
|
|
else
|
|
SceneItem::display2(5, 10);
|
|
|
|
R2_GLOBALS._sound3.stop();
|
|
break;
|
|
case R2_CHARGED_POWER_CAPSULE:
|
|
if (R2_INVENTORY.getObjectScene(R2_SPENT_POWER_CAPSULE) == 1) {
|
|
R2_GLOBALS._sound3.play(49);
|
|
R2_INVENTORY.setObjectScene(R2_CHARGED_POWER_CAPSULE, 100);
|
|
R2_GLOBALS.setFlag(1);
|
|
SceneItem::display2(5, 4);
|
|
} else {
|
|
SceneItem::display2(5, 5);
|
|
}
|
|
break;
|
|
default:
|
|
selectDefault(objectNumber);
|
|
break;
|
|
}
|
|
break;
|
|
case R2_STEPPING_DISKS:
|
|
switch (currentItem) {
|
|
case R2_SENSOR_PROBE:
|
|
if (R2_INVENTORY.getObjectScene(R2_CHARGED_POWER_CAPSULE) == 400) {
|
|
R2_GLOBALS._sound3.play(48);
|
|
SceneItem::display2(5, 6);
|
|
R2_INVENTORY.setObjectScene(R2_CHARGED_POWER_CAPSULE, 1);
|
|
} else {
|
|
SceneItem::display2(5, 7);
|
|
}
|
|
break;
|
|
case R2_COM_SCANNER:
|
|
R2_GLOBALS._sound3.play(44);
|
|
if (R2_INVENTORY.getObjectScene(R2_CHARGED_POWER_CAPSULE) == 400)
|
|
SceneItem::display2(5, 16);
|
|
else
|
|
SceneItem::display2(5, 17);
|
|
R2_GLOBALS._sound3.stop();
|
|
break;
|
|
default:
|
|
selectDefault(objectNumber);
|
|
break;
|
|
}
|
|
break;
|
|
case R2_ATTRACTOR_UNIT:
|
|
case R2_CABLE_HARNESS:
|
|
if (currentItem == R2_CABLE_HARNESS ||
|
|
currentItem == R2_ATTRACTOR_UNIT) {
|
|
R2_INVENTORY.setObjectScene(R2_CABLE_HARNESS, 0);
|
|
R2_INVENTORY.setObjectScene(R2_ATTRACTOR_UNIT, 0);
|
|
R2_INVENTORY.setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 1);
|
|
} else {
|
|
selectDefault(objectNumber);
|
|
}
|
|
break;
|
|
case R2_TANNER_MASK:
|
|
case R2_PURE_GRAIN_ALCOHOL:
|
|
if (currentItem == R2_TANNER_MASK ||
|
|
currentItem == R2_PURE_GRAIN_ALCOHOL) {
|
|
R2_INVENTORY.setObjectScene(R2_TANNER_MASK, 0);
|
|
R2_INVENTORY.setObjectScene(R2_PURE_GRAIN_ALCOHOL, 0);
|
|
R2_INVENTORY.setObjectScene(R2_SOAKED_FACEMASK, R2_SEEKER);
|
|
} else {
|
|
selectDefault(objectNumber);
|
|
}
|
|
break;
|
|
default:
|
|
// Standard item selection
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Ringworld2InvObjectList::selectDefault(int objectNumber) {
|
|
Common::String msg1 = g_resourceManager->getMessage(4, 53);
|
|
Common::String msg2 = g_resourceManager->getMessage(4, R2_GLOBALS._events.getCursor());
|
|
Common::String msg3 = g_resourceManager->getMessage(4, 54);
|
|
Common::String msg4 = g_resourceManager->getMessage(4, objectNumber);
|
|
Common::String line = Common::String::format("%.5s%.5s%.5s%.5s%s %s %s %s.",
|
|
msg1.c_str(), msg2.c_str(), msg3.c_str(), msg4.c_str(),
|
|
msg1.c_str() + 5, msg2.c_str() + 5, msg3.c_str() + 5, msg4.c_str() + 5);
|
|
|
|
SceneItem::display(-1, -1, line.c_str(),
|
|
SET_WIDTH, 280,
|
|
SET_X, 160,
|
|
SET_Y, 20,
|
|
SET_POS_MODE, 1,
|
|
SET_EXT_BGCOLOR, 7,
|
|
LIST_END);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void Ringworld2Game::start() {
|
|
int slot = -1;
|
|
|
|
if (ConfMan.hasKey("save_slot")) {
|
|
slot = ConfMan.getInt("save_slot");
|
|
Common::String file = g_vm->getSaveStateName(slot);
|
|
Common::InSaveFile *in = g_vm->_system->getSavefileManager()->openForLoading(file);
|
|
if (in)
|
|
delete in;
|
|
else
|
|
slot = -1;
|
|
}
|
|
|
|
if (slot >= 0)
|
|
R2_GLOBALS._sceneHandler->_loadGameSlot = slot;
|
|
else {
|
|
// Switch to the first title screen
|
|
R2_GLOBALS._uiElements._active = true;
|
|
R2_GLOBALS._sceneManager.setNewScene(180);
|
|
}
|
|
|
|
g_globals->_events.showCursor();
|
|
}
|
|
|
|
void Ringworld2Game::restartGame() {
|
|
if (MessageDialog::show(Ringworld2::R2_RESTART_MSG, CANCEL_BTN_STRING, YES_MSG) == 1)
|
|
restart();
|
|
}
|
|
|
|
void Ringworld2Game::restart() {
|
|
g_globals->_scenePalette.clearListeners();
|
|
g_globals->_soundHandler.stop();
|
|
|
|
// Reset the globals
|
|
g_globals->reset();
|
|
|
|
// Clear save/load slots
|
|
g_globals->_sceneHandler->_saveGameSlot = -1;
|
|
g_globals->_sceneHandler->_loadGameSlot = -1;
|
|
|
|
// Change to the first game scene
|
|
g_globals->_sceneManager.changeScene(100);
|
|
}
|
|
|
|
void Ringworld2Game::endGame(int resNum, int lineNum) {
|
|
g_globals->_events.setCursor(CURSOR_WALK);
|
|
Common::String msg = g_resourceManager->getMessage(resNum, lineNum);
|
|
bool savesExist = g_saver->savegamesExist();
|
|
|
|
if (!savesExist) {
|
|
// No savegames exist, so prompt the user to restart or quit
|
|
if (MessageDialog::show(msg, QUIT_BTN_STRING, RESTART_BTN_STRING) == 0)
|
|
g_vm->quitGame();
|
|
else
|
|
restart();
|
|
} else {
|
|
// Savegames exist, so prompt for Restore/Restart
|
|
bool breakFlag;
|
|
do {
|
|
if (g_vm->shouldQuit()) {
|
|
breakFlag = true;
|
|
} else if (MessageDialog::show(msg, RESTART_BTN_STRING, RESTORE_BTN_STRING) == 0) {
|
|
restart();
|
|
breakFlag = true;
|
|
} else {
|
|
handleSaveLoad(false, g_globals->_sceneHandler->_loadGameSlot, g_globals->_sceneHandler->_saveName);
|
|
breakFlag = g_globals->_sceneHandler->_loadGameSlot >= 0;
|
|
}
|
|
} while (!breakFlag);
|
|
}
|
|
|
|
g_globals->_events.setCursorFromFlag();
|
|
}
|
|
|
|
void Ringworld2Game::processEvent(Event &event) {
|
|
if (event.eventType == EVENT_KEYPRESS) {
|
|
switch (event.kbd.keycode) {
|
|
case Common::KEYCODE_F1:
|
|
// F1 - Help
|
|
HelpDialog::show();
|
|
break;
|
|
|
|
case Common::KEYCODE_F2:
|
|
// F2 - Sound Options
|
|
SoundDialog::execute();
|
|
break;
|
|
|
|
case Common::KEYCODE_F3:
|
|
// F3 - Quit
|
|
quitGame();
|
|
event.handled = false;
|
|
break;
|
|
|
|
case Common::KEYCODE_F4:
|
|
// F4 - Restart
|
|
restartGame();
|
|
R2_GLOBALS._events.setCursorFromFlag();
|
|
break;
|
|
|
|
case Common::KEYCODE_F5:
|
|
// F5 - Save
|
|
saveGame();
|
|
R2_GLOBALS._events.setCursorFromFlag();
|
|
event.handled = true;
|
|
break;
|
|
|
|
case Common::KEYCODE_F7:
|
|
// F7 - Restore
|
|
restoreGame();
|
|
R2_GLOBALS._events.setCursorFromFlag();
|
|
break;
|
|
|
|
case Common::KEYCODE_F8:
|
|
// F8 - Credits
|
|
if (R2_GLOBALS._sceneManager._sceneNumber != 205)
|
|
R2_GLOBALS._sceneManager.changeScene(205);
|
|
break;
|
|
|
|
case Common::KEYCODE_F10:
|
|
// F10 - Pause
|
|
GfxDialog::setPalette();
|
|
MessageDialog::show(GAME_PAUSED_MSG, OK_BTN_STRING);
|
|
R2_GLOBALS._events.setCursorFromFlag();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Ringworld2Game::rightClick() {
|
|
RightClickDialog *dlg = new RightClickDialog();
|
|
int option = dlg->execute();
|
|
delete dlg;
|
|
|
|
if (option == 0)
|
|
CharacterDialog::show();
|
|
else if (option == 1)
|
|
HelpDialog::show();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
NamedHotspot::NamedHotspot() : SceneHotspot() {
|
|
_resNum = 0;
|
|
_lookLineNum = _useLineNum = _talkLineNum = -1;
|
|
}
|
|
|
|
bool NamedHotspot::startAction(CursorType action, Event &event) {
|
|
switch (action) {
|
|
case CURSOR_WALK:
|
|
// Nothing
|
|
return false;
|
|
case CURSOR_LOOK:
|
|
if (_lookLineNum == -1)
|
|
return SceneHotspot::startAction(action, event);
|
|
|
|
SceneItem::display2(_resNum, _lookLineNum);
|
|
return true;
|
|
case CURSOR_USE:
|
|
if (_useLineNum == -1)
|
|
return SceneHotspot::startAction(action, event);
|
|
|
|
SceneItem::display2(_resNum, _useLineNum);
|
|
return true;
|
|
case CURSOR_TALK:
|
|
if (_talkLineNum == -1)
|
|
return SceneHotspot::startAction(action, event);
|
|
|
|
SceneItem::display2(_resNum, _talkLineNum);
|
|
return true;
|
|
default:
|
|
return SceneHotspot::startAction(action, event);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void SceneActor::postInit(SceneObjectList *OwnerList) {
|
|
_lookLineNum = _talkLineNum = _useLineNum = -1;
|
|
SceneObject::postInit();
|
|
}
|
|
|
|
void SceneActor::remove() {
|
|
R2_GLOBALS._sceneItems.remove(this);
|
|
_shadowMap = NULL;
|
|
_linkedActor = NULL;
|
|
|
|
SceneObject::remove();
|
|
}
|
|
|
|
bool SceneActor::startAction(CursorType action, Event &event) {
|
|
bool handled = true;
|
|
|
|
switch (action) {
|
|
case CURSOR_LOOK:
|
|
if (_lookLineNum == -1)
|
|
handled = false;
|
|
else
|
|
SceneItem::display2(_resNum, _lookLineNum);
|
|
break;
|
|
case CURSOR_USE:
|
|
if (_useLineNum == -1)
|
|
handled = false;
|
|
else
|
|
SceneItem::display2(_resNum, _useLineNum);
|
|
break;
|
|
case CURSOR_TALK:
|
|
if (_talkLineNum == -1)
|
|
handled = false;
|
|
else
|
|
SceneItem::display2(_resNum, _talkLineNum);
|
|
break;
|
|
default:
|
|
handled = false;
|
|
break;
|
|
}
|
|
|
|
if (!handled)
|
|
handled = ((SceneExt *)R2_GLOBALS._sceneManager._scene)->display(action, event);
|
|
return handled;
|
|
}
|
|
|
|
GfxSurface SceneActor::getFrame() {
|
|
GfxSurface frame = SceneObject::getFrame();
|
|
|
|
return frame;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
SceneArea::SceneArea(): SceneItem() {
|
|
_enabled = true;
|
|
_insideArea = false;
|
|
_savedCursorNum = CURSOR_NONE;
|
|
_cursorState = 0;
|
|
_cursorNum = CURSOR_NONE;
|
|
}
|
|
|
|
void SceneArea::synchronize(Serializer &s) {
|
|
EventHandler::synchronize(s);
|
|
|
|
_bounds.synchronize(s);
|
|
s.syncAsSint16LE(_enabled);
|
|
s.syncAsSint16LE(_insideArea);
|
|
s.syncAsSint32LE(_cursorNum);
|
|
s.syncAsSint32LE(_savedCursorNum);
|
|
s.syncAsSint16LE(_cursorState);
|
|
}
|
|
|
|
void SceneArea::remove() {
|
|
static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.remove(this);
|
|
}
|
|
|
|
void SceneArea::process(Event &event) {
|
|
Common::Point mousePos = event.mousePos;
|
|
mousePos.x += R2_GLOBALS._sceneManager._scene->_sceneBounds.left;
|
|
|
|
if (!R2_GLOBALS._insetUp && _enabled && R2_GLOBALS._events.isCursorVisible()) {
|
|
CursorType cursor = R2_GLOBALS._events.getCursor();
|
|
|
|
if (_bounds.contains(mousePos)) {
|
|
// Cursor moving in bounded area
|
|
if (cursor != _cursorNum) {
|
|
_savedCursorNum = cursor;
|
|
_cursorState = 0;
|
|
R2_GLOBALS._events.setCursor(_cursorNum);
|
|
}
|
|
_insideArea = true;
|
|
} else if ((mousePos.y < 171) && _insideArea && (_cursorNum == cursor) &&
|
|
(_savedCursorNum != CURSOR_NONE)) {
|
|
// Cursor moved outside bounded area
|
|
R2_GLOBALS._events.setCursor(_savedCursorNum);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SceneArea::setDetails(const Rect &bounds, CursorType cursor) {
|
|
_bounds = bounds;
|
|
_cursorNum = cursor;
|
|
|
|
static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
SceneExit::SceneExit(): SceneArea() {
|
|
_moving = false;
|
|
_destPos = Common::Point(-1, -1);
|
|
|
|
_sceneNumber = 0;
|
|
}
|
|
|
|
void SceneExit::synchronize(Serializer &s) {
|
|
SceneArea::synchronize(s);
|
|
|
|
s.syncAsSint16LE(_moving);
|
|
s.syncAsSint16LE(_destPos.x);
|
|
s.syncAsSint16LE(_destPos.y);
|
|
}
|
|
|
|
void SceneExit::setDetails(const Rect &bounds, CursorType cursor, int sceneNumber) {
|
|
_sceneNumber = sceneNumber;
|
|
SceneArea::setDetails(bounds, cursor);
|
|
}
|
|
|
|
void SceneExit::changeScene() {
|
|
R2_GLOBALS._sceneManager.setNewScene(_sceneNumber);
|
|
}
|
|
|
|
void SceneExit::process(Event &event) {
|
|
Common::Point mousePos = event.mousePos;
|
|
mousePos.x += R2_GLOBALS._sceneManager._scene->_sceneBounds.left;
|
|
|
|
if (!R2_GLOBALS._insetUp) {
|
|
SceneArea::process(event);
|
|
|
|
if (_enabled && R2_GLOBALS._player._enabled) {
|
|
if (event.eventType == EVENT_BUTTON_DOWN) {
|
|
if (!_bounds.contains(mousePos))
|
|
_moving = false;
|
|
else if (!R2_GLOBALS._player._canWalk) {
|
|
_moving = false;
|
|
changeScene();
|
|
event.handled = true;
|
|
} else {
|
|
Common::Point dest((_destPos.x == -1) ? mousePos.x : _destPos.x,
|
|
(_destPos.y == -1) ? mousePos.y : _destPos.y);
|
|
ADD_PLAYER_MOVER(dest.x, dest.y);
|
|
|
|
_moving = true;
|
|
event.handled = true;
|
|
}
|
|
}
|
|
|
|
if (_moving && (_bounds.contains(R2_GLOBALS._player._position) || (R2_GLOBALS._player._position == _destPos)))
|
|
changeScene();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void SceneAreaObject::remove() {
|
|
R2_GLOBALS._sceneItems.remove(this);
|
|
_object1.remove();
|
|
SceneArea::remove();
|
|
--R2_GLOBALS._insetUp;
|
|
}
|
|
|
|
void SceneAreaObject::process(Event &event) {
|
|
if (_insetCount == R2_GLOBALS._insetUp) {
|
|
CursorType cursor = R2_GLOBALS._events.getCursor();
|
|
|
|
if (_object1._bounds.contains(event.mousePos)) {
|
|
// Cursor moving in bounded area
|
|
if (cursor == _cursorNum) {
|
|
R2_GLOBALS._events.setCursor(_savedCursorNum);
|
|
}
|
|
} else if (event.mousePos.y < 168) {
|
|
if (_cursorNum != cursor) {
|
|
// Cursor moved outside bounded area
|
|
_savedCursorNum = R2_GLOBALS._events.getCursor();
|
|
R2_GLOBALS._events.setCursor(CURSOR_INVALID);
|
|
}
|
|
|
|
if (event.eventType == EVENT_BUTTON_DOWN) {
|
|
event.handled = true;
|
|
R2_GLOBALS._events.setCursor(_savedCursorNum);
|
|
remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SceneAreaObject::setDetails(int visage, int strip, int frameNumber, const Common::Point &pt) {
|
|
_object1.postInit();
|
|
_object1.setup(visage, strip, frameNumber);
|
|
_object1.setPosition(pt);
|
|
_object1.fixPriority(250);
|
|
|
|
_cursorNum = CURSOR_INVALID;
|
|
Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene;
|
|
scene->_sceneAreas.push_front(this);
|
|
|
|
_insetCount = ++R2_GLOBALS._insetUp;
|
|
}
|
|
|
|
void SceneAreaObject::setDetails(int resNum, int lookLineNum, int talkLineNum, int useLineNum) {
|
|
_object1.setDetails(resNum, lookLineNum, talkLineNum, useLineNum,
|
|
2, (SceneItem *)NULL);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
MazeUI::MazeUI() {
|
|
_mapData = NULL;
|
|
_cellsVisible.x = _cellsVisible.y = 0;
|
|
_mapCells.x = _mapCells.y = 0;
|
|
_cellSize.x = _cellSize.y = 0;
|
|
_mapOffset.x = _mapOffset.y = 0;
|
|
_resNum = _cellsResNum = 0;
|
|
_frameCount = _resCount = _mapImagePitch = 0;
|
|
}
|
|
|
|
MazeUI::~MazeUI() {
|
|
DEALLOCATE(_mapData);
|
|
}
|
|
|
|
void MazeUI::synchronize(Serializer &s) {
|
|
SceneObject::synchronize(s);
|
|
|
|
s.syncAsSint16LE(_resNum);
|
|
if (s.isLoading())
|
|
load(_resNum);
|
|
|
|
s.syncAsSint16LE(_mapOffset.x);
|
|
s.syncAsSint16LE(_mapOffset.y);
|
|
|
|
int dummy = 0;
|
|
s.syncAsSint16LE(dummy);
|
|
}
|
|
|
|
void MazeUI::load(int resNum) {
|
|
clear();
|
|
_resNum = resNum;
|
|
|
|
const byte *header = g_resourceManager->getResource(RT17, resNum, 0);
|
|
|
|
_cellsResNum = resNum + 1000;
|
|
_mapCells.x = READ_LE_UINT16(header + 2);
|
|
_mapCells.y = READ_LE_UINT16(header + 4);
|
|
_frameCount = 10;
|
|
_resCount = _frameCount << 3;
|
|
|
|
Visage visage;
|
|
visage.setVisage(_cellsResNum, 1);
|
|
|
|
GfxSurface frame = visage.getFrame(2);
|
|
_cellSize.x = frame.getBounds().width();
|
|
_cellSize.y = frame.getBounds().height();
|
|
|
|
_mapData = g_resourceManager->getResource(RT17, resNum, 1);
|
|
|
|
_mapOffset.y = _mapOffset.x = 0;
|
|
_cellsVisible.x = (_bounds.width() + _cellSize.x - 1) / _cellSize.x;
|
|
_cellsVisible.y = (_bounds.height() + _cellSize.y - 1) / _cellSize.y;
|
|
|
|
_mapImagePitch = (_cellsVisible.x + 1) * _cellSize.x;
|
|
_mapImage.create(_mapImagePitch, _cellSize.y);
|
|
|
|
_mapBounds = Rect(0, 0, _cellSize.x * _mapCells.x, _cellSize.y * _mapCells.y);
|
|
}
|
|
|
|
void MazeUI::clear() {
|
|
if (!_resNum)
|
|
_resNum = 1;
|
|
|
|
if (_mapData)
|
|
DEALLOCATE(_mapData);
|
|
_mapData = NULL;
|
|
|
|
_mapImage.clear();
|
|
}
|
|
|
|
bool MazeUI::setMazePosition(const Common::Point &pt) {
|
|
bool retval = false;
|
|
|
|
_mapOffset = pt;
|
|
|
|
if (_mapOffset.x < _mapBounds.top) {
|
|
_mapOffset.x = _mapBounds.top;
|
|
retval = true;
|
|
}
|
|
|
|
if (_mapOffset.y < _mapBounds.left) {
|
|
_mapOffset.y = _mapBounds.left;
|
|
retval = true;
|
|
}
|
|
|
|
if (_mapOffset.x + _bounds.width() > _mapBounds.right) {
|
|
_mapOffset.x = _mapBounds.right - _bounds.width();
|
|
retval = true;
|
|
}
|
|
|
|
if (_mapOffset.y + _bounds.height() > _mapBounds.bottom) {
|
|
_mapOffset.y = _mapBounds.bottom - _bounds.height();
|
|
retval = true;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
void MazeUI::reposition() {
|
|
}
|
|
|
|
void MazeUI::draw() {
|
|
int yPos = 0;
|
|
int ySize;
|
|
Visage visage;
|
|
|
|
_cellsVisible.y = ((_mapOffset.y % _cellSize.y) + _bounds.height() +
|
|
(_cellSize.y - 1)) / _cellSize.y;
|
|
|
|
// Loop to handle the cell rows of the visible display area one at a time
|
|
for (int yCtr = 0; yCtr <= _cellsVisible.y; ++yCtr, yPos += ySize) {
|
|
int cellY = _mapOffset.y / _cellSize.y + yCtr;
|
|
|
|
// Loop to iterate through the horizontal visible cells to build up
|
|
// an entire cell high horizontal slice of the map, plus one extra cell
|
|
// to allow for partial cell scrolling on-screen on the left/right sides
|
|
for (int xCtr = 0; xCtr <= _cellsVisible.x; ++xCtr) {
|
|
int cellX = _mapOffset.x / _cellSize.x + xCtr;
|
|
|
|
// Get the type of content to display in the cell
|
|
int cell = getCellFromCellXY(Common::Point(cellX, cellY)) - 1;
|
|
if (cell >= 0) {
|
|
int frameNum = (cell % _frameCount) + 1;
|
|
int rlbNum = (cell % _resCount) / _frameCount + 1;
|
|
int resNum = _cellsResNum + (cell / _resCount);
|
|
|
|
visage.setVisage(resNum, rlbNum);
|
|
GfxSurface frame = visage.getFrame(frameNum);
|
|
|
|
_mapImage.copyFrom(frame, xCtr * _cellSize.x, 0);
|
|
} else {
|
|
GfxSurface emptyRect;
|
|
emptyRect.create(_cellSize.x, _cellSize.y);
|
|
|
|
_mapImage.copyFrom(emptyRect, xCtr * _cellSize.x, 0);
|
|
}
|
|
}
|
|
|
|
if (yPos == 0) {
|
|
// First line of the map to be displayed - only the bottom portion of that
|
|
// first cell row may be visible
|
|
yPos = _bounds.top;
|
|
ySize = _cellSize.y - (_mapOffset.y % _cellSize.y);
|
|
|
|
Rect srcBounds(_mapOffset.x % _cellSize.x, _mapOffset.y % _cellSize.y,
|
|
(_mapOffset.x % _cellSize.x) + _bounds.width(), _cellSize.y);
|
|
Rect destBounds(_bounds.left, yPos, _bounds.right, yPos + ySize);
|
|
|
|
R2_GLOBALS.gfxManager().copyFrom(_mapImage, srcBounds, destBounds);
|
|
} else {
|
|
if ((yPos + _cellSize.y) < _bounds.bottom) {
|
|
ySize = _cellSize.y;
|
|
} else {
|
|
ySize = _bounds.bottom - yPos;
|
|
}
|
|
|
|
Rect srcBounds(_mapOffset.x % _cellSize.x, 0,
|
|
(_mapOffset.x % _cellSize.x) + _bounds.width(), ySize);
|
|
Rect destBounds(_bounds.left, yPos, _bounds.right, yPos + ySize);
|
|
|
|
R2_GLOBALS.gfxManager().copyFrom(_mapImage, srcBounds, destBounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
int MazeUI::getCellFromPixelXY(const Common::Point &pt) {
|
|
if (!_bounds.contains(pt))
|
|
return -1;
|
|
|
|
int cellX = (pt.x - _bounds.left + _mapOffset.x) / _cellSize.x;
|
|
int cellY = (pt.y - _bounds.top + _mapOffset.y) / _cellSize.y;
|
|
|
|
if ((cellX >= 0) && (cellY >= 0) && (cellX < _mapCells.x) && (cellY < _mapCells.y))
|
|
return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * cellY + cellX) * 2);
|
|
|
|
return -1;
|
|
}
|
|
|
|
int MazeUI::getCellFromCellXY(const Common::Point &p) {
|
|
if (p.x < 0 || p.y < 0 || p.x >= _mapCells.x || p.y >= _mapCells.y) {
|
|
return -1;
|
|
} else {
|
|
return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * p.y + p.x) * 2);
|
|
}
|
|
}
|
|
|
|
int MazeUI::pixelToCellXY(Common::Point &pt) {
|
|
pt.x /= _cellSize.x;
|
|
pt.y /= _cellSize.y;
|
|
|
|
if ((pt.x >= 0) && (pt.y >= 0) && (pt.x < _mapCells.x) && (pt.y < _mapCells.y)) {
|
|
return (int16)READ_LE_UINT16(_mapData + (_mapCells.x * pt.y + pt.x) * 2);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void MazeUI::setDisplayBounds(const Rect &r) {
|
|
_bounds = r;
|
|
_bounds.clip(g_globals->gfxManager()._bounds);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void AnimationSlice::load(Common::File &f) {
|
|
f.skip(2);
|
|
_sliceOffset = f.readUint16LE();
|
|
f.skip(6);
|
|
_drawMode = f.readByte();
|
|
_secondaryIndex = f.readByte();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
AnimationSlices::AnimationSlices() {
|
|
_pixelData = NULL;
|
|
|
|
_dataSize = 0;
|
|
_dataSize2 = 0;
|
|
_slices->_sliceOffset = 0;
|
|
_slices->_drawMode = 0;
|
|
_slices->_secondaryIndex = 0;
|
|
}
|
|
|
|
AnimationSlices::~AnimationSlices() {
|
|
delete[] _pixelData;
|
|
}
|
|
|
|
void AnimationSlices::load(Common::File &f) {
|
|
f.skip(4);
|
|
_dataSize = f.readUint32LE();
|
|
f.skip(8);
|
|
_dataSize2 = f.readUint32LE();
|
|
f.skip(28);
|
|
|
|
// Load the four slice indexes
|
|
for (int idx = 0; idx < 4; ++idx)
|
|
_slices[idx].load(f);
|
|
}
|
|
|
|
int AnimationSlices::loadPixels(Common::File &f, int slicesSize) {
|
|
delete[] _pixelData;
|
|
_pixelData = new byte[slicesSize];
|
|
return f.read(_pixelData, slicesSize);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void AnimationPlayerSubData::load(Common::File &f) {
|
|
uint32 posStart = f.pos();
|
|
|
|
f.skip(6);
|
|
_duration = f.readUint32LE();
|
|
_frameRate = f.readUint16LE();
|
|
_framesPerSlices = f.readUint16LE();
|
|
_drawType = f.readUint16LE();
|
|
f.skip(2);
|
|
_sliceSize = f.readUint16LE();
|
|
_ySlices = f.readUint16LE();
|
|
_field16 = f.readUint32LE();
|
|
f.skip(2);
|
|
_palStart = f.readUint16LE();
|
|
_palSize = f.readUint16LE();
|
|
f.read(_palData, 768);
|
|
_totalSize = f.readSint32LE();
|
|
f.skip(12);
|
|
_slices.load(f);
|
|
|
|
uint32 posEnd = f.pos();
|
|
assert((posEnd - posStart) == 0x390);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
AnimationPlayer::AnimationPlayer(): EventHandler() {
|
|
_endAction = NULL;
|
|
|
|
_animData1 = NULL;
|
|
_animData2 = NULL;
|
|
|
|
_screenBounds = R2_GLOBALS._gfxManagerInstance._bounds;
|
|
_rect1 = R2_GLOBALS._gfxManagerInstance._bounds;
|
|
_paletteMode = ANIMPALMODE_REPLACE_PALETTE;
|
|
_canSkip = true;
|
|
_sliceHeight = 1;
|
|
_endAction = NULL;
|
|
|
|
_sliceCurrent = nullptr;
|
|
_sliceNext = nullptr;
|
|
_animLoaded = false;
|
|
_objectMode = ANIMOBJMODE_1;
|
|
_dataNeeded = 0;
|
|
_playbackTick = 0;
|
|
_playbackTickPrior = 0;
|
|
_position = 0;
|
|
_nextSlicesPosition = 0;
|
|
_frameDelay = 0;
|
|
_gameFrame = 0;
|
|
}
|
|
|
|
AnimationPlayer::~AnimationPlayer() {
|
|
if (!isCompleted())
|
|
close();
|
|
}
|
|
|
|
void AnimationPlayer::synchronize(Serializer &s) {
|
|
EventHandler::synchronize(s);
|
|
|
|
// TODO: Implement saving for animation player state. Currently, I disable saving
|
|
// when an animation is active, so saving it's state would a "nice to have".
|
|
}
|
|
|
|
void AnimationPlayer::remove() {
|
|
if (_endAction)
|
|
_endAction->signal();
|
|
|
|
_endAction = NULL;
|
|
}
|
|
|
|
void AnimationPlayer::process(Event &event) {
|
|
if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE) && _canSkip) {
|
|
// Move the current position to the end
|
|
_position = _subData._duration;
|
|
}
|
|
}
|
|
|
|
void AnimationPlayer::dispatch() {
|
|
uint32 gameFrame = R2_GLOBALS._events.getFrameNumber();
|
|
uint32 gameDiff = gameFrame - _gameFrame;
|
|
|
|
if (gameDiff >= _frameDelay) {
|
|
drawFrame(_playbackTick % _subData._framesPerSlices);
|
|
++_playbackTick;
|
|
_position = _playbackTick / _subData._framesPerSlices;
|
|
|
|
if (_position == _nextSlicesPosition)
|
|
nextSlices();
|
|
|
|
_playbackTickPrior = _playbackTick;
|
|
_gameFrame = gameFrame;
|
|
}
|
|
}
|
|
|
|
bool AnimationPlayer::load(int animId, Action *endAction) {
|
|
// Open up the main resource file for access
|
|
TLib &libFile = g_resourceManager->first();
|
|
if (!_resourceFile.open(libFile.getFilename()))
|
|
error("Could not open resource");
|
|
|
|
// Get the offset of the given resource and seek to it in the player's file reference
|
|
ResourceEntry entry;
|
|
uint32 fileOffset = libFile.getResourceStart(RES_IMAGE, animId, 0, entry);
|
|
_resourceFile.seek(fileOffset);
|
|
|
|
// At this point, the file is pointing to the start of the resource data
|
|
|
|
// Set the end action
|
|
_endAction = endAction;
|
|
|
|
// Load the sub data block
|
|
_subData.load(_resourceFile);
|
|
|
|
// Set other properties
|
|
_playbackTickPrior = -1;
|
|
_playbackTick = 0;
|
|
|
|
_frameDelay = (60 / _subData._frameRate);
|
|
_gameFrame = R2_GLOBALS._events.getFrameNumber();
|
|
|
|
// WORKAROUND: Slow down the title sequences to better match the original
|
|
if (animId <= 4 || animId == 15)
|
|
_frameDelay *= 8;
|
|
|
|
if (_subData._totalSize) {
|
|
_dataNeeded = _subData._totalSize;
|
|
} else {
|
|
int v = (_subData._sliceSize + 2) * _subData._ySlices * _subData._framesPerSlices;
|
|
_dataNeeded = (_subData._field16 / _subData._framesPerSlices) + v + 96;
|
|
}
|
|
|
|
debugC(1, ktSageDebugGraphics, "Data needed %d", _dataNeeded);
|
|
|
|
// Set up animation data objects
|
|
_animData1 = new AnimationData();
|
|
_sliceCurrent = _animData1;
|
|
|
|
if (_subData._framesPerSlices <= 1) {
|
|
_animData2 = NULL;
|
|
_sliceNext = _sliceCurrent;
|
|
} else {
|
|
_animData2 = new AnimationData();
|
|
_sliceNext = _animData2;
|
|
}
|
|
|
|
_position = 0;
|
|
_nextSlicesPosition = 1;
|
|
|
|
// Load up the first slices set
|
|
_sliceCurrent->_dataSize = _subData._slices._dataSize;
|
|
_sliceCurrent->_slices = _subData._slices;
|
|
int slicesSize = _sliceCurrent->_dataSize - 96;
|
|
int readSize = _sliceCurrent->_slices.loadPixels(_resourceFile, slicesSize);
|
|
_sliceCurrent->_animSlicesSize = readSize + 96;
|
|
|
|
if (_sliceNext != _sliceCurrent) {
|
|
getSlices();
|
|
}
|
|
|
|
// Handle starting palette
|
|
switch (_paletteMode) {
|
|
case ANIMPALMODE_REPLACE_PALETTE:
|
|
// Use the palette provided with the animation directly
|
|
_palette.getPalette();
|
|
for (int idx = _subData._palStart; idx < (_subData._palStart + _subData._palSize); ++idx) {
|
|
byte r = _subData._palData[idx * 3];
|
|
byte g = _subData._palData[idx * 3 + 1];
|
|
byte b = _subData._palData[idx * 3 + 2];
|
|
|
|
R2_GLOBALS._scenePalette.setEntry(idx, r, g, b);
|
|
}
|
|
|
|
R2_GLOBALS._sceneManager._hasPalette = true;
|
|
break;
|
|
case ANIMPALMODE_NONE:
|
|
break;
|
|
|
|
default:
|
|
// ANIMPALMODE_CURR_PALETTE
|
|
// Use the closest matching colors in the currently active palette to those specified in the animation
|
|
for (int idx = _subData._palStart; idx < (_subData._palStart + _subData._palSize); ++idx) {
|
|
byte r = _subData._palData[idx * 3];
|
|
byte g = _subData._palData[idx * 3 + 1];
|
|
byte b = _subData._palData[idx * 3 + 2];
|
|
|
|
int palIndex = R2_GLOBALS._scenePalette.indexOf(r, g, b);
|
|
_palIndexes[idx] = palIndex;
|
|
}
|
|
break;
|
|
}
|
|
|
|
++R2_GLOBALS._animationCtr;
|
|
_animLoaded = true;
|
|
return true;
|
|
}
|
|
|
|
void AnimationPlayer::drawFrame(int sliceIndex) {
|
|
assert(sliceIndex < 4);
|
|
AnimationSlices &slices = _sliceCurrent->_slices;
|
|
AnimationSlice &slice = _sliceCurrent->_slices._slices[sliceIndex];
|
|
|
|
byte *sliceDataStart = &slices._pixelData[slice._sliceOffset - 96];
|
|
byte *sliceData1 = sliceDataStart;
|
|
|
|
Rect playerBounds = _screenBounds;
|
|
|
|
Graphics::Surface dest = R2_GLOBALS._screen.getSubArea(playerBounds);
|
|
int y = 0;
|
|
|
|
// Handle different drawing modes
|
|
switch (slice._drawMode) {
|
|
case 0:
|
|
// Draw from uncompressed source
|
|
for (int sliceNum = 0; sliceNum < _subData._ySlices; ++sliceNum) {
|
|
for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex, ++y) {
|
|
// TODO: Check of _subData._drawType was done for two different kinds of
|
|
// line slice drawing in original
|
|
const byte *pSrc = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
|
|
byte *pDest = (byte *)dest.getBasePtr(0, y);
|
|
|
|
Common::copy(pSrc, pSrc + _subData._sliceSize, pDest);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
switch (slice._secondaryIndex) {
|
|
case 0xfe:
|
|
// Draw from uncompressed source with optional skipped rows
|
|
for (int sliceNum = 0; sliceNum < _subData._ySlices; ++sliceNum) {
|
|
for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex, ++y) {
|
|
int offset = READ_LE_UINT16(sliceData1 + sliceNum * 2);
|
|
|
|
if (offset) {
|
|
const byte *pSrc = (const byte *)sliceDataStart + offset;
|
|
byte *pDest = (byte *)dest.getBasePtr(0, y);
|
|
|
|
//Common::copy(pSrc, pSrc + playerBounds.width(), pDest);
|
|
rleDecode(pSrc, pDest, playerBounds.width());
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 0xff:
|
|
// Draw from RLE compressed source
|
|
for (int sliceNum = 0; sliceNum < _subData._ySlices; ++sliceNum) {
|
|
for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex, ++y) {
|
|
// TODO: Check of _subData._drawType was done for two different kinds of
|
|
// line slice drawing in original
|
|
const byte *pSrc = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
|
|
byte *pDest = (byte *)dest.getBasePtr(0, y);
|
|
|
|
rleDecode(pSrc, pDest, _subData._sliceSize);
|
|
}
|
|
}
|
|
break;
|
|
default: {
|
|
// Draw from two slice sets simultaneously
|
|
AnimationSlice &slice2 = _sliceCurrent->_slices._slices[slice._secondaryIndex];
|
|
byte *sliceData2 = &slices._pixelData[slice2._sliceOffset - 96];
|
|
|
|
for (int sliceNum = 0; sliceNum < _subData._ySlices; ++sliceNum) {
|
|
for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex, ++y) {
|
|
const byte *pSrc1 = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData2 + sliceNum * 2);
|
|
const byte *pSrc2 = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
|
|
byte *pDest = (byte *)dest.getBasePtr(0, y);
|
|
|
|
if (slice2._drawMode == 0) {
|
|
// Uncompressed background, foreground compressed
|
|
Common::copy(pSrc1, pSrc1 + _subData._sliceSize, pDest);
|
|
rleDecode(pSrc2, pDest, _subData._sliceSize);
|
|
} else {
|
|
// Both background and foreground is compressed
|
|
rleDecode(pSrc1, pDest, _subData._sliceSize);
|
|
rleDecode(pSrc2, pDest, _subData._sliceSize);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (_objectMode == ANIMOBJMODE_42) {
|
|
_screenBounds.expandPanes();
|
|
|
|
// Copy the drawn frame to the back surface
|
|
Rect srcRect = R2_GLOBALS._screen.getBounds();
|
|
Rect destRect = srcRect;
|
|
destRect.translate(-g_globals->_sceneOffset.x, -g_globals->_sceneOffset.y);
|
|
R2_GLOBALS._sceneManager._scene->_backSurface.copyFrom(R2_GLOBALS._screen,
|
|
srcRect, destRect);
|
|
|
|
// Draw any objects into the scene
|
|
R2_GLOBALS._sceneObjects->draw();
|
|
} else {
|
|
if (R2_GLOBALS._sceneManager._hasPalette) {
|
|
R2_GLOBALS._sceneManager._hasPalette = false;
|
|
R2_GLOBALS._scenePalette.refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Read the next frame's slice set
|
|
*/
|
|
void AnimationPlayer::nextSlices() {
|
|
_position = _nextSlicesPosition++;
|
|
_playbackTick = _position * _subData._framesPerSlices;
|
|
_playbackTickPrior = _playbackTick - 1;
|
|
|
|
if (_sliceNext == _sliceCurrent) {
|
|
int dataSize = _sliceCurrent->_slices._dataSize2;
|
|
_sliceCurrent->_dataSize = dataSize;
|
|
debugC(1, ktSageDebugGraphics, "Next frame size = %xh", dataSize);
|
|
if (dataSize == 0)
|
|
return;
|
|
|
|
dataSize -= 96;
|
|
assert(dataSize >= 0);
|
|
_sliceCurrent->_slices.load(_resourceFile);
|
|
_sliceCurrent->_animSlicesSize = _sliceCurrent->_slices.loadPixels(_resourceFile, dataSize);
|
|
} else {
|
|
SWAP(_sliceCurrent, _sliceNext);
|
|
getSlices();
|
|
}
|
|
}
|
|
|
|
bool AnimationPlayer::isCompleted() {
|
|
return (_position >= _subData._duration);
|
|
}
|
|
|
|
void AnimationPlayer::close() {
|
|
if (_animLoaded) {
|
|
switch (_paletteMode) {
|
|
case 0:
|
|
R2_GLOBALS._scenePalette.replace(&_palette);
|
|
changePane();
|
|
R2_GLOBALS._sceneManager._hasPalette = true;
|
|
break;
|
|
case 2:
|
|
closing();
|
|
break;
|
|
default:
|
|
changePane();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Close the resource file
|
|
_resourceFile.close();
|
|
|
|
if (_objectMode != ANIMOBJMODE_42) {
|
|
// flip screen in original
|
|
}
|
|
|
|
// Free animation objects
|
|
delete _animData1;
|
|
delete _animData2;
|
|
_animData1 = NULL;
|
|
_animData2 = NULL;
|
|
|
|
_animLoaded = false;
|
|
if (g_globals != NULL)
|
|
R2_GLOBALS._animationCtr = MAX(R2_GLOBALS._animationCtr - 1, 0);
|
|
}
|
|
|
|
void AnimationPlayer::rleDecode(const byte *pSrc, byte *pDest, int size) {
|
|
while (size > 0) {
|
|
byte v = *pSrc++;
|
|
if (!(v & 0x80)) {
|
|
// Following uncompressed set of bytes
|
|
Common::copy(pSrc, pSrc + v, pDest);
|
|
pSrc += v;
|
|
pDest += v;
|
|
size -= v;
|
|
} else {
|
|
int count = v & 0x3F;
|
|
size -= count;
|
|
|
|
if (!(v & 0x40)) {
|
|
// Skip over a number of bytes
|
|
pDest += count;
|
|
} else {
|
|
// Replicate a number of bytes
|
|
Common::fill(pDest, pDest + count, *pSrc++);
|
|
pDest += count;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AnimationPlayer::getSlices() {
|
|
assert((_sliceNext == _animData1) || (_sliceNext == _animData2));
|
|
assert((_sliceCurrent == _animData1) || (_sliceCurrent == _animData2));
|
|
|
|
_sliceNext->_dataSize = _sliceCurrent->_slices._dataSize2;
|
|
if (_sliceNext->_dataSize) {
|
|
if (_sliceNext->_dataSize >= _dataNeeded)
|
|
error("Bogus dataNeeded == %d / %d", _sliceNext->_dataSize, _dataNeeded);
|
|
}
|
|
|
|
int dataSize = _sliceNext->_dataSize - 96;
|
|
_sliceNext->_slices.load(_resourceFile);
|
|
_sliceNext->_animSlicesSize = _sliceNext->_slices.loadPixels(_resourceFile, dataSize);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
AnimationPlayerExt::AnimationPlayerExt(): AnimationPlayer() {
|
|
_isActive = false;
|
|
_canSkip = false;
|
|
}
|
|
|
|
void AnimationPlayerExt::synchronize(Serializer &s) {
|
|
AnimationPlayer::synchronize(s);
|
|
s.syncAsSint16LE(_isActive);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
ModalWindow::ModalWindow() {
|
|
_insetCount = 0;
|
|
}
|
|
|
|
void ModalWindow::remove() {
|
|
R2_GLOBALS._sceneItems.remove(&_object1);
|
|
_object1.remove();
|
|
|
|
SceneArea::remove();
|
|
|
|
--R2_GLOBALS._insetUp;
|
|
}
|
|
|
|
void ModalWindow::synchronize(Serializer &s) {
|
|
SceneArea::synchronize(s);
|
|
|
|
s.syncAsByte(_insetCount);
|
|
}
|
|
|
|
void ModalWindow::process(Event &event) {
|
|
if (_insetCount != R2_GLOBALS._insetUp)
|
|
return;
|
|
|
|
CursorType cursor = R2_GLOBALS._events.getCursor();
|
|
|
|
if (_object1._bounds.contains(event.mousePos.x + g_globals->gfxManager()._bounds.left , event.mousePos.y)) {
|
|
if (cursor == _cursorNum) {
|
|
R2_GLOBALS._events.setCursor(_savedCursorNum);
|
|
}
|
|
} else if (event.mousePos.y < 168) {
|
|
if (cursor != _cursorNum) {
|
|
_savedCursorNum = cursor;
|
|
R2_GLOBALS._events.setCursor(CURSOR_INVALID);
|
|
}
|
|
if (event.eventType == EVENT_BUTTON_DOWN) {
|
|
event.handled = true;
|
|
R2_GLOBALS._events.setCursor(_savedCursorNum);
|
|
remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ModalWindow::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY) {
|
|
Scene1200 *scene = (Scene1200 *)R2_GLOBALS._sceneManager._scene;
|
|
|
|
_object1.postInit();
|
|
_object1.setup(visage, stripFrameNum, frameNum);
|
|
_object1.setPosition(Common::Point(posX, posY));
|
|
_object1.fixPriority(250);
|
|
_cursorNum = CURSOR_INVALID;
|
|
scene->_sceneAreas.push_front(this);
|
|
++R2_GLOBALS._insetUp;
|
|
_insetCount = R2_GLOBALS._insetUp;
|
|
}
|
|
|
|
void ModalWindow::setup3(int resNum, int lookLineNum, int talkLineNum, int useLineNum) {
|
|
_object1.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
ScannerDialog::Button::Button() {
|
|
_buttonId = 0;
|
|
_buttonDown = false;
|
|
}
|
|
|
|
void ScannerDialog::Button::setup(int buttonId) {
|
|
_buttonId = buttonId;
|
|
_buttonDown = false;
|
|
SceneActor::postInit();
|
|
|
|
SceneObject::setup(4, 2, 2);
|
|
fixPriority(255);
|
|
|
|
if (_buttonId == 1)
|
|
setPosition(Common::Point(141, 99));
|
|
else if (_buttonId == 2)
|
|
setPosition(Common::Point(141, 108));
|
|
|
|
static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this);
|
|
}
|
|
|
|
void ScannerDialog::Button::synchronize(Serializer &s) {
|
|
SceneActor::synchronize(s);
|
|
s.syncAsSint16LE(_buttonId);
|
|
}
|
|
|
|
void ScannerDialog::Button::process(Event &event) {
|
|
if (event.eventType == EVENT_BUTTON_DOWN && R2_GLOBALS._events.getCursor() == CURSOR_USE
|
|
&& _bounds.contains(event.mousePos) && !_buttonDown) {
|
|
setFrame(3);
|
|
_buttonDown = true;
|
|
event.handled = true;
|
|
}
|
|
|
|
if (event.eventType == EVENT_BUTTON_UP && _buttonDown) {
|
|
setFrame(2);
|
|
_buttonDown = false;
|
|
event.handled = true;
|
|
|
|
reset();
|
|
}
|
|
}
|
|
|
|
bool ScannerDialog::Button::startAction(CursorType action, Event &event) {
|
|
if (action == CURSOR_USE)
|
|
return false;
|
|
|
|
return startAction(action, event);
|
|
}
|
|
|
|
void ScannerDialog::Button::reset() {
|
|
Scene *scene = R2_GLOBALS._sceneManager._scene;
|
|
ScannerDialog &scanner = *R2_GLOBALS._scannerDialog;
|
|
|
|
switch (_buttonId) {
|
|
case 1:
|
|
// Talk button
|
|
switch (R2_GLOBALS._sceneManager._sceneNumber) {
|
|
case 1550:
|
|
scene->_sceneMode = 80;
|
|
scene->signal();
|
|
break;
|
|
case 1700:
|
|
scene->_sceneMode = 30;
|
|
scene->signal();
|
|
remove();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case 2:
|
|
// Scan button
|
|
switch (R2_GLOBALS._sceneManager._sceneNumber) {
|
|
case 1550:
|
|
scanner._obj4.setup(4, 3, 1);
|
|
|
|
scanner._obj5.postInit();
|
|
scanner._obj5.setup(4, 4, 1);
|
|
scanner._obj5.setPosition(Common::Point(R2_GLOBALS._s1550PlayerArea[R2_QUINN].x + 145,
|
|
R2_GLOBALS._s1550PlayerArea[R2_QUINN].y + 59));
|
|
scanner._obj5.fixPriority(257);
|
|
|
|
scanner._obj6.postInit();
|
|
scanner._obj6.setup(4, 4, 2);
|
|
scanner._obj6.setPosition(Common::Point(R2_GLOBALS._s1550PlayerArea[R2_SEEKER].x + 145,
|
|
R2_GLOBALS._s1550PlayerArea[R2_SEEKER].y + 59));
|
|
scanner._obj6.fixPriority(257);
|
|
break;
|
|
case 1700:
|
|
case 1800:
|
|
if (R2_GLOBALS._rimLocation < 1201)
|
|
scanner._obj4.setup(4, 3, 3);
|
|
else if (R2_GLOBALS._rimLocation > 1201)
|
|
scanner._obj4.setup(4, 3, 4);
|
|
else
|
|
scanner._obj4.setup(4, 3, 5);
|
|
break;
|
|
case 3800:
|
|
case 3900:
|
|
if ((R2_GLOBALS._desertWrongDirCtr + 1) == 0 && R2_GLOBALS._desertCorrectDirection == 0) {
|
|
do {
|
|
R2_GLOBALS._desertCorrectDirection = R2_GLOBALS._randomSource.getRandomNumber(3) + 1;
|
|
} while (R2_GLOBALS._desertCorrectDirection == R2_GLOBALS._desertPreviousDirection);
|
|
}
|
|
|
|
scanner._obj4.setup(4, 7, R2_GLOBALS._desertCorrectDirection);
|
|
if (!R2_GLOBALS.getFlag(46))
|
|
R2_GLOBALS.setFlag(46);
|
|
break;
|
|
default:
|
|
scanner._obj4.setup(4, 3, 2);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
ScannerDialog::Slider::Slider() {
|
|
_initial = _xStart = _yp = 0;
|
|
_width = _xInc = 0;
|
|
_sliderDown = false;
|
|
}
|
|
|
|
void ScannerDialog::Slider::synchronize(Serializer &s) {
|
|
SceneActor::synchronize(s);
|
|
|
|
s.syncAsSint16LE(_initial);
|
|
s.syncAsSint16LE(_xStart);
|
|
s.syncAsSint16LE(_yp);
|
|
s.syncAsSint16LE(_width);
|
|
s.syncAsSint16LE(_xInc);
|
|
}
|
|
|
|
void ScannerDialog::Slider::remove() {
|
|
static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.remove(this);
|
|
SceneActor::remove();
|
|
}
|
|
|
|
void ScannerDialog::Slider::process(Event &event) {
|
|
if (event.eventType == EVENT_BUTTON_DOWN && R2_GLOBALS._events.getCursor() == CURSOR_USE
|
|
&& _bounds.contains(event.mousePos)) {
|
|
_sliderDown = true;
|
|
}
|
|
|
|
if (event.eventType == EVENT_BUTTON_UP && _sliderDown) {
|
|
_sliderDown = false;
|
|
event.handled = true;
|
|
update();
|
|
}
|
|
|
|
if (_sliderDown) {
|
|
event.handled = true;
|
|
if (event.mousePos.x < _xStart) {
|
|
setPosition(Common::Point(_xStart, _yp));
|
|
} else if (event.mousePos.x >= (_xStart + _width)) {
|
|
setPosition(Common::Point(_xStart + _width, _yp));
|
|
} else {
|
|
setPosition(Common::Point(event.mousePos.x, _yp));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ScannerDialog::Slider::startAction(CursorType action, Event &event) {
|
|
if (action == CURSOR_USE)
|
|
return false;
|
|
|
|
return startAction(action, event);
|
|
}
|
|
|
|
void ScannerDialog::Slider::update() {
|
|
int incHalf = (_width / (_xInc - 1)) / 2;
|
|
int newFrequency = ((_position.x - _xStart + incHalf) * _xInc) / (_width + incHalf * 2);
|
|
setPosition(Common::Point(_xStart + ((_width * newFrequency) / (_xInc - 1)), _yp));
|
|
|
|
R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex] = newFrequency + 1;
|
|
|
|
switch (newFrequency) {
|
|
case 0:
|
|
R2_GLOBALS._sound4.stop();
|
|
break;
|
|
case 1:
|
|
R2_GLOBALS._sound4.play(45);
|
|
break;
|
|
case 2:
|
|
R2_GLOBALS._sound4.play(4);
|
|
break;
|
|
case 3:
|
|
R2_GLOBALS._sound4.play(5);
|
|
break;
|
|
case 4:
|
|
R2_GLOBALS._sound4.play(6);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ScannerDialog::Slider::setup(int initial, int xStart, int yp, int width, int xInc) {
|
|
_initial = initial;
|
|
_xStart = xStart;
|
|
_yp = yp;
|
|
_width = width;
|
|
_xInc = xInc;
|
|
_sliderDown = false;
|
|
SceneActor::postInit();
|
|
SceneObject::setup(4, 2, 1);
|
|
fixPriority(255);
|
|
setPosition(Common::Point(_width * (_initial - 1) / (_xInc - 1) + _xStart, yp));
|
|
|
|
static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene)->_sceneAreas.push_front(this);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
ScannerDialog::ScannerDialog() {
|
|
}
|
|
|
|
void ScannerDialog::remove() {
|
|
switch (R2_GLOBALS._sceneManager._sceneNumber) {
|
|
case 1550:
|
|
case 1700:
|
|
R2_GLOBALS._events.setCursor(R2_GLOBALS._player._canWalk ? CURSOR_WALK : CURSOR_USE);
|
|
break;
|
|
case 3800:
|
|
case 3900: {
|
|
Scene *scene = R2_GLOBALS._sceneManager._scene;
|
|
scene->_sceneMode = 3806;
|
|
scene->signal();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
SceneExt *scene = static_cast<SceneExt *>(R2_GLOBALS._sceneManager._scene);
|
|
scene->_sceneAreas.remove(&_talkButton);
|
|
scene->_sceneAreas.remove(&_scanButton);
|
|
_talkButton.remove();
|
|
_scanButton.remove();
|
|
_slider.remove();
|
|
_obj4.remove();
|
|
_obj5.remove();
|
|
_obj6.remove();
|
|
_obj7.remove();
|
|
|
|
ModalWindow::remove();
|
|
}
|
|
|
|
void ScannerDialog::setup2(int visage, int stripFrameNum, int frameNum, int posX, int posY) {
|
|
// Stop player moving if currently doing so
|
|
if (R2_GLOBALS._player._mover)
|
|
R2_GLOBALS._player.addMover(NULL);
|
|
|
|
R2_GLOBALS._events.setCursor(CURSOR_USE);
|
|
ModalWindow::setup2(visage, stripFrameNum, frameNum, posX, posY);
|
|
|
|
setup3(100, -1, -1, -1);
|
|
_talkButton.setup(1);
|
|
_scanButton.setup(2);
|
|
_slider.setup(R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex], 142, 124, 35, 5);
|
|
|
|
_obj4.postInit();
|
|
_obj4.setup(4, 3, 2);
|
|
_obj4.setPosition(Common::Point(160, 83));
|
|
_obj4.fixPriority(256);
|
|
|
|
if (R2_GLOBALS._sceneManager._sceneNumber == 3800 || R2_GLOBALS._sceneManager._sceneNumber == 3900) {
|
|
Scene *scene = R2_GLOBALS._sceneManager._scene;
|
|
scene->_sceneMode = 3805;
|
|
scene->signal();
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
} // End of namespace Ringworld2
|
|
|
|
} // End of namespace TsAGE
|