scummvm/engines/tsage/ringworld2/ringworld2_logic.cpp
2021-12-26 18:48:43 +01:00

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