diff options
author | Thierry Crozat | 2018-04-15 18:51:48 +0100 |
---|---|---|
committer | Thierry Crozat | 2018-04-15 18:51:48 +0100 |
commit | b5c59443669f6fa468b023ebcd26cf090f20b62b (patch) | |
tree | 4a62910909e85dbd037d700291c898447e2eb3fd | |
parent | 284f7208308ae14dd1128058e0e87ff702378cff (diff) | |
parent | d4592b6077aebaf1630b05d1904723c6544d4537 (diff) | |
download | scummvm-rg350-b5c59443669f6fa468b023ebcd26cf090f20b62b.tar.gz scummvm-rg350-b5c59443669f6fa468b023ebcd26cf090f20b62b.tar.bz2 scummvm-rg350-b5c59443669f6fa468b023ebcd26cf090f20b62b.zip |
Merge branch 'Joefish-merge_nova'
-rw-r--r-- | engines/supernova/detection.cpp | 19 | ||||
-rw-r--r-- | engines/supernova/graphics.cpp | 25 | ||||
-rw-r--r-- | engines/supernova/graphics.h | 6 | ||||
-rw-r--r-- | engines/supernova/imageid.h | 654 | ||||
-rw-r--r-- | engines/supernova/module.mk | 7 | ||||
-rw-r--r-- | engines/supernova/msn_def.h | 292 | ||||
-rw-r--r-- | engines/supernova/resman.cpp | 395 | ||||
-rw-r--r-- | engines/supernova/resman.h | 77 | ||||
-rw-r--r-- | engines/supernova/rooms.cpp | 404 | ||||
-rw-r--r-- | engines/supernova/rooms.h | 45 | ||||
-rw-r--r-- | engines/supernova/screen.cpp | 636 | ||||
-rw-r--r-- | engines/supernova/screen.h | 197 | ||||
-rw-r--r-- | engines/supernova/screenstatic.cpp | 328 | ||||
-rw-r--r-- | engines/supernova/sound.cpp | 65 | ||||
-rw-r--r-- | engines/supernova/sound.h | 80 | ||||
-rw-r--r-- | engines/supernova/state.cpp | 363 | ||||
-rw-r--r-- | engines/supernova/state.h | 36 | ||||
-rw-r--r-- | engines/supernova/supernova.cpp | 858 | ||||
-rw-r--r-- | engines/supernova/supernova.h | 174 |
19 files changed, 3040 insertions, 1621 deletions
diff --git a/engines/supernova/detection.cpp b/engines/supernova/detection.cpp index 7fd2da1760..b172b7fa49 100644 --- a/engines/supernova/detection.cpp +++ b/engines/supernova/detection.cpp @@ -32,7 +32,7 @@ static const PlainGameDescriptor supernovaGames[] = { {"msn1", "Mission Supernova 1"}, {"msn2", "Mission Supernova 2"}, - {NULL, NULL} + {nullptr, nullptr} }; namespace Supernova { @@ -40,7 +40,7 @@ static const ADGameDescription gameDescriptions[] = { // Mission Supernova 1 { "msn1", - NULL, + nullptr, AD_ENTRY1s("msn_data.000", "f64f16782a86211efa919fbae41e7568", 24163), Common::DE_DEU, Common::kPlatformDOS, @@ -49,7 +49,7 @@ static const ADGameDescription gameDescriptions[] = { }, { "msn1", - NULL, + nullptr, AD_ENTRY1s("msn_data.000", "f64f16782a86211efa919fbae41e7568", 24163), Common::EN_ANY, Common::kPlatformDOS, @@ -60,13 +60,22 @@ static const ADGameDescription gameDescriptions[] = { // Mission Supernova 2 { "msn2", - NULL, + nullptr, AD_ENTRY1s("ms2_data.000", "e595610cba4a6d24a763e428d05cc83f", 24805), Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + { + "msn2", + nullptr, + AD_ENTRY1s("ms2_data.000", "e595610cba4a6d24a763e428d05cc83f", 24805), + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_UNSTABLE, + GUIO1(GUIO_NONE) + }, AD_TABLE_END_MARKER }; @@ -122,7 +131,7 @@ bool SupernovaMetaEngine::createInstance(OSystem *syst, Engine **engine, const A *engine = new Supernova::SupernovaEngine(syst); } - return desc != NULL; + return desc != nullptr; } SaveStateList SupernovaMetaEngine::listSaves(const char *target) const { diff --git a/engines/supernova/graphics.cpp b/engines/supernova/graphics.cpp index 3a29bacacc..9a05a424ca 100644 --- a/engines/supernova/graphics.cpp +++ b/engines/supernova/graphics.cpp @@ -28,13 +28,14 @@ #include "graphics/palette.h" #include "graphics/surface.h" -#include "graphics.h" -#include "msn_def.h" -#include "supernova.h" +#include "supernova/graphics.h" +#include "supernova/msn_def.h" +#include "supernova/screen.h" +#include "supernova/supernova.h" namespace Supernova { -MSNImageDecoder::MSNImageDecoder() { +MSNImage::MSNImage() { _palette = nullptr; _encodedImage = nullptr; _filenumber = -1; @@ -43,11 +44,11 @@ MSNImageDecoder::MSNImageDecoder() { _numClickFields = 0; } -MSNImageDecoder::~MSNImageDecoder() { +MSNImage::~MSNImage() { destroy(); } -bool MSNImageDecoder::init(int filenumber) { +bool MSNImage::init(int filenumber) { Common::File file; if (!file.open(Common::String::format("msn_data.%03d", filenumber))) { warning("Image data file msn_data.%03d could not be read!", filenumber); @@ -60,7 +61,7 @@ bool MSNImageDecoder::init(int filenumber) { return true; } -bool MSNImageDecoder::loadFromEngineDataFile() { +bool MSNImage::loadFromEngineDataFile() { Common::String name; if (_filenumber == 1) name = "IMG1"; @@ -102,7 +103,7 @@ bool MSNImageDecoder::loadFromEngineDataFile() { return false; } -bool MSNImageDecoder::loadStream(Common::SeekableReadStream &stream) { +bool MSNImage::loadStream(Common::SeekableReadStream &stream) { destroy(); uint size = 0; @@ -199,7 +200,7 @@ bool MSNImageDecoder::loadStream(Common::SeekableReadStream &stream) { return true; } -bool MSNImageDecoder::loadSections() { +bool MSNImage::loadSections() { bool isNewspaper = _filenumber == 1 || _filenumber == 2; int imageWidth = isNewspaper ? 640 : 320; int imageHeight = isNewspaper ? 480 : 200; @@ -238,14 +239,14 @@ bool MSNImageDecoder::loadSections() { return true; } -void MSNImageDecoder::destroy() { +void MSNImage::destroy() { if (_palette) { delete[] _palette; - _palette = NULL; + _palette = nullptr; } if (_encodedImage) { delete[] _encodedImage; - _encodedImage = NULL; + _encodedImage = nullptr; } for (Common::Array<Graphics::Surface *>::iterator it = _sectionSurfaces.begin(); it != _sectionSurfaces.end(); ++it) { diff --git a/engines/supernova/graphics.h b/engines/supernova/graphics.h index 2a820c9432..058da45ba8 100644 --- a/engines/supernova/graphics.h +++ b/engines/supernova/graphics.h @@ -36,10 +36,10 @@ struct Surface; namespace Supernova { -class MSNImageDecoder : public Image::ImageDecoder { +class MSNImage : public Image::ImageDecoder { public: - MSNImageDecoder(); - virtual ~MSNImageDecoder(); + MSNImage(); + virtual ~MSNImage(); virtual void destroy(); virtual bool loadStream(Common::SeekableReadStream &stream); diff --git a/engines/supernova/imageid.h b/engines/supernova/imageid.h new file mode 100644 index 0000000000..7cfa08370e --- /dev/null +++ b/engines/supernova/imageid.h @@ -0,0 +1,654 @@ +/* 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 2 +* 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, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef SUPERNOVA_IMAGEID_H +#define SUPERNOVA_IMAGEID_H + +namespace Supernova { + +enum ImageId { + // file 0 + kAxacussanShipBackground, + kAxacussanShipCenterMouthOpen, + kAxacussanShipRightMouthOpen, + // file 1 + kNewspaper1, + // file 2 + kNewspaper2, + // file 3 + kElevatorBackground, + kElevatorGreenButton, + kElevatorRedButton, + kElevatorDoorAnimation1, + kElevatorDoorAnimation2, + kElevatorDoorAnimation3, + kElevatorDoorAnimation4, + kElevatorDoorAnimation5, + kElevatorDummy1, + kElevatorDummy2, + kElevatorDummy3, + kElevatorDummy4, + // file 4 + kShipSpaceBackground, + kShipSpaceRope, + kShipSpaceDummy1, + kShipSpaceDummy2, + // file 5 + kBusStationBackground, + kBusStationArrived, + kBusStationPlantAnimation1, + kBusStationPlantAnimation2, + kBusStationPlantAnimation3, + kBusStationPlantAnimation4, + kBusStationPlantAnimation5, + kBusStationPlantAnimation6, + kBusStationPlantAnimation7, + kBusStationDoorOpened, + // file 6 + kOfficesBackground, + kOfficesDoorOpenTopLeft, + kOfficesDoorOpenBottomLeft, + kOfficesDoorOpenTopRight, + kOfficesDoorOpenBottomRight, + kOfficesAlienCorridorAnimation1, + kOfficesAlienCorridorAnimation2, + kOfficesAlienCorridorAnimation3, + kOfficesAlienCorridorAnimation4, + kOfficesAlienCorridorAnimation5, + kOfficesAlienCorridorAnimation6, + kOfficesAlienTopOfficeAnimation1, + kOfficesAlienTopOfficeAnimation2, + kOfficesAlienTopOfficeAnimation3, + kOfficesAlienTopOfficeAnimation4, + kOfficesAlienTopOfficeAnimation5, + kOfficesAlienBottomOfficeAnimation1, + kOfficesAlienBottomOfficeAnimation2, + kOfficesAlienBottomOfficeAnimation3, + kOfficesAlienBottomOfficeAnimation4, + kOfficesAlienBottomOfficeAnimation5, + kOfficesAlienBottom, + // file 7 + kOfficeLeftBackground, + kOfficeLeftDecoration, + kOfficeLeftMemo, + kOfficeLeftGraffiti, + kOfficeLeftTerminalSmashed, + kOfficeLeftDrawerMoney, + kOfficeLeftSafeOpen, + kOfficeLeftSafeClosed, + kOfficeLeftSafeMoney, + kOfficeLeftDoorOpen, + kOfficeLeftAlienShootAnimation1, + kOfficeLeftAlienShootAnimation2, + kOfficeLeftAlienShootAnimation3, + kOfficeLeftAlienShootAnimation4, + kOfficeLeftAlienShootAnimation5, + kOfficeLeftAlienShootAnimation6, + kOfficeLeftTerminalText, + kOfficeLeftDoorClosed, + kOfficeLeftDummy1, + kOfficeLeftDummy2, + kOfficeLeftDummy3, + kOfficeLeftDummy4, + kOfficeLeftDummy5, + // file 8 + kOfficeRightBackground, + kOfficeRightDecorationPictures, + kOfficeRightDecorationPlants, + kOfficeRightDoorOpen, + kOfficeRightTerminalSmashed, + kOfficeRightAlienShootAnimation1, + kOfficeRightAlienShootAnimation2, + kOfficeRightAlienShootAnimation3, + kOfficeRightAlienTalking, + kOfficeRightDummy1, + kOfficeRightDummy2, + kOfficeRightDummy3, + kOfficeRightDummy4, + // file 9 + kShipCockpitBackground, + kShipCockpitPilotAnimation1, + kShipCockpitPilotAnimation2, + kShipCockpitPilotAnimation3, + kShipCockpitPilotAnimation4, + kShipCockpitPilotAnimation5, + kShipCockpitPilotAnimation6, + kShipCockpitPilotAnimation7, + kShipCockpitPilotAnimation8, + kShipCockpitPilotAnimation9, + kShipCockpitPilotAnimation10, + kShipCockpitPilotAnimation11, + kShipCockpitPilotAnimation12, + kShipCockpitPilotAnimation13, + kShipCockpitPilotAnimation14, + kShipCockpitPilotAnimation15, + kShipCockpitPilotAnimation16, + kShipCockpitPilotAnimation17, + kShipCockpitPilotAnimation18, + kShipCockpitPilotAnimation19, + kShipCockpitPilotAnimation20, + kShipCockpitDisplayStatusAnimation1, + kShipCockpitDisplayStatusAnimation2, + kShipCockpitWindowRocks, + // file 10 + kRestaurantEntranceBackground, + kRestaurantEntrancePorterAnimation1, + kRestaurantEntrancePorterAnimation2, + kRestaurantEntrancePorterAnimation3, + kRestaurantEntrancePorterAnimation4, + kRestaurantEntranceBathroomDoorAnimation1, + kRestaurantEntranceBathroomDoorAnimation2, + kRestaurantEntranceBathroomDoorAnimation3, + kRestaurantEntranceBathroomDoorAnimation4, + kRestaurantEntranceBathroomDoorAnimation5, + kRestaurantEntranceGreenCandy, + kRestaurantEntranceBlueCandy, + kRestaurantEntrancePinkCandy, + kRestaurantEntranceWhiteCandy, + kRestaurantEntranceBlackCandy, + kRestaurantEntraceDummy1, + kRestaurantEntraceDummy2, + // file 11 + kDeathScreen, + // file 12 + kRocksBackground, + kRocksRockAnimation1, + kRocksRockAnimation2, + kRocksRockAnimation3, + // file 13 + kBluePlanetBackground, + kBluePlanetShipAnimation1, + kBluePlanetShipAnimation2, + kBluePlanetShipAnimation3, + kBluePlanetShipAnimation4, + kBluePlanetShipAnimation5, + kBluePlanetShipAnimation6, + kBluePlanetShipAnimation7, + kBluePlanetShipAnimation8, + kBluePlanetShipAnimation9, + kBluePlanetShipAnimation10, + kBluePlanetShipAnimation11, + kBluePlanetShipAnimation12, + kBluePlanetShipAnimation13, + // file 14 + kRogerCrashBackground, + kRogerCrashAnimation1, + kRogerCrashAnimation2, + kRogerCrashAnimation3, + kRogerCrashAnimation4, + kRogerCrashAnimation5, + kRogerCrashAnimation6, + kRogerCrashAnimation7, + kRogerCrashAnimation8, + kRogerCrashAnimation9, + kRogerCrashAnimation10, + kRogerCrashAnimation11, + kRogerCrashAnimation12, + kRogerCrashAnimation13, + kRogerCrashAnimation14, + kRogerCrashAnimation15, + kRogerCrashAnimation16, + kRogerCrashAnimation17, + kRogerCrashAnimation18, + kRogerCrashAnimation19, + // file 15 + kShipCorridorBackground, + kShipCorridorCockpitDoorOpen, + kShipCorridorSleepCabinDoorAnimation1, + kShipCorridorSleepCabinDoorAnimation2, + kShipCorridorSleepCabinDoorAnimation3, + kShipCorridorDummy1, + // file 16 + kAxacussCorridorTileWalled, + kAxacussCorridorToLeft, + kAxacussCorridorToRight, + kAxacussCorridorToTop, + kAxacussCorridorToBottom, + kAxacussCorridorTile, + kAxacussCorridorDoorClosed, + kAxacussCorridorDoorOpen, + kAxacussCorridorDesk, + kAxacussCorridorLaptop, + kAxacussCorridorStuff10, + kAxacussCorridorStuff11, + kAxacussCorridorStuff12, + kAxacussCorridorStuff13, + kAxacussCorridorStuff14, + kAxacussCorridorStuff15, + kAxacussCorridorStuff16, + kAxacussCorridorStuff17, + kAxacussCorridorStuff18, + kAxacussCorridorStuff19, + kAxacussCorridorStuff21, + kAxacussCorridorStuff22, + kAxacussCorridorStuff23, + kAxacussCorridorStuff24, + kAxacussCorridorStuff25, + kAxacussCorridorStuff26, + kAxacussCorridorStuff27, + kAxacussCorridorStuff28, + kAxacussCorridorAlarmStatus, + kAxacussCorridorAlienRight, + kAxacussCorridorAlienLeft, + kAxacussCorridorAlienBottom, + kAxacussCorridorAlienTop, + kAxacussCorridorDummy1, + // file 17 + kShipCorridorCabinBackground, + kShipCorridorCabinL1Open, + kShipCorridorCabinL2Open, + kShipCorridorCabinL3Open, + kShipCorridorCabinR1Open, + kShipCorridorCabinR2Open, + kShipCorridorCabinR3Open, + kShipCorridorCabinAirlockDoorAnimation1, + kShipCorridorCabinAirlockDoorAnimation2, + kShipCorridorCabinAirlockDoorAnimation3, + kShipCorridorCabinDummy1, + kShipCorridorCabinDummy2, + kShipCorridorCabinDummy3, + kShipCorridorCabinDummy4, + kShipCorridorCabinDummy5, + kShipCorridorCabinDummy6, + // file 18 + kShipGeneratorBackground, + kShipGeneratorHatchOpen, + kShipGeneratorJunctionBoxOpen, + kShipGeneratorJunctionBoxOffline, + kShipGeneratorJunctionBoxDisplay, + kShipGeneratorKeycard, + kShipGeneratorSpoolFloating, + kShipGeneratorSpoolOnGround, + kShipGeneratorCableUnplugged, + kShipGeneratorCablePluggedIn, + kShipGeneratorHatchRocks, + kShipGeneratorRopeRocks, + kShipGeneratorRopeSpace, + kShipGeneratorRopeFloor, + kShipGeneratorDummy1, + kShipGeneratorDummy2, + kShipGeneratorDummy3, + kShipGeneratorDummy4, + kShipGeneratorDummy5, + kShipGeneratorDummy6, + kShipGeneratorDummy7, + kShipGeneratorDummy8, + // file 19 + kRogerShipBackground, + kRogerShipButtonPressed1, + kRogerShipButtonPressed2, + kRogerShipButtonPressed3, + kRogerShipButtonPressed4, + kRogerShipCardInSlot, + kRogerShipCompartmentOpen, + kRogerShipUnknown7, + kRogerShipDisplayLeftOn, + kRogerShipGreenDisplayAnimation1, + kRogerShipGreenDisplayAnimation2, + kRogerShipGreenDisplayAnimation3, + kRogerShipGreenDisplayAnimation4, + kRogerShipGreenDisplayAnimation5, + kRogerShipGreenDisplayAnimation6, + kRogerShipGreenDisplayAnimation7, + kRogerShipBlueDisplayAnimation1, + kRogerShipBlueDisplayAnimation2, + kRogerShipBlueDisplayAnimation3, + kRogerShipBlueDisplayAnimation4, + kRogerShipBlueDisplayAnimation5, + kRogerShipBlueDisplayAnimation6, + kRogerShipBlueDisplayAnimation7, + kRogerShipUnknown23, + kRogerShipDisplaySinewaveAnimation1, + kRogerShipDisplaySinewaveAnimation2, + kRogerShipDisplaySinewaveAnimation3, + kRogerShipDisplaySinewaveAnimation4, + kRogerShipDisplaySinewaveAnimation5, + kRogerShipDisplaySinewaveAnimation6, + kRogerShipDisplaySinewaveAnimation7, + kRogerShipDisplaySinewaveAnimation8, + kRogerShipDisplaySinewaveAnimation9, + kRogerShipDisplaySinewaveAnimation10, + kRogerShipDisplaySinewaveAnimation11, + kRogerShipDisplaySinewaveAnimation12, + kRogerShipDisplaySinewaveAnimation13, + kRogerShipDisplaySinewaveAnimation14, + kRogerShipCompartmentContent, + kRogerShipDummy1, + kRogerShipDummy2, + // file 20 + kHelpScreen, + // file 21 + kShipCabinLeftBackground, + kShipCabinLeftPaintingSunset, + kShipCabinLeftPaintingLandscape, + kShipCabinLeftPaintingAbstract, + kShipCabinLeftTableStuff1, + kShipCabinLeftCeilingPencil, + kShipCabinLeft3Decoration, + kShipCabinLeftSocketPluggedIn, + kShipCabinLeftVinyl, + kShipCabinLeftTurntable, + kShipCabinLeftSocketUnplugged, + kShipCabinLeftTurntableCableCut, + kShipCabinLeftTurntableCable, + kShipCabinLeftTurntableAnimation1, + kShipCabinLeftTurntableAnimation2, + kShipCabinLeftTurntableAnimation3, + kShipCabinLeftTableStuff2, + kShipCabinLeftLockerOpen, + kShipCabinLeftLockerBooksOpen, + kShipCabinLeftLockerSpoolOpen, + kShipCabinLeftLockerPistolRemoved, + kShipCabinLeftLockerSpoolRemoved, + kShipCabinLeftBedSafeOpen, + kShipCabinLeftBedSafeEmpty, + kShipCabinLeftDoorClosed, + kShipCabinLeftTurntableCableSparks, + kShipCabinLeftTurntableCableCutEnd, + kShipCabinLeftDummy1, + kShipCabinLeftDummy2, + kShipCabinLeftDummy3, + kShipCabinLeftDummy4, + kShipCabinLeftDummy5, + kShipCabinLeftDummy6, + kShipCabinLeftDummy7, + kShipCabinLeftDummy8, + kShipCabinLeftDummy9, + kShipCabinLeftDummy10, + kShipCabinLeftDummy11, + kShipCabinLeftDummy12, + // file 22 + kShipCabinRightBackground, + kShipCabinRightPosterSnowman, + kShipCabinRightTableStuff, + kShipCabinRightCeilingChess, + kShipCabinRightTennisRacket, + kShipCabinRightTennisBallsFloating, + kShipCabinRightTennisBallsOnGround, + kShipCabinRightTableChess, + kShipCabinRight2Bed, + kShipCabinRightLockerBooksOpen, + kShipCabinRightLockerRopeOpen, + kShipCabinRightLockerOpen, + kShipCabinRightLockerRopeRemoved, + kShipCabinRightBedSafeOpen, + kShipCabinRightBedSafeEmpty, + kShipCabinRightDoorClosed, + kShipCabinRightLockerDiscmanRemoved, + kShipCabinRightDummy1, + kShipCabinRightDummy2, + // file 23 + kShipBathroomBackground, + // file 24 + kShipHoldBackgroundFloating, + kShipHoldBackgroundOnGround, + kShipHoldLandingModuleDoorOpen, + kShipHoldGeneratorHatchOpen, + kShipHoldLandingModuleSpool, + kShipHoldCableToGeneratorUnplugged, + kShipHoldCableToGeneratorPluggedIn, + kShipHoldDummy1, + kShipHoldDummy2, + // file 25 + kShipLandingModuleBackground, + kShipLandingModuleDoorClosed, + kShipLandingModuleDisplayLeftOn, + kShipLandingModuleCablePluggedIn, + kShipLandingModuleCableSpoolConnected, + kShipLandingModuleCableToHold, + kShipLandingModuleDisplayRightOn, + kShipLandingModuleDisplayTop1On, + kShipLandingModuleDisplayTop2On, + kShipLandingModuleDisplayTop3On, + kShipLandingModuleCableWithTerminalStrip, + kShipLandingModuleDummy1, + kShipLandingModuleDummy2, + kShipLandingModuleDummy3, + kShipLandingModuleDummy4, + kShipLandingModuleDummy5, + kShipLandingModuleDummy6, + kShipLandingModuleDummy7, + kShipLandingModuleDummy8, + // file 26 + kArsanoStar, + // file 27 + kSaveLoadScreen, + // file 28 + kRestaurantBackground, + kRestaurantAnimation1, + kRestaurantAnimation2, + kRestaurantAnimation3, + kRestaurantAnimation4, + kRestaurantAnimation5, + kRestaurantAnimation6, + kRestaurantAnimation7, + kRestaurantAnimation8, + kRestaurantAnimation9, + kRestaurantAnimation10, + kRestaurantAnimation11, + kRestaurantAnimation12, + kRestaurantAnimation13, + kRestaurantAnimation14, + kRestaurantAnimation15, + kRestaurantAnimation16, + kRestaurantAnimation17, + kRestaurantAnimation18, + kRestaurantAnimation19, + kRestaurantAnimation20, + kRestaurantAnimation21, + kRestaurantAnimation22, + // file 29 + kRestaurantRogerBackground, + kRestaurantRogerEyes1Closed, + kRestaurantRogerMouthOpen, + kRestaurantRogerPlayingChess, + kRestaurantRogerWalletRemoved, + kRestaurantRogerHandAnimation1, + kRestaurantRogerHandAnimation2, + kRestaurantRogerHandAnimation3, + kRestaurantRogerHandAnimation4, + kRestaurantRogerHandAnimation5, + kRestaurantRogerEyes2Closed, + kRestaurantRogerChessBoard, + kRestaurantRogerEyes2Open, + kRestaurantRogerDummy1, + // file 30 + kRogerOutsideBackground, + kRogerOutsideMouthOpen, + // file 31 + kIntroScreenBackground, + kIntroScreenShipAnimation1, + kIntroScreenShipAnimation2, + kIntroScreenShipAnimation3, + kIntroScreenShipAnimation4, + kIntroScreenShipAnimation5, + kIntroScreenShipAnimation6, + // file 32 + kBusStationSignBackground, + kBusStationSignPrice, + kBusStationSignPleaseWait, + kBusStationSignPleasantFlight, + // file 33 + kShipSleepCabinBackground, + kShipSleepCabinTerminalWarning, + kShipSleepCabinTerminal1, + kShipSleepCabinTerminal2, + kShipSleepCabinStatusLight, + kShipSleepCabinTerminal3, + // file 34 + kShipAirlockBackground, + kShipAirlockDoorLeftAnimation1, + kShipAirlockDoorLeftAnimation2, + kShipAirlockDoorLeftAnimation3, + kShipAirlockDoorRightAnimation1, + kShipAirlockDoorRightAnimation2, + kShipAirlockDoorRightAnimation3, + kShipAirlockHelmetRemoved, + kShipAirlockSpacesuitRemoved, + kShipAirlockSupplyRemoved, + kShipAirlockDoorLeftButton, + kShipAirlockDoorRightButton, + kShipAirlockManometerAnimation1, + kShipAirlockManometerAnimation2, + kShipAirlockManometerAnimation3, + kShipAirlockManometerAnimation4, + kShipAirlockManometerAnimation5, + kShipAirlockManometerAnimation6, + // file 35 + kAxacussSpaceBackground, + kAxacussSpaceShipAnimation1, + kAxacussSpaceShipAnimation2, + kAxacussSpaceShipAnimation3, + kAxacussSpaceShipAnimation4, + kAxacussSpaceShipAnimation5, + kAxacussSpaceShipAnimation6, + kAxacussSpaceShipAnimation7, + kAxacussSpaceBusAnimation1, + kAxacussSpaceBusAnimation2, + kAxacussSpaceBusAnimation3, + kAxacussSpaceBusAnimation4, + kAxacussSpaceBusAnimation5, + kAxacussSpaceBusAnimation6, + kAxacussSpaceBusAnimation7, + kAxacussSpaceBusAnimation8, + kAxacussSpaceBusAnimation9, + kAxacussSpaceBusAnimation10, + kAxacussSpaceBusAnimation11, + kAxacussSpaceBusAnimation12, + kAxacussSpaceBusAnimation13, + kAxacussSpaceBusAnimation14, + // file 36 + kAxacussanCapsuleBackground, + kAxacussanCapsuleRobotAnimation1, + kAxacussanCapsuleRobotAnimation2, + kAxacussanCapsuleRobotAnimation3, + kAxacussanCapsuleRobotAnimation4, + kAxacussanCapsuleDummy1, + // file 37 + kArsanoMeetupBackground, + kArsanoMeetupRestaurantLightAnimation1, + kArsanoMeetupRestaurantLightAnimation2, + kArsanoMeetupRestaurantLightAnimation3, + kArsanoMeetupRestaurantLightAnimation4, + kArsanoMeetupRestaurantLightAnimation5, + kArsanoMeetupRestaurantDoorAnimation1, + kArsanoMeetupRestaurantDoorAnimation2, + kArsanoMeetupRestaurantDoorSignAnimation1, + kArsanoMeetupRestaurantDoorSignAnimation2, + kArsanoMeetupRestaurantDoorSignAnimation3, + kArsanoMeetupRestaurantDoorSignAnimation4, + kArsanoMeetupRestaurantDoorSignAnimation5, + kArsanoMeetupRestaurantSignAnimation1, + kArsanoMeetupRestaurantSignAnimation2, + kArsanoMeetupRestaurantSignAnimation3, + kArsanoMeetupRestaurantSignAnimation4, + kArsanoMeetupRestaurantSignAnimation5, + kArsanoMeetupRestaurantSignAnimation6, + kArsanoMeetupRestaurantSignAnimation7, + kArsanoMeetupRestaurantSignAnimation8, + kArsanoMeetupRestaurantSignAnimation9, + kArsanoMeetupRestaurantSignAnimation10, + kArsanoMeetupRestaurantSignAnimation11, + kArsanoMeetupRestaurantSignAnimation12, + kArsanoMeetupRestaurantSignAnimation13, + kArsanoMeetupRestaurantSignAnimation14, + // file 38 + kArsanoAfterNovaBackground, + kArsanoAfterNovaRogerShipAnimation1, + kArsanoAfterNovaRogerShipAnimation2, + kArsanoAfterNovaRogerShipAnimation3, + kArsanoAfterNovaRogerShipAnimation4, + kArsanoAfterNovaRogerShipAnimation5, + kArsanoAfterNovaRogerShipAnimation6, + kArsanoAfterNovaRogerShipAnimation7, + kArsanoAfterNovaRogerShipAnimation8, + kArsanoAfterNovaRogerShipAnimation9, + kArsanoAfterNovaRogerShipAnimation10, + kArsanoAfterNovaRogerShipAnimation11, + kArsanoAfterNovaRoger, + // file 39 + kArsanoDesolate, + // file 40 + kIntersectionBackground, + kIntersectionGuardRemoved, + kIntersectionGuardMouthOpen, + kIntersectionGuardShootAnimation1, + kIntersectionGuardShootAnimation2, + kIntersectionGuardMouthClosed, + kIntersectionDoorOpen, + kIntersectoinKeycard, + // file 41 + kInformationDeskBackground, + kInformationDeskAlienMouthOpen, + kInformationDeskAlienHandMoved, + kInformationDeskAlienShoot, + // file 42 + kArtGalleryBackground, + kArtGalleryAlienShootAnimation1, + kArtGalleryAlienShootAnimation2, + kArtGalleryAlienShootAnimation3, + kArtGalleryThrowingBlockAnimation1, + kArtGalleryThrowingBlockAnimation2, + kArtGalleryThrowingBlockAnimation3, + kArtGalleryThrowingBlockAnimation4, + kArtGalleryThrowingBlockAnimation5, + kArtGalleryThrowingBlockAnimation6, + kArtGalleryThrowingBlockAnimation7, + kArtGalleryDummy1, + // file 43 + kCellBackground, + kCellCablePluggedIn, + kCellCableUnplugged, + kCellCableCutUnplugged, + kCellCableCutPluggedIn, + kCellCableCutTableUnplugged, + kCellCableCutTablePluggedIn, + kCellTableTablet, + kCellRobotComesAnimation1, + kCellRobotComesAnimation2, + kCellRobotComesAnimation3, + kCellRobotComesAnimation4, + kCellRobotComesAnimation5, + kCellRobotComesAnimation6, + kCellRobotComesAnimation7, + kCellRobotComesAnimation8, + kCellRobotComesAnimation9, + kCellRobotComesAnimation10, + kCellRobotComesAnimation11, + kCellRobotLeavesAnimation1, + kCellRobotLeavesAnimation2, + kCellRobotLeavesAnimation3, + kCellRobotLeavesAnimation4, + kCellRobotLeavesAnimation5, + kCellRobotLeavesAnimation6, + kCellRobotLeavesAnimation7, + kCellRobotLeavesAnimation8, + kCellRobotLeavesAnimation9, + kCellRobotSparks, + kCellRobotBroken, + kCellDoorClosed, + kCellDummy1 +}; + +} + +#endif diff --git a/engines/supernova/module.mk b/engines/supernova/module.mk index 9baf196c7c..722a230cde 100644 --- a/engines/supernova/module.mk +++ b/engines/supernova/module.mk @@ -4,9 +4,12 @@ MODULE_OBJS := \ console.o \ detection.o \ graphics.o \ - supernova.o \ + resman.o \ rooms.o \ - state.o + screen.o \ + sound.o \ + state.o \ + supernova.o MODULE_DIRS += \ engines/supernova diff --git a/engines/supernova/msn_def.h b/engines/supernova/msn_def.h index c18baa068c..6ce16b8283 100644 --- a/engines/supernova/msn_def.h +++ b/engines/supernova/msn_def.h @@ -25,10 +25,6 @@ namespace Supernova { -const int kScreenWidth = 320; -const int kScreenHeight = 200; -const int kFontWidth = 5; -const int kFontHeight = 8; const int kTextSpeed[] = {19, 14, 10, 7, 4}; const int kMsecPerTick = 55; @@ -50,266 +46,6 @@ enum MessagePosition { kMessageTop }; -enum AudioIndex { - kAudioFoundLocation, // 44|0 - kAudioCrash, // 45|0 - kAudioVoiceHalt, // 46|0 - kAudioGunShot, // 46|2510 - kAudioSmash, // 46|4020 - kAudioVoiceSupernova, // 47|0 - kAudioVoiceYeah, // 47|24010 - kAudioRobotShock, // 48|0 - kAudioRobotBreaks, // 48|2510 - kAudioShock, // 48|10520 - kAudioTurntable, // 48|13530 - kAudioSiren, // 50|0 - kAudioSnoring, // 50|12786 - kAudioRocks, // 51|0 - kAudioDeath, // 53|0 - kAudioAlarm, // 54|0 - kAudioSuccess, // 54|8010 - kAudioSlideDoor, // 54|24020 - kAudioDoorOpen, // 54|30030 - kAudioDoorClose, // 54|31040 - kAudioNumSamples -}; - -enum MusicIndex { - kMusicIntro = 52, - kMusicOutro = 49 -}; - -struct AudioInfo { - int _filenumber; - int _offsetStart; - int _offsetEnd; -}; - -const int kColorBlack = 0; -const int kColorWhite25 = 1; -const int kColorWhite35 = 2; -const int kColorWhite44 = 3; -const int kColorWhite99 = 4; -const int kColorDarkGreen = 5; -const int kColorGreen = 6; -const int kColorDarkRed = 7; -const int kColorRed = 8; -const int kColorDarkBlue = 9; -const int kColorBlue = 10; -const int kColorWhite63 = 11; -const int kColorLightBlue = 12; -const int kColorLightGreen = 13; -const int kColorLightYellow = 14; -const int kColorLightRed = 15; -const int kColorCursorTransparent = kColorWhite25; - -const byte mouseNormal[64] = { - 0xff,0x3f,0xff,0x1f,0xff,0x0f,0xff,0x07, - 0xff,0x03,0xff,0x01,0xff,0x00,0x7f,0x00, - 0x3f,0x00,0x1f,0x00,0x0f,0x00,0x0f,0x00, - 0xff,0x00,0x7f,0x18,0x7f,0x38,0x7f,0xfc, - - 0x00,0x00,0x00,0x40,0x00,0x60,0x00,0x70, - 0x00,0x78,0x00,0x7c,0x00,0x7e,0x00,0x7f, - 0x80,0x7f,0xc0,0x7f,0xe0,0x7f,0x00,0x7e, - 0x00,0x66,0x00,0x43,0x00,0x03,0x00,0x00 -}; - -const byte mouseWait[64] = { - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80, - 0x01,0x80,0x01,0x80,0x11,0x88,0x31,0x8c, - 0x31,0x8c,0x11,0x88,0x01,0x80,0x01,0x80, - 0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0xfe,0x7f,0xf4,0x2f,0xf4,0x2f, - 0x14,0x28,0x24,0x24,0x44,0x22,0x84,0x21, - 0x84,0x21,0xc4,0x23,0xe4,0x27,0x74,0x2e, - 0x34,0x2c,0x14,0x28,0xfe,0x7f,0x00,0x00 -}; - -const byte font[][5] = { - {0x00,0x00,0x00,0xff,0x00}, - {0x5f,0xff,0x00,0x00,0x00}, - {0x03,0x00,0x03,0xff,0x00}, - {0x14,0x7f,0x14,0x7f,0x14}, - {0x24,0x2a,0x7f,0x2a,0x12}, - {0x61,0x10,0x08,0x04,0x43}, - {0x38,0x4e,0x59,0x26,0x50}, - {0x03,0xff,0x00,0x00,0x00}, - {0x3e,0x41,0xff,0x00,0x00}, - {0x41,0x3e,0xff,0x00,0x00}, - {0x10,0x54,0x38,0x54,0x10}, - {0x10,0x10,0x7c,0x10,0x10}, - {0x80,0x40,0xff,0x00,0x00}, - {0x10,0x10,0x10,0x10,0x10}, - {0x40,0xff,0x00,0x00,0x00}, - {0x60,0x10,0x08,0x04,0x03}, - - {0x3e,0x41,0x41,0x41,0x3e}, /* digits */ - {0x04,0x02,0x7f,0xff,0x00}, - {0x42,0x61,0x51,0x49,0x46}, - {0x22,0x41,0x49,0x49,0x36}, - {0x18,0x14,0x12,0x7f,0x10}, - {0x27,0x45,0x45,0x45,0x39}, - {0x3e,0x49,0x49,0x49,0x32}, - {0x01,0x61,0x19,0x07,0x01}, - {0x36,0x49,0x49,0x49,0x36}, - {0x26,0x49,0x49,0x49,0x3e}, - - {0x44,0xff,0x00,0x00,0x00}, - {0x80,0x44,0xff,0x00,0x00}, - {0x10,0x28,0x44,0xff,0x00}, - {0x28,0x28,0x28,0x28,0x28}, - {0x44,0x28,0x10,0xff,0x00}, - {0x02,0x01,0x51,0x09,0x06}, - {0x3e,0x41,0x5d,0x5d,0x1e}, - - {0x7c,0x12,0x11,0x12,0x7c}, /* uppercase letters*/ - {0x7f,0x49,0x49,0x49,0x36}, - {0x3e,0x41,0x41,0x41,0x22}, - {0x7f,0x41,0x41,0x22,0x1c}, - {0x7f,0x49,0x49,0x49,0xff}, - {0x7f,0x09,0x09,0x09,0xff}, - {0x3e,0x41,0x41,0x49,0x3a}, - {0x7f,0x08,0x08,0x08,0x7f}, - {0x41,0x7f,0x41,0xff,0x00}, - {0x20,0x40,0x40,0x3f,0xff}, - {0x7f,0x08,0x14,0x22,0x41}, - {0x7f,0x40,0x40,0x40,0xff}, - {0x7f,0x02,0x04,0x02,0x7f}, - {0x7f,0x02,0x0c,0x10,0x7f}, - {0x3e,0x41,0x41,0x41,0x3e}, - {0x7f,0x09,0x09,0x09,0x06}, - {0x3e,0x41,0x51,0x21,0x5e}, - {0x7f,0x09,0x19,0x29,0x46}, - {0x26,0x49,0x49,0x49,0x32}, - {0x01,0x01,0x7f,0x01,0x01}, - {0x3f,0x40,0x40,0x40,0x3f}, - {0x07,0x18,0x60,0x18,0x07}, - {0x1f,0x60,0x18,0x60,0x1f}, - {0x63,0x14,0x08,0x14,0x63}, - {0x03,0x04,0x78,0x04,0x03}, - {0x61,0x51,0x49,0x45,0x43}, - - {0x7f,0x41,0x41,0xff,0x00}, - {0x03,0x04,0x08,0x10,0x60}, - {0x41,0x41,0x7f,0xff,0x00}, - {0x02,0x01,0x02,0xff,0x00}, - {0x80,0x80,0x80,0x80,0x80}, - {0x01,0x02,0xff,0x00,0x00}, - - {0x38,0x44,0x44,0x44,0x7c}, /* lowercase letters */ - {0x7f,0x44,0x44,0x44,0x38}, - {0x38,0x44,0x44,0x44,0x44}, - {0x38,0x44,0x44,0x44,0x7f}, - {0x38,0x54,0x54,0x54,0x58}, - {0x04,0x7e,0x05,0x01,0xff}, - {0x98,0xa4,0xa4,0xa4,0x7c}, - {0x7f,0x04,0x04,0x04,0x78}, - {0x7d,0xff,0x00,0x00,0x00}, - {0x80,0x80,0x7d,0xff,0x00}, - {0x7f,0x10,0x28,0x44,0xff}, - {0x7f,0xff,0x00,0x00,0x00}, - {0x7c,0x04,0x7c,0x04,0x78}, - {0x7c,0x04,0x04,0x04,0x78}, - {0x38,0x44,0x44,0x44,0x38}, - {0xfc,0x24,0x24,0x24,0x18}, - {0x18,0x24,0x24,0x24,0xfc}, - {0x7c,0x08,0x04,0x04,0xff}, - {0x48,0x54,0x54,0x54,0x24}, - {0x04,0x3e,0x44,0x40,0xff}, - {0x7c,0x40,0x40,0x40,0x3c}, - {0x0c,0x30,0x40,0x30,0x0c}, - {0x3c,0x40,0x3c,0x40,0x3c}, - {0x44,0x28,0x10,0x28,0x44}, - {0x9c,0xa0,0xa0,0xa0,0x7c}, - {0x44,0x64,0x54,0x4c,0x44}, - - {0x08,0x36,0x41,0xff,0x00}, - {0x77,0xff,0x00,0x00,0x00}, - {0x41,0x36,0x08,0xff,0x00}, - {0x02,0x01,0x02,0x01,0xff}, - {0xff,0x00,0x00,0x00,0x00}, - - {0xfe,0x49,0x49,0x4e,0x30}, /* sharp S */ - - {0x7c,0x41,0x40,0x41,0x3c}, /* umlauts */ - - {0x04,0x06,0x7f,0x06,0x04}, /* arrows */ - {0x20,0x60,0xfe,0x60,0x20}, - - {0x38,0x45,0x44,0x45,0x7c}, /* umlauts */ - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0x79,0x14,0x12,0x14,0x79}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0x38,0x45,0x44,0x45,0x38}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0xff,0x00,0x00,0x00,0x00}, - {0x3d,0x42,0x42,0x42,0x3d}, - {0x3d,0x40,0x40,0x40,0x3d}, -}; - -// Default palette -const byte initVGAPalette[768] = { - 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x58, 0x58, 0x70, 0x70, 0x70, 0xfc, 0xfc, 0xfc, 0x00, 0xd0, 0x00, - 0x00, 0xfc, 0x00, 0xd8, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0xb0, 0xa0, 0xa0, 0xa0, - 0x50, 0xc8, 0xfc, 0x28, 0xfc, 0x28, 0xf0, 0xf0, 0x00, 0xfc, 0x28, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, - 0x20, 0x20, 0x20, 0x2c, 0x2c, 0x2c, 0x38, 0x38, 0x38, 0x44, 0x44, 0x44, 0x50, 0x50, 0x50, 0x60, 0x60, 0x60, - 0x70, 0x70, 0x70, 0x80, 0x80, 0x80, 0x90, 0x90, 0x90, 0xa0, 0xa0, 0xa0, 0xb4, 0xb4, 0xb4, 0xc8, 0xc8, 0xc8, - 0xe0, 0xe0, 0xe0, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, - 0xfc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, - 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, - 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, - 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, - 0xfc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, - 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, - 0x7c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, - 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, - 0xfc, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, - 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, - 0xb4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, - 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, - 0x70, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, - 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, - 0x00, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, - 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, - 0x70, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, - 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, - 0x38, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, - 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, - 0x70, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, - 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, - 0x50, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, - 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, - 0x40, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, - 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, - 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, - 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, - 0x40, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, - 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, - 0x20, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, - 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, - 0x40, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, - 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, - 0x2c, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, - 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - enum ObjectType { NULLTYPE = 0, TAKE = 1, @@ -341,7 +77,7 @@ enum Action { ACTION_GIVE }; -enum RoomID { +enum RoomId { INTRO,CORRIDOR,HALL,SLEEP,COCKPIT,AIRLOCK, HOLD,LANDINGMODULE,GENERATOR,OUTSIDE, CABIN_R1,CABIN_R2,CABIN_R3,CABIN_L1,CABIN_L2,CABIN_L3,BATHROOM, @@ -353,7 +89,7 @@ enum RoomID { ELEVATOR,STATION,SIGN,OUTRO,NUMROOMS,NULLROOM }; -enum ObjectID { +enum ObjectId { INVALIDOBJECT = -1, NULLOBJECT = 0, KEYCARD,KNIFE,WATCH, @@ -397,7 +133,7 @@ enum ObjectID { JUNGLE,STATION_SLOT,STATION_SIGN }; -enum StringID { +enum StringId { kNoString = -1, // 0 kStringCommandGo = 0, kStringCommandLook, kStringCommandTake, kStringCommandOpen, kStringCommandClose, @@ -568,8 +304,6 @@ ObjectType &operator&=(ObjectType &a, ObjectType b); ObjectType &operator^=(ObjectType &a, ObjectType b); struct Object { - static const Object nullObject; - Object() : _name(kNoString) , _description(kStringDefaultDescription) @@ -582,8 +316,8 @@ struct Object { , _exitRoom(NULLROOM) , _direction(0) {} - Object(byte roomId, StringID name, StringID description, ObjectID id, ObjectType type, - byte click, byte click2, byte section = 0, RoomID exitRoom = NULLROOM, byte direction = 0) + Object(byte roomId, StringId name, StringId description, ObjectId id, ObjectType type, + byte click, byte click2, byte section = 0, RoomId exitRoom = NULLROOM, byte direction = 0) : _name(name) , _description(description) , _id(id) @@ -596,12 +330,6 @@ struct Object { , _direction(direction) {} - static void setObjectNull(Object *&obj) { - obj = const_cast<Object *>(&nullObject); - } - static bool isNullObject(Object *obj) { - return obj == &nullObject; - } void resetProperty(ObjectType type = NULLTYPE) { _type = type; } @@ -618,7 +346,7 @@ struct Object { return _type & type; } - static bool combine(Object &obj1, Object &obj2, ObjectID id1, ObjectID id2) { + static bool combine(Object &obj1, Object &obj2, ObjectId id1, ObjectId id2) { if (obj1.hasProperty(COMBINABLE)) return (((obj1._id == id1) && (obj2._id == id2)) || ((obj1._id == id2) && (obj2._id == id1))); @@ -627,14 +355,14 @@ struct Object { } byte _roomId; - StringID _name; - StringID _description; - ObjectID _id; + StringId _name; + StringId _description; + ObjectId _id; ObjectTypes _type; byte _click; byte _click2; byte _section; - RoomID _exitRoom; + RoomId _exitRoom; byte _direction; }; diff --git a/engines/supernova/resman.cpp b/engines/supernova/resman.cpp new file mode 100644 index 0000000000..1c178846ed --- /dev/null +++ b/engines/supernova/resman.cpp @@ -0,0 +1,395 @@ +/* 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 2 +* 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, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "audio/audiostream.h" +#include "audio/decoders/raw.h" +#include "audio/mixer.h" +#include "audio/mods/protracker.h" +#include "common/memstream.h" +#include "common/system.h" +#include "graphics/cursorman.h" +#include "graphics/palette.h" + +#include "supernova/graphics.h" +#include "supernova/resman.h" +#include "supernova/screen.h" +#include "supernova/supernova.h" + +namespace Supernova { + +struct AudioInfo { + int _filenumber; + int _offsetStart; + int _offsetEnd; +}; + +static Common::MemoryReadStream *convertToMod(const char *filename, int version = 1); + +static const AudioInfo audioInfo[kAudioNumSamples] = { + {44, 0, -1}, + {45, 0, -1}, + {46, 0, 2510}, + {46, 2510, 4020}, + {46, 4020, -1}, + {47, 0, 24010}, + {47, 24010, -1}, + {48, 0, 2510}, + {48, 2510, 10520}, + {48, 10520, 13530}, + {48, 13530, -1}, + {50, 0, 12786}, + {50, 12786, -1}, + {51, 0, -1}, + {53, 0, -1}, + {54, 0, 8010}, + {54, 8010, 24020}, + {54, 24020, 30030}, + {54, 30030, 31040}, + {54, 31040, -1} +}; + +static const byte mouseNormal[64] = { + 0xff,0x3f,0xff,0x1f,0xff,0x0f,0xff,0x07, + 0xff,0x03,0xff,0x01,0xff,0x00,0x7f,0x00, + 0x3f,0x00,0x1f,0x00,0x0f,0x00,0x0f,0x00, + 0xff,0x00,0x7f,0x18,0x7f,0x38,0x7f,0xfc, + + 0x00,0x00,0x00,0x40,0x00,0x60,0x00,0x70, + 0x00,0x78,0x00,0x7c,0x00,0x7e,0x00,0x7f, + 0x80,0x7f,0xc0,0x7f,0xe0,0x7f,0x00,0x7e, + 0x00,0x66,0x00,0x43,0x00,0x03,0x00,0x00 +}; + +static const byte mouseWait[64] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80, + 0x01,0x80,0x01,0x80,0x11,0x88,0x31,0x8c, + 0x31,0x8c,0x11,0x88,0x01,0x80,0x01,0x80, + 0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00, + + 0x00,0x00,0xfe,0x7f,0xf4,0x2f,0xf4,0x2f, + 0x14,0x28,0x24,0x24,0x44,0x22,0x84,0x21, + 0x84,0x21,0xc4,0x23,0xe4,0x27,0x74,0x2e, + 0x34,0x2c,0x14,0x28,0xfe,0x7f,0x00,0x00 +}; + + +ResourceManager::ResourceManager() + : _audioRate(11931) { + initSoundFiles(); + initGraphics(); +} + +void ResourceManager::initSoundFiles() { + // Sound + // Note: + // - samples start with a header of 6 bytes: 01 SS SS 00 AD 00 + // where SS SS (LE uint16) is the size of the sound sample + 2 + // - samples end with a footer of 4 bytes: 00 00 + // Skip those in the buffer + Common::File file; + + for (int i = 0; i < kAudioNumSamples; ++i) { + if (!file.open(Common::String::format("msn_data.%03d", audioInfo[i]._filenumber))) { + error("File %s could not be read!", file.getName()); + } + + int length = 0; + byte *buffer = nullptr; + + if (audioInfo[i]._offsetEnd == -1) { + file.seek(0, SEEK_END); + length = file.pos() - audioInfo[i]._offsetStart - 10; + } else { + length = audioInfo[i]._offsetEnd - audioInfo[i]._offsetStart - 10; + } + buffer = new byte[length]; + file.seek(audioInfo[i]._offsetStart + 6); + file.read(buffer, length); + file.close(); + + byte streamFlag = Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN; + _soundSamples[i].reset(Audio::makeRawStream(buffer, length, _audioRate, + streamFlag, DisposeAfterUse::YES)); + } + + _musicIntroBuffer.reset(convertToMod("msn_data.052")); + _musicOutroBuffer.reset(convertToMod("msn_data.049")); +} + +void ResourceManager::initGraphics() { + Screen::initPalette(); + initCursorGraphics(); + initImages(); +} + +void ResourceManager::initCursorGraphics() { + const uint16 *bufferNormal = reinterpret_cast<const uint16 *>(mouseNormal); + const uint16 *bufferWait = reinterpret_cast<const uint16 *>(mouseWait); + for (uint i = 0; i < sizeof(mouseNormal) / 4; ++i) { + for (uint bit = 0; bit < 16; ++bit) { + uint mask = 0x8000 >> bit; + uint bitIndex = i * 16 + bit; + + _cursorNormal[bitIndex] = (READ_LE_UINT16(bufferNormal + i) & mask) ? + kColorCursorTransparent : kColorBlack; + if (READ_LE_UINT16(bufferNormal + i + 16) & mask) + _cursorNormal[bitIndex] = kColorLightRed; + + _cursorWait[bitIndex] = (READ_LE_UINT16(bufferWait + i) & mask) ? + kColorCursorTransparent : kColorBlack; + if (READ_LE_UINT16(bufferWait + i + 16) & mask) + _cursorWait[bitIndex] = kColorLightRed; + } + } +} + +void ResourceManager::initImages() { + for (int i = 0; i < kNumImageFiles; ++i) { + if (!_images[i].init(i)) + error("Failed reading image file msn_data.%03d", i); + } +} + +Audio::SeekableAudioStream *ResourceManager::getSoundStream(AudioId index) { + Audio::SeekableAudioStream *stream = _soundSamples[index].get(); + stream->rewind(); + + return stream; +} + +Audio::AudioStream *ResourceManager::getSoundStream(MusicId index) { + switch (index) { + case kMusicIntro: + _musicIntro.reset(Audio::makeProtrackerStream(_musicIntroBuffer.get())); + return _musicIntro.get(); + case kMusicOutro: + _musicOutro.reset(Audio::makeProtrackerStream(_musicOutroBuffer.get())); + return _musicOutro.get(); + default: + error("Invalid music constant in playAudio()"); + } +} + +const MSNImage *ResourceManager::getImage(int filenumber) const { + assert(filenumber < kNumImageFiles); + + return &_images[filenumber]; +} + +const byte *ResourceManager::getImage(CursorId id) const { + switch (id) { + case kCursorNormal: + return _cursorNormal; + case kCursorWait: + return _cursorWait; + default: + return nullptr; + } +} + +static Common::MemoryReadStream *convertToMod(const char *filename, int version) { + // MSN format + struct { + uint16 seg; + uint16 start; + uint16 end; + uint16 loopStart; + uint16 loopEnd; + char volume; + char dummy[5]; + } instr2[22]; + int nbInstr2; // 22 for version1, 15 for version 2 + int16 songLength; + char arrangement[128]; + int16 patternNumber; + int32 note2[28][64][4]; + + nbInstr2 = ((version == 1) ? 22 : 15); + + Common::File msnFile; + msnFile.open(filename); + if (!msnFile.isOpen()) { + warning("Data file '%s' not found", msnFile.getName()); + return nullptr; + } + + for (int i = 0 ; i < nbInstr2 ; ++i) { + instr2[i].seg = msnFile.readUint16LE(); + instr2[i].start = msnFile.readUint16LE(); + instr2[i].end = msnFile.readUint16LE(); + instr2[i].loopStart = msnFile.readUint16LE(); + instr2[i].loopEnd = msnFile.readUint16LE(); + instr2[i].volume = msnFile.readByte(); + msnFile.read(instr2[i].dummy, 5); + } + songLength = msnFile.readSint16LE(); + msnFile.read(arrangement, 128); + patternNumber = msnFile.readSint16LE(); + for (int p = 0 ; p < patternNumber ; ++p) { + for (int n = 0 ; n < 64 ; ++n) { + for (int k = 0 ; k < 4 ; ++k) { + note2[p][n][k] = msnFile.readSint32LE(); + } + } + } + + /* MOD format */ + struct { + char iname[22]; + uint16 length; + char finetune; + char volume; + uint16 loopStart; + uint16 loopLength; + } instr[31]; + int32 note[28][64][4]; + + // We can't recover some MOD effects since several of them are mapped to 0. + // Assume the MSN effect of value 0 is Arpeggio (MOD effect of value 0). + const char invConvEff[8] = {0, 1, 2, 3, 10, 12, 13 ,15}; + + // Reminder from convertToMsn + // 31 30 29 28 27 26 25 24 - 23 22 21 20 19 18 17 16 - 15 14 13 12 11 10 09 08 - 07 06 05 04 03 02 01 00 + // h h h h g g g g f f f f e e e e d d d d c c c c b b b b a a a a + // + // MSN: + // hhhh (4 bits) Cleared to 0 + // dddd c (5 bits) Sample index | after mapping through convInstr + // ccc (3 bits) Effect type | after mapping through convEff + // bbbb aaaa (8 bits) Effect value | unmodified + // gggg ffff eeee (12 bits) Sample period | unmodified + // + // MS2: + // hhhh (4 bits) Cleared to 0 + // dddd (4 bits) Sample index | after mapping through convInstr + // cccc (4 bits) Effect type | unmodified + // bbbb aaaa (8 bits) Effect value | unmodified + // gggg ffff eeee (12 bits) Sample period | transformed (0xE000 / p) - 256 + // + // MOD: + // hhhh dddd (8 bits) Sample index + // cccc (4 bits) Effect type for this channel/division + // bbbb aaaa (8 bits) Effect value + // gggg ffff eeee (12 bits) Sample period + + // Can we recover the instruments mapping? I don't think so as part of the original instrument index is cleared. + // And it doesn't really matter as long as we are consistent. + // However we need to make sure 31 (or 15 in MS2) is mapped to 0 in MOD. + // We just add 1 to all other values, and this means a 1 <-> 1 mapping for the instruments + for (int p = 0; p < patternNumber; ++p) { + for (int n = 0; n < 64; ++n) { + for (int k = 0; k < 4; ++k) { + int32* l = &(note[p][n][k]); + *l = note2[p][n][k]; + int32 i = 0; + if (nbInstr2 == 22) { // version 1 + i = ((*l & 0xF800) >> 11); + int32 e = ((*l & 0x0700) >> 8); + int32 e1 = invConvEff[e]; + *l &= 0x0FFF00FF; + *l |= (e1 << 8); + } else { // version 2 + int32 h = (*l >> 16); + i = ((*l & 0xF000) >> 12); + *l &= 0x00000FFF; + if (h) + h = 0xE000 / (h + 256); + *l |= (h << 16); + if (i == 15) + i = 31; + } + + // Add back index in note + if (i != 31) { + ++i; + *l |= ((i & 0x0F) << 12); + *l |= ((i & 0xF0) << 24); + } + } + } + } + + for (int i = 0; i < 31; ++i) { + // iname is not stored in the mod file. Just set it to 'instrument#' + // finetune is not stored either. Assume 0. + memset(instr[i].iname, 0, 22); + sprintf(instr[i].iname, "instrument%d", i+1); + instr[i].length = 0; + instr[i].finetune = 0; + instr[i].volume = 0; + instr[i].loopStart = 0; + instr[i].loopLength = 0; + + if (i < nbInstr2) { + instr[i].length = ((instr2[i].end - instr2[i].start) >> 1); + instr[i].loopStart = ((instr2[i].loopStart - instr2[i].start) >> 1); + instr[i].loopLength = (( instr2[i].loopEnd - instr2[i].loopStart) >> 1); + instr[i].volume = instr2[i].volume; + } + } + + // The ciaaSpeed is kind of useless and not present in the MSN file. + // Traditionally 0x78 in SoundTracker. Was used in NoiseTracker as a restart point. + // ProTracker uses 0x7F. FastTracker uses it as a restart point, whereas ScreamTracker 3 uses 0x7F like ProTracker. + // You can use this to roughly detect which tracker made a MOD, and detection gets more accurate for more obscure MOD types. + char ciaaSpeed = 0x7F; + + // The mark cannot be recovered either. Since we have 4 channels and 31 instrument it can be either ID='M.K.' or ID='4CHN'. + // Assume 'M.K.' + const char mark[4] = { 'M', '.', 'K', '.' }; + + Common::MemoryWriteStreamDynamic buffer(DisposeAfterUse::NO); + + buffer.write(msnFile.getName(), 19); + buffer.writeByte(0); + + for (int i = 0 ; i < 31 ; ++i) { + buffer.write(instr[i].iname, 22); + buffer.writeUint16BE(instr[i].length); + buffer.writeByte(instr[i].finetune); + buffer.writeByte(instr[i].volume); + buffer.writeUint16BE(instr[i].loopStart); + buffer.writeUint16BE(instr[i].loopLength); + } + buffer.writeByte((char)songLength); + buffer.writeByte(ciaaSpeed); + buffer.write(arrangement, 128); + buffer.write(mark, 4); + + for (int p = 0 ; p < patternNumber ; ++p) { + for (int n = 0 ; n < 64 ; ++n) { + for (int k = 0 ; k < 4 ; ++k) { +// buffer.writeUint32BE(*((uint32*)(note[p][n]+k))); + buffer.writeSint32BE(note[p][n][k]); + } + } + } + + uint nb; + char buf[4096]; + while ((nb = msnFile.read(buf, 4096)) > 0) + buffer.write(buf, nb); + + return new Common::MemoryReadStream(buffer.getData(), buffer.size(), DisposeAfterUse::YES); +} + +} diff --git a/engines/supernova/resman.h b/engines/supernova/resman.h new file mode 100644 index 0000000000..080ecc5da4 --- /dev/null +++ b/engines/supernova/resman.h @@ -0,0 +1,77 @@ +/* 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 2 +* 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, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef SUPERNOVA_RESOURCES_H +#define SUPERNOVA_RESOURCES_H + +#include "audio/audiostream.h" +#include "common/ptr.h" + +#include "supernova/graphics.h" +#include "supernova/sound.h" + + +namespace Common { +class MemoryReadStream; +} + +namespace Supernova { + +class ResourceManager { +public: + enum CursorId { + kCursorNormal, + kCursorWait + }; + +public: + static const int kNumImageFiles = 44; + +public: + ResourceManager(); + + Audio::SeekableAudioStream *getSoundStream(AudioId index); + Audio::AudioStream *getSoundStream(MusicId index); + const MSNImage *getImage(int filenumber) const; + const byte *getImage(CursorId id) const; + +private: + void initSoundFiles(); + void initGraphics(); + void initCursorGraphics(); + void initImages(); + +private: + Common::ScopedPtr<Audio::SeekableAudioStream> _soundSamples[kAudioNumSamples]; + Common::ScopedPtr<Common::MemoryReadStream> _musicIntroBuffer; + Common::ScopedPtr<Common::MemoryReadStream> _musicOutroBuffer; + Common::ScopedPtr<Audio::AudioStream> _musicIntro; + Common::ScopedPtr<Audio::AudioStream> _musicOutro; + int _audioRate; + MSNImage _images[kNumImageFiles]; + byte _cursorNormal[256]; + byte _cursorWait[256]; +}; + +} + +#endif diff --git a/engines/supernova/rooms.cpp b/engines/supernova/rooms.cpp index 83147c1630..9360d58aa1 100644 --- a/engines/supernova/rooms.cpp +++ b/engines/supernova/rooms.cpp @@ -24,6 +24,7 @@ #include "graphics/palette.h" #include "graphics/cursorman.h" +#include "supernova/screen.h" #include "supernova/supernova.h" #include "supernova/state.h" @@ -79,15 +80,15 @@ bool Room::deserialize(Common::ReadStream *in, int version) { int numObjects = in->readSint32LE(); for (int i = 0; i < numObjects; ++i) { - _objectState[i]._name = static_cast<StringID>(in->readSint32LE()); - _objectState[i]._description = static_cast<StringID>(in->readSint32LE()); + _objectState[i]._name = static_cast<StringId>(in->readSint32LE()); + _objectState[i]._description = static_cast<StringId>(in->readSint32LE()); _objectState[i]._roomId = in->readByte(); - _objectState[i]._id = static_cast<ObjectID>(in->readSint32LE()); + _objectState[i]._id = static_cast<ObjectId>(in->readSint32LE()); _objectState[i]._type = static_cast<ObjectType>(in->readSint32LE()); _objectState[i]._click = in->readByte(); _objectState[i]._click2 = in->readByte(); _objectState[i]._section = in->readByte(); - _objectState[i]._exitRoom = static_cast<RoomID>(in->readSint32LE()); + _objectState[i]._exitRoom = static_cast<RoomId>(in->readSint32LE()); _objectState[i]._direction = in->readByte(); } @@ -147,102 +148,11 @@ void Intro::onEntrance() { leaveCutscene(); } -class Marquee { -public: - enum MarqueeIndex { - kMarqueeIntro, - kMarqueeOutro - }; - - Marquee(SupernovaEngine *vm, MarqueeIndex id, const char *text) - : _text(text) - , _textBegin(text) - , _delay(0) - , _color(kColorLightBlue) - , _loop(false) - , _vm(vm) - { - if (id == kMarqueeIntro) { - _y = 191; - _loop = true; - } else if (id == kMarqueeOutro) { - _y = 1; - } - _textWidth = _vm->textWidth(_text); - _x = kScreenWidth / 2 - _textWidth / 2; - _vm->_textCursorX = _x; - _vm->_textCursorY = _y; - _vm->_textColor = _color; - } - - void renderCharacter(); - -private: - void clearText(); - - SupernovaEngine *_vm; - MarqueeIndex _id; - const char *const _textBegin; - const char *_text; - bool _loop; - int _delay; - int _color; - int _x; - int _y; - int _textWidth; -}; - -void Marquee::clearText() { - _vm->renderBox(_x, _y - 1, _textWidth + 1, 9, kColorBlack); -} - -void Marquee::renderCharacter() { - if (_delay != 0) { - _delay--; - return; - } - - switch (*_text) { - case '\233': - if (_loop) { - _loop = false; - _text = _textBegin; - clearText(); - _textWidth = _vm->textWidth(_text); - _x = kScreenWidth / 2 - _textWidth / 2; - _vm->_textCursorX = _x; - } - break; - case '\0': - clearText(); - _text++; - _textWidth = _vm->textWidth(_text); - _x = kScreenWidth / 2 - _textWidth / 2; - _vm->_textCursorX = _x; - _color = kColorLightBlue; - _vm->_textColor = _color; - break; - case '^': - _color = kColorLightYellow; - _vm->_textColor = _color; - _text++; - break; - case '#': - _delay = 50; - _text++; - break; - default: - _vm->renderText((uint16)*_text++); - _delay = 1; - break; - } -} - void Intro::titleScreen() { // Newspaper CursorMan.showMouse(false); - _vm->_brightness = 0; - _vm->_menuBrightness = 0; + _vm->_screen->setViewportBrightness(0); + _vm->_screen->setGuiBrightness(0); _vm->paletteBrightness(); _vm->setCurrentImage(1); _vm->renderImage(0); @@ -254,25 +164,25 @@ void Intro::titleScreen() { _vm->setCurrentImage(31); _vm->renderImage(0); _vm->paletteFadeIn(); - _gm->wait2(1); + _gm->wait(1); _vm->playSound(kAudioVoiceSupernova); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - _gm->wait2(1); + while (_vm->_sound->isPlaying()) + _gm->wait(1); titleFadeIn(); _vm->renderText(kStringTitleVersion, 295, 190, kColorWhite44); const Common::String& title1 = _vm->getGameString(kStringTitle1); const Common::String& title2 = _vm->getGameString(kStringTitle2); const Common::String& title3 = _vm->getGameString(kStringTitle3); - _vm->renderText(title1, 78 - _vm->textWidth(title1) / 2, 120, kColorLightBlue); - _vm->renderText(title2, 78 - _vm->textWidth(title2) / 2, 132, kColorWhite99); - _vm->renderText(title3, 78 - _vm->textWidth(title3) / 2, 142, kColorWhite99); - _gm->wait2(1); + _vm->_screen->renderText(title1, 78 - Screen::textWidth(title1) / 2, 120, kColorLightBlue); + _vm->_screen->renderText(title2, 78 - Screen::textWidth(title2) / 2, 132, kColorWhite99); + _vm->_screen->renderText(title3, 78 - Screen::textWidth(title3) / 2, 142, kColorWhite99); + _gm->wait(1); CursorMan.showMouse(true); - _vm->playSoundMod(kMusicIntro); + _vm->playSound(kMusicIntro); - Marquee marquee(_vm, Marquee::kMarqueeIntro, _introText.c_str()); + Marquee marquee(_vm->_screen, Marquee::kMarqueeIntro, _introText.c_str()); while (!_vm->shouldQuit()) { - _vm->updateEvents(); + _gm->updateEvents(); marquee.renderCharacter(); if (_gm->_mouseClicked || _gm->_keyPressed) break; @@ -280,8 +190,8 @@ void Intro::titleScreen() { g_system->delayMillis(_vm->_delay); } _vm->playSound(kAudioVoiceYeah); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - _gm->wait2(1); + while (_vm->_sound->isPlaying()) + _gm->wait(1); _vm->paletteFadeOut(); } @@ -319,7 +229,7 @@ bool Intro::animate(int section1, int section2, int duration) { } bool Intro::animate(int section1, int section2, int duration, - MessagePosition position, StringID textId) { + MessagePosition position, StringId textId) { Common::KeyCode key = Common::KEYCODE_INVALID; const Common::String& text = _vm->getGameString(textId); _vm->renderMessage(text, position); @@ -344,7 +254,7 @@ bool Intro::animate(int section1, int section2, int duration, } bool Intro::animate(int section1, int section2, int section3, int section4, - int duration, MessagePosition position, StringID textId) { + int duration, MessagePosition position, StringId textId) { Common::KeyCode key = Common::KEYCODE_INVALID; const Common::String& text = _vm->getGameString(textId); _vm->renderMessage(text, position); @@ -381,11 +291,11 @@ void Intro::cutscene() { _vm->_system->fillScreen(kColorBlack); _vm->setCurrentImage(31); - _vm->_menuBrightness = 255; + _vm->_screen->setGuiBrightness(255); _vm->paletteBrightness(); if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene1)) return; - _vm->_menuBrightness = 0; + _vm->_screen->setGuiBrightness(0); _vm->paletteBrightness(); exitOnEscape(1); @@ -423,7 +333,7 @@ void Intro::cutscene() { exitOnEscape(28); _vm->removeMessage(); - StringID textCounting[4] = + StringId textCounting[4] = {kStringIntroCutscene7, kStringIntroCutscene8, kStringIntroCutscene9, kStringIntroCutscene10}; _vm->setCurrentImage(31); _vm->renderImage(0); @@ -527,15 +437,15 @@ void Intro::cutscene() { return; _vm->paletteFadeOut(); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) + while (_vm->_sound->isPlaying()) exitOnEscape(1); _vm->_system->fillScreen(kColorBlack); - _vm->_menuBrightness = 255; + _vm->_screen->setGuiBrightness(255); _vm->paletteBrightness(); if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene25)) return; - _vm->_menuBrightness = 5; + _vm->_screen->setGuiBrightness(5); _vm->paletteBrightness(); _vm->setCurrentImage(31); @@ -558,20 +468,20 @@ void Intro::cutscene() { return; CursorMan.showMouse(false); - _vm->_brightness = 0; + _vm->_screen->setViewportBrightness(0); _vm->paletteBrightness(); exitOnEscape(10); _vm->playSound(kAudioSnoring); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - _gm->wait2(1); + while (_vm->_sound->isPlaying()) + _gm->wait(1); exitOnEscape(10); _vm->playSound(kAudioSnoring); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - _gm->wait2(1); + while (_vm->_sound->isPlaying()) + _gm->wait(1); exitOnEscape(10); _vm->playSound(kAudioSnoring); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - _gm->wait2(1); + while (_vm->_sound->isPlaying()) + _gm->wait(1); exitOnEscape(30); CursorMan.showMouse(true); @@ -605,7 +515,7 @@ void Intro::cutscene() { } void Intro::leaveCutscene() { - _vm->_brightness = 255; + _vm->_screen->setViewportBrightness(255); _vm->removeMessage(); _gm->changeRoom(CABIN_R3); _gm->_guiEnabled = true; @@ -620,19 +530,19 @@ bool ShipCorridor::interact(Action verb, Object &obj1, Object &obj2) { _objectState[6].disableProperty(OPENED); _vm->renderImage(8); setSectionVisible(9, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(7); setSectionVisible(8, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(7)); } else { _vm->playSound(kAudioSlideDoor); _objectState[6].setProperty(OPENED); _vm->renderImage(7); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(8); setSectionVisible(7, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(9); setSectionVisible(8, false); } @@ -649,18 +559,18 @@ bool ShipHall::interact(Action verb, Object &obj1, Object &obj2) { _objectState[2].disableProperty(OPENED); _vm->renderImage(3); setSectionVisible(4, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(2); setSectionVisible(3, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(2)); } else { _objectState[2].setProperty(OPENED); _vm->renderImage(2); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(3); setSectionVisible(2, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(4); setSectionVisible(3, false); _gm->great(1); @@ -727,13 +637,13 @@ bool ShipSleepCabin::interact(Action verb, Object &obj1, Object &obj2) { if (daysSleep != 0) { _gm->_state._timeSleep = daysSleep; _vm->renderText(kStringShipSleepCabin8, 30, 105, kColorWhite99); - _gm->wait2(18); + _gm->wait(18); setSectionVisible(5, true); } } while (daysSleep == 0); } else { _vm->renderText(kStringShipSleepCabin9, 100, 125, kColorLightRed); - _gm->wait2(18); + _gm->wait(18); } } } @@ -813,12 +723,12 @@ bool ShipSleepCabin::interact(Action verb, Object &obj1, Object &obj2) { _gm->_state._dream = true; _gm->loadTime(); } - _gm->wait2(18); + _gm->wait(18); _vm->paletteFadeIn(); if (_gm->_state._arrivalDaysLeft == 0) { _vm->playSound(kAudioCrash); _gm->screenShake(); - _gm->wait2(18); + _gm->wait(18); _vm->renderMessage(kStringShipSleepCabin12); } } @@ -860,10 +770,10 @@ void ShipSleepCabin::animation() { void ShipSleepCabin::onEntrance() { if (_gm->_state._dream && (_gm->_rooms[CAVE]->getObject(1)->_exitRoom == MEETUP3)) { _vm->renderMessage(kStringShipSleepCabin14); - _gm->waitOnInput(_gm->_timer1); + _gm->waitOnInput(_gm->_messageDuration); _vm->removeMessage(); _vm->renderMessage(kStringShipSleepCabin15); - _gm->waitOnInput(_gm->_timer1); + _gm->waitOnInput(_gm->_messageDuration); _vm->removeMessage(); _vm->renderMessage(kStringShipSleepCabin16); _gm->_state._dream = false; @@ -1004,7 +914,7 @@ bool ShipCabinL3::interact(Action verb, Object &obj1, Object &obj2) { setSectionVisible(15, false); for (int i = 3; i; i--) { _vm->playSound(kAudioTurntable); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) { + while (_vm->_sound->isPlaying()) { if (isSectionVisible(13)) { _vm->renderImage(14); setSectionVisible(13, false); @@ -1012,7 +922,7 @@ bool ShipCabinL3::interact(Action verb, Object &obj1, Object &obj2) { _vm->renderImage(13); setSectionVisible(14, false); } - _gm->wait2(3); + _gm->wait(3); } } @@ -1037,7 +947,7 @@ bool ShipCabinL3::interact(Action verb, Object &obj1, Object &obj2) { setSectionVisible(10, false); getObject(10)->_click = 20; } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KNIFE, WIRE2)) - _vm->renderMessage(kStringShipCabinL3_4); + _vm->renderMessage(kStringShipCabinL3_4); // cutting near plug else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KNIFE, WIRE)) { r = _gm->_rooms[AIRLOCK]; if (!isSectionVisible(10) && !r->getObject(5)->hasProperty(WORN)) { @@ -1125,20 +1035,20 @@ bool ShipAirlock::interact(Action verb, Object &obj1, Object &obj2) { if (getObject(0)->hasProperty(OPENED)) { getObject(0)->disableProperty(OPENED); _vm->renderImage(1); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(2); setSectionVisible(1, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(3); setSectionVisible(2, false); } else { getObject(0)->setProperty(OPENED); _vm->renderImage(2); setSectionVisible(3, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(1); setSectionVisible(2, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(1)); } _vm->renderImage(_gm->invertSection(10)); @@ -1150,53 +1060,53 @@ bool ShipAirlock::interact(Action verb, Object &obj1, Object &obj2) { _vm->playSound(kAudioSlideDoor); getObject(1)->disableProperty(OPENED); _vm->renderImage(4); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(5); setSectionVisible(4, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(6); setSectionVisible(5, false); _vm->renderImage(16); setSectionVisible(17, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(15); setSectionVisible(16, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(14); setSectionVisible(15, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(13); setSectionVisible(14, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(12); setSectionVisible(13, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(_gm->invertSection(12)); } else { getObject(1)->setProperty(OPENED); _vm->renderImage(12); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(13); setSectionVisible(12, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(14); setSectionVisible(13, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(15); setSectionVisible(14, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(16); setSectionVisible(15, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(17); setSectionVisible(16, false); _vm->playSound(kAudioSlideDoor); _vm->renderImage(5); setSectionVisible(6, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(4); setSectionVisible(5, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(4)); r = _gm->_rooms[AIRLOCK]; if (!r->getObject(4)->hasProperty(WORN) || @@ -1302,13 +1212,13 @@ bool ShipLandingModule::interact(Action verb, Object &obj1, Object &obj2) { r = _gm->_rooms[SLEEP]; r->setSectionVisible(1, false); r->setSectionVisible(2, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(2); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(8); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(9); - _gm->wait2(1); + _gm->wait(1); _vm->renderImage(10); } } @@ -1529,9 +1439,9 @@ bool ArsanoRocks::interact(Action verb, Object &obj1, Object &obj2) { if (((verb == ACTION_PULL) || (verb == ACTION_PRESS)) && (obj1._id == STONE) && !isSectionVisible(3)) { _vm->renderImage(1); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(2); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(3); _vm->playSound(kAudioRocks); obj1._click = 3; @@ -1544,10 +1454,10 @@ bool ArsanoRocks::interact(Action verb, Object &obj1, Object &obj2) { void ArsanoMeetup::onEntrance() { if (isSectionVisible(7)) { - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(6); setSectionVisible(7, false); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(_gm->invertSection(6)); } if (!(_gm->_state._greatFlag & 0x8000)) { @@ -1591,10 +1501,10 @@ bool ArsanoMeetup::interact(Action verb, Object &obj1, Object &obj2) { _vm->paletteBrightness(); } else if ((verb == ACTION_WALK) && (obj1._id == DOOR)) { _vm->renderImage(6); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(7); setSectionVisible(6, false); - _gm->wait2(3); + _gm->wait(3); return false; } else if ((verb == ACTION_LOOK) && (obj1._id == MEETUP_SIGN) && _gm->_state._language) { @@ -1616,21 +1526,21 @@ bool ArsanoMeetup::interact(Action verb, Object &obj1, Object &obj2) { } void ArsanoEntrance::animation() { - if (!_vm->_messageDisplayed && isSectionVisible(kMaxSection - 5)) { + if (!_vm->_screen->isMessageShown() && isSectionVisible(kMaxSection - 5)) { _gm->animationOff(); // to avoid recursive call _vm->playSound(kAudioSlideDoor); _vm->renderImage(8); setSectionVisible(9, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(7); setSectionVisible(8, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(6); setSectionVisible(7, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(5); setSectionVisible(6, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(5)); getObject(11)->_click = 255; setSectionVisible(kMaxSection - 5, false); @@ -1695,7 +1605,7 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) { } } else if ((verb == ACTION_WALK) && (obj1._id == STAIRCASE) && (_gm->_state._shoes != 3)) { _vm->renderImage(3); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(4); setSectionVisible(3, false); if (_gm->_rooms[AIRLOCK]->getObject(4)->hasProperty(WORN)) @@ -1706,7 +1616,7 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) { _gm->reply(kStringArsanoEntrance12, 1, _gm->invertSection(1)); _vm->renderImage(3); setSectionVisible(4, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(3)); if (!_gm->_rooms[AIRLOCK]->getObject(4)->hasProperty(WORN)) { if (_gm->_state._language) { @@ -1732,13 +1642,13 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) { break; case 3: _vm->renderImage(3); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(4); setSectionVisible(3, false); _gm->reply(kStringArsanoEntrance16, 1, 1 + 128); _vm->renderImage(3); setSectionVisible(4, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(3)); break; } @@ -1752,16 +1662,16 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) { } else if ((verb == ACTION_PRESS) && (obj1._id == BATHROOM_BUTTON)) { _vm->playSound(kAudioSlideDoor); _vm->renderImage(5); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(6); setSectionVisible(5, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(7); setSectionVisible(6, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(8); setSectionVisible(7, false); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(9); setSectionVisible(8, false); getObject(11)->_click = 9; @@ -1782,7 +1692,7 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) { _vm->renderMessage(kStringArsanoEntrance20); else { _vm->renderMessage(kStringArsanoEntrance21); - _gm->waitOnInput(_gm->_timer1); + _gm->waitOnInput(_gm->_messageDuration); _vm->removeMessage(); _vm->renderMessage(kStringArsanoEntrance22); _gm->takeObject(*getObject(16)); @@ -1829,7 +1739,7 @@ bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) { _gm->_rooms[AIRLOCK]->getObject(4)->setProperty(WORN); _gm->_rooms[AIRLOCK]->getObject(5)->setProperty(WORN); _gm->_rooms[AIRLOCK]->getObject(6)->setProperty(WORN); - _gm->waitOnInput(_gm->_timer1); + _gm->waitOnInput(_gm->_messageDuration); _vm->removeMessage(); } return false; @@ -2097,12 +2007,12 @@ bool ArsanoRoger::interact(Action verb, Object &obj1, Object &obj2) { _vm->paletteFadeOut(); _gm->_inventory.remove(*_gm->_rooms[CABIN_R3]->getObject(0)); // Chess board g_system->fillScreen(kColorBlack); - _vm->_menuBrightness = 255; + _vm->_screen->setGuiBrightness(255); _vm->paletteBrightness(); _vm->renderMessage(kStringArsanoRoger39); - _gm->waitOnInput(_gm->_timer1); + _gm->waitOnInput(_gm->_messageDuration); _vm->removeMessage(); - _vm->_menuBrightness = 0; + _vm->_screen->setGuiBrightness(0); _vm->paletteBrightness(); _gm->_state._time += ticksToMsec(125000); // 2 hours _gm->_state._alarmOn = (_gm->_state._timeAlarm > _gm->_state._time); @@ -2117,7 +2027,7 @@ bool ArsanoRoger::interact(Action verb, Object &obj1, Object &obj2) { getObject(6)->_click = 7; _vm->paletteFadeIn(); _vm->renderMessage(kStringArsanoRoger40); - _gm->waitOnInput(_gm->_timer1); + _gm->waitOnInput(_gm->_messageDuration); _vm->removeMessage(); } else return false; @@ -2140,7 +2050,7 @@ bool ArsanoGlider::interact(Action verb, Object &obj1, Object &obj2) { static char l, r; if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KEYCARD_R, GLIDER_SLOT)) { _vm->renderImage(5); - _gm->wait2(7); + _gm->wait(7); _vm->renderImage(8); getObject(5)->_click = 10; _gm->_inventory.remove(*_gm->_rooms[ROGER]->getObject(8)); @@ -2192,7 +2102,7 @@ bool ArsanoGlider::interact(Action verb, Object &obj1, Object &obj2) { } } } - _gm->wait2(4); + _gm->wait(4); _vm->renderImage(_gm->invertSection(i)); } else if ((verb == ACTION_USE) && (obj1._id == GLIDER_BUTTONS)) _vm->renderMessage(kStringArsanoGlider1); @@ -2264,40 +2174,40 @@ bool ArsanoMeetup2::interact(Action verb, Object &obj1, Object &obj2) { _vm->setCurrentImage(13); _vm->renderImage(0); _vm->paletteBrightness(); - _gm->wait2(36); + _gm->wait(36); for (int i = 1; i <= 13; i++) { if (i > 1) _vm->renderImage(_gm->invertSection(i - 1)); _vm->renderImage(i); - _gm->wait2(2); + _gm->wait(2); } _vm->renderImage(_gm->invertSection(13)); - _gm->wait2(20); + _gm->wait(20); _vm->setCurrentImage(14); _vm->renderImage(0); _vm->paletteBrightness(); - _gm->wait2(36); + _gm->wait(36); for (int i = 1; i <= 13; i++) { if (i > 1) _vm->renderImage(_gm->invertSection(i - 1)); _vm->renderImage(i); - _gm->wait2(2); + _gm->wait(2); } _vm->renderImage(_gm->invertSection(13)); - _gm->wait2(9); + _gm->wait(9); _vm->playSound(kAudioCrash); for (int i = 14; i <= 19; i++) { _vm->renderImage(i); - _gm->wait2(3); + _gm->wait(3); } _vm->paletteFadeOut(); _vm->setCurrentImage(11); _vm->renderImage(0); _vm->paletteFadeIn(); - _gm->wait2(18); + _gm->wait(18); _vm->renderMessage(kStringArsanoMeetup2_12); _gm->great(0); - _gm->waitOnInput(_gm->_timer1); + _gm->waitOnInput(_gm->_messageDuration); _vm->removeMessage(); _vm->paletteFadeOut(); g_system->fillScreen(kColorBlack); @@ -2321,14 +2231,14 @@ bool ArsanoMeetup2::interact(Action verb, Object &obj1, Object &obj2) { } void ArsanoMeetup2::shipStart() { - _gm->wait2(12); + _gm->wait(12); for (int i = 2; i <= 11; ++i) { if (i >= 9) _vm->renderImage(i - 1 + 128); else setSectionVisible(i - 1, false); _vm->renderImage(i); - _gm->wait2(2); + _gm->wait(2); } _vm->renderImage(11 + 128); } @@ -2354,34 +2264,34 @@ bool ArsanoMeetup3::interact(Action verb, Object &obj1, Object &obj2) { _vm->paletteBrightness(); _gm->dialog(3, rowsX, _dialogsX, 0); _vm->renderImage(1); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(2); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(3); - _gm->wait2(6); + _gm->wait(6); _vm->renderImage(4); _vm->playSound(kAudioGunShot); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - _gm->wait2(1); + while (_vm->_sound->isPlaying()) + _gm->wait(1); _vm->renderImage(5); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(4); _vm->playSound(kAudioGunShot); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - _gm->wait2(1); + while (_vm->_sound->isPlaying()) + _gm->wait(1); _vm->renderImage(5); _vm->paletteFadeOut(); - _gm->wait2(12); + _gm->wait(12); _vm->setCurrentImage(0); _vm->renderImage(0); _vm->paletteFadeIn(); - _gm->wait2(18); + _gm->wait(18); _gm->reply(kStringArsanoMeetup3_1, 2, 2 + 128); - _gm->wait2(10); + _gm->wait(10); _gm->reply(kStringArsanoMeetup3_2, 1, 1 + 128); do { @@ -2604,8 +2514,8 @@ bool AxacussCell::interact(Action verb, Object &obj1, Object &obj2) { return false; _vm->playSound(kAudioGunShot); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - _gm->wait2(1); + while (_vm->_sound->isPlaying()) + _gm->wait(1); _vm->playSound(kAudioGunShot); _vm->playSound(kAudioGunShot); @@ -2693,27 +2603,29 @@ bool AxacussCorridor5::handleMoneyDialog() { } switch (_gm->dialog(4, _rows, _dialog3, 2)) { case 1: - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(1); _vm->playSound(kAudioVoiceHalt); _vm->renderImage(_gm->invertSection(1)); - _gm->wait2(5); + _gm->wait(5); _vm->renderImage(2); - _gm->wait2(2); + _gm->wait(2); _gm->shot(3, _gm->invertSection(3)); break; - case 3: - if (_gm->_state._money >= 900) { - stopInteract(_gm->_state._money); - return true; - } - // fall through case 2: if (_gm->_state._money > 1100) { stopInteract(_gm->_state._money - 200); return true; } _gm->reply(kStringAxacussCorridor5_6, 1, 1 + 128); + break; + case 3: + if (_gm->_state._money >= 900) { + stopInteract(_gm->_state._money); + return true; + } + _gm->reply(kStringAxacussCorridor5_6, 1, 1 + 128); + break; } } return false; @@ -2959,7 +2871,7 @@ bool AxacussExit::interact(Action verb, Object &obj1, Object &obj2) { _vm->renderImage(i); if (i == 11) _vm->playSound(kAudioSmash); // 046/4020 - _gm->wait2(1); + _gm->wait(1); _vm->renderImage(i + 128); } _gm->_state._powerOff = true; @@ -3176,9 +3088,9 @@ bool AxacussElevator::interact(Action verb, Object &obj1, Object &obj2) { _vm->renderImage(1); getObject(2)->resetProperty(); _vm->playSound(kAudioSlideDoor); - _gm->wait2(25); + _gm->wait(25); for (int i = 3; i <= 7; i++) { - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(i); } getObject(3)->resetProperty(EXIT); @@ -3196,10 +3108,10 @@ bool AxacussElevator::interact(Action verb, Object &obj1, Object &obj2) { getObject(3)->_click = 255; _vm->playSound(kAudioSlideDoor); for (int i = 7; i >= 3; i--) { - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(i)); } - _gm->wait2(25); + _gm->wait(25); _vm->playSound(kAudioSlideDoor); getObject(2)->resetProperty(EXIT); _vm->renderImage(_gm->invertSection(2)); @@ -3207,12 +3119,12 @@ bool AxacussElevator::interact(Action verb, Object &obj1, Object &obj2) { } else if ((verb == ACTION_WALK) && (obj1._id == JUNGLE)) { _vm->paletteFadeOut(); g_system->fillScreen(kColorBlack); - _vm->_menuBrightness = 255; + _vm->_screen->setGuiBrightness(255); _vm->paletteBrightness(); _vm->renderMessage(kStringAxacussElevator_3); - _gm->waitOnInput(_gm->_timer1); + _gm->waitOnInput(_gm->_messageDuration); _vm->removeMessage(); - _vm->_menuBrightness = 0; + _vm->_screen->setGuiBrightness(0); _vm->paletteBrightness(); _gm->_state._time += ticksToMsec(125000); // 2 hours _gm->_state._alarmOn = (_gm->_state._timeAlarm > _gm->_state._time); @@ -3281,24 +3193,24 @@ void Outro::onEntrance() { _vm->renderImage(0); _vm->renderImage(1); _vm->paletteFadeIn(); - _gm->wait2(10); + _gm->wait(10); for (int i = 8; i <= 21; i++) { _vm->renderImage(i); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(_gm->invertSection(i)); } - _gm->wait2(18); + _gm->wait(18); _vm->renderImage(_gm->invertSection(1)); for (int i = 2; i <= 7; i++) { _vm->renderImage(i); - _gm->wait2(3); + _gm->wait(3); _vm->renderImage(_gm->invertSection(i)); } - _vm->playSoundMod(kMusicOutro); - Marquee marquee(_vm, Marquee::kMarqueeOutro, _outroText.c_str()); + _vm->playSound(kMusicOutro); + Marquee marquee(_vm->_screen, Marquee::kMarqueeOutro, _outroText.c_str()); while (!_vm->shouldQuit()) { - _vm->updateEvents(); + _gm->updateEvents(); marquee.renderCharacter(); if (_gm->_mouseClicked || _gm->_keyPressed) break; @@ -3311,7 +3223,7 @@ void Outro::onEntrance() { _vm->paletteFadeIn(); _gm->getInput(); _vm->paletteFadeOut(); - _vm->_brightness = 1; + _vm->_screen->setViewportBrightness(1); Common::Event event; event.type = Common::EVENT_RTL; @@ -3325,9 +3237,9 @@ void Outro::animate(int filenumber, int section1, int section2, int duration) { _vm->setCurrentImage(filenumber); while (duration) { _vm->renderImage(section1); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(section2); - _gm->wait2(2); + _gm->wait(2); --duration; } } @@ -3340,10 +3252,10 @@ void Outro::animate(int filenumber, int section1, int section2, int duration, while (delay) { if (section1) _vm->renderImage(section1); - _gm->wait2(2); + _gm->wait(2); if (section2) _vm->renderImage(section2); - _gm->wait2(2); + _gm->wait(2); --delay; } _vm->removeMessage(); @@ -3359,10 +3271,10 @@ void Outro::animate(int filenumber, int section1, int section2, int section3, in while(duration) { _vm->renderImage(section1); _vm->renderImage(section3); - _gm->wait2(2); + _gm->wait(2); _vm->renderImage(section2); _vm->renderImage(section4); - _gm->wait2(2); + _gm->wait(2); duration--; } _vm->removeMessage(); diff --git a/engines/supernova/rooms.h b/engines/supernova/rooms.h index 3cedc356db..5c9b283dcd 100644 --- a/engines/supernova/rooms.h +++ b/engines/supernova/rooms.h @@ -27,6 +27,11 @@ #include "msn_def.h" +namespace Common { +class ReadStream; +class WriteStream; +} + namespace Supernova { class GameManager; @@ -52,7 +57,7 @@ public: int getFileNumber() const { return _fileNumber; } - RoomID getId() const { + RoomId getId() const { return _id; } @@ -112,7 +117,7 @@ protected: bool _shown[kMaxSection]; byte _sentenceRemoved[kMaxDialog]; Object _objectState[kMaxObject]; - RoomID _id; + RoomId _id; SupernovaEngine *_vm; GameManager *_gm; @@ -129,9 +134,9 @@ public: private: bool animate(int section1, int section2, int duration); bool animate(int section1, int section2, int duration, MessagePosition position, - StringID text); + StringId text); bool animate(int section1, int section2, int section3, int section4, int duration, - MessagePosition position, StringID text); + MessagePosition position, StringId text); void titleScreen(); void titleFadeIn(); @@ -681,9 +686,9 @@ public: virtual void animation(); private: - StringID _dialog1[5]; - StringID _dialog2[5]; - StringID _dialog3[5]; + StringId _dialog1[5]; + StringId _dialog2[5]; + StringId _dialog3[5]; byte _eyewitness; }; class ArsanoRemaining : public Room { @@ -742,7 +747,7 @@ public: virtual bool interact(Action verb, Object &obj1, Object &obj2); private: - StringID _dialog1[4]; + StringId _dialog1[4]; byte _eyewitness; byte _hands; }; @@ -809,10 +814,10 @@ public: private: // TODO: change to 6, fix initialization - StringID _dialog1[2]; - StringID _dialog2[2]; - StringID _dialog3[4]; - StringID _dialog4[3]; + StringId _dialog1[2]; + StringId _dialog2[2]; + StringId _dialog3[4]; + StringId _dialog4[3]; bool _found; bool _flug; @@ -846,11 +851,11 @@ public: virtual bool interact(Action verb, Object &obj1, Object &obj2); private: - StringID _dialog2[4]; - StringID _dialog3[2]; + StringId _dialog2[4]; + StringId _dialog3[2]; // TODO: Hack, to be move away and renamed when the other uses are found - StringID _dialogsX[6]; + StringId _dialogsX[6]; // }; @@ -1025,9 +1030,9 @@ private: bool handleMoneyDialog(); // TODO: Change to 6, or change struct, and fix initialization - StringID _dialog1[2]; - StringID _dialog2[2]; - StringID _dialog3[4]; + StringId _dialog1[2]; + StringId _dialog2[2]; + StringId _dialog3[4]; byte _rows[6]; }; @@ -1176,7 +1181,7 @@ public: virtual bool interact(Action verb, Object &obj1, Object &obj2); private: - StringID _dialogsX[6]; + StringId _dialogsX[6]; }; class AxacussExit : public Room { @@ -1205,7 +1210,7 @@ public: virtual bool interact(Action verb, Object &obj1, Object &obj2); private: - StringID _dialogsX[6]; + StringId _dialogsX[6]; }; class AxacussOffice1 : public Room { public: diff --git a/engines/supernova/screen.cpp b/engines/supernova/screen.cpp new file mode 100644 index 0000000000..5404b13254 --- /dev/null +++ b/engines/supernova/screen.cpp @@ -0,0 +1,636 @@ +/* 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 2 +* 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, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "common/str.h" +#include "common/system.h" +#include "engines/util.h" +#include "graphics/cursorman.h" +#include "graphics/palette.h" +#include "graphics/surface.h" + +#include "supernova/imageid.h" +#include "supernova/resman.h" +#include "supernova/state.h" +#include "supernova/screen.h" +#include "supernova/supernova.h" + +#include "supernova/screenstatic.cpp" + +namespace Supernova { + +ScreenBuffer::ScreenBuffer() + : _x(0) + , _y(0) + , _width(0) + , _height(0) + , _pixels(nullptr) { +} + +ScreenBufferStack::ScreenBufferStack() + : _last(_buffer) { +} + +void ScreenBufferStack::push(int x, int y, int width, int height) { + if (_last == ARRAYEND(_buffer)) + return; + + Graphics::Surface *screenSurface = g_system->lockScreen(); + + if (x < 0) { + width += x; + x = 0; + } + + if (x + width > screenSurface->w) + width = screenSurface->w - x; + + if (y < 0) { + height += y; + y = 0; + } + + if (y + height > screenSurface->h) + height = screenSurface->h - y; + + _last->_pixels = new byte[width * height]; + byte *pixels = _last->_pixels; + const byte *screen = static_cast<const byte *>(screenSurface->getBasePtr(x, y)); + for (int i = 0; i < height; ++i) { + Common::copy(screen, screen + width, pixels); + screen += screenSurface->pitch; + pixels += width; + } + g_system->unlockScreen(); + + _last->_x = x; + _last->_y = y; + _last->_width = width; + _last->_height = height; + + ++_last; +} + +void ScreenBufferStack::restore() { + if (_last == _buffer) + return; + + --_last; + g_system->lockScreen()->copyRectToSurface(_last->_pixels, _last->_width, _last->_x, + _last->_y, _last->_width, _last->_height); + g_system->unlockScreen(); + + delete[] _last->_pixels; +} + +Marquee::Marquee(Screen *screen, MarqueeId id, const char *text) + : _text(text) + , _textBegin(text) + , _delay(0) + , _color(kColorLightBlue) + , _loop(false) + , _screen(screen) { + if (id == kMarqueeIntro) { + _y = 191; + _loop = true; + } else if (id == kMarqueeOutro) { + _y = 1; + } + + _textWidth = Screen::textWidth(_text); + _x = kScreenWidth / 2 - _textWidth / 2; + _screen->_textCursorX = _x; + _screen->_textCursorY = _y; + _screen->_textColor = _color; +} + +void Marquee::clearText() { + _screen->renderBox(_x, _y - 1, _textWidth + 1, 9, kColorBlack); +} + +void Marquee::renderCharacter() { + if (_delay != 0) { + _delay--; + return; + } + + switch (*_text) { + case '\233': + if (_loop) { + _loop = false; + _text = _textBegin; + clearText(); + _textWidth = Screen::textWidth(_text); + _x = kScreenWidth / 2 - _textWidth / 2; + _screen->_textCursorX = _x; + } + break; + case '\0': + clearText(); + _text++; + _textWidth = Screen::textWidth(_text); + _x = kScreenWidth / 2 - _textWidth / 2; + _screen->_textCursorX = _x; + _color = kColorLightBlue; + _screen->_textColor = _color; + break; + case '^': + _color = kColorLightYellow; + _screen->_textColor = _color; + _text++; + break; + case '#': + _delay = 50; + _text++; + break; + default: + _screen->renderText((uint16)*_text++); + _delay = 1; + break; + } +} + +Screen::Screen(SupernovaEngine *vm, GameManager *gm, ResourceManager *resMan) + : _vm(vm) + , _gm(gm) + , _resMan(resMan) + , _currentImage(nullptr) + , _viewportBrightness(255) + , _guiBrightness(255) + , _screenWidth(320) + , _screenHeight(200) + , _textColor(kColorBlack) + , _textCursorX(0) + , _textCursorY(0) + , _messageShown(false) { + + CursorMan.replaceCursor(_resMan->getImage(ResourceManager::kCursorNormal), + 16, 16, 0, 0, kColorCursorTransparent); + CursorMan.replaceCursorPalette(initVGAPalette, 0, 16); + CursorMan.showMouse(true); +} + +int Screen::getGuiBrightness() const { + return _guiBrightness; +} + +void Screen::setViewportBrightness(int brightness) { + _viewportBrightness = brightness; +} + +int Screen::getViewportBrightness() const { + return _viewportBrightness; +} + +void Screen::setGuiBrightness(int brightness) { + _guiBrightness = brightness; +} + +const MSNImage *Screen::getCurrentImage() const { + return _currentImage; +} + +bool Screen::isMessageShown() const { + return _messageShown; +} + +Common::Point Screen::getTextCursorPos() { + return Common::Point(_textCursorX, _textCursorY); +} + +void Screen::setTextCursorPos(int x, int y) { + _textCursorX = x; + _textCursorY = y; +} + +byte Screen::getTextCursorColor() { + return _textColor; +} + +void Screen::setTextCursorColor(byte color) { + _textColor = color; +} + +void Screen::renderMessage(StringId stringId, MessagePosition position, + Common::String var1, Common::String var2) { + Common::String text = _vm->getGameString(stringId); + + if (!var1.empty()) { + if (!var2.empty()) + text = Common::String::format(text.c_str(), var1.c_str(), var2.c_str()); + else + text = Common::String::format(text.c_str(), var1.c_str()); + } + + renderMessage(text, position); +} + +void Screen::renderMessage(const Common::String &text, MessagePosition position) { + if (!text.empty()) + renderMessage(text.c_str(), position); +} + +void Screen::renderText(const uint16 character) { + char text[2]; + text[0] = character & 0xFF; + text[1] = 0; + renderText(text, _textCursorX, _textCursorY, _textColor); +} + +void Screen::renderText(const char *text) { + renderText(text, _textCursorX, _textCursorY, _textColor); +} + +void Screen::renderText(StringId stringId) { + renderText(_vm->getGameString(stringId)); +} + +void Screen::renderText(const Common::String &text) { + if (!text.empty()) + renderText(text.c_str()); +} + +void Screen::renderText(const GuiElement &guiElement) { + renderText(guiElement.getText(), guiElement.getTextPos().x, + guiElement.getTextPos().y, guiElement.getTextColor()); +} + +void Screen::renderText(const uint16 character, int x, int y, byte color) { + char text[2]; + text[0] = character & 0xFF; + text[1] = 0; + renderText(text, x, y, color); +} + +void Screen::renderText(const char *text, int x, int y, byte color) { + Graphics::Surface *screen = _vm->_system->lockScreen(); + byte *cursor = static_cast<byte *>(screen->getBasePtr(x, y)); + const byte *basePtr = cursor; + + byte c; + while ((c = *text++) != '\0') { + if (c < 32) { + continue; + } else if (c == 225) { + c = 128; + } + + for (uint i = 0; i < 5; ++i) { + if (font[c - 32][i] == 0xff) { + break; + } + + byte *ascentLine = cursor; + for (byte j = font[c - 32][i]; j != 0; j >>= 1) { + if (j & 1) { + *cursor = color; + } + cursor += kScreenWidth; + } + cursor = ++ascentLine; + } + ++cursor; + } + _vm->_system->unlockScreen(); + + uint numChars = cursor - basePtr; + uint absPosition = y * kScreenWidth + x + numChars; + _textCursorX = absPosition % kScreenWidth; + _textCursorY = absPosition / kScreenWidth; + _textColor = color; +} + +void Screen::renderText(const Common::String &text, int x, int y, byte color) { + if (!text.empty()) + renderText(text.c_str(), x, y, color); +} + +void Screen::renderText(StringId stringId, int x, int y, byte color) { + renderText(_vm->getGameString(stringId), x, y, color); +} + +void Screen::renderImageSection(const MSNImage *image, int section) { + // Note: inverting means we are removing the section. So we should get the rect for that + // section but draw the background (section 0) instead. + bool invert = false; + if (section > 128) { + section -= 128; + invert = true; + } + if (section > image->_numSections - 1) + return; + + Common::Rect sectionRect(image->_section[section].x1, + image->_section[section].y1, + image->_section[section].x2 + 1, + image->_section[section].y2 + 1) ; + if (image->_filenumber == 1 || image->_filenumber == 2) { + sectionRect.setWidth(640); + sectionRect.setHeight(480); + if (_screenWidth != 640) { + _screenWidth = 640; + _screenHeight = 480; + initGraphics(_screenWidth, _screenHeight); + } + } else { + if (_screenWidth != 320) { + _screenWidth = 320; + _screenHeight = 200; + initGraphics(_screenWidth, _screenHeight); + } + } + + uint offset = 0; + int pitch = sectionRect.width(); + if (invert) { + pitch = image->_pitch; + offset = image->_section[section].y1 * pitch + + image->_section[section].x1; + section = 0; + } + + void *pixels = image->_sectionSurfaces[section]->getPixels(); + _vm->_system->copyRectToScreen(static_cast<const byte *>(pixels) + offset, + pitch, sectionRect.left, sectionRect.top, + sectionRect.width(), sectionRect.height()); +} + +void Screen::renderImage(ImageId id, bool removeImage) { + ImageInfo info = imageInfo[id]; + const MSNImage *image = _resMan->getImage(info.filenumber); + + if (_currentImage != image) { + _currentImage = image; + _vm->_system->getPaletteManager()->setPalette(image->getPalette(), 16, 239); + } + + do { + if (removeImage) + renderImageSection(image, info.section + 128); + else + renderImageSection(image, info.section); + + info.section = image->_section[info.section].next; + } while (info.section != 0); +} + +void Screen::renderImage(int section) { + if (!_currentImage) + return; + + bool sectionVisible = true; + + if (section > 128) { + sectionVisible = false; + section -= 128; + } + + _gm->_currentRoom->setSectionVisible(section, sectionVisible); + + do { + if (sectionVisible) + renderImageSection(_currentImage, section); + else + renderImageSection(_currentImage, section + 128); + section = _currentImage->_section[section].next; + } while (section != 0); +} + +bool Screen::setCurrentImage(int filenumber) { + _currentImage = _resMan->getImage(filenumber); + _vm->_system->getPaletteManager()->setPalette(_currentImage->getPalette(), 16, 239); + paletteBrightness(); + + return true; +} + +void Screen::saveScreen(int x, int y, int width, int height) { + _screenBuffer.push(x, y, width, height); +} + +void Screen::saveScreen(const GuiElement &guiElement) { + saveScreen(guiElement.left, guiElement.top, guiElement.width(), guiElement.height()); +} + +void Screen::restoreScreen() { + _screenBuffer.restore(); +} + +void Screen::renderRoom(Room &room) { + if (room.getId() == INTRO) + return; + + if (setCurrentImage(room.getFileNumber())) { + for (int i = 0; i < _currentImage->_numSections; ++i) { + int section = i; + if (room.isSectionVisible(section)) { + do { + renderImageSection(_currentImage, section); + section = _currentImage->_section[section].next; + } while (section != 0); + } + } + } +} + +int Screen::textWidth(const uint16 key) { + char text[2]; + text[0] = key & 0xFF; + text[1] = 0; + return textWidth(text); +} + +int Screen::textWidth(const char *text) { + int charWidth = 0; + while (*text != '\0') { + byte c = *text++; + if (c < 32) { + continue; + } else if (c == 225) { + c = 35; + } + + for (uint i = 0; i < 5; ++i) { + if (font[c - 32][i] == 0xff) { + break; + } + ++charWidth; + } + ++charWidth; + } + + return charWidth; +} + +int Screen::textWidth(const Common::String &text) { + return Screen::textWidth(text.c_str()); +} + +void Screen::renderMessage(const char *text, MessagePosition position) { + Common::String t(text); + char *row[20]; + Common::String::iterator p = t.begin(); + uint numRows = 0; + int rowWidthMax = 0; + int x = 0; + int y = 0; + byte textColor = 0; + + while (*p != '\0') { + row[numRows] = p; + ++numRows; + while ((*p != '\0') && (*p != '|')) { + ++p; + } + if (*p == '|') { + *p = '\0'; + ++p; + } + } + for (uint i = 0; i < numRows; ++i) { + int rowWidth = textWidth(row[i]); + if (rowWidth > rowWidthMax) + rowWidthMax = rowWidth; + } + + switch (position) { + case kMessageNormal: + x = 160 - rowWidthMax / 2; + textColor = kColorWhite99; + break; + case kMessageTop: + x = 160 - rowWidthMax / 2; + textColor = kColorLightYellow; + break; + case kMessageCenter: + x = 160 - rowWidthMax / 2; + textColor = kColorLightRed; + break; + case kMessageLeft: + x = 3; + textColor = kColorLightYellow; + break; + case kMessageRight: + x = 317 - rowWidthMax; + textColor = kColorLightGreen; + break; + } + + if (position == kMessageNormal) { + y = 70 - ((numRows * 9) / 2); + } else if (position == kMessageTop) { + y = 5; + } else { + y = 142; + } + + int message_columns = x - 3; + int message_rows = y - 3; + int message_width = rowWidthMax + 6; + int message_height = numRows * 9 + 5; + saveScreen(message_columns, message_rows, message_width, message_height); + renderBox(message_columns, message_rows, message_width, message_height, kColorWhite35); + for (uint i = 0; i < numRows; ++i) { + renderText(row[i], x, y, textColor); + y += 9; + } + + _messageShown = true; + _gm->_messageDuration = (Common::strnlen(text, 512) + 20) * _vm->_textSpeed / 10; +} + +void Screen::removeMessage() { + if (_messageShown) { + restoreScreen(); + _messageShown = false; + } +} + +void Screen::renderBox(int x, int y, int width, int height, byte color) { + Graphics::Surface *screen = _vm->_system->lockScreen(); + screen->fillRect(Common::Rect(x, y, x + width, y + height), color); + _vm->_system->unlockScreen(); +} + +void Screen::renderBox(const GuiElement &guiElement) { + renderBox(guiElement.left, guiElement.top, guiElement.width(), + guiElement.height(), guiElement.getBackgroundColor()); +} + +void Screen::initPalette() { + g_system->getPaletteManager()->setPalette(initVGAPalette, 0, 256); +} + +void Screen::paletteBrightness() { + byte palette[768]; + + _vm->_system->getPaletteManager()->grabPalette(palette, 0, 255); + for (uint i = 0; i < 48; ++i) { + palette[i] = (initVGAPalette[i] * _guiBrightness) >> 8; + } + for (uint i = 0; i < 717; ++i) { + const byte *imagePalette; + if (_currentImage && _currentImage->getPalette()) { + imagePalette = _currentImage->getPalette(); + } else { + imagePalette = palette + 48; + } + palette[i + 48] = (imagePalette[i] * _viewportBrightness) >> 8; + } + _vm->_system->getPaletteManager()->setPalette(palette, 0, 255); +} + +void Screen::paletteFadeOut() { + while (_guiBrightness > 10) { + _guiBrightness -= 10; + if (_viewportBrightness > _guiBrightness) + _viewportBrightness = _guiBrightness; + paletteBrightness(); + _vm->_system->updateScreen(); + _vm->_system->delayMillis(_vm->_delay); + } + _guiBrightness = 0; + _viewportBrightness = 0; + paletteBrightness(); + _vm->_system->updateScreen(); +} + +void Screen::paletteFadeIn() { + while (_guiBrightness < 245) { + if (_viewportBrightness < _gm->_roomBrightness) + _viewportBrightness += 10; + _guiBrightness += 10; + paletteBrightness(); + _vm->_system->updateScreen(); + _vm->_system->delayMillis(_vm->_delay); + } + _guiBrightness = 255; + _viewportBrightness = _gm->_roomBrightness; + paletteBrightness(); + _vm->_system->updateScreen(); +} + +void Screen::setColor63(byte value) { + byte color[3] = {value, value, value}; + _vm->_system->getPaletteManager()->setPalette(color, 63, 1); +} + +} diff --git a/engines/supernova/screen.h b/engines/supernova/screen.h new file mode 100644 index 0000000000..d57fb53ed2 --- /dev/null +++ b/engines/supernova/screen.h @@ -0,0 +1,197 @@ +/* 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 2 +* 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, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef SUPERNOVA_SCREEN_H +#define SUPERNOVA_SCREEN_H + +#include "common/array.h" +#include "common/rect.h" +#include "common/scummsys.h" + +#include "supernova/imageid.h" +#include "supernova/msn_def.h" + +namespace Supernova { + +class SupernovaEngine; +class GameManager; +class ResourceManager; +class GuiElement; +class Room; +class MSNImage; +class Screen; + +const int kScreenWidth = 320; +const int kScreenHeight = 200; +const int kFontWidth = 5; +const int kFontHeight = 8; + +enum Color { + kColorBlack = 0, + kColorWhite25 = 1, + kColorWhite35 = 2, + kColorWhite44 = 3, + kColorWhite99 = 4, + kColorDarkGreen = 5, + kColorGreen = 6, + kColorDarkRed = 7, + kColorRed = 8, + kColorDarkBlue = 9, + kColorBlue = 10, + kColorWhite63 = 11, + kColorLightBlue = 12, + kColorLightGreen = 13, + kColorLightYellow = 14, + kColorLightRed = 15, + kColorCursorTransparent = kColorWhite25 +}; + +class ScreenBuffer { + friend class ScreenBufferStack; + +public: + ScreenBuffer(); + +private: + byte *_pixels; + int _x; + int _y; + int _width; + int _height; +}; + +class ScreenBufferStack { +public: + ScreenBufferStack(); + + void push(int x, int y, int width, int height); + void restore(); + +private: + ScreenBuffer _buffer[8]; + ScreenBuffer *_last; +}; + +class Marquee { +public: + enum MarqueeId { + kMarqueeIntro, + kMarqueeOutro + }; + + Marquee(Screen *screen, MarqueeId id, const char *text); + + void renderCharacter(); + +private: + void clearText(); + + Screen *_screen; + const char *const _textBegin; + const char *_text; + bool _loop; + int _delay; + int _color; + int _x; + int _y; + int _textWidth; +}; + +class Screen { + friend class Marquee; + +public: + struct ImageInfo { + int filenumber; + int section; + }; + +public: + static void initPalette(); + static int textWidth(const uint16 key); + static int textWidth(const char *text); + static int textWidth(const Common::String &text); + +public: + Screen(SupernovaEngine *vm, GameManager *gm, ResourceManager *resMan); + + int getViewportBrightness() const; + void setViewportBrightness(int brightness); + int getGuiBrightness() const; + void setGuiBrightness(int brightness); + const MSNImage *getCurrentImage() const; + bool isMessageShown() const; + void paletteFadeIn(); + void paletteFadeOut(); + void paletteBrightness(); + void renderImage(ImageId id, bool removeImage = false); + void renderImage(int section); + bool setCurrentImage(int filenumber); + void saveScreen(int x, int y, int width, int height); + void saveScreen(const GuiElement &guiElement); + void restoreScreen(); + void renderRoom(Room &room); + void renderMessage(const char *text, MessagePosition position = kMessageNormal); + void renderMessage(const Common::String &text, MessagePosition position = kMessageNormal); + void renderMessage(StringId stringId, MessagePosition position = kMessageNormal, + Common::String var1 = "", Common::String var2 = ""); + void removeMessage(); + void renderText(const uint16 character); + void renderText(const char *text); + void renderText(const Common::String &text); + void renderText(StringId stringId); + void renderText(const uint16 character, int x, int y, byte color); + void renderText(const char *text, int x, int y, byte color); + void renderText(const Common::String &text, int x, int y, byte color); + void renderText(StringId stringId, int x, int y, byte color); + void renderText(const GuiElement &guiElement); + void renderBox(int x, int y, int width, int height, byte color); + void renderBox(const GuiElement &guiElement); + void setColor63(byte value); + Common::Point getTextCursorPos(); + void setTextCursorPos(int x, int y); + byte getTextCursorColor(); + void setTextCursorColor(byte color); + void update(); + +private: + void renderImageSection(const MSNImage *image, int section); + +private: + SupernovaEngine *_vm; + GameManager *_gm; + ResourceManager *_resMan; + const MSNImage *_currentImage; + ScreenBufferStack _screenBuffer; + int _screenWidth; + int _screenHeight; + int _textCursorX; + int _textCursorY; + int _textColor; + byte _viewportBrightness; + byte _guiBrightness; + bool _messageShown; +}; + +} + +#endif diff --git a/engines/supernova/screenstatic.cpp b/engines/supernova/screenstatic.cpp new file mode 100644 index 0000000000..db987bf2fb --- /dev/null +++ b/engines/supernova/screenstatic.cpp @@ -0,0 +1,328 @@ +/* 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 2 +* 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, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +namespace Supernova { + +static const Screen::ImageInfo imageInfo[] = { + { 0, 0}, { 0, 1}, { 0, 2}, + { 1, 0}, + { 2, 0}, + { 3, 0}, { 3, 1}, { 3, 2}, { 3, 3}, { 3, 4}, { 3, 5}, + { 3, 6}, { 3, 7}, { 3, 8}, { 3, 9}, { 3, 10}, { 3, 11}, + { 4, 0}, { 4, 1}, { 4, 2}, { 4, 3}, + { 5, 0}, { 5, 1}, { 5, 2}, { 5, 3}, { 5, 4}, { 5, 5}, + { 5, 6}, { 5, 7}, { 5, 8}, { 5, 9}, + { 6, 0}, { 6, 1}, { 6, 2}, { 6, 3}, { 6, 4}, { 6, 5}, + { 6, 6}, { 6, 7}, { 6, 8}, { 6, 9}, { 6, 10}, { 6, 11}, + { 6, 12}, { 6, 13}, { 6, 14}, { 6, 15}, { 6, 16}, { 6, 17}, + { 6, 18}, { 6, 19}, { 6, 20}, { 6, 21}, + { 7, 0}, { 7, 1}, { 7, 2}, { 7, 3}, { 7, 4}, { 7, 5}, + { 7, 6}, { 7, 7}, { 7, 8}, { 7, 9}, { 7, 10}, { 7, 11}, + { 7, 12}, { 7, 13}, { 7, 14}, { 7, 15}, { 7, 16}, { 7, 17}, + { 7, 18}, { 7, 19}, { 7, 20}, { 7, 21}, { 7, 22}, + { 8, 0}, { 8, 1}, { 8, 2}, { 8, 3}, { 8, 4}, { 8, 5}, + { 8, 6}, { 8, 7}, { 8, 8}, { 8, 9}, { 8, 10}, { 8, 11}, + { 8, 12}, + { 9, 0}, { 9, 1}, { 9, 2}, { 9, 3}, { 9, 4}, { 9, 5}, + { 9, 6}, { 9, 7}, { 9, 8}, { 9, 9}, { 9, 10}, { 9, 11}, + { 9, 12}, { 9, 13}, { 9, 14}, { 9, 15}, { 9, 16}, { 9, 17}, + { 9, 18}, { 9, 19}, { 9, 20}, { 9, 21}, { 9, 22}, { 9, 23}, + {10, 0}, {10, 1}, {10, 2}, {10, 3}, {10, 4}, {10, 5}, + {10, 6}, {10, 7}, {10, 8}, {10, 9}, {10, 10}, {10, 11}, + {10, 12}, {10, 13}, {10, 14}, {10, 15}, {10, 16}, + {11, 0}, + {12, 0}, {12, 1}, {12, 2}, {12, 3}, + {13, 0}, {13, 1}, {13, 2}, {13, 3}, {13, 4}, {13, 5}, + {13, 6}, {13, 7}, {13, 8}, {13, 9}, {13, 10}, {13, 11}, + {13, 12}, {13, 13}, + {14, 0}, {14, 1}, {14, 2}, {14, 3}, {14, 4}, {14, 5}, + {14, 6}, {14, 7}, {14, 8}, {14, 9}, {14, 10}, {14, 11}, + {14, 12}, {14, 13}, {14, 14}, {14, 15}, {14, 16}, {14, 17}, + {14, 18}, {14, 19}, + {15, 0}, {15, 1}, {15, 2}, {15, 3}, {15, 4}, {15, 5}, + {16, 0}, {16, 1}, {16, 2}, {16, 3}, {16, 4}, {16, 5}, + {16, 6}, {16, 7}, {16, 8}, {16, 9}, {16, 10}, {16, 11}, + {16, 12}, {16, 13}, {16, 14}, {16, 15}, {16, 16}, {16, 17}, + {16, 18}, {16, 19}, {16, 20}, {16, 21}, {16, 22}, {16, 23}, + {16, 24}, {16, 25}, {16, 26}, {16, 27}, {16, 28}, {16, 29}, + {16, 30}, {16, 31}, {16, 32}, {16, 33}, + {17, 0}, {17, 1}, {17, 2}, {17, 3}, {17, 4}, {17, 5}, + {17, 6}, {17, 7}, {17, 8}, {17, 9}, {17, 10}, {17, 11}, + {17, 12}, {17, 13}, {17, 14}, {17, 15}, + {18, 0}, {18, 1}, {18, 2}, {18, 3}, {18, 4}, {18, 5}, + {18, 6}, {18, 7}, {18, 8}, {18, 9}, {18, 10}, {18, 11}, + {18, 12}, {18, 13}, {18, 14}, {18, 15}, {18, 16}, {18, 17}, + {18, 18}, {18, 19}, {18, 20}, {18, 21}, + {19, 0}, {19, 1}, {19, 2}, {19, 3}, {19, 4}, {19, 5}, + {19, 6}, {19, 7}, {19, 8}, {19, 9}, {19, 10}, {19, 11}, + {19, 12}, {19, 13}, {19, 14}, {19, 15}, {19, 16}, {19, 17}, + {19, 18}, {19, 19}, {19, 20}, {19, 21}, {19, 22}, {19, 23}, + {19, 24}, {19, 25}, {19, 26}, {19, 27}, {19, 28}, {19, 29}, + {19, 30}, {19, 31}, {19, 32}, {19, 33}, {19, 34}, {19, 35}, + {19, 36}, {19, 37}, {19, 38}, {19, 39}, {19, 40}, + {20, 0}, + {21, 0}, {21, 1}, {21, 2}, {21, 3}, {21, 4}, {21, 5}, + {21, 6}, {21, 7}, {21, 8}, {21, 9}, {21, 10}, {21, 11}, + {21, 12}, {21, 13}, {21, 14}, {21, 15}, {21, 16}, {21, 17}, + {21, 18}, {21, 19}, {21, 20}, {21, 21}, {21, 22}, {21, 23}, + {21, 24}, {21, 25}, {21, 26}, {21, 27}, {21, 28}, {21, 29}, + {21, 30}, {21, 31}, {21, 32}, {21, 33}, {21, 34}, {21, 35}, + {21, 36}, {21, 37}, {21, 38}, + {22, 0}, {22, 1}, {22, 2}, {22, 3}, {22, 4}, {22, 5}, + {22, 6}, {22, 7}, {22, 8}, {22, 9}, {22, 10}, {22, 11}, + {22, 12}, {22, 13}, {22, 14}, {22, 15}, {22, 16}, {22, 17}, + {22, 18}, + {23, 0}, + {24, 0}, {24, 1}, {24, 2}, {24, 3}, {24, 4}, {24, 5}, + {24, 6}, {24, 7}, {24, 8}, + {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5}, + {25, 6}, {25, 7}, {25, 8}, {25, 9}, {25, 10}, {25, 11}, + {25, 12}, {25, 13}, {25, 14}, {25, 15}, {25, 16}, {25, 17}, + {25, 18}, + {26, 0}, + {27, 0}, + {28, 0}, {28, 1}, {28, 2}, {28, 3}, {28, 4}, {28, 5}, + {28, 6}, {28, 7}, {28, 8}, {28, 9}, {28, 10}, {28, 11}, + {28, 12}, {28, 13}, {28, 14}, {28, 15}, {28, 16}, {28, 17}, + {28, 18}, {28, 19}, {28, 20}, {28, 21}, {28, 22}, + {29, 0}, {29, 1}, {29, 2}, {29, 3}, {29, 4}, {29, 5}, + {29, 6}, {29, 7}, {29, 8}, {29, 9}, {29, 10}, {29, 11}, + {29, 12}, {29, 13}, + {30, 0}, {30, 1}, + {31, 0}, {31, 1}, {31, 2}, {31, 3}, {31, 4}, {31, 5}, + {31, 6}, + {32, 0}, {32, 1}, {32, 2}, {32, 3}, + {33, 0}, {33, 1}, {33, 2}, {33, 3}, {33, 4}, {33, 5}, + {34, 0}, {34, 1}, {34, 2}, {34, 3}, {34, 4}, {34, 5}, + {34, 6}, {34, 7}, {34, 8}, {34, 9}, {34, 10}, {34, 11}, + {34, 12}, {34, 13}, {34, 14}, {34, 15}, {34, 16}, {34, 17}, + {35, 0}, {35, 1}, {35, 2}, {35, 3}, {35, 4}, {35, 5}, + {35, 6}, {35, 7}, {35, 8}, {35, 9}, {35, 10}, {35, 11}, + {35, 12}, {35, 13}, {35, 14}, {35, 15}, {35, 16}, {35, 17}, + {35, 18}, {35, 19}, {35, 20}, {35, 21}, + {36, 0}, {36, 1}, {36, 2}, {36, 3}, {36, 4}, {36, 5}, + {37, 0}, {37, 1}, {37, 2}, {37, 3}, {37, 4}, {37, 5}, + {37, 6}, {37, 7}, {37, 8}, {37, 9}, {37, 10}, {37, 11}, + {37, 12}, {37, 13}, {37, 14}, {37, 15}, {37, 16}, {37, 17}, + {37, 18}, {37, 19}, {37, 20}, {37, 21}, {37, 22}, {37, 23}, + {37, 24}, {37, 25}, {37, 26}, + {38, 0}, {38, 1}, {38, 2}, {38, 3}, {38, 4}, {38, 5}, + {38, 6}, {38, 7}, {38, 8}, {38, 9}, {38, 10}, {38, 11}, + {38, 12}, + {39, 0}, + {40, 0}, {40, 1}, {40, 2}, {40, 3}, {40, 4}, {40, 5}, + {40, 6}, {40, 7}, + {41, 0}, {41, 1}, {41, 2}, {41, 3}, + {42, 0}, {42, 1}, {42, 2}, {42, 3}, {42, 4}, {42, 5}, + {42, 6}, {42, 7}, {42, 8}, {42, 9}, {42, 10}, {42, 11}, + {43, 0}, {43, 1}, {43, 2}, {43, 3}, {43, 4}, {43, 5}, + {43, 6}, {43, 7}, {43, 8}, {43, 9}, {43, 10}, {43, 11}, + {43, 12}, {43, 13}, {43, 14}, {43, 15}, {43, 16}, {43, 17}, + {43, 18}, {43, 19}, {43, 20}, {43, 21}, {43, 22}, {43, 23}, + {43, 24}, {43, 25}, {43, 26}, {43, 27}, {43, 28}, {43, 29}, + {43, 30}, {43, 31} +}; + +// Default palette +static const byte initVGAPalette[768] = { + 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x58, 0x58, 0x70, 0x70, 0x70, 0xfc, 0xfc, 0xfc, 0x00, 0xd0, 0x00, + 0x00, 0xfc, 0x00, 0xd8, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0xb0, 0xa0, 0xa0, 0xa0, + 0x50, 0xc8, 0xfc, 0x28, 0xfc, 0x28, 0xf0, 0xf0, 0x00, 0xfc, 0x28, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, + 0x20, 0x20, 0x20, 0x2c, 0x2c, 0x2c, 0x38, 0x38, 0x38, 0x44, 0x44, 0x44, 0x50, 0x50, 0x50, 0x60, 0x60, 0x60, + 0x70, 0x70, 0x70, 0x80, 0x80, 0x80, 0x90, 0x90, 0x90, 0xa0, 0xa0, 0xa0, 0xb4, 0xb4, 0xb4, 0xc8, 0xc8, 0xc8, + 0xe0, 0xe0, 0xe0, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, + 0xfc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, + 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, + 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, + 0xfc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, + 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, + 0x7c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, + 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, + 0xfc, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, + 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, + 0xb4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, + 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, + 0x70, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, + 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, + 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, + 0x70, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, + 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, + 0x38, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, + 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, + 0x70, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, + 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, + 0x50, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, + 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, + 0x40, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, + 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, + 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, + 0x40, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, + 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, + 0x20, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, + 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, + 0x40, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, + 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, + 0x2c, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, + 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const byte font[][5] = { + {0x00,0x00,0x00,0xff,0x00}, + {0x5f,0xff,0x00,0x00,0x00}, + {0x03,0x00,0x03,0xff,0x00}, + {0x14,0x7f,0x14,0x7f,0x14}, + {0x24,0x2a,0x7f,0x2a,0x12}, + {0x61,0x10,0x08,0x04,0x43}, + {0x38,0x4e,0x59,0x26,0x50}, + {0x03,0xff,0x00,0x00,0x00}, + {0x3e,0x41,0xff,0x00,0x00}, + {0x41,0x3e,0xff,0x00,0x00}, + {0x10,0x54,0x38,0x54,0x10}, + {0x10,0x10,0x7c,0x10,0x10}, + {0x80,0x40,0xff,0x00,0x00}, + {0x10,0x10,0x10,0x10,0x10}, + {0x40,0xff,0x00,0x00,0x00}, + {0x60,0x10,0x08,0x04,0x03}, + + {0x3e,0x41,0x41,0x41,0x3e}, /* digits */ + {0x04,0x02,0x7f,0xff,0x00}, + {0x42,0x61,0x51,0x49,0x46}, + {0x22,0x41,0x49,0x49,0x36}, + {0x18,0x14,0x12,0x7f,0x10}, + {0x27,0x45,0x45,0x45,0x39}, + {0x3e,0x49,0x49,0x49,0x32}, + {0x01,0x61,0x19,0x07,0x01}, + {0x36,0x49,0x49,0x49,0x36}, + {0x26,0x49,0x49,0x49,0x3e}, + + {0x44,0xff,0x00,0x00,0x00}, + {0x80,0x44,0xff,0x00,0x00}, + {0x10,0x28,0x44,0xff,0x00}, + {0x28,0x28,0x28,0x28,0x28}, + {0x44,0x28,0x10,0xff,0x00}, + {0x02,0x01,0x51,0x09,0x06}, + {0x3e,0x41,0x5d,0x5d,0x1e}, + + {0x7c,0x12,0x11,0x12,0x7c}, /* uppercase letters*/ + {0x7f,0x49,0x49,0x49,0x36}, + {0x3e,0x41,0x41,0x41,0x22}, + {0x7f,0x41,0x41,0x22,0x1c}, + {0x7f,0x49,0x49,0x49,0xff}, + {0x7f,0x09,0x09,0x09,0xff}, + {0x3e,0x41,0x41,0x49,0x3a}, + {0x7f,0x08,0x08,0x08,0x7f}, + {0x41,0x7f,0x41,0xff,0x00}, + {0x20,0x40,0x40,0x3f,0xff}, + {0x7f,0x08,0x14,0x22,0x41}, + {0x7f,0x40,0x40,0x40,0xff}, + {0x7f,0x02,0x04,0x02,0x7f}, + {0x7f,0x02,0x0c,0x10,0x7f}, + {0x3e,0x41,0x41,0x41,0x3e}, + {0x7f,0x09,0x09,0x09,0x06}, + {0x3e,0x41,0x51,0x21,0x5e}, + {0x7f,0x09,0x19,0x29,0x46}, + {0x26,0x49,0x49,0x49,0x32}, + {0x01,0x01,0x7f,0x01,0x01}, + {0x3f,0x40,0x40,0x40,0x3f}, + {0x07,0x18,0x60,0x18,0x07}, + {0x1f,0x60,0x18,0x60,0x1f}, + {0x63,0x14,0x08,0x14,0x63}, + {0x03,0x04,0x78,0x04,0x03}, + {0x61,0x51,0x49,0x45,0x43}, + + {0x7f,0x41,0x41,0xff,0x00}, + {0x03,0x04,0x08,0x10,0x60}, + {0x41,0x41,0x7f,0xff,0x00}, + {0x02,0x01,0x02,0xff,0x00}, + {0x80,0x80,0x80,0x80,0x80}, + {0x01,0x02,0xff,0x00,0x00}, + + {0x38,0x44,0x44,0x44,0x7c}, /* lowercase letters */ + {0x7f,0x44,0x44,0x44,0x38}, + {0x38,0x44,0x44,0x44,0x44}, + {0x38,0x44,0x44,0x44,0x7f}, + {0x38,0x54,0x54,0x54,0x58}, + {0x04,0x7e,0x05,0x01,0xff}, + {0x98,0xa4,0xa4,0xa4,0x7c}, + {0x7f,0x04,0x04,0x04,0x78}, + {0x7d,0xff,0x00,0x00,0x00}, + {0x80,0x80,0x7d,0xff,0x00}, + {0x7f,0x10,0x28,0x44,0xff}, + {0x7f,0xff,0x00,0x00,0x00}, + {0x7c,0x04,0x7c,0x04,0x78}, + {0x7c,0x04,0x04,0x04,0x78}, + {0x38,0x44,0x44,0x44,0x38}, + {0xfc,0x24,0x24,0x24,0x18}, + {0x18,0x24,0x24,0x24,0xfc}, + {0x7c,0x08,0x04,0x04,0xff}, + {0x48,0x54,0x54,0x54,0x24}, + {0x04,0x3e,0x44,0x40,0xff}, + {0x7c,0x40,0x40,0x40,0x3c}, + {0x0c,0x30,0x40,0x30,0x0c}, + {0x3c,0x40,0x3c,0x40,0x3c}, + {0x44,0x28,0x10,0x28,0x44}, + {0x9c,0xa0,0xa0,0xa0,0x7c}, + {0x44,0x64,0x54,0x4c,0x44}, + + {0x08,0x36,0x41,0xff,0x00}, + {0x77,0xff,0x00,0x00,0x00}, + {0x41,0x36,0x08,0xff,0x00}, + {0x02,0x01,0x02,0x01,0xff}, + {0xff,0x00,0x00,0x00,0x00}, + + {0xfe,0x49,0x49,0x4e,0x30}, /* sharp S */ + + {0x7c,0x41,0x40,0x41,0x3c}, /* umlauts */ + + {0x04,0x06,0x7f,0x06,0x04}, /* arrows */ + {0x20,0x60,0xfe,0x60,0x20}, + + {0x38,0x45,0x44,0x45,0x7c}, /* umlauts */ + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0x79,0x14,0x12,0x14,0x79}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0x38,0x45,0x44,0x45,0x38}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0xff,0x00,0x00,0x00,0x00}, + {0x3d,0x42,0x42,0x42,0x3d}, + {0x3d,0x40,0x40,0x40,0x3d}, +}; + +} diff --git a/engines/supernova/sound.cpp b/engines/supernova/sound.cpp new file mode 100644 index 0000000000..e7f3ce83bd --- /dev/null +++ b/engines/supernova/sound.cpp @@ -0,0 +1,65 @@ +/* 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 2 +* 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, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "audio/audiostream.h" +#include "audio/mixer.h" +#include "audio/decoders/raw.h" +#include "audio/mods/protracker.h" +#include "common/system.h" + +#include "supernova/resman.h" +#include "supernova/sound.h" +#include "supernova/supernova.h" + +namespace Supernova { + +Sound::Sound(Audio::Mixer *mixer, ResourceManager *resMan) + : _mixer(mixer) + , _resMan(resMan) { +} + +void Sound::play(AudioId index) { + Audio::AudioStream *stream = _resMan->getSoundStream(index); + + stop(); + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, stream, + -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); +} + +void Sound::play(MusicId index) { + Audio::AudioStream *stream = _resMan->getSoundStream(index); + + stop(); + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, stream, + -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); +} + +bool Sound::isPlaying() { + return _mixer->isSoundHandleActive(_soundHandle); +} + +void Sound::stop() { + if (_mixer->isSoundHandleActive(_soundHandle)) + _mixer->stopHandle(_soundHandle); +} + +} diff --git a/engines/supernova/sound.h b/engines/supernova/sound.h new file mode 100644 index 0000000000..100c9a372b --- /dev/null +++ b/engines/supernova/sound.h @@ -0,0 +1,80 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SUPERNOVA_SOUND_H +#define SUPERNOVA_SOUND_H + +#include "audio/mixer.h" + +namespace Supernova { + +class SupernovaEngine; +class ResourceManager; + +enum AudioId { + kAudioFoundLocation, // 44|0 + kAudioCrash, // 45|0 + kAudioVoiceHalt, // 46|0 + kAudioGunShot, // 46|2510 + kAudioSmash, // 46|4020 + kAudioVoiceSupernova, // 47|0 + kAudioVoiceYeah, // 47|24010 + kAudioRobotShock, // 48|0 + kAudioRobotBreaks, // 48|2510 + kAudioShock, // 48|10520 + kAudioTurntable, // 48|13530 + kAudioSiren, // 50|0 + kAudioSnoring, // 50|12786 + kAudioRocks, // 51|0 + kAudioDeath, // 53|0 + kAudioAlarm, // 54|0 + kAudioSuccess, // 54|8010 + kAudioSlideDoor, // 54|24020 + kAudioDoorOpen, // 54|30030 + kAudioDoorClose, // 54|31040 + kAudioNumSamples +}; + +enum MusicId { + kMusicIntro = 49, + kMusicOutro = 52 +}; + +class Sound { +public: + +public: + Sound(Audio::Mixer *mixer, ResourceManager *resMan); + + void play(AudioId index); + void play(MusicId index); + void stop(); + bool isPlaying(); +private: + Audio::Mixer *_mixer; + ResourceManager *_resMan; + Audio::SoundHandle _soundHandle; +}; + +} + +#endif diff --git a/engines/supernova/state.cpp b/engines/supernova/state.cpp index e41edbf1d5..00a35055b7 100644 --- a/engines/supernova/state.cpp +++ b/engines/supernova/state.cpp @@ -21,11 +21,13 @@ */ #include "common/system.h" +#include "graphics/cursorman.h" #include "graphics/palette.h" #include "gui/message.h" + +#include "supernova/screen.h" #include "supernova/supernova.h" #include "supernova/state.h" -#include "graphics/cursorman.h" namespace Supernova { @@ -136,13 +138,13 @@ bool GameManager::deserialize(Common::ReadStream *in, int version) { _inventoryScroll = in->readSint32LE(); _inventory.clear(); for (int i = 0; i < inventorySize; ++i) { - RoomID objectRoom = static_cast<RoomID>(in->readSint32LE()); + RoomId objectRoom = static_cast<RoomId>(in->readSint32LE()); int objectIndex = in->readSint32LE(); _inventory.add(*_rooms[objectRoom]->getObject(objectIndex)); } // Rooms - RoomID curRoomId = static_cast<RoomID>(in->readByte()); + RoomId curRoomId = static_cast<RoomId>(in->readByte()); for (int i = 0; i < NUMROOMS; ++i) { _rooms[i]->deserialize(in, version); } @@ -194,16 +196,16 @@ Object *Inventory::get(int index) const { if (index < _numObjects) return _inventory[index]; - return const_cast<Object *>(&Object::nullObject); + return _nullObject; } -Object *Inventory::get(ObjectID id) const { +Object *Inventory::get(ObjectId id) const { for (int i = 0; i < _numObjects; ++i) { if (_inventory[i]->_id == id) return _inventory[i]; } - return const_cast<Object *>(&Object::nullObject); + return _nullObject; } @@ -275,19 +277,20 @@ static Common::String timeToString(int msec) { return Common::String(s); } -StringID GameManager::guiCommands[] = { +StringId GameManager::guiCommands[] = { kStringCommandGo, kStringCommandLook, kStringCommandTake, kStringCommandOpen, kStringCommandClose, kStringCommandPress, kStringCommandPull, kStringCommandUse, kStringCommandTalk, kStringCommandGive }; -StringID GameManager::guiStatusCommands[] = { +StringId GameManager::guiStatusCommands[] = { kStringStatusCommandGo, kStringStatusCommandLook, kStringStatusCommandTake, kStringStatusCommandOpen, kStringStatusCommandClose, kStringStatusCommandPress, kStringStatusCommandPull, kStringStatusCommandUse, kStringStatusCommandTalk, kStringStatusCommandGive }; -GameManager::GameManager(SupernovaEngine *vm) - : _inventory(_inventoryScroll) - , _vm(vm) { +GameManager::GameManager(SupernovaEngine *vm, Sound *sound) + : _inventory(&_nullObject, _inventoryScroll) + , _vm(vm) + , _sound(sound) { initRooms(); changeRoom(INTRO); initState(); @@ -351,11 +354,10 @@ void GameManager::destroyRooms() { delete _rooms[OUTRO]; } - void GameManager::initState() { - Object::setObjectNull(_currentInputObject); - Object::setObjectNull(_inputObject[0]); - Object::setObjectNull(_inputObject[1]); + _currentInputObject = &_nullObject; + _inputObject[0] = &_nullObject; + _inputObject[1] = &_nullObject; _inputVerb = ACTION_WALK; _processInput = false; _guiEnabled = true; @@ -370,7 +372,7 @@ void GameManager::initState() { _oldTime = g_system->getMillis(); _timerPaused = 0; _timePaused = false; - _timer1 = 0; + _messageDuration = 0; _animationTimer = 0; _currentSentence = -1; @@ -466,7 +468,7 @@ void GameManager::initGui() { int cmdAvailableSpace = 320 - (cmdCount - 1) * 2; for (int i = 0; i < cmdCount; ++i) { const Common::String &text = _vm->getGameString(guiCommands[i]); - cmdAvailableSpace -= _vm->textWidth(text); + cmdAvailableSpace -= Screen::textWidth(text); } int commandButtonX = 0; @@ -476,7 +478,7 @@ void GameManager::initGui() { if (i < cmdCount - 1) { int space = cmdAvailableSpace / (cmdCount - i); cmdAvailableSpace -= space; - width = _vm->textWidth(text) + space; + width = Screen::textWidth(text) + space; } else width = 320 - commandButtonX; @@ -503,6 +505,75 @@ void GameManager::initGui() { _guiInventoryArrow[1].setTextPosition(273, 186); } +void GameManager::updateEvents() { + handleTime(); + if (_animationEnabled && !_vm->_screen->isMessageShown() && _animationTimer == 0) + _currentRoom->animation(); + + if (_state._eventCallback != kNoFn && _state._time >= _state._eventTime) { + _vm->_allowLoadGame = false; + _vm->_allowSaveGame = false; + _state._eventTime = kMaxTimerValue; + EventFunction fn = _state._eventCallback; + _state._eventCallback = kNoFn; + switch (fn) { + case kNoFn: + break; + case kSupernovaFn: + supernovaEvent(); + break; + case kGuardReturnedFn: + guardReturnedEvent(); + break; + case kGuardWalkFn: + guardWalkEvent(); + break; + case kTaxiFn: + taxiEvent(); + break; + case kSearchStartFn: + searchStartEvent(); + break; + } + _vm->_allowLoadGame = true; + _vm->_allowSaveGame = true; + return; + } + + if (_state._alarmOn && _state._timeAlarm <= _state._time) { + _state._alarmOn = false; + alarm(); + return; + } + + _mouseClicked = false; + _keyPressed = false; + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + _keyPressed = true; + processInput(event.kbd); + break; + case Common::EVENT_LBUTTONUP: + // fallthrough + case Common::EVENT_RBUTTONUP: + if (_currentRoom->getId() != INTRO && _sound->isPlaying()) + return; + _mouseClicked = true; + // fallthrough + case Common::EVENT_MOUSEMOVE: + _mouseClickType = event.type; + _mouseX = event.mouse.x; + _mouseY = event.mouse.y; + if (_guiEnabled) + processInput(); + break; + default: + break; + } + } +} void GameManager::processInput(Common::KeyState &state) { _key = state; @@ -529,14 +600,18 @@ void GameManager::processInput(Common::KeyState &state) { _vm->quitGame(); } break; + case Common::KEYCODE_d: + if (state.flags & Common::KBD_CTRL) + _vm->_console->attach(); + break; default: break; } } void GameManager::resetInputState() { - Object::setObjectNull(_inputObject[0]); - Object::setObjectNull(_inputObject[1]); + setObjectNull(_inputObject[0]); + setObjectNull(_inputObject[1]); _inputVerb = ACTION_WALK; _processInput = false; _mouseClicked = false; @@ -571,7 +646,7 @@ void GameManager::processInput() { mouseLocation = onNone; if (_mouseClickType == Common::EVENT_LBUTTONUP) { - if (_vm->_messageDisplayed) { + if (_vm->_screen->isMessageShown()) { // Hide the message and consume the event _vm->removeMessage(); if (mouseLocation != onCmdButton) @@ -583,7 +658,7 @@ void GameManager::processInput() { case onInventory: // Fallthrough if (_inputVerb == ACTION_GIVE || _inputVerb == ACTION_USE) { - if (Object::isNullObject(_inputObject[0])) { + if (isNullObject(_inputObject[0])) { _inputObject[0] = _currentInputObject; if (!_inputObject[0]->hasProperty(COMBINABLE)) _processInput = true; @@ -593,7 +668,7 @@ void GameManager::processInput() { } } else { _inputObject[0] = _currentInputObject; - if (!Object::isNullObject(_currentInputObject)) + if (!isNullObject(_currentInputObject)) _processInput = true; } break; @@ -614,13 +689,13 @@ void GameManager::processInput() { } } else if (_mouseClickType == Common::EVENT_RBUTTONUP) { - if (_vm->_messageDisplayed) { + if (_vm->_screen->isMessageShown()) { // Hide the message and consume the event _vm->removeMessage(); return; } - if (Object::isNullObject(_currentInputObject)) + if (isNullObject(_currentInputObject)) return; if (mouseLocation == onObject || mouseLocation == onInventory) { @@ -666,8 +741,9 @@ void GameManager::processInput() { for (int i = 0; (_currentRoom->getObject(i)->_id != INVALIDOBJECT) && (field == -1) && i < kMaxObject; i++) { click = _currentRoom->getObject(i)->_click; - if (click != 255 && _vm->_currentImage) { - MSNImageDecoder::ClickField *clickField = _vm->_currentImage->_clickField; + const MSNImage *image = _vm->_screen->getCurrentImage(); + if (click != 255 && image) { + const MSNImage::ClickField *clickField = image->_clickField; do { if ((_mouseX >= clickField[click].x1) && (_mouseX <= clickField[click].x2) && (_mouseY >= clickField[click].y1) && (_mouseY <= clickField[click].y2)) @@ -698,7 +774,7 @@ void GameManager::processInput() { break; } - Object::setObjectNull(_currentInputObject); + setObjectNull(_currentInputObject); _mouseField = field; if (_mouseField >= 0 && _mouseField < 256) @@ -737,6 +813,14 @@ void GameManager::processInput() { } } +void GameManager::setObjectNull(Object *&obj) { + obj = &_nullObject; +} + +bool GameManager::isNullObject(Object *obj) { + return obj == &_nullObject; +} + void GameManager::corridorOnEntrance() { if (_state._corridorSearch) busted(0); @@ -761,7 +845,7 @@ void GameManager::telomat(int nr) { "Alga Hurz Li" }; - StringID dial1[4]; + StringId dial1[4]; dial1[0] = kStringTelomat1; dial1[1] = kNoString; dial1[2] = kStringTelomat3; @@ -769,7 +853,7 @@ void GameManager::telomat(int nr) { static byte rows1[3] = {1, 2, 1}; - StringID dial2[4]; + StringId dial2[4]; dial2[0] = kStringTelomat4; dial2[1] = kStringTelomat5; dial2[2] = kStringTelomat6; @@ -813,7 +897,7 @@ void GameManager::telomat(int nr) { i >>= 1; if (i == 4) { _vm->renderText(kStringTelomat14, 50, 120, kColorGreen); - wait2(10); + wait(10); _vm->renderBox(0, 0, 320, 200, kColorBlack); _vm->renderRoom(*_currentRoom); _vm->paletteBrightness(); @@ -824,7 +908,7 @@ void GameManager::telomat(int nr) { if ((i == nr) || _rooms[BCORRIDOR]->getObject(4 + i)->hasProperty(CAUGHT)) { _vm->renderText(kStringTelomat15, 50, 120, kColorGreen); - wait2(10); + wait(10); _vm->renderBox(0, 0, 320, 200, kColorBlack); _vm->renderRoom(*_currentRoom); _vm->paletteBrightness(); @@ -834,12 +918,12 @@ void GameManager::telomat(int nr) { } _vm->renderText(kStringTelomat16, 50, 120, kColorGreen); - wait2(10); + wait(10); _vm->renderBox(0, 0, 320, 200, kColorBlack); _vm->renderRoom(*_currentRoom); _vm->paletteBrightness(); _vm->renderMessage(kStringTelomat17, kMessageTop, name2[i]); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); if (_state._nameSeen[nr]) { Common::String string = _vm->getGameString(kStringTelomat2); @@ -851,7 +935,7 @@ void GameManager::telomat(int nr) { switch (dialog(3, rows1, dial1, 1)) { case 1: _vm->renderMessage(kStringTelomat18, kMessageTop); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); if ((_state._destination == 255) && !_rooms[BCORRIDOR]->isSectionVisible(7)) { _state._eventTime = _state._time + ticksToMsec(150); @@ -861,10 +945,10 @@ void GameManager::telomat(int nr) { } break; case 0: _vm->renderMessage(kStringTelomat19, kMessageTop); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); if (dialog(4, rows2, dial2, 0) != 3) { - wait2(10); + wait(10); say(kStringTelomat20); } _rooms[BCORRIDOR]->setSectionVisible(7, true); @@ -888,7 +972,7 @@ void GameManager::telomat(int nr) { if (_key.keycode == Common::KEYCODE_RETURN) { _vm->renderText(kStringShipSleepCabin9, 100, 120, kColorGreen); - wait2(10); + wait(10); } // fallthrough case Common::KEYCODE_ESCAPE: @@ -926,7 +1010,7 @@ void GameManager::guardNoticed() { _vm->paletteFadeIn(); _vm->renderImage(2); reply(kStringGuardNoticed1, 2, 5); - wait2(2); + wait(2); reply(kStringGuardNoticed2, 2, 5); _vm->paletteFadeOut(); _currentRoom->setSectionVisible(2, false); @@ -947,19 +1031,19 @@ void GameManager::busted(int i) { i = 5; if (!_currentRoom->getObject(0)->hasProperty(OPENED)) { _vm->renderImage(i - 1); - _vm->playSound(kAudioDoorOpen); - wait2(2); + _sound->play(kAudioDoorOpen); + wait(2); } _vm->renderImage(i); - wait2(3); + wait(3); _vm->renderImage(i + 3); - _vm->playSound(kAudioVoiceHalt); + _sound->play(kAudioVoiceHalt); _vm->renderImage(i); - wait2(5); + wait(5); if (_currentRoom->getId() == OFFICE_L2) i = 13; _vm->renderImage(i + 1); - wait2(3); + wait(3); _vm->renderImage(i + 2); shot(0, 0); } else if (_currentRoom->getId() == BCORRIDOR) @@ -973,8 +1057,8 @@ void GameManager::busted(int i) { else _vm->renderImage(33); // above } - _vm->playSound(kAudioVoiceHalt); - wait2(3); + _sound->play(kAudioVoiceHalt); + wait(3); shot(0, 0); } @@ -1025,7 +1109,7 @@ void GameManager::supernovaEvent() { CursorMan.showMouse(false); if (_currentRoom->getId() <= CAVE) { _vm->renderMessage(kStringSupernova1); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); _vm->paletteFadeOut(); changeRoom(MEETUP); @@ -1038,7 +1122,7 @@ void GameManager::supernovaEvent() { _vm->paletteFadeIn(); } _vm->renderMessage(kStringSupernova2); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); _vm->setCurrentImage(26); _vm->renderImage(0); @@ -1046,28 +1130,28 @@ void GameManager::supernovaEvent() { novaScroll(); _vm->paletteFadeOut(); _vm->renderBox(0, 0, 320, 200, kColorBlack); - _vm->_menuBrightness = 255; + _vm->_screen->setGuiBrightness(255); _vm->paletteBrightness(); if (_currentRoom->getId() == GLIDER) { _vm->renderMessage(kStringSupernova3); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); - _vm->_menuBrightness = 0; + _vm->_screen->setGuiBrightness(0); _vm->paletteBrightness(); _vm->renderRoom(*_currentRoom); _vm->paletteFadeIn(); _vm->renderMessage(kStringSupernova4, kMessageTop); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); _vm->renderMessage(kStringSupernova5, kMessageTop); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); _vm->renderMessage(kStringSupernova6, kMessageTop); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); _vm->renderMessage(kStringSupernova7, kMessageTop); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); changeRoom(MEETUP2); _rooms[MEETUP2]->setSectionVisible(1, true); @@ -1077,9 +1161,9 @@ void GameManager::supernovaEvent() { _inventory.remove(*(_rooms[ROGER]->getObject(8))); } else { _vm->renderMessage(kStringSupernova8); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); - _vm->_menuBrightness = 0; + _vm->_screen->setGuiBrightness(0); _vm->paletteBrightness(); changeRoom(MEETUP2); if (_rooms[ROGER]->getObject(3)->hasProperty(CARRIED) && !_rooms[GLIDER]->isSectionVisible(5)) { @@ -1121,7 +1205,7 @@ void GameManager::walk(int imgId) { _vm->renderImage(_prevImgId + 128); _vm->renderImage(imgId); _prevImgId = imgId; - wait2(3); + wait(3); } void GameManager::guardWalkEvent() { @@ -1130,14 +1214,14 @@ void GameManager::guardWalkEvent() { _rooms[BCORRIDOR]->getObject(_state._origin + 4)->hasProperty(OPENED)); _rooms[BCORRIDOR]->getObject(_state._origin + 4)->disableProperty(OCCUPIED); if (_currentRoom == _rooms[BCORRIDOR]) { - if (_vm->_messageDisplayed) + if (_vm->_screen->isMessageShown()) _vm->removeMessage(); if (!behind) { _vm->renderImage(_state._origin + 1); _prevImgId = _state._origin + 1; - _vm->playSound(kAudioDoorOpen); - wait2(3); + _sound->play(kAudioDoorOpen); + wait(3); } int imgId; @@ -1158,13 +1242,13 @@ void GameManager::guardWalkEvent() { } _vm->renderImage(imgId); if (!behind) { - wait2(3); + wait(3); _vm->renderImage(_prevImgId + 128); - _vm->playSound(kAudioDoorClose); + _sound->play(kAudioDoorClose); } _prevImgId = imgId; - wait2(3); + wait(3); switch (_state._origin) { case 0: walk(12); @@ -1221,12 +1305,12 @@ void GameManager::guardWalkEvent() { if (behind) { _vm->renderImage(_state._destination + 1); - _vm->playSound(kAudioDoorOpen); - wait2(3); + _sound->play(kAudioDoorOpen); + wait(3); _vm->renderImage(_prevImgId + 128); - wait2(3); + wait(3); _vm->renderImage(_state._destination + 1 + 128); - _vm->playSound(kAudioDoorClose); + _sound->play(kAudioDoorClose); _rooms[BCORRIDOR]->getObject(_state._destination + 4)->setProperty(OCCUPIED); _state._destination = 255; } else if (_rooms[BCORRIDOR]->isSectionVisible(_state._destination + 1)) { @@ -1236,7 +1320,7 @@ void GameManager::guardWalkEvent() { _state._eventTime = _state._time + ticksToMsec(60); _state._eventCallback = kGuardWalkFn; } else { - wait2(18); + wait(18); SWAP(_state._origin, _state._destination); _state._eventCallback = kGuardWalkFn; } @@ -1266,7 +1350,7 @@ void GameManager::taxiEvent() { _vm->renderImage(1); _vm->renderImage(2); - _vm->playSound(kAudioRocks); + _sound->play(kAudioRocks); screenShake(); _vm->renderImage(9); _currentRoom->getObject(1)->setProperty(OPENED); @@ -1274,7 +1358,7 @@ void GameManager::taxiEvent() { _currentRoom->setSectionVisible(2, false); _vm->renderImage(3); for (int i = 4; i <= 8; i++) { - wait2(2); + wait(2); _vm->renderImage(invertSection(i - 1)); _vm->renderImage(i); } @@ -1292,7 +1376,7 @@ void GameManager::great(uint number) { if (number && (_state._greatFlag & (1 << number))) return; - _vm->playSound(kAudioSuccess); + _sound->play(kAudioSuccess); _state._greatFlag |= 1 << number; } @@ -1321,7 +1405,7 @@ void GameManager::sentence(int number, bool brightness) { } } -void GameManager::say(StringID textId) { +void GameManager::say(StringId textId) { Common::String str = _vm->getGameString(textId); if (!str.empty()) say(str.c_str()); @@ -1351,7 +1435,7 @@ void GameManager::say(const char *text) { _vm->renderBox(0, 138, 320, 62, kColorBlack); } -void GameManager::reply(StringID textId, int aus1, int aus2) { +void GameManager::reply(StringId textId, int aus1, int aus2) { Common::String str = _vm->getGameString(textId); if (!str.empty()) reply(str.c_str(), aus1, aus2); @@ -1375,7 +1459,7 @@ void GameManager::reply(const char *text, int aus1, int aus2) { _vm->removeMessage(); } -int GameManager::dialog(int num, byte rowLength[6], StringID text[6], int number) { +int GameManager::dialog(int num, byte rowLength[6], StringId text[6], int number) { _vm->_allowLoadGame = false; _guiEnabled = false; @@ -1407,7 +1491,12 @@ int GameManager::dialog(int num, byte rowLength[6], StringID text[6], int number _currentSentence = -1; do { - mouseInput3(); + do { + updateEvents(); + mousePosDialog(_mouseX, _mouseY); + g_system->updateScreen(); + g_system->delayMillis(_vm->_delay); + } while (!_mouseClicked && !_vm->shouldQuit()); } while (_currentSentence == -1 && !_vm->shouldQuit()); _vm->renderBox(0, 138, 320, 62, kColorBlack); @@ -1443,7 +1532,7 @@ void GameManager::turnOn() { return; _state._powerOff = false; - _vm->_brightness = 255; + _vm->_screen->setViewportBrightness(255); _rooms[SLEEP]->setSectionVisible(1, false); _rooms[SLEEP]->setSectionVisible(2, false); _rooms[COCKPIT]->setSectionVisible(22, false); @@ -1462,7 +1551,7 @@ void GameManager::takeObject(Object &obj) { void GameManager::drawCommandBox() { for (int i = 0; i < ARRAYSIZE(_guiCommandButton); ++i) { _vm->renderBox(_guiCommandButton[i]); - int space = (_guiCommandButton[i].width() - _vm->textWidth(_guiCommandButton[i].getText())) / 2; + int space = (_guiCommandButton[i].width() - Screen::textWidth(_guiCommandButton[i].getText())) / 2; _vm->renderText(_guiCommandButton[i].getText(), _guiCommandButton[i].getTextPos().x + space, _guiCommandButton[i].getTextPos().y, @@ -1491,7 +1580,7 @@ void GameManager::drawInventory() { uint16 GameManager::getKeyInput(bool blockForPrintChar) { while (!_vm->shouldQuit()) { - _vm->updateEvents(); + updateEvents(); if (_keyPressed) { if (blockForPrintChar) { if (Common::isPrint(_key.keycode) || @@ -1521,7 +1610,7 @@ uint16 GameManager::getKeyInput(bool blockForPrintChar) { Common::EventType GameManager::getMouseInput() { while (!_vm->shouldQuit()) { - _vm->updateEvents(); + updateEvents(); if (_mouseClicked) return _mouseClickType; g_system->updateScreen(); @@ -1532,7 +1621,7 @@ Common::EventType GameManager::getMouseInput() { void GameManager::getInput() { while (!_vm->shouldQuit()) { - _vm->updateEvents(); + updateEvents(); if (_mouseClicked || _keyPressed) break; g_system->updateScreen(); @@ -1540,15 +1629,6 @@ void GameManager::getInput() { } } -void GameManager::mouseInput3() { - do { - _vm->updateEvents(); - mousePosDialog(_mouseX, _mouseY); - g_system->updateScreen(); - g_system->delayMillis(_vm->_delay); - } while (!_mouseClicked && !_vm->shouldQuit()); -} - void GameManager::roomBrightness() { _roomBrightness = 255; if ((_currentRoom->getId() != OUTSIDE) && (_currentRoom->getId() < ROCKS) && _state._powerOff) @@ -1558,22 +1638,22 @@ void GameManager::roomBrightness() { else if ((_currentRoom->getId() == GUARD3) && _state._powerOff) _roomBrightness = 0; - if (_vm->_brightness != 0) - _vm->_brightness = _roomBrightness; + if (_vm->_screen->getViewportBrightness() != 0) + _vm->_screen->setViewportBrightness(_roomBrightness); _vm->paletteBrightness(); } -void GameManager::changeRoom(RoomID id) { +void GameManager::changeRoom(RoomId id) { _currentRoom = _rooms[id]; _newRoom = true; } -void GameManager::wait2(int ticks) { +void GameManager::wait(int ticks) { int32 end = _state._time + ticksToMsec(ticks); do { g_system->delayMillis(_vm->_delay); - _vm->updateEvents(); + updateEvents(); g_system->updateScreen(); } while (_state._time < end && !_vm->shouldQuit()); } @@ -1582,7 +1662,7 @@ void GameManager::waitOnInput(int ticks) { int32 end = _state._time + ticksToMsec(ticks); do { g_system->delayMillis(_vm->_delay); - _vm->updateEvents(); + updateEvents(); g_system->updateScreen(); } while (_state._time < end && !_vm->shouldQuit() && !_keyPressed && !_mouseClicked); } @@ -1592,7 +1672,7 @@ bool GameManager::waitOnInput(int ticks, Common::KeyCode &keycode) { int32 end = _state._time + ticksToMsec(ticks); do { g_system->delayMillis(_vm->_delay); - _vm->updateEvents(); + updateEvents(); g_system->updateScreen(); if (_keyPressed) { keycode = _key.keycode; @@ -1652,14 +1732,14 @@ void GameManager::saveTime() { void GameManager::screenShake() { for (int i = 0; i < 12; ++i) { _vm->_system->setShakePos(8); - wait2(1); + wait(1); _vm->_system->setShakePos(0); - wait2(1); + wait(1); } } void GameManager::shock() { - _vm->playSound(kAudioShock); + _sound->play(kAudioShock); dead(kStringShock); } @@ -1704,24 +1784,24 @@ void GameManager::edit(Common::String &input, int x, int y, uint length) { kScreenWidth - x : (length + 1) * (kFontWidth + 2); while (isEditing) { - _vm->_textCursorX = x; - _vm->_textCursorY = y; - _vm->_textColor = kColorWhite99; + _vm->_screen->setTextCursorPos(x, y); + _vm->_screen->setTextCursorColor(kColorWhite99); _vm->renderBox(x, y - 1, overdrawWidth, 9, kColorDarkBlue); for (uint i = 0; i < input.size(); ++i) { // Draw char highlight depending on cursor position if (i == cursorIndex) { - _vm->renderBox(_vm->_textCursorX, y - 1, _vm->textWidth(input[i]), 9, kColorWhite99); - _vm->_textColor = kColorDarkBlue; + _vm->renderBox(_vm->_screen->getTextCursorPos().x, y - 1, + Screen::textWidth(input[i]), 9, kColorWhite99); + _vm->_screen->setTextCursorColor(kColorDarkBlue); _vm->renderText(input[i]); - _vm->_textColor = kColorWhite99; + _vm->_screen->setTextCursorColor(kColorWhite99); } else _vm->renderText(input[i]); } if (cursorIndex == input.size()) { - _vm->renderBox(_vm->_textCursorX + 1, y - 1, 6, 9, kColorDarkBlue); - _vm->renderBox(_vm->_textCursorX , y - 1, 1, 9, kColorWhite99); + _vm->renderBox(_vm->_screen->getTextCursorPos().x + 1, y - 1, 6, 9, kColorDarkBlue); + _vm->renderBox(_vm->_screen->getTextCursorPos().x, y - 1, 1, 9, kColorWhite99); } getKeyInput(true); @@ -1767,15 +1847,15 @@ void GameManager::edit(Common::String &input, int x, int y, uint length) { void GameManager::shot(int a, int b) { if (a) _vm->renderImage(a); - _vm->playSound(kAudioGunShot); - wait2(2); + _sound->play(kAudioGunShot); + wait(2); if (b) _vm->renderImage(b); - wait2(2); + wait(2); if (a) _vm->renderImage(a); - _vm->playSound(kAudioGunShot); - wait2(2); + _sound->play(kAudioGunShot); + wait(2); if (b) _vm->renderImage(b); @@ -1801,7 +1881,7 @@ void GameManager::drawStatus() { _vm->renderBox(0, 140, 320, 9, kColorWhite25); _vm->renderText(_vm->getGameString(guiStatusCommands[index]), 1, 141, kColorDarkGreen); - if (Object::isNullObject(_inputObject[0])) + if (isNullObject(_inputObject[0])) _vm->renderText(_currentInputObject->_name); else { _vm->renderText(_inputObject[0]->_name); @@ -1832,19 +1912,18 @@ void GameManager::closeLocker(const Room *room, Object *obj, Object *lock, int s } } -void GameManager::dead(StringID messageId) { +void GameManager::dead(StringId messageId) { _vm->paletteFadeOut(); _guiEnabled = false; _vm->setCurrentImage(11); _vm->renderImage(0); _vm->renderMessage(messageId); - _vm->playSound(kAudioDeath); + _sound->play(kAudioDeath); _vm->paletteFadeIn(); getInput(); _vm->paletteFadeOut(); _vm->removeMessage(); - // TODO: Load screen destroyRooms(); initRooms(); initState(); @@ -1926,10 +2005,10 @@ bool GameManager::genericInteract(Action verb, Object &obj1, Object &obj2) { } } else if ((verb == ACTION_LOOK) && (obj1._id == NEWSPAPER)) { _vm->renderMessage(kStringGenericInteract_10); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); _vm->renderMessage(kStringGenericInteract_11); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); _vm->setCurrentImage(2); _vm->renderImage(0); @@ -2127,7 +2206,7 @@ bool GameManager::genericInteract(Action verb, Object &obj1, Object &obj2) { _vm->renderMessage(kStringGenericInteract_30); else if ((verb == ACTION_LOOK) && (obj1._id == BOOK2)) { _vm->renderMessage(kStringGenericInteract_31); - waitOnInput(_timer1); + waitOnInput(_messageDuration); _vm->removeMessage(); _vm->renderMessage(kStringGenericInteract_32); } else @@ -2192,7 +2271,7 @@ void GameManager::handleInput() { byte i = _inputObject[0]->_click; _inputObject[0]->_click = _inputObject[0]->_click2; _inputObject[0]->_click2 = i; - _vm->playSound(kAudioDoorOpen); + _sound->play(kAudioDoorOpen); } break; @@ -2211,7 +2290,7 @@ void GameManager::handleInput() { byte i = _inputObject[0]->_click; _inputObject[0]->_click = _inputObject[0]->_click2; _inputObject[0]->_click2 = i; - _vm->playSound(kAudioDoorClose); + _sound->play(kAudioDoorClose); } break; @@ -2230,7 +2309,7 @@ void GameManager::handleInput() { } void GameManager::executeRoom() { - if (_processInput && !_vm->_messageDisplayed && _guiEnabled) { + if (_processInput && !_vm->_screen->isMessageShown() && _guiEnabled) { handleInput(); if (_mouseClicked) { Common::Event event; @@ -2246,7 +2325,7 @@ void GameManager::executeRoom() { } if (_guiEnabled) { - if (!_vm->_messageDisplayed) { + if (!_vm->_screen->isMessageShown()) { g_system->fillScreen(kColorBlack); _vm->renderRoom(*_currentRoom); } @@ -2257,7 +2336,7 @@ void GameManager::executeRoom() { } roomBrightness(); - if (_vm->_brightness == 0) + if (_vm->_screen->getViewportBrightness() == 0) _vm->paletteFadeIn(); if (!_currentRoom->hasSeen() && _newRoom) { @@ -2269,31 +2348,31 @@ void GameManager::executeRoom() { void GameManager::guardShot() { _vm->renderImage(2); _vm->renderImage(5); - wait2(3); + wait(3); _vm->renderImage(2); - _vm->playSound(kAudioVoiceHalt); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - wait2(1); + _sound->play(kAudioVoiceHalt); + while (_sound->isPlaying()) + wait(1); _vm->renderImage(5); - wait2(5); + wait(5); _vm->renderImage(3); - wait2(3); + wait(3); shot(4, 3); } void GameManager::guard3Shot() { _vm->renderImage(1); - wait2(3); - _vm->playSound(kAudioVoiceHalt); // 46/0 - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) - wait2(1); + wait(3); + _sound->play(kAudioVoiceHalt); // 46/0 + while (_sound->isPlaying()) + wait(1); - wait2(5); + wait(5); _vm->renderImage(2); - wait2(3); + wait(3); shot(3,2); } @@ -2337,12 +2416,12 @@ void GameManager::alarmSound() { _vm->removeMessage(); _vm->renderMessage(kStringAlarm); - int32 end = _state._time + ticksToMsec(_timer1); + int32 end = _state._time + ticksToMsec(_messageDuration); do { - _vm->playSound(kAudioAlarm); - while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) { + _sound->play(kAudioAlarm); + while (_sound->isPlaying()) { g_system->delayMillis(_vm->_delay); - _vm->updateEvents(); + updateEvents(); g_system->updateScreen(); } } while (_state._time < end && !_vm->shouldQuit()); diff --git a/engines/supernova/state.h b/engines/supernova/state.h index ab21842296..1b885ccbdd 100644 --- a/engines/supernova/state.h +++ b/engines/supernova/state.h @@ -23,9 +23,11 @@ #ifndef SUPERNOVA_STATE_H #define SUPERNOVA_STATE_H +#include "common/events.h" #include "common/rect.h" #include "common/keyboard.h" #include "supernova/rooms.h" +#include "supernova/sound.h" namespace Supernova { @@ -63,8 +65,9 @@ struct GameState { class Inventory { public: - Inventory(int &inventoryScroll) + Inventory(Object *nullObject, int &inventoryScroll) : _numObjects(0) + , _nullObject(nullObject) , _inventoryScroll(inventoryScroll) {} @@ -72,11 +75,12 @@ public: void remove(Object &obj); void clear(); Object *get(int index) const; - Object *get(ObjectID id) const; + Object *get(ObjectId id) const; int getSize() const { return _numObjects; } private: Object *_inventory[kMaxCarry]; + Object *_nullObject; int &_inventoryScroll; int _numObjects; }; @@ -121,18 +125,20 @@ private: class GameManager { public: - GameManager(SupernovaEngine *vm); + GameManager(SupernovaEngine *vm, Sound *sound); ~GameManager(); + void updateEvents(); void processInput(Common::KeyState &state); void processInput(); void executeRoom(); bool serialize(Common::WriteStream *out); bool deserialize(Common::ReadStream *in, int version); - static StringID guiCommands[]; - static StringID guiStatusCommands[]; + static StringId guiCommands[]; + static StringId guiStatusCommands[]; SupernovaEngine *_vm; + Sound *_sound; Common::KeyState _key; Common::EventType _mouseClickType; bool _mouseClicked; @@ -150,13 +156,14 @@ public: bool _animationEnabled; byte _roomBrightness; Action _inputVerb; + Object _nullObject; Object *_currentInputObject; Object *_inputObject[2]; bool _waitEvent; int32 _oldTime; uint _timePaused; bool _timerPaused; - int32 _timer1; + int32 _messageDuration; int32 _animationTimer; int _inventoryScroll; int _exitList[25]; @@ -166,11 +173,13 @@ public: // Dialog int _currentSentence; int _sentenceNumber[6]; - StringID _texts[6]; + StringId _texts[6]; byte _rows[6]; byte _rowsStart[6]; void takeObject(Object &obj); + void setObjectNull(Object *&obj); + bool isNullObject(Object *obj); void initState(); void initRooms(); @@ -184,8 +193,7 @@ public: Common::EventType getMouseInput(); uint16 getKeyInput(bool blockForPrintChar = false); void getInput(); - void mouseInput3(); - void wait2(int ticks); + void wait(int ticks); void waitOnInput(int ticks); bool waitOnInput(int ticks, Common::KeyCode &keycode); void turnOff(); @@ -203,7 +211,7 @@ public: void drawStatus(); void drawCommandBox(); void drawInventory(); - void changeRoom(RoomID id); + void changeRoom(RoomId id); void resetInputState(); void handleInput(); void handleTime(); @@ -211,12 +219,12 @@ public: void loadTime(); void saveTime(); void setAnimationTimer(int ticks); - void dead(StringID messageId); - int dialog(int num, byte rowLength[6], StringID text[6], int number); + void dead(StringId messageId); + int dialog(int num, byte rowLength[6], StringId text[6], int number); void sentence(int number, bool brightness); - void say(StringID textId); + void say(StringId textId); void say(const char *text); - void reply(StringID textId, int aus1, int aus2); + void reply(StringId textId, int aus1, int aus2); void reply(const char *text, int aus1, int aus2); void mousePosDialog(int x, int y); void shot(int a, int b); diff --git a/engines/supernova/supernova.cpp b/engines/supernova/supernova.cpp index 50731ae52f..c47e476de7 100644 --- a/engines/supernova/supernova.cpp +++ b/engines/supernova/supernova.cpp @@ -20,7 +20,6 @@ * */ -#include "audio/mods/protracker.h" #include "common/config-manager.h" #include "common/debug.h" #include "common/debug-channels.h" @@ -42,36 +41,14 @@ #include "graphics/thumbnail.h" #include "gui/saveload.h" +#include "supernova/resman.h" +#include "supernova/screen.h" +#include "supernova/sound.h" #include "supernova/supernova.h" #include "supernova/state.h" namespace Supernova { -const AudioInfo audioInfo[kAudioNumSamples] = { - {44, 0, -1}, - {45, 0, -1}, - {46, 0, 2510}, - {46, 2510, 4020}, - {46, 4020, -1}, - {47, 0, 24010}, - {47, 24010, -1}, - {48, 0, 2510}, - {48, 2510, 10520}, - {48, 10520, 13530}, - {48, 13530, -1}, - {50, 0, 12786}, - {50, 12786, -1}, - {51, 0, -1}, - {53, 0, -1}, - {54, 0, 8010}, - {54, 8010, 24020}, - {54, 24020, 30030}, - {54, 30030, 31040}, - {54, 31040, -1} -}; - -const Object Object::nullObject; - ObjectType operator|(ObjectType a, ObjectType b) { return static_cast<ObjectType>(+a | +b); } @@ -98,74 +75,37 @@ ObjectType &operator^=(ObjectType &a, ObjectType b) { SupernovaEngine::SupernovaEngine(OSystem *syst) : Engine(syst) - , _console(NULL) - , _gm(NULL) - , _currentImage(NULL) - , _soundMusicIntro(NULL) - , _soundMusicOutro(NULL) - , _rnd("supernova") - , _brightness(255) - , _menuBrightness(255) + , _console(nullptr) + , _gm(nullptr) + , _sound(nullptr) + , _resMan(nullptr) + , _screen(nullptr) , _delay(33) , _textSpeed(kTextSpeed[2]) - , _screenWidth(320) - , _screenHeight(200) - , _messageDisplayed(false) , _allowLoadGame(true) - , _allowSaveGame(true) -{ -// const Common::FSNode gameDataDir(ConfMan.get("path")); -// SearchMan.addSubDirectoryMatching(gameDataDir, "sound"); - + , _allowSaveGame(true) { if (ConfMan.hasKey("textspeed")) _textSpeed = ConfMan.getInt("textspeed"); - // setup engine specific debug channels DebugMan.addDebugChannel(kDebugGeneral, "general", "Supernova general debug channel"); } SupernovaEngine::~SupernovaEngine() { DebugMan.clearAllDebugChannels(); - delete _currentImage; delete _console; delete _gm; - delete _soundMusicIntro; - delete _soundMusicOutro; + delete _sound; + delete _resMan; + delete _screen; } Common::Error SupernovaEngine::run() { - Graphics::ModeList modes; - modes.push_back(Graphics::Mode(320, 200)); - modes.push_back(Graphics::Mode(640, 480)); - initGraphicsModes(modes); - initGraphics(_screenWidth, _screenHeight); - - Common::Error status = loadGameStrings(); - if (status.getCode() != Common::kNoError) - return status; - - _gm = new GameManager(this); - _console = new Console(this, _gm); - - initData(); - initPalette(); - - CursorMan.replaceCursor(_mouseNormal, 16, 16, 0, 0, kColorCursorTransparent); - CursorMan.replaceCursorPalette(initVGAPalette, 0, 16); - CursorMan.showMouse(true); - - setTotalPlayTime(0); - - int saveSlot = ConfMan.getInt("save_slot"); - if (saveSlot >= 0) { - if (loadGameState(saveSlot).getCode() != Common::kNoError) - error("Failed to load save game from slot %i", saveSlot); - } + init(); while (!shouldQuit()) { uint32 start = _system->getMillis(); - updateEvents(); + _gm->updateEvents(); _gm->executeRoom(); _console->onFrame(); _system->updateScreen(); @@ -174,89 +114,34 @@ Common::Error SupernovaEngine::run() { _system->delayMillis(end); } - stopSound(); + _mixer->stopAll(); return Common::kNoError; } -void SupernovaEngine::updateEvents() { - _gm->handleTime(); - if (_gm->_animationEnabled && !_messageDisplayed && _gm->_animationTimer == 0) - _gm->_currentRoom->animation(); - - if (_gm->_state._eventCallback != kNoFn && _gm->_state._time >= _gm->_state._eventTime) { - _allowLoadGame = false; - _allowSaveGame = false; - _gm->_state._eventTime = kMaxTimerValue; - EventFunction fn = _gm->_state._eventCallback; - _gm->_state._eventCallback = kNoFn; - switch (fn) { - case kNoFn: - break; - case kSupernovaFn: - _gm->supernovaEvent(); - break; - case kGuardReturnedFn: - _gm->guardReturnedEvent(); - break; - case kGuardWalkFn: - _gm->guardWalkEvent(); - break; - case kTaxiFn: - _gm->taxiEvent(); - break; - case kSearchStartFn: - _gm->searchStartEvent(); - break; - } - _allowLoadGame = true; - _allowSaveGame = true; - return; - } - - if (_gm->_state._alarmOn && _gm->_state._timeAlarm <= _gm->_state._time) { - _gm->_state._alarmOn = false; - _gm->alarm(); - return; - } +void SupernovaEngine::init() { + Graphics::ModeList modes; + modes.push_back(Graphics::Mode(320, 200)); + modes.push_back(Graphics::Mode(640, 480)); + initGraphicsModes(modes); + initGraphics(320, 200); - _gm->_mouseClicked = false; - _gm->_keyPressed = false; - Common::Event event; - while (g_system->getEventManager()->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_KEYDOWN: - _gm->_keyPressed = true; - if (event.kbd.keycode == Common::KEYCODE_d && - (event.kbd.flags & Common::KBD_CTRL)) { - _console->attach(); - } - if (event.kbd.keycode == Common::KEYCODE_x && - (event.kbd.flags & Common::KBD_CTRL)) { - // TODO: Draw exit box - } + Common::Error status = loadGameStrings(); + if (status.getCode() != Common::kNoError) + error("Failed reading game strings"); - _gm->processInput(event.kbd); - break; + _resMan = new ResourceManager(); + _sound = new Sound(_mixer, _resMan); + _gm = new GameManager(this, _sound); + _screen = new Screen(this, _gm, _resMan); + _console = new Console(this, _gm); - case Common::EVENT_LBUTTONUP: - // fallthrough - case Common::EVENT_RBUTTONUP: - if (_gm->_currentRoom->getId() != INTRO && _mixer->isSoundHandleActive(_soundHandle)) - return; - _gm->_mouseClicked = true; - // fallthrough - case Common::EVENT_MOUSEMOVE: - _gm->_mouseClickType = event.type; - _gm->_mouseX = event.mouse.x; - _gm->_mouseY = event.mouse.y; - if (_gm->_guiEnabled) - _gm->processInput(); - break; + setTotalPlayTime(0); - default: - break; - } + int saveSlot = ConfMan.getInt("save_slot"); + if (saveSlot >= 0) { + if (loadGameState(saveSlot).getCode() != Common::kNoError) + error("Failed to load save game from slot %i", saveSlot); } } @@ -337,440 +222,133 @@ Common::Error SupernovaEngine::loadGameStrings() { return Common::kReadingFailed; } -void SupernovaEngine::initData() { - // Sound - // Note: - // - samples start with a header of 6 bytes: 01 SS SS 00 AD 00 - // where SS SS (LE uint16) is the size of the sound sample + 2 - // - samples end with a footer of 4 bytes: 00 00 - // Skip those in the buffer - Common::File file; - - for (int i = 0; i < kAudioNumSamples; ++i) { - if (!file.open(Common::String::format("msn_data.%03d", audioInfo[i]._filenumber))) { - error("File %s could not be read!", file.getName()); - } - - if (audioInfo[i]._offsetEnd == -1) { - file.seek(0, SEEK_END); - _soundSamples[i]._length = file.pos() - audioInfo[i]._offsetStart - 10; - } else { - _soundSamples[i]._length = audioInfo[i]._offsetEnd - audioInfo[i]._offsetStart - 10; - } - _soundSamples[i]._buffer = new byte[_soundSamples[i]._length]; - file.seek(audioInfo[i]._offsetStart + 6); - file.read(_soundSamples[i]._buffer, _soundSamples[i]._length); - file.close(); - } - - _soundMusicIntro = convertToMod("msn_data.049"); - _soundMusicOutro = convertToMod("msn_data.052"); - - // Cursor - const uint16 *bufferNormal = reinterpret_cast<const uint16 *>(mouseNormal); - const uint16 *bufferWait = reinterpret_cast<const uint16 *>(mouseWait); - for (uint i = 0; i < sizeof(mouseNormal) / 4; ++i) { - for (uint bit = 0; bit < 16; ++bit) { - uint mask = 0x8000 >> bit; - uint bitIndex = i * 16 + bit; - - _mouseNormal[bitIndex] = (READ_LE_UINT16(bufferNormal + i) & mask) ? kColorCursorTransparent : kColorBlack; - if (READ_LE_UINT16(bufferNormal + i + 16) & mask) - _mouseNormal[bitIndex] = kColorLightRed; - _mouseWait[bitIndex] = (READ_LE_UINT16(bufferWait + i) & mask) ? kColorCursorTransparent : kColorBlack; - if (READ_LE_UINT16(bufferWait + i + 16) & mask) - _mouseWait[bitIndex] = kColorLightRed; - } - } +const Common::String &SupernovaEngine::getGameString(int idx) const { + if (idx < 0 || idx >= (int)_gameStrings.size()) + return _nullString; + return _gameStrings[idx]; } -void SupernovaEngine::initPalette() { - _system->getPaletteManager()->setPalette(initVGAPalette, 0, 256); -} - -void SupernovaEngine::playSound(AudioIndex sample) { - if (sample > kAudioNumSamples - 1) +void SupernovaEngine::setGameString(int idx, const Common::String &string) { + if (idx < 0) return; - - Audio::SeekableAudioStream *audioStream = Audio::makeRawStream( - _soundSamples[sample]._buffer, _soundSamples[sample]._length, - 11931, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN, DisposeAfterUse::NO); - stopSound(); - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, audioStream); -} - -void SupernovaEngine::stopSound() { - if (_mixer->isSoundHandleActive(_soundHandle)) - _mixer->stopHandle(_soundHandle); + while ((int)_gameStrings.size() <= idx) + _gameStrings.push_back(Common::String()); + _gameStrings[idx] = string; } -void SupernovaEngine::playSoundMod(int filenumber) -{ - Audio::AudioStream *audioStream; - if (filenumber == 49) - audioStream = Audio::makeProtrackerStream(_soundMusicIntro); - else if (filenumber == 52) - audioStream = Audio::makeProtrackerStream(_soundMusicOutro); - else - return; - - stopSound(); - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, audioStream, - -1, Audio::Mixer::kMaxChannelVolume, 0); +void SupernovaEngine::playSound(AudioId sample) { + _sound->play(sample); } -void SupernovaEngine::renderImageSection(int section) { - // Note: inverting means we are removing the section. So we should get the rect for that - // section but draw the background (section 0) instead. - bool invert = false; - if (section > 128) { - section -= 128; - invert = true; - } - if (!_currentImage || section > _currentImage->_numSections - 1) - return; - - Common::Rect sectionRect(_currentImage->_section[section].x1, - _currentImage->_section[section].y1, - _currentImage->_section[section].x2 + 1, - _currentImage->_section[section].y2 + 1) ; - if (_currentImage->_filenumber == 1 || _currentImage->_filenumber == 2) { - sectionRect.setWidth(640); - sectionRect.setHeight(480); - if (_screenWidth != 640) { - _screenWidth = 640; - _screenHeight = 480; - initGraphics(_screenWidth, _screenHeight); - } - } else { - if (_screenWidth != 320) { - _screenWidth = 320; - _screenHeight = 200; - initGraphics(_screenWidth, _screenHeight); - } - } - - uint offset = 0; - int pitch = sectionRect.width(); - if (invert) { - pitch = _currentImage->_pitch; - offset = _currentImage->_section[section].y1 * pitch + _currentImage->_section[section].x1; - section = 0; - } - - _system->copyRectToScreen(static_cast<const byte *>(_currentImage->_sectionSurfaces[section]->getPixels()) + offset, - pitch, - sectionRect.left, sectionRect.top, - sectionRect.width(), sectionRect.height()); +void SupernovaEngine::playSound(MusicId index) { + _sound->play(index); } void SupernovaEngine::renderImage(int section) { - if (!_currentImage) - return; - - bool sectionVisible = true; - - if (section > 128) { - sectionVisible = false; - section -= 128; - } - - _gm->_currentRoom->setSectionVisible(section, sectionVisible); - - do { - if (sectionVisible) - renderImageSection(section); - else - renderImageSection(section + 128); - section = _currentImage->_section[section].next; - } while (section != 0); + _screen->renderImage(section); } bool SupernovaEngine::setCurrentImage(int filenumber) { - if (_currentImage && _currentImage->_filenumber == filenumber) - return true; - - delete _currentImage; - _currentImage = new MSNImageDecoder(); - if (!_currentImage->init(filenumber)) { - delete _currentImage; - _currentImage = NULL; - return false; - } - - _system->getPaletteManager()->setPalette(_currentImage->getPalette(), 16, 239); - paletteBrightness(); - return true; + return _screen->setCurrentImage(filenumber); } void SupernovaEngine::saveScreen(int x, int y, int width, int height) { - _screenBuffer.push(x, y, width, height); + _screen->saveScreen(x, y, width, height); } void SupernovaEngine::saveScreen(const GuiElement &guiElement) { - saveScreen(guiElement.left, guiElement.top, guiElement.width(), guiElement.height()); + _screen->saveScreen(guiElement); } void SupernovaEngine::restoreScreen() { - _screenBuffer.restore(); + _screen->restoreScreen(); } void SupernovaEngine::renderRoom(Room &room) { - if (room.getId() == INTRO) - return; - - if (setCurrentImage(room.getFileNumber())) { - for (int i = 0; i < _currentImage->_numSections; ++i) { - int section = i; - if (room.isSectionVisible(section)) { - do { - renderImageSection(section); - section = _currentImage->_section[section].next; - } while (section != 0); - } - } - } + _screen->renderRoom(room); } -int SupernovaEngine::textWidth(const uint16 key) { - char text[2]; - text[0] = key & 0xFF; - text[1] = 0; - return textWidth(text); +void SupernovaEngine::renderMessage(const char *text, MessagePosition position) { + _screen->renderMessage(text, position); } -int SupernovaEngine::textWidth(const char *text) { - int charWidth = 0; - while (*text != '\0') { - byte c = *text++; - if (c < 32) { - continue; - } else if (c == 225) { - c = 35; - } - - for (uint i = 0; i < 5; ++i) { - if (font[c - 32][i] == 0xff) { - break; - } - ++charWidth; - } - ++charWidth; - } - - return charWidth; +void SupernovaEngine::renderMessage(const Common::String &text, MessagePosition position) { + _screen->renderMessage(text, position); } -void SupernovaEngine::renderMessage(const char *text, MessagePosition position) { - Common::String t(text); - char *row[20]; - Common::String::iterator p = t.begin(); - uint numRows = 0; - int rowWidthMax = 0; - int x = 0; - int y = 0; - byte textColor = 0; - - while (*p != '\0') { - row[numRows] = p; - ++numRows; - while ((*p != '\0') && (*p != '|')) { - ++p; - } - if (*p == '|') { - *p = '\0'; - ++p; - } - } - for (uint i = 0; i < numRows; ++i) { - int rowWidth = textWidth(row[i]); - if (rowWidth > rowWidthMax) - rowWidthMax = rowWidth; - } - - switch (position) { - case kMessageNormal: - x = 160 - rowWidthMax / 2; - textColor = kColorWhite99; - break; - case kMessageTop: - x = 160 - rowWidthMax / 2; - textColor = kColorLightYellow; - break; - case kMessageCenter: - x = 160 - rowWidthMax / 2; - textColor = kColorLightRed; - break; - case kMessageLeft: - x = 3; - textColor = kColorLightYellow; - break; - case kMessageRight: - x = 317 - rowWidthMax; - textColor = kColorLightGreen; - break; - } - - if (position == kMessageNormal) { - y = 70 - ((numRows * 9) / 2); - } else if (position == kMessageTop) { - y = 5; - } else { - y = 142; - } - - int message_columns = x - 3; - int message_rows = y - 3; - int message_width = rowWidthMax + 6; - int message_height = numRows * 9 + 5; - saveScreen(message_columns, message_rows, message_width, message_height); - renderBox(message_columns, message_rows, message_width, message_height, kColorWhite35); - for (uint i = 0; i < numRows; ++i) { - renderText(row[i], x, y, textColor); - y += 9; - } - - _messageDisplayed = true; - _gm->_timer1 = (Common::strnlen(text, 512) + 20) * _textSpeed / 10; +void SupernovaEngine::renderMessage(StringId stringId, MessagePosition position, Common::String var1, Common::String var2) { + _screen->renderMessage(stringId, position, var1, var2); } void SupernovaEngine::removeMessage() { - if (_messageDisplayed) { - restoreScreen(); - _messageDisplayed = false; - } + _screen->removeMessage(); } -void SupernovaEngine::renderText(const char *text, int x, int y, byte color) { - Graphics::Surface *screen = _system->lockScreen(); - byte *cursor = static_cast<byte *>(screen->getBasePtr(x, y)); - const byte *basePtr = cursor; - - byte c; - while ((c = *text++) != '\0') { - if (c < 32) { - continue; - } else if (c == 225) { - c = 128; - } +void SupernovaEngine::renderText(const uint16 character) { + _screen->renderText(character); +} - for (uint i = 0; i < 5; ++i) { - if (font[c - 32][i] == 0xff) { - break; - } +void SupernovaEngine::renderText(const char *text) { + _screen->renderText(text); +} - byte *ascentLine = cursor; - for (byte j = font[c - 32][i]; j != 0; j >>= 1) { - if (j & 1) { - *cursor = color; - } - cursor += kScreenWidth; - } - cursor = ++ascentLine; - } - ++cursor; - } - _system->unlockScreen(); +void SupernovaEngine::renderText(const Common::String &text) { + _screen->renderText(text); +} - uint numChars = cursor - basePtr; - uint absPosition = y * kScreenWidth + x + numChars; - _textCursorX = absPosition % kScreenWidth; - _textCursorY = absPosition / kScreenWidth; - _textColor = color; +void SupernovaEngine::renderText(StringId stringId) { + _screen->renderText(stringId); +} + +void SupernovaEngine::renderText(const GuiElement &guiElement) { + _screen->renderText(guiElement); } void SupernovaEngine::renderText(const uint16 character, int x, int y, byte color) { - char text[2]; - text[0] = character & 0xFF; - text[1] = 0; - renderText(text, x, y, color); + _screen->renderText(character, x, y, color); } -void SupernovaEngine::renderText(const char *text) { - renderText(text, _textCursorX, _textCursorY, _textColor); +void SupernovaEngine::renderText(const char *text, int x, int y, byte color) { + _screen->renderText(text, x, y, color); } -void SupernovaEngine::renderText(const uint16 character) { - char text[2]; - text[0] = character & 0xFF; - text[1] = 0; - renderText(text, _textCursorX, _textCursorY, _textColor); +void SupernovaEngine::renderText(const Common::String &text, int x, int y, byte color) { + _screen->renderText(text, x, y, color); } -void SupernovaEngine::renderText(const GuiElement &guiElement) { - renderText(guiElement.getText(), guiElement.getTextPos().x, - guiElement.getTextPos().y, guiElement.getTextColor()); + +void SupernovaEngine::renderText(StringId stringId, int x, int y, byte color) { + _screen->renderText(stringId, x, y, color); } void SupernovaEngine::renderBox(int x, int y, int width, int height, byte color) { - Graphics::Surface *screen = _system->lockScreen(); - screen->fillRect(Common::Rect(x, y, x + width, y + height), color); - _system->unlockScreen(); + _screen->renderBox(x, y, width, height, color); } void SupernovaEngine::renderBox(const GuiElement &guiElement) { - renderBox(guiElement.left, guiElement.top, guiElement.width(), - guiElement.height(), guiElement.getBackgroundColor()); + _screen->renderBox(guiElement); } void SupernovaEngine::paletteBrightness() { - byte palette[768]; - - _system->getPaletteManager()->grabPalette(palette, 0, 255); - for (uint i = 0; i < 48; ++i) { - palette[i] = (initVGAPalette[i] * _menuBrightness) >> 8; - } - for (uint i = 0; i < 717; ++i) { - const byte *imagePalette; - if (_currentImage && _currentImage->getPalette()) { - imagePalette = _currentImage->getPalette(); - } else { - imagePalette = palette + 48; - } - palette[i + 48] = (imagePalette[i] * _brightness) >> 8; - } - _system->getPaletteManager()->setPalette(palette, 0, 255); + _screen->paletteBrightness(); } void SupernovaEngine::paletteFadeOut() { - while (_menuBrightness > 10) { - _menuBrightness -= 10; - if (_brightness > _menuBrightness) - _brightness = _menuBrightness; - paletteBrightness(); - _system->updateScreen(); - _system->delayMillis(_delay); - } - _menuBrightness = 0; - _brightness = 0; - paletteBrightness(); - _system->updateScreen(); + _screen->paletteFadeOut(); } void SupernovaEngine::paletteFadeIn() { - while (_menuBrightness < 245) { - if (_brightness < _gm->_roomBrightness) - _brightness += 10; - _menuBrightness += 10; - paletteBrightness(); - _system->updateScreen(); - _system->delayMillis(_delay); - } - _menuBrightness = 255; - _brightness = _gm->_roomBrightness; - paletteBrightness(); - _system->updateScreen(); + _screen->paletteFadeIn(); } void SupernovaEngine::setColor63(byte value) { - byte color[3] = {value, value, value}; - _system->getPaletteManager()->setPalette(color, 63, 1); + _screen->setColor63(value); } void SupernovaEngine::setTextSpeed() { - const Common::String& textSpeedString = getGameString(kStringTextSpeed); - int stringWidth = textWidth(textSpeedString); - int textX = (320 - stringWidth) / 2; + const Common::String &textSpeedString = getGameString(kStringTextSpeed); + int stringWidth = Screen::textWidth(textSpeedString); + int textX = (kScreenWidth - stringWidth) / 2; int textY = 100; stringWidth += 4; - int boxX = stringWidth > 110 ? (320 - stringWidth) / 2 : 105; + int boxX = stringWidth > 110 ? (kScreenWidth - stringWidth) / 2 : 105; int boxY = 97; int boxWidth = stringWidth > 110 ? stringWidth : 110; int boxHeight = 27; @@ -878,191 +456,6 @@ bool SupernovaEngine::quitGameDialog() { return quit; } -Common::MemoryReadStream *SupernovaEngine::convertToMod(const char *filename, int version) { - // MSN format - struct { - uint16 seg; - uint16 start; - uint16 end; - uint16 loopStart; - uint16 loopEnd; - char volume; - char dummy[5]; - } instr2[22]; - int nbInstr2; // 22 for version1, 15 for version 2 - int16 songLength; - char arrangement[128]; - int16 patternNumber; - int32 note2[28][64][4]; - - nbInstr2 = ((version == 1) ? 22 : 15); - - Common::File msnFile; - msnFile.open(filename); - if (!msnFile.isOpen()) { - warning("Data file '%s' not found", msnFile.getName()); - return NULL; - } - - for (int i = 0 ; i < nbInstr2 ; ++i) { - instr2[i].seg = msnFile.readUint16LE(); - instr2[i].start = msnFile.readUint16LE(); - instr2[i].end = msnFile.readUint16LE(); - instr2[i].loopStart = msnFile.readUint16LE(); - instr2[i].loopEnd = msnFile.readUint16LE(); - instr2[i].volume = msnFile.readByte(); - msnFile.read(instr2[i].dummy, 5); - } - songLength = msnFile.readSint16LE(); - msnFile.read(arrangement, 128); - patternNumber = msnFile.readSint16LE(); - for (int p = 0 ; p < patternNumber ; ++p) { - for (int n = 0 ; n < 64 ; ++n) { - for (int k = 0 ; k < 4 ; ++k) { - note2[p][n][k] = msnFile.readSint32LE(); - } - } - } - - /* MOD format */ - struct { - char iname[22]; - uint16 length; - char finetune; - char volume; - uint16 loopStart; - uint16 loopLength; - } instr[31]; - int32 note[28][64][4]; - - // We can't recover some MOD effects since several of them are mapped to 0. - // Assume the MSN effect of value 0 is Arpeggio (MOD effect of value 0). - const char invConvEff[8] = {0, 1, 2, 3, 10, 12, 13 ,15}; - - // Reminder from convertToMsn - // 31 30 29 28 27 26 25 24 - 23 22 21 20 19 18 17 16 - 15 14 13 12 11 10 09 08 - 07 06 05 04 03 02 01 00 - // h h h h g g g g f f f f e e e e d d d d c c c c b b b b a a a a - // - // MSN: - // hhhh (4 bits) Cleared to 0 - // dddd c (5 bits) Sample index | after mapping through convInstr - // ccc (3 bits) Effect type | after mapping through convEff - // bbbb aaaa (8 bits) Effect value | unmodified - // gggg ffff eeee (12 bits) Sample period | unmodified - // - // MS2: - // hhhh (4 bits) Cleared to 0 - // dddd (4 bits) Sample index | after mapping through convInstr - // cccc (4 bits) Effect type | unmodified - // bbbb aaaa (8 bits) Effect value | unmodified - // gggg ffff eeee (12 bits) Sample period | transformed (0xE000 / p) - 256 - // - // MOD: - // hhhh dddd (8 bits) Sample index - // cccc (4 bits) Effect type for this channel/division - // bbbb aaaa (8 bits) Effect value - // gggg ffff eeee (12 bits) Sample period - - // Can we recover the instruments mapping? I don't think so as part of the original instrument index is cleared. - // And it doesn't really matter as long as we are consistent. - // However we need to make sure 31 (or 15 in MS2) is mapped to 0 in MOD. - // We just add 1 to all other values, and this means a 1 <-> 1 mapping for the instruments - for (int p = 0; p < patternNumber; ++p) { - for (int n = 0; n < 64; ++n) { - for (int k = 0; k < 4; ++k) { - int32* l = &(note[p][n][k]); - *l = note2[p][n][k]; - int32 i = 0; - if (nbInstr2 == 22) { // version 1 - i = ((*l & 0xF800) >> 11); - int32 e = ((*l & 0x0700) >> 8); - int32 e1 = invConvEff[e]; - *l &= 0x0FFF00FF; - *l |= (e1 << 8); - } else { // version 2 - int32 h = (*l >> 16); - i = ((*l & 0xF000) >> 12); - *l &= 0x00000FFF; - if (h) - h = 0xE000 / (h + 256); - *l |= (h << 16); - if (i == 15) - i = 31; - } - - // Add back index in note - if (i != 31) { - ++i; - *l |= ((i & 0x0F) << 12); - *l |= ((i & 0xF0) << 24); - } - } - } - } - - for (int i = 0; i < 31; ++i) { - // iname is not stored in the mod file. Just set it to 'instrument#' - // finetune is not stored either. Assume 0. - memset(instr[i].iname, 0, 22); - sprintf(instr[i].iname, "instrument%d", i+1); - instr[i].length = 0; - instr[i].finetune = 0; - instr[i].volume = 0; - instr[i].loopStart = 0; - instr[i].loopLength = 0; - - if (i < nbInstr2) { - instr[i].length = ((instr2[i].end - instr2[i].start) >> 1); - instr[i].loopStart = ((instr2[i].loopStart - instr2[i].start) >> 1); - instr[i].loopLength = (( instr2[i].loopEnd - instr2[i].loopStart) >> 1); - instr[i].volume = instr2[i].volume; - } - } - - // The ciaaSpeed is kind of useless and not present in the MSN file. - // Traditionally 0x78 in SoundTracker. Was used in NoiseTracker as a restart point. - // ProTracker uses 0x7F. FastTracker uses it as a restart point, whereas ScreamTracker 3 uses 0x7F like ProTracker. - // You can use this to roughly detect which tracker made a MOD, and detection gets more accurate for more obscure MOD types. - char ciaaSpeed = 0x7F; - - // The mark cannot be recovered either. Since we have 4 channels and 31 instrument it can be either ID='M.K.' or ID='4CHN'. - // Assume 'M.K.' - const char mark[4] = { 'M', '.', 'K', '.' }; - - Common::MemoryWriteStreamDynamic buffer(DisposeAfterUse::NO); - - buffer.write(msnFile.getName(), 19); - buffer.writeByte(0); - - for (int i = 0 ; i < 31 ; ++i) { - buffer.write(instr[i].iname, 22); - buffer.writeUint16BE(instr[i].length); - buffer.writeByte(instr[i].finetune); - buffer.writeByte(instr[i].volume); - buffer.writeUint16BE(instr[i].loopStart); - buffer.writeUint16BE(instr[i].loopLength); - } - buffer.writeByte((char)songLength); - buffer.writeByte(ciaaSpeed); - buffer.write(arrangement, 128); - buffer.write(mark, 4); - - for (int p = 0 ; p < patternNumber ; ++p) { - for (int n = 0 ; n < 64 ; ++n) { - for (int k = 0 ; k < 4 ; ++k) { -// buffer.writeUint32BE(*((uint32*)(note[p][n]+k))); - buffer.writeSint32BE(note[p][n][k]); - } - } - } - - uint nb; - char buf[4096]; - while ((nb = msnFile.read(buf, 4096)) > 0) - buffer.write(buf, nb); - - return new Common::MemoryReadStream(buffer.getData(), buffer.size(), DisposeAfterUse::YES); -} bool SupernovaEngine::canLoadGameStateCurrently() { return _allowLoadGame; @@ -1117,10 +510,11 @@ bool SupernovaEngine::loadGame(int slot) { _gm->deserialize(savefile, saveVersion); if (saveVersion >= 5) { - _menuBrightness = savefile->readByte(); - _brightness = savefile->readByte(); + _screen->setGuiBrightness(savefile->readByte()); + _screen->setViewportBrightness(savefile->readByte()); } else { - _menuBrightness = _brightness = 255; + _screen->setGuiBrightness(255); + _screen->setViewportBrightness(255); } delete savefile; @@ -1153,8 +547,8 @@ bool SupernovaEngine::saveGame(int slot, const Common::String &description) { Graphics::saveThumbnail(*savefile); _gm->serialize(savefile); - savefile->writeByte(_menuBrightness); - savefile->writeByte(_brightness); + savefile->writeByte(_screen->getGuiBrightness()); + savefile->writeByte(_screen->getViewportBrightness()); savefile->finalize(); delete savefile; @@ -1169,59 +563,5 @@ void SupernovaEngine::errorTempSave(bool saving) { error("Unrecoverable error"); } -ScreenBufferStack::ScreenBufferStack() - : _last(_buffer) { -} - -void ScreenBufferStack::push(int x, int y, int width, int height) { - if (_last == ARRAYEND(_buffer)) - return; - - Graphics::Surface* screenSurface = g_system->lockScreen(); - - if (x < 0) { - width += x; - x = 0; - } - if (x + width > screenSurface->w) - width = screenSurface->w - x; - - if (y < 0) { - height += y; - y = 0; - } - if (y + height > screenSurface->h) - height = screenSurface->h - y; - - _last->_pixels = new byte[width * height]; - byte *pixels = _last->_pixels; - const byte *screen = static_cast<const byte *>(screenSurface->getBasePtr(x, y)); - for (int i = 0; i < height; ++i) { - Common::copy(screen, screen + width, pixels); - screen += screenSurface->pitch; - pixels += width; - } - g_system->unlockScreen(); - - _last->_x = x; - _last->_y = y; - _last->_width = width; - _last->_height = height; - - ++_last; -} - -void ScreenBufferStack::restore() { - if (_last == _buffer) - return; - - --_last; - g_system->lockScreen()->copyRectToSurface( - _last->_pixels, _last->_width, _last->_x, _last->_y, - _last->_width, _last->_height); - g_system->unlockScreen(); - - delete[] _last->_pixels; -} } diff --git a/engines/supernova/supernova.h b/engines/supernova/supernova.h index e01fb778a5..132e25deeb 100644 --- a/engines/supernova/supernova.h +++ b/engines/supernova/supernova.h @@ -23,9 +23,6 @@ #ifndef SUPERNOVA_SUPERNOVA_H #define SUPERNOVA_SUPERNOVA_H -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "audio/decoders/raw.h" #include "common/array.h" #include "common/events.h" #include "common/random.h" @@ -38,6 +35,7 @@ #include "supernova/graphics.h" #include "supernova/msn_def.h" #include "supernova/rooms.h" +#include "supernova/sound.h" namespace Supernova { @@ -48,96 +46,55 @@ namespace Supernova { #define SUPERNOVA_DAT "supernova.dat" #define SUPERNOVA_DAT_VERSION 1 - -struct ScreenBuffer { - ScreenBuffer() - : _x(0) - , _y(0) - , _width(0) - , _height(0) - , _pixels(NULL) - {} - - byte *_pixels; - int _x; - int _y; - int _width; - int _height; -}; -class ScreenBufferStack { -public: - ScreenBufferStack(); - - void push(int x, int y, int width, int height); - void restore(); - -private: - ScreenBuffer _buffer[8]; - ScreenBuffer *_last; -}; - -struct SoundSample { - SoundSample() - : _buffer(NULL) - , _length(0) - {} - - ~SoundSample() { - delete[] _buffer; - } - - byte *_buffer; - int _length; -}; - class GuiElement; +class ResourceManager; +class Sound; +class console; +class GameManager; +class Screen; + class SupernovaEngine : public Engine { public: explicit SupernovaEngine(OSystem *syst); ~SupernovaEngine(); virtual Common::Error run(); + virtual Common::Error loadGameState(int slot); + virtual bool canLoadGameStateCurrently(); + virtual Common::Error saveGameState(int slot, const Common::String &desc); + virtual bool canSaveGameStateCurrently(); + virtual bool hasFeature(EngineFeature f) const; + virtual void pauseEngineIntern(bool pause); - Common::RandomSource _rnd; GameManager *_gm; Console *_console; - Audio::SoundHandle _soundHandle; - ScreenBufferStack _screenBuffer; - byte _mouseNormal[256]; - byte _mouseWait[256]; - MSNImageDecoder *_currentImage; - SoundSample _soundSamples[kAudioNumSamples]; - Common::MemoryReadStream *_soundMusicIntro; - Common::MemoryReadStream *_soundMusicOutro; - int _screenWidth; - int _screenHeight; + Sound *_sound; + ResourceManager *_resMan; + Screen *_screen; bool _allowLoadGame; bool _allowSaveGame; Common::StringArray _gameStrings; Common::String _nullString; - byte _menuBrightness; - byte _brightness; uint _delay; - bool _messageDisplayed; int _textSpeed; - int _textCursorX; - int _textCursorY; - int _textColor; - int textWidth(const char *text); - int textWidth(const uint16 key); Common::Error loadGameStrings(); - void initData(); - void initPalette(); + void init(); + bool loadGame(int slot); + bool saveGame(int slot, const Common::String &description); + bool quitGameDialog(); + void errorTempSave(bool saving); + void setTextSpeed(); + const Common::String &getGameString(int idx) const; + void setGameString(int idx, const Common::String &string); + + // forwarding calls + void playSound(AudioId sample); + void playSound(MusicId index); void paletteFadeIn(); void paletteFadeOut(); void paletteBrightness(); - void updateEvents(); - void playSound(AudioIndex sample); - void playSoundMod(int filenumber); - void stopSound(); - void renderImageSection(int section); void renderImage(int section); bool setCurrentImage(int filenumber); void saveScreen(int x, int y, int width, int height); @@ -145,77 +102,22 @@ public: void restoreScreen(); void renderRoom(Room &room); void renderMessage(const char *text, MessagePosition position = kMessageNormal); + void renderMessage(const Common::String &text, MessagePosition position = kMessageNormal); + void renderMessage(StringId stringId, MessagePosition position = kMessageNormal, + Common::String var1 = "", Common::String var2 = ""); void removeMessage(); - void renderText(const char *text, int x, int y, byte color); - void renderText(const uint16 character, int x, int y, byte color); - void renderText(const char *text); void renderText(const uint16 character); + void renderText(const char *text); + void renderText(const Common::String &text); + void renderText(StringId stringId); + void renderText(const uint16 character, int x, int y, byte color); + void renderText(const char *text, int x, int y, byte color); + void renderText(const Common::String &text, int x, int y, byte color); + void renderText(StringId stringId, int x, int y, byte color); void renderText(const GuiElement &guiElement); void renderBox(int x, int y, int width, int height, byte color); void renderBox(const GuiElement &guiElement); void setColor63(byte value); - bool loadGame(int slot); - bool saveGame(int slot, const Common::String &description); - bool quitGameDialog(); - void errorTempSave(bool saving); - void setTextSpeed(); - - const Common::String &getGameString(int idx) const { - if (idx < 0 || idx >= (int)_gameStrings.size()) - return _nullString; - return _gameStrings[idx]; - } - - void setGameString(int idx, const Common::String &string) { - if (idx < 0) - return; - while ((int)_gameStrings.size() <= idx) - _gameStrings.push_back(Common::String()); - _gameStrings[idx] = string; - } - - int textWidth(const Common::String &text) { - if (text.empty()) - return 0; - return textWidth(text.c_str()); - } - void renderMessage(StringID stringId, MessagePosition position = kMessageNormal, Common::String var1 = "", Common::String var2 = "") { - Common::String text = getGameString(stringId); - if (!var1.empty()) { - if (!var2.empty()) - text = Common::String::format(text.c_str(), var1.c_str(), var2.c_str()); - else - text = Common::String::format(text.c_str(), var1.c_str()); - } - renderMessage(text, position); - } - void renderMessage(const Common::String &text, MessagePosition position = kMessageNormal) { - if (!text.empty()) - renderMessage(text.c_str(), position); - } - void renderText(StringID stringId, int x, int y, byte color) { - renderText(getGameString(stringId), x, y, color); - } - void renderText(const Common::String &text, int x, int y, byte color) { - if (!text.empty()) - renderText(text.c_str(), x, y, color); - } - void renderText(StringID stringId) { - renderText(getGameString(stringId)); - } - void renderText(const Common::String &text) { - if (!text.empty()) - renderText(text.c_str()); - } - - Common::MemoryReadStream *convertToMod(const char *filename, int version = 1); - - virtual Common::Error loadGameState(int slot); - virtual bool canLoadGameStateCurrently(); - virtual Common::Error saveGameState(int slot, const Common::String &desc); - virtual bool canSaveGameStateCurrently(); - virtual bool hasFeature(EngineFeature f) const; - virtual void pauseEngineIntern(bool pause); }; } |