Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,544 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA_H
#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA_H
#include "pegasus/neighborhood/neighborhood.h"
namespace Pegasus {
static const TimeScale kCaldoriaMovieScale = 600;
static const TimeScale kCaldoriaFramesPerSecond = 15;
static const TimeScale kCaldoriaFrameDuration = 40;
// Alternate IDs.
static const AlternateID kAltCaldoriaNormal = 0;
static const AlternateID kAltCaldoriaRoofDoorBlown = 2;
static const AlternateID kAltCaldoriaSinclairDown = 3;
// Room IDs.
static const RoomID kCaldoria00 = 1;
static const RoomID kCaldoria01 = 2;
static const RoomID kCaldoria02 = 3;
static const RoomID kCaldoria03 = 4;
static const RoomID kCaldoria04 = 5;
static const RoomID kCaldoria05 = 6;
static const RoomID kCaldoria06 = 7;
static const RoomID kCaldoria07 = 8;
static const RoomID kCaldoria08 = 9;
static const RoomID kCaldoria09 = 10;
static const RoomID kCaldoria10 = 11;
static const RoomID kCaldoriaToilet = 12;
static const RoomID kCaldoria11 = 13;
static const RoomID kCaldoria12 = 14;
static const RoomID kCaldoriaVidPhone = 15;
static const RoomID kCaldoriaReplicator = 16;
static const RoomID kCaldoriaDrawers = 17;
static const RoomID kCaldoria13 = 18;
static const RoomID kCaldoria14 = 19;
static const RoomID kCaldoria15 = 20;
static const RoomID kCaldoria16 = 21;
static const RoomID kCaldoria17 = 22;
static const RoomID kCaldoria18 = 23;
static const RoomID kCaldoria19 = 24;
static const RoomID kCaldoria20 = 25;
static const RoomID kCaldoria21 = 26;
static const RoomID kCaldoria22 = 27;
static const RoomID kCaldoria23 = 28;
static const RoomID kCaldoria24 = 29;
static const RoomID kCaldoria25 = 30;
static const RoomID kCaldoria26 = 31;
static const RoomID kCaldoria27 = 32;
static const RoomID kCaldoria28 = 33;
static const RoomID kCaldoria29 = 34;
static const RoomID kCaldoria30 = 35;
static const RoomID kCaldoria31 = 36;
static const RoomID kCaldoria32 = 37;
static const RoomID kCaldoria33 = 38;
static const RoomID kCaldoria34 = 39;
static const RoomID kCaldoria35 = 40;
static const RoomID kCaldoria36 = 41;
static const RoomID kCaldoria37 = 42;
static const RoomID kCaldoria38 = 43;
static const RoomID kCaldoria39 = 44;
static const RoomID kCaldoria40 = 45;
static const RoomID kCaldoria41 = 46;
static const RoomID kCaldoriaBinoculars = 47;
static const RoomID kCaldoria42 = 48;
static const RoomID kCaldoriaKiosk = 49;
static const RoomID kCaldoria44 = 50;
static const RoomID kCaldoria45 = 51;
static const RoomID kCaldoria46 = 52;
static const RoomID kCaldoria47 = 53;
static const RoomID kCaldoria48 = 54;
static const RoomID kCaldoria49 = 55;
static const RoomID kCaldoria50 = 56;
static const RoomID kCaldoria51 = 57;
static const RoomID kCaldoria52 = 58;
static const RoomID kCaldoria53 = 59;
static const RoomID kCaldoria54 = 60;
static const RoomID kCaldoria55 = 61;
static const RoomID kCaldoria56 = 62;
static const RoomID kCaldoriaDeathRoom = 0;
// Hot Spot Activation IDs.
static const HotSpotActivationID kActivate4DClosed = 1;
static const HotSpotActivationID kActivate4DOpen = 2;
static const HotSpotActivationID kActivateMirrorReady = 3;
static const HotSpotActivationID kActivateStylistReady = 4;
static const HotSpotActivationID kActivateReplicatorReady = 5;
static const HotSpotActivationID kActivateOJOnThePad = 6;
static const HotSpotActivationID kActivateDrawersClosed = 7;
static const HotSpotActivationID kActivateRightOpen = 8;
static const HotSpotActivationID kActivateLeftOpen = 9;
static const HotSpotActivationID kActivateFocusedOnShip = 10;
static const HotSpotActivationID kActivateNotFocusedOnShip = 11;
static const HotSpotActivationID kActivateReadyForCard = 12;
static const HotSpotActivationID kActivateReadyToTransport = 13;
static const HotSpotActivationID kActivateRoofSlotEmpty = 14;
static const HotSpotActivationID kActivateZoomedOnSinclair = 15;
// Hot Spot IDs.
static const HotSpotID kCa4DEnvironOpenSpotID = 5000;
static const HotSpotID kCa4DEnvironCloseSpotID = 5001;
static const HotSpotID kCa4DVisualSpotID = 5002;
static const HotSpotID kCa4DAudioSpotID = 5003;
static const HotSpotID kCa4DChoice1SpotID = 5004;
static const HotSpotID kCa4DChoice2SpotID = 5005;
static const HotSpotID kCa4DChoice3SpotID = 5006;
static const HotSpotID kCa4DChoice4SpotID = 5007;
static const HotSpotID kCaBathroomMirrorSpotID = 5008;
static const HotSpotID kCaHairStyle1SpotID = 5009;
static const HotSpotID kCaHairStyle2SpotID = 5010;
static const HotSpotID kCaHairStyle3SpotID = 5011;
static const HotSpotID kCaShowerSpotID = 5012;
static const HotSpotID kCaBathroomToiletSpotID = 5013;
static const HotSpotID kCaldoriaVidPhoneSpotID = 5014;
static const HotSpotID kCaldoriaReplicatorSpotID = 5015;
static const HotSpotID kCaldoriaDrawersSpotID = 5016;
static const HotSpotID kCaldoriaVidPhoneOutSpotID = 5017;
static const HotSpotID kCaBedroomVidPhoneActivationSpotID = 5018;
static const HotSpotID kCaldoriaReplicatorOutSpotID = 5019;
static const HotSpotID kCaldoriaMakeOJSpotID = 5020;
static const HotSpotID kCaldoriaMakeStickyBunsSpotID = 5021;
static const HotSpotID kCaldoriaOrangeJuiceSpotID = 5022;
static const HotSpotID kCaldoriaOrangeJuiceDropSpotID = 5023;
static const HotSpotID kCaldoriaDrawersOutSpotID = 5024;
static const HotSpotID kCaldoriaLeftDrawerOpenSpotID = 5025;
static const HotSpotID kCaldoriaRightDrawerOpenSpotID = 5026;
static const HotSpotID kCaldoriaKeyCardSpotID = 5027;
static const HotSpotID kCaldoriaLeftDrawerCloseSpotID = 5028;
static const HotSpotID kCaldoriaRightDrawerWithKeysCloseSpotID = 5029;
static const HotSpotID kCaldoriaRightDrawerNoKeysCloseSpotID = 5030;
static const HotSpotID kCaldoriaFourthFloorElevatorSpotID = 5031;
static const HotSpotID kCaldoria20DoorbellSpotID = 5032;
static const HotSpotID kCaldoria21DoorbellSpotID = 5033;
static const HotSpotID kCaldoria26DoorbellSpotID = 5034;
static const HotSpotID kCaldoriaFourthFloorElevator1 = 5035;
static const HotSpotID kCaldoriaFourthFloorElevator2 = 5036;
static const HotSpotID kCaldoriaFourthFloorElevator3 = 5037;
static const HotSpotID kCaldoriaFourthFloorElevator4 = 5038;
static const HotSpotID kCaldoriaFourthFloorElevator5 = 5039;
static const HotSpotID kCaldoriaGroundElevator1 = 5040;
static const HotSpotID kCaldoriaGroundElevator2 = 5041;
static const HotSpotID kCaldoriaGroundElevator3 = 5042;
static const HotSpotID kCaldoriaGroundElevator4 = 5043;
static const HotSpotID kCaldoriaGroundElevator5 = 5044;
static const HotSpotID kCaldoria29DoorbellSpotID = 5045;
static const HotSpotID kCaldoria34DoorbellSpotID = 5046;
static const HotSpotID kCaldoria35DoorbellSpotID = 5047;
static const HotSpotID kCaldoriaGroundElevatorSpotID = 5048;
static const HotSpotID kCaldoriaBinocularZoomInSpotID = 5049;
static const HotSpotID kCaldoriaBinocularsOutSpotID = 5050;
static const HotSpotID kCaldoriaZoomInOnShipSpotID = 5051;
static const HotSpotID kCaldoriaKioskSpotID = 5052;
static const HotSpotID kCaldoriaKioskOutSpotID = 5053;
static const HotSpotID kCaldoriaKioskInfoSpotID = 5054;
static const HotSpotID kCaldoriaGTCardDropSpotID = 5055;
static const HotSpotID kCaldoriaGTTokyoSpotID = 5056;
static const HotSpotID kCaldoriaGTTSASpotID = 5057;
static const HotSpotID kCaldoriaGTBeachSpotID = 5058;
static const HotSpotID kCaldoriaGTOtherSpotID = 5059;
static const HotSpotID kCaldoriaRoofElevator1 = 5060;
static const HotSpotID kCaldoriaRoofElevator2 = 5061;
static const HotSpotID kCaldoriaRoofElevator3 = 5062;
static const HotSpotID kCaldoriaRoofElevator4 = 5063;
static const HotSpotID kCaldoriaRoofElevator5 = 5064;
static const HotSpotID kCaldoriaRoofElevatorSpotID = 5065;
static const HotSpotID kCaldoriaRoofDoorSpotID = 5066;
static const HotSpotID kCaldoriaRoofCardDropSpotID = 5067;
static const HotSpotID kCaldoria53EastSinclairTargetSpotID = 5068;
static const HotSpotID kCaldoriaCornbread = 5069;
// Extra sequence IDs.
static const ExtraID kCaldoriaWakeUpView1 = 0;
static const ExtraID kCaldoria00WakeUp1 = 1;
static const ExtraID kCaldoria00WakeUp2 = 2;
static const ExtraID kCaldoria00SitDown = 3;
static const ExtraID k4DEnvironOpenToINN = 4;
static const ExtraID k4DINNInterruption = 5;
static const ExtraID k4DINNIntro = 6;
static const ExtraID k4DINNMarkJohnson = 7;
static const ExtraID k4DINNMeganLove = 8;
static const ExtraID k4DINNFadeOut = 9;
static const ExtraID k4DEnvironOpenFromINN = 10;
static const ExtraID k4DEnvironOpen = 11;
static const ExtraID k4DEnvironOpenView = 12;
static const ExtraID k4DEnvironClose = 13;
static const ExtraID k4DIslandLoop = 14;
static const ExtraID k4DDesertLoop = 15;
static const ExtraID k4DMountainLoop = 16;
static const ExtraID k4DIsland1ToIsland0 = 17;
static const ExtraID k4DIsland2ToIsland0 = 18;
static const ExtraID k4DIsland0ToDesert0 = 19;
static const ExtraID k4DIsland1ToDesert0 = 20;
static const ExtraID k4DIsland2ToDesert0 = 21;
static const ExtraID k4DIsland0ToMountain0 = 22;
static const ExtraID k4DIsland1ToMountain0 = 23;
static const ExtraID k4DIsland2ToMountain0 = 24;
static const ExtraID k4DDesert0ToIsland0 = 25;
static const ExtraID k4DDesert1ToIsland0 = 26;
static const ExtraID k4DDesert2ToIsland0 = 27;
static const ExtraID k4DDesert0ToMountain0 = 28;
static const ExtraID k4DDesert1ToMountain0 = 29;
static const ExtraID k4DDesert2ToMountain0 = 30;
static const ExtraID k4DMountain0ToIsland0 = 31;
static const ExtraID k4DMountain1ToIsland0 = 32;
static const ExtraID k4DMountain2ToIsland0 = 33;
static const ExtraID k4DMountain0ToDesert0 = 34;
static const ExtraID k4DMountain1ToDesert0 = 35;
static const ExtraID k4DMountain2ToDesert0 = 36;
static const ExtraID kCaBathroomGreeting = 37;
static const ExtraID kCaBathroomBodyFat = 38;
static const ExtraID kCaBathroomStylistIntro = 39;
static const ExtraID kCaBathroomRetrothrash = 40;
static const ExtraID kCaBathroomRetrothrashReturn = 41;
static const ExtraID kCaBathroomGeoWave = 42;
static const ExtraID kCaBathroomGeoWaveReturn = 43;
static const ExtraID kCaBathroomAgencyStandard = 44;
static const ExtraID kCaldoriaShowerTitle = 45;
static const ExtraID kCaldoriaShowerButton = 46;
static const ExtraID kCaldoriaShowerDown = 47;
static const ExtraID kCaldoriaShowerUp = 48;
static const ExtraID kCaBedroomVidPhone = 49;
static const ExtraID kCaBedroomMessage1 = 50;
static const ExtraID kCaBedroomMessage2 = 51;
static const ExtraID kCreateOrangeJuice = 52;
static const ExtraID kDisposeOrangeJuice = 53;
static const ExtraID kReplicatorNorthViewWithOJ = 54;
static const ExtraID kLeftDrawerOpen = 55;
static const ExtraID kLeftDrawerClose = 56;
static const ExtraID kRightDrawerOpenWithKeys = 57;
static const ExtraID kRightDrawerCloseWithKeys = 58;
static const ExtraID kRightDrawerOpenNoKeys = 59;
static const ExtraID kRightDrawerCloseNoKeys = 60;
static const ExtraID kRightDrawerOpenViewWithKeys = 61;
static const ExtraID kRightDrawerOpenViewNoKeys = 62;
static const ExtraID kCaldoria16ElevatorUp = 63;
static const ExtraID kCaldoria16ElevatorDown = 64;
static const ExtraID kCaldoria16SouthViewWithElevator = 65;
static const ExtraID kCaldoria20Doorbell = 66;
static const ExtraID kCaldoria21Doorbell = 67;
static const ExtraID kCaldoria26Doorbell = 68;
static const ExtraID kCaldoriaFourthToGround = 69;
static const ExtraID kCaldoriaRoofToFourth = 70;
static const ExtraID kCaldoriaRoofToGround = 71;
static const ExtraID kCaldoriaGroundToFourth = 72;
static const ExtraID kCaldoriaGroundToRoof = 73;
static const ExtraID kCaldoriaFourthToRoof = 74;
static const ExtraID kCaldoria29Doorbell = 75;
static const ExtraID kCaldoria34Doorbell = 76;
static const ExtraID kCaldoria35Doorbell = 77;
static const ExtraID kBinocularsZoomInOnShip = 78;
static const ExtraID kCaldoriaKioskVideo = 79;
static const ExtraID kCaldoriaTransporterArrowLoop = 80;
static const ExtraID kArriveAtCaldoriaFromTSA = 81;
static const ExtraID kCaGTOtherChoice = 82;
static const ExtraID kCaGTCardSwipe = 83;
static const ExtraID kCaGTSelectTSA = 84;
static const ExtraID kCaGTFryTheFly = 85;
static const ExtraID kCaGTGoToTSA = 86;
static const ExtraID kCaGTSelectBeach = 87;
static const ExtraID kCaGTGoToBeach = 88;
static const ExtraID kCaGTArriveAtBeach = 89;
static const ExtraID kCaGTSelectTokyo = 90;
static const ExtraID kCaGTGoToTokyo = 91;
static const ExtraID kCaGTArriveAtTokyo = 92;
static const ExtraID kCa48NorthRooftopClosed = 93;
static const ExtraID kCa48NorthExplosion = 94;
static const ExtraID kCa48NorthExplosionDeath = 95;
static const ExtraID kCa49NorthVoiceAnalysis = 96;
static const ExtraID kCa50SinclairShoots = 97;
static const ExtraID kCa53EastZoomToSinclair = 98;
static const ExtraID kCa53EastDeath2 = 99;
static const ExtraID kCa53EastShootSinclair = 100;
static const ExtraID kCa53EastZoomOutFromSinclair = 101;
static const ExtraID kCa54SouthDeath = 102;
static const ExtraID kCaldoria56BombStage1 = 103;
static const ExtraID kCaldoria56BombStage2 = 104;
static const ExtraID kCaldoria56BombStage3 = 105;
static const ExtraID kCaldoria56BombStage4 = 106;
static const ExtraID kCaldoria56BombStage5 = 107;
static const ExtraID kCaldoria56BombStage6 = 108;
static const ExtraID kCaldoria56BombStage7 = 109;
static const ExtraID kCaldoria56BombExplodes = 110;
// Caldoria interactions.
static const InteractionID kCaldoria4DInteractionID = 0;
static const InteractionID kCaldoriaBombInteractionID = 1;
static const InteractionID kCaldoriaMessagesInteractionID = 2;
static const InteractionID kCaldoriaMirrorInteractionID = 3;
// Caldoria:
static const DisplayOrder kVidPhoneOrder = kMonitorLayer;
static const DisplayOrder k4DSpritesOrder = kMonitorLayer;
static const DisplayOrder kCaldoriaMessagesOrder = kMonitorLayer;
static const DisplayOrder kCaldoriaElevatorOrder = kMonitorLayer;
static const DisplayOrder kCaldoriaA05LightLoopOrder = kMonitorLayer;
static const DisplayOrder kCaldoriaA07LightLoopOrder = kMonitorLayer;
static const DisplayOrder kCaldoriaBombGridOrder = kMonitorLayer;
static const DisplayOrder kCaldoriaBombTimerOrder = kCaldoriaBombGridOrder + 1;
/////////////////////////////////////////////
//
// Caldoria
static const CoordType kCaldoriaVidPhoneLeft = kNavAreaLeft + 105;
static const CoordType kCaldoriaVidPhoneTop = kNavAreaTop + 28;
static const CoordType kCaldoria4DSpritesLeft = kNavAreaLeft + 10;
static const CoordType kCaldoria4DSpritesTop = kNavAreaTop + 142;
static const CoordType kCaldoriaMessageLeft = kNavAreaLeft + 202;
static const CoordType kCaldoriaMessageTop = kNavAreaTop + 26;
static const CoordType kCaldoriaElevatorLeft = kNavAreaLeft + 407;
static const CoordType kCaldoriaElevatorTop = kNavAreaTop + 138;
static const CoordType kCaldoriaA05LightLoopLeft = kNavAreaLeft + 213;
static const CoordType kCaldoriaA05LightLoopTop = kNavAreaTop + 215;
static const CoordType kCaldoriaA07LightLoopLeft = kNavAreaLeft + 414;
static const CoordType kCaldoriaA07LightLoopTop = kNavAreaTop + 215;
static const CoordType kCaldoriaGunSpriteLeft = kNavAreaLeft + 276;
static const CoordType kCaldoriaGunSpriteTop = kNavAreaTop + 115;
static const CoordType kCaldoria11MessageLoopLeft = kNavAreaLeft + 135;
static const CoordType kCaldoria11MessageLoopTop = kNavAreaTop + 214;
static const CoordType kCaldoria12MessageLoopLeft = kNavAreaLeft + 209;
static const CoordType kCaldoria12MessageLoopTop = kNavAreaTop + 170;
static const CoordType kCaldoria13MessageLoopLeft = kNavAreaLeft + 480;
static const CoordType kCaldoria13MessageLoopTop = kNavAreaTop + 191;
static const CoordType kCaldoria14MessageLoopLeft = kNavAreaLeft + 248;
static const CoordType kCaldoria14MessageLoopTop = kNavAreaTop + 191;
static const CoordType kCaldoria48CardBombLoopLeft = kNavAreaLeft + 337;
static const CoordType kCaldoria48CardBombLoopTop = kNavAreaTop + 205;
static const CoordType kCaldoriaBombGridLeft = kNavAreaLeft + 290;
static const CoordType kCaldoriaBombGridTop = kNavAreaTop + 58;
static const CoordType kCaldoriaBombTimerLeft = kNavAreaLeft + 58;
static const CoordType kCaldoriaBombTimerTop = kNavAreaTop + 204;
// Caldoria display IDs.
static const DisplayElementID kCaldoriaVidPhoneID = kNeighborhoodDisplayID;
static const DisplayElementID kCaldoria4DSpritesID = kCaldoriaVidPhoneID + 1;
static const DisplayElementID kCaldoriaMessagesID = kCaldoria4DSpritesID + 1;
static const DisplayElementID kCaldoriaUtilityID = kCaldoriaMessagesID + 1;
static const DisplayElementID kCaldoriaBombGridID = kCaldoriaUtilityID + 1;
static const DisplayElementID kCaldoriaBombTimerID = kCaldoriaBombGridID + 1;
static const TimeValue kCaldoria4DInstructionsIn = 28013;
static const TimeValue kCaldoria4DInstructionsOut = 29730;
static const TimeValue kCaldoria4DBlankChoiceIn = 29730;
static const TimeValue kCaldoria4DBlankChoiceOut = 33910;
class Caldoria;
class SinclairCallBack : public TimeBaseCallBack {
public:
SinclairCallBack(Caldoria *);
~SinclairCallBack() override {}
protected:
void callBack() override;
Caldoria *_caldoria;
};
class Caldoria : public Neighborhood {
friend class SinclairCallBack;
public:
Caldoria(InputHandler *, PegasusEngine *);
~Caldoria() override;
uint16 getDateResID() const override;
void pickedUpItem(Item *) override;
GameInteraction *makeInteraction(const InteractionID) override;
Common::Path getBriefingMovie() override;
Common::Path getEnvScanMovie() override;
uint getNumHints() override;
Common::Path getHintMovie(uint) override;
void loadAmbientLoops() override;
bool wantsCursor() override;
void flushGameState() override;
void checkContinuePoint(const RoomID, const DirectionConstant) override;
void setSoundFXLevel(const uint16) override;
protected:
enum {
kCaldoriaPrivate4DSystemOpenFlag,
kCaloriaPrivateLeftDrawerOpenFlag,
kCaldoriaPrivateRightDrawerOpenFlag,
kCaldoriaPrivateReadyToShootFlag,
kCaldoriaPrivateZoomingToBombFlag,
kCaldoriaPrivateCanOpenElevatorDoorFlag,
kCaldoriaPrivateSinclairTimerExpiredFlag,
kCaldoriaPrivateSeen13CarFlag,
kCaldoriaPrivateSeen14CarFlag,
kCaldoriaPrivateSeen18CarFlag,
kCaldoriaPrivateSeen23CarFlag,
kCaldoriaPrivateSeen33CarFlag,
kCaldoriaPrivateSeen36CarFlag,
kCaldoriaPrivateSeen41NorthCarFlag,
kCaldoriaPrivateSeen41EastCarFlag,
kCaldoriaPrivateSeen41WestCarFlag,
kNumCaldoriaPrivateFlags
};
void init() override;
void start() override;
void throwAwayInterface() override;
void setUpRoofTop();
void setUpAIRules() override;
void doAIRecalibration();
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &) override;
void startSpotOnceOnly(TimeValue, TimeValue) override;
void startExitMovie(const ExitTable::Entry &) override;
void startZoomMovie(const ZoomTable::Entry &) override;
void startDoorOpenMovie(const TimeValue, const TimeValue) override;
void startTurnPush(const TurnDirection, const TimeValue, const DirectionConstant) override;
void bumpIntoWall() override;
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &) override;
void getZoomCompassMove(const ZoomTable::Entry &, FaderMoveSpec &) override;
void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &) override;
void spotCompleted() override;
void arriveAt(const RoomID, const DirectionConstant) override;
void arriveAtCaldoria00();
void arriveAtCaldoriaToilet();
void arriveAtCaldoria44();
void arriveAtCaldoria49();
void arriveAtCaldoria56();
void arriveAtCaldoriaDeath();
void turnTo(const DirectionConstant) override;
void zoomTo(const Hotspot *) override;
void leftButton(const Input &) override;
void rightButton(const Input &) override;
void downButton(const Input &) override;
void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void receiveNotification(Notification *, const NotificationFlags) override;
InputBits getInputFilter() override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void newInteraction(const InteractionID) override;
void clickOnDoorbell(const HotSpotID);
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
void dropItemIntoRoom(Item *, Hotspot *) override;
void playMissingFloorSound();
void takeElevator(uint, uint);
void updateElevatorMovie();
void openElevatorMovie();
void emptyOJGlass();
void closeDoorOffScreen(const RoomID, const DirectionConstant) override;
void doorBombTimerExpired();
void sinclairTimerExpired();
void checkSinclairShootsOS();
void setUpSinclairLoops();
void zoomToSinclair();
void playEndMessage();
void checkInterruptSinclair();
void doArthurJoyride();
void cantMoveThatWay(CanMoveForwardReason) override;
CanOpenDoorReason canOpenDoor(DoorTable::Entry &) override;
void doorOpened() override;
void updateCursor(const Common::Point &, const Hotspot *) override;
FlagsArray<uint16, kNumCaldoriaPrivateFlags> _privateFlags;
const Hotspot *_zoomOutSpot;
Hotspot _laundryZoomInSpot;
Hotspot _laundryZoomOutSpot;
Hotspot _cornbreadSpot;
Movie _extraMovie;
NotificationCallBack _extraMovieCallBack;
bool _lookingAtLaundry;
FuseFunction _utilityFuse;
long _sinclairLoopCount;
long _numSinclairLoops;
Sprite *_gunSprite;
SinclairCallBack _sinclairInterrupt;
Common::Path getSoundSpotsName() override;
Common::Path getNavMovieName() override;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,391 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/neighborhood/caldoria/caldoria.h"
#include "pegasus/neighborhood/caldoria/caldoria4dsystem.h"
namespace Pegasus {
enum {
kSwitchableSlop = 3 * kCaldoriaFrameDuration,
// Two seconds - some slop
kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop,
// Twelve frames + some slop
kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop,
kSwitchable1Start = 0,
kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration,
kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration,
kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration,
kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration,
kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration,
kVidPhoneDoneFlag = 1,
kRockMusicLoopIn = 0,
kRockMusicLoopOut = 2088,
kOrchestralMusicLoopIn = 2088,
kOrchestralMusicLoopOut = 4985,
kRhythmsMusicLoopIn = 4985,
kRhythmsMusicLoopOut = 6824,
kAcousticMusicLoopIn = 6824,
kAcousticMusicLoopOut = 9387
};
enum {
k4DVideoMenu,
k4DAudioMenu,
k4DShuttingDown,
// These constants are the exact frame numbers of the sprite movie.
k4DRockChoice = 0,
k4DOrchestralChoice,
k4DRhythmsChoice,
k4DAcousticChoice,
k4DIslandChoice,
k4DDesertChoice,
k4DMountainChoice,
k4DFirstVideoChoice = k4DIslandChoice
};
static const ExtraID s_transitionExtras0[3][3] = {
{ 0xffffffff, k4DIsland0ToDesert0, k4DIsland0ToMountain0 },
{ k4DDesert0ToIsland0, 0xffffffff, k4DDesert0ToMountain0 },
{ k4DMountain0ToIsland0, k4DMountain0ToDesert0, 0xffffffff }
};
static const ExtraID s_transitionExtras1[3][3] = {
{ 0xffffffff, k4DIsland1ToDesert0, k4DIsland1ToMountain0 },
{ k4DDesert1ToIsland0, 0xffffffff, k4DDesert1ToMountain0 },
{ k4DMountain1ToIsland0, k4DMountain1ToDesert0, 0xffffffff }
};
static const ExtraID s_transitionExtras2[3][3] = {
{ 0xffffffff, k4DIsland2ToDesert0, k4DIsland2ToMountain0 },
{ k4DDesert2ToIsland0, 0xffffffff, k4DDesert2ToMountain0 },
{ k4DMountain2ToIsland0, k4DMountain2ToDesert0, 0xffffffff }
};
static const ExtraID s_shutDownExtras[3][3] = {
{ 0xffffffff, k4DIsland1ToIsland0, k4DIsland2ToIsland0 },
{ k4DDesert0ToIsland0, k4DDesert1ToIsland0, k4DDesert2ToIsland0 },
{ k4DMountain0ToIsland0, k4DMountain1ToIsland0, k4DMountain2ToIsland0 }
};
Caldoria4DSystem::Caldoria4DSystem(Neighborhood *owner) : GameInteraction(kCaldoria4DInteractionID, owner),
_4DSpritesMovie(kCaldoria4DSpritesID) {
_4DSpritesScale = 0;
_whichMenu = k4DVideoMenu;
_videoChoice = k4DIslandChoice;
_audioChoice = k4DRockChoice;
_neighborhoodNotification = nullptr;
_loopStart = 0;
_clickedHotspotID = kNoHotSpotID;
g_AIArea->lockAIOut();
}
Caldoria4DSystem::~Caldoria4DSystem() {
g_AIArea->unlockAI();
}
void Caldoria4DSystem::openInteraction() {
_whichMenu = k4DVideoMenu;
_videoChoice = k4DIslandChoice;
_audioChoice = k4DRockChoice;
_clickedHotspotID = kNoHotSpotID;
_4DSpritesMovie.initFromMovieFile("Images/Caldoria/4D Sprites", true);
_4DSpritesMovie.moveElementTo(kCaldoria4DSpritesLeft, kCaldoria4DSpritesTop);
_4DSpritesMovie.setDisplayOrder(k4DSpritesOrder);
_4DSpritesMovie.startDisplaying();
_4DSpritesMovie.show();
_4DSpritesScale = _4DSpritesMovie.getScale();
_neighborhoodNotification = _owner->getNeighborhoodNotification();
_neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
startIdling();
}
void Caldoria4DSystem::loopExtra(const ExtraID extraID) {
ExtraTable::Entry extraEntry;
_owner->getExtraEntry(extraID, extraEntry);
_loopStart = extraEntry.movieStart;
_owner->loopExtraSequence(extraID);
}
void Caldoria4DSystem::useIdleTime() {
if (_whichMenu == k4DShuttingDown) {
TimeValue movieTime = _owner->getNavMovie()->getTime() - _loopStart;
ExtraID extraID;
if (movieTime < kSwitchable1Stop)
extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][0];
else if (movieTime >= kSwitchable2Start && movieTime < kSwitchable2Stop)
extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][1];
else if (movieTime >= kSwitchable3Start && movieTime < kSwitchable3Stop)
extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][2];
else
extraID = 0xffffffff;
if (extraID != 0xffffffff) {
setSpritesMovie();
_loopStart = 0;
_owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
}
} else if (_clickedHotspotID != kNoHotSpotID) {
TimeValue movieTime = _owner->getNavMovie()->getTime() - _loopStart;
ExtraID extraID;
if (movieTime < kSwitchable1Stop) {
extraID = s_transitionExtras0[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
_clickedHotspotID = kNoHotSpotID;
} else if (movieTime >= kSwitchable2Start && movieTime < kSwitchable2Stop) {
extraID = s_transitionExtras1[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
_clickedHotspotID = kNoHotSpotID;
} else if (movieTime >= kSwitchable3Start && movieTime < kSwitchable3Stop) {
extraID = s_transitionExtras2[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
_clickedHotspotID = kNoHotSpotID;
} else
extraID = 0xffffffff;
if (extraID != 0xffffffff) {
switch (extraID) {
case k4DDesert0ToIsland0:
case k4DMountain0ToIsland0:
case k4DDesert1ToIsland0:
case k4DMountain1ToIsland0:
case k4DDesert2ToIsland0:
case k4DMountain2ToIsland0:
_videoChoice = k4DIslandChoice;
break;
case k4DIsland0ToDesert0:
case k4DMountain0ToDesert0:
case k4DIsland1ToDesert0:
case k4DMountain1ToDesert0:
case k4DIsland2ToDesert0:
case k4DMountain2ToDesert0:
_videoChoice = k4DDesertChoice;
break;
case k4DDesert0ToMountain0:
case k4DIsland0ToMountain0:
case k4DIsland1ToMountain0:
case k4DDesert1ToMountain0:
case k4DIsland2ToMountain0:
case k4DDesert2ToMountain0:
_videoChoice = k4DMountainChoice;
break;
default:
break;
}
setSpritesMovie();
_loopStart = 0;
_owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
}
}
}
void Caldoria4DSystem::initInteraction() {
setSpritesMovie();
playSound("Rock");
_owner->playSpotSoundSync(kCaldoria4DInstructionsIn, kCaldoria4DInstructionsOut);
loopExtra(k4DIslandLoop);
}
void Caldoria4DSystem::closeInteraction() {
stopIdling();
_neighborhoodNotification->cancelNotification(this);
_4DSpritesMovie.releaseMovie();
_owner->loadAmbientLoops();
}
void Caldoria4DSystem::setSpritesMovie() {
if (_whichMenu == k4DShuttingDown)
_4DSpritesMovie.setTime(_4DSpritesScale * k4DIslandChoice);
else if (_whichMenu == k4DVideoMenu)
_4DSpritesMovie.setTime(_4DSpritesScale * _videoChoice);
else if (_whichMenu == k4DAudioMenu)
_4DSpritesMovie.setTime(_4DSpritesScale * _audioChoice);
_4DSpritesMovie.redrawMovieWorld();
}
void Caldoria4DSystem::handleInput(const Input &input, const Hotspot *cursorSpot) {
if (input.downButtonAnyDown())
return;
if (input.anyDirectionInput())
shutDown4DSystem();
else
GameInteraction::handleInput(input, cursorSpot);
}
void Caldoria4DSystem::activateHotspots() {
GameInteraction::activateHotspots();
g_allHotspots.activateOneHotspot(kCa4DChoice4SpotID);
}
void Caldoria4DSystem::clickInHotspot(const Input &input, const Hotspot *spot) {
switch (spot->getObjectID()) {
case kCa4DVisualSpotID:
if (_whichMenu == k4DAudioMenu) {
_whichMenu = k4DVideoMenu;
setSpritesMovie();
}
break;
case kCa4DAudioSpotID:
if (_whichMenu == k4DVideoMenu) {
_whichMenu = k4DAudioMenu;
setSpritesMovie();
}
break;
case kCa4DChoice1SpotID:
if (_whichMenu == k4DVideoMenu)
makeIslandChoice();
else if (_whichMenu == k4DAudioMenu)
makeRockChoice();
break;
case kCa4DChoice2SpotID:
if (_whichMenu == k4DVideoMenu)
makeDesertChoice();
else if (_whichMenu == k4DAudioMenu)
makeOrchestralChoice();
break;
case kCa4DChoice3SpotID:
if (_whichMenu == k4DVideoMenu)
makeMountainChoice();
else if (_whichMenu == k4DAudioMenu)
makeRhythmsChoice();
break;
case kCa4DChoice4SpotID:
if (_whichMenu == k4DAudioMenu)
makeAcousticChoice();
else
_owner->playSpotSoundSync(kCaldoria4DBlankChoiceIn, kCaldoria4DBlankChoiceOut);
break;
default:
GameInteraction::clickInHotspot(input, spot);
}
}
void Caldoria4DSystem::receiveNotification(Notification *, const NotificationFlags) {
if (_whichMenu == k4DShuttingDown) {
_owner->requestDeleteCurrentInteraction();
} else {
uint32 extraID;
switch (_videoChoice) {
case k4DIslandChoice:
extraID = k4DIslandLoop;
break;
case k4DDesertChoice:
extraID = k4DDesertLoop;
break;
case k4DMountainChoice:
extraID = k4DMountainLoop;
break;
default:
extraID = 0xffffffff;
break;
}
if (extraID != 0xffffffff)
loopExtra(extraID);
}
}
void Caldoria4DSystem::makeIslandChoice() {
if (_videoChoice != k4DIslandChoice && _clickedHotspotID == kNoHotSpotID)
_clickedHotspotID = kCa4DChoice1SpotID;
}
void Caldoria4DSystem::makeDesertChoice() {
if (_videoChoice != k4DDesertChoice && _clickedHotspotID == kNoHotSpotID)
_clickedHotspotID = kCa4DChoice2SpotID;
}
void Caldoria4DSystem::makeMountainChoice() {
if (_videoChoice != k4DMountainChoice && _clickedHotspotID == kNoHotSpotID)
_clickedHotspotID = kCa4DChoice3SpotID;
}
void Caldoria4DSystem::makeRockChoice() {
if (_audioChoice != k4DRockChoice) {
_audioChoice = k4DRockChoice;
setSpritesMovie();
playSound("Rock");
}
}
void Caldoria4DSystem::makeOrchestralChoice() {
if (_audioChoice != k4DOrchestralChoice) {
_audioChoice = k4DOrchestralChoice;
setSpritesMovie();
playSound("Orchestral");
}
}
void Caldoria4DSystem::makeRhythmsChoice() {
if (_audioChoice != k4DRhythmsChoice) {
_audioChoice = k4DRhythmsChoice;
setSpritesMovie();
playSound("Rhythms");
}
}
void Caldoria4DSystem::makeAcousticChoice() {
if (_audioChoice != k4DAcousticChoice) {
_audioChoice = k4DAcousticChoice;
setSpritesMovie();
playSound("Acoustic");
}
}
void Caldoria4DSystem::shutDown4DSystem() {
_whichMenu = k4DShuttingDown;
}
void Caldoria4DSystem::playSound(const Common::String &baseFileName) {
Common::String fileName = "Sounds/Caldoria/" + baseFileName;
// Updated DVD files
if (g_vm->isDVD())
fileName += ".44K";
_owner->loadLoopSound1(Common::Path(fileName + ".aiff"));
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,79 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA4DSYSTEM_H
#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA4DSYSTEM_H
#include "pegasus/interaction.h"
#include "pegasus/movie.h"
#include "pegasus/notification.h"
#include "pegasus/timers.h"
namespace Pegasus {
class Neighborhood;
class Caldoria4DSystem : public GameInteraction, private Idler, public NotificationReceiver {
public:
Caldoria4DSystem(Neighborhood *);
~Caldoria4DSystem() override;
void shutDown4DSystem();
protected:
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void handleInput(const Input &, const Hotspot *) override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void receiveNotification(Notification *, const NotificationFlags) override;
void setSpritesMovie();
void makeIslandChoice();
void makeRockChoice();
void makeMountainChoice();
void makeOrchestralChoice();
void makeDesertChoice();
void makeRhythmsChoice();
void makeAcousticChoice();
void useIdleTime() override;
void loopExtra(const ExtraID);
void playSound(const Common::String &baseFileName);
Movie _4DSpritesMovie;
TimeScale _4DSpritesScale;
uint _whichMenu;
uint _videoChoice;
uint _audioChoice;
Notification *_neighborhoodNotification;
TimeValue _loopStart;
HotSpotID _clickedHotspotID;
};
} // End of namespace Pegasus
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,158 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIABOMB_H
#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIABOMB_H
#include "pegasus/interaction.h"
#include "pegasus/notification.h"
#include "pegasus/surface.h"
namespace Pegasus {
/*
Edge list is arranged as follows:
all values in the edge list are bytes.
all vertices are numbers between 0 and 24. x coordinate of vertex is vertex % 5,
and y coordinate is vertex / 5.
an edge is
a direction code
a number of vertices in the edge
an array of vertices -- all vertices along the edge, whether or not they're
clickable.
an array of bools (bytes) indicating that a portion of the edge is
traversed (and should be drawn). the number of bools is one less than
the number of vertices.
an edge list is
an array of 25 bools indicating which vertex is clickable.
an array of 25 bools indicating which vertex is used (drawn).
a number of edges
an array of edges.
a hot vertex list is
a number of vertices
an array of 25 vertices
*/
typedef int8 VertexType;
typedef VertexType *BombEdgeList;
static const VertexType kEdgeOneSixteenth = 0;
static const VertexType kEdgeOneEighth = 1;
static const VertexType kEdgeThreeSixteenths = 2;
static const VertexType kEdgeOneFourth = 3;
static const VertexType kEdgeFiveSixteenths = 4;
static const VertexType kEdgeThreeEighths = 5;
static const VertexType kEdgeSevenSixteenths = 6;
static const VertexType kEdgeOneHalf = 7;
class BombTimer : public IdlerAnimation {
public:
BombTimer(const DisplayElementID);
~BombTimer() override {}
void draw(const Common::Rect &) override;
protected:
void timeChanged(const TimeValue) override;
int _middle;
Surface _leftImage, _rightImage;
};
class BombGrid : public Picture {
public:
BombGrid(const DisplayElementID);
~BombGrid() override {}
void drawEdges(BombEdgeList);
protected:
Frame _yellowDot;
Frame _yellowOneSixteenth;
Frame _yellowOneEighth;
Frame _yellowThreeSixteenths;
Frame _yellowOneFourth;
Frame _yellowFiveSixteenths;
Frame _yellowThreeEighths;
Frame _yellowSevenSixteenths;
Frame _yellowOneHalf;
Frame _redDot;
Frame _redOneSixteenth;
Frame _redOneEighth;
Frame _redThreeSixteenths;
Frame _redOneFourth;
Frame _redFiveSixteenths;
Frame _redThreeEighths;
Frame _redSevenSixteenths;
Frame _redOneHalf;
};
class Hotspot;
class CaldoriaBomb : public GameInteraction, public NotificationReceiver {
public:
CaldoriaBomb(Neighborhood *, NotificationManager *);
~CaldoriaBomb() override;
void setSoundFXLevel(const uint16) override;
void setAmbienceLevel(const uint16) override;
long getNumHints() override;
Common::Path getHintMovie(uint) override;
void doSolve() override;
bool canSolve() override;
protected:
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void receiveNotification(Notification *, const NotificationFlags) override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void handleInput(const Input &, const Hotspot *) override;
InputBits getInputFilter() override;
void startBombAmbient(const Common::Path &);
Notification *_neighborhoodNotification;
BombGrid _grid;
BombTimer _timer;
BombEdgeList _bombLevel[6];
int _currentLevel, _flashTime;
Hotspot *_vertexHotspot[25];
VertexType _lastVertex;
Notification _timerNotification;
NotificationCallBack _timerCallBack;
TimeValue _readTime;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,124 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/neighborhood.h"
#include "pegasus/neighborhood/caldoria/caldoria.h"
#include "pegasus/neighborhood/caldoria/caldoriamessages.h"
namespace Pegasus {
static const NotificationFlags kMessageDoneFlag = 1;
CaldoriaMessages::CaldoriaMessages(Neighborhood *owner, const NotificationID id, NotificationManager *manager) :
GameInteraction(kCaldoriaMessagesInteractionID, owner), Notification(id, manager), _messageMovie(kCaldoriaMessagesID) {
_neighborhoodNotification = nullptr;
_messageNumber = 0;
}
void CaldoriaMessages::openInteraction() {
_neighborhoodNotification = GameInteraction::_owner->getNeighborhoodNotification();
_neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
_messageCallBack.setNotification(this);
notifyMe(this, kMessageDoneFlag, kMessageDoneFlag);
_messageCallBack.setCallBackFlag(kMessageDoneFlag);
_messageNumber = 1;
}
void CaldoriaMessages::setSoundFXLevel(const uint16 fxLevel) {
_messageMovie.setVolume(fxLevel);
}
void CaldoriaMessages::initInteraction() {
GameInteraction::_owner->startExtraSequence(kCaBedroomVidPhone, kExtraCompletedFlag, kFilterNoInput);
}
void CaldoriaMessages::closeInteraction() {
cancelNotification(this);
_neighborhoodNotification->cancelNotification(this);
}
void CaldoriaMessages::receiveNotification(Notification *notification, const NotificationFlags) {
if (notification == _neighborhoodNotification) {
switch (GameInteraction::_owner->getLastExtra()) {
case kCaBedroomVidPhone:
GameInteraction::_owner->showExtraView(kCaBedroomMessage1);
break;
case kCaBedroomMessage1:
play1Message(1);
break;
case kCaBedroomMessage2:
play1Message(2);
break;
default:
break;
}
} else {
_messageCallBack.releaseCallBack();
_messageMovie.releaseMovie();
uint32 extraID = (_messageNumber == 1) ? kCaBedroomMessage1 : kCaBedroomMessage2;
GameInteraction::_owner->showExtraView(extraID);
allowInput(true);
}
}
void CaldoriaMessages::clickInHotspot(const Input &input, const Hotspot *spot) {
uint32 extraID;
switch (spot->getObjectID()) {
case kCaBedroomVidPhoneActivationSpotID:
extraID = (_messageNumber == 1) ? kCaBedroomMessage1 : kCaBedroomMessage2;
GameInteraction::_owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
break;
default:
GameInteraction::clickInHotspot(input, spot);
break;
}
}
void CaldoriaMessages::play1Message(uint messageNumber) {
if (messageNumber == 1) {
_messageMovie.initFromMovieFile("Images/Caldoria/A12NVA.movie");
_messageNumber = 2;
} else {
_messageMovie.initFromMovieFile("Images/Caldoria/A12NVB.movie");
_messageNumber = 1;
GameState.setCaldoriaSeenMessages(true);
}
_messageMovie.setVolume(g_vm->getSoundFXLevel());
_messageMovie.moveElementTo(kCaldoriaMessageLeft, kCaldoriaMessageTop);
_messageMovie.setDisplayOrder(kCaldoriaMessagesOrder);
_messageMovie.startDisplaying();
_messageCallBack.initCallBack(&_messageMovie, kCallBackAtExtremes);
_messageCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
allowInput(false);
_messageMovie.show();
_messageMovie.redrawMovieWorld();
_messageMovie.start();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,61 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMESSAGES_H
#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMESSAGES_H
#include "pegasus/input.h"
#include "pegasus/interaction.h"
#include "pegasus/movie.h"
#include "pegasus/notification.h"
#include "pegasus/timers.h"
namespace Pegasus {
class Neighborhood;
class CaldoriaMessages : public GameInteraction, public Notification, public NotificationReceiver {
public:
CaldoriaMessages(Neighborhood *, const NotificationID, NotificationManager *);
~CaldoriaMessages() override {}
void setSoundFXLevel(const uint16) override;
protected:
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void receiveNotification(Notification *, const NotificationFlags) override;
void clickInHotspot(const Input &, const Hotspot *) override;
void play1Message(uint);
Movie _messageMovie;
NotificationCallBack _messageCallBack;
Notification *_neighborhoodNotification;
uint _messageNumber;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,133 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/neighborhood.h"
#include "pegasus/neighborhood/caldoria/caldoria.h"
#include "pegasus/neighborhood/caldoria/caldoriamirror.h"
namespace Pegasus {
CaldoriaMirror::CaldoriaMirror(Neighborhood *owner) : GameInteraction(kCaldoriaMirrorInteractionID, owner) {
_neighborhoodNotification = nullptr;
}
void CaldoriaMirror::openInteraction() {
_neighborhoodNotification = _owner->getNeighborhoodNotification();
_neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
}
void CaldoriaMirror::initInteraction() {
_owner->setCurrentActivation(kActivateMirrorReady);
_owner->startExtraSequence(kCaBathroomGreeting, kExtraCompletedFlag, kFilterNoInput);
// The original made the player click to start each of the following sequences,
// which was unnecessary, so it is automated here.
_owner->startExtraSequenceSync(kCaBathroomGreeting, kFilterNoInput);
_owner->startExtraSequenceSync(kCaBathroomBodyFat, kFilterNoInput);
_owner->startExtraSequence(kCaBathroomStylistIntro, kExtraCompletedFlag, kFilterNoInput);
}
void CaldoriaMirror::closeInteraction() {
_neighborhoodNotification->cancelNotification(this);
}
void CaldoriaMirror::handleInput(const Input &input, const Hotspot *cursorSpot) {
if (_owner->getLastExtra() == (uint32)kCaBathroomAgencyStandard || !input.anyDirectionInput())
GameInteraction::handleInput(input, cursorSpot);
}
void CaldoriaMirror::activateHotspots() {
GameInteraction::activateHotspots();
switch (_owner->getLastExtra()) {
case kCaBathroomGreeting:
case kCaBathroomBodyFat:
case kCaBathroomRetrothrash:
case kCaBathroomGeoWave:
g_allHotspots.activateOneHotspot(kCaBathroomMirrorSpotID);
g_allHotspots.deactivateOneHotspot(kCaHairStyle1SpotID);
g_allHotspots.deactivateOneHotspot(kCaHairStyle2SpotID);
g_allHotspots.deactivateOneHotspot(kCaHairStyle3SpotID);
break;
case kCaBathroomStylistIntro:
case kCaBathroomRetrothrashReturn:
case kCaBathroomGeoWaveReturn:
g_allHotspots.activateOneHotspot(kCaHairStyle1SpotID);
g_allHotspots.activateOneHotspot(kCaHairStyle2SpotID);
g_allHotspots.activateOneHotspot(kCaHairStyle3SpotID);
g_allHotspots.deactivateOneHotspot(kCaBathroomMirrorSpotID);
break;
default:
break;
}
}
void CaldoriaMirror::clickInHotspot(const Input &input, const Hotspot *spot) {
switch (spot->getObjectID()) {
// The original made the player click through several interstitial screens before
// reaching the hairstyle menu, which was unnecessary, so it's skipped here.
case kCaHairStyle1SpotID:
_owner->startExtraSequenceSync(kCaBathroomRetrothrash, kFilterNoInput);
_owner->startExtraSequence(kCaBathroomRetrothrashReturn, kExtraCompletedFlag, kFilterNoInput);
break;
case kCaHairStyle2SpotID:
_owner->startExtraSequence(kCaBathroomAgencyStandard, kExtraCompletedFlag, kFilterNoInput);
break;
case kCaHairStyle3SpotID:
_owner->startExtraSequenceSync(kCaBathroomGeoWave, kFilterNoInput);
_owner->startExtraSequence(kCaBathroomGeoWaveReturn, kExtraCompletedFlag, kFilterNoInput);
break;
default:
GameInteraction::clickInHotspot(input, spot);
break;
}
}
void CaldoriaMirror::receiveNotification(Notification *, const NotificationFlags) {
switch (_owner->getLastExtra()) {
case kCaBathroomRetrothrash:
case kCaBathroomGeoWave:
_owner->setCurrentActivation(kActivateMirrorReady);
break;
case kCaBathroomStylistIntro:
case kCaBathroomRetrothrashReturn:
case kCaBathroomGeoWaveReturn:
_owner->setCurrentActivation(kActivateStylistReady);
break;
case kCaBathroomAgencyStandard:
_owner->setCurrentActivation(kActivateHotSpotAlways);
_owner->requestDeleteCurrentInteraction();
GameState.setScoringFixedHair(true);
GameState.setCaldoriaDoneHygiene(true);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA43", kArthurCaldoriaChoseAgencyHairStyle);
break;
default:
break;
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,53 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMIRROR_H
#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMIRROR_H
#include "pegasus/interaction.h"
#include "pegasus/notification.h"
namespace Pegasus {
class CaldoriaMirror : public GameInteraction, public NotificationReceiver {
public:
CaldoriaMirror(Neighborhood *);
~CaldoriaMirror() override {}
protected:
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void handleInput(const Input &, const Hotspot *) override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void receiveNotification(Notification *, const NotificationFlags) override;
Notification *_neighborhoodNotification;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,63 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "pegasus/neighborhood/door.h"
namespace Pegasus {
void DoorTable::loadFromStream(Common::SeekableReadStream *stream) {
uint32 count = stream->readUint32BE();
_entries.resize(count);
for (uint32 i = 0; i < count; i++) {
_entries[i].room = stream->readUint16BE();
_entries[i].direction = stream->readByte();
_entries[i].altCode = stream->readByte();
_entries[i].movieStart = stream->readUint32BE();
_entries[i].movieEnd = stream->readUint32BE();
_entries[i].flags = stream->readByte();
stream->readByte(); // alignment
debug(0, "Door[%d]: %d %d %d %d %d %d", i, _entries[i].room, _entries[i].direction,
_entries[i].altCode, _entries[i].movieStart, _entries[i].movieEnd,
_entries[i].flags);
}
}
void DoorTable::clear() {
_entries.clear();
}
DoorTable::Entry DoorTable::findEntry(RoomID room, DirectionConstant direction, AlternateID altCode) {
for (uint32 i = 0; i < _entries.size(); i++)
if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].altCode == altCode)
return _entries[i];
return Entry();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,88 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_DOOR_H
#define PEGASUS_NEIGHBORHOOD_DOOR_H
#include "common/array.h"
#include "common/endian.h"
#include "pegasus/constants.h"
namespace Common {
class SeekableReadStream;
}
namespace Pegasus {
typedef byte DoorFlags;
enum {
kDoorPresentBit, // Bit set if there is a door here.
kDoorLockedBit // Bit set if door is locked, clear if unlocked.
};
static const DoorFlags kNoDoorFlags = 0;
static const DoorFlags kDoorPresentMask = 1 << kDoorPresentBit;
static const DoorFlags kDoorLockedMask = 1 << kDoorLockedBit;
class DoorTable {
public:
DoorTable() {}
~DoorTable() {}
static uint32 getResTag() { return MKTAG('D', 'o', 'o', 'r'); }
void loadFromStream(Common::SeekableReadStream *stream);
void clear();
struct Entry {
Entry() { clear(); }
bool isEmpty() { return movieStart == 0xffffffff; }
void clear() {
room = kNoRoomID;
direction = kNoDirection;
altCode = kNoAlternateID;
movieStart = 0xffffffff;
movieEnd = 0xffffffff;
flags = kNoDoorFlags;
}
RoomID room;
DirectionConstant direction;
AlternateID altCode;
TimeValue movieStart;
TimeValue movieEnd;
DoorFlags flags;
};
Entry findEntry(RoomID room, DirectionConstant direction, AlternateID altCode);
private:
Common::Array<Entry> _entries;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,69 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "pegasus/neighborhood/exit.h"
namespace Pegasus {
void ExitTable::loadFromStream(Common::SeekableReadStream *stream) {
uint32 count = stream->readUint32BE();
_entries.resize(count);
for (uint32 i = 0; i < count; i++) {
_entries[i].room = stream->readUint16BE();
_entries[i].direction = stream->readByte();
_entries[i].altCode = stream->readByte();
_entries[i].movieStart = stream->readUint32BE();
_entries[i].movieEnd = stream->readUint32BE();
_entries[i].exitEnd = stream->readUint32BE();
_entries[i].exitLoop = stream->readUint32BE();
_entries[i].exitRoom = stream->readUint16BE();
_entries[i].exitDirection = stream->readByte();
stream->readByte(); // alignment
_entries[i].originalEnd = _entries[i].exitEnd;
debug(0, "Exit[%d]: %d %d %d %d %d %d %d %d %d", i, _entries[i].room, _entries[i].direction,
_entries[i].altCode, _entries[i].movieStart, _entries[i].movieEnd, _entries[i].exitEnd,
_entries[i].exitLoop, _entries[i].exitRoom, _entries[i].exitDirection);
}
}
void ExitTable::clear() {
_entries.clear();
}
ExitTable::Entry ExitTable::findEntry(RoomID room, DirectionConstant direction, AlternateID altCode) {
for (uint32 i = 0; i < _entries.size(); i++)
if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].altCode == altCode)
return _entries[i];
return Entry();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,92 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_EXIT_H
#define PEGASUS_NEIGHBORHOOD_EXIT_H
#include "common/array.h"
#include "common/endian.h"
#include "pegasus/constants.h"
namespace Common {
class SeekableReadStream;
}
namespace Pegasus {
class ExitTable {
public:
ExitTable() {}
~ExitTable() {}
static uint32 getResTag() { return MKTAG('E', 'x', 'i', 't'); }
void loadFromStream(Common::SeekableReadStream *stream);
void clear();
struct Entry {
Entry() { clear(); }
bool isEmpty() { return movieStart == 0xffffffff; }
void clear() {
room = kNoRoomID;
direction = kNoDirection;
altCode = kNoAlternateID;
movieStart = 0xffffffff;
movieEnd = 0xffffffff;
exitEnd = 0xffffffff;
originalEnd = 0xffffffff;
exitLoop = 0xffffffff;
exitRoom = kNoRoomID;
exitDirection = kNoDirection;
}
RoomID room;
DirectionConstant direction;
AlternateID altCode;
TimeValue movieStart;
TimeValue movieEnd;
// exitEnd is the end of the optimized run of walks.
TimeValue exitEnd;
TimeValue originalEnd;
// exitLoop is the loop start time of the optimized run of walks if the run
// loops back on itself (so far, only in TSA).
TimeValue exitLoop;
RoomID exitRoom;
DirectionConstant exitDirection;
};
Entry findEntry(RoomID room, DirectionConstant direction, AlternateID altCode);
typedef Common::Array<Entry>::iterator iterator;
iterator begin() { return _entries.begin(); }
iterator end() { return _entries.end(); }
private:
Common::Array<Entry> _entries;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,57 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "pegasus/neighborhood/extra.h"
namespace Pegasus {
void ExtraTable::loadFromStream(Common::SeekableReadStream *stream) {
uint32 count = stream->readUint32BE();
_entries.resize(count);
for (uint32 i = 0; i < count; i++) {
_entries[i].extra = stream->readUint32BE();
_entries[i].movieStart = stream->readUint32BE();
_entries[i].movieEnd = stream->readUint32BE();
debug(0, "Extra[%d]: %d %d %d", i, _entries[i].extra, _entries[i].movieStart, _entries[i].movieEnd);
}
}
void ExtraTable::clear() {
_entries.clear();
}
ExtraTable::Entry ExtraTable::findEntry(ExtraID extra) {
for (uint32 i = 0; i < _entries.size(); i++)
if (_entries[i].extra == extra)
return _entries[i];
return Entry();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,66 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_EXTRA_H
#define PEGASUS_NEIGHBORHOOD_EXTRA_H
#include "common/array.h"
#include "common/endian.h"
#include "pegasus/constants.h"
namespace Common {
class SeekableReadStream;
}
namespace Pegasus {
class ExtraTable {
public:
ExtraTable() {}
~ExtraTable() {}
static uint32 getResTag() { return MKTAG('X', 't', 'r', 'a'); }
void loadFromStream(Common::SeekableReadStream *stream);
void clear();
struct Entry {
Entry() { movieStart = 0xffffffff; }
bool isEmpty() { return movieStart == 0xffffffff; }
ExtraID extra;
TimeValue movieStart;
TimeValue movieEnd;
};
Entry findEntry(ExtraID extra);
private:
Common::Array<Entry> _entries;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,64 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "pegasus/neighborhood/hotspotinfo.h"
namespace Pegasus {
void HotspotInfoTable::loadFromStream(Common::SeekableReadStream *stream) {
uint32 count = stream->readUint32BE();
_entries.resize(count);
for (uint32 i = 0; i < count; i++) {
_entries[i].hotspot = stream->readUint16BE();
_entries[i].hotspotActivation = stream->readSByte();
stream->readByte(); // alignment
_entries[i].hotspotRoom = stream->readUint16BE();
_entries[i].hotspotDirection = stream->readByte();
stream->readByte(); // alignment
_entries[i].hotspotExtra = stream->readUint32BE();
_entries[i].hotspotItem = stream->readUint16BE();
debug(0, "Hotspot[%d]: %d %d %d %d %d %d", i, _entries[i].hotspot, _entries[i].hotspotActivation,
_entries[i].hotspotRoom, _entries[i].hotspotDirection, _entries[i].hotspotExtra,
_entries[i].hotspotItem);
}
}
void HotspotInfoTable::clear() {
_entries.clear();
}
HotspotInfoTable::Entry HotspotInfoTable::findEntry(HotSpotID hotspot) {
for (uint32 i = 0; i < _entries.size(); i++)
if (_entries[i].hotspot == hotspot)
return _entries[i];
return Entry();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,76 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_HOTSPOTINFO_H
#define PEGASUS_NEIGHBORHOOD_HOTSPOTINFO_H
#include "common/array.h"
#include "common/endian.h"
#include "pegasus/constants.h"
namespace Common {
class SeekableReadStream;
}
namespace Pegasus {
class HotspotInfoTable {
public:
HotspotInfoTable() {}
~HotspotInfoTable() {}
static uint32 getResTag() { return MKTAG('H', 'S', 'I', 'n'); }
void loadFromStream(Common::SeekableReadStream *stream);
void clear();
struct Entry {
Entry() { hotspotRoom = kNoRoomID; }
bool isEmpty() { return hotspotRoom == kNoRoomID; }
HotSpotID hotspot;
HotSpotActivationID hotspotActivation;
// Location hot spot lives in:
RoomID hotspotRoom;
DirectionConstant hotspotDirection;
// Extra to play if this is a "play extra" hot spot.
ExtraID hotspotExtra;
// Item corresponding to this hot spot if it is an item-related hot spot.
ItemID hotspotItem;
};
Entry findEntry(HotSpotID hotspot);
typedef Common::Array<Entry>::iterator iterator;
iterator begin() { return _entries.begin(); }
iterator end() { return _entries.end(); }
private:
Common::Array<Entry> _entries;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,539 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-2013 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/mars/canyonchase.h"
#include "pegasus/neighborhood/mars/mars.h"
namespace Pegasus {
// Segment start and end points.
//static const TimeValue kPrepStart = 0;
static const TimeValue kPrepEnd = 3000;
static const TimeValue kLaunchStart = kPrepEnd;
static const TimeValue kLaunchEnd = 6640;
static const TimeValue kBranch1Start = kLaunchEnd;
static const TimeValue kBranch1End = 22240;
static const TimeValue kBranch2Start = kBranch1End;
static const TimeValue kBranch2End = 28440;
static const TimeValue kBranch3Start = kBranch2End;
static const TimeValue kBranch3End = 38640;
static const TimeValue kBranch4Start = kBranch3End;
static const TimeValue kBranch4End = 43880;
static const TimeValue kBranch5Start = kBranch4End;
static const TimeValue kBranch5End = 58680;
static const TimeValue kExitStart = kBranch5End;
static const TimeValue kExitEnd = 66480;
static const TimeValue kExitLoopPoint = 66200;
static const TimeValue kExitGenoPoint = 62560;
// Death start and end points.
static const TimeValue kDeath1Start = 0;
static const TimeValue kDeath1End = 2400;
static const TimeValue kDeath2Start = kDeath1End;
static const TimeValue kDeath2End = 4720;
static const TimeValue kDeath3Start = kDeath2End;
static const TimeValue kDeath3End = 7120;
static const TimeValue kDeath4Start = kDeath3End;
static const TimeValue kDeath4End = 9280;
static const TimeValue kDeath5Start = kDeath4End;
static const TimeValue kDeath5End = 12000;
// Chase state.
enum {
kCanyonLaunch,
kCanyonBranch1Left,
kCanyonBranch1Right,
kCanyonBranch2Left,
kCanyonBranch2Right,
kCanyonBranch3Left,
kCanyonBranch4Left,
kCanyonBranch4Right,
kCanyonBranch5Left,
kCanyonBranch5Right,
kCanyonExit,
kCanyonLoop
};
void MusicTimerEvent::fire() {
canyonChase->musicTimerExpired(*this);
}
CanyonChase::CanyonChase(Neighborhood *handler) : ChaseInteraction(kMarsCanyonChaseInteractionID, handler,
kMarsCanyonChaseNotificationID, g_vm), _canyonMovie1(kNoDisplayElement),
_canyonMovie2(kNoDisplayElement), _deathMovie(kNoDisplayElement), _genoMovie(kNoDisplayElement) {
_currentMovie = nullptr;
_currentCallBack = nullptr;
}
void CanyonChase::setSoundFXLevel(const uint16 fxLevel) {
_canyonMovie1.setVolume(fxLevel);
_canyonMovie2.setVolume(fxLevel);
_deathMovie.setVolume(fxLevel);
}
void CanyonChase::setAmbienceLevel(const uint16 level) {
_genoMovie.setVolume(level);
_musicFader.setMasterVolume(level);
}
void CanyonChase::startCanyonMusicLoop(void) {
FaderMoveSpec spec;
_musicLoop.loopSound();
spec.makeTwoKnotFaderSpec(10, 0, 0, 1, 255);
_musicFader.startFader(spec);
}
void CanyonChase::stopCanyonMusicLoop(const long ticks) {
FaderMoveSpec spec;
spec.makeTwoKnotFaderSpec(10, 0, 255, ticks, 0);
_musicFader.startFader(spec);
}
void CanyonChase::openInteraction() {
_canyonMovie1.initFromMovieFile("Images/Mars/Canyon_hq1.mov");
_canyonMovie1.setVolume(g_vm->getSoundFXLevel());
_canyonMovie1.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
_canyonMovie1.setDisplayOrder(kShuttleMonitorOrder);
_canyon1CallBack.setNotification(&_chaseNotification);
_canyon1CallBack.initCallBack(&_canyonMovie1, kCallBackAtExtremes);
_canyon1CallBack.setCallBackFlag(kChaseEnteredBranchZone);
_canyon1CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_canyonMovie2.initFromMovieFile("Images/Mars/Canyon_hq2.mov");
_canyonMovie2.setVolume(g_vm->getSoundFXLevel());
_canyonMovie2.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
_canyonMovie2.setDisplayOrder(kShuttleMonitorOrder);
_canyon2CallBack.setNotification(&_chaseNotification);
_canyon2CallBack.initCallBack(&_canyonMovie2, kCallBackAtExtremes);
_canyon2CallBack.setCallBackFlag(kChaseEnteredBranchZone);
_canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_deathMovie.initFromMovieFile("Images/Mars/Canyon_hqD.mov");
_deathMovie.setVolume(g_vm->getSoundFXLevel());
_deathMovie.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
_deathMovie.setDisplayOrder(kShuttleMonitorOrder);
_deathCallBack.setNotification(&_chaseNotification);
_deathCallBack.initCallBack(&_deathMovie, kCallBackAtExtremes);
_deathCallBack.setCallBackFlag(kChaseFinished);
_deathCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_musicLoop.attachFader(&_musicFader);
_musicLoop.initFromAIFFFile("Sounds/Mars/Canyon Loop.44K.16.AIFF");
_musicFader.setMasterVolume(g_vm->getAmbienceLevel());
ChaseInteraction::openInteraction();
_steerPict.setDisplayOrder(kShuttleMonitorOrder + 1);
_steerPict.moveElementTo(kShuttleSteerLeft, kShuttleSteerTop);
}
void CanyonChase::initInteraction() {
_steerPict.startDisplaying();
// Launch branch is identical in both movies
_canyonState = kCanyonLaunch;
_canyonMovie1.setSegment(kLaunchStart, kLaunchEnd - kDecisionTime);
_canyonMovie1.setTime(kLaunchStart);
switchTo(_canyonMovie1, _canyon1CallBack);
startCanyonMusicLoop();
ChaseInteraction::initInteraction();
}
void CanyonChase::closeInteraction() {
_canyonMovie1.stop();
_canyonMovie1.stopDisplaying();
_canyonMovie1.releaseMovie();
_canyon1CallBack.releaseCallBack();
_canyonMovie2.stop();
_canyonMovie2.stopDisplaying();
_canyonMovie2.releaseMovie();
_canyon2CallBack.releaseCallBack();
_deathMovie.stop();
_deathMovie.stopDisplaying();
_deathMovie.releaseMovie();
_deathCallBack.releaseCallBack();
_genoMovie.stop();
_genoMovie.stopDisplaying();
_genoMovie.releaseMovie();
_genoCallBack.releaseCallBack();
ChaseInteraction::closeInteraction();
}
void CanyonChase::receiveNotification(Notification *notification, const NotificationFlags flags) {
Input input;
if (notification == &_chaseNotification && flags == kChaseFinished) {
if (_canyonState == kCanyonLoop) {
// Swallow the notification if we loop back to the beginning
InputDevice.getInput(input, kFilterAllInput);
if (JMPPPInput::isEasterEggModifierInput(input)) {
stopCanyonMusicLoop(15);
doGenoChase();
} else {
_canyonMovie2.setSegment(kExitGenoPoint, kExitLoopPoint - kDecisionTime);
_canyonMovie2.setTime(kExitGenoPoint);
switchTo(_canyonMovie2, _canyon2CallBack);
_canyon2CallBack.setCallBackFlag(kChaseEnteredBranchZone);
_canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_canyonState = kCanyonLaunch;
}
return;
} else if (_canyonState != kCanyonExit) {
// We died
((Mars *)_owner)->die(kDeathRanIntoCanyonWall);
}
}
ChaseInteraction::receiveNotification(notification, flags);
}
void CanyonChase::setUpBranch() {
TimeValue branchStart, branchEnd;
branchStart = 0;
branchEnd = 0;
switch (_canyonState) {
case kCanyonLaunch:
case kCanyonExit:
branchStart = kLaunchEnd - kDecisionTime;
branchEnd = kLaunchEnd;
break;
case kCanyonBranch1Left:
case kCanyonBranch1Right:
branchStart = kBranch1End - kDecisionTime;
branchEnd = kBranch1End;
break;
case kCanyonBranch2Left:
case kCanyonBranch2Right:
branchStart = kBranch2End - kDecisionTime;
branchEnd = kBranch2End;
break;
case kCanyonBranch3Left:
branchStart = kBranch3End - kDecisionTime;
branchEnd = kBranch3End;
break;
case kCanyonBranch4Left:
case kCanyonBranch4Right:
branchStart = kBranch4End - kDecisionTime;
branchEnd = kBranch4End;
break;
case kCanyonBranch5Left:
case kCanyonBranch5Right:
branchStart = kBranch5End - kDecisionTime;
branchEnd = kBranch5End;
break;
default:
break;
}
_currentMovie->setSegment(branchStart, branchEnd);
// Need to call SetTime here in case we loop
_currentMovie->setTime(branchStart);
_currentCallBack->setCallBackFlag(kChaseExitedBranchZone);
_currentCallBack->scheduleCallBack(kTriggerAtStop, 0, 0);
}
void CanyonChase::branchLeft() {
TimeValue branchStart, branchEnd;
Movie *movie;
NotificationCallBack *callBack;
branchStart = 0;
branchEnd = 0;
switch (_canyonState) {
case kCanyonLaunch:
branchStart = kBranch1Start;
branchEnd = kBranch1End - kDecisionTime;
_canyonState = kCanyonBranch1Left;
break;
case kCanyonBranch1Left:
case kCanyonBranch1Right:
branchStart = kBranch2Start;
branchEnd = kBranch2End - kDecisionTime;
_canyonState = kCanyonBranch2Left;
break;
case kCanyonBranch2Left:
case kCanyonBranch2Right:
branchStart = kBranch3Start;
branchEnd = kBranch3End - kDecisionTime;
_canyonState = kCanyonBranch3Left;
break;
case kCanyonBranch3Left:
branchStart = kBranch4Start;
branchEnd = kBranch4End - kDecisionTime;
_canyonState = kCanyonBranch4Left;
break;
case kCanyonBranch4Left:
case kCanyonBranch4Right:
branchStart = kBranch5Start;
branchEnd = kBranch5End - kDecisionTime;
_canyonState = kCanyonBranch5Left;
break;
case kCanyonBranch5Left:
case kCanyonBranch5Right:
dontBranch();
return;
default:
break;
}
// Left branches are in hq2 (except exit)
// Segment 5 branches are switched
if (_canyonState == kCanyonBranch5Left || _canyonState == kCanyonBranch5Right) {
movie = &_canyonMovie1;
callBack = &_canyon1CallBack;
} else {
movie = &_canyonMovie2;
callBack = &_canyon2CallBack;
}
movie->setSegment(branchStart, branchEnd);
movie->setTime(branchStart);
switchTo(*movie, *callBack);
callBack->setCallBackFlag(kChaseEnteredBranchZone);
callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
}
void CanyonChase::branchRight() {
TimeValue branchStart, branchEnd;
NotificationFlags flag;
Movie *movie;
NotificationCallBack *callBack;
branchStart = 0;
branchEnd = 0;
flag = 0;
switch (_canyonState) {
case kCanyonLaunch:
branchStart = kBranch1Start;
branchEnd = kBranch1End - kDecisionTime;
_canyonState = kCanyonBranch1Right;
flag = kChaseEnteredBranchZone;
break;
case kCanyonBranch1Left:
case kCanyonBranch1Right:
branchStart = kBranch2Start;
branchEnd = kBranch2End - kDecisionTime;
_canyonState = kCanyonBranch2Right;
flag = kChaseEnteredBranchZone;
break;
case kCanyonBranch2Left:
case kCanyonBranch2Right:
dontBranch();
return;
case kCanyonBranch3Left:
branchStart = kBranch4Start;
branchEnd = kBranch4End - kDecisionTime;
_canyonState = kCanyonBranch4Right;
flag = kChaseEnteredBranchZone;
break;
case kCanyonBranch4Left:
case kCanyonBranch4Right:
branchStart = kBranch5Start;
branchEnd = kBranch5End - kDecisionTime;
_canyonState = kCanyonBranch5Right;
flag = kChaseEnteredBranchZone;
break;
case kCanyonBranch5Left:
case kCanyonBranch5Right:
// Exit loop branch is in hq2
branchStart = kExitStart;
branchEnd = kExitEnd;
_canyonState = kCanyonExit;
flag = kChaseFinished;
startMusicTimer(kCanyonChaseStart + kCanyonChaseExitedTime - kExitStart, kMovieTicksPerSecond,
kCanyonExited);
break;
default:
break;
}
// Right branches are in hq1 (except exit)
// Segment 5 branches are switched
if (_canyonState == kCanyonBranch5Left || _canyonState == kCanyonBranch5Right) {
movie = &_canyonMovie2;
callBack = &_canyon2CallBack;
} else {
movie = &_canyonMovie1;
callBack = &_canyon1CallBack;
}
movie->setSegment(branchStart, branchEnd);
movie->setTime(branchStart);
switchTo(*movie, *callBack);
callBack->setCallBackFlag(flag);
callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
}
void CanyonChase::dontBranch() {
TimeValue branchStart, branchEnd;
branchStart = 0;
branchEnd = 0;
switch (_canyonState) {
case kCanyonLaunch:
branchStart = kDeath1Start;
branchEnd = kDeath1End;
break;
case kCanyonBranch1Left:
case kCanyonBranch1Right:
branchStart = kDeath2Start;
branchEnd = kDeath2End;
break;
case kCanyonBranch2Left:
case kCanyonBranch2Right:
branchStart = kDeath3Start;
branchEnd = kDeath3End;
break;
case kCanyonBranch3Left:
branchStart = kDeath4Start;
branchEnd = kDeath4End;
break;
case kCanyonBranch4Left:
case kCanyonBranch4Right:
branchStart = kDeath5Start;
branchEnd = kDeath5End;
break;
case kCanyonBranch5Left:
case kCanyonBranch5Right:
_canyonMovie2.setSegment(kExitStart, kExitGenoPoint);
_canyonMovie2.setTime(kExitStart);
switchTo(_canyonMovie2, _canyon2CallBack);
_canyon2CallBack.setCallBackFlag(kChaseFinished);
_canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_canyonState = kCanyonLoop;
return;
default:
break;
}
_deathMovie.setSegment(branchStart, branchEnd);
_deathMovie.setTime(branchStart);
switchTo(_deathMovie, _deathCallBack);
startMusicTimer(10, 10, kCanyonRanIntoWall);
}
void CanyonChase::showControlsHint() {
((Mars *)_owner)->_lowerLeftShuttleMovie.setTime(kShuttleLowerLeftKeypadHintTime);
((Mars *)_owner)->_lowerLeftShuttleMovie.redrawMovieWorld();
ChaseInteraction::showControlsHint();
}
void CanyonChase::hideControlsHint() {
((Mars *)_owner)->_lowerLeftShuttleMovie.setTime(kShuttleLowerLeftCollisionTime);
((Mars *)_owner)->_lowerLeftShuttleMovie.redrawMovieWorld();
ChaseInteraction::hideControlsHint();
}
void CanyonChase::switchTo(Movie &movie, NotificationCallBack &callBack) {
if (_currentMovie != &movie) {
if (_currentMovie != nullptr) {
_currentMovie->stop();
_currentMovie->hide();
_currentMovie->stopDisplaying();
}
_currentMovie = &movie;
_currentMovie->startDisplaying();
_currentMovie->show();
_currentMovie->start();
}
if (_currentCallBack != &callBack) {
_currentCallBack = &callBack;
}
}
void CanyonChase::startMusicTimer(TimeValue time, TimeScale scale, MusicTimerCode code) {
_musicFuse.primeFuse(time, scale);
_musicEvent.canyonChase = this;
_musicEvent.theEvent = code;
_musicFuse.setFunctor(new Common::Functor0Mem<void, MusicTimerEvent>(&_musicEvent, &MusicTimerEvent::fire));
_musicFuse.lightFuse();
}
void CanyonChase::musicTimerExpired(MusicTimerEvent &event) {
FaderMoveSpec spec;
switch (event.theEvent) {
case kCanyonRanIntoWall:
stopCanyonMusicLoop(5);
break;
case kCanyonExited:
spec.makeTwoKnotFaderSpec(20, 0, 255, 5, 160);
_musicFader.startFader(spec);
startMusicTimer(kCanyonChaseFadedTime, kMovieTicksPerSecond, kCanyonFaded);
break;
case kCanyonFaded:
spec.makeTwoKnotFaderSpec(10, 0, 160, 30, 0);
_musicFader.startFader(spec);
((Mars *)_owner)->startMarsTimer(kLaunchTubeDVDReachedTime, kMovieTicksPerSecond,
kMarsLaunchTubeReached);
break;
default:
break;
}
}
void CanyonChase::doGenoChase() {
_genoMovie.initFromMovieFile("Images/Mars/Canyon_hqG.mov");
_genoMovie.setVolume(g_vm->getAmbienceLevel());
_genoMovie.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
_genoMovie.setDisplayOrder(kShuttleMonitorOrder);
_genoMovie.startDisplaying();
_genoMovie.show();
_genoMovie.start();
_genoCallBack.setNotification(&_chaseNotification);
_genoCallBack.initCallBack(&_genoMovie, kCallBackAtExtremes);
_genoCallBack.setCallBackFlag(kChaseFinished);
_genoCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_canyonState = kCanyonExit;
((Mars *)_owner)->startMarsTimer(_genoMovie.getDuration() - 5 * kMovieTicksPerSecond,
kMovieTicksPerSecond, kMarsLaunchTubeReached);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,107 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-2013 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_CANYONCHASE_H
#define PEGASUS_NEIGHBORHOOD_MARS_CANYONCHASE_H
#include "pegasus/chase.h"
#include "pegasus/fader.h"
#include "pegasus/movie.h"
#include "pegasus/sound.h"
namespace Pegasus {
class CanyonChase;
class Mars;
enum MusicTimerCode {
kCanyonRanIntoWall,
kCanyonExited,
kCanyonFaded
};
struct MusicTimerEvent {
CanyonChase *canyonChase;
MusicTimerCode theEvent;
void fire();
};
class CanyonChase : public ChaseInteraction {
friend class Mars;
friend struct MusicTimerEvent;
public:
CanyonChase(Neighborhood *);
virtual ~CanyonChase() {}
void setSoundFXLevel(const uint16);
void setAmbienceLevel(const uint16);
protected:
void startCanyonMusicLoop();
void stopCanyonMusicLoop(const long);
void openInteraction();
void initInteraction();
void closeInteraction();
void receiveNotification(Notification *, const NotificationFlags);
void setUpBranch();
void branchLeft();
void branchRight();
void dontBranch();
void showControlsHint();
void hideControlsHint();
void switchTo(Movie &, NotificationCallBack &);
void startMusicTimer(TimeValue, TimeScale, MusicTimerCode);
void musicTimerExpired(MusicTimerEvent &);
void doGenoChase();
Movie _canyonMovie1;
Movie _canyonMovie2;
Movie _deathMovie;
Movie _genoMovie;
NotificationCallBack _canyon1CallBack;
NotificationCallBack _canyon2CallBack;
NotificationCallBack _deathCallBack;
NotificationCallBack _genoCallBack;
Sound _musicLoop;
SoundFader _musicFader;
FuseFunction _musicFuse;
MusicTimerEvent _musicEvent;
Movie *_currentMovie;
NotificationCallBack *_currentCallBack;
short _canyonState;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,966 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_CONSTANTS_H
#define PEGASUS_NEIGHBORHOOD_MARS_CONSTANTS_H
#include "pegasus/constants.h"
namespace Pegasus {
// Element Coordinates
static const CoordType kPodScreenLeft = kNavAreaLeft + 88;
static const CoordType kPodScreenTop = kNavAreaTop + 204;
static const CoordType kPodSteerLeft = kNavAreaLeft + 212;
static const CoordType kPodSteerTop = kNavAreaTop + 232;
static const CoordType kUndoHiliteLeft = kNavAreaLeft + 140;
static const CoordType kUndoHiliteTop = kNavAreaTop + 36;
static const CoordType kCurrentGuessLeft = kNavAreaLeft + 146;
static const CoordType kCurrentGuessTop = kNavAreaTop + 90;
static const CoordType kReactorChoiceHiliteLeft = kNavAreaLeft + 116;
static const CoordType kReactorChoiceHiliteTop = kNavAreaTop + 158;
static const CoordType kReactorHistoryLeft = kNavAreaLeft + 302;
static const CoordType kReactorHistoryTop = kNavAreaTop + 39;
static const CoordType kAnswerLeft = kNavAreaLeft + 304;
static const CoordType kAnswerTop = kNavAreaTop + 180;
static const CoordType kShuttle1Left = 0;
static const CoordType kShuttle1Top = 0;
static const CoordType kShuttle2Left = 0;
static const CoordType kShuttle2Top = 96;
static const CoordType kShuttle3Left = 500;
static const CoordType kShuttle3Top = 96;
static const CoordType kShuttle4Left = 0;
static const CoordType kShuttle4Top = 320;
static const CoordType kShuttleWindowLeft = 140;
static const CoordType kShuttleWindowTop = 96;
static const CoordType kShuttleWindowWidth = 360;
static const CoordType kShuttleWindowHeight = 224;
static const CoordType kShuttleWindowMidH = (kShuttleWindowLeft * 2 + kShuttleWindowWidth) / 2;
static const CoordType kShuttleWindowMidV = (kShuttleWindowTop * 2 + kShuttleWindowHeight) / 2;
static const CoordType kShuttleLeftLeft = 0;
static const CoordType kShuttleLeftTop = 128;
static const CoordType kShuttleRightLeft = 506;
static const CoordType kShuttleRightTop = 128;
static const CoordType kShuttleLowerLeftLeft = 74;
static const CoordType kShuttleLowerLeftTop = 358;
static const CoordType kShuttleLowerRightLeft = 486;
static const CoordType kShuttleLowerRightTop = 354;
static const CoordType kShuttleCenterLeft = 260;
static const CoordType kShuttleCenterTop = 336;
static const CoordType kShuttleUpperLeftLeft = 30;
static const CoordType kShuttleUpperLeftTop = 32;
static const CoordType kShuttleUpperRightLeft = 506;
static const CoordType kShuttleUpperRightTop = 52;
static const CoordType kShuttleLeftEnergyLeft = 110;
static const CoordType kShuttleLeftEnergyTop = 186;
static const CoordType kShuttleRightEnergyLeft = 510;
static const CoordType kShuttleRightEnergyTop = 186;
static const CoordType kShuttleEnergyLeft = 186;
static const CoordType kShuttleEnergyTop = 60;
static const CoordType kShuttleEnergyWidth = 252;
static const CoordType kShuttleEnergyHeight = 22;
static const CoordType kShuttleSteerLeft = kShuttleWindowLeft + 136;
static const CoordType kShuttleSteerTop = kShuttleWindowTop + 196;
static const CoordType kPlanetStartLeft = kShuttleWindowLeft;
static const CoordType kPlanetStartTop = kShuttleWindowTop + kShuttleWindowHeight;
static const CoordType kPlanetStopLeft = kShuttleWindowLeft;
static const CoordType kPlanetStopTop = kShuttleWindowTop + kShuttleWindowHeight - 100;
static const CoordType kShuttleTractorLeft = kShuttleWindowLeft + 6;
static const CoordType kShuttleTractorTop = kShuttleWindowTop + 56;
static const CoordType kShuttleTractorWidth = 348;
static const CoordType kShuttleTractorHeight = 112;
static const CoordType kShuttleJunkLeft = kShuttleWindowLeft + 6;
static const CoordType kShuttleJunkTop = kShuttleWindowTop + 6;
static const DisplayOrder kShuttlePlanetOrder = kInterfaceLayer;
static const DisplayOrder kShuttleAlienShipOrder = kShuttlePlanetOrder + 1;
static const DisplayOrder kShuttleRobotShipOrder = kShuttleAlienShipOrder + 1;
static const DisplayOrder kShuttleTractorBeamMovieOrder = kShuttleRobotShipOrder + 1;
static const DisplayOrder kShuttleWeaponBackOrder = kShuttleTractorBeamMovieOrder + 1;
static const DisplayOrder kShuttleJunkOrder = kShuttleWeaponBackOrder + 1;
static const DisplayOrder kShuttleWeaponFrontOrder = kShuttleJunkOrder + 1;
static const DisplayOrder kShuttleTractorBeamOrder = kShuttleWeaponFrontOrder + 1;
static const DisplayOrder kShuttleHUDOrder = kShuttleTractorBeamOrder + 1;
static const DisplayOrder kShuttleBackgroundOrder = kShuttleHUDOrder + 1;
static const DisplayOrder kShuttleMonitorOrder = kShuttleBackgroundOrder + 1;
static const DisplayOrder kShuttleStatusOrder = kShuttleMonitorOrder + 1;
static const TimeValue kShuttleSwingStart = 0;
static const TimeValue kShuttleSwingStop = 5 * 600;
static const TimeValue kCanyonChaseStart = kShuttleSwingStop;
static const TimeValue kCanyonChaseCDStop = 60 * 600 + 43 * 600 + 14 * 40;
static const TimeValue kCanyonChaseDVDStop = 60 * 600 + 50 * 600 + 12 * 40;
static const TimeValue kCanyonChaseExitedTime = 60 * 600 + 40 * 600 + 13 * 40 - kCanyonChaseStart;
static const TimeValue kCanyonChaseFadedTime = 60 * 600 + 43 * 600 + 6 * 40 - kCanyonChaseStart -
kCanyonChaseExitedTime;
static const TimeValue kLaunchTubeCDReachedTime = 60 * 600 + 38 * 600 - kCanyonChaseStart;
static const TimeValue kLaunchTubeDVDReachedTime = 60 * 600 + 45 * 600 - kCanyonChaseStart -
kCanyonChaseExitedTime - kCanyonChaseFadedTime;
static const TimeValue kCanyonChaseCDFinishedTime = kCanyonChaseCDStop - kCanyonChaseStart -
kLaunchTubeCDReachedTime;
static const TimeValue kCanyonChaseDVDFinishedTime = kCanyonChaseDVDStop - kCanyonChaseStart -
kCanyonChaseExitedTime - kCanyonChaseFadedTime -
kLaunchTubeDVDReachedTime;
// Left shuttle.
static const TimeValue kShuttleLeftIntroStart = 0;
static const TimeValue kShuttleLeftIntroStop = 400;
static const TimeValue kShuttleLeftBlankTime = 400;
static const TimeValue kShuttleLeftNormalTime = 440;
static const TimeValue kShuttleLeftAutoTestTime = 480;
static const TimeValue kShuttleLeftDamagedTime = 520;
static const TimeValue kShuttleLeftDampingTime = 560;
static const TimeValue kShuttleLeftGravitonTime = 600;
static const TimeValue kShuttleLeftTractorTime = 640;
// Right shuttle.
static const TimeValue kShuttleRightIntroStart = 0;
static const TimeValue kShuttleRightIntroStop = 400;
static const TimeValue kShuttleRightDestroyedStart = 400;
static const TimeValue kShuttleRightDestroyedStop = 840;
static const TimeValue kShuttleRightBlankTime = 840;
static const TimeValue kShuttleRightNormalTime = 880;
static const TimeValue kShuttleRightDamagedTime = 920;
static const TimeValue kShuttleRightTargetLockTime = 960;
static const TimeValue kShuttleRightGravitonTime = 1000;
static const TimeValue kShuttleRightOverloadTime = 1040;
// Lower Left shuttle.
static const TimeValue kShuttleLowerLeftCollisionTime = 0;
static const TimeValue kShuttleLowerLeftTubeTime = 40;
static const TimeValue kShuttleLowerLeftAutopilotTime = 80;
static const TimeValue kShuttleLowerLeftKeypadHintTime = 120;
// Lower Right shuttle.
static const TimeValue kShuttleLowerRightOffTime = 0;
static const TimeValue kShuttleLowerRightTrackingTime = 40;
static const TimeValue kShuttleLowerRightTransportTime = 80;
static const TimeValue kShuttleLowerRightTransportHiliteTime = 120;
// Center shuttle.
static const TimeValue kShuttleCenterBoardingTime = 0;
static const TimeValue kShuttleCenterCheckTime = 40;
static const TimeValue kShuttleCenterNavCompTime = 80;
static const TimeValue kShuttleCenterCommTime = 120;
static const TimeValue kShuttleCenterWeaponsTime = 160;
static const TimeValue kShuttleCenterAllSystemsTime = 200;
static const TimeValue kShuttleCenterSecureLooseTime = 240;
static const TimeValue kShuttleCenterAutoTestTime = 280;
static const TimeValue kShuttleCenterLaunchTime = 320;
static const TimeValue kShuttleCenterEnterTubeTime = 360;
static const TimeValue kShuttleCenterTargetSightedTime = 400;
static const TimeValue kShuttleCenterVerifyingTime = 440;
static const TimeValue kShuttleCenterScanningTime = 480;
static const TimeValue kShuttleCenterSafeTime = 520;
// Upper Left shuttle.
static const TimeValue kShuttleUpperLeftDimTime = 0;
static const TimeValue kShuttleUpperLeftDampingTime = 40;
static const TimeValue kShuttleUpperLeftGravitonTime = 80;
static const TimeValue kShuttleUpperLeftTractorTime = 120;
// Upper Right shuttle.
static const TimeValue kShuttleUpperRightLockedTime = 0;
static const TimeValue kShuttleUpperRightArmedTime = 40;
static const TimeValue kShuttleUpperRightAlienDestroyedTime = 80;
static const TimeValue kShuttleUpperRightOverloadTime = 120;
static const TimeValue kShuttleUpperRightTargetDestroyedTime = 160;
// Shuttle distance
static const int kShuttleDistance = 500;
static const int kJunkMaxDistance = kShuttleDistance;
static const int kJunkMinDistance = 40;
static const int kEnergyBeamMaxDistance = kShuttleDistance;
static const int kEnergyBeamMinDistance = 40;
static const int kGravitonMaxDistance = kShuttleDistance;
static const int kGravitonMinDistance = 40;
static const TimeValue kMarsOxyMaskOnIn = 0;
static const TimeValue kMarsOxyMaskOnOut = 1560;
static const TimeValue kMarsAirlockButtonBeepIn = 1560;
static const TimeValue kMarsAirlockButtonBeepOut = 1620;
static const TimeValue kMarsColorMatchingButtonBeepIn = 1620;
static const TimeValue kMarsColorMatchingButtonBeepOut = 1680;
static const TimeValue kMarsKioskBeepIn = 1680;
static const TimeValue kMarsKioskBeepOut = 1740;
static const TimeValue kMarsBumpIntoWallIn = 1740;
static const TimeValue kMarsBumpIntoWallOut = 1888;
static const TimeValue kMarsGantryDoorCloseIn = 1888;
static const TimeValue kMarsGantryDoorCloseOut = 2866;
static const TimeValue kMarsTransportDoorCloseIn = 2866;
static const TimeValue kMarsTransportDoorCloseOut = 3593;
static const TimeValue kMarsAirlockPressurizeIn = 3593;
static const TimeValue kMarsAirlockPressurizeOut = 4766;
static const TimeValue kMarsBigAirlockDoorCloseIn = 4766;
static const TimeValue kMarsBigAirlockDoorCloseOut = 7872;
static const TimeValue kMarsSmallAirlockDoorCloseIn = 7872;
static const TimeValue kMarsSmallAirlockDoorCloseOut = 10000;
static const TimeValue kMarsMazeDoorCloseIn = 10000;
static const TimeValue kMarsMazeDoorCloseOut = 10969;
static const TimeValue kMarsRobotTakesTransportIn = 10969;
static const TimeValue kMarsRobotTakesTransportOut = 12802;
static const TimeValue kMarsPodDepartedUpperPlatformIn = 12802;
static const TimeValue kMarsPodDepartedUpperPlatformOut = 15783;
static const TimeValue kMarsPodDepartedLowerPlatformIn = 15783;
static const TimeValue kMarsPodDepartedLowerPlatformOut = 18736;
static const TimeValue kMarsPodArrivedUpperPlatformIn = 18736;
static const TimeValue kMarsPodArrivedUpperPlatformOut = 21605;
static const TimeValue kMarsCheckInRequiredIn = 21605;
static const TimeValue kMarsCheckInRequiredOut = 27463;
static const TimeValue kMarsCantOpenShuttleIn = 27463;
static const TimeValue kMarsCantOpenShuttleOut = 29214;
static const TimeValue kMarsShuttleLockOverrideIn = 29214;
static const TimeValue kMarsShuttleLockOverrideOut = 30330;
static const TimeValue kMarsNoShuttleIn = 30330;
static const TimeValue kMarsNoShuttleOut = 31502;
static const TimeValue kMustBeUnlockedIn = 31502;
static const TimeValue kMustBeUnlockedOut = 33960;
static const TimeValue kColorMatchBlueIn = 33960;
static const TimeValue kColorMatchBlueOut = 34240;
static const TimeValue kColorMatchRedIn = 34240;
static const TimeValue kColorMatchRedOut = 34538;
static const TimeValue kColorMatchGreenIn = 34538;
static const TimeValue kColorMatchGreenOut = 34827;
static const TimeValue kColorMatchYellowIn = 34827;
static const TimeValue kColorMatchYellowOut = 35162;
static const TimeValue kColorMatchPurpleIn = 35162;
static const TimeValue kColorMatchPurpleOut = 35426;
static const TimeValue kColorMatchZeroNodesIn = 35426;
static const TimeValue kColorMatchZeroNodesOut = 36376;
static const TimeValue kColorMatchOneNodeIn = 36376;
static const TimeValue kColorMatchOneNodeOut = 37209;
static const TimeValue kColorMatchTwoNodesIn = 37209;
static const TimeValue kColorMatchTwoNodesOut = 37983;
static const TimeValue kColorMatchThreeNodesIn = 37983;
static const TimeValue kColorMatchThreeNodesOut = 38784;
static const TimeValue kMarsShuttle1DepartedIn = 38784;
static const TimeValue kMarsShuttle1DepartedOut = 40323;
static const TimeValue kMarsShuttle2DepartedIn = 40323;
static const TimeValue kMarsShuttle2DepartedOut = 41824;
static const TimeValue kShuttleCockpitIn = 41824;
static const TimeValue kShuttleCockpitOut = 43126;
static const TimeValue kShuttleOnboardIn = 43126;
static const TimeValue kShuttleOnboardOut = 44284;
static const TimeValue kShuttleNavigationIn = 44284;
static const TimeValue kShuttleNavigationOut = 46049;
static const TimeValue kShuttleCommunicationIn = 46049;
static const TimeValue kShuttleCommunicationOut = 47288;
static const TimeValue kShuttleAutoTestingIn = 47288;
static const TimeValue kShuttleAutoTestingOut = 48179;
static const TimeValue kMarsThrusterAutoTestIn = 48179;
static const TimeValue kMarsThrusterAutoTestOut = 49979;
static const TimeValue kShuttleAllSystemsIn = 49979;
static const TimeValue kShuttleAllSystemsOut = 51065;
static const TimeValue kShuttleSecureLooseIn = 51065;
static const TimeValue kShuttleSecureLooseOut = 52346;
static const TimeValue kShuttlePrepareForDropIn = 52346;
static const TimeValue kShuttlePrepareForDropOut = 53216;
static const TimeValue kShuttleAllClearIn = 53216;
static const TimeValue kShuttleAllClearOut = 54031;
static const TimeValue kShuttleConfiguringIn = 54031;
static const TimeValue kShuttleConfiguringOut = 54994;
static const TimeValue kShuttleGeneratingIn = 54994;
static const TimeValue kShuttleGeneratingOut = 56033;
static const TimeValue kShuttleBreakawayIn = 56033;
static const TimeValue kShuttleBreakawayOut = 57346;
static const TimeValue kMarsAtmosphericBreakawayIn = 57346;
static const TimeValue kMarsAtmosphericBreakawayOut = 59237;
static const TimeValue kMarsCockpitChatterIn = 59237;
static const TimeValue kMarsCockpitChatterOut = 70344;
static const TimeValue kShuttleDamperDescIn = 70344;
static const TimeValue kShuttleDamperDescOut = 73262;
static const TimeValue kShuttleGravitonDescIn = 73262;
static const TimeValue kShuttleGravitonDescOut = 75296;
static const TimeValue kShuttleTractorDescIn = 75296;
static const TimeValue kShuttleTractorDescOut = 78381;
static const TimeValue kShuttleTargetSightedIn = 78381;
static const TimeValue kShuttleTargetSightedOut = 79074;
static const TimeValue kShuttleAutopilotEngagedIn = 79074;
static const TimeValue kShuttleAutopilotEngagedOut = 80414;
static const TimeValue kMarsEDBBlastIn = 80414;
static const TimeValue kMarsEDBBlastOut = 80705;
static const TimeValue kMarsGravitonBlastIn = 80705;
static const TimeValue kMarsGravitonBlastOut = 81199;
static const TimeValue kMarsJunkCollisionIn = 81199;
static const TimeValue kMarsJunkCollisionOut = 81961;
static const TimeValue kShuttleGravitonIn = 81961;
static const TimeValue kShuttleGravitonOut = 82587;
static const TimeValue kShuttleDampingBeamIn = 82587;
static const TimeValue kShuttleDampingBeamOut = 83331;
static const TimeValue kShuttleTractorBeamIn = 83331;
static const TimeValue kShuttleTractorBeamOut = 83802;
static const TimeValue kShuttleHullBreachIn = 83802;
static const TimeValue kShuttleHullBreachOut = 84721;
static const TimeValue kShuttleWingDamageIn = 84721;
static const TimeValue kShuttleWingDamageOut = 85640;
static const TimeValue kShuttleHullDamageIn = 85640;
static const TimeValue kShuttleHullDamageOut = 86513;
static const TimeValue kShuttleEnergyTooLowIn = 86513;
static const TimeValue kShuttleEnergyTooLowOut = 87578;
static const TimeValue kShuttleTractorLimitedIn = 87578;
static const TimeValue kShuttleTractorLimitedOut = 89164;
static const TimeValue kShuttleCantHoldIn = 89164;
static const TimeValue kShuttleCantHoldOut = 90945;
static const TimeValue kShuttleBrokeFreeIn = 90945;
static const TimeValue kShuttleBrokeFreeOut = 92322;
static const TimeValue kShuttleDestroyedIn = 92322;
static const TimeValue kShuttleDestroyedOut = 93189;
static const TimeValue kShuttleCoordinatesIn = 93189;
static const TimeValue kShuttleCoordinatesOut = 94018;
static const TimeValue kShuttleScanningIn = 94018;
static const TimeValue kShuttleScanningOut = 94975;
static const TimeValue kShuttleSafeIn = 94975;
static const TimeValue kShuttleSafeOut = 96176;
static const TimeValue kShuttleOverloadedIn = 96176;
static const TimeValue kShuttleOverloadedOut = 101308;
static const TimeScale kMarsMovieScale = 600;
static const TimeScale kMarsFramesPerSecond = 15;
static const TimeScale kMarsFrameDuration = 40;
// Alternate IDs.
static const AlternateID kAltMarsNormal = 0;
static const AlternateID kAltMarsPodAtMars34 = 1;
static const AlternateID kAltMarsTookCard = 2;
static const AlternateID kAltMars35AirlockEast = 3;
static const AlternateID kAltMars35AirlockWest = 4;
static const AlternateID kAltMarsPodAtMars45 = 5;
static const AlternateID kAltMarsTookMask = 6;
static const AlternateID kAltMarsMaskOnFiller = 7;
static const AlternateID kAltMars60AirlockEast = 8;
static const AlternateID kAltMars60AirlockWest = 9;
// Room IDs.
static const RoomID kMars0A = 0;
static const RoomID kMars00 = 1;
static const RoomID kMars01 = 2;
static const RoomID kMars02 = 3;
static const RoomID kMars03 = 4;
static const RoomID kMars04 = 5;
static const RoomID kMars05 = 6;
static const RoomID kMars06 = 7;
static const RoomID kMars07 = 8;
static const RoomID kMars08 = 9;
static const RoomID kMars09 = 10;
static const RoomID kMars10 = 11;
static const RoomID kMars11 = 12;
static const RoomID kMars12 = 13;
static const RoomID kMars13 = 14;
static const RoomID kMars14 = 15;
static const RoomID kMars15 = 16;
static const RoomID kMars16 = 17;
static const RoomID kMars17 = 18;
static const RoomID kMars18 = 19;
static const RoomID kMars19 = 20;
static const RoomID kMars20 = 21;
static const RoomID kMars21 = 22;
static const RoomID kMars22 = 23;
static const RoomID kMars23 = 24;
static const RoomID kMars24 = 25;
static const RoomID kMars25 = 26;
static const RoomID kMars26 = 27;
static const RoomID kMars27 = 28;
static const RoomID kMars28 = 29;
static const RoomID kMars29 = 30;
static const RoomID kMars30 = 31;
static const RoomID kMars31 = 32;
static const RoomID kMars31South = 33;
static const RoomID kMars32 = 34;
static const RoomID kMars33 = 35;
static const RoomID kMars33North = 36;
static const RoomID kMars34 = 37;
static const RoomID kMars35 = 38;
static const RoomID kMars36 = 39;
static const RoomID kMars37 = 40;
static const RoomID kMars38 = 41;
static const RoomID kMars39 = 42;
static const RoomID kMars41 = 43;
static const RoomID kMars42 = 44;
static const RoomID kMars43 = 45;
static const RoomID kMars44 = 46;
static const RoomID kMars45 = 47;
static const RoomID kMars46 = 48;
static const RoomID kMars47 = 49;
static const RoomID kMars48 = 50;
static const RoomID kMars49 = 51;
static const RoomID kMars50 = 52;
static const RoomID kMars51 = 53;
static const RoomID kMars52 = 54;
static const RoomID kMars54 = 55;
static const RoomID kMars56 = 56;
static const RoomID kMars58 = 57;
static const RoomID kMars60 = 58;
static const RoomID kMarsRobotShuttle = 59;
static const RoomID kMarsMaze004 = 60;
static const RoomID kMarsMaze005 = 61;
static const RoomID kMarsMaze006 = 62;
static const RoomID kMarsMaze007 = 63;
static const RoomID kMarsMaze008 = 64;
static const RoomID kMarsMaze009 = 65;
static const RoomID kMarsMaze010 = 66;
static const RoomID kMarsMaze011 = 67;
static const RoomID kMarsMaze012 = 68;
static const RoomID kMarsMaze015 = 69;
static const RoomID kMarsMaze016 = 70;
static const RoomID kMarsMaze017 = 71;
static const RoomID kMarsMaze018 = 72;
static const RoomID kMarsMaze019 = 73;
static const RoomID kMarsMaze020 = 74;
static const RoomID kMarsMaze021 = 75;
static const RoomID kMarsMaze022 = 76;
static const RoomID kMarsMaze023 = 77;
static const RoomID kMarsMaze024 = 78;
static const RoomID kMarsMaze025 = 79;
static const RoomID kMarsMaze026 = 80;
static const RoomID kMarsMaze027 = 81;
static const RoomID kMarsMaze028 = 82;
static const RoomID kMarsMaze031 = 83;
static const RoomID kMarsMaze032 = 84;
static const RoomID kMarsMaze033 = 85;
static const RoomID kMarsMaze034 = 86;
static const RoomID kMarsMaze035 = 87;
static const RoomID kMarsMaze036 = 88;
static const RoomID kMarsMaze037 = 89;
static const RoomID kMarsMaze038 = 90;
static const RoomID kMarsMaze039 = 91;
static const RoomID kMarsMaze042 = 92;
static const RoomID kMarsMaze043 = 93;
static const RoomID kMarsMaze044 = 94;
static const RoomID kMarsMaze045 = 95;
static const RoomID kMarsMaze046 = 96;
static const RoomID kMarsMaze047 = 97;
static const RoomID kMarsMaze049 = 98;
static const RoomID kMarsMaze050 = 99;
static const RoomID kMarsMaze051 = 100;
static const RoomID kMarsMaze052 = 101;
static const RoomID kMarsMaze053 = 102;
static const RoomID kMarsMaze054 = 103;
static const RoomID kMarsMaze055 = 104;
static const RoomID kMarsMaze056 = 105;
static const RoomID kMarsMaze057 = 106;
static const RoomID kMarsMaze058 = 107;
static const RoomID kMarsMaze059 = 108;
static const RoomID kMarsMaze060 = 109;
static const RoomID kMarsMaze061 = 110;
static const RoomID kMarsMaze063 = 111;
static const RoomID kMarsMaze064 = 112;
static const RoomID kMarsMaze065 = 113;
static const RoomID kMarsMaze066 = 114;
static const RoomID kMarsMaze067 = 115;
static const RoomID kMarsMaze068 = 116;
static const RoomID kMarsMaze069 = 117;
static const RoomID kMarsMaze070 = 118;
static const RoomID kMarsMaze071 = 119;
static const RoomID kMarsMaze072 = 120;
static const RoomID kMarsMaze074 = 121;
static const RoomID kMarsMaze076 = 122;
static const RoomID kMarsMaze078 = 123;
static const RoomID kMarsMaze079 = 124;
static const RoomID kMarsMaze081 = 125;
static const RoomID kMarsMaze083 = 126;
static const RoomID kMarsMaze084 = 127;
static const RoomID kMarsMaze085 = 128;
static const RoomID kMarsMaze086 = 129;
static const RoomID kMarsMaze087 = 130;
static const RoomID kMarsMaze088 = 131;
static const RoomID kMarsMaze089 = 132;
static const RoomID kMarsMaze090 = 133;
static const RoomID kMarsMaze091 = 134;
static const RoomID kMarsMaze092 = 135;
static const RoomID kMarsMaze093 = 136;
static const RoomID kMarsMaze098 = 137;
static const RoomID kMarsMaze099 = 138;
static const RoomID kMarsMaze100 = 139;
static const RoomID kMarsMaze101 = 140;
static const RoomID kMarsMaze104 = 141;
static const RoomID kMarsMaze105 = 142;
static const RoomID kMarsMaze106 = 143;
static const RoomID kMarsMaze107 = 144;
static const RoomID kMarsMaze108 = 145;
static const RoomID kMarsMaze111 = 146;
static const RoomID kMarsMaze113 = 147;
static const RoomID kMarsMaze114 = 148;
static const RoomID kMarsMaze115 = 149;
static const RoomID kMarsMaze116 = 150;
static const RoomID kMarsMaze117 = 151;
static const RoomID kMarsMaze118 = 152;
static const RoomID kMarsMaze119 = 153;
static const RoomID kMarsMaze120 = 154;
static const RoomID kMarsMaze121 = 155;
static const RoomID kMarsMaze122 = 156;
static const RoomID kMarsMaze123 = 157;
static const RoomID kMarsMaze124 = 158;
static const RoomID kMarsMaze125 = 159;
static const RoomID kMarsMaze126 = 160;
static const RoomID kMarsMaze127 = 161;
static const RoomID kMarsMaze128 = 162;
static const RoomID kMarsMaze129 = 163;
static const RoomID kMarsMaze130 = 164;
static const RoomID kMarsMaze131 = 165;
static const RoomID kMarsMaze132 = 166;
static const RoomID kMarsMaze133 = 167;
static const RoomID kMarsMaze136 = 168;
static const RoomID kMarsMaze137 = 169;
static const RoomID kMarsMaze138 = 170;
static const RoomID kMarsMaze139 = 171;
static const RoomID kMarsMaze140 = 172;
static const RoomID kMarsMaze141 = 173;
static const RoomID kMarsMaze142 = 174;
static const RoomID kMarsMaze143 = 175;
static const RoomID kMarsMaze144 = 176;
static const RoomID kMarsMaze145 = 177;
static const RoomID kMarsMaze146 = 178;
static const RoomID kMarsMaze147 = 179;
static const RoomID kMarsMaze148 = 180;
static const RoomID kMarsMaze149 = 181;
static const RoomID kMarsMaze152 = 182;
static const RoomID kMarsMaze153 = 183;
static const RoomID kMarsMaze154 = 184;
static const RoomID kMarsMaze155 = 185;
static const RoomID kMarsMaze156 = 186;
static const RoomID kMarsMaze157 = 187;
static const RoomID kMarsMaze159 = 188;
static const RoomID kMarsMaze160 = 189;
static const RoomID kMarsMaze161 = 190;
static const RoomID kMarsMaze162 = 191;
static const RoomID kMarsMaze163 = 192;
static const RoomID kMarsMaze164 = 193;
static const RoomID kMarsMaze165 = 194;
static const RoomID kMarsMaze166 = 195;
static const RoomID kMarsMaze167 = 196;
static const RoomID kMarsMaze168 = 197;
static const RoomID kMarsMaze169 = 198;
static const RoomID kMarsMaze170 = 199;
static const RoomID kMarsMaze171 = 200;
static const RoomID kMarsMaze172 = 201;
static const RoomID kMarsMaze173 = 202;
static const RoomID kMarsMaze174 = 203;
static const RoomID kMarsMaze175 = 204;
static const RoomID kMarsMaze177 = 205;
static const RoomID kMarsMaze178 = 206;
static const RoomID kMarsMaze179 = 207;
static const RoomID kMarsMaze180 = 208;
static const RoomID kMarsMaze181 = 209;
static const RoomID kMarsMaze182 = 210;
static const RoomID kMarsMaze183 = 211;
static const RoomID kMarsMaze184 = 212;
static const RoomID kMarsMaze187 = 213;
static const RoomID kMarsMaze188 = 214;
static const RoomID kMarsMaze189 = 215;
static const RoomID kMarsMaze190 = 216;
static const RoomID kMarsMaze191 = 217;
static const RoomID kMarsMaze192 = 218;
static const RoomID kMarsMaze193 = 219;
static const RoomID kMarsMaze194 = 220;
static const RoomID kMarsMaze195 = 221;
static const RoomID kMarsMaze198 = 222;
static const RoomID kMarsMaze199 = 223;
static const RoomID kMarsMaze200 = 224;
static const RoomID kMarsDeathRoom = 225;
// Hot Spot Activation IDs.
static const HotSpotActivationID kActivationReadyForKiosk = 1;
static const HotSpotActivationID kActivationKioskChoice = 2;
static const HotSpotActivationID kActivationTunnelMapReady = 3;
static const HotSpotActivationID kActivateMarsPodClosed = 4;
static const HotSpotActivationID kActivateMarsPodOpen = 5;
static const HotSpotActivationID kActivateReadyToPressurizeAirlock = 6;
static const HotSpotActivationID kActivateAirlockPressurized = 7;
static const HotSpotActivationID kActivateMaskOnHolder = 8;
static const HotSpotActivationID kActivateMaskOnFiller = 9;
static const HotSpotActivationID kActivateReactorPlatformOut = 10;
static const HotSpotActivationID kActivateReactorPlatformIn = 11;
static const HotSpotActivationID kActivateReactorAskLowerScreen = 12;
static const HotSpotActivationID kActivateReactorReadyForNitrogen = 13;
static const HotSpotActivationID kActivateReactorReadyForCrowBar = 14;
static const HotSpotActivationID kActivateReactorAskOperation = 15;
static const HotSpotActivationID kActivateReactorRanEvaluation = 16;
static const HotSpotActivationID kActivateReactorRanDiagnostics = 17;
static const HotSpotActivationID kActivateReactorAnalyzed = 18;
static const HotSpotActivationID kActivateReactorInstructions = 19;
static const HotSpotActivationID kActivateReactorInGame = 20;
static const HotSpotActivationID kActivateReactorBombSafe = 21;
static const HotSpotActivationID kActivateReactorBombExposed = 22;
static const HotSpotActivationID kActivationRobotHeadClosed = 23;
static const HotSpotActivationID kActivationRobotHeadOpen = 24;
// Hot Spot IDs.
static const HotSpotID kMars11NorthKioskSpotID = 5000;
static const HotSpotID kMars11NorthKioskSightsSpotID = 5001;
static const HotSpotID kMars11NorthKioskColonySpotID = 5002;
static const HotSpotID kMars12NorthKioskSpotID = 5003;
static const HotSpotID kMars12NorthKioskSightsSpotID = 5004;
static const HotSpotID kMars12NorthKioskColonySpotID = 5005;
static const HotSpotID kMars31SouthSpotID = 5006;
static const HotSpotID kMars31SouthOutSpotID = 5007;
static const HotSpotID kMars31SouthCardSpotID = 5008;
static const HotSpotID kMars33NorthSpotID = 5009;
static const HotSpotID kMars33NorthOutSpotID = 5010;
static const HotSpotID kMars33NorthMonitorSpotID = 5011;
static const HotSpotID kMars34NorthCardDropSpotID = 5012;
static const HotSpotID kMars34SouthOpenStorageSpotID = 5013;
static const HotSpotID kMars34SouthCloseStorageSpotID = 5014;
static const HotSpotID kMars34SouthCrowbarSpotID = 5015;
static const HotSpotID kMars35EastPressurizeSpotID = 5016;
static const HotSpotID kMars35EastSpinSpotID = 5017;
static const HotSpotID kMars35WestPressurizeSpotID = 5018;
static const HotSpotID kMars35WestSpinSpotID = 5019;
static const HotSpotID kMars45NorthOpenStorageSpotID = 5020;
static const HotSpotID kMars45NorthCloseStorageSpotID = 5021;
static const HotSpotID kMars45NorthCrowbarSpotID = 5022;
static const HotSpotID kAttackRobotHotSpotID = 5023;
static const HotSpotID kMars49AirMaskSpotID = 5024;
static const HotSpotID kMars49AirMaskFilledSpotID = 5025;
static const HotSpotID kMars49AirFillingDropSpotID = 5026;
static const HotSpotID kMars52MoveLeftSpotID = 5027;
static const HotSpotID kMars52MoveRightSpotID = 5028;
static const HotSpotID kMars52ExtractSpotID = 5029;
static const HotSpotID kMars53RetractSpotID = 5030;
static const HotSpotID kMars54MoveLeftSpotID = 5031;
static const HotSpotID kMars54MoveRightSpotID = 5032;
static const HotSpotID kMars54ExtractSpotID = 5033;
static const HotSpotID kMars55RetractSpotID = 5034;
static const HotSpotID kMars56MoveLeftSpotID = 5035;
static const HotSpotID kMars56MoveRightSpotID = 5036;
static const HotSpotID kMars56ExtractSpotID = 5037;
static const HotSpotID kMars57RetractSpotID = 5038;
static const HotSpotID kMars57LowerScreenSpotID = 5039;
static const HotSpotID kMars57Retract2SpotID = 5040;
static const HotSpotID kMars57DropNitrogenSpotID = 5041;
static const HotSpotID kMars57DropCrowBarSpotID = 5042;
static const HotSpotID kMars57CantOpenPanelSpotID = 5043;
static const HotSpotID kMars57ShieldEvaluationSpotID = 5044;
static const HotSpotID kMars57MeasureOutputSpotID = 5045;
static const HotSpotID kMars57RunDiagnosticsSpotID = 5046;
static const HotSpotID kMars57BackToOperationMenuSpotID = 5047;
static const HotSpotID kMars57AnalyzeObjectSpotID = 5048;
static const HotSpotID kMars57RemoveObjectMenuSpotID = 5049;
static const HotSpotID kMars57CircuitLinkSpotID = 5050;
static const HotSpotID kMars57CancelCircuitLinkSpotID = 5051;
static const HotSpotID kMars57GameInstructionsSpotID = 5052;
static const HotSpotID kMars57UndoMoveSpotID = 5053;
static const HotSpotID kMars57RedMoveSpotID = 5054;
static const HotSpotID kMars57YellowMoveSpotID = 5055;
static const HotSpotID kMars57GreenMoveSpotID = 5056;
static const HotSpotID kMars57BlueMoveSpotID = 5057;
static const HotSpotID kMars57PurpleMoveSpotID = 5058;
static const HotSpotID kMars57LowerScreenSafelySpotID = 5059;
static const HotSpotID kMars57GrabBombSpotID = 5060;
static const HotSpotID kMars58MoveLeftSpotID = 5061;
static const HotSpotID kMars58MoveRightSpotID = 5062;
static const HotSpotID kMars58ExtractSpotID = 5063;
static const HotSpotID kMars59RetractSpotID = 5064;
static const HotSpotID kMars60EastPressurizeSpotID = 5065;
static const HotSpotID kMars60EastSpinSpotID = 5066;
static const HotSpotID kMars60WestPressurizeSpotID = 5067;
static const HotSpotID kMars60WestSpinSpotID = 5068;
static const HotSpotID kRobotShuttleOpenHeadSpotID = 5069;
static const HotSpotID kRobotShuttleMapChipSpotID = 5070;
static const HotSpotID kRobotShuttleOpticalChipSpotID = 5071;
static const HotSpotID kRobotShuttleShieldChipSpotID = 5072;
// Extra sequence IDs.
static const ExtraID kMarsArrivalFromTSA = 0;
static const ExtraID kMars0AWatchShuttleDepart = 1;
static const ExtraID kRobotThrowsPlayer = 2;
static const ExtraID kMarsInfoKioskIntro = 3;
static const ExtraID kMarsColonyInfo = 4;
static const ExtraID kMarsSightsInfo = 5;
static const ExtraID kRobotOnWayToShuttle = 6;
static const ExtraID kMars31SouthZoomInNoCard = 7;
static const ExtraID kMars31SouthViewNoCard = 8;
static const ExtraID kMars31SouthZoomOutNoCard = 9;
static const ExtraID kMars31SouthZoomViewNoCard = 10;
static const ExtraID kMars33SlideShow1 = 11;
static const ExtraID kMars33SlideShow2 = 12;
static const ExtraID kMars33SlideShow3 = 13;
static const ExtraID kMars33SlideShow4 = 14;
static const ExtraID kMars34SpotOpenWithBar = 15;
static const ExtraID kMars34SpotCloseWithBar = 16;
static const ExtraID kMars34SpotOpenNoBar = 17;
static const ExtraID kMars34SpotCloseNoBar = 18;
static const ExtraID kMars34ViewOpenWithBar = 19;
static const ExtraID kMars34ViewOpenNoBar = 20;
static const ExtraID kMars34NorthPodGreeting = 21;
static const ExtraID kMarsTurnOnPod = 22;
static const ExtraID kMarsTakePodToMars45 = 23;
static const ExtraID kMars35WestSpinAirlockToEast = 24;
static const ExtraID kMars35EastSpinAirlockToWest = 25;
static const ExtraID kMars45SpotOpenWithBar = 26;
static const ExtraID kMars45SpotCloseWithBar = 27;
static const ExtraID kMars45SpotOpenNoBar = 28;
static const ExtraID kMars45SpotCloseNoBar = 29;
static const ExtraID kMars45ViewOpenWithBar = 30;
static const ExtraID kMars45ViewOpenNoBar = 31;
static const ExtraID kMars48RobotApproaches = 32;
static const ExtraID kMars48RobotKillsPlayer = 33;
static const ExtraID kMars48RobotLoops = 34;
static const ExtraID kMars48RobotView = 35;
static const ExtraID kMars48RobotDefends = 36;
static const ExtraID kMars49SouthViewMaskFilling = 37;
static const ExtraID kMars52SpinLeft = 38;
static const ExtraID kMars52SpinRight = 39;
static const ExtraID kMars52Extend = 40;
static const ExtraID kMars53Retract = 41;
static const ExtraID kMars54SpinLeft = 42;
static const ExtraID kMars54SpinRight = 43;
static const ExtraID kMars54Extend = 44;
static const ExtraID kMars55Retract = 45;
static const ExtraID kMars56SpinLeft = 46;
static const ExtraID kMars56SpinRight = 47;
static const ExtraID kMars56ExtendWithBomb = 48;
static const ExtraID kMars56ExtendNoBomb = 49;
static const ExtraID kMars57RetractWithBomb = 50;
static const ExtraID kMars57RetractNoBomb = 51;
static const ExtraID kMars57LowerScreenClosed = 52;
static const ExtraID kMars57CantOpenPanel = 53;
static const ExtraID kMars57FreezeLock = 54;
static const ExtraID kMars57BreakLock = 55;
static const ExtraID kMars57LockFrozenView = 56;
static const ExtraID kMars57ThawLock = 57;
static const ExtraID kMars57OpenPanel = 58;
static const ExtraID kMars57OpenPanelChoices = 59;
static const ExtraID kMars57ShieldEvaluation = 60;
static const ExtraID kMars57MeasureOutput = 61;
static const ExtraID kMars57ShieldOkayLoop = 62;
static const ExtraID kMars57RunDiagnostics = 63;
static const ExtraID kMars57BombExplodes = 64;
static const ExtraID kMars57BombAnalysis = 65;
static const ExtraID kMars57DontLink = 66;
static const ExtraID kMars57CircuitLink = 67;
static const ExtraID kMars57GameLevel1 = 68;
static const ExtraID kMars57GameLevel2 = 69;
static const ExtraID kMars57GameLevel3 = 70;
static const ExtraID kMars57BombExplodesInGame = 71;
static const ExtraID kMars57GameSolved = 72;
static const ExtraID kMars57ExposeBomb = 73;
static const ExtraID kMars57BackToNormal = 74;
static const ExtraID kMars57ViewOpenNoBomb = 75;
static const ExtraID kMars58SpinLeft = 76;
static const ExtraID kMars58SpinRight = 77;
static const ExtraID kMars58Extend = 78;
static const ExtraID kMars59Retract = 79;
static const ExtraID kMars60WestSpinAirlockToEast = 80;
static const ExtraID kMars60EastSpinAirlockToWest = 81;
static const ExtraID kMarsRobotHeadOpen = 82;
static const ExtraID kMarsRobotHeadClose = 83;
static const ExtraID kMarsRobotHead000 = 84;
static const ExtraID kMarsRobotHead001 = 85;
static const ExtraID kMarsRobotHead010 = 86;
static const ExtraID kMarsRobotHead011 = 87;
static const ExtraID kMarsRobotHead100 = 88;
static const ExtraID kMarsRobotHead101 = 89;
static const ExtraID kMarsRobotHead110 = 90;
static const ExtraID kMarsRobotHead111 = 91;
static const ExtraID kMarsMaze007RobotApproach = 92;
static const ExtraID kMarsMaze007RobotLoop = 93;
static const ExtraID kMarsMaze007RobotDeath = 94;
static const ExtraID kMarsMaze015SouthRobotApproach = 95;
static const ExtraID kMarsMaze015SouthRobotLoop = 96;
static const ExtraID kMarsMaze015SouthRobotDeath = 97;
static const ExtraID kMarsMaze101EastRobotApproach = 98;
static const ExtraID kMarsMaze101EastRobotLoop = 99;
static const ExtraID kMarsMaze101EastRobotDeath = 100;
static const ExtraID kMarsMaze104WestLoop = 101;
static const ExtraID kMarsMaze104WestDeath = 102;
static const ExtraID kMarsMaze133SouthApproach = 103;
static const ExtraID kMarsMaze133SouthLoop = 104;
static const ExtraID kMarsMaze133SouthDeath = 105;
static const ExtraID kMarsMaze136NorthApproach = 106;
static const ExtraID kMarsMaze136NorthLoop = 107;
static const ExtraID kMarsMaze136NorthDeath = 108;
static const ExtraID kMarsMaze184WestLoop = 109;
static const ExtraID kMarsMaze184WestDeath = 110;
static const ExtraID kMars200DeathInBucket = 111;
// Mars interactions.
static const InteractionID kMarsTunnelPodInteractionID = 0;
static const InteractionID kMarsCanyonChaseInteractionID = 1;
static const ResIDType kReactorUndoHilitePICTID = 900;
static const int16 kMars52Compass = 90;
static const int16 kMars54Compass = 180;
static const int16 kMars56Compass = 270;
static const int16 kMars58Compass = 0;
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,69 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/mars/energybeam.h"
namespace Pegasus {
static const TimeValue kEnergyBeamTime = kOneSecond * kShuttleWeaponScale / 2;
static const CoordType kEnergyBeamOriginH = kShuttleWindowMidH;
static const CoordType kEnergyBeamOriginV = kShuttleWindowTop + kShuttleWindowHeight;
static const float kBeamXOrigin = convertScreenHToSpaceX(kEnergyBeamOriginH, kEnergyBeamMinDistance);
static const float kBeamYOrigin = convertScreenVToSpaceY(kEnergyBeamOriginV, kEnergyBeamMinDistance);
static const float kBeamZOrigin = kEnergyBeamMinDistance;
EnergyBeam::EnergyBeam() {
_weaponDuration = kEnergyBeamTime;
setSegment(0, kEnergyBeamTime);
_weaponOrigin = Point3D(kBeamXOrigin, kBeamYOrigin, kBeamZOrigin);
}
void EnergyBeam::draw(const Common::Rect &) {
static const int kBeamColorRed1 = 224;
static const int kBeamColorRed2 = 64;
Graphics::Surface *surface = g_vm->_gfx->getWorkArea();
byte red = linearInterp(0, kEnergyBeamTime, _lastTime, kBeamColorRed1, kBeamColorRed2);
uint32 color = surface->format.RGBToColor(red, 0, 0);
Point3D startPoint;
if (_weaponTime < 0.1)
startPoint = _weaponOrigin;
else
linearInterp(_weaponOrigin, _weaponTarget, _weaponTime - 0.1, startPoint);
Common::Point lineStart;
project3DTo2D(startPoint, lineStart);
Common::Point lineEnd;
project3DTo2D(_weaponLocation, lineEnd);
surface->drawThickLine(lineStart.x, lineStart.y, lineEnd.x, lineEnd.y, 2, 1, color);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,42 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_ENERGYBEAM_H
#define PEGASUS_NEIGHBORHOOD_MARS_ENERGYBEAM_H
#include "pegasus/neighborhood/mars/shuttleweapon.h"
namespace Pegasus {
class EnergyBeam : public ShuttleWeapon {
public:
EnergyBeam();
~EnergyBeam() override {}
void draw(const Common::Rect &) override;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,133 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/neighborhood/mars/gravitoncannon.h"
#include "pegasus/neighborhood/mars/robotship.h"
#include "pegasus/neighborhood/mars/spacejunk.h"
namespace Pegasus {
static const TimeValue kGravitonTime = kOneSecond * kShuttleWeaponScale;
static const CoordType kGravitonOriginH = kShuttleWindowLeft - 1;
static const CoordType kGravitonOriginV = kShuttleWindowMidV;
static const float kGravitonXOrigin = convertScreenHToSpaceX(kGravitonOriginH, kGravitonMinDistance);
static const float kGravitonYOrigin = convertScreenVToSpaceY(kGravitonOriginV, kGravitonMinDistance);
static const float kGravitonZOrigin = kGravitonMinDistance;
// Width of graviton sprite...
static const CoordType kGravitonMaxScreenWidth = 78;
static const CoordType kGravitonMaxScreenHeight = 46;
static const float kGravitonWidth = convertScreenHToSpaceX(kShuttleWindowMidH + kGravitonMaxScreenWidth / 2, kGravitonMinDistance)
- convertScreenHToSpaceX(kShuttleWindowMidH - kGravitonMaxScreenWidth / 2, kGravitonMinDistance);
static const float kGravitonHeight = convertScreenVToSpaceY(kShuttleWindowMidV - kGravitonMaxScreenHeight / 2, kGravitonMinDistance)
- convertScreenVToSpaceY(kShuttleWindowMidV + kGravitonMaxScreenHeight / 2, kGravitonMinDistance);
GravitonCannon::GravitonCannon() {
_weaponDuration = kGravitonTime;
setSegment(0, kGravitonTime);
_weaponOrigin = Point3D(kGravitonXOrigin, kGravitonYOrigin, kGravitonZOrigin);
_rightOrigin = Point3D(-kGravitonXOrigin, kGravitonYOrigin, kGravitonZOrigin);
}
void GravitonCannon::initShuttleWeapon() {
ShuttleWeapon::initShuttleWeapon();
_gravitonImage.getImageFromPICTFile("Images/Mars/Graviton Cannon");
_gravitonImage.getSurfaceBounds(_gravitonBounds);
}
void GravitonCannon::cleanUpShuttleWeapon() {
_gravitonImage.deallocateSurface();
ShuttleWeapon::cleanUpShuttleWeapon();
}
void GravitonCannon::draw(const Common::Rect &) {
// Left graviton...
Point3D pt3D = _weaponLocation;
pt3D.translate(-kGravitonWidth / 2, kGravitonHeight / 2, 0);
Common::Point pt2D;
project3DTo2D(pt3D, pt2D);
Common::Rect gravitonRect;
gravitonRect.left = pt2D.x;
gravitonRect.top = pt2D.y;
pt3D.translate(kGravitonWidth, -kGravitonHeight, 0);
project3DTo2D(pt3D, pt2D);
gravitonRect.right = pt2D.x;
gravitonRect.bottom = pt2D.y;
_gravitonImage.scaleTransparentCopy(_gravitonBounds, gravitonRect);
// Right graviton...
pt3D = _rightLocation;
pt3D.translate(-kGravitonWidth / 2, kGravitonHeight / 2, 0);
project3DTo2D(pt3D, pt2D);
gravitonRect.left = pt2D.x;
gravitonRect.top = pt2D.y;
pt3D.translate(kGravitonWidth, -kGravitonHeight, 0);
project3DTo2D(pt3D, pt2D);
gravitonRect.right = pt2D.x;
gravitonRect.bottom = pt2D.y;
_gravitonImage.scaleTransparentCopy(_gravitonBounds, gravitonRect);
}
void GravitonCannon::updateWeaponPosition() {
ShuttleWeapon::updateWeaponPosition();
if (_weaponTime != 1.0)
linearInterp(_rightOrigin, _weaponTarget, _weaponTime, _rightLocation);
}
bool GravitonCannon::collisionWithJunk(Common::Point &impactPoint) {
if (getDisplayOrder() == kShuttleWeaponFrontOrder) {
Point3D junkPosition;
g_spaceJunk->getJunkPosition(junkPosition);
if (junkPosition.z < _weaponLocation.z) {
setDisplayOrder(kShuttleWeaponBackOrder);
project3DTo2D(_weaponLocation, impactPoint);
if (g_spaceJunk->pointInJunk(impactPoint))
return true;
project3DTo2D(_rightLocation, impactPoint);
return g_spaceJunk->pointInJunk(impactPoint);
}
}
return false;
}
void GravitonCannon::hitJunk(Common::Point impactPoint) {
g_spaceJunk->hitByGravitonCannon(impactPoint);
}
void GravitonCannon::hitShuttle(Common::Point impactPoint) {
g_robotShip->hitByGravitonCannon(impactPoint);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,56 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_GRAVITONCANNON_H
#define PEGASUS_NEIGHBORHOOD_MARS_GRAVITONCANNON_H
#include "pegasus/surface.h"
#include "pegasus/neighborhood/mars/shuttleweapon.h"
namespace Pegasus {
class GravitonCannon : public ShuttleWeapon {
public:
GravitonCannon();
~GravitonCannon() override {}
void initShuttleWeapon() override;
void cleanUpShuttleWeapon() override;
void draw(const Common::Rect &) override;
protected:
void updateWeaponPosition() override;
bool collisionWithJunk(Common::Point &impactPoint) override;
void hitJunk(Common::Point impactPoint) override;
void hitShuttle(Common::Point impactPoint) override;
Surface _gravitonImage;
Common::Rect _gravitonBounds;
Point3D _rightOrigin, _rightLocation;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,75 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/neighborhood/mars/hermite.h"
namespace Pegasus {
CoordType hermite(CoordType p1, CoordType p4, CoordType r1, CoordType r4, int32 time, int32 duration) {
float t = (float)time / duration;
float tsq = t * t;
float tcu = t * tsq;
float tcu2 = tcu + tcu;
float tsq2 = tsq + tsq;
float tsq3 = tsq2 + tsq;
return (CoordType)((tcu2 - tsq3 + 1) * p1 + (tsq3 - tcu2) * p4 + (tcu - tsq2 + t) * r1 + (tcu - tsq) * r4);
}
CoordType dHermite(CoordType p1, CoordType p4, CoordType r1, CoordType r4, int32 time, int32 duration) {
float t = (float)time / duration;
float t2 = t + t;
float t4 = t2 + t2;
float t6 = t4 + t2;
float tsq = t * t;
float tsq3 = tsq + tsq + tsq;
float tsq6 = tsq3 + tsq3;
return (CoordType)((tsq6 - t6) * p1 + (t6 - tsq6) * p4 + (tsq3 - t4 + 1) * r1 + (tsq3 - t2) * r4);
}
void hermite(Common::Point p1, Common::Point p4, Common::Point r1, Common::Point r4, int32 time, int32 duration, Common::Point &result) {
float t = (float)time / duration;
float tsq = t * t;
float tcu = t * tsq;
float tcu2 = tcu + tcu;
float tsq2 = tsq + tsq;
float tsq3 = tsq2 + tsq;
result.x = (int16)((tcu2 - tsq3 + 1) * p1.x + (tsq3 - tcu2) * p4.x + (tcu - tsq2 + t) * r1.x + (tcu - tsq) * r4.x);
result.y = (int16)((tcu2 - tsq3 + 1) * p1.y + (tsq3 - tcu2) * p4.y + (tcu - tsq2 + t) * r1.y + (tcu - tsq) * r4.y);
}
void dHermite(Common::Point p1, Common::Point p4, Common::Point r1, Common::Point r4, int32 time, int32 duration, Common::Point &result) {
float t = (float)time / duration;
float t2 = t + t;
float t4 = t2 + t2;
float t6 = t4 + t2;
float tsq = t * t;
float tsq3 = tsq + tsq + tsq;
float tsq6 = tsq3 + tsq3;
result.x = (int16)((tsq6 - t6) * p1.x + (t6 - tsq6) * p4.x + (tsq3 - t4 + 1) * r1.x + (tsq3 - t2) * r4.x);
result.y = (int16)((tsq6 - t6) * p1.y + (t6 - tsq6) * p4.y + (tsq3 - t4 + 1) * r1.y + (tsq3 - t2) * r4.y);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,40 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_HERMITE_H
#define PEGASUS_NEIGHBORHOOD_MARS_HERMITE_H
#include "common/rect.h"
#include "pegasus/types.h"
namespace Pegasus {
CoordType hermite(CoordType p1, CoordType p4, CoordType r1, CoordType r4, int32 t, int32 duration);
CoordType dHermite(CoordType p1, CoordType p4, CoordType r1, CoordType r4, int32 t, int32 duration);
void hermite(Common::Point p1, Common::Point p4, Common::Point r1, Common::Point r4, int32 t, int32 duration, Common::Point &result);
void dHermite(Common::Point p1, Common::Point p4, Common::Point r1, Common::Point r4, int32 t, int32 duration, Common::Point &result);
} // End of namespace Pegasus
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,258 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_MARS_H
#define PEGASUS_NEIGHBORHOOD_MARS_MARS_H
#include "pegasus/neighborhood/neighborhood.h"
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/mars/energybeam.h"
#include "pegasus/neighborhood/mars/gravitoncannon.h"
#include "pegasus/neighborhood/mars/planetmover.h"
#include "pegasus/neighborhood/mars/reactor.h"
#include "pegasus/neighborhood/mars/robotship.h"
#include "pegasus/neighborhood/mars/shuttleenergymeter.h"
#include "pegasus/neighborhood/mars/shuttlehud.h"
#include "pegasus/neighborhood/mars/spacejunk.h"
#include "pegasus/neighborhood/mars/tractorbeam.h"
namespace Pegasus {
class CanyonChase;
class InventoryItem;
class Mars;
class TunnelPod;
enum MarsTimerCode {
kMarsPodCautionDisplayed,
kMarsPodCautionDismissed,
kMarsCanyonChaseExited,
kMarsCanyonChaseFaded,
kMarsLaunchTubeReached,
kMarsCanyonChaseFinished,
kMarsSpaceChaseFinished // Player ran out of time...
};
struct MarsTimerEvent {
Mars *mars;
MarsTimerCode event;
void fire();
};
enum ShuttleWeaponSelection {
kNoWeapon,
kEnergyBeam,
kGravitonCannon,
kTractorBeam
};
class Mars : public Neighborhood {
friend class CanyonChase;
friend class TunnelPod;
friend struct MarsTimerEvent;
public:
Mars(InputHandler *, PegasusEngine *);
~Mars() override;
GameInteraction *makeInteraction(const InteractionID) override;
void flushGameState() override;
uint16 getDateResID() const override;
AirQuality getAirQuality(const RoomID) override;
void checkAirMask() override;
void showBigExplosion(const Common::Rect &, const DisplayOrder);
void showLittleExplosion(const Common::Rect &, const DisplayOrder);
void hitByJunk();
void decreaseRobotShuttleEnergy(const int, Common::Point impactPoint);
void setUpNextDropTime();
Common::Path getBriefingMovie() override;
Common::Path getEnvScanMovie() override;
uint getNumHints() override;
Common::Path getHintMovie(uint) override;
void shieldOn() override;
void shieldOff() override;
void checkContinuePoint(const RoomID, const DirectionConstant) override;
void setSoundFXLevel(const uint16) override;
void setAmbienceLevel(const uint16) override;
bool canSolve() override;
void doSolve() override;
bool inColorMatchingGame();
protected:
enum {
kMarsPrivatePodStorageOpenFlag,
kMarsPrivatePodTurnLeftFlag,
kMarsPrivatePodTurnRightFlag,
kMarsPrivateRobotTiredOfWaitingFlag,
kMarsPrivatePlatformZoomedInFlag,
kMarsPrivateBombExposedFlag,
kMarsPrivateDraggingBombFlag,
kMarsPrivateInSpaceChaseFlag,
kMarsPrivateGotMapChipFlag,
kMarsPrivateGotOpticalChipFlag,
kMarsPrivateGotShieldChipFlag,
kNumMarsPrivateFlags
};
void init() override;
void start() override;
void setUpAIRules() override;
void arriveAt(const RoomID, const DirectionConstant) override;
void takeItemFromRoom(Item *) override;
void dropItemIntoRoom(Item *, Hotspot *) override;
void activateHotspots() override;
void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *) override;
void clickInHotspot(const Input &, const Hotspot *) override;
InputBits getInputFilter() override;
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
void getZoomEntry(const HotSpotID, ZoomTable::Entry &) override;
void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &) override;
CanOpenDoorReason canOpenDoor(DoorTable::Entry &) override;
void openDoor() override;
void closeDoorOffScreen(const RoomID, const DirectionConstant) override;
void startDoorOpenMovie(const TimeValue, const TimeValue) override;
void startExitMovie(const ExitTable::Entry &) override;
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &) override;
void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &) override;
void turnTo(const DirectionConstant) override;
void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void receiveNotification(Notification *, const NotificationFlags) override;
void doorOpened() override;
void startUpFromFinishedTunnelPod();
void setUpReactorEnergyDrain();
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
void lockThawed();
void robotTiredOfWaiting();
void setUpReactorLevel1();
void setUpNextReactorLevel();
void makeColorSequence();
void doUndoOneGuess();
void doReactorGuess(int32 guess);
void bombExplodesInGame();
void didntFindBomb();
CanMoveForwardReason canMoveForward(ExitTable::Entry &) override;
void cantMoveThatWay(CanMoveForwardReason) override;
void moveForward() override;
void bumpIntoWall() override;
void turnLeft() override;
void turnRight() override;
void airStageExpired();
void loadAmbientLoops() override;
void checkAirlockDoors();
void pickedUpItem(Item *item) override;
void cantOpenDoor(CanOpenDoorReason) override;
void launchMaze007Robot();
void launchMaze015Robot();
void launchMaze101Robot();
void launchMaze104Robot();
void launchMaze133Robot();
void launchMaze136Robot();
void launchMaze184Robot();
void timerExpired(const uint32) override;
void showRobotAtReactor();
void spotCompleted() override;
void doCanyonChase(void);
void startMarsTimer(TimeValue, TimeScale, MarsTimerCode);
void marsTimerExpired(MarsTimerEvent &);
void throwAwayMarsShuttle();
void startUpFromFinishedSpaceChase();
void startUpFromSpaceChase();
void transportOutFromSpaceChase(bool);
void spaceChaseClick(const Input &, const HotSpotID);
void updateCursor(const Common::Point &, const Hotspot *) override;
void playSpaceAmbient();
Common::Path getSoundSpotsName() override;
Common::Path getNavMovieName() override;
Movie _extraMovie;
NotificationCallBack _extraMovieCallBack;
InventoryItem *_attackingItem;
FuseFunction _bombFuse;
FuseFunction _noAirFuse;
FuseFunction _utilityFuse;
FlagsArray<byte, kNumMarsPrivateFlags> _privateFlags;
uint _reactorStage, _nextGuess;
int32 _currentGuess[3];
ReactorGuess _guessObject;
Picture _undoPict;
ReactorHistory _guessHistory;
ReactorChoiceHighlight _choiceHighlight;
Picture _shuttleInterface1;
Picture _shuttleInterface2;
Picture _shuttleInterface3;
Picture _shuttleInterface4;
Movie _canyonChaseMovie;
Sound _musicLoop;
SoundFader _musicFader;
MarsTimerEvent _marsEvent;
Movie _leftShuttleMovie;
Movie _rightShuttleMovie;
Movie _lowerLeftShuttleMovie;
Movie _lowerRightShuttleMovie;
Movie _centerShuttleMovie;
Movie _upperLeftShuttleMovie;
Movie _upperRightShuttleMovie;
Movie _leftDamageShuttleMovie;
Movie _rightDamageShuttleMovie;
ShuttleEnergyMeter _shuttleEnergyMeter;
Movie _planetMovie;
PlanetMover _planetMover;
RobotShip _robotShip;
ShuttleHUD _shuttleHUD;
TractorBeam _tractorBeam;
SpaceJunk _junk;
EnergyBeam _energyBeam;
GravitonCannon _gravitonCannon;
Hotspot _energyChoiceSpot;
Hotspot _gravitonChoiceSpot;
Hotspot _tractorChoiceSpot;
Hotspot _shuttleViewSpot;
Hotspot _shuttleTransportSpot;
ShuttleWeaponSelection _weaponSelection;
ScalingMovie _explosions;
NotificationCallBack _explosionCallBack;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,103 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/movie.h"
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/mars/hermite.h"
#include "pegasus/neighborhood/mars/planetmover.h"
#include "pegasus/neighborhood/mars/shuttleenergymeter.h"
namespace Pegasus {
static const TimeScale kRovingScale = kTractorBeamScale;
static const TimeValue kRovingTime = kTenSeconds * kRovingScale;
static const TimeValue kRovingSlop = kTwoSeconds * kRovingScale;
static const CoordType kMaxVelocity = 20;
PlanetMover::PlanetMover() {
setScale(kRovingScale);
_dropping = false;
_planetMovie = nullptr;
}
void PlanetMover::startMoving(Movie *planetMovie) {
_planetMovie = planetMovie;
_p4 = kPlanetStartTop;
_r4 = g_vm->getRandomNumber(kMaxVelocity - 1);
if (_r4 + _p4 < kPlanetStopTop)
_r4 = kPlanetStopTop - _p4;
newDestination();
}
void PlanetMover::stopMoving() {
stop();
}
void PlanetMover::dropPlanetOutOfSight() {
stop();
CoordType currentLoc = hermite(_p1, _p4, _r1, _r4, _lastTime, _duration);
CoordType currentV = dHermite(_p1, _p4, _r1, _r4, _lastTime, _duration);
_p1 = currentLoc;
_r1 = currentV;
_p4 = kPlanetStartTop;
_r4 = 0;
_duration = kTractorBeamTime - kTractorBeamScale;
_dropping = true;
setSegment(0, _duration);
setTime(0);
start();
}
void PlanetMover::newDestination() {
_p1 = _p4;
_r1 = _r4;
_p4 = kPlanetStopTop + g_vm->getRandomNumber(kPlanetStartTop - kPlanetStopTop - 1);
_r4 = g_vm->getRandomNumber(kMaxVelocity - 1);
if (_r4 + _p4 < kPlanetStopTop)
_r4 = kPlanetStopTop - _p4;
stop();
_duration = kRovingTime + g_vm->getRandomNumber(kRovingSlop - 1);
setSegment(0, _duration);
setTime(0);
start();
}
void PlanetMover::timeChanged(const TimeValue) {
if (_planetMovie) {
_planetMovie->moveElementTo(kPlanetStartLeft, hermite(_p1, _p4, _r1, _r4, _lastTime, _duration));
if (_lastTime == _duration) {
if (_dropping)
stop();
else
newDestination();
}
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,56 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_PLANETMOVER_H
#define PEGASUS_NEIGHBORHOOD_MARS_PLANETMOVER_H
#include "pegasus/timers.h"
namespace Pegasus {
class Movie;
class PlanetMover : IdlerTimeBase {
public:
PlanetMover();
~PlanetMover() override {}
void startMoving(Movie *);
void stopMoving();
void dropPlanetOutOfSight();
protected:
void newDestination();
void timeChanged(const TimeValue) override;
Movie *_planetMovie;
CoordType _p1, _p4, _r1, _r4;
TimeValue _duration;
bool _dropping;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,296 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* aint32 with this program; if not, write to the Free Software
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/mars/reactor.h"
namespace Pegasus {
static const CoordType kCurrentGuessWidth = 121;
static const CoordType kCurrentGuessHeight = 23;
static const CoordType kOneGuessWidth = 25;
static const CoordType kOneGuessHeight = 23;
static const ResIDType kReactorChoicesPICTID = 905;
static const CoordType kCurrentGuessLeft = kNavAreaLeft + 146;
static const CoordType kCurrentGuessTop = kNavAreaTop + 90;
ReactorGuess::ReactorGuess(const DisplayElementID id) : DisplayElement(id) {
setBounds(kCurrentGuessLeft, kCurrentGuessTop, kCurrentGuessLeft + kCurrentGuessWidth,
kCurrentGuessTop + kCurrentGuessHeight);
setDisplayOrder(kMonitorLayer);
_currentGuess[0] = -1;
_currentGuess[1] = -1;
_currentGuess[2] = -1;
}
void ReactorGuess::initReactorGuess() {
_colors.getImageFromPICTResource(g_vm->_resFork, kReactorChoicesPICTID);
startDisplaying();
show();
}
void ReactorGuess::disposeReactorGuess() {
stopDisplaying();
_colors.deallocateSurface();
}
void ReactorGuess::setGuess(int32 a, int32 b, int32 c) {
_currentGuess[0] = a;
_currentGuess[1] = b;
_currentGuess[2] = c;
triggerRedraw();
}
void ReactorGuess::draw(const Common::Rect &) {
if (_colors.isSurfaceValid()) {
Common::Rect r1(0, 0, kOneGuessWidth, kOneGuessHeight);
Common::Rect r2 = r1;
for (int i = 0; i < 3; i++) {
if (_currentGuess[i] >= 0) {
r1.moveTo(kOneGuessWidth * _currentGuess[i], 0);
r2.moveTo(kCurrentGuessLeft + 48 * i, kCurrentGuessTop);
_colors.copyToCurrentPortTransparent(r1, r2);
}
}
}
}
static const CoordType kReactorChoiceHiliteWidth = 166;
static const CoordType kReactorChoiceHiliteHeight = 26;
static const CoordType kChoiceHiliteLefts[6] = {
0,
34,
34 + 34,
34 + 34 + 32,
34 + 34 + 32 + 34,
34 + 34 + 32 + 34 + 32
};
static const ResIDType kReactorChoiceHilitePICTID = 901;
static const CoordType kReactorChoiceHiliteLeft = kNavAreaLeft + 116;
static const CoordType kReactorChoiceHiliteTop = kNavAreaTop + 158;
ReactorChoiceHighlight::ReactorChoiceHighlight(const DisplayElementID id) : DisplayElement(id) {
setBounds(kReactorChoiceHiliteLeft, kReactorChoiceHiliteTop, kReactorChoiceHiliteLeft + kReactorChoiceHiliteWidth,
kReactorChoiceHiliteTop + kReactorChoiceHiliteHeight);
setDisplayOrder(kMonitorLayer);
}
void ReactorChoiceHighlight::initReactorChoiceHighlight() {
_colors.getImageFromPICTResource(g_vm->_resFork, kReactorChoiceHilitePICTID);
startDisplaying();
show();
}
void ReactorChoiceHighlight::disposeReactorChoiceHighlight() {
stopDisplaying();
_colors.deallocateSurface();
}
void ReactorChoiceHighlight::draw(const Common::Rect &) {
if (_colors.isSurfaceValid()) {
for (int i = 0; i < 5; ++i) {
if (_choices.getFlag(i)) {
Common::Rect r1(0, 0, kChoiceHiliteLefts[i + 1] - kChoiceHiliteLefts[i], kReactorChoiceHiliteHeight);
Common::Rect r2 = r1;
r1.moveTo(kChoiceHiliteLefts[i], 0);
r2.moveTo(kReactorChoiceHiliteLeft + kChoiceHiliteLefts[i], kReactorChoiceHiliteTop);
_colors.copyToCurrentPort(r1, r2);
}
}
}
}
static const CoordType kReactorHistoryWidth = 128;
static const CoordType kReactorHistoryHeight = 168;
static const CoordType kColorWidths[5] = { 24, 25, 25, 26, 27 };
static const CoordType kColorHeights[5] = { 14, 15, 17, 17, 19};
static const CoordType kHistoryLefts[5][3] = {
{ 302 + kNavAreaLeft, 329 + kNavAreaLeft, 357 + kNavAreaLeft },
{ 302 + kNavAreaLeft, 331 + kNavAreaLeft, 360 + kNavAreaLeft },
{ 303 + kNavAreaLeft, 333 + kNavAreaLeft, 363 + kNavAreaLeft },
{ 304 + kNavAreaLeft, 335 + kNavAreaLeft, 366 + kNavAreaLeft },
{ 305 + kNavAreaLeft, 337 + kNavAreaLeft, 369 + kNavAreaLeft }
};
static const CoordType kHistoryTops[5] = {
39 + kNavAreaTop,
61 + kNavAreaTop,
84 + kNavAreaTop,
110 + kNavAreaTop,
137 + kNavAreaTop
};
static const CoordType kOneAnswerWidth = 35;
static const CoordType kOneAnswerHeight = 27;
static const CoordType kDigitWidth = 16;
static const CoordType kDigitHeight = 12;
static const CoordType kCorrectCountLefts[5] = {
388 + kNavAreaLeft,
392 + kNavAreaLeft,
398 + kNavAreaLeft,
402 + kNavAreaLeft,
406 + kNavAreaLeft
};
static const CoordType kCorrectCountTops[5] = {
40 + kNavAreaTop,
62 + kNavAreaTop,
86 + kNavAreaTop,
112 + kNavAreaTop,
140 + kNavAreaTop
};
static const ResIDType kReactorDigitsPICTID = 902;
static const ResIDType kReactorHistoryPICTID = 903;
static const ResIDType kReactorAnswerPICTID = 904;
static const CoordType kReactorHistoryLeft = kNavAreaLeft + 302;
static const CoordType kReactorHistoryTop = kNavAreaTop + 39;
static const CoordType kAnswerLeft = kNavAreaLeft + 304;
static const CoordType kAnswerTop = kNavAreaTop + 180;
ReactorHistory::ReactorHistory(const DisplayElementID id) : DisplayElement(id) {
setBounds(kReactorHistoryLeft, kReactorHistoryTop, kReactorHistoryLeft + kReactorHistoryWidth,
kReactorHistoryTop + kReactorHistoryHeight);
setDisplayOrder(kMonitorLayer);
_numGuesses = 0;
_answer[0] = -1;
_answer[1] = -1;
_answer[2] = -1;
_showAnswer = false;
}
void ReactorHistory::initReactorHistory() {
_colors.getImageFromPICTResource(g_vm->_resFork, kReactorHistoryPICTID);
_digits.getImageFromPICTResource(g_vm->_resFork, kReactorDigitsPICTID);
_answerColors.getImageFromPICTResource(g_vm->_resFork, kReactorAnswerPICTID);
startDisplaying();
show();
}
void ReactorHistory::disposeReactorHistory() {
stopDisplaying();
_colors.deallocateSurface();
}
void ReactorHistory::addGuess(int32 a, int32 b, int32 c) {
_history[_numGuesses][0] = a;
_history[_numGuesses][1] = b;
_history[_numGuesses][2] = c;
_numGuesses++;
triggerRedraw();
}
void ReactorHistory::clearHistory() {
_numGuesses = 0;
_showAnswer = false;
triggerRedraw();
}
void ReactorHistory::setAnswer(int32 a, int32 b, int32 c) {
_answer[0] = a;
_answer[1] = b;
_answer[2] = c;
}
void ReactorHistory::showAnswer() {
_showAnswer = true;
triggerRedraw();
}
bool ReactorHistory::isSolved() {
for (int i = 0; i < _numGuesses; i++)
if (_history[i][0] == _answer[0] && _history[i][1] == _answer[1] && _history[i][2] == _answer[2])
return true;
return false;
}
void ReactorHistory::draw(const Common::Rect &) {
static const CoordType kColorTops[5] = {
0,
kColorHeights[0],
(CoordType)(kColorHeights[0] + kColorHeights[1]),
(CoordType)(kColorHeights[0] + kColorHeights[1] + kColorHeights[2]),
(CoordType)(kColorHeights[0] + kColorHeights[1] + kColorHeights[2] + kColorHeights[3]),
};
if (_colors.isSurfaceValid() && _digits.isSurfaceValid()) {
for (int i = 0; i < _numGuesses; ++i) {
Common::Rect r1(0, 0, kColorWidths[i], kColorHeights[i]);
Common::Rect r2 = r1;
Common::Rect r3(0, 0, kDigitWidth, kDigitHeight);
Common::Rect r4 = r3;
int correct = 0;
for (int j = 0; j < 3; ++j) {
r1.moveTo(kColorWidths[i] * _history[i][j], kColorTops[i]);
r2.moveTo(kHistoryLefts[i][j], kHistoryTops[i]);
_colors.copyToCurrentPortTransparent(r1, r2);
if (_history[i][j] == _answer[j])
correct++;
}
r3.moveTo(kDigitWidth * correct, 0);
r4.moveTo(kCorrectCountLefts[i], kCorrectCountTops[i]);
_digits.copyToCurrentPort(r3, r4);
}
if (_showAnswer && _answerColors.isSurfaceValid()) {
Common::Rect r1(0, 0, kOneAnswerWidth, kOneAnswerHeight);
Common::Rect r2 = r1;
for (int i = 0; i < 3; i++) {
r1.moveTo(kOneAnswerWidth * _answer[i], 0);
r2.moveTo(kAnswerLeft + 34 * i, kAnswerTop);
_answerColors.copyToCurrentPortTransparent(r1, r2);
}
}
}
}
int32 ReactorHistory::getCurrentNumCorrect() {
int correct = 0;
for (int i = 0; i < 3; i++)
if (_history[_numGuesses - 1][i] == _answer[i])
correct++;
return correct;
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,107 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_REACTOR_H
#define PEGASUS_NEIGHBORHOOD_MARS_REACTOR_H
#include "pegasus/elements.h"
#include "pegasus/surface.h"
#include "pegasus/util.h"
namespace Pegasus {
class ReactorGuess : public DisplayElement {
public:
ReactorGuess(const DisplayElementID);
~ReactorGuess() override {}
void initReactorGuess();
void disposeReactorGuess();
void setGuess(int32, int32, int32);
void draw(const Common::Rect &) override;
protected:
int32 _currentGuess[3];
Surface _colors;
};
class ReactorChoiceHighlight : public DisplayElement {
public:
ReactorChoiceHighlight(const DisplayElementID);
~ReactorChoiceHighlight() override {}
void initReactorChoiceHighlight();
void disposeReactorChoiceHighlight();
void resetHighlight() {
_choices.clearAllFlags();
triggerRedraw();
}
bool choiceHighlighted(uint32 whichChoice) { return _choices.getFlag(whichChoice); }
void draw(const Common::Rect &) override;
void highlightChoice(uint32 whichChoice) {
_choices.setFlag(whichChoice);
triggerRedraw();
}
protected:
Surface _colors;
FlagsArray<byte, 5> _choices;
};
class ReactorHistory : public DisplayElement {
public:
ReactorHistory(const DisplayElementID);
~ReactorHistory() override {}
void initReactorHistory();
void disposeReactorHistory();
void draw(const Common::Rect &) override;
void addGuess(int32, int32, int32);
int32 getNumGuesses() { return _numGuesses; }
void clearHistory();
void setAnswer(int32, int32, int32);
void showAnswer();
bool isSolved();
int32 getCurrentNumCorrect();
protected:
Surface _colors, _digits, _answerColors;
int32 _answer[3];
int32 _history[5][3];
int32 _numGuesses;
bool _showAnswer;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,266 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/mars/hermite.h"
#include "pegasus/neighborhood/mars/mars.h"
#include "pegasus/neighborhood/mars/robotship.h"
#include "pegasus/neighborhood/mars/spacechase3d.h"
#include "pegasus/neighborhood/mars/spacejunk.h"
namespace Pegasus {
static const TimeScale kRovingScale = kTractorBeamScale;
static const TimeValue kRovingTime = kSixSeconds * kRovingScale;
static const TimeValue kRovingSlop = kThreeSeconds * kRovingScale;
static const int kNumSpriteColumns = 15;
static const int kNumSpriteRows = 16;
static const CoordType kInitialLocationLeft = kShuttleWindowLeft - 50;
static const CoordType kInitialLocationTop = kShuttleWindowTop - 50;
static const CoordType kInitialLocationWidth = kShuttleWindowWidth + 100;
static const CoordType kInitialLocationHeight = kShuttleWindowHeight + 100;
static const CoordType kVelocityVectorLength = 100;
static const CoordType kVelocityVectorSlop = 50;
static const CoordType kRovingLeft = kShuttleWindowLeft + 20;
static const CoordType kRovingTop = kShuttleWindowTop + 20;
static const CoordType kRovingWidth = kShuttleWindowMidH - kRovingLeft;
static const CoordType kRovingHeight = kShuttleWindowMidV - kRovingTop;
RobotShip *g_robotShip = nullptr;
RobotShip::RobotShip() : _spritesMovie(kNoDisplayElement) {
g_robotShip = this;
_shipRange = Common::Rect(kShuttleWindowLeft, kShuttleWindowTop, kShuttleWindowLeft + kShuttleWindowWidth,
kShuttleWindowTop + kShuttleWindowHeight);
setScale(kRovingScale);
_currentLocation.x = 0;
_currentLocation.y = 0;
_snaring = false;
_dropJunkFuse.setFunctor(new Common::Functor0Mem<void, RobotShip>(this, &RobotShip::timeToDropJunk));
_duration = 0xFFFFFFFF;
}
RobotShip::~RobotShip() {
g_robotShip = nullptr;
}
void RobotShip::initRobotShip() {
_spritesMovie.initFromMovieFile("Images/Mars/Ship.movie", true);
_spritesMovie.setDisplayOrder(kShuttleRobotShipOrder);
_spritesMovie.moveElementTo(kPlanetStartLeft, kPlanetStartTop);
_spritesMovie.startDisplaying();
_spritesMovie.show();
Common::Rect r;
_spritesMovie.getBounds(r);
_shipWidth = r.width();
_shipHeight = r.height();
_dead = false;
}
void RobotShip::cleanUpRobotShip() {
_dropJunkFuse.stopFuse();
_spritesMovie.stopDisplaying();
_spritesMovie.releaseMovie();
}
void RobotShip::startMoving() {
if (g_vm->getRandomBit()) {
_p4.x = kInitialLocationLeft + g_vm->getRandomNumber(kInitialLocationWidth - 1);
if (g_vm->getRandomBit())
_p4.y = kInitialLocationTop;
else
_p4.y = kInitialLocationTop + kInitialLocationHeight;
} else {
_p4.y = kInitialLocationTop + g_vm->getRandomNumber(kInitialLocationHeight - 1);
if (g_vm->getRandomBit())
_p4.x = kInitialLocationLeft;
else
_p4.x = kInitialLocationLeft + kInitialLocationWidth;
}
makeVelocityVector(_p4.x, _p4.y, kShuttleWindowLeft + kShuttleWindowWidth / 2,
kShuttleWindowTop + kShuttleWindowHeight / 2, _r4);
newDestination();
setUpNextDropTime();
}
void RobotShip::killRobotShip() {
cleanUpRobotShip();
_dead = true;
}
void RobotShip::setUpNextDropTime() {
if (!isSnared()) {
_dropJunkFuse.primeFuse(kJunkDropBaseTime + g_vm->getRandomNumber(kJunkDropSlopTime));
_dropJunkFuse.lightFuse();
}
}
void RobotShip::timeToDropJunk() {
if (g_spaceJunk) {
CoordType x, y;
_spritesMovie.getCenter(x, y);
g_spaceJunk->launchJunk(g_vm->getRandomNumber(24), x, y);
}
}
void RobotShip::newDestination() {
_p1 = _p4;
_r1 = _r4;
_p4.x = kRovingLeft + g_vm->getRandomNumber(kRovingWidth - 1);
_p4.y = kRovingTop + g_vm->getRandomNumber(kRovingHeight - 1);
if (g_vm->getRandomNumber(7) < 6) {
if (!sameSign(_p4.x - kShuttleWindowMidH, kShuttleWindowMidH - _p1.x)) {
if (sign(_p4.x - kShuttleWindowMidH) > 0)
_p4.x -= kRovingWidth;
else
_p4.x += kRovingWidth;
}
}
if (g_vm->getRandomNumber(7) < 6) {
if (!sameSign(_p4.y - kShuttleWindowMidV, kShuttleWindowMidV - _p1.y)) {
if (sign(_p4.y - kShuttleWindowMidV) > 0)
_p4.y -= kRovingHeight;
else
_p4.y += kRovingHeight;
}
}
makeVelocityVector(_p4.x, _p4.y, kShuttleWindowLeft + kShuttleWindowWidth / 2,
kShuttleWindowTop + kShuttleWindowHeight / 2, _r4);
stop();
_duration = kRovingTime + g_vm->getRandomNumber(kRovingSlop - 1);
setSegment(0, _duration);
setTime(0);
start();
}
void RobotShip::moveRobotTo(CoordType x, CoordType y) {
_currentLocation.x = x;
_currentLocation.y = y;
if (_spritesMovie.isMovieValid()) {
_spritesMovie.moveElementTo(x - (_shipWidth >> 1), y - (_shipHeight >> 1));
if (x < _shipRange.left)
x = 0;
else if (x > _shipRange.right - 1)
x = _shipRange.width() - 1;
else
x -= _shipRange.left;
if (y < _shipRange.top)
y = 0;
else if (y > _shipRange.bottom - 1)
y = _shipRange.height() - 1;
else
y -= _shipRange.top;
x = kNumSpriteColumns * x / _shipRange.width();
y = kNumSpriteRows * y / _shipRange.height();
_spritesMovie.setTime(40 * (x + y * kNumSpriteColumns));
_spritesMovie.redrawMovieWorld();
}
}
bool RobotShip::pointInShuttle(Common::Point &pt) {
Common::Rect r;
_spritesMovie.getBounds(r);
int dx = r.width() / 4;
int dy = r.height() / 6;
r.left += dx;
r.right -= dx;
r.top += dy;
r.bottom -= dy;
return r.contains(pt);
}
void RobotShip::hitByEnergyBeam(Common::Point impactPoint) {
((Mars *)g_neighborhood)->decreaseRobotShuttleEnergy(1, impactPoint);
setGlowing(true);
g_vm->delayShell(1, 3);
setGlowing(false);
}
void RobotShip::hitByGravitonCannon(Common::Point impactPoint) {
GameState.setMarsHitRobotWithCannon(true);
((Mars *)g_neighborhood)->decreaseRobotShuttleEnergy(6, impactPoint);
}
void RobotShip::snareByTractorBeam() {
_dropJunkFuse.stopFuse();
stop();
Common::Point currentV;
dHermite(_p1, _p4, _r1, _r4, _lastTime, _duration, currentV);
_p1 = _currentLocation;
_r1 = currentV;
_p4.x = kShuttleWindowMidH;
_p4.y = kShuttleWindowMidV;
_r4.x = 0;
_r4.y = 0;
_duration = kTractorBeamTime;
_snaring = true;
setSegment(0, _duration);
setTime(0);
start();
}
void RobotShip::timeChanged(const TimeValue) {
Common::Point newLocation;
hermite(_p1, _p4, _r1, _r4, _lastTime, _duration, newLocation);
moveRobotTo(newLocation.x, newLocation.y);
if (_lastTime == _duration) {
if (_snaring)
stop();
else
newDestination();
}
}
void RobotShip::makeVelocityVector(CoordType x1, CoordType y1, CoordType x2, CoordType y2, Common::Point &vector) {
CoordType length = g_vm->getRandomNumber(kVelocityVectorSlop - 1) + kVelocityVectorLength;
vector.x = x2 - x1;
vector.y = y2 - y1;
float oldLength = sqrt((float)(vector.x * vector.x + vector.y * vector.y));
vector.x = (int)(vector.x * length / oldLength);
vector.y = (int)(vector.y * length / oldLength);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,83 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_ROBOTSHIP_H
#define PEGASUS_NEIGHBORHOOD_MARS_ROBOTSHIP_H
#include "pegasus/movie.h"
namespace Pegasus {
static const CoordType kShuttleMovieWidth = 114;
static const CoordType kShuttleMovieHeight = 42;
class RobotShip : IdlerTimeBase {
public:
RobotShip();
~RobotShip() override;
void initRobotShip();
void cleanUpRobotShip();
void startMoving();
void killRobotShip();
bool pointInShuttle(Common::Point&);
void hitByEnergyBeam(Common::Point impactPoint);
void hitByGravitonCannon(Common::Point impactPoint);
void getShuttleBounds(Common::Rect &r) { _spritesMovie.getBounds(r); }
void setGlowing(const bool glowing) { _spritesMovie.setGlowing(glowing); }
void snareByTractorBeam();
bool isSnared() { return _snaring && getTime() == _duration; }
bool isDead() { return _dead; }
void setUpNextDropTime();
protected:
void newDestination();
void moveRobotTo(CoordType, CoordType);
void timeToDropJunk();
void timeChanged(const TimeValue) override;
void makeVelocityVector(CoordType, CoordType, CoordType, CoordType, Common::Point &);
GlowingMovie _spritesMovie;
Common::Rect _shipRange;
int _shipWidth, _shipHeight;
Common::Point _p1, _p4, _r1, _r4, _currentLocation;
FuseFunction _dropJunkFuse;
TimeValue _duration;
bool _snaring, _dead;
};
extern RobotShip *g_robotShip;
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,115 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/mars/shuttleenergymeter.h"
namespace Pegasus {
ShuttleEnergyMeter::ShuttleEnergyMeter() : FaderAnimation(kNoDisplayElement) {
setBounds(kShuttleEnergyLeft, kShuttleEnergyTop, kShuttleEnergyLeft + kShuttleEnergyWidth,
kShuttleEnergyTop + kShuttleEnergyHeight);
setDisplayOrder(kShuttleStatusOrder);
setFaderValue(0);
}
void ShuttleEnergyMeter::initShuttleEnergyMeter() {
_meterImage.getImageFromPICTFile("Images/Mars/Shuttle Energy.pict");
_lowWarning.getImageFromPICTFile("Images/Mars/Shuttle Low Energy.pict");
startDisplaying();
show();
}
void ShuttleEnergyMeter::disposeShuttleEnergyMeter() {
stopFader();
hide();
stopDisplaying();
_meterImage.deallocateSurface();
_lowWarning.deallocateSurface();
}
void ShuttleEnergyMeter::draw(const Common::Rect &) {
int32 currentValue = getFaderValue();
Common::Rect r1, r2, bounds;
getBounds(bounds);
if (currentValue < kLowShuttleEnergy) {
_lowWarning.getSurfaceBounds(r1);
r2 = r1;
r2.moveTo(bounds.left, bounds.top);
_lowWarning.copyToCurrentPort(r1, r2);
}
_meterImage.getSurfaceBounds(r1);
r1.right = r1.left + r1.width() * currentValue / kFullShuttleEnergy;
r2 = r1;
r2.moveTo(bounds.left + 102, bounds.top + 6);
_meterImage.copyToCurrentPort(r1, r2);
}
void ShuttleEnergyMeter::powerUpMeter() {
FaderMoveSpec moveSpec;
moveSpec.makeTwoKnotFaderSpec(kThirtyTicksPerSecond, 0, 0, 45, kFullShuttleEnergy);
startFader(moveSpec);
}
void ShuttleEnergyMeter::setEnergyValue(const int32 value) {
stopFader();
FaderMoveSpec moveSpec;
moveSpec.makeTwoKnotFaderSpec(kFifteenTicksPerSecond, value * 3, value, kFullShuttleEnergy * 3, kFullShuttleEnergy);
startFader(moveSpec);
}
void ShuttleEnergyMeter::drainForTractorBeam() {
stopFader();
TimeValue startTime = 0, stopTime;
int32 startValue = getFaderValue(), stopValue;
if (startValue < kTractorBeamEnergy) {
stopTime = startValue * kTractorBeamTime / kTractorBeamEnergy;
stopValue = 0;
} else {
stopTime = kTractorBeamTime;
stopValue = startValue - kTractorBeamEnergy;
}
FaderMoveSpec moveSpec;
moveSpec.makeTwoKnotFaderSpec(kTractorBeamScale, startTime, startValue, stopTime, stopValue);
startFader(moveSpec);
}
int32 ShuttleEnergyMeter::getEnergyValue() const {
return getFaderValue();
}
void ShuttleEnergyMeter::dropEnergyValue(const int32 delta) {
setEnergyValue(getFaderValue() - delta);
}
bool ShuttleEnergyMeter::enoughEnergyForTractorBeam() const {
return getEnergyValue() >= kTractorBeamEnergy;
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,72 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEENERGYMETER_H
#define PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEENERGYMETER_H
#include "pegasus/fader.h"
#include "pegasus/surface.h"
namespace Pegasus {
static const int32 kFullShuttleEnergy = 100;
// Low is 20 percent
static const int32 kLowShuttleEnergy = kFullShuttleEnergy * 20 / 100;
static const int32 kMinDampingEnergy = 15;
static const int32 kMinGravitonEnergy = 63;
static const TimeScale kTractorBeamScale = kFifteenTicksPerSecond;
static const TimeValue kTractorBeamTime = kFiveSeconds * kTractorBeamScale;
static const int32 kTractorBeamEnergy = kLowShuttleEnergy;
class ShuttleEnergyMeter : public FaderAnimation {
public:
ShuttleEnergyMeter();
~ShuttleEnergyMeter() override {}
void initShuttleEnergyMeter();
void disposeShuttleEnergyMeter();
void powerUpMeter();
void setEnergyValue(const int32);
int32 getEnergyValue() const;
void dropEnergyValue(const int32);
void drainForTractorBeam();
bool enoughEnergyForTractorBeam() const;
void draw(const Common::Rect &) override;
protected:
Surface _meterImage;
Surface _lowWarning;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,247 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/mars/robotship.h"
#include "pegasus/neighborhood/mars/shuttlehud.h"
namespace Pegasus {
enum {
kHUDTargetGridLeft = kShuttleWindowLeft + 16,
kHUDTargetGridTop = kShuttleWindowTop + 8,
kHUDTargetGridWidth = 328,
kHUDTargetGridHeight = 206,
kHUDRS232Left = kHUDTargetGridLeft + 264,
kHUDRS232Top = kHUDTargetGridTop + 2,
kHUDLockLeft = kShuttleWindowLeft + 101,
kHUDLockTop = kShuttleWindowTop + 49,
kHUDLockWidth = 145,
kHUDLockHeight = 124,
kTractorLockWidth = 50,
kTractorLockHeight = 30,
kTractorLockLeft = kShuttleWindowMidH - kTractorLockWidth / 2,
kTractorLockTop = kShuttleWindowMidV - kTractorLockHeight / 2,
kTractorLockRight = kTractorLockLeft + kTractorLockWidth,
kTractorLockBottom = kTractorLockTop + kTractorLockHeight
};
static const uint16 s_RS232Data[] = {
0xF0E1, 0xCE70,
0xF9E1, 0xEF78,
0x4900, 0x2108,
0x79C0, 0xE738,
0x70E1, 0xC770,
0x5821, 0x0140,
0x4DE1, 0xEF78,
0x45C1, 0xEE78
};
static const uint16 s_lockData[] = {
0xE007, 0xFE1F, 0xF8E0, 0x7000,
0xE00F, 0xFF3F, 0xFCE0, 0xE000,
0xE00E, 0x0738, 0x1CE1, 0xC000,
0xE00E, 0x0738, 0x00FF, 0x8000,
0xE00E, 0x0738, 0x00FF, 0x0000,
0xE00E, 0x0738, 0x00E3, 0x8000,
0xE00E, 0x0738, 0x1CE1, 0xC000,
0xFFCF, 0xFF3F, 0xFCE0, 0xE000,
0xFFC7, 0xFE1F, 0xF8E0, 0x7000
};
#define drawHUDLockLine(x1, y1, x2, y2, penX, penY, color) \
screen->drawThickLine((x1) + kHUDLockLeft, (y1) + kHUDLockTop, \
(x2) + kHUDLockLeft, (y2) + kHUDLockTop, penX, penY, color)
#define drawHUDLockArrows(offset, color) \
drawHUDLockLine(63, 0 + (offset), 68, 5 + (offset), 1, 3, color); \
drawHUDLockLine(71, 8 + (offset), 77, 14 + (offset), 1, 3, color); \
drawHUDLockLine(78, 14 + (offset), 84, 8 + (offset), 1, 3, color); \
drawHUDLockLine(87, 5 + (offset), 92, 0 + (offset), 1, 3, color); \
drawHUDLockLine(63, 121 - (offset), 68, 116 - (offset), 1, 3, color); \
drawHUDLockLine(71, 113 - (offset), 77, 107 - (offset), 1, 3, color); \
drawHUDLockLine(78, 107 - (offset), 84, 113 - (offset), 1, 3, color); \
drawHUDLockLine(87, 116 - (offset), 92, 121 - (offset), 1, 3, color); \
\
drawHUDLockLine(13 + (offset), 47, 18 + (offset), 52, 3, 1, color); \
drawHUDLockLine(21 + (offset), 55, 27 + (offset), 61, 3, 1, color); \
drawHUDLockLine(27 + (offset), 62, 21 + (offset), 68, 3, 1, color); \
drawHUDLockLine(18 + (offset), 71, 13 + (offset), 76, 3, 1, color); \
drawHUDLockLine(142 - (offset), 47, 137 - (offset), 52, 3, 1, color); \
drawHUDLockLine(134 - (offset), 55, 128 - (offset), 61, 3, 1, color); \
drawHUDLockLine(128 - (offset), 62, 134 - (offset), 68, 3, 1, color); \
drawHUDLockLine(137 - (offset), 71, 142 - (offset), 76, 3, 1, color)
ShuttleHUD::ShuttleHUD() : DisplayElement(kNoDisplayElement) {
_lightGreen = g_system->getScreenFormat().RGBToColor(0, 204, 0);
_gridDarkGreen = g_system->getScreenFormat().RGBToColor(0, 85, 0);
_lockDarkGreen1 = g_system->getScreenFormat().RGBToColor(0, 68, 0);
_lockDarkGreen2 = g_system->getScreenFormat().RGBToColor(0, 65, 0);
_targetLocked = false;
setBounds(kShuttleWindowLeft, kShuttleWindowTop, kShuttleWindowLeft + kShuttleWindowWidth,
kShuttleWindowTop + kShuttleWindowHeight);
setDisplayOrder(kShuttleHUDOrder);
}
void ShuttleHUD::initShuttleHUD() {
startDisplaying();
startIdling();
}
void ShuttleHUD::cleanUpShuttleHUD() {
stopIdling();
stopDisplaying();
}
void ShuttleHUD::showTargetGrid() {
show();
}
void ShuttleHUD::hideTargetGrid() {
hide();
unlockOnTarget();
}
void ShuttleHUD::useIdleTime() {
if (isVisible()) {
Common::Rect r;
g_robotShip->getShuttleBounds(r);
if (r.left < kTractorLockRight && r.right > kTractorLockLeft && r.top < kTractorLockBottom && r.bottom > kTractorLockTop)
lockOnTarget();
else
unlockOnTarget();
}
}
void ShuttleHUD::lockOnTarget() {
if (!_targetLocked) {
_targetLocked = true;
triggerRedraw();
}
}
void ShuttleHUD::unlockOnTarget() {
if (_targetLocked) {
_targetLocked = false;
triggerRedraw();
}
}
void ShuttleHUD::draw(const Common::Rect &) {
Graphics::Surface *screen = g_vm->_gfx->getWorkArea();
for (int y = 0; y < 35; y++) {
Common::Rect r;
if (y & 1) {
if (y == 17) {
r = Common::Rect(0, 0, 4, 2);
r.moveTo(kHUDTargetGridLeft + 8, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 12, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r = Common::Rect(0, 0, 6, 2);
r.moveTo(kHUDTargetGridLeft + 2, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _lightGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 8, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _lightGreen);
r = Common::Rect(0, 0, 23, 2);
r.moveTo(kHUDTargetGridLeft + 12, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _lightGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 35, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _lightGreen);
} else if (y == 1 || y == 15 || y == 19 || y == 33) {
r = Common::Rect(0, 0, 4, 2);
r.moveTo(kHUDTargetGridLeft + 2, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 6, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r = Common::Rect(0, 0, 15, 2);
r.moveTo(kHUDTargetGridLeft + 8, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 23, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
} else {
r = Common::Rect(0, 0, 4, 2);
r.moveTo(kHUDTargetGridLeft + 2, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 6, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r = Common::Rect(0, 0, 10, 2);
r.moveTo(kHUDTargetGridLeft + 8, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 18, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
}
} else {
r = Common::Rect(0, 0, 2, 2);
r.moveTo(kHUDTargetGridLeft, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 2, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r = Common::Rect(0, 0, 4, 2);
r.moveTo(kHUDTargetGridLeft + 8, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 12, y * 6 + kHUDTargetGridTop);
screen->fillRect(r, _gridDarkGreen);
}
}
drawOneBitImageOr(screen, s_RS232Data, 2, Common::Rect(kHUDRS232Left, kHUDRS232Top,
kHUDRS232Left + 29, kHUDRS232Top + 8), _gridDarkGreen);
if (_targetLocked) {
drawHUDLockArrows(0, _lockDarkGreen2);
drawHUDLockArrows(12, _lockDarkGreen1);
drawHUDLockArrows(24, _lightGreen);
drawOneBitImageOr(screen, s_lockData, 4, Common::Rect(kHUDLockLeft, kHUDLockTop + 115,
kHUDLockLeft + 52, kHUDLockTop + 115 + 9), _lightGreen);
}
}
void ShuttleHUD::drawOneBitImageOr(Graphics::Surface *screen, const uint16 *data, int pitch, const Common::Rect &bounds, uint32 color) {
for (int y = 0; y < bounds.height(); y++) {
for (int x = 0; x < bounds.width(); x++) {
if ((data[y * pitch + x / 16] & (1 << (15 - (x % 16)))) != 0) {
if (screen->format.bytesPerPixel == 2)
WRITE_UINT16((byte *)screen->getBasePtr(x + bounds.left, y + bounds.top), color);
else
WRITE_UINT32((byte *)screen->getBasePtr(x + bounds.left, y + bounds.top), color);
}
}
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,59 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEHUD_H
#define PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEHUD_H
#include "pegasus/elements.h"
#include "pegasus/timers.h"
namespace Pegasus {
class ShuttleHUD : public DisplayElement, public Idler {
public:
ShuttleHUD();
void showTargetGrid();
void hideTargetGrid();
void initShuttleHUD();
void cleanUpShuttleHUD();
bool isTargetLocked() { return _targetLocked; }
void draw(const Common::Rect &) override;
protected:
void useIdleTime() override;
void lockOnTarget();
void unlockOnTarget();
void drawOneBitImageOr(Graphics::Surface *, const uint16 *, int, const Common::Rect &, uint32);
bool _targetLocked;
uint32 _lightGreen, _gridDarkGreen, _lockDarkGreen1, _lockDarkGreen2;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,128 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/mars/robotship.h"
#include "pegasus/neighborhood/mars/shuttleweapon.h"
#include "pegasus/neighborhood/mars/spacejunk.h"
namespace Pegasus {
ShuttleWeapon::ShuttleWeapon() : IdlerAnimation(kNoDisplayElement) {
setScale(kShuttleWeaponScale);
_weaponDuration = kShuttleWeaponScale * 2;
setSegment(0, _weaponDuration);
setBounds(kShuttleWindowLeft, kShuttleWindowTop, kShuttleWindowLeft + kShuttleWindowWidth,
kShuttleWindowTop + kShuttleWindowHeight);
setDisplayOrder(kShuttleWeaponFrontOrder);
}
void ShuttleWeapon::initShuttleWeapon() {
startDisplaying();
}
void ShuttleWeapon::cleanUpShuttleWeapon() {
stop();
hide();
stopDisplaying();
}
bool ShuttleWeapon::canFireWeapon() {
return !isRunning();
}
void ShuttleWeapon::fireWeapon(const CoordType hStop, const CoordType vStop) {
if (!isRunning()) {
stop();
setTime(0);
show();
Common::Point pt2D(hStop, vStop);
project2DTo3D(pt2D, kShuttleDistance, _weaponTarget);
_weaponTime = 0;
setDisplayOrder(kShuttleWeaponFrontOrder);
start();
}
}
void ShuttleWeapon::updateWeaponPosition() {
_weaponTime = (float)_lastTime / _weaponDuration;
linearInterp(_weaponOrigin, _weaponTarget, _weaponTime, _weaponLocation);
if (_weaponTime == 1.0) {
stop();
hide();
} else {
triggerRedraw();
}
}
void ShuttleWeapon::timeChanged(const TimeValue) {
updateWeaponPosition();
bool hit = false;
Common::Point impactPoint;
if (g_spaceJunk->isJunkFlying()) {
hit = collisionWithJunk(impactPoint);
if (hit) {
stop();
hide();
hitJunk(impactPoint);
}
}
if (!hit && _weaponTime == 1.0 && collisionWithShuttle(impactPoint))
hitShuttle(impactPoint);
}
bool ShuttleWeapon::collisionWithJunk(Common::Point &impactPoint) {
if (getDisplayOrder() == kShuttleWeaponFrontOrder) {
Point3D junkPosition;
g_spaceJunk->getJunkPosition(junkPosition);
if (junkPosition.z < _weaponLocation.z) {
setDisplayOrder(kShuttleWeaponBackOrder);
project3DTo2D(_weaponLocation, impactPoint);
return g_spaceJunk->pointInJunk(impactPoint);
}
}
return false;
}
bool ShuttleWeapon::collisionWithShuttle(Common::Point &impactPoint) {
project3DTo2D(_weaponLocation, impactPoint);
return g_robotShip->pointInShuttle(impactPoint);
}
void ShuttleWeapon::hitJunk(Common::Point impactPoint) {
g_spaceJunk->hitByEnergyBeam(impactPoint);
}
void ShuttleWeapon::hitShuttle(Common::Point impactPoint) {
g_robotShip->hitByEnergyBeam(impactPoint);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,67 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEWEAPON_H
#define PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEWEAPON_H
#include "pegasus/elements.h"
#include "pegasus/neighborhood/mars/spacechase3d.h"
namespace Pegasus {
// Can fire multiple times?
// For now, no...
// clone2727 adds: And now forever
static const TimeScale kShuttleWeaponScale = kFifteenTicksPerSecond;
class ShuttleWeapon : public IdlerAnimation {
public:
ShuttleWeapon();
~ShuttleWeapon() override {}
virtual void initShuttleWeapon();
virtual void cleanUpShuttleWeapon();
virtual void fireWeapon(const CoordType, const CoordType);
bool canFireWeapon();
protected:
void timeChanged(const TimeValue) override;
virtual void updateWeaponPosition();
virtual bool collisionWithJunk(Common::Point &impactPoint);
bool collisionWithShuttle(Common::Point &impactPoint);
virtual void hitJunk(Common::Point impactPoint);
virtual void hitShuttle(Common::Point impactPoint);
Point3D _weaponOrigin, _weaponTarget;
Point3D _weaponLocation;
float _weaponTime;
TimeValue _weaponDuration;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,105 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/neighborhood/mars/spacechase3d.h"
namespace Pegasus {
void project3DTo2D(const Point3D &pt3D, Common::Point &pt2D) {
pt2D.x = (int)convertSpaceXToScreenH(pt3D.x, pt3D.z);
pt2D.y = (int)convertSpaceYToScreenV(pt3D.y, pt3D.z);
}
void project2DTo3D(const Common::Point &pt2D, const float screenDistance, Point3D &pt3D) {
pt3D.x = convertScreenHToSpaceX(pt2D.x, screenDistance);
pt3D.y = convertScreenVToSpaceY(pt2D.y, screenDistance);
pt3D.z = screenDistance;
}
void linearInterp(const Point3D &pt1, const Point3D &pt2, const float t, Point3D &pt3) {
pt3.x = pt1.x + (pt2.x - pt1.x) * t;
pt3.y = pt1.y + (pt2.y - pt1.y) * t;
pt3.z = pt1.z + (pt2.z - pt1.z) * t;
}
void linearInterp(const Point3D &pt1, const float x2, const float y2, const float z2, const float t, Point3D &pt3) {
pt3.x = pt1.x + (x2 - pt1.x) * t;
pt3.y = pt1.y + (y2 - pt1.y) * t;
pt3.z = pt1.z + (z2 - pt1.z) * t;
}
void linearInterp(const float x1, const float y1, const float z1, const Point3D &pt2, const float t, Point3D &pt3) {
pt3.x = x1 + (pt2.x - x1) * t;
pt3.y = y1 + (pt2.y - y1) * t;
pt3.z = z1 + (pt2.z - z1) * t;
}
void linearInterp(const float x1, const float y1, const float z1, const float x2, const float y2, const float z2,
const float t, Point3D &pt3) {
pt3.x = x1 + (x2 - x1) * t;
pt3.y = y1 + (y2 - y1) * t;
pt3.z = z1 + (z2 - z1) * t;
}
void linearInterp(const Common::Point &pt1, const Common::Point &pt2, const float t, Common::Point &pt3) {
pt3.x = (int)(pt1.x + (pt2.x - pt1.x) * t);
pt3.y = (int)(pt1.y + (pt2.y - pt1.y) * t);
}
void linearInterp(const Common::Point &pt1, const float h2, const float v2, const float t, Common::Point &pt3) {
pt3.x = (int)(pt1.x + (h2 - pt1.x) * t);
pt3.y = (int)(pt1.y + (v2 - pt1.y) * t);
}
void linearInterp(const float h1, const float v1, const Common::Point &pt2, const float t, Common::Point &pt3) {
pt3.x = (int)(h1 + (pt2.x - h1) * t);
pt3.y = (int)(v1 + (pt2.y - v1) * t);
}
void linearInterp(const float h1, const float v1, const float h2, const float v2, const float t, Common::Point &pt3) {
pt3.x = (int)(h1 + (h2 - h1) * t);
pt3.y = (int)(v1 + (v2 - v1) * t);
}
float linearInterp(const float arg1, const float arg2, const float t) {
return arg1 + (arg2 - arg1) * t;
}
bool isNegative(int a) {
return a < 0;
}
bool isPositive(int a) {
return a > 0;
}
int sign(int a) {
return isNegative(a) ? -1 : isPositive(a) ? 1 : 0;
}
bool sameSign(int a, int b) {
return sign(a) == sign(b);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,90 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_SPACECHASE3D_H
#define PEGASUS_NEIGHBORHOOD_MARS_SPACECHASE3D_H
#include "pegasus/neighborhood/mars/constants.h"
namespace Pegasus {
// This is approximately right for a field of view of 72 degrees
// (Should be set to the tangent of FOV).
//static const float kTangentFOV = 0.76254;
static const float kTangentFOV = 1.0;
// Define these as macros and they can be used to define constants...
#define convertSpaceXToScreenH(x, z) \
((x) / (z) * (kScreenWidth / (2 * kTangentFOV)) + kShuttleWindowMidH)
#define convertSpaceYToScreenV(y, z) \
(kShuttleWindowMidV - (y) / (z) * (kScreenWidth / (2 * kTangentFOV)))
#define convertScreenHToSpaceX(x, d) \
(((2.0F * kTangentFOV) / kScreenWidth) * ((float)(x) - kShuttleWindowMidH) * (d))
#define convertScreenVToSpaceY(y, d) \
(((2.0F * kTangentFOV) / kScreenWidth) * ((float)kShuttleWindowMidV - (y)) * (d))
struct Point3D {
float x, y, z;
Point3D() : x(0), y(0), z(0) {}
Point3D(float x1, float y1, float z1) : x(x1), y(y1), z(z1) {}
bool operator==(const Point3D &p) const { return x == p.x && y == p.y && z == p.z; }
bool operator!=(const Point3D &p) const { return x != p.x || y != p.y || z != p.z; }
void translate(float dx, float dy, float dz) {
x += dx;
y += dy;
z += dz;
}
};
static const int kScreenWidth = kShuttleWindowWidth;
bool isNegative(int a);
bool isPositive(int a);
int sign(int a);
bool sameSign(int a, int b);
void project3DTo2D(const Point3D &pt3D, Common::Point &pt2D);
void project2DTo3D(const Common::Point &pt2D, const float screenDistance, Point3D &pt3D);
void linearInterp(const Point3D &pt1, const Point3D &pt2, const float t, Point3D &pt3);
void linearInterp(const Point3D &pt1, const float x2, const float y2, const float z2, const float t, Point3D &pt3);
void linearInterp(const float x1, const float y1, const float z1, const Point3D &pt2, const float t, Point3D &pt3);
void linearInterp(const float x1, const float y1, const float z1, const float x2,
const float y2, const float z2, const float t, Point3D &pt3);
void linearInterp(const Common::Point &pt1, const Common::Point &pt2, const float t, Common::Point &pt3);
void linearInterp(const Common::Point &pt1, const float h2, const float v2, const float t, Common::Point &pt3);
void linearInterp(const float h1, const float v1, const Common::Point &pt2, const float t, Common::Point &pt3);
void linearInterp(const float h1, const float v1, const float h2, const float v2, const float t, Common::Point &pt3);
float linearInterp(const float arg1, const float arg2, const float t);
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,211 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/mars/mars.h"
#include "pegasus/neighborhood/mars/spacejunk.h"
namespace Pegasus {
static const CoordType kMaxBounceSize = 90;
static const CoordType kBounceTargetHRange = 640 - kMaxBounceSize - 2;
static const CoordType kBounceTargetVRange = 480 - kMaxBounceSize - 2;
static const float kJunkXTarget = 0;
static const float kJunkYTarget = 0;
static const float kJunkZTarget = kJunkMinDistance;
SpaceJunk *g_spaceJunk = nullptr;
SpaceJunk::SpaceJunk(const DisplayElementID id) : ScalingMovie(id) {
_timer.setScale(kJunkTimeScale);
_bouncing = false;
g_spaceJunk = this;
}
SpaceJunk::~SpaceJunk() {
g_spaceJunk = nullptr;
}
void SpaceJunk::launchJunk(int16 whichJunk, CoordType xOrigin, CoordType yOrigin) {
_bouncing = false;
TimeValue startTime = whichJunk * 16 * 40;
TimeValue stopTime = startTime + 16 * 40;
_launchPoint = Point3D(convertScreenHToSpaceX(xOrigin, kJunkMaxDistance),
convertScreenVToSpaceY(yOrigin, kJunkMaxDistance), kJunkMaxDistance);
startIdling();
stop();
setFlags(0);
setSegment(startTime, stopTime);
setFlags(kLoopTimeBase);
setTime(startTime);
start();
show();
_timer.stop();
_timer.setSegment(0, kJunkTravelTime);
_timer.setTime(0);
// Force it to set up correctly from the get-go
useIdleTime();
_timer.start();
}
void SpaceJunk::setCenter(const CoordType centerX, const CoordType centerY) {
_center.x = centerX;
_center.y = centerY;
Common::Rect r;
getBounds(r);
r.moveTo(CLIP<int>(centerX - (r.width() >> 1), 0, 640 - r.width()), CLIP<int>(centerY - (r.height() >> 1), 0, 480 - r.height()));
setBounds(r);
}
void SpaceJunk::setScaleSize(const CoordType size) {
Common::Rect r;
r.left = _center.x - (size >> 1);
r.top = _center.y - (size >> 1);
r.right = r.left + size;
r.bottom = r.top + size;
setBounds(r);
}
void SpaceJunk::useIdleTime() {
if (_bouncing) {
TimeValue time = _timer.getTime();
Common::Point pt;
pt.x = linearInterp(0, _bounceTime, time, _bounceStart.x, _bounceStop.x);
pt.y = linearInterp(0, _bounceTime, time, _bounceStart.y, _bounceStop.y);
CoordType size = linearInterp(0, _bounceTime, time, _bounceSizeStart, _bounceSizeStop);
setCenter(pt.x, pt.y);
setScaleSize(size);
if (time == _bounceTime) {
stop();
stopIdling();
hide();
((Mars *)g_neighborhood)->setUpNextDropTime();
}
} else {
float t = (float)_timer.getTime() / kJunkTravelTime;
linearInterp(_launchPoint, kJunkXTarget, kJunkYTarget, kJunkZTarget, t, _junkPosition);
Common::Point pt2D;
project3DTo2D(_junkPosition, pt2D);
setCenter(pt2D.x, pt2D.y);
setScaleSize((int)(convertSpaceYToScreenV(_junkPosition.y - kJunkSize / 2, _junkPosition.z) -
convertSpaceYToScreenV(_junkPosition.y + kJunkSize / 2, _junkPosition.z)));
if (t == 1.0) {
rebound(kCollisionReboundTime);
((Mars *)g_neighborhood)->hitByJunk();
}
}
}
bool SpaceJunk::pointInJunk(const Common::Point &pt) {
Common::Rect r;
getBounds(r);
int dx = r.width() / 4;
int dy = r.height() / 4;
r.left += dx;
r.right -= dx;
r.top += dy;
r.top -= dy;
return r.contains(pt);
}
void SpaceJunk::rebound(const TimeValue reboundTime) {
Common::Rect bounds;
getBounds(bounds);
_bounceStart.x = (bounds.left + bounds.right) >> 1;
_bounceStart.y = (bounds.top + bounds.bottom) >> 1;
switch (g_vm->getRandomNumber(3)) {
case 0:
_bounceStop.x = kMaxBounceSize / 2 + 1 + g_vm->getRandomNumber(kBounceTargetHRange - 1);
_bounceStop.y = kMaxBounceSize / 2 + 1;
break;
case 1:
_bounceStop.x = kMaxBounceSize / 2 + 1 + g_vm->getRandomNumber(kBounceTargetHRange - 1);
_bounceStop.y = 480 - kMaxBounceSize / 2 + 1;
break;
case 2:
_bounceStop.x = kMaxBounceSize / 2 + 1;
_bounceStop.y = kMaxBounceSize / 2 + 1 + g_vm->getRandomNumber(kBounceTargetVRange - 1);
break;
case 3:
_bounceStop.x = 640 - kMaxBounceSize / 2 + 1;
_bounceStop.y = kMaxBounceSize / 2 + 1 + g_vm->getRandomNumber(kBounceTargetVRange - 1);
break;
default:
break;
}
_bounceSizeStart = bounds.width();
_bounceSizeStop = MIN(_bounceSizeStart, kMaxBounceSize);
_timer.stop();
_timer.setSegment(0, reboundTime);
_bounceTime = reboundTime;
_timer.setTime(0);
_timer.start();
_bouncing = true;
}
void SpaceJunk::hitByEnergyBeam(Common::Point) {
rebound(kWeaponReboundTime);
setGlowing(true);
g_vm->delayShell(1, 3);
setGlowing(false);
}
void SpaceJunk::hitByGravitonCannon(Common::Point impactPoint) {
stop();
stopIdling();
hide();
Common::Rect r;
getBounds(r);
r = Common::Rect::center(impactPoint.x, impactPoint.y, r.width(), r.height());
((Mars *)g_neighborhood)->showBigExplosion(r, kShuttleJunkOrder);
((Mars *)g_neighborhood)->setUpNextDropTime();
}
void SpaceJunk::getJunkPosition(Point3D &position) {
position = _junkPosition;
}
bool SpaceJunk::isJunkFlying() {
return isIdling();
}
} // End of namespace Pegasus

View File

@@ -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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_SPACEJUNK_H
#define PEGASUS_NEIGHBORHOOD_MARS_SPACEJUNK_H
#include "pegasus/movie.h"
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/mars/spacechase3d.h"
namespace Pegasus {
static const CoordType kJunkMaxScreenSize = 250;
static const float kJunkSize = convertScreenVToSpaceY(kShuttleWindowMidV - kJunkMaxScreenSize / 2, kJunkMinDistance) -
convertScreenVToSpaceY(kShuttleWindowMidV + kJunkMaxScreenSize / 2, kJunkMinDistance);
class SpaceJunk : public ScalingMovie, public Idler {
public:
SpaceJunk(const DisplayElementID);
~SpaceJunk() override;
void setCenter(const CoordType, const CoordType);
void setScaleSize(const CoordType);
void useIdleTime() override;
void launchJunk(int16, CoordType, CoordType);
void getJunkPosition(Point3D &);
bool isJunkFlying();
bool pointInJunk(const Common::Point &);
void hitByEnergyBeam(Common::Point impactPoint);
void hitByGravitonCannon(Common::Point impactPoint);
bool junkFlying() { return _timer.isRunning(); }
protected:
void rebound(const TimeValue);
TimeBase _timer;
Point3D _launchPoint, _junkPosition;
Common::Point _center;
bool _bouncing;
Common::Point _bounceStart, _bounceStop;
CoordType _bounceSizeStart, _bounceSizeStop;
TimeValue _bounceTime;
};
extern SpaceJunk *g_spaceJunk;
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,138 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/mars/tractorbeam.h"
namespace Pegasus {
TractorBeam::TractorBeam() : DisplayElement(kNoDisplayElement) {
setBounds(kShuttleTractorLeft, kShuttleTractorTop, kShuttleTractorLeft + kShuttleTractorWidth,
kShuttleTractorTop + kShuttleTractorHeight);
setDisplayOrder(kShuttleTractorBeamOrder);
}
static const int kHalfWidth = kShuttleTractorWidth >> 1;
static const int kHalfHeight = kShuttleTractorHeight >> 1;
static const int kW3Vert = kHalfHeight * kHalfHeight * kHalfHeight;
static const int kW3Div2Vert = kW3Vert >> 1;
static const int kW3Horiz = kHalfWidth * kHalfWidth * kHalfWidth;
static const int kW3Div2Horiz = kW3Horiz >> 1;
static const int kMaxLevel = 50;
static const int kAVert = -2 * kMaxLevel;
static const int kBVert = 3 * kMaxLevel * kHalfHeight;
#define READ_PIXEL(ptr) \
if (screen->format.bytesPerPixel == 2) \
color = READ_UINT16(ptr); \
else \
color = READ_UINT32(ptr); \
screen->format.colorToRGB(color, r, g, b)
#define WRITE_PIXEL(ptr) \
color = screen->format.RGBToColor(r, g, b); \
if (screen->format.bytesPerPixel == 2) \
WRITE_UINT16(ptr, color); \
else \
WRITE_UINT32(ptr, color)
#define DO_BLEND(ptr) \
READ_PIXEL(ptr); \
g += (((0xff - g) * blendHoriz) >> 8); \
b += (((0xff - b) * blendHoriz) >> 8); \
WRITE_PIXEL(ptr)
void TractorBeam::draw(const Common::Rect &) {
Graphics::Surface *screen = g_vm->_gfx->getWorkArea();
// Set up vertical DDA.
int blendVert = 0;
int dVert = 0;
int d1Vert = kAVert + kBVert;
int d2Vert = 6 * kAVert + 2 * kBVert;
int d3Vert = 6 * kAVert;
byte *rowPtrTop = (byte *)screen->getBasePtr(_bounds.left, _bounds.top);
byte *rowPtrBottom = (byte *)screen->getBasePtr(_bounds.left, _bounds.top + ((kHalfHeight << 1) - 1));
for (int y = kHalfHeight; y > 0; y--) {
// Set up horizontal DDA
int A = -2 * blendVert;
int B = 3 * blendVert * kHalfWidth;
int blendHoriz = 0;
int dHoriz = 0;
int d1Horiz = A + B;
int d2Horiz = 6 * A + 2 * B;
int d3Horiz = 6 * A;
byte *pTopLeft = rowPtrTop;
byte *pTopRight = rowPtrTop + (kHalfWidth * 2 - 1) * screen->format.bytesPerPixel;
byte *pBottomLeft = rowPtrBottom;
byte *pBottomRight = rowPtrBottom + (kHalfWidth * 2 - 1) * screen->format.bytesPerPixel;
for (int x = kHalfWidth; x > 0; x--) {
byte r, g, b;
uint32 color;
DO_BLEND(pTopLeft);
DO_BLEND(pTopRight);
DO_BLEND(pBottomLeft);
DO_BLEND(pBottomRight);
pTopLeft += screen->format.bytesPerPixel;
pBottomLeft += screen->format.bytesPerPixel;
pTopRight -= screen->format.bytesPerPixel;
pBottomRight -= screen->format.bytesPerPixel;
while (dHoriz > kW3Div2Horiz) {
blendHoriz++;
dHoriz -= kW3Horiz;
}
dHoriz += d1Horiz;
d1Horiz += d2Horiz;
d2Horiz += d3Horiz;
}
rowPtrTop += screen->pitch;
rowPtrBottom -= screen->pitch;
while (dVert > kW3Div2Vert) {
blendVert++;
dVert -= kW3Vert;
}
dVert += d1Vert;
d1Vert += d2Vert;
d2Vert += d3Vert;
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,42 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_TRACTORBEAM_H
#define PEGASUS_NEIGHBORHOOD_MARS_TRACTORBEAM_H
#include "pegasus/elements.h"
namespace Pegasus {
class TractorBeam : public DisplayElement {
public:
TractorBeam();
~TractorBeam() override {}
void draw(const Common::Rect &) override;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,372 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-2013 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/mars/tunnelpod.h"
#include "pegasus/neighborhood/mars/mars.h"
namespace Pegasus {
// Segment start and end points.
static const TimeValue kLaunchStart = 315754;
static const TimeValue kLaunchEnd = 319392;
static const TimeValue kBranch1MainStart = 0;
static const TimeValue kBranch1MainEnd = 3600;
static const TimeValue kBranch2MainStart = kBranch1MainEnd;
static const TimeValue kBranch2MainEnd = 13200;
static const TimeValue kBranch3MainStart = kBranch2MainEnd;
static const TimeValue kBranch3MainEnd = 20400;
static const TimeValue kFinishMainStart = kBranch3MainEnd;
static const TimeValue kFinishMainEnd = 30640;
static const TimeValue kBranch2AltStart = 0;
static const TimeValue kBranch2AltEnd = 13200;
static const TimeValue kBranch3AltStart = kBranch2AltEnd;
static const TimeValue kBranch3AltEnd = 22800;
static const TimeValue kFinishAltStart = kBranch3AltEnd;
static const TimeValue kFinishAltEnd = 33640;
// Tunnel state.
enum {
kTunnelLaunch,
kTunnelBranch1Left,
kTunnelBranch2Left,
kTunnelBranch2Right,
kTunnelBranch3Left,
kTunnelBranch3Right,
kTunnelFinish
};
TunnelPod::TunnelPod(Neighborhood *handler) : ChaseInteraction(kMarsTunnelPodInteractionID, handler,
kMarsTunnelPodNotificationID, g_vm), _tunnelMainMovie(kNoDisplayElement),
_tunnelAltMovie(kNoDisplayElement), _deathMovie(kNoDisplayElement) {
_currentMovie = nullptr;
_currentCallBack = nullptr;
}
void TunnelPod::setSoundFXLevel(const uint16 fxLevel) {
_tunnelMainMovie.setVolume(fxLevel);
_tunnelAltMovie.setVolume(fxLevel);
_deathMovie.setVolume(fxLevel);
}
void TunnelPod::openInteraction() {
((Mars *)_owner)->_navMovie.stop();
_tunnelCallBack.setNotification(&_chaseNotification);
_tunnelCallBack.initCallBack(&((Mars *)_owner)->_navMovie, kCallBackAtExtremes);
_tunnelCallBack.setCallBackFlag(kChaseEnteredBranchZone);
_tunnelCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_tunnelMainMovie.initFromMovieFile("Images/Mars/Pod 2345M.mov");
_tunnelMainMovie.setVolume(g_vm->getSoundFXLevel());
_tunnelMainMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
_tunnelMainMovie.setDisplayOrder(kNavMovieOrder);
_tunnelMainCallBack.setNotification(&_chaseNotification);
_tunnelMainCallBack.initCallBack(&_tunnelMainMovie, kCallBackAtExtremes);
_tunnelMainCallBack.setCallBackFlag(kChaseEnteredBranchZone);
_tunnelMainCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_tunnelAltMovie.initFromMovieFile("Images/Mars/Pod 345A.mov");
_tunnelAltMovie.setVolume(g_vm->getSoundFXLevel());
_tunnelAltMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
_tunnelAltMovie.setDisplayOrder(kNavMovieOrder);
_tunnelAltCallBack.setNotification(&_chaseNotification);
_tunnelAltCallBack.initCallBack(&_tunnelAltMovie, kCallBackAtExtremes);
_tunnelAltCallBack.setCallBackFlag(kChaseEnteredBranchZone);
_tunnelAltCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_deathMovie.initFromMovieFile("Images/Mars/Pod 2D.mov");
_deathMovie.setVolume(g_vm->getSoundFXLevel());
_deathMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
_deathMovie.setDisplayOrder(kNavMovieOrder);
_deathCallBack.setNotification(&_chaseNotification);
_deathCallBack.initCallBack(&_deathMovie, kCallBackAtExtremes);
_deathCallBack.setCallBackFlag(kChaseFinished);
_deathCallBack.scheduleCallBack(kTriggerAtStop, 0 ,0);
ChaseInteraction::openInteraction();
_steerPict.setDisplayOrder(kNavMovieOrder + 1);
_steerPict.moveElementTo(kPodSteerLeft, kPodSteerTop);
}
void TunnelPod::initInteraction() {
_steerPict.startDisplaying();
_tunnelState = kTunnelLaunch;
((Mars *)_owner)->_navMovie.setSegment(kLaunchStart, kLaunchEnd - kDecisionTime);
((Mars *)_owner)->_navMovie.setTime(kLaunchStart);
((Mars *)_owner)->_navMovie.start();
_currentMovie = &((Mars *)_owner)->_navMovie;
_currentCallBack = &_tunnelCallBack;
ChaseInteraction::initInteraction();
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB27", kArthurMarsTurnedOnTransport);
}
void TunnelPod::closeInteraction() {
((Mars *)_owner)->_navMovie.stop();
if (_tunnelState == kTunnelFinish) {
// Only bring nack the nav movie if we successfully finished the chase
((Mars *)_owner)->_navMovie.startDisplaying();
((Mars *)_owner)->_navMovie.show();
}
_tunnelCallBack.releaseCallBack();
_tunnelAltMovie.stop();
_tunnelAltMovie.stopDisplaying();
_tunnelAltMovie.releaseMovie();
_tunnelAltCallBack.releaseCallBack();
_deathMovie.stop();
_deathMovie.stopDisplaying();
_deathMovie.releaseMovie();
_deathCallBack.releaseCallBack();
ChaseInteraction::closeInteraction();
}
void TunnelPod::receiveNotification(Notification *notification, const NotificationFlags flags) {
if (notification == &_chaseNotification && flags == kChaseFinished) {
if (_tunnelState != kTunnelFinish) {
// We died
((Mars *)_owner)->die(kDeathCollidedWithPod);
} else {
((Mars *)_owner)->startUpFromFinishedTunnelPod();
}
}
ChaseInteraction::receiveNotification(notification, flags);
}
void TunnelPod::setUpBranch() {
TimeValue branchStart, branchEnd;
branchStart = 0;
branchEnd = 0;
switch (_tunnelState) {
case kTunnelLaunch:
branchStart = kLaunchEnd - kDecisionTime;
branchEnd = kLaunchEnd;
break;
case kTunnelBranch1Left:
branchStart = kBranch1MainEnd - kDecisionTime;
branchEnd = kBranch1MainEnd;
break;
case kTunnelBranch2Left:
branchStart = kBranch2AltEnd - kDecisionTime;
branchEnd = kBranch2AltEnd;
break;
case kTunnelBranch2Right:
branchStart = kBranch2MainEnd - kDecisionTime;
branchEnd = kBranch2MainEnd;
break;
case kTunnelBranch3Left:
branchStart = kBranch3MainEnd - kDecisionTime;
branchEnd = kBranch3MainEnd;
break;
case kTunnelBranch3Right:
branchStart = kBranch3AltEnd - kDecisionTime;
branchEnd = kBranch3AltEnd;
break;
default:
break;
}
_currentMovie->setSegment(branchStart, branchEnd);
_currentCallBack->setCallBackFlag(kChaseExitedBranchZone);
_currentCallBack->scheduleCallBack(kTriggerAtStop, 0, 0);
}
void TunnelPod::branchLeft() {
TimeValue branchStart, branchEnd;
NotificationFlags flag;
Movie *movie;
NotificationCallBack *callBack;
branchStart = 0;
branchEnd = 0;
flag = 0;
movie = nullptr;
callBack = nullptr;
switch (_tunnelState) {
case kTunnelLaunch:
branchStart = kBranch1MainStart;
branchEnd = kBranch1MainEnd - kDecisionTime;
_tunnelState = kTunnelBranch1Left;
flag = kChaseEnteredBranchZone;
movie = &_tunnelMainMovie;
callBack = &_tunnelMainCallBack;
break;
case kTunnelBranch1Left:
branchStart = kBranch2AltStart;
branchEnd = kBranch2AltEnd - kDecisionTime;
_tunnelState = kTunnelBranch2Left;
flag = kChaseEnteredBranchZone;
movie = &_tunnelAltMovie;
callBack = &_tunnelAltCallBack;
break;
case kTunnelBranch2Left:
case kTunnelBranch2Right:
branchStart = kBranch3MainStart;
branchEnd = kBranch3MainEnd - kDecisionTime;
_tunnelState = kTunnelBranch3Left;
flag = kChaseEnteredBranchZone;
movie = &_tunnelMainMovie;
callBack = &_tunnelMainCallBack;
break;
case kTunnelBranch3Left:
case kTunnelBranch3Right:
branchStart = kFinishAltStart;
branchEnd = kFinishAltEnd;
_tunnelState = kTunnelFinish;
flag = kChaseFinished;
movie = &_tunnelAltMovie;
callBack = &_tunnelAltCallBack;
break;
default:
break;
}
movie->setSegment(branchStart, branchEnd);
movie->setTime(branchStart);
switchTo(*movie, *callBack);
callBack->setCallBackFlag(flag);
callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
}
void TunnelPod::branchRight() {
TimeValue branchStart, branchEnd;
NotificationFlags flag;
Movie *movie;
NotificationCallBack *callBack;
branchStart = 0;
branchEnd = 0;
flag = 0;
movie = nullptr;
callBack = nullptr;
switch (_tunnelState) {
case kTunnelLaunch:
switchTo(_deathMovie, _deathCallBack);
return;
case kTunnelBranch1Left:
branchStart = kBranch2MainStart;
branchEnd = kBranch2MainEnd - kDecisionTime;
_tunnelState = kTunnelBranch2Right;
flag = kChaseEnteredBranchZone;
movie = &_tunnelMainMovie;
callBack = &_tunnelMainCallBack;
break;
case kTunnelBranch2Left:
case kTunnelBranch2Right:
branchStart = kBranch3AltStart;
branchEnd = kBranch3AltEnd - kDecisionTime;
_tunnelState = kTunnelBranch3Right;
flag = kChaseEnteredBranchZone;
movie = &_tunnelAltMovie;
callBack = &_tunnelAltCallBack;
break;
case kTunnelBranch3Left:
case kTunnelBranch3Right:
branchStart = kFinishMainStart;
branchEnd = kFinishMainEnd;
_tunnelState = kTunnelFinish;
flag = kChaseFinished;
movie = &_tunnelMainMovie;
callBack = &_tunnelMainCallBack;
break;
default:
break;
}
movie->setSegment(branchStart, branchEnd);
movie->setTime(branchStart);
switchTo(*movie, *callBack);
callBack->setCallBackFlag(flag);
callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
}
void TunnelPod::dontBranch() {
switch (_tunnelState) {
case kTunnelLaunch:
case kTunnelBranch1Left:
if (_currentMovie == &_tunnelAltMovie)
branchLeft();
else
branchRight();
break;
case kTunnelBranch2Left:
case kTunnelBranch2Right:
if (_currentMovie == &_tunnelAltMovie)
branchRight();
else
branchLeft();
break;
case kTunnelBranch3Left:
case kTunnelBranch3Right:
if (_currentMovie == &_tunnelAltMovie)
branchLeft();
else
branchRight();
break;
default:
break;
}
}
void TunnelPod::switchTo(Movie &movie, NotificationCallBack &callBack) {
if (_currentMovie != &movie) {
if (_currentMovie != nullptr) {
_currentMovie->stop();
_currentMovie->hide();
_currentMovie->stopDisplaying();
}
_currentMovie = &movie;
_currentMovie->startDisplaying();
_currentMovie->show();
_currentMovie->start();
}
if (_currentCallBack != &callBack) {
_currentCallBack = &callBack;
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,75 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-2013 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_MARS_TUNNELPOD_H
#define PEGASUS_NEIGHBORHOOD_MARS_TUNNELPOD_H
#include "pegasus/chase.h"
#include "pegasus/movie.h"
namespace Pegasus {
class Mars;
class TunnelPod : public ChaseInteraction {
friend class Mars;
friend struct MusicTimerEvent;
public:
TunnelPod(Neighborhood *);
virtual ~TunnelPod() {}
void setSoundFXLevel(const uint16);
protected:
void openInteraction();
void initInteraction();
void closeInteraction();
void receiveNotification(Notification *, const NotificationFlags);
void setUpBranch();
void branchLeft();
void branchRight();
void dontBranch();
void switchTo(Movie &, NotificationCallBack &);
Movie _tunnelMainMovie;
Movie _tunnelAltMovie;
Movie _deathMovie;
NotificationCallBack _tunnelCallBack;
NotificationCallBack _tunnelMainCallBack;
NotificationCallBack _tunnelAltCallBack;
NotificationCallBack _deathCallBack;
Movie *_currentMovie;
NotificationCallBack *_currentCallBack;
short _tunnelState;
};
} // End of namespace Pegasus
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,409 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_H
#define PEGASUS_NEIGHBORHOOD_H
#include "common/queue.h"
#include "common/str.h"
#include "pegasus/fader.h"
#include "pegasus/hotspot.h"
#include "pegasus/input.h"
#include "pegasus/movie.h"
#include "pegasus/notification.h"
#include "pegasus/sound.h"
#include "pegasus/timers.h"
#include "pegasus/transition.h"
#include "pegasus/util.h"
#include "pegasus/neighborhood/door.h"
#include "pegasus/neighborhood/exit.h"
#include "pegasus/neighborhood/extra.h"
#include "pegasus/neighborhood/hotspotinfo.h"
#include "pegasus/neighborhood/spot.h"
#include "pegasus/neighborhood/turn.h"
#include "pegasus/neighborhood/view.h"
#include "pegasus/neighborhood/zoom.h"
namespace Pegasus {
class PegasusEngine;
// Pegasus Prime neighborhood id's
static const NeighborhoodID kCaldoriaID = 0;
static const NeighborhoodID kFullTSAID = 1;
static const NeighborhoodID kFinalTSAID = 2;
static const NeighborhoodID kTinyTSAID = 3;
static const NeighborhoodID kPrehistoricID = 4;
static const NeighborhoodID kMarsID = 5;
static const NeighborhoodID kWSCID = 6;
static const NeighborhoodID kNoradAlphaID = 7;
static const NeighborhoodID kNoradDeltaID = 8;
// The sub chase is not really a neighborhood, but we define a constant that is used
// to allow an easy transition out of Norad Alpha.
static const NeighborhoodID kNoradSubChaseID = 1000;
static const TimeScale kDefaultLoopFadeScale = kThirtyTicksPerSecond;
static const TimeValue kDefaultLoopFadeOut = kHalfSecondPerThirtyTicks;
static const TimeValue kDefaultLoopFadeIn = kHalfSecondPerThirtyTicks;
enum QueueRequestType {
kNavExtraRequest,
kSpotSoundRequest,
kDelayRequest
};
// For delay requests, start is interpreted as the total delay and stop is interpreted
// as the scale the delay is in.
// For extra requests, start and stop are not used.
struct QueueRequest {
QueueRequestType requestType;
ExtraID extra;
TimeValue start, stop;
InputBits interruptionFilter;
bool playing;
NotificationFlags flags;
Notification *notification;
};
bool operator==(const QueueRequest &arg1, const QueueRequest &arg2);
bool operator!=(const QueueRequest &arg1, const QueueRequest &arg2);
class CaldoriaBomb;
class GameInteraction;
class Item;
class Neighborhood;
class StriderCallBack : public TimeBaseCallBack {
public:
StriderCallBack(Neighborhood *);
~StriderCallBack() override {}
protected:
void callBack() override;
Neighborhood *_neighborhood;
};
typedef Common::Queue<QueueRequest> NeighborhoodActionQueue;
class Neighborhood : public IDObject, public NotificationReceiver, public InputHandler, public Idler {
friend class CaldoriaBomb;
friend class StriderCallBack;
public:
Neighborhood(InputHandler *nextHandler, PegasusEngine *vm, const Common::String &resName, NeighborhoodID id);
~Neighborhood() override;
virtual void init();
virtual void start();
virtual void moveNavTo(const CoordType, const CoordType);
virtual void checkContinuePoint(const RoomID, const DirectionConstant) = 0;
void makeContinuePoint();
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
virtual CanMoveForwardReason canMoveForward(ExitTable::Entry &entry);
virtual CanTurnReason canTurn(TurnDirection turn, DirectionConstant &nextDir);
virtual CanOpenDoorReason canOpenDoor(DoorTable::Entry &entry);
virtual void cantMoveThatWay(CanMoveForwardReason);
virtual void cantTurnThatWay(CanTurnReason) {}
virtual void cantOpenDoor(CanOpenDoorReason);
virtual void arriveAt(const RoomID room, const DirectionConstant direction);
virtual void turnTo(const DirectionConstant);
virtual void spotCompleted();
virtual void doorOpened();
virtual void closeDoorOffScreen(const RoomID, const DirectionConstant) {}
virtual void moveForward();
virtual void turn(const TurnDirection);
virtual void turnLeft();
virtual void turnRight();
virtual void turnUp();
virtual void turnDown();
virtual void openDoor();
virtual void zoomTo(const Hotspot *);
virtual void updateViewFrame();
void requestExtraSequence(const ExtraID, const NotificationFlags, const InputBits interruptionFilter);
void requestSpotSound(const TimeValue, const TimeValue, const InputBits interruptionFilter, const NotificationFlags);
void playSpotSoundSync(const TimeValue in, const TimeValue out);
void requestDelay(const TimeValue, const TimeScale, const InputBits interruptionFilter, const NotificationFlags);
Notification *getNeighborhoodNotification() { return &_neighborhoodNotification; }
virtual void getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry);
virtual void startSpotLoop(TimeValue, TimeValue, NotificationFlags = 0);
virtual bool actionQueueEmpty() { return _actionQueue.empty(); }
virtual void showViewFrame(TimeValue);
virtual void findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &spotEntry);
virtual void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits interruptionFilter);
bool startExtraSequenceSync(const ExtraID, const InputBits);
virtual void loopExtraSequence(const uint32, NotificationFlags = 0);
int32 getLastExtra() const { return _lastExtra; }
virtual void scheduleNavCallBack(NotificationFlags);
Movie *getNavMovie() { return &_navMovie; }
bool navMoviePlaying();
void setCurrentAlternate(const AlternateID alt) { _currentAlternate = alt; }
AlternateID getCurrentAlternate() const { return _currentAlternate; }
void setCurrentActivation(const HotSpotActivationID a) { _currentActivation = a; }
HotSpotActivationID getCurrentActivation() { return _currentActivation; }
virtual void playDeathExtra(ExtraID, DeathReason);
virtual void die(const DeathReason);
virtual void setSoundFXLevel(const uint16);
virtual void setAmbienceLevel(const uint16);
void forceStridingStop(const RoomID, const DirectionConstant, const AlternateID);
void restoreStriding(const RoomID, const DirectionConstant, const AlternateID);
HotspotInfoTable::Entry *findHotspotEntry(const HotSpotID);
Push *getTurnPush() { return &_turnPush; }
Picture *getTurnPushPicture() { return &_pushIn; }
void hideNav();
void showNav();
virtual void loadAmbientLoops() {}
virtual void flushGameState() {}
virtual Common::Path getBriefingMovie();
virtual Common::Path getEnvScanMovie();
virtual uint getNumHints();
virtual Common::Path getHintMovie(uint);
virtual bool canSolve();
virtual void prepareForAIHint(const Common::Path &) {}
virtual void cleanUpAfterAIHint(const Common::Path &) {}
virtual void doSolve();
virtual bool okayToJump();
virtual AirQuality getAirQuality(const RoomID);
virtual void checkAirMask() {}
virtual void checkFlashlight() {}
virtual void shieldOn() {}
virtual void shieldOff() {}
virtual void loadLoopSound1(const Common::Path &, const uint16 volume = 0x100,
const TimeValue fadeOut = kDefaultLoopFadeOut, const TimeValue fadeIn = kDefaultLoopFadeIn,
const TimeScale fadeScale = kDefaultLoopFadeScale);
virtual void loadLoopSound2(const Common::Path &, const uint16 volume = 0x100,
const TimeValue fadeOut = kDefaultLoopFadeOut, const TimeValue fadeIn = kDefaultLoopFadeIn,
const TimeScale fadeScale = kDefaultLoopFadeScale);
bool loop1Loaded(const Common::Path &soundName) { return _loop1SoundString == soundName; }
bool loop2Loaded(const Common::Path &soundName) { return _loop2SoundString == soundName; }
void startLoop1Fader(const FaderMoveSpec &);
void startLoop2Fader(const FaderMoveSpec &);
virtual void takeItemFromRoom(Item *);
virtual void dropItemIntoRoom(Item *, Hotspot *);
virtual Hotspot *getItemScreenSpot(Item *, DisplayElement *) { return 0; }
virtual GameInteraction *makeInteraction(const InteractionID);
virtual void requestDeleteCurrentInteraction() { _doneWithInteraction = true; }
virtual uint16 getDateResID() const = 0;
virtual void showExtraView(uint32);
virtual void startExtraLongSequence(const uint32, const uint32, NotificationFlags, const InputBits interruptionFilter);
void openCroppedMovie(const Common::Path &, CoordType, CoordType);
void loopCroppedMovie(const Common::Path &, CoordType, CoordType);
void closeCroppedMovie();
void playCroppedMovieOnce(const Common::Path &, CoordType, CoordType, const InputBits interruptionFilter = kFilterNoInput);
void playMovieSegment(Movie *, TimeValue = 0, TimeValue = 0xffffffff);
virtual void recallToTSASuccess();
virtual void recallToTSAFailure();
virtual void pickedUpItem(Item *) {}
void handleInput(const Input &, const Hotspot *) override;
protected:
PegasusEngine *_vm;
Common::String _resName;
virtual Common::Path getSoundSpotsName() = 0;
virtual Common::Path getNavMovieName() = 0;
// Notification function.
void receiveNotification(Notification *, const NotificationFlags) override;
// Map info functions.
virtual void getExitEntry(const RoomID room, const DirectionConstant direction, ExitTable::Entry &entry);
virtual TimeValue getViewTime(const RoomID room, const DirectionConstant direction);
virtual void getDoorEntry(const RoomID room, const DirectionConstant direction, DoorTable::Entry &doorEntry);
virtual DirectionConstant getTurnEntry(const RoomID room, const DirectionConstant direction, const TurnDirection turn);
virtual void getZoomEntry(const HotSpotID id, ZoomTable::Entry &zoomEntry);
virtual void getHotspotEntry(const HotSpotID id, HotspotInfoTable::Entry &hotspotEntry);
// Nav movie sequences.
virtual void startExitMovie(const ExitTable::Entry &);
virtual void keepStriding(ExitTable::Entry &);
virtual void stopStriding();
virtual void checkStriding();
virtual bool stillMoveForward();
virtual void scheduleStridingCallBack(const TimeValue, NotificationFlags flags);
virtual void startZoomMovie(const ZoomTable::Entry &);
virtual void startDoorOpenMovie(const TimeValue, const TimeValue);
virtual void startTurnPush(const TurnDirection, const TimeValue, const DirectionConstant);
virtual void playExtraMovie(const ExtraTable::Entry &, const NotificationFlags, const InputBits interruptionFilter);
virtual void activateCurrentView(const RoomID, const DirectionConstant, SpotFlags);
virtual void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *);
virtual void startSpotOnceOnly(TimeValue, TimeValue);
virtual void startMovieSequence(const TimeValue, const TimeValue, NotificationFlags,
bool loopSequence, const InputBits interruptionFilter, const TimeValue strideStop = 0xffffffff);
virtual void createNeighborhoodSpots();
void resetLastExtra() { _lastExtra = 0xffffffff; }
virtual void throwAwayInterface();
// Action queue stuff
void popActionQueue();
void serviceActionQueue();
void requestAction(const QueueRequestType, const ExtraID, const TimeValue, const TimeValue, const InputBits, const NotificationFlags);
virtual bool prepareExtraSync(const ExtraID);
virtual bool waitMovieFinish(Movie *, const InputBits);
InputBits getInputFilter() override;
// Misc.
virtual int16 getStaticCompassAngle(const RoomID, const DirectionConstant dir);
virtual void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &);
virtual void getZoomCompassMove(const ZoomTable::Entry &, FaderMoveSpec&);
virtual void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec&);
virtual void setUpAIRules();
virtual void setHotspotFlags(const HotSpotID, const HotSpotFlags);
virtual void setIsItemTaken(const ItemID);
virtual void upButton(const Input &);
virtual void leftButton(const Input &);
virtual void rightButton(const Input &);
virtual void downButton(const Input &);
void initOnePicture(Picture *, const Common::Path &, DisplayOrder, CoordType, CoordType, bool);
void initOneMovie(Movie *, const Common::Path &, DisplayOrder, CoordType, CoordType, bool);
void reinstateMonocleInterface();
virtual void newInteraction(const InteractionID);
void useIdleTime() override;
virtual void bumpIntoWall();
virtual void zoomUpOrBump();
void scheduleEvent(const TimeValue, const TimeScale, const uint32);
void cancelEvent();
virtual void timerExpired(const uint32) {}
bool isEventTimerRunning() { return _eventTimer.isFuseLit(); }
uint32 getTimerEvent() { return _timerEvent; }
void timerFunction();
void pauseTimer();
void resumeTimer();
bool timerPaused();
// Navigation Data
DoorTable _doorTable;
ExitTable _exitTable;
ExtraTable _extraTable;
HotspotInfoTable _hotspotInfoTable;
SpotTable _spotTable;
TurnTable _turnTable;
ViewTable _viewTable;
ZoomTable _zoomTable;
AlternateID _currentAlternate;
HotSpotActivationID _currentActivation;
ExtraID _lastExtra;
DeathReason _extraDeathReason;
// Graphics
Movie _navMovie;
Picture _pushIn;
Push _turnPush;
// Callbacks
Notification _neighborhoodNotification;
NotificationCallBack _navMovieCallBack;
StriderCallBack _stridingCallBack;
NotificationCallBack _turnPushCallBack;
NotificationCallBack _spotSoundCallBack;
NotificationCallBack _delayCallBack;
// Hotspots
HotspotList _neighborhoodHotspots;
// Sounds
SoundTimeBase _spotSounds;
// Action queue
NeighborhoodActionQueue _actionQueue;
TimeBase _delayTimer;
// Interruptibility...
InputBits _interruptionFilter;
// Nav hiding (for info support...)
bool _isRunning;
GameInteraction *_currentInteraction;
bool _doneWithInteraction;
Movie _croppedMovie;
Sound _soundLoop1;
Common::Path _loop1SoundString;
SoundFader _loop1Fader;
Sound _soundLoop2;
Common::Path _loop2SoundString;
SoundFader _loop2Fader;
// The event timer...
FuseFunction _eventTimer;
uint32 _timerEvent;
};
extern Neighborhood *g_neighborhood;
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,224 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
#include "pegasus/neighborhood/norad/alpha/ecrmonitor.h"
namespace Pegasus {
static const NotificationFlags kECRSection1FinishedFlag = 1;
static const NotificationFlags kECRPanFinishedFlag = kECRSection1FinishedFlag << 1;
static const NotificationFlags kECRSection2FinishedFlag = kECRPanFinishedFlag << 1;
static const NotificationFlags kECRNotificationFlags = kECRSection1FinishedFlag |
kECRPanFinishedFlag |
kECRSection2FinishedFlag;
static const TimeValue kSection1Start = 0;
static const TimeValue kSection1Stop = 25;
static const TimeValue kPanStart = 0;
static const TimeValue kPanStop = 20;
static const TimeValue kSection2Start = 26;
static const TimeValue kSection2Stop = 1000;
// Seems to be a good value for a 20 second pan.
enum {
kPanPixelsPerFrame = 8
};
// Interesting times are in seconds.
static const TimeValue s_ECRInterestingTimes[] = {
0, 1, 2, 10, 25, 26, 56, 64, 72, 80, 88, 94, 102, 108, 116, 999
};
// Index into s_ECRInterestingTimes of interesting time before security pan.
static const int kBeforePanTime = 3;
// Index into s_ECRInterestingTimes of interesting time after security pan.
static const int kAfterPanTime = 5;
NoradAlphaECRMonitor::NoradAlphaECRMonitor(Neighborhood *nextHandler) : GameInteraction(kNoradECRMonitorInteractionID, nextHandler),
_ecrSlideShowNotification(kNoradECRNotificationID, g_vm), _ecrMovie(kECRSlideShowMovieID),
_ecrPan(kECRPanID) {
}
void NoradAlphaECRMonitor::receiveNotification(Notification *, const NotificationFlags flags) {
if (flags & kECRSection1FinishedFlag)
ecrSection1Finished();
else if (flags & kECRPanFinishedFlag)
ecrPanFinished();
else if (flags & kECRSection2FinishedFlag)
ecrSection2Finished();
}
int NoradAlphaECRMonitor::findCurrentInterestingTime() {
TimeValue time = _ecrMovie.getTime();
TimeScale scale = _ecrMovie.getScale();
for (int i = ARRAYSIZE(s_ECRInterestingTimes) - 1; i >= 0; i--)
if (time >= s_ECRInterestingTimes[i] * scale)
return i;
return 0;
}
void NoradAlphaECRMonitor::skipToNextInterestingTime() {
if (_ecrMovie.isRunning()) {
int interestingTime = findCurrentInterestingTime();
_ecrMovie.setTime(s_ECRInterestingTimes[interestingTime + 1] * _ecrMovie.getScale());
_ecrMovie.redrawMovieWorld();
} else if (_ecrPan.isRunning()) {
_ecrPanCallBack.cancelCallBack();
ecrPanFinished();
}
}
void NoradAlphaECRMonitor::skipToPreviousInterestingTime() {
if (_ecrPan.isRunning()) {
_ecrPan.stop();
_ecrPan.stopDisplaying();
_ecrPanCallBack.cancelCallBack();
_ecrMovieCallBack.setCallBackFlag(kECRSection1FinishedFlag);
_ecrMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
TimeScale scale = _ecrMovie.getScale();
_ecrMovie.setSegment(kSection1Start * scale, kSection1Stop * scale + 1);
_ecrMovie.setTime(s_ECRInterestingTimes[kBeforePanTime] * scale);
_ecrMovie.start();
} else {
int interestingTime = findCurrentInterestingTime();
if (interestingTime == kAfterPanTime) {
_ecrMovieCallBack.cancelCallBack();
TimeScale scale = _ecrMovie.getScale();
_ecrMovie.setSegment(kSection1Start * scale, kSection1Stop * scale + 1);
_ecrMovie.setTime(kSection1Stop * scale);
ecrSection1Finished();
} else if (interestingTime == 0) {
_ecrMovie.setTime(kSection1Start * _ecrMovie.getScale());
_ecrMovie.redrawMovieWorld();
} else {
_ecrMovie.setTime(s_ECRInterestingTimes[interestingTime - 1] * _ecrMovie.getScale());
_ecrMovie.redrawMovieWorld();
}
}
}
void NoradAlphaECRMonitor::handleInput(const Input &input, const Hotspot *cursorSpot) {
if (isInteracting()) {
if (input.rightButtonDown())
skipToNextInterestingTime();
else if (input.leftButtonDown())
skipToPreviousInterestingTime();
else
InputHandler::handleInput(input, cursorSpot);
} else {
InputHandler::handleInput(input, cursorSpot);
}
}
void NoradAlphaECRMonitor::ecrSection1Finished() {
_ecrMovie.stop();
_ecrPanCallBack.setNotification(&_ecrSlideShowNotification);
_ecrPanCallBack.initCallBack(&_ecrPan, kCallBackAtExtremes);
_ecrPanCallBack.setCallBackFlag(kECRPanFinishedFlag);
_ecrSlideShowNotification.notifyMe(this, kECRNotificationFlags, kECRNotificationFlags);
_ecrPanCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_ecrPan.startDisplaying();
_ecrPan.show();
TimeScale scale = _ecrPan.getScale();
_ecrPan.setSegment(kPanStart * scale, kPanStop * scale);
_ecrPan.setTime(0);
_ecrPan.start();
}
void NoradAlphaECRMonitor::ecrPanFinished() {
_ecrPan.stop();
_ecrPan.stopDisplaying();
_ecrMovieCallBack.setCallBackFlag(kECRSection2FinishedFlag);
_ecrMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
TimeScale scale = _ecrMovie.getScale();
_ecrMovie.setSegment(kSection2Start * scale, kSection2Stop * scale);
_ecrMovie.start();
}
void NoradAlphaECRMonitor::ecrSection2Finished() {
_ecrMovie.stop();
_ecrMovie.stopDisplaying();
}
void NoradAlphaECRMonitor::openInteraction() {
// Initialize the security pan.
_ecrPan.initFromMovieFile("Images/Norad Alpha/Security Pan.pano");
_ecrPan.initMaskFromPICTFile("Images/Norad Alpha/Security Pan Mask");
_ecrPan.setBounds(Common::Rect(kECRPanLeft, kECRPanTop, kECRPanRight, kECRPanBottom));
_ecrPan.setDisplayOrder(kECRPanOrder);
_ecrPan.setScale(15); // 15 fps.
// Begin the lame ECR slide show.
// clone2727: I didn't say it :P
_ecrMovie.initFromMovieFile("Images/Norad Alpha/ECR Monitor Movie");
_ecrMovieCallBack.setNotification(&_ecrSlideShowNotification);
_ecrMovieCallBack.initCallBack(&_ecrMovie, kCallBackAtExtremes);
_ecrMovieCallBack.setCallBackFlag(kECRSection1FinishedFlag);
_ecrSlideShowNotification.notifyMe(this, kECRNotificationFlags, kECRNotificationFlags);
_ecrMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_ecrMovie.moveElementTo(kECRSlideShowLeft, kECRSlideShowTop);
_ecrMovie.setDisplayOrder(kECRMonitorOrder);
_ecrMovie.startDisplaying();
_ecrMovie.show();
_ecrMovie.redrawMovieWorld();
TimeScale scale = _ecrMovie.getScale();
_ecrMovie.setSegment(kSection1Start * scale, kSection1Stop * scale + 1);
_ecrMovie.start();
}
void NoradAlphaECRMonitor::closeInteraction() {
_ecrMovieCallBack.releaseCallBack();
_ecrMovie.stop();
_ecrMovie.stopDisplaying();
_ecrMovie.releaseMovie();
_ecrMovieCallBack.releaseCallBack();
_ecrPanCallBack.releaseCallBack();
_ecrPan.stop();
_ecrPan.stopDisplaying();
_ecrPan.releasePanorama();
_ecrPanCallBack.releaseCallBack();
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB33", kArthurNoradAtSecurityMonitor);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,64 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_ecrMONITOR_H
#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_ecrMONITOR_H
#include "pegasus/interaction.h"
#include "pegasus/notification.h"
#include "pegasus/neighborhood/norad/alpha/panoramascroll.h"
namespace Pegasus {
class NoradAlphaECRMonitor : public GameInteraction, public NotificationReceiver {
public:
NoradAlphaECRMonitor(Neighborhood *);
~NoradAlphaECRMonitor() override {}
void handleInput(const Input &, const Hotspot *) override;
protected:
void openInteraction() override;
void closeInteraction() override;
void receiveNotification(Notification *, const NotificationFlags) override;
void ecrSection1Finished();
void ecrPanFinished();
void ecrSection2Finished();
int findCurrentInterestingTime();
void skipToNextInterestingTime();
void skipToPreviousInterestingTime();
Notification _ecrSlideShowNotification;
Movie _ecrMovie;
NotificationCallBack _ecrMovieCallBack;
PanoramaScroll _ecrPan;
NotificationCallBack _ecrPanCallBack;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,459 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/inventory/airmask.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/alpha/fillingstation.h"
#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
namespace Pegasus {
static const NotificationFlags kFSPowerUpFinishedFlag = 1;
static const NotificationFlags kFSSplashFinishedFlag = kFSPowerUpFinishedFlag << 1;
static const NotificationFlags kFSIntakeWarningFinishedFlag = kFSSplashFinishedFlag << 1;
static const NotificationFlags kFSIntakeHiliteFinishedFlag = kFSIntakeWarningFinishedFlag << 1;
static const NotificationFlags kFSDispenseHiliteFinishedFlag = kFSIntakeHiliteFinishedFlag << 1;
static const NotificationFlags kFSArHiliteFinishedFlag = kFSDispenseHiliteFinishedFlag << 1;
static const NotificationFlags kFSCO2HiliteFinishedFlag = kFSArHiliteFinishedFlag << 1;
static const NotificationFlags kFSHeHiliteFinishedFlag = kFSCO2HiliteFinishedFlag << 1;
static const NotificationFlags kFSOHiliteFinishedFlag = kFSHeHiliteFinishedFlag << 1;
static const NotificationFlags kFSNHiliteFinishedFlag = kFSOHiliteFinishedFlag << 1;
static const NotificationFlags kFSNotificationFlags = kFSPowerUpFinishedFlag |
kFSSplashFinishedFlag |
kFSIntakeWarningFinishedFlag |
kFSIntakeHiliteFinishedFlag |
kFSDispenseHiliteFinishedFlag |
kFSArHiliteFinishedFlag |
kFSCO2HiliteFinishedFlag |
kFSHeHiliteFinishedFlag |
kFSOHiliteFinishedFlag |
kFSNHiliteFinishedFlag;
static const int16 kNoState = 0;
static const int16 kMainMenu = 1;
static const int16 kWaitingForAttach = 2;
static const int16 kDispenseMenu = 3;
static const int16 kWaitingForDispense = 4;
// Dummy itemIDs
static const ItemID kCO2Item = 10000;
static const ItemID kHeItem = 10001;
// Interactive points.
enum {
kFSPowerUpStartStart = 0,
kFSPowerUpStartStop = 600,
kFSSplashStart = 600,
kFSSplashStop = 7800,
kFSSplashIntakeStart = 7800,
kFSSplashIntakeStop = 18600,
kFSMainMenu = 18600,
kFSIntakeHiliteStart = 19200,
kFSIntakeHiliteStop = 19800,
kFSDispenseHiliteStart = 19800,
kFSDispenseHiliteStop = 20400,
kFSDispenseMenu = 20400,
kFSArHiliteStart = 21000,
kFSArHiliteStop = 21600,
kFSArAttach = 21600,
kFSArFilledStart = 22200,
kFSArFilledStop = 25200,
kFSArIncompatibleStart = 25200,
kFSArIncompatibleStop = 30000,
kFSCO2HiliteStart = 30000,
kFSCO2HiliteStop = 30600,
kFSCO2Attach = 30600,
kFSCO2FilledStart = 31200,
kFSCO2FilledStop = 34200,
kFSCO2IncompatibleStart = 34200,
kFSCO2IncompatibleStop = 39000,
kFSHeHiliteStart = 39000,
kFSHeHiliteStop = 39600,
kFSHeAttach = 39600,
kFSHeFilledStart = 40200,
kFSHeFilledStop = 43200,
kFSHeIncompatibleStart = 43200,
kFSHeIncompatibleStop = 48000,
kFSOHiliteStart = 48000,
kFSOHiliteStop = 48600,
kFSOAttach = 48600,
kFSOFilledStart = 49200,
kFSOFilledStop = 52200,
kFSOIncompatibleStart = 52200,
kFSOIncompatibleStop = 57000,
kFSNHiliteStart = 57000,
kFSNHiliteStop = 57600,
kFSNAttach = 57600,
kFSNFilledStart = 58200,
kFSNFilledStop = 61200,
kFSNIncompatibleStart = 61200,
kFSNIncompatibleStop = 66000,
kFSIntakeMenu = 66000,
kFSIntakeInProgressStart = 66600,
kFSIntakeInProgressStop = 69600
};
NoradAlphaFillingStation::NoradAlphaFillingStation(Neighborhood *owner) : GameInteraction(kNoradFillingStationInteractionID, owner),
_rightSideMovie(kN01RightSideID), _rightSideNotification(kNoradFillingStationNotificationID, g_vm) {
_state = kNoState;
}
void NoradAlphaFillingStation::openInteraction() {
_rightSideMovie.initFromMovieFile("Images/Norad Alpha/N01W Right Side");
_rightSideMovie.moveElementTo(kNoradAlpha01RightSideLeft, kNoradAlpha01RightSideTop);
_rightSideMovie.setDisplayOrder(kN01RightSideOrder);
_rightSideMovie.startDisplaying();
_rightSideCallBack.setNotification(&_rightSideNotification);
_rightSideCallBack.initCallBack(&_rightSideMovie, kCallBackAtExtremes);
_rightSideCallBack.setCallBackFlag(kFSPowerUpFinishedFlag);
_rightSideNotification.notifyMe(this, kFSNotificationFlags, kFSNotificationFlags);
_rightSideCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_rightSideMovie.show();
_rightSideMovie.redrawMovieWorld();
_rightSideMovie.setSegment(kFSPowerUpStartStart, kFSPowerUpStartStop);
}
void NoradAlphaFillingStation::initInteraction() {
allowInput(false);
_rightSideMovie.setRate(2);
}
void NoradAlphaFillingStation::closeInteraction() {
_rightSideMovie.stop();
_rightSideMovie.stopDisplaying();
_rightSideMovie.releaseMovie();
_rightSideCallBack.releaseCallBack();
((NoradAlpha *)getOwner())->turnOffFillingStation();
}
void NoradAlphaFillingStation::setStaticState(TimeValue time, int16 state) {
_rightSideMovie.stop();
_rightSideMovie.setSegment(0, _rightSideMovie.getDuration());
_rightSideMovie.setTime(time);
_rightSideMovie.redrawMovieWorld();
_state = state;
allowInput(true);
}
void NoradAlphaFillingStation::setSegmentState(TimeValue start, TimeValue stop, NotificationFlags flag, int16 state) {
_rightSideMovie.stop();
_rightSideMovie.setSegment(start, stop);
_rightSideMovie.setTime(start);
_rightSideCallBack.setCallBackFlag(flag);
_rightSideCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_state = state;
allowInput(false);
_rightSideMovie.setRate(2);
}
void NoradAlphaFillingStation::powerUpFinished() {
((NoradAlpha *)getOwner())->turnOnFillingStation();
setSegmentState(kFSSplashStart, kFSSplashStop, kFSSplashFinishedFlag, kNoState);
}
void NoradAlphaFillingStation::splashFinished() {
if (GameState.getNoradGassed())
setSegmentState(kFSSplashIntakeStart, kFSSplashIntakeStop, kFSIntakeWarningFinishedFlag, kNoState);
else
intakeWarningFinished();
}
void NoradAlphaFillingStation::intakeWarningFinished() {
setStaticState(kFSMainMenu, kMainMenu);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA29", kArthurNoradSawIntakeWarning);
}
void NoradAlphaFillingStation::showIntakeInProgress(uint16 numSeconds) {
if (numSeconds == 0) {
setSegmentState(kFSIntakeInProgressStart, kFSIntakeInProgressStop, kFSIntakeWarningFinishedFlag, kNoState);
Item *item = ((NoradAlpha *)getOwner())->getFillingItem();
if (item->getObjectID() == kGasCanister) {
GameState.setNoradGassed(true);
((NoradAlpha *)getOwner())->checkAirMask();
getOwner()->restoreStriding(kNorad03, kEast, kAltNoradAlphaNormal);
}
} else {
setSegmentState(kFSIntakeInProgressStart, kFSIntakeInProgressStart + _rightSideMovie.getScale() * numSeconds,
kFSIntakeWarningFinishedFlag, kNoState);
}
}
void NoradAlphaFillingStation::intakeHighlightFinished() {
_rightSideMovie.stop();
if (GameState.getNoradGassed()) {
showIntakeInProgress(2);
} else {
Item *item = ((NoradAlpha *)getOwner())->getFillingItem();
if (item)
showIntakeInProgress(0);
else
setStaticState(kFSIntakeMenu, kWaitingForAttach);
}
}
void NoradAlphaFillingStation::dispenseHighlightFinished() {
setStaticState(kFSDispenseMenu, kDispenseMenu);
}
void NoradAlphaFillingStation::dispenseGas() {
Item *item = ((NoradAlpha *)getOwner())->getFillingItem();
if (item) {
if (item->getObjectID() != _dispenseItemID)
switch (_dispenseItemID) {
case kArgonCanister:
setSegmentState(kFSArIncompatibleStart, kFSArIncompatibleStop,
kFSIntakeWarningFinishedFlag, kNoState);
break;
case kCO2Item:
setSegmentState(kFSCO2IncompatibleStart, kFSCO2IncompatibleStop,
kFSIntakeWarningFinishedFlag, kNoState);
break;
case kHeItem:
setSegmentState(kFSHeIncompatibleStart, kFSHeIncompatibleStop,
kFSIntakeWarningFinishedFlag, kNoState);
break;
case kAirMask:
setSegmentState(kFSOIncompatibleStart, kFSOIncompatibleStop,
kFSIntakeWarningFinishedFlag, kNoState);
break;
case kNitrogenCanister:
setSegmentState(kFSNIncompatibleStart, kFSNIncompatibleStop,
kFSIntakeWarningFinishedFlag, kNoState);
break;
default:
break;
}
else {
if (_dispenseItemID == kArgonCanister) {
setSegmentState(kFSArFilledStart, kFSArFilledStop, kFSIntakeWarningFinishedFlag, kNoState);
item->setItemState(kArgonFull);
GameState.setScoringFilledArgonCanister(true);
} else if (_dispenseItemID == kAirMask) {
setSegmentState(kFSOFilledStart, kFSOFilledStop, kFSIntakeWarningFinishedFlag, kNoState);
((AirMask *)item)->refillAirMask();
GameState.setScoringFilledOxygenCanister(true);
} else if (_dispenseItemID == kNitrogenCanister) {
setSegmentState(kFSNFilledStart, kFSNFilledStop, kFSIntakeWarningFinishedFlag, kNoState);
item->setItemState(kNitrogenFull);
}
}
} else {
switch (_dispenseItemID) {
case kArgonCanister:
setStaticState(kFSArAttach, kWaitingForDispense);
break;
case kCO2Item:
setStaticState(kFSCO2Attach, kWaitingForDispense);
break;
case kHeItem:
setStaticState(kFSHeAttach, kWaitingForDispense);
break;
case kAirMask:
setStaticState(kFSOAttach, kWaitingForDispense);
break;
case kNitrogenCanister:
setStaticState(kFSNAttach, kWaitingForDispense);
break;
default:
break;
}
}
}
void NoradAlphaFillingStation::ArHighlightFinished() {
_dispenseItemID = kArgonCanister;
dispenseGas();
}
void NoradAlphaFillingStation::CO2HighlightFinished() {
_dispenseItemID = kCO2Item;
dispenseGas();
}
void NoradAlphaFillingStation::HeHighlightFinished() {
_dispenseItemID = kHeItem;
dispenseGas();
}
void NoradAlphaFillingStation::OHighlightFinished() {
_dispenseItemID = kAirMask;
dispenseGas();
}
void NoradAlphaFillingStation::NHighlightFinished() {
_dispenseItemID = kNitrogenCanister;
dispenseGas();
}
void NoradAlphaFillingStation::receiveNotification(Notification *, const NotificationFlags flags) {
switch (flags) {
case kFSPowerUpFinishedFlag:
powerUpFinished();
break;
case kFSSplashFinishedFlag:
splashFinished();
break;
case kFSIntakeWarningFinishedFlag:
intakeWarningFinished();
break;
case kFSIntakeHiliteFinishedFlag:
intakeHighlightFinished();
break;
case kFSDispenseHiliteFinishedFlag:
dispenseHighlightFinished();
break;
case kFSArHiliteFinishedFlag:
ArHighlightFinished();
break;
case kFSCO2HiliteFinishedFlag:
CO2HighlightFinished();
break;
case kFSHeHiliteFinishedFlag:
HeHighlightFinished();
break;
case kFSOHiliteFinishedFlag:
OHighlightFinished();
break;
case kFSNHiliteFinishedFlag:
NHighlightFinished();
break;
default:
break;
}
}
void NoradAlphaFillingStation::handleInput(const Input &input, const Hotspot *cursorSpot) {
InputHandler::handleInput(input, cursorSpot);
}
void NoradAlphaFillingStation::clickInIntake() {
setSegmentState(kFSIntakeHiliteStart, kFSIntakeHiliteStop, kFSIntakeHiliteFinishedFlag, kNoState);
}
void NoradAlphaFillingStation::clickInDispense() {
setSegmentState(kFSDispenseHiliteStart, kFSDispenseHiliteStop, kFSDispenseHiliteFinishedFlag, kNoState);
}
void NoradAlphaFillingStation::clickInAr() {
setSegmentState(kFSArHiliteStart, kFSArHiliteStop, kFSArHiliteFinishedFlag, kNoState);
}
void NoradAlphaFillingStation::clickInCO2() {
setSegmentState(kFSCO2HiliteStart, kFSCO2HiliteStop, kFSCO2HiliteFinishedFlag, kNoState);
}
void NoradAlphaFillingStation::clickInHe() {
setSegmentState(kFSHeHiliteStart, kFSHeHiliteStop, kFSHeHiliteFinishedFlag, kNoState);
}
void NoradAlphaFillingStation::clickInO() {
setSegmentState(kFSOHiliteStart, kFSOHiliteStop, kFSOHiliteFinishedFlag, kNoState);
}
void NoradAlphaFillingStation::clickInN() {
setSegmentState(kFSNHiliteStart, kFSNHiliteStop, kFSNHiliteFinishedFlag, kNoState);
}
void NoradAlphaFillingStation::clickInHotspot(const Input &input, const Hotspot *spot) {
GameInteraction::clickInHotspot(input, spot);
switch (spot->getObjectID()) {
case kNorad01IntakeSpotID:
clickInIntake();
break;
case kNorad01DispenseSpotID:
clickInDispense();
break;
case kNorad01ArSpotID:
clickInAr();
break;
case kNorad01CO2SpotID:
clickInCO2();
break;
case kNorad01HeSpotID:
clickInHe();
break;
case kNorad01OSpotID:
clickInO();
break;
case kNorad01NSpotID:
clickInN();
break;
default:
break;
}
}
void NoradAlphaFillingStation::activateHotspots() {
GameInteraction::activateHotspots();
switch (_state) {
case kMainMenu:
g_allHotspots.activateOneHotspot(kNorad01IntakeSpotID);
g_allHotspots.activateOneHotspot(kNorad01DispenseSpotID);
break;
case kDispenseMenu:
g_allHotspots.activateOneHotspot(kNorad01ArSpotID);
g_allHotspots.activateOneHotspot(kNorad01CO2SpotID);
g_allHotspots.activateOneHotspot(kNorad01HeSpotID);
g_allHotspots.activateOneHotspot(kNorad01OSpotID);
g_allHotspots.activateOneHotspot(kNorad01NSpotID);
break;
default:
break;
}
}
void NoradAlphaFillingStation::newFillingItem(Item *item) {
switch (_state) {
case kWaitingForAttach:
if (item)
showIntakeInProgress(0);
break;
case kWaitingForDispense:
dispenseGas();
break;
default:
break;
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,90 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_FILLINGSTATION_H
#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_FILLINGSTATION_H
#include "pegasus/interaction.h"
#include "pegasus/movie.h"
#include "pegasus/notification.h"
namespace Pegasus {
class Item;
class NoradAlphaFillingStation : public GameInteraction, public NotificationReceiver {
public:
NoradAlphaFillingStation(Neighborhood *);
~NoradAlphaFillingStation() override {}
void handleInput(const Input &, const Hotspot *) override;
void clickInHotspot(const Input &, const Hotspot *) override;
void activateHotspots() override;
void newFillingItem(Item *);
protected:
void receiveNotification(Notification *, const NotificationFlags) override;
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void powerUpFinished();
void splashFinished();
void intakeWarningFinished();
void intakeHighlightFinished();
void dispenseHighlightFinished();
void ArHighlightFinished();
void CO2HighlightFinished();
void HeHighlightFinished();
void OHighlightFinished();
void NHighlightFinished();
void showIntakeInProgress(uint16);
void clickInIntake();
void clickInDispense();
void clickInAr();
void clickInCO2();
void clickInHe();
void clickInO();
void clickInN();
void dispenseGas();
void setStaticState(TimeValue, int16);
void setSegmentState(TimeValue, TimeValue, NotificationFlags, int16);
Movie _rightSideMovie;
Notification _rightSideNotification;
NotificationCallBack _rightSideCallBack;
int16 _state;
ItemID _dispenseItemID;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,969 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/cursor.h"
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
#include "pegasus/interface.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/inventory/airmask.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/subcontrolroom.h"
#include "pegasus/neighborhood/norad/alpha/ecrmonitor.h"
#include "pegasus/neighborhood/norad/alpha/fillingstation.h"
#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
#include "pegasus/neighborhood/norad/alpha/subchase.h"
namespace Pegasus {
static const ExtraID kShowThermalScan = 1000;
static const HotSpotID kThermalScanHotSpotID = 10000;
const uint32 NoradAlpha::_noradAlphaClawExtras[22] = {
kN22ClawFromAToB,
kN22ClawALoop,
kN22ClawAPinch,
kN22ClawACounterclockwise,
kN22ClawAClockwise,
kN22ClawFromBToA,
kN22ClawFromBToC,
kN22ClawFromBToD,
kN22ClawBLoop,
kN22ClawBPinch,
kN22ClawBCounterclockwise,
kN22ClawBClockwise,
kN22ClawFromCToB,
kN22ClawCLoop,
kN22ClawCPinch,
kN22ClawCCounterclockwise,
kN22ClawCClockwise,
kN22ClawFromDToB,
kN22ClawDLoop,
kN22ClawDPinch,
kN22ClawDCounterclockwise,
kN22ClawDClockwise
};
NoradAlpha::NoradAlpha(InputHandler *nextHandler, PegasusEngine *owner)
: Norad(nextHandler, owner, "Norad Alpha", kNoradAlphaID),
_thermalScanSpot(kThermalScanHotSpotID), _extraMovie(kNoDisplayElement) {
_elevatorUpRoomID = kNorad11South;
_elevatorDownRoomID = kNorad12South;
_elevatorUpSpotID = kNorad12ElevatorUpSpotID;
_elevatorDownSpotID = kNorad11ElevatorDownSpotID;
_subRoomEntryRoom1 = kNorad10;
_subRoomEntryDir1 = kEast;
_subRoomEntryRoom2 = kNorad21;
_subRoomEntryDir2 = kWest;
_upperPressureDoorRoom = kNorad10East;
_lowerPressureDoorRoom = kNorad21West;
_upperPressureDoorUpSpotID = kAlphaUpperPressureDoorUpSpotID;
_upperPressureDoorDownSpotID = kAlphaUpperPressureDoorDownSpotID;
_upperPressureDoorAbortSpotID = kNorad10EastOutSpotID;
_lowerPressureDoorUpSpotID = kAlphaLowerPressureDoorUpSpotID;
_lowerPressureDoorDownSpotID = kAlphaLowerPressureDoorDownSpotID;
_lowerPressureDoorAbortSpotID = kNorad21WestOutSpotID;
_pressureSoundIn = kAlphaPressureDoorIntro1In;
_pressureSoundOut = kAlphaPressureDoorIntro1Out;
_equalizeSoundIn = kAlphaPressureDoorIntro2In;
_equalizeSoundOut = kAlphaPressureDoorIntro2Out;
_accessDeniedIn = kAlphaAccessDeniedIn;
_accessDeniedOut = kAlphaAccessDeniedOut;
_platformRoom = kNorad19West;
_subControlRoom = kNorad22West;
_subPrepFailed = false;
_fillingStationItem = nullptr;
setIsItemTaken(kGasCanister);
}
NoradAlpha::~NoradAlpha() {
if (_vm->isDVD())
_vm->getAllHotspots().remove(&_thermalScanSpot);
}
void NoradAlpha::init() {
Norad::init();
_extraMovieCallBack.setNotification(&_neighborhoodNotification);
if (_vm->isDVD()) {
_thermalScanSpot.setArea(Common::Rect(216, 112, 336, 312));
_thermalScanSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
_vm->getAllHotspots().push_back(&_thermalScanSpot);
}
Hotspot *hotspot = _vm->getAllHotspots().findHotspotByID(kN01GasCanisterSpotID);
hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
HotspotInfoTable::Entry *hotspotEntry = findHotspotEntry(kN01GasCanisterSpotID);
hotspotEntry->hotspotItem = kGasCanister;
hotspot = _vm->getAllHotspots().findHotspotByID(kN01ArgonCanisterSpotID);
hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
hotspotEntry = findHotspotEntry(kN01ArgonCanisterSpotID);
hotspotEntry->hotspotItem = kArgonCanister;
hotspot = _vm->getAllHotspots().findHotspotByID(kN01NitrogenCanisterSpotID);
hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
hotspotEntry = findHotspotEntry(kN01NitrogenCanisterSpotID);
hotspotEntry->hotspotItem = kNitrogenCanister;
hotspot = _vm->getAllHotspots().findHotspotByID(kN01AirMaskSpotID);
hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
hotspotEntry = findHotspotEntry(kN01AirMaskSpotID);
hotspotEntry->hotspotItem = kAirMask;
hotspot = _vm->getAllHotspots().findHotspotByID(kN01GasOutletSpotID);
hotspot->setMaskedHotspotFlags(kDropItemSpotFlag, kDropItemSpotFlag);
}
void NoradAlpha::start() {
if (g_energyMonitor) {
g_energyMonitor->stopEnergyDraining();
g_energyMonitor->restoreLastEnergyValue();
_vm->resetEnergyDeathReason();
g_energyMonitor->startEnergyDraining();
}
NeighborhoodID itemNeighborhood;
RoomID itemRoom;
DirectionConstant itemDirection;
Item *item = (Item *)_vm->getAllItems().findItemByID(kGasCanister);
item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
if (itemNeighborhood == getObjectID()) {
_fillingStationItem = item;
} else {
item = (Item *)_vm->getAllItems().findItemByID(kAirMask);
item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
if (itemNeighborhood == getObjectID()) {
_fillingStationItem = item;
} else {
item = (Item *)_vm->getAllItems().findItemByID(kNitrogenCanister);
item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
if (itemNeighborhood == getObjectID()) {
_fillingStationItem = item;
} else {
item = (Item *)_vm->getAllItems().findItemByID(kArgonCanister);
item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
if (itemNeighborhood == getObjectID())
_fillingStationItem = item;
else
_fillingStationItem = nullptr;
}
}
}
if (!GameState.getNoradGassed())
forceStridingStop(kNorad03, kEast, kAltNoradAlphaNormal);
GameState.setNoradArrivedFromSub(false);
Norad::start();
}
void NoradAlpha::setUpAIRules() {
Neighborhood::setUpAIRules();
if (g_AIArea) {
AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Norad/XN01WD1", false);
AIHasItemCondition *hasGasCanisterCondition = new AIHasItemCondition(kGasCanister);
AIRule *rule = new AIRule(hasGasCanisterCondition, messageAction);
g_AIArea->addAIRule(rule);
}
}
bool NoradAlpha::okayToJump() {
bool result = Neighborhood::okayToJump();
if (!result)
playSpotSoundSync(kAlphaCantTransportIn, kAlphaCantTransportOut);
return result;
}
void NoradAlpha::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) {
if (entry.extra == kNorad19ExitToSub) {
compassMove.makeTwoKnotFaderSpec(kNoradAlphaMovieScale, entry.movieStart, 270 + kSubPlatformCompassAngle,
entry.movieEnd, 90 + 20 + 360);
compassMove.insertFaderKnot(entry.movieStart + 10 * kNoradAlphaFrameDuration, 270 + kSubPlatformCompassAngle);
compassMove.insertFaderKnot(entry.movieStart + 29 * kNoradAlphaFrameDuration, 270 + kSubPlatformCompassAngle + 20);
compassMove.insertFaderKnot(entry.movieStart + 52 * kNoradAlphaFrameDuration, 270 + kSubPlatformCompassAngle + 20);
compassMove.insertFaderKnot(entry.movieStart + 84 * kNoradAlphaFrameDuration, 360 + 90);
compassMove.insertFaderKnot(entry.movieStart + 198 * kNoradAlphaFrameDuration, 360 + 90);
compassMove.insertFaderKnot(entry.movieStart + 270 * kNoradAlphaFrameDuration, 360 + 90 + 15);
compassMove.insertFaderKnot(entry.movieStart + 280 * kNoradAlphaFrameDuration, 360 + 90 + 20);
} else {
Norad::getExtraCompassMove(entry, compassMove);
}
}
void NoradAlpha::playClawMonitorIntro() {
playSpotSoundSync(kAlphaLoadClawIntroIn, kAlphaLoadClawIntroOut);
}
GameInteraction *NoradAlpha::makeInteraction(const InteractionID interactionID) {
switch (interactionID) {
case kNoradECRMonitorInteractionID:
return new NoradAlphaECRMonitor(this);
case kNoradFillingStationInteractionID:
return new NoradAlphaFillingStation(this);
case kNoradSubChaseInteractionID:
return new SubChase(this);
default:
break;
}
return Norad::makeInteraction(interactionID);
}
void NoradAlpha::loadAmbientLoops() {
// clone2727 would like to point out that the following comment does not quite
// match the code logic below
/*
Logic:
loop sound 1:
if gassed,
play warning loop of some sort
else
play nothing
loop sound 2:
if gassed and not wearing air mask
if in ECR
play breathing water loop
else
play breathing
else
if in ECR
play water loop
if at N07 north
play unmanned loop
*/
if (!GameState.getNoradSeenTimeStream() || !g_interface || _vm->getEnergyDeathReason() == kDeathSubDestroyed)
return;
RoomID room = GameState.getCurrentRoom();
if (GameState.getNoradGassed()) {
if (room >= kNorad11 && room <= kNorad19West) {
if (_vm->isDVD())
loadLoopSound1("Sounds/Norad/NEW SUB AMB.44K.AIFF", kNoradWarningVolume * 3);
else
loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", kNoradWarningVolume * 3);
} else if (room >= kNorad21 && room <= kNorad22West) {
if (_vm->isDVD())
loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.32K.AIFF", kNoradWarningVolume * 3);
else
loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.22K.AIFF", kNoradWarningVolume * 3);
} else {
if (_vm->isDVD())
loadLoopSound1("Sounds/Norad/WARNING LOOP.32K.AIFF", kNoradWarningVolume);
else
loadLoopSound1("Sounds/Norad/WARNING LOOP.22K.AIFF", kNoradWarningVolume);
}
} else {
loadLoopSound1("");
}
if (GameState.getNoradGassed() && !g_airMask->isAirFilterOn()) {
if (room >= kNorad01 && room <= kNorad01West) {
loadLoopSound2("Sounds/Norad/Breathing Water.22K.AIFF", kNoradSuckWindVolume);
} else if (room == kNorad02) {
if (GameState.isCurrentDoorOpen())
loadLoopSound2("Sounds/Norad/Breathing Water.22K.AIFF", kNoradSuckWindVolume);
else
loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", kNoradSuckWindVolume, 0, 0);
} else {
loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", kNoradSuckWindVolume, 0, 0);
}
} else {
if (room >= kNorad01 && room <= kNorad01West) {
loadLoopSound2("Sounds/Norad/WATER FLOWING.AIFF", 0x100 / 2);
} else if (room == kNorad02) {
if (GameState.isCurrentDoorOpen())
loadLoopSound2("Sounds/Norad/WATER FLOWING.AIFF", 0x100 / 2);
else
loadLoopSound2("");
} else {
loadLoopSound2("");
}
}
}
void NoradAlpha::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
switch (MakeRoomView(room, direction)) {
case MakeRoomView(kNorad02, kEast):
case MakeRoomView(kNorad06, kEast):
case MakeRoomView(kNorad11, kEast):
case MakeRoomView(kNorad15, kEast):
case MakeRoomView(kNorad19, kWest):
case MakeRoomView(kNorad21, kSouth):
makeContinuePoint();
break;
default:
break;
}
}
void NoradAlpha::arriveAt(const RoomID room, const DirectionConstant direction) {
Norad::arriveAt(room, direction);
switch (GameState.getCurrentRoom()) {
case kNorad01:
arriveAtNorad01();
break;
case kNorad01East:
arriveAtNorad01East();
break;
case kNorad01West:
arriveAtNorad01West();
break;
case kNorad04:
arriveAtNorad04();
break;
case kNorad07:
if (_vm->isDVD() && GameState.getLastRoom() == kNorad06)
startExtraSequence(kShowThermalScan, kExtraCompletedFlag, kFilterNoInput);
break;
case kNorad07North:
GameState.setScoringSawUnconsciousOperator(true);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA70", kArthurNoradSawUnconsciousOperator);
break;
case kNorad11:
GameState.setScoringWentThroughPressureDoor(true);
break;
case kNorad22:
arriveAtNorad22();
break;
default:
break;
}
}
void NoradAlpha::arriveAtNorad01() {
Item *argonCanister, *nitrogenCanister;
switch (GameState.getCurrentDirection()) {
case kSouth:
if (!GameState.getNoradSeenTimeStream()) {
GameState.setNoradN22MessagePlayed(false);
requestExtraSequence(kNoradArriveFromTSA, kExtraCompletedFlag, kFilterNoInput);
// You are no match for me, human.
requestExtraSequence(kNorad01RobotTaunt, kExtraCompletedFlag, kFilterNoInput);
}
break;
case kEast:
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA33", kArthurNoradAtSecurityMonitor);
break;
case kWest:
if (GameState.getLastRoom() == kNorad01West) {
argonCanister = g_allItems.findItemByID(kArgonCanister);
nitrogenCanister = g_allItems.findItemByID(kNitrogenCanister);
if (((GameState.isTakenItemID(kArgonCanister) && argonCanister->getItemState() != kArgonFull) ||
(GameState.isTakenItemID(kNitrogenCanister) && nitrogenCanister->getItemState() != kNitrogenFull)) && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA34", kArthurNoradDidntFillCanisters);
}
break;
}
}
void NoradAlpha::arriveAtNorad01East() {
GameState.setScoringSawSecurityMonitor(true);
newInteraction(kNoradECRMonitorInteractionID);
}
void NoradAlpha::arriveAtNorad01West() {
newInteraction(kNoradFillingStationInteractionID);
}
void NoradAlpha::arriveAtNorad04() {
if (GameState.getCurrentDirection() == kEast && !GameState.getNoradGassed())
playDeathExtra(kNorad04EastDeath, kDeathWokeUpNorad);
}
void NoradAlpha::arriveAtNorad22() {
if (!GameState.getNoradN22MessagePlayed() && GameState.getCurrentDirection() == kSouth) {
startExtraSequence(kNorad22SouthIntro, kExtraCompletedFlag, kFilterNoInput);
GameState.setNoradN22MessagePlayed(true);
}
}
void NoradAlpha::turnTo(const DirectionConstant direction) {
Norad::turnTo(direction);
if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad01, kEast) && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA33", kArthurNoradAtSecurityMonitor);
}
void NoradAlpha::bumpIntoWall() {
requestSpotSound(kAlphaBumpIntoWallIn, kAlphaBumpIntoWallOut, kFilterNoInput, 0);
Neighborhood::bumpIntoWall();
}
void NoradAlpha::startExtraSequence(const ExtraID extraID, const NotificationFlags flags, const InputBits interruptionFilter) {
TimeValue segmentStart = 0, segmentStop = 0;
bool loopSequence = false;
Common::Rect pushBounds;
NotificationFlags extraFlags;
switch (extraID) {
case kShowThermalScan:
_turnPush.getBounds(pushBounds);
switch (extraID) {
case kShowThermalScan:
_extraMovie.initFromMovieFile("Images/Norad Alpha/N07NS.movie");
segmentStart = 0;
segmentStop = _extraMovie.getDuration();
loopSequence = false;
break;
default:
break;
}
_lastExtra = extraID;
_turnPush.hide();
if (!loopSequence && g_AIArea)
g_AIArea->lockAIOut();
extraFlags = flags;
_interruptionFilter = interruptionFilter;
// Stop the nav movie before doing anything else
_navMovie.stop();
_navMovie.stopDisplaying();
_extraMovie.setVolume(_vm->getSoundFXLevel());
_extraMovie.moveElementTo(pushBounds.left, pushBounds.top);
_extraMovie.setDisplayOrder(kNavMovieOrder + 1);
_extraMovie.startDisplaying();
_extraMovie.show();
_extraMovie.setFlags(0);
_extraMovie.setSegment(segmentStart, segmentStop);
_extraMovie.setTime(segmentStart);
if (loopSequence)
_extraMovie.setFlags(kLoopTimeBase);
else
extraFlags |= kNeighborhoodMovieCompletedFlag;
_extraMovieCallBack.cancelCallBack();
_extraMovieCallBack.initCallBack(&_extraMovie, kCallBackAtExtremes);
if (extraFlags != 0) {
_extraMovieCallBack.setCallBackFlag(extraFlags);
_extraMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
}
_extraMovie.start();
break;
default:
Neighborhood::startExtraSequence(extraID, flags, interruptionFilter);
break;
}
}
void NoradAlpha::receiveNotification(Notification *notification, const NotificationFlags flags) {
if ((flags & kExtraCompletedFlag) != 0) {
switch (_lastExtra) {
case kShowThermalScan:
_interruptionFilter = kFilterAllInput;
_extraMovie.stopDisplaying();
_extraMovie.releaseMovie();
_navMovie.startDisplaying();
break;
case kNorad19ExitToSub:
if (_vm->isDVD()) {
_interruptionFilter = kFilterAllInput;
_vm->_cursor->hide();
setNextHandler(_vm);
throwAwayInterface();
loadLoopSound1("");
newInteraction(kNoradSubChaseInteractionID);
GameState.setScoringEnteredSub(true);
}
break;
case kNoradArriveFromTSA:
GameState.setNoradSeenTimeStream(true);
loadAmbientLoops();
break;
case kNorad01RobotTaunt:
if (_vm->isChattyAI())
g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN01SB", false, kWarningInterruption);
_interruptionFilter = kFilterAllInput;
makeContinuePoint();
break;
default:
break;
}
}
Norad::receiveNotification(notification, flags);
if ((flags & kExtraCompletedFlag) != 0) {
switch (_lastExtra) {
case kNorad22SouthIntro:
loopExtraSequence(kNorad22SouthReply);
playSpotSoundSync(kN22ReplyIn, kN22ReplyOut);
startExtraSequence(kNorad22SouthFinish, kExtraCompletedFlag, kFilterNoInput);
break;
case kNorad22SouthFinish:
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB29", kArthurNoradSawSubMessage);
_interruptionFilter = kFilterAllInput;
// Force ArriveAt to do its thing...
GameState.setCurrentRoom(kNorad21);
arriveAt(kNorad22, kSouth);
break;
case kN22ClawFromAToB:
case kN22ClawAPinch:
case kN22ClawACounterclockwise:
case kN22ClawAClockwise:
case kN22ClawFromBToA:
case kN22ClawFromBToC:
case kN22ClawFromBToD:
case kN22ClawBPinch:
case kN22ClawBCounterclockwise:
case kN22ClawBClockwise:
case kN22ClawFromCToB:
case kN22ClawCPinch:
case kN22ClawCCounterclockwise:
case kN22ClawCClockwise:
case kN22ClawFromDToB:
case kN22ClawDPinch:
case kN22ClawDCounterclockwise:
case kN22ClawDClockwise:
if (g_arthurChip) {
if (_vm->getRandomBit())
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA64", kArthurNoradPlayedWithClaw);
else
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA66", kArthurNoradPlayedWithClaw);
}
break;
default:
break;
}
}
g_AIArea->checkMiddleArea();
}
void NoradAlpha::getZoomEntry(const HotSpotID spotID, ZoomTable::Entry &entry) {
Norad::getZoomEntry(spotID, entry);
ExtraTable::Entry extra;
if (spotID == kNorad01GasSpotID) {
if (_fillingStationItem) {
if (_fillingStationItem->getObjectID() == kGasCanister) {
getExtraEntry(kNorad01ZoomInWithGasCanister, extra);
entry.movieStart = extra.movieStart;
entry.movieEnd = extra.movieEnd;
} else {
entry.clear();
}
}
} else if (spotID == kNorad01GasOutSpotID) {
if (_fillingStationItem) {
if (_fillingStationItem->getObjectID() == kGasCanister) {
getExtraEntry(kNorad01ZoomOutWithGasCanister, extra);
entry.movieStart = extra.movieStart;
entry.movieEnd = extra.movieEnd;
} else {
entry.clear();
}
}
}
}
TimeValue NoradAlpha::getViewTime(const RoomID room, const DirectionConstant direction) {
ExtraTable::Entry entry;
if (room == kNorad01 && direction == kSouth && !GameState.getNoradSeenTimeStream()) {
getExtraEntry(kNoradArriveFromTSA, entry);
return entry.movieStart;
}
if (room == kNorad01 && direction == kWest) {
if (!_fillingStationItem) {
return Norad::getViewTime(room, direction);
} else {
getExtraEntry(kN01WGasCanister, entry);
return entry.movieStart;
}
} else if (room == kNorad01West && direction == kWest) {
uint32 extraID = 0xffffffff;
if (_fillingStationItem) {
switch (_fillingStationItem->getObjectID()) {
case kArgonCanister:
if (GameState.getNoradFillingStationOn())
extraID = kN01WZArgonCanisterLit;
else
extraID = kN01WZArgonCanisterDim;
break;
case kGasCanister:
if (GameState.getNoradFillingStationOn())
extraID = kN01WZGasCanisterLit;
else
extraID = kN01WZGasCanisterDim;
break;
case kAirMask:
if (GameState.getNoradFillingStationOn())
extraID = kN01WZAirMaskLit;
else
extraID = kN01WZAirMaskDim;
break;
case kNitrogenCanister:
if (GameState.getNoradFillingStationOn())
extraID = kN01WZNitrogenCanisterLit;
else
extraID = kN01WZNitrogenCanisterDim;
break;
default:
// Should never happen.
break;
}
} else if (GameState.getNoradFillingStationOn()) {
extraID = kN01WZEmptyLit;
}
if (extraID == 0xffffffff) {
return Norad::getViewTime(room, direction);
} else {
getExtraEntry(extraID, entry);
return entry.movieStart;
}
}
return Norad::getViewTime(room, direction);
}
void NoradAlpha::setSoundFXLevel(const uint16 level) {
Neighborhood::setSoundFXLevel(level);
if (_extraMovie.isMovieValid())
_extraMovie.setVolume(level);
}
void NoradAlpha::turnOnFillingStation() {
if (GameState.getCurrentRoom() == kNorad01West && !GameState.getNoradFillingStationOn()) {
GameState.setNoradFillingStationOn(true);
updateViewFrame();
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA72", kArthurNoradSawFillingStation);
}
}
void NoradAlpha::turnOffFillingStation() {
if (GameState.getCurrentRoom() == kNorad01West && GameState.getNoradFillingStationOn()) {
GameState.setNoradFillingStationOn(false);
updateViewFrame();
}
}
void NoradAlpha::activateHotspots() {
Norad::activateHotspots();
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kNorad01West, kWest):
if (_vm->getDragType() == kDragInventoryUse) {
if (!_fillingStationItem) {
ItemID itemID = _vm->getDraggingItem()->getObjectID();
if (itemID == kArgonCanister || itemID == kGasCanister || itemID == kAirMask ||
itemID == kNitrogenCanister)
_vm->getAllHotspots().activateOneHotspot(kN01GasOutletSpotID);
}
} else {
HotSpotID spotID;
if (_fillingStationItem) {
switch (_fillingStationItem->getObjectID()) {
case kArgonCanister:
spotID = kN01ArgonCanisterSpotID;
_vm->getAllHotspots().deactivateOneHotspot(kNorad01GasOutSpotID);
break;
case kGasCanister:
spotID = kN01GasCanisterSpotID;
break;
case kAirMask:
spotID = kN01AirMaskSpotID;
_vm->getAllHotspots().deactivateOneHotspot(kNorad01GasOutSpotID);
break;
case kNitrogenCanister:
spotID = kN01NitrogenCanisterSpotID;
_vm->getAllHotspots().deactivateOneHotspot(kNorad01GasOutSpotID);
break;
default:
// Should never happen.
spotID = kNoHotSpotID;
break;
}
_vm->getAllHotspots().activateOneHotspot(spotID);
}
}
break;
case MakeRoomView(kNorad07, kNorth):
if (_vm->isDVD())
_vm->getAllHotspots().activateOneHotspot(kThermalScanHotSpotID);
break;
case MakeRoomView(kNorad10, kEast):
if (GameState.isCurrentDoorOpen())
_vm->getAllHotspots().deactivateOneHotspot(kNorad10DoorSpotID);
break;
case MakeRoomView(kNorad21, kWest):
if (GameState.isCurrentDoorOpen())
_vm->getAllHotspots().deactivateOneHotspot(kNorad21WestSpotID);
break;
default:
break;
}
}
void NoradAlpha::clickInHotspot(const Input &input, const Hotspot *cursorSpot) {
Norad::clickInHotspot(input, cursorSpot);
if (_vm->getDragType() == kDragInventoryUse) {
if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad01West, kWest)) {
Item *item = _vm->getDraggingItem();
if (item->getObjectID() == kAirMask || item->getObjectID() == kArgonCanister ||
item->getObjectID() == kNitrogenCanister || item->getObjectID() == kGasCanister) {
HotspotInfoTable::Entry *hotspotEntry = findHotspotEntry(kN01GasOutletSpotID);
hotspotEntry->hotspotItem = item->getObjectID();
}
}
} else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad07, kNorth) &&
cursorSpot->getObjectID() == kThermalScanHotSpotID) {
startExtraSequence(kShowThermalScan, kExtraCompletedFlag, kFilterNoInput);
}
}
void NoradAlpha::takeItemFromRoom(Item *item) {
if (GameState.getCurrentRoom() == kNorad01West) {
if (_fillingStationItem == item) {
_fillingStationItem = nullptr;
GameState.setNoradGassed(false);
checkAirMask();
((NoradAlphaFillingStation *)_currentInteraction)->newFillingItem(nullptr);
forceStridingStop(kNorad03, kEast, kAltNoradAlphaNormal);
}
}
Norad::takeItemFromRoom(item);
}
void NoradAlpha::dropItemIntoRoom(Item *item, Hotspot *droppedSpot) {
if (GameState.getCurrentRoom() == kNorad01West) {
if (!_fillingStationItem) {
_fillingStationItem = item;
((NoradAlphaFillingStation *)_currentInteraction)->newFillingItem(item);
}
}
Norad::dropItemIntoRoom(item, droppedSpot);
}
void NoradAlpha::getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID, HotSpotID &clawControlSpotID, HotSpotID &pinchClawSpotID,
HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID, HotSpotID &moveClawLeftSpotID, HotSpotID &moveClawUpSpotID,
HotSpotID &clawCCWSpotID, HotSpotID &clawCWSpotID, uint32 &clawPosition, const uint32 *&clawExtraIDs) {
outSpotID = kNorad22MonitorOutSpotID;
prepSpotID = kNorad22LaunchPrepSpotID;
clawControlSpotID = kNorad22ClawControlSpotID;
pinchClawSpotID = kNorad22ClawPinchSpotID;
moveClawDownSpotID = kNorad22ClawDownSpotID;
moveClawRightSpotID = kNorad22ClawRightSpotID;
moveClawLeftSpotID = kNorad22ClawLeftSpotID;
moveClawUpSpotID = kNorad22ClawUpSpotID;
clawCCWSpotID = kNorad22ClawCCWSpotID;
clawCWSpotID = kNorad22ClawCWSpotID;
clawPosition = kClawAtD;
clawExtraIDs = _noradAlphaClawExtras;
}
Hotspot *NoradAlpha::getItemScreenSpot(Item *item, DisplayElement *element) {
switch (item->getObjectID()) {
case kGasCanister:
return _vm->getAllHotspots().findHotspotByID(kN01GasCanisterSpotID);
case kAirMask:
return _vm->getAllHotspots().findHotspotByID(kN01AirMaskSpotID);
case kArgonCanister:
return _vm->getAllHotspots().findHotspotByID(kN01ArgonCanisterSpotID);
case kNitrogenCanister:
return _vm->getAllHotspots().findHotspotByID(kN01NitrogenCanisterSpotID);
default:
break;
}
return Norad::getItemScreenSpot(item, element);
}
Common::Path NoradAlpha::getEnvScanMovie() {
Common::Path movieName = Neighborhood::getEnvScanMovie();
if (movieName.empty()) {
RoomID room = GameState.getCurrentRoom();
if (room >= kNorad01 && room <= kNorad01West)
return "Images/AI/Norad/XNE1";
else if ((room >= kNorad02 && room <= kNorad19West))
return "Images/AI/Norad/XNE2";
return "Images/AI/Norad/XNE3";
}
return movieName;
}
uint NoradAlpha::getNumHints() {
uint numHints = Neighborhood::getNumHints();
if (numHints == 0) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kNorad01, kNorth):
case MakeRoomView(kNorad01, kSouth):
case MakeRoomView(kNorad01, kEast):
case MakeRoomView(kNorad01, kWest):
case MakeRoomView(kNorad01East, kEast):
case MakeRoomView(kNorad01West, kWest):
if (GameState.getNoradGassed()) {
if (g_airMask->isAirFilterOn())
numHints = 0;
else
numHints = 3;
} else {
numHints = 2;
}
break;
case MakeRoomView(kNorad19West, kWest):
if (getSubPrepFailed() && GameState.getNoradSubPrepState() != kSubPrepped)
numHints = 1;
break;
case MakeRoomView(kNorad22, kWest):
numHints = 1;
break;
default:
break;
}
}
return numHints;
}
Common::Path NoradAlpha::getHintMovie(uint hintNum) {
Common::Path movieName = Neighborhood::getHintMovie(hintNum);
if (movieName.empty()) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kNorad01, kNorth):
case MakeRoomView(kNorad01, kSouth):
case MakeRoomView(kNorad01, kEast):
case MakeRoomView(kNorad01, kWest):
case MakeRoomView(kNorad01East, kEast):
case MakeRoomView(kNorad01West, kWest):
switch (hintNum) {
case 1:
if (GameState.getNoradGassed())
return "Images/AI/Norad/XN01SW";
return "Images/AI/Norad/XN01WD2";
case 2:
if (GameState.getNoradGassed()) {
if (_vm->playerHasItemID(kAirMask))
// Mask must not be on if we get here...
return "Images/AI/Globals/XGLOB1A";
return "Images/AI/Globals/XGLOB3D";
}
return "Images/AI/Globals/XGLOB5C";
case 3:
return "Images/AI/Norad/XN01SH";
default:
break;
}
break;
case MakeRoomView(kNorad19West, kWest):
return "Images/AI/Norad/XN19NH";
case MakeRoomView(kNorad22, kWest):
return "Images/AI/Globals/XGLOB1C";
default:
break;
}
}
return movieName;
}
void NoradAlpha::closeDoorOffScreen(const RoomID room, const DirectionConstant) {
switch (room) {
case kNorad12:
case kNorad13:
case kNorad18:
case kNorad19:
playSpotSoundSync(kAlphaElevatorDoorCloseIn, kAlphaElevatorDoorCloseOut);
break;
default:
playSpotSoundSync(kAlphaRegDoorCloseIn, kAlphaRegDoorCloseOut);
break;
}
}
void NoradAlpha::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &spotEntry) {
if (room == kNorad01 && direction == kSouth)
spotEntry.clear();
else
Norad::findSpotEntry(room, direction, flags, spotEntry);
}
bool NoradAlpha::canSolve() {
return Norad::canSolve() || getHintMovie(1) == "Images/AI/Norad/XN01SW";
}
void NoradAlpha::doSolve() {
Norad::doSolve();
if (getHintMovie(1) == "Images/AI/Norad/XN01SW") {
_vm->addItemToInventory(g_airMask);
g_airMask->putMaskOn();
}
}
Common::Path NoradAlpha::getNavMovieName() {
return "Images/Norad Alpha/Norad Alpha.movie";
}
Common::Path NoradAlpha::getSoundSpotsName() {
return "Sounds/Norad/Norad Alpha Spots";
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,126 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_NORADALPHA_H
#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_NORADALPHA_H
#include "pegasus/neighborhood/norad/norad.h"
namespace Pegasus {
class Item;
class SubChase;
class NoradAlpha : public Norad {
friend class SubChase;
public:
NoradAlpha(InputHandler *, PegasusEngine *);
~NoradAlpha() override;
void init() override;
void start() override;
bool okayToJump() override;
void playClawMonitorIntro() override;
void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &) override;
void turnOnFillingStation();
void turnOffFillingStation();
Item *getFillingItem() { return _fillingStationItem; }
bool gasCanisterIntake();
void takeItemFromRoom(Item *) override;
void dropItemIntoRoom(Item *, Hotspot *) override;
GameInteraction *makeInteraction(const InteractionID) override;
void getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID, HotSpotID &clawControlSpotID,
HotSpotID &pinchClawSpotID, HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID,
HotSpotID &moveClawLeftSpotID, HotSpotID &moveClawUpSpotID, HotSpotID &clawCCWSpotID,
HotSpotID &clawCWSpotID, uint32 &, const uint32 *&) override;
void loadAmbientLoops() override;
Common::Path getEnvScanMovie() override;
uint getNumHints() override;
Common::Path getHintMovie(uint) override;
void setUpAIRules() override;
void setSubPrepFailed(bool value) { _subPrepFailed = value; }
bool getSubPrepFailed() { return _subPrepFailed; }
void closeDoorOffScreen(const RoomID, const DirectionConstant) override;
void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &) override;
void clickInHotspot(const Input &, const Hotspot *) override;
void checkContinuePoint(const RoomID, const DirectionConstant) override;
void setSoundFXLevel(const uint16) override;
bool canSolve() override;
void doSolve() override;
protected:
static const uint32 _noradAlphaClawExtras[22];
virtual void arriveAtNorad01();
virtual void arriveAtNorad01East();
virtual void arriveAtNorad01West();
virtual void arriveAtNorad04();
virtual void arriveAtNorad22();
void arriveAt(const RoomID, const DirectionConstant) override;
void turnTo(const DirectionConstant) override;
void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void getZoomEntry(const HotSpotID, ZoomTable::Entry &) override;
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
void receiveNotification(Notification *, const NotificationFlags) override;
void activateHotspots() override;
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
void bumpIntoWall() override;
Hotspot _thermalScanSpot;
Movie _extraMovie;
NotificationCallBack _extraMovieCallBack;
Item *_fillingStationItem;
bool _subPrepFailed;
Common::Path getSoundSpotsName() override;
Common::Path getNavMovieName() override;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,238 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/macresman.h"
#include "common/stream.h"
#include "pegasus/neighborhood/norad/alpha/panorama.h"
namespace Pegasus {
Panorama::Panorama() : _panoramaMovie(kNoDisplayElement) {
blankFields();
}
Panorama::~Panorama() {
releasePanorama();
}
void Panorama::blankFields() {
_viewBounds = Common::Rect();
_drawBounds = Common::Rect();
_mask = nullptr;
_panoramaWidth = 0;
_panoramaHeight = 0;
_stripWidth = 0;
_stripLeft = -1;
_stripRight = -1;
}
void Panorama::releasePanorama() {
if (_panoramaMovie.isMovieValid()) {
_panoramaMovie.releaseMovie();
_panoramaWorld.deallocateSurface();
blankFields();
}
}
static const uint32 kPanoramaResType = MKTAG('P', 'a', 'n', 'I'); // Panorama Information.
static const uint16 kPanoramaResID = 128;
void Panorama::initFromMovieFile(const Common::Path &fileName) {
// First, we need the resource fork for other reasons -- PanI resource
Common::MacResManager *resFork = new Common::MacResManager();
if (!resFork->open(fileName) || !resFork->hasResFork())
error("Could not open the resource fork of '%s'", fileName.toString().c_str());
Common::SeekableReadStream *resource = resFork->getResource(kPanoramaResType, kPanoramaResID);
if (!resource)
error("No panorama information in the resource fork of '%s'", fileName.toString().c_str());
_panoramaWidth = resource->readUint16BE();
_panoramaHeight = resource->readUint16BE();
_stripWidth = resource->readUint16BE();
delete resource;
delete resFork;
// Now we open the movie like normal
_panoramaMovie.initFromMovieFile(fileName);
}
void Panorama::setMask(Surface *mask) {
_mask = mask;
}
// If the panorama is not open, do nothing and return.
// Otherwise, set up the view bounds.
void Panorama::setViewBounds(const Common::Rect &newView) {
if (!isPanoramaOpen())
return;
if (newView.isEmpty())
return;
Common::Rect r = newView;
if (r.width() > _panoramaWidth) {
r.left = 0;
r.right = _panoramaWidth;
} else {
if (r.right > _panoramaWidth)
r.translate(_panoramaWidth - r.right, 0);
if (r.left < 0)
r.translate(-r.left, 0);
}
if (r.height() > _panoramaHeight) {
r.top = 0;
r.bottom = _panoramaHeight;
} else {
if (r.bottom > _panoramaHeight)
r.translate(0, _panoramaHeight - r.bottom);
if (r.top < 0)
r.translate(0, -r.top);
}
if (_viewBounds != r) {
CoordType stripLeft = 0;
if (r.width() != _viewBounds.width() || !_panoramaWorld.isSurfaceValid()) {
_panoramaWorld.deallocateSurface();
makeNewSurface(r);
} else {
CoordType stripRight;
calcStripRange(r, stripLeft, stripRight);
loadStrips(stripLeft, stripRight);
}
_viewBounds = r;
_drawBounds = r;
_drawBounds.translate(-stripLeft * _stripWidth, 0);
}
}
void Panorama::getViewBounds(Common::Rect &r) const {
r = _viewBounds;
}
void Panorama::getPanoramaBounds(Common::Rect &r) const {
r = Common::Rect(0, 0, _panoramaWidth, _panoramaHeight);
}
void Panorama::drawPanorama(const Common::Rect &destRect) {
if (_panoramaWorld.isSurfaceValid()) {
if (_mask)
_panoramaWorld.copyToCurrentPortMasked(_drawBounds, destRect, _mask);
else
_panoramaWorld.copyToCurrentPortTransparent(_drawBounds, destRect);
}
}
// Make a new Surface big enough to show r, which is assumed to be a valid view bounds.
// Assumptions:
// r is a valid view bounds.
// _panoramaWorld is not allocated.
// _panoramaHeight, _stripWidth is correct.
// _panoramaMovie is allocated.
void Panorama::makeNewSurface(const Common::Rect& view) {
CoordType stripLeft, stripRight;
calcStripRange(view, stripLeft, stripRight);
Common::Rect r(0, 0, (stripRight - stripLeft + 1) * _stripWidth, _panoramaHeight);
_panoramaWorld.allocateSurface(r);
_panoramaMovie.shareSurface(&_panoramaWorld);
loadStrips(stripLeft, stripRight);
}
// Assumes view is not empty.
void Panorama::calcStripRange(const Common::Rect &view, CoordType &stripLeft, CoordType &stripRight) {
stripLeft = view.left / _stripWidth;
stripRight = (view.left - view.left % _stripWidth + _stripWidth - 1 + view.width()) / _stripWidth;
}
// Load in all needed strips to put range (stripLeft, stripRight) into the
// panorama's Surface. Try to optimize by saving any pixels already in the Surface.
// Assumptions:
// Surface is allocated and is big enough for maximum range of
// stripLeft and stripRight
void Panorama::loadStrips(CoordType stripLeft, CoordType stripRight) {
if (_stripLeft == -1) {
// Surface has just been allocated.
// Load in all strips.
for (CoordType i = stripLeft; i <= stripRight; i++)
loadOneStrip(i, stripLeft);
_stripLeft = stripLeft;
_stripRight = stripRight;
} else if (stripLeft != _stripLeft) {
CoordType overlapLeft = MAX(stripLeft, _stripLeft);
CoordType overlapRight = MIN(stripRight, _stripRight);
if (overlapLeft <= overlapRight) {
Common::Rect r1((overlapLeft - _stripLeft) * _stripWidth, 0,
(overlapRight - _stripLeft + 1) * _stripWidth, _panoramaHeight);
if (stripLeft < _stripLeft) {
Common::Rect bounds;
_panoramaWorld.getSurfaceBounds(bounds);
_panoramaWorld.getSurface()->move(bounds.right - r1.right, 0, _panoramaHeight);
for (CoordType i = stripLeft; i < _stripLeft; i++)
loadOneStrip(i, stripLeft);
} else {
_panoramaWorld.getSurface()->move(-r1.left, 0, _panoramaHeight);
for (CoordType i = _stripRight + 1; i <= stripRight; i++)
loadOneStrip(i, stripLeft);
}
} else {
// No overlap.
// Load everything.
for (CoordType i = stripLeft; i <= stripRight; i++)
loadOneStrip(i, stripLeft);
}
_stripLeft = stripLeft;
_stripRight = stripRight;
} else if (stripRight > _stripRight) {
// Need to add one or more strips.
for (CoordType i = _stripRight + 1; i <= stripRight; i++)
loadOneStrip(i, _stripLeft);
_stripRight = stripRight;
} else if (stripRight < _stripRight) {
// Need to chop off one strip.
_stripRight = stripRight;
}
}
void Panorama::loadOneStrip(CoordType stripToLoad, CoordType leftStrip) {
_panoramaMovie.moveMovieBoxTo((stripToLoad - leftStrip) * _stripWidth, 0);
_panoramaMovie.setTime(stripToLoad, 1);
_panoramaMovie.redrawMovieWorld();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,97 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMA_H
#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMA_H
#include "pegasus/movie.h"
namespace Pegasus {
/*
Panorama implements a wide image using a specially constructed movie file.
The movie holds the image as a series of vertical strips, say 16 or 32 pixels wide.
The panorama bounds defines the entire panorama. The view bounds represents the
area on the panorama that is kept in memory.
The panorama bounds is also stored in the movie file; it cannot be changed. The
view bounds must always be a subset of the panorama bounds.
In actuality, the area kept in memory is at least as wide as the view bounds (but
may be wider to coincide with the width of the movies slices), and is as tall as
the panorama bounds. The view bounds is used by the drawPanorama function to draw
a piece of the panorama to the current screen.
The panorama movie is built at a time scale of 1, with each strip lasting for one
second, so that strip number corresponds exactly with the time value at which the
strip is stored.
TO USE:
Call one initFromMovieFile to open the movie. Then set up a view rect by
calling setViewBounds. Once these two functions have been called, drawPanorama
will draw the panorama.
*/
class Panorama {
public:
Panorama();
virtual ~Panorama();
void initFromMovieFile(const Common::Path &);
void releasePanorama();
bool isPanoramaOpen() { return _panoramaMovie.isMovieValid(); }
void setViewBounds(const Common::Rect &);
void getViewBounds(Common::Rect &) const;
void setMask(Surface *);
void getPanoramaBounds(Common::Rect &) const;
void drawPanorama(const Common::Rect &);
protected:
void blankFields();
void makeNewSurface(const Common::Rect &);
void calcStripRange(const Common::Rect &, CoordType &, CoordType &);
void loadStrips(CoordType, CoordType);
void loadOneStrip(CoordType, CoordType);
Movie _panoramaMovie;
Surface _panoramaWorld, *_mask;
Common::Rect _viewBounds;
Common::Rect _drawBounds;
CoordType _panoramaWidth, _panoramaHeight;
CoordType _stripWidth; // Pixels per strip.
CoordType _numStrips;
CoordType _stripLeft, _stripRight;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,90 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/neighborhood/norad/alpha/panoramascroll.h"
namespace Pegasus {
PanoramaScroll::PanoramaScroll(const DisplayElementID id) : IdlerAnimation(id) {
_boundsWidth = 0;
_totalWidth = 0;
}
void PanoramaScroll::initFromMovieFile(const Common::Path &fileName) {
_panorama.initFromMovieFile(fileName);
Common::Rect r;
_panorama.getPanoramaBounds(r);
_totalWidth = r.width();
}
void PanoramaScroll::initMaskFromPICTFile(const Common::Path &fileName) {
if (!_panorama.isPanoramaOpen())
return;
_mask.getImageFromPICTFile(fileName);
_panorama.setMask(&_mask);
}
void PanoramaScroll::releasePanorama() {
if (_panorama.isPanoramaOpen())
_panorama.releasePanorama();
_mask.deallocateSurface();
}
void PanoramaScroll::setBounds(const Common::Rect &r) {
Animation::setBounds(r);
_boundsWidth = r.width();
Common::Rect r2;
_panorama.getViewBounds(r2);
r2.right = r2.left + _boundsWidth;
r2.bottom = r2.top + r.height();
_panorama.setViewBounds(r2);
}
void PanoramaScroll::draw(const Common::Rect &) {
_panorama.drawPanorama(_bounds);
}
void PanoramaScroll::timeChanged(const TimeValue newTime) {
CoordType leftPixel = (_totalWidth - _boundsWidth) * newTime / getDuration();
Common::Rect r;
_panorama.getViewBounds(r);
if (leftPixel != r.left) {
_panorama.getViewBounds(r);
r.moveTo(leftPixel, 0);
_panorama.setViewBounds(r);
triggerRedraw();
}
}
void PanoramaScroll::getPanoramaBounds(Common::Rect &r) const {
_panorama.getPanoramaBounds(r);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,59 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMASCROLL_H
#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMASCROLL_H
#include "pegasus/neighborhood/norad/alpha/panorama.h"
namespace Pegasus {
class PanoramaScroll : public IdlerAnimation {
public:
PanoramaScroll(const DisplayElementID);
~PanoramaScroll() override {}
void initFromMovieFile(const Common::Path &);
void initMaskFromPICTFile(const Common::Path &);
void releasePanorama();
bool isPanoramaOpen() { return _panorama.isPanoramaOpen(); }
void getPanoramaBounds(Common::Rect &) const;
void setBounds(const Common::Rect&) override;
void draw(const Common::Rect &) override;
protected:
void timeChanged(const TimeValue) override;
Panorama _panorama;
Surface _mask;
CoordType _totalWidth, _boundsWidth;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,458 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-2013 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/pegasus.h"
#include "pegasus/gamestate.h"
#include "pegasus/neighborhood/norad/alpha/subchase.h"
#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
#include "pegasus/neighborhood/norad/constants.h"
namespace Pegasus {
static const TimeScale kSubChaseScale = 600;
static const DisplayOrder kSubChaseOrder = 27000;
// Segment start and end points.
static const TimeValue kIntroStart = 0;
static const TimeValue kIntroEnd = 2400;
static const TimeValue kDialogStart = kIntroEnd;
static const TimeValue kDialogEnd = 20920;
static const TimeValue kBranch1Start = kDialogEnd;
static const TimeValue kBranch1End = 32120;
static const TimeValue kBranch2LeftStart = kBranch1End;
static const TimeValue kBranch2LeftEnd = 48080;
static const TimeValue kBranch3Start = kBranch2LeftEnd;
static const TimeValue kBranch3End = 61080;
static const TimeValue kBranch4Start = kBranch3End;
static const TimeValue kBranch4End = 84080;
static const TimeValue kBranch5Start = kBranch4End;
static const TimeValue kBranch5End = 94840;
static const TimeValue kBranch6Start = kBranch5End;
static const TimeValue kBranch6End = 106040;
static const TimeValue kBranch7LeftStart = kBranch6End;
static const TimeValue kBranch7LeftEnd = 118840;
static const TimeValue kExitStart = kBranch7LeftEnd;
static const TimeValue kExitEnd = 133200;
static const TimeValue kBranch2RightStart = 133200;
static const TimeValue kBranch2RightEnd = 149160;
static const TimeValue kBranch7RightStart = 168000;
static const TimeValue kBranch7RightEnd = 180800;
// Death start and end points.
static const TimeValue kDeath4Start = 149160;
static const TimeValue kDeath4End = 158040;
static const TimeValue kDeath5Start = kDeath4End;
static const TimeValue kDeath5End = 163760;
static const TimeValue kDeath6Start = kDeath5End;
static const TimeValue kDeath6End = 168000;
static const TimeValue kDeath7Start = 180800;
static const TimeValue kDeath7End = 187040;
// Chase state.
enum {
kSubDialog,
kSubBranch1,
kSubBranch2Left,
kSubBranch2Right,
kSubBranch3,
kSubBranch4,
kSubBranch5,
kSubBranch6,
kSubBranch7Left,
kSubBranch7Right,
kSubExit
};
void HintTimerEvent::fire() {
subChase->hintTimerExpired(*this);
}
void BlinkTimerEvent::fire() {
subChase->blinkTimerExpired(*this);
}
SubChase::SubChase(Neighborhood *handler) : ChaseInteraction(kNoradSubChaseInteractionID, handler,
kNoradSubChaseNotificationID, g_vm), _subMovie(kNoDisplayElement),
_hintPict(kNoDisplayElement), _blinkPict(kNoDisplayElement), _canSteerSub(true) {
}
void SubChase::setSoundFXLevel(const uint16 fxLevel) {
_subMovie.setVolume(fxLevel);
}
void SubChase::openInteraction() {
_subMovie.initFromMovieFile("Images/Norad Alpha/Sub Chase Movie");
_subMovie.setVolume(g_vm->getSoundFXLevel());
_subMovie.moveElementTo(0, 0);
_subMovie.setDisplayOrder(kSubChaseOrder);
_subMovie.startDisplaying();
_subMovie.show();
_subCallBack.setNotification(&_chaseNotification);
_subCallBack.initCallBack(&_subMovie, kCallBackAtExtremes);
ChaseInteraction::openInteraction();
_steerPict.setDisplayOrder(kSubChaseOrder + 1);
_steerPict.moveElementTo(kNoradSubSteerLeft, kNoradSubSteerTop);
_hintPict.initFromPICTFile("Images/Norad Alpha/Sub Chase steerk1.pict", true);
_hintPict.setDisplayOrder(kSubChaseOrder + 1);
_hintPict.moveElementTo(kNoradSubHintLeft, kNoradSubHintTop);
_blinkPict.initFromPICTFile("Images/Norad Alpha/Sub Chase steerk0.pict", true);
_blinkPict.setDisplayOrder(kSubChaseOrder + 1);
_blinkPict.moveElementTo(kNoradSubHintLeft, kNoradSubHintTop);
}
void SubChase::initInteraction() {
_canSteerSub = !GameState.getWalkthroughMode();
_owner->playMovieSegment(&_subMovie, kIntroStart, kIntroEnd);
_subCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
if (_canSteerSub) {
_steerPict.startDisplaying();
_hintPict.startDisplaying();
_blinkPict.startDisplaying();
startHintTimer(20000 - kDialogStart, kSubChaseScale, kStartedHint);
_subCallBack.setCallBackFlag(kChaseEnteredBranchZone);
_subMovie.setSegment(kDialogStart, kBranch1End - kDecisionTime);
} else {
_subCallBack.setCallBackFlag(kChaseFinished);
_subMovie.setSegment(kDialogStart, kExitEnd);
}
_subState = kSubDialog;
_subMovie.setTime(kDialogStart);
_subMovie.start();
ChaseInteraction::initInteraction();
}
void SubChase::closeInteraction() {
_subMovie.stop();
_subMovie.stopDisplaying();
_subMovie.releaseMovie();
_subCallBack.releaseCallBack();
_hintPict.hide();
_hintPict.deallocateSurface();
_blinkPict.hide();
_blinkPict.deallocateSurface();
ChaseInteraction::closeInteraction();
}
void SubChase::receiveNotification(Notification *notification, const NotificationFlags flags) {
if (notification == &_chaseNotification && flags == kChaseFinished) {
if (_subState != kSubDialog && _subState != kSubExit) {
// We died
((NoradAlpha *)_owner)->die(kDeathSubDestroyed);
} else {
_subMovie.stopDisplaying();
g_vm->_gfx->enableErase();
g_vm->_gfx->updateDisplay();
g_vm->_gfx->disableErase();
g_vm->jumpToNewEnvironment(kNoradDeltaID, kNorad41, kEast);
}
}
ChaseInteraction::receiveNotification(notification, flags);
}
void SubChase::handleInput(const Input &input, const Hotspot *cursorSpot) {
if (_subMovie.getTime() < kBranch1Start && input.anyInput()) {
if (_canSteerSub) {
if (!_blinkFuse.isFuseLit()) {
// If the hint is not blinking then it must not be running, so display it
_hintPict.show();
startBlinkTimer(10, 10, kEnteredBlinkState);
}
_subState = kSubBranch1;
startHintTimer(3000, kSubChaseScale, kEndedHint);
} else {
_subState = kSubExit;
}
_subMovie.setTime(kBranch1Start);
} else {
ChaseInteraction::handleInput(input, cursorSpot);
}
}
void SubChase::setUpBranch() {
TimeValue branchStart, branchEnd;
branchStart = 0;
branchEnd = 0;
switch (_subState) {
case kSubDialog:
case kSubBranch1:
branchStart = kBranch1End - kDecisionTime;
branchEnd = kBranch1End;
break;
case kSubBranch2Left:
branchStart = kBranch2LeftEnd - kDecisionTime;
branchEnd = kBranch2LeftEnd;
break;
case kSubBranch2Right:
branchStart = kBranch2RightEnd - kDecisionTime;
branchEnd = kBranch2RightEnd;
break;
case kSubBranch3:
branchStart = kBranch3End - kDecisionTime;
branchEnd = kBranch3End;
break;
case kSubBranch4:
branchStart = kBranch4End - kDecisionTime;
branchEnd = kBranch4End;
break;
case kSubBranch5:
branchStart = kBranch5End - kDecisionTime;
branchEnd = kBranch5End;
break;
case kSubBranch6:
branchStart = kBranch6End - kDecisionTime;
branchEnd = kBranch6End;
break;
case kSubBranch7Left:
branchStart = kBranch7LeftEnd - kDecisionTime;
branchEnd = kBranch7LeftEnd;
break;
case kSubBranch7Right:
branchStart = kBranch7RightEnd - kDecisionTime;
branchEnd = kBranch7RightEnd;
break;
default:
break;
}
_subMovie.setSegment(branchStart, branchEnd);
_subCallBack.setCallBackFlag(kChaseExitedBranchZone);
_subCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
}
void SubChase::branchLeft() {
TimeValue branchStart, branchEnd;
NotificationFlags flag;
branchStart = 0;
branchEnd = 0;
flag = 0;
switch (_subState) {
case kSubDialog:
case kSubBranch1:
branchStart = kBranch2LeftStart;
branchEnd = kBranch2LeftEnd;
// Don't show the controls hint when we approach the whale
// since the branch segments here are identical
flag = kChaseExitedBranchZone;
_subState = kSubBranch2Left;
break;
case kSubBranch2Left:
case kSubBranch2Right:
branchStart = kBranch3Start;
branchEnd = kBranch3End - kDecisionTime;
flag = kChaseEnteredBranchZone;
_subState = kSubBranch3;
break;
case kSubBranch3:
branchStart = kBranch4Start;
branchEnd = kBranch4End - kDecisionTime;
flag = kChaseEnteredBranchZone;
_subState = kSubBranch4;
break;
case kSubBranch4:
branchStart = kDeath5Start;
branchEnd = kDeath5End;
flag = kChaseFinished;
_subState = kSubBranch5;
break;
case kSubBranch5:
branchStart = kBranch6Start;
branchEnd = kBranch6End - kDecisionTime;
flag = kChaseEnteredBranchZone;
_subState = kSubBranch6;
break;
case kSubBranch6:
branchStart = kBranch7LeftStart;
branchEnd = kBranch7LeftEnd;
flag = kChaseExitedBranchZone;
_subState = kSubBranch7Left;
break;
case kSubBranch7Left:
case kSubBranch7Right:
branchStart = kExitStart;
branchEnd = kExitEnd;
flag = kChaseFinished;
_subState = kSubExit;
break;
default:
break;
}
_subMovie.setSegment(branchStart, branchEnd);
_subMovie.setTime(branchStart);
_subCallBack.setCallBackFlag(flag);
_subCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
}
void SubChase::branchRight() {
TimeValue branchStart, branchEnd;
NotificationFlags flag;
branchStart = 0;
branchEnd = 0;
flag = 0;
switch (_subState) {
case kSubDialog:
case kSubBranch1:
branchStart = kBranch2RightStart;
branchEnd = kBranch2RightEnd;
// Don't show the controls hint when we approach the whale
// since the branch segments here are identical
flag = kChaseExitedBranchZone;
_subState = kSubBranch2Right;
break;
case kSubBranch2Left:
case kSubBranch2Right:
branchStart = kBranch3Start;
branchEnd = kBranch3End - kDecisionTime;
flag = kChaseEnteredBranchZone;
_subState = kSubBranch3;
break;
case kSubBranch3:
branchStart = kDeath4Start;
branchEnd = kDeath4End;
flag = kChaseFinished;
_subState = kSubBranch4;
break;
case kSubBranch4:
branchStart = kBranch5Start;
branchEnd = kBranch5End - kDecisionTime;
flag = kChaseEnteredBranchZone;
_subState = kSubBranch5;
break;
case kSubBranch5:
branchStart = kDeath6Start;
branchEnd = kDeath6End;
flag = kChaseFinished;
_subState = kSubBranch6;
break;
case kSubBranch6:
if (g_vm->getRandomBit()) {
branchStart = kBranch7RightStart;
branchEnd = kBranch7RightEnd;
flag = kChaseExitedBranchZone;
} else {
branchStart = kDeath7Start;
branchEnd = kDeath7End;
flag = kChaseFinished;
}
_subState = kSubBranch7Right;
break;
case kSubBranch7Left:
case kSubBranch7Right:
branchStart = kExitStart;
branchEnd = kExitEnd;
flag = kChaseFinished;
_subState = kSubExit;
break;
default:
break;
}
_subMovie.setSegment(branchStart, branchEnd);
_subMovie.setTime(branchStart);
_subCallBack.setCallBackFlag(flag);
_subCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
}
void SubChase::dontBranch() {
if (g_vm->getRandomBit())
branchLeft();
else
branchRight();
}
void SubChase::startHintTimer(TimeValue time, TimeScale scale, HintTimerCode code) {
if (_canSteerSub) {
_hintFuse.primeFuse(time, scale);
_hintEvent.subChase = this;
_hintEvent.theEvent = code;
_hintFuse.setFunctor(new Common::Functor0Mem<void, HintTimerEvent>(&_hintEvent, &HintTimerEvent::fire));
_hintFuse.lightFuse();
}
}
void SubChase::hintTimerExpired(HintTimerEvent &event) {
switch (event.theEvent) {
case kStartedHint:
_hintPict.show();
startBlinkTimer(10, 10, kEnteredBlinkState);
startHintTimer(3920, kSubChaseScale, kEndedHint);
break;
case kEndedHint:
_hintPict.hide();
_blinkPict.hide();
_blinkFuse.stopFuse();
break;
default:
break;
}
}
void SubChase::startBlinkTimer(TimeValue time, TimeScale scale, BlinkTimerCode code) {
_blinkFuse.primeFuse(time, scale);
_blinkEvent.subChase = this;
_blinkEvent.theEvent = code;
_blinkFuse.setFunctor(new Common::Functor0Mem<void, BlinkTimerEvent>(&_blinkEvent, &BlinkTimerEvent::fire));
_blinkFuse.lightFuse();
}
void SubChase::blinkTimerExpired(BlinkTimerEvent &event) {
switch (event.theEvent) {
case kEnteredBlinkState:
_hintPict.hide();
_blinkPict.show();
startBlinkTimer(5, 10, kExitedBlinkState);
break;
case kExitedBlinkState:
_blinkPict.hide();
_hintPict.show();
startBlinkTimer(10, 10, kEnteredBlinkState);
break;
default:
break;
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,110 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-2013 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_SUBCHASE_H
#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_SUBCHASE_H
#include "pegasus/chase.h"
#include "pegasus/movie.h"
namespace Pegasus {
class NoradAlpha;
class SubChase;
enum HintTimerCode {
kStartedHint,
kEndedHint
};
struct HintTimerEvent {
SubChase *subChase;
HintTimerCode theEvent;
void fire();
};
enum BlinkTimerCode {
kEnteredBlinkState,
kExitedBlinkState
};
struct BlinkTimerEvent {
SubChase *subChase;
BlinkTimerCode theEvent;
void fire();
};
class SubChase : public ChaseInteraction {
friend class NoradAlpha;
friend struct HintTimerEvent;
friend struct BlinkTimerEvent;
public:
SubChase(Neighborhood *);
virtual ~SubChase() {}
void setSoundFXLevel(const uint16);
void handleInput(const Input &, const Hotspot *);
protected:
void openInteraction();
void initInteraction();
void closeInteraction();
void receiveNotification(Notification *, const NotificationFlags);
void startBranching();
void setUpBranch();
void branchLeft();
void branchRight();
void dontBranch();
void startHintTimer(TimeValue, TimeScale, HintTimerCode);
void hintTimerExpired(HintTimerEvent &);
void startBlinkTimer(TimeValue, TimeScale, BlinkTimerCode);
void blinkTimerExpired(BlinkTimerEvent &);
Movie _subMovie;
NotificationCallBack _subCallBack;
Picture _hintPict;
Picture _blinkPict;
FuseFunction _hintFuse;
FuseFunction _blinkFuse;
HintTimerEvent _hintEvent;
BlinkTimerEvent _blinkEvent;
short _subState;
bool _canSteerSub;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,762 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_CONSTANTS_H
#define PEGASUS_NEIGHBORHOOD_NORAD_CONSTANTS_H
#include "pegasus/constants.h"
namespace Pegasus {
// Norad Alpha spot constants
static const TimeValue kAlphaBumpIntoWallIn = 0;
static const TimeValue kAlphaBumpIntoWallOut = 303;
static const TimeValue kAlphaAccessDeniedIn = 303;
static const TimeValue kAlphaAccessDeniedOut = 3045;
static const TimeValue kAlphaRegDoorCloseIn = 3045;
static const TimeValue kAlphaRegDoorCloseOut = 4476;
static const TimeValue kAlphaElevatorDoorCloseIn = 4476;
static const TimeValue kAlphaElevatorDoorCloseOut = 5071;
static const TimeValue kAlphaCantTransportIn = 5071;
static const TimeValue kAlphaCantTransportOut = 9348;
static const TimeValue kAlphaPressureDoorIntro1In = 9348;
static const TimeValue kAlphaPressureDoorIntro1Out = 11061;
static const TimeValue kAlphaPressureDoorIntro2In = 11061;
static const TimeValue kAlphaPressureDoorIntro2Out = 14098;
static const TimeValue kN22ReplyIn = 14098;
static const TimeValue kN22ReplyOut = 18442;
static const TimeValue kAlphaLoadClawIntroIn = 18442;
static const TimeValue kAlphaLoadClawIntroOut = 20698;
// Norad Delta spot constants
static const TimeValue kDeltaBumpIntoWallIn = 0;
static const TimeValue kDeltaBumpIntoWallOut = 303;
static const TimeValue kDeltaAccessDeniedIn = 303;
static const TimeValue kDeltaAccessDeniedOut = 3045;
static const TimeValue kDeltaRegDoorCloseIn = 3045;
static const TimeValue kDeltaRegDoorCloseOut = 4476;
static const TimeValue kDeltaElevatorDoorCloseIn = 4476;
static const TimeValue kDeltaElevatorDoorCloseOut = 5071;
static const TimeValue kPressureDoorIntro1In = 5071;
static const TimeValue kPressureDoorIntro1Out = 6784;
static const TimeValue kPressureDoorIntro2In = 6784;
static const TimeValue kPressureDoorIntro2Out = 9821;
static const TimeValue kLoadClawIntroIn = 9821;
static const TimeValue kLoadClawIntroOut = 12077;
static const TimeValue kHoldForRetinalIn = 12077;
static const TimeValue kHoldForRetinalOut = 14104;
static const TimeValue kRetinalScanFailedIn = 14104;
static const TimeValue kRetinalScanFailedOut = 17538;
static const TimeValue kAddisAbabaIn = 17538;
static const TimeValue kAddisAbabaOut = 19263;
static const TimeValue kBangkokIn = 19263;
static const TimeValue kBangkokOut = 20201;
static const TimeValue kBonnIn = 20201;
static const TimeValue kBonnOut = 20915;
static const TimeValue kDublinIn = 20915;
static const TimeValue kDublinOut = 21660;
static const TimeValue kHonoluluIn = 21660;
static const TimeValue kHonoluluOut = 22498;
static const TimeValue kMadridIn = 22498;
static const TimeValue kMadridOut = 23474;
static const TimeValue kReykjavikIn = 23474;
static const TimeValue kReykjavikOut = 24488;
static const TimeValue kSanAntonioIn = 24488;
static const TimeValue kSanAntonioOut = 25561;
static const TimeValue kSeoulIn = 25561;
static const TimeValue kSeoulOut = 26461;
static const TimeValue kSvortalskIn = 26461;
static const TimeValue kSvortalskOut = 27582;
static const TimeValue kSiloBeepIn = 27582;
static const TimeValue kSiloBeepOut = 27721;
static const TimeValue kAllSilosDeactivatedIn = 27721;
static const TimeValue kAllSilosDeactivatedOut = 28928;
static const TimeValue kGlobalLaunchOverrideIn = 28928;
static const TimeValue kGlobalLaunchOverrideOut = 30736;
static const TimeValue kLaunchSiloSelectedIn = 30736;
static const TimeValue kLaunchSiloSelectedOut = 31660;
static const TimeValue kLaunchToProceedIn = 31660;
static const TimeValue kLaunchToProceedOut = 32536;
static const TimeValue kMaximumDeactivationIn = 32536;
static const TimeValue kMaximumDeactivationOut = 34337;
static const TimeValue kMissileLaunchedIn = 34337;
static const TimeValue kMissileLaunchedOut = 35082;
static const TimeValue kNewLaunchSiloIn = 35082;
static const TimeValue kNewLaunchSiloOut = 36320;
static const TimeValue kStrikeAuthorizedIn = 36320;
static const TimeValue kStrikeAuthorizedOut = 37393;
static const TimeValue kPrimaryTargetIn = 37393;
static const TimeValue kPrimaryTargetOut = 38628;
static const TimeValue kSiloDeactivatedIn = 38628;
static const TimeValue kSiloDeactivatedOut = 39566;
static const TimeValue kStrikeCodeRejectedIn = 39566;
static const TimeValue kStrikeCodeRejectedOut = 41056;
static const TimeValue kToDeactivateIn = 41056;
static const TimeValue kToDeactivateOut = 46494;
static const TimeValue kTwoMinutesIn = 46494;
static const TimeValue kTwoMinutesOut = 47166;
static const TimeValue kOneMinuteIn = 47166;
static const TimeValue kOneMinuteOut = 47856;
static const TimeValue kFiftySecondsIn = 47856;
static const TimeValue kFiftySecondsOut = 48691;
static const TimeValue kFortySecondsIn = 48691;
static const TimeValue kFortySecondsOut = 49500;
static const TimeValue kThirtySecondsIn = 49500;
static const TimeValue kThirtySecondsOut = 50362;
static const TimeValue kTwentySecondsIn = 50362;
static const TimeValue kTwentySecondsOut = 51245;
static const TimeValue kTenSecondsIn = 51245;
static const TimeValue kTenSecondsOut = 52069;
static const TimeValue kGiveUpHumanIn = 52069;
static const TimeValue kGiveUpHumanOut = 55023;
static const TimeValue kIJustBrokeIn = 55023;
static const TimeValue kIJustBrokeOut = 59191;
static const TimeValue kTheOnlyGoodHumanIn = 59191;
static const TimeValue kTheOnlyGoodHumanOut = 62379;
static const TimeValue kYouAreRunningIn = 62379;
static const TimeValue kYouAreRunningOut = 64201;
static const TimeValue kYouCannotPossiblyIn = 64201;
static const TimeValue kYouCannotPossiblyOut = 65740;
static const TimeValue kYouWillFailIn = 65740;
static const TimeValue kYouWillFailOut = 67217;
static const CanOpenDoorReason kCantOpenBadPressure = kCantOpenLastReason + 1;
static const NotificationFlags kAirTimerExpiredFlag = kLastNeighborhoodNotificationFlag << 1;
static const uint16 kNoradWarningVolume = 0x100 / 3;
static const uint16 kNoradSuckWindVolume = 0x100 / 2;
static const int16 kElevatorCompassAngle = -40;
static const int16 kSubPlatformCompassAngle = 45;
static const int16 kSubControlCompassAngle = -10;
// Norad interactions.
static const InteractionID kNoradGlobeGameInteractionID = 0;
static const InteractionID kNoradECRMonitorInteractionID = 1;
static const InteractionID kNoradFillingStationInteractionID = 2;
static const InteractionID kNoradElevatorInteractionID = 3;
static const InteractionID kNoradPressureDoorInteractionID = 4;
static const InteractionID kNoradSubControlRoomInteractionID = 5;
static const InteractionID kNoradSubPlatformInteractionID = 6;
static const InteractionID kNoradSubChaseInteractionID = 7;
/////////////////////////////////////////////
//
// Norad Alpha
static const CoordType kECRSlideShowLeft = kNavAreaLeft + 78;
static const CoordType kECRSlideShowTop = kNavAreaTop + 1;
static const CoordType kECRPanLeft = kNavAreaLeft + 78 + 5;
static const CoordType kECRPanTop = kNavAreaTop + 1 + 4;
static const CoordType kECRPanRight = kECRPanLeft + 213;
static const CoordType kECRPanBottom = kECRPanTop + 241;
static const CoordType kNoradAlphaElevatorControlsLeft = kNavAreaLeft + 332;
static const CoordType kNoradAlphaElevatorControlsTop = kNavAreaTop + 127;
static const CoordType kNoradAlpha01LeftSideLeft = kNavAreaLeft + 0;
static const CoordType kNoradAlpha01LeftSideTop = kNavAreaTop + 0;
static const CoordType kNoradAlpha01RightSideLeft = kNavAreaLeft + 240;
static const CoordType kNoradAlpha01RightSideTop = kNavAreaTop + 12;
static const CoordType kNoradUpperLevelsLeft = kNavAreaLeft + 98;
static const CoordType kNoradUpperLevelsTop = kNavAreaTop + 31;
static const CoordType kNoradUpperTypeLeft = kNoradUpperLevelsLeft + 114;
static const CoordType kNoradUpperTypeTop = kNoradUpperLevelsTop + 8;
static const CoordType kNoradUpperUpLeft = kNavAreaLeft + 361;
static const CoordType kNoradUpperUpTop = kNavAreaTop + 32;
static const CoordType kNoradUpperDownLeft = kNavAreaLeft + 367;
static const CoordType kNoradUpperDownTop = kNavAreaTop + 66;
static const CoordType kNoradLowerLevelsLeft = kNavAreaLeft + 74;
static const CoordType kNoradLowerLevelsTop = kNavAreaTop + 157;
static const CoordType kNoradLowerTypeLeft = kNoradLowerLevelsLeft + 144;
static const CoordType kNoradLowerTypeTop = kNoradLowerLevelsTop + 9;
static const CoordType kNoradLowerUpLeft = kNavAreaLeft + 380;
static const CoordType kNoradLowerUpTop = kNavAreaTop + 164;
static const CoordType kNoradLowerDownLeft = kNavAreaLeft + 388;
static const CoordType kNoradLowerDownTop = kNavAreaTop + 212;
static const CoordType kNoradPlatformLeft = kNavAreaLeft + 36;
static const CoordType kNoradPlatformTop = kNavAreaTop + 87;
static const CoordType kNoradSubSteerLeft = 288;
static const CoordType kNoradSubSteerTop = 28;
static const CoordType kNoradSubHintLeft = 480;
static const CoordType kNoradSubHintTop = 240;
static const CoordType kNoradSubControlLeft = kNavAreaLeft + 0;
static const CoordType kNoradSubControlTop = kNavAreaTop + 84;
static const CoordType kNoradSubControlPinchLeft = kNoradSubControlLeft + 106;
static const CoordType kNoradSubControlPinchTop = kNoradSubControlTop + 86;
static const CoordType kNoradSubControlDownLeft = kNoradSubControlLeft + 66;
static const CoordType kNoradSubControlDownTop = kNoradSubControlTop + 106;
static const CoordType kNoradSubControlRightLeft = kNoradSubControlLeft + 83;
static const CoordType kNoradSubControlRightTop = kNoradSubControlTop + 90;
static const CoordType kNoradSubControlLeftLeft = kNoradSubControlLeft + 56;
static const CoordType kNoradSubControlLeftTop = kNoradSubControlTop + 91;
static const CoordType kNoradSubControlUpLeft = kNoradSubControlLeft + 66;
static const CoordType kNoradSubControlUpTop = kNoradSubControlTop + 81;
static const CoordType kNoradSubControlCCWLeft = kNoradSubControlLeft + 29;
static const CoordType kNoradSubControlCCWTop = kNoradSubControlTop + 88;
static const CoordType kNoradSubControlCWLeft = kNoradSubControlLeft + 0;
static const CoordType kNoradSubControlCWTop = kNoradSubControlTop + 89;
static const CoordType kNoradClawMonitorLeft = kNavAreaLeft + 288;
static const CoordType kNoradClawMonitorTop = kNavAreaTop + 97;
static const CoordType kNoradGreenBallAtALeft = kNoradClawMonitorLeft + 179;
static const CoordType kNoradGreenBallAtATop = kNoradClawMonitorTop + 82;
static const CoordType kNoradGreenBallAtBLeft = kNoradClawMonitorLeft + 130;
static const CoordType kNoradGreenBallAtBTop = kNoradClawMonitorTop + 73;
static const CoordType kNoradGreenBallAtCLeft = kNoradClawMonitorLeft + 110;
static const CoordType kNoradGreenBallAtCTop = kNoradClawMonitorTop + 26;
static const CoordType kNoradGreenBallAtDLeft = kNoradClawMonitorLeft + 21;
static const CoordType kNoradGreenBallAtDTop = kNoradClawMonitorTop + 49;
/////////////////////////////////////////////
//
// Norad Delta
static const CoordType kGlobeMonitorLeft = kNavAreaLeft + 360;
static const CoordType kGlobeMonitorTop = kNavAreaTop + 144;
static const CoordType kGlobeLeft = kNavAreaLeft + 172;
static const CoordType kGlobeTop = kNavAreaTop;
static const CoordType kGlobeCircleLeftLeft = kNavAreaLeft + 186;
static const CoordType kGlobeCircleLeftTop = kNavAreaTop + 41;
static const CoordType kGlobeCircleRightLeft = kNavAreaLeft + 321;
static const CoordType kGlobeCircleRightTop = kNavAreaTop + 41;
static const CoordType kGlobeCircleUpLeft = kNavAreaLeft + 220;
static const CoordType kGlobeCircleUpTop = kNavAreaTop + 7;
static const CoordType kGlobeCircleDownLeft = kNavAreaLeft + 220;
static const CoordType kGlobeCircleDownTop = kNavAreaTop + 142;
static const CoordType kGlobeUpperLeftHiliteLeft = kNavAreaLeft + 207;
static const CoordType kGlobeUpperLeftHiliteTop = kNavAreaTop + 28;
static const CoordType kGlobeUpperRightHiliteLeft = kNavAreaLeft + 307;
static const CoordType kGlobeUpperRightHiliteTop = kNavAreaTop + 28;
static const CoordType kGlobeLowerLeftHiliteLeft = kNavAreaLeft + 207;
static const CoordType kGlobeLowerLeftHiliteTop = kNavAreaTop + 128;
static const CoordType kGlobeLowerRightHiliteLeft = kNavAreaLeft + 307;
static const CoordType kGlobeLowerRightHiliteTop = kNavAreaTop + 128;
static const CoordType kGlobeLeftMotionHiliteLeft = kNavAreaLeft + 182;
static const CoordType kGlobeLeftMotionHiliteTop = kNavAreaTop + 60;
static const CoordType kGlobeRightMotionHiliteLeft = kNavAreaLeft + 331;
static const CoordType kGlobeRightMotionHiliteTop = kNavAreaTop + 60;
static const CoordType kGlobeUpMotionHiliteLeft = kNavAreaLeft + 239;
static const CoordType kGlobeUpMotionHiliteTop = kNavAreaTop + 3;
static const CoordType kGlobeDownMotionHiliteLeft = kNavAreaLeft + 239;
static const CoordType kGlobeDownMotionHiliteTop = kNavAreaTop + 152;
static const CoordType kGlobeUpperNamesLeft = kNavAreaLeft + 368;
static const CoordType kGlobeUpperNamesTop = kNavAreaTop + 188;
static const CoordType kGlobeLowerNamesLeft = kNavAreaLeft + 368;
static const CoordType kGlobeLowerNamesTop = kNavAreaTop + 212;
static const CoordType kGlobeCountdownLeft = kNavAreaLeft + 478;
static const CoordType kGlobeCountdownTop = kNavAreaTop + 164;
// Norad Alpha display IDs.
static const DisplayElementID kECRSlideShowMovieID = kNeighborhoodDisplayID;
static const DisplayElementID kECRPanID = kECRSlideShowMovieID + 1;
static const DisplayElementID kNoradAlphaDeathMovieID = kECRPanID + 1;
static const DisplayElementID kNoradElevatorControlsID = kNoradAlphaDeathMovieID + 1;
static const DisplayElementID kN01LeftSideID = kNoradElevatorControlsID + 1;
static const DisplayElementID kN01RightSideID = kN01LeftSideID + 1;
static const DisplayElementID kPressureDoorLevelsID = kN01RightSideID + 1;
static const DisplayElementID kPressureDoorTypeID = kPressureDoorLevelsID + 1;
static const DisplayElementID kPressureDoorUpButtonID = kPressureDoorTypeID + 1;
static const DisplayElementID kPressureDoorDownButtonID = kPressureDoorUpButtonID + 1;
static const DisplayElementID kPlatformMonitorID = kPressureDoorDownButtonID + 1;
static const DisplayElementID kSubControlMonitorID = kPlatformMonitorID + 1;
static const DisplayElementID kClawMonitorID = kSubControlMonitorID + 1;
static const DisplayElementID kSubControlPinchID = kClawMonitorID + 1;
static const DisplayElementID kSubControlDownID = kSubControlPinchID + 1;
static const DisplayElementID kSubControlRightID = kSubControlDownID + 1;
static const DisplayElementID kSubControlLeftID = kSubControlRightID + 1;
static const DisplayElementID kSubControlUpID = kSubControlLeftID + 1;
static const DisplayElementID kSubControlCCWID = kSubControlUpID + 1;
static const DisplayElementID kSubControlCWID = kSubControlCCWID + 1;
static const DisplayElementID kClawMonitorGreenBallID = kSubControlCWID + 1;
// Norad Delta display IDs.
static const DisplayElementID kGlobeRobotID = kNeighborhoodDisplayID;
static const DisplayElementID kGlobeMonitorID = kGlobeRobotID + 1;
static const DisplayElementID kGlobeMovieID = kGlobeMonitorID + 1;
static const DisplayElementID kGlobeCircleLeftID = kGlobeMovieID + 1;
static const DisplayElementID kGlobeCircleRightID = kGlobeCircleLeftID + 1;
static const DisplayElementID kGlobeCircleUpID = kGlobeCircleRightID + 1;
static const DisplayElementID kGlobeCircleDownID = kGlobeCircleUpID + 1;
static const DisplayElementID kMotionHiliteLeftID = kGlobeCircleDownID + 1;
static const DisplayElementID kMotionHiliteRightID = kMotionHiliteLeftID + 1;
static const DisplayElementID kMotionHiliteUpID = kMotionHiliteRightID + 1;
static const DisplayElementID kMotionHiliteDownID = kMotionHiliteUpID + 1;
static const DisplayElementID kTargetHiliteUpperLeftID = kMotionHiliteDownID + 1;
static const DisplayElementID kTargetHiliteUpperRightID = kTargetHiliteUpperLeftID + 1;
static const DisplayElementID kTargetHiliteLowerLeftID = kTargetHiliteUpperRightID + 1;
static const DisplayElementID kTargetHiliteLowerRightID = kTargetHiliteLowerLeftID + 1;
static const DisplayElementID kGlobeUpperNamesID = kTargetHiliteLowerRightID + 1;
static const DisplayElementID kGlobeLowerNamesID = kGlobeUpperNamesID + 1;
static const DisplayElementID kGlobeCountdownID = kGlobeLowerNamesID + 1;
// Norad Alpha:
static const DisplayOrder kECRMonitorOrder = kMonitorLayer;
static const DisplayOrder kECRPanOrder = kECRMonitorOrder + 1;
static const DisplayOrder kN01LeftSideOrder = kMonitorLayer;
static const DisplayOrder kN01RightSideOrder = kN01LeftSideOrder + 1;
static const DisplayOrder kElevatorControlsOrder = kMonitorLayer;
static const DisplayOrder kPressureLevelsOrder = kMonitorLayer;
static const DisplayOrder kPressureTypeOrder = kPressureLevelsOrder + 1;
static const DisplayOrder kPressureUpOrder = kPressureTypeOrder + 1;
static const DisplayOrder kPressureDownOrder = kPressureUpOrder + 1;
static const DisplayOrder kPlatformOrder = kMonitorLayer;
static const DisplayOrder kSubControlOrder = kMonitorLayer;
static const DisplayOrder kClawMonitorOrder = kSubControlOrder + 1;
static const DisplayOrder kSubControlPinchOrder = kClawMonitorOrder + 1;
static const DisplayOrder kSubControlDownOrder = kSubControlPinchOrder + 1;
static const DisplayOrder kSubControlRightOrder = kSubControlDownOrder + 1;
static const DisplayOrder kSubControlLeftOrder = kSubControlRightOrder + 1;
static const DisplayOrder kSubControlUpOrder = kSubControlLeftOrder + 1;
static const DisplayOrder kSubControlCCWOrder = kSubControlUpOrder + 1;
static const DisplayOrder kSubControlCWOrder = kSubControlCCWOrder + 1;
static const DisplayOrder kClawMonitorGreenBallOrder = kSubControlCWOrder + 1;
// Norad Delta:
static const DisplayOrder kGlobeMonitorLayer = kMonitorLayer;
static const DisplayOrder kGlobeMovieLayer = kGlobeMonitorLayer + 1;
static const DisplayOrder kGlobeCircleLayer = kGlobeMovieLayer + 1;
static const DisplayOrder kGlobeHilitesLayer = kGlobeCircleLayer + 1;
static const DisplayOrder kGlobeUpperNamesLayer = kGlobeHilitesLayer + 1;
static const DisplayOrder kGlobeLowerNamesLayer = kGlobeUpperNamesLayer + 1;
static const DisplayOrder kGlobeCountdownLayer = kGlobeLowerNamesLayer + 1;
// Norad Alpha Tables
static const TimeScale kNoradAlphaMovieScale = 600;
static const TimeScale kNoradAlphaFramesPerSecond = 15;
static const TimeScale kNoradAlphaFrameDuration = 40;
// Alternate IDs.
static const AlternateID kAltNoradAlphaNormal = 0;
// Room IDs.
static const RoomID kNorad01 = 0;
static const RoomID kNorad01East = 1;
static const RoomID kNorad01West = 2;
static const RoomID kNorad02 = 3;
static const RoomID kNorad03 = 4;
static const RoomID kNorad04 = 5;
static const RoomID kNorad05 = 6;
static const RoomID kNorad06 = 7;
static const RoomID kNorad07 = 8;
static const RoomID kNorad07North = 9;
static const RoomID kNorad08 = 10;
static const RoomID kNorad09 = 11;
static const RoomID kNorad10 = 12;
static const RoomID kNorad10East = 13;
static const RoomID kNorad11 = 14;
static const RoomID kNorad11South = 15;
static const RoomID kNorad12 = 16;
static const RoomID kNorad12South = 17;
static const RoomID kNorad13 = 18;
static const RoomID kNorad14 = 19;
static const RoomID kNorad15 = 20;
static const RoomID kNorad16 = 21;
static const RoomID kNorad17 = 22;
static const RoomID kNorad18 = 23;
static const RoomID kNorad19 = 24;
static const RoomID kNorad19West = 25;
static const RoomID kNorad21 = 26;
static const RoomID kNorad21West = 27;
static const RoomID kNorad22 = 28;
static const RoomID kNorad22West = 29;
// Hot Spot Activation IDs.
// Hot Spot IDs.
static const HotSpotID kNorad01ECRSpotID = 5000;
static const HotSpotID kNorad01GasSpotID = 5001;
static const HotSpotID kNorad01ECROutSpotID = 5002;
static const HotSpotID kNorad01GasOutSpotID = 5003;
static const HotSpotID kNorad01MonitorSpotID = 5004;
static const HotSpotID kNorad01IntakeSpotID = 5005;
static const HotSpotID kNorad01DispenseSpotID = 5006;
static const HotSpotID kNorad01ArSpotID = 5007;
static const HotSpotID kNorad01CO2SpotID = 5008;
static const HotSpotID kNorad01HeSpotID = 5009;
static const HotSpotID kNorad01OSpotID = 5010;
static const HotSpotID kNorad01NSpotID = 5011;
static const HotSpotID kN01GasCanisterSpotID = 5012;
static const HotSpotID kN01ArgonCanisterSpotID = 5013;
static const HotSpotID kN01AirMaskSpotID = 5014;
static const HotSpotID kN01NitrogenCanisterSpotID = 5015;
static const HotSpotID kN01GasOutletSpotID = 5016;
static const HotSpotID kNorad07DoorSpotID = 5017;
static const HotSpotID kNorad07DoorOutSpotID = 5018;
static const HotSpotID kNorad10DoorSpotID = 5019;
static const HotSpotID kNorad10EastOutSpotID = 5020;
static const HotSpotID kAlphaUpperPressureDoorUpSpotID = 5021;
static const HotSpotID kAlphaUpperPressureDoorDownSpotID = 5022;
static const HotSpotID kNorad11ElevatorSpotID = 5023;
static const HotSpotID kNorad11ElevatorOutSpotID = 5024;
static const HotSpotID kNorad11ElevatorDownSpotID = 5025;
static const HotSpotID kNorad12ElevatorSpotID = 5026;
static const HotSpotID kNorad12ElevatorOutSpotID = 5027;
static const HotSpotID kNorad12ElevatorUpSpotID = 5028;
static const HotSpotID kNorad19MonitorSpotID = 5029;
static const HotSpotID kNorad19MonitorOutSpotID = 5030;
static const HotSpotID kNorad19ActivateMonitorSpotID = 5031;
static const HotSpotID kNorad21WestSpotID = 5032;
static const HotSpotID kNorad21WestOutSpotID = 5033;
static const HotSpotID kAlphaLowerPressureDoorUpSpotID = 5034;
static const HotSpotID kAlphaLowerPressureDoorDownSpotID = 5035;
static const HotSpotID kNorad22MonitorSpotID = 5036;
static const HotSpotID kNorad22MonitorOutSpotID = 5037;
static const HotSpotID kNorad22LaunchPrepSpotID = 5038;
static const HotSpotID kNorad22ClawControlSpotID = 5039;
static const HotSpotID kNorad22ClawPinchSpotID = 5040;
static const HotSpotID kNorad22ClawDownSpotID = 5041;
static const HotSpotID kNorad22ClawRightSpotID = 5042;
static const HotSpotID kNorad22ClawLeftSpotID = 5043;
static const HotSpotID kNorad22ClawUpSpotID = 5044;
static const HotSpotID kNorad22ClawCCWSpotID = 5045;
static const HotSpotID kNorad22ClawCWSpotID = 5046;
// Extra sequence IDs.
static const ExtraID kNoradArriveFromTSA = 0;
static const ExtraID kNorad01RobotTaunt = 1;
static const ExtraID kNorad01ZoomInWithGasCanister = 2;
static const ExtraID kN01WGasCanister = 3;
static const ExtraID kNorad01ZoomOutWithGasCanister = 4;
static const ExtraID kN01WZEmptyLit = 5;
static const ExtraID kN01WZGasCanisterDim = 6;
static const ExtraID kN01WZGasCanisterLit = 7;
static const ExtraID kN01WZArgonCanisterDim = 8;
static const ExtraID kN01WZArgonCanisterLit = 9;
static const ExtraID kN01WZAirMaskDim = 10;
static const ExtraID kN01WZAirMaskLit = 11;
static const ExtraID kN01WZNitrogenCanisterDim = 12;
static const ExtraID kN01WZNitrogenCanisterLit = 13;
static const ExtraID kNorad04EastDeath = 14;
static const ExtraID kNorad19PrepSub = 15;
static const ExtraID kNorad19ExitToSub = 16;
static const ExtraID kNorad22SouthIntro = 17;
static const ExtraID kNorad22SouthReply = 18;
static const ExtraID kNorad22SouthFinish = 19;
static const ExtraID kN22ClawFromAToB = 20;
static const ExtraID kN22ClawALoop = 21;
static const ExtraID kN22ClawAPinch = 22;
static const ExtraID kN22ClawACounterclockwise = 23;
static const ExtraID kN22ClawAClockwise = 24;
static const ExtraID kN22ClawFromBToA = 25;
static const ExtraID kN22ClawFromBToC = 26;
static const ExtraID kN22ClawFromBToD = 27;
static const ExtraID kN22ClawBLoop = 28;
static const ExtraID kN22ClawBPinch = 29;
static const ExtraID kN22ClawBCounterclockwise = 30;
static const ExtraID kN22ClawBClockwise = 31;
static const ExtraID kN22ClawFromCToB = 32;
static const ExtraID kN22ClawCLoop = 33;
static const ExtraID kN22ClawCPinch = 34;
static const ExtraID kN22ClawCCounterclockwise = 35;
static const ExtraID kN22ClawCClockwise = 36;
static const ExtraID kN22ClawFromDToB = 37;
static const ExtraID kN22ClawDLoop = 38;
static const ExtraID kN22ClawDPinch = 39;
static const ExtraID kN22ClawDCounterclockwise = 40;
static const ExtraID kN22ClawDClockwise = 41;
// Norad Delta Extra sequence IDs.
static const ExtraID kArriveFromSubChase = 0;
static const ExtraID kN59ZoomWithRobot = 1;
static const ExtraID kN59RobotApproaches = 2;
static const ExtraID kN59RobotPunchLoop = 3;
static const ExtraID kN59PlayerWins1 = 4;
static const ExtraID kN59PlayerWins2 = 5;
static const ExtraID kN59RobotWins = 6;
static const ExtraID kN59RobotHeadOpens = 7;
static const ExtraID kN59Biochips111 = 8;
static const ExtraID kN59Biochips011 = 9;
static const ExtraID kN59Biochips101 = 10;
static const ExtraID kN59Biochips001 = 11;
static const ExtraID kN59Biochips110 = 12;
static const ExtraID kN59Biochips010 = 13;
static const ExtraID kN59Biochips100 = 14;
static const ExtraID kN59Biochips000 = 15;
static const ExtraID kN59RobotDisappears = 16;
static const ExtraID kN60ClawFromAToB = 17;
static const ExtraID kN60ClawALoop = 18;
static const ExtraID kN60ClawAPinch = 19;
static const ExtraID kN60ClawACounterclockwise = 20;
static const ExtraID kN60ClawAClockwise = 21;
static const ExtraID kN60ClawFromBToA = 22;
static const ExtraID kN60ClawFromBToC = 23;
static const ExtraID kN60ClawFromBToD = 24;
static const ExtraID kN60ClawBLoop = 25;
static const ExtraID kN60ClawBPinch = 26;
static const ExtraID kN60ClawBCounterclockwise = 27;
static const ExtraID kN60ClawBClockwise = 28;
static const ExtraID kN60ClawFromCToB = 29;
static const ExtraID kN60ClawCLoop = 30;
static const ExtraID kN60ClawCPinch = 31;
static const ExtraID kN60ClawCCounterclockwise = 32;
static const ExtraID kN60ClawCClockwise = 33;
static const ExtraID kN60ClawFromDToB = 34;
static const ExtraID kN60ClawDLoop = 35;
static const ExtraID kN60ClawDPinch = 36;
static const ExtraID kN60ClawDCounterclockwise = 37;
static const ExtraID kN60ClawDClockwise = 38;
static const ExtraID kN60RobotApproaches = 39;
static const ExtraID kN60FirstMistake = 40;
static const ExtraID kN60ArmActivated = 41;
static const ExtraID kN60SecondMistake = 42;
static const ExtraID kN60ArmToPositionB = 43;
static const ExtraID kN60ThirdMistake = 44;
static const ExtraID kN60ArmGrabsRobot = 45;
static const ExtraID kN60FourthMistake = 46;
static const ExtraID kN60ArmCarriesRobotToPositionA = 47;
static const ExtraID kN60PlayerFollowsRobotToDoor = 48;
static const ExtraID kN60RobotHeadOpens = 49;
static const ExtraID kN60Biochips111 = 50;
static const ExtraID kN60Biochips011 = 51;
static const ExtraID kN60Biochips101 = 52;
static const ExtraID kN60Biochips001 = 53;
static const ExtraID kN60Biochips110 = 54;
static const ExtraID kN60Biochips010 = 55;
static const ExtraID kN60Biochips100 = 56;
static const ExtraID kN60Biochips000 = 57;
static const ExtraID kN60RobotDisappears = 58;
static const ExtraID kNoradDeltaRetinalScanBad = 59;
static const ExtraID kNoradDeltaRetinalScanGood = 60;
static const ExtraID kN79BrightView = 61;
// Norad Delta Tables
static const TimeScale kNoradDeltaMovieScale = 600;
static const TimeScale kNoradDeltaFramesPerSecond = 15;
static const TimeScale kNoradDeltaFrameDuration = 40;
// Alternate IDs.
static const AlternateID kAltNoradDeltaNormal = 0;
// Room IDs.
static const RoomID kNorad41 = 0;
static const RoomID kNorad42 = 1;
static const RoomID kNorad43 = 2;
static const RoomID kNorad44 = 3;
static const RoomID kNorad45 = 4;
static const RoomID kNorad46 = 5;
static const RoomID kNorad47 = 6;
static const RoomID kNorad48 = 7;
static const RoomID kNorad48South = 8;
static const RoomID kNorad49 = 9;
static const RoomID kNorad49South = 10;
static const RoomID kNorad50 = 11;
static const RoomID kNorad50East = 12;
static const RoomID kNorad51 = 13;
static const RoomID kNorad52 = 14;
static const RoomID kNorad53 = 15;
static const RoomID kNorad54 = 16;
static const RoomID kNorad54North = 17;
static const RoomID kNorad55 = 18;
static const RoomID kNorad56 = 19;
static const RoomID kNorad57 = 20;
static const RoomID kNorad58 = 21;
static const RoomID kNorad59 = 22;
static const RoomID kNorad59West = 23;
static const RoomID kNorad60 = 24;
static const RoomID kNorad60West = 25;
static const RoomID kNorad61 = 26;
static const RoomID kNorad62 = 27;
static const RoomID kNorad63 = 28;
static const RoomID kNorad64 = 29;
static const RoomID kNorad65 = 30;
static const RoomID kNorad66 = 31;
static const RoomID kNorad67 = 32;
static const RoomID kNorad68 = 33;
static const RoomID kNorad68West = 34;
static const RoomID kNorad69 = 35;
static const RoomID kNorad78 = 36;
static const RoomID kNorad79 = 37;
static const RoomID kNorad79West = 38;
// Hot Spot Activation IDs.
// Hot Spot IDs.
static const HotSpotID kNorad48ElevatorSpotID = 5000;
static const HotSpotID kNorad48ElevatorOutSpotID = 5001;
static const HotSpotID kNorad48ElevatorUpSpotID = 5002;
static const HotSpotID kNorad49ElevatorSpotID = 5003;
static const HotSpotID kNorad49ElevatorOutSpotID = 5004;
static const HotSpotID kNorad49ElevatorDownSpotID = 5005;
static const HotSpotID kNorad50DoorSpotID = 5006;
static const HotSpotID kNorad50DoorOutSpotID = 5007;
static const HotSpotID kDeltaUpperPressureDoorUpSpotID = 5008;
static const HotSpotID kDeltaUpperPressureDoorDownSpotID = 5009;
static const HotSpotID kNorad54DoorSpotID = 5010;
static const HotSpotID kNorad54DoorOutSpotID = 5011;
static const HotSpotID kNorad59WestSpotID = 5012;
static const HotSpotID kNorad59WestOutSpotID = 5013;
static const HotSpotID kDeltaLowerPressureDoorUpSpotID = 5014;
static const HotSpotID kDeltaLowerPressureDoorDownSpotID = 5015;
static const HotSpotID kDelta59RobotHeadSpotID = 5016;
static const HotSpotID kDelta59RobotShieldBiochipSpotID = 5017;
static const HotSpotID kDelta59RobotOpMemBiochipSpotID = 5018;
static const HotSpotID kDelta59RobotRetinalBiochipSpotID = 5019;
static const HotSpotID kNorad60MonitorSpotID = 5020;
static const HotSpotID kNorad60MonitorOutSpotID = 5021;
static const HotSpotID kNorad60LaunchPrepSpotID = 5022;
static const HotSpotID kNorad60ClawControlSpotID = 5023;
static const HotSpotID kNorad60ClawPinchSpotID = 5024;
static const HotSpotID kNorad60ClawDownSpotID = 5025;
static const HotSpotID kNorad60ClawRightSpotID = 5026;
static const HotSpotID kNorad60ClawLeftSpotID = 5027;
static const HotSpotID kNorad60ClawUpSpotID = 5028;
static const HotSpotID kNorad60ClawCCWSpotID = 5029;
static const HotSpotID kNorad60ClawCWSpotID = 5030;
static const HotSpotID kDelta60RobotHeadSpotID = 5031;
static const HotSpotID kDelta60RobotShieldBiochipSpotID = 5032;
static const HotSpotID kDelta60RobotOpMemBiochipSpotID = 5033;
static const HotSpotID kDelta60RobotRetinalBiochipSpotID = 5034;
static const HotSpotID kNorad68WestSpotID = 5035;
static const HotSpotID kNorad68WestOutSpotID = 5036;
static const HotSpotID kNorad79WestSpotID = 5037;
static const HotSpotID kNorad79WestOutSpotID = 5038;
static const HotSpotID kNorad79SpinLeftSpotID = 5039;
static const HotSpotID kNorad79SpinRightSpotID = 5040;
static const HotSpotID kNorad79SpinUpSpotID = 5041;
static const HotSpotID kNorad79SpinDownSpotID = 5042;
static const HotSpotID kNorad79SiloAreaSpotID = 5043;
} // End of namespace Pegasus
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,172 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_DELTA_GLOBEGAME_H
#define PEGASUS_NEIGHBORHOOD_NORAD_DELTA_GLOBEGAME_H
#include "pegasus/interaction.h"
#include "pegasus/movie.h"
#include "pegasus/notification.h"
namespace Pegasus {
enum GlobeTrackDirection {
kTrackLeft,
kTrackRight,
kTrackUp,
kTrackDown
};
// This class assumes that the globe movie is built at 15 frames per second with a
// time scale of 600, yielding 40 time unit per frame.
class GlobeTracker : public Tracker {
public:
GlobeTracker(Movie *, Picture *, Picture *, Picture *, Picture *);
~GlobeTracker() override {}
void setTrackParameters(const Hotspot *, GlobeTrackDirection);
void continueTracking(const Input &) override;
void startTracking(const Input &) override;
void stopTracking(const Input &) override;
void activateHotspots() override;
bool stopTrackingInput(const Input &) override;
protected:
void trackGlobeMovie();
void stopGlobeMovie();
Movie *_globeMovie;
Picture *_leftHighlight;
Picture *_rightHighlight;
Picture *_upHighlight;
Picture *_downHighlight;
const Hotspot *_trackSpot;
int _trackTime;
GlobeTrackDirection _trackDirection;
};
class GlobeCountdown : public IdlerAnimation {
public:
GlobeCountdown(const DisplayElementID);
~GlobeCountdown() override {}
void setCountdownTime(const int);
void startCountdown();
void stopCountdown();
void setDisplayOrder(const DisplayOrder);
void show() override;
void hide() override;
void moveElementTo(const CoordType, const CoordType) override;
void draw(const Common::Rect &) override;
protected:
Surface _digits;
int16 _digitOffset;
};
static const int16 kNumAllSilos = 40;
static const int16 kNumTargetSilos = 10;
static const int16 kNumLongSlices = 72;
class GlobeGame : public GameInteraction, public NotificationReceiver {
public:
GlobeGame(Neighborhood *);
~GlobeGame() override {}
void setSoundFXLevel(const uint16) override;
void handleInput(const Input &, const Hotspot *) override;
void clickInHotspot(const Input &, const Hotspot *) override;
void activateHotspots() override;
bool canSolve() override;
void doSolve() override;
struct Point3D {
float x, y, z;
};
struct Line3D {
Point3D pt1, pt2;
};
protected:
// Latitude (-90 - 90) and longitude (-180 - 180)
static const int16 _siloCoords[kNumAllSilos][2];
static const int16 _targetSilo[kNumTargetSilos];
static const int16 _timeLimit[kNumTargetSilos];
static const TimeValue _siloName[kNumTargetSilos][2];
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void receiveNotification(Notification *, const NotificationFlags) override;
void spinGlobe(const Input &, const Hotspot *, GlobeTrackDirection);
void clickGlobe(const Input &);
int16 findClickedSilo(const Input &);
void globeMovieFrameToOrigin(int16, int16 &, int16 &);
void globePointToLatLong(const Point3D &, int16, int16, int16 &, int16 &);
void screenPointTo3DPoint(int16, int16, Point3D &);
bool lineHitsGlobe(const Line3D &, Point3D &);
Movie _robotMovie;
Movie _monitorMovie;
Movie _globeMovie;
Movie _upperNamesMovie;
Movie _lowerNamesMovie;
Notification _globeNotification;
NotificationCallBack _robotCallBack;
NotificationCallBack _monitorCallBack;
GlobeTracker _globeTracker;
Picture _globeCircleLeft;
Picture _globeCircleRight;
Picture _globeCircleUp;
Picture _globeCircleDown;
Picture _motionHighlightLeft;
Picture _motionHighlightRight;
Picture _motionHighlightUp;
Picture _motionHighlightDown;
Picture _targetHighlightUpperLeft;
Picture _targetHighlightUpperRight;
Picture _targetHighlightLowerLeft;
Picture _targetHighlightLowerRight;
GlobeCountdown _countdown;
NotificationCallBack _countdownCallBack;
int16 _gameState;
int16 _currentSiloIndex;
Notification *_neighborhoodNotification;
bool _playedInstructions;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,984 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
#include "pegasus/interface.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/opticalchip.h"
#include "pegasus/items/biochips/retscanchip.h"
#include "pegasus/items/inventory/airmask.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/subcontrolroom.h"
#include "pegasus/neighborhood/norad/delta/globegame.h"
#include "pegasus/neighborhood/norad/delta/noraddelta.h"
namespace Pegasus {
const uint32 NoradDelta::_noradDeltaClawExtras[22] = {
kN60ClawFromAToB,
kN60ClawALoop,
kN60ClawAPinch,
kN60ClawACounterclockwise,
kN60ClawAClockwise,
kN60ClawFromBToA,
kN60ClawFromBToC,
kN60ClawFromBToD,
kN60ClawBLoop,
kN60ClawBPinch,
kN60ClawBCounterclockwise,
kN60ClawBClockwise,
kN60ClawFromCToB,
kN60ClawCLoop,
kN60ClawCPinch,
kN60ClawCCounterclockwise,
kN60ClawCClockwise,
kN60ClawFromDToB,
kN60ClawDLoop,
kN60ClawDPinch,
kN60ClawDCounterclockwise,
kN60ClawDClockwise
};
NoradDelta::NoradDelta(InputHandler *nextHandler, PegasusEngine *owner) : Norad(nextHandler, owner, "Norad Delta", kNoradDeltaID) {
_elevatorUpRoomID = kNorad49South;
_elevatorDownRoomID = kNorad48South;
_elevatorUpSpotID = kNorad48ElevatorUpSpotID;
_elevatorDownSpotID = kNorad49ElevatorDownSpotID;
// Pressure door stuff.
_subRoomEntryRoom1 = kNorad50;
_subRoomEntryDir1 = kEast;
_subRoomEntryRoom2 = kNorad59;
_subRoomEntryDir2 = kWest;
_upperPressureDoorRoom = kNorad50East;
_lowerPressureDoorRoom = kNorad59West;
_upperPressureDoorUpSpotID = kDeltaUpperPressureDoorUpSpotID;
_upperPressureDoorDownSpotID = kDeltaUpperPressureDoorDownSpotID;
_upperPressureDoorAbortSpotID = kNorad50DoorOutSpotID;
_lowerPressureDoorUpSpotID = kDeltaLowerPressureDoorUpSpotID;
_lowerPressureDoorDownSpotID = kDeltaLowerPressureDoorDownSpotID;
_lowerPressureDoorAbortSpotID = kNorad59WestOutSpotID;
_pressureSoundIn = kPressureDoorIntro1In;
_pressureSoundOut = kPressureDoorIntro1Out;
_equalizeSoundIn = kPressureDoorIntro2In;
_equalizeSoundOut = kPressureDoorIntro2Out;
_accessDeniedIn = kDeltaAccessDeniedIn;
_accessDeniedOut = kDeltaAccessDeniedOut;
GameState.setNoradSubPrepState(kSubDamaged);
_subControlRoom = kNorad60West;
}
void NoradDelta::init() {
Norad::init();
// Little fix for the retinal scan zoom in spot...
Hotspot *hotspot = _vm->getAllHotspots().findHotspotByID(kNorad68WestSpotID);
hotspot->setMaskedHotspotFlags(kZoomInSpotFlag, kZoomInSpotFlag | kZoomOutSpotFlag);
hotspot = _vm->getAllHotspots().findHotspotByID(kNorad79WestSpotID);
hotspot->setMaskedHotspotFlags(kZoomInSpotFlag, kZoomInSpotFlag | kZoomOutSpotFlag);
hotspot = _vm->getAllHotspots().findHotspotByID(kDelta59RobotShieldBiochipSpotID);
hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
HotspotInfoTable::Entry *hotspotEntry = findHotspotEntry(kDelta59RobotShieldBiochipSpotID);
hotspotEntry->hotspotItem = kShieldBiochip;
hotspot = _vm->getAllHotspots().findHotspotByID(kDelta59RobotOpMemBiochipSpotID);
hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
hotspotEntry = findHotspotEntry(kDelta59RobotOpMemBiochipSpotID);
hotspotEntry->hotspotItem = kOpticalBiochip;
hotspot = _vm->getAllHotspots().findHotspotByID(kDelta59RobotRetinalBiochipSpotID);
hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
hotspotEntry = findHotspotEntry(kDelta59RobotRetinalBiochipSpotID);
hotspotEntry->hotspotItem = kRetinalScanBiochip;
hotspot = _vm->getAllHotspots().findHotspotByID(kDelta60RobotShieldBiochipSpotID);
hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
hotspotEntry = findHotspotEntry(kDelta60RobotShieldBiochipSpotID);
hotspotEntry->hotspotItem = kShieldBiochip;
hotspot = _vm->getAllHotspots().findHotspotByID(kDelta60RobotOpMemBiochipSpotID);
hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
hotspotEntry = findHotspotEntry(kDelta60RobotOpMemBiochipSpotID);
hotspotEntry->hotspotItem = kOpticalBiochip;
hotspot = _vm->getAllHotspots().findHotspotByID(kDelta60RobotRetinalBiochipSpotID);
hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
hotspotEntry = findHotspotEntry(kDelta60RobotRetinalBiochipSpotID);
hotspotEntry->hotspotItem = kRetinalScanBiochip;
}
void NoradDelta::start() {
if (g_energyMonitor) {
g_energyMonitor->stopEnergyDraining();
g_energyMonitor->restoreLastEnergyValue();
_vm->resetEnergyDeathReason();
g_energyMonitor->startEnergyDraining();
}
Norad::start();
}
void NoradDelta::setUpAIRules() {
Neighborhood::setUpAIRules();
if (g_AIArea) {
AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Norad/XN07NE", false);
AILocationCondition *locCondition = new AILocationCondition(1);
locCondition->addLocation(MakeRoomView(kNorad68, kWest));
AIRule *rule = new AIRule(locCondition, messageAction);
g_AIArea->addAIRule(rule);
}
}
void NoradDelta::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) {
switch (entry.extra) {
case kArriveFromSubChase:
compassMove.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, entry.movieStart, 20, entry.movieEnd, 90);
compassMove.insertFaderKnot(entry.movieStart + 25 * kNoradDeltaFrameDuration, 20);
compassMove.insertFaderKnot(entry.movieStart + 94 * kNoradDeltaFrameDuration, 45);
compassMove.insertFaderKnot(entry.movieStart + 101 * kNoradDeltaFrameDuration, 45);
compassMove.insertFaderKnot(entry.movieStart + 146 * kNoradDeltaFrameDuration, 90 + 15);
compassMove.insertFaderKnot(entry.movieStart + 189 * kNoradDeltaFrameDuration, 90 + 15);
compassMove.insertFaderKnot(entry.movieStart + 204 * kNoradDeltaFrameDuration, 90 + 30);
compassMove.insertFaderKnot(entry.movieStart + 214 * kNoradDeltaFrameDuration, 90 + 20);
compassMove.insertFaderKnot(entry.movieStart + 222 * kNoradDeltaFrameDuration, 90 + 20);
compassMove.insertFaderKnot(entry.movieStart + 228 * kNoradDeltaFrameDuration, 90 + 10);
compassMove.insertFaderKnot(entry.movieStart + 245 * kNoradDeltaFrameDuration, 90 + 85);
compassMove.insertFaderKnot(entry.movieStart + 262 * kNoradDeltaFrameDuration, 90 + 70);
compassMove.insertFaderKnot(entry.movieStart + 273 * kNoradDeltaFrameDuration, 90 + 80);
compassMove.insertFaderKnot(entry.movieStart + 287 * kNoradDeltaFrameDuration, 90);
break;
case kN60PlayerFollowsRobotToDoor:
compassMove.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, entry.movieStart, 270 + kSubControlCompassAngle,
entry.movieEnd, 270 - 15);
compassMove.insertFaderKnot(entry.movieStart + 280, 270 + kSubControlCompassAngle);
compassMove.insertFaderKnot(entry.movieStart + 920, 360);
compassMove.insertFaderKnot(entry.movieStart + 1840, 360);
compassMove.insertFaderKnot(entry.movieStart + 2520, 270);
compassMove.insertFaderKnot(entry.movieStart + 3760, 270);
compassMove.insertFaderKnot(entry.movieStart + 4640, 270 + kSubControlCompassAngle);
break;
case kN59PlayerWins2:
compassMove.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, entry.movieStart, 270, entry.movieEnd, 280);
compassMove.insertFaderKnot(entry.movieEnd - 1000, 270);
// fall through
// FIXME: fall through intentional?
default:
Norad::getExtraCompassMove(entry, compassMove);
break;
}
}
GameInteraction *NoradDelta::makeInteraction(const InteractionID interactionID) {
if (interactionID == kNoradGlobeGameInteractionID)
return new GlobeGame(this);
return Norad::makeInteraction(interactionID);
}
void NoradDelta::playClawMonitorIntro() {
playSpotSoundSync(kLoadClawIntroIn, kLoadClawIntroOut);
}
void NoradDelta::getExitEntry(const RoomID room, const DirectionConstant direction, ExitTable::Entry &entry) {
Norad::getExitEntry(room, direction, entry);
if (room == kNorad61 && direction == kSouth)
entry.movieStart += kNoradDeltaFrameDuration;
}
void NoradDelta::getZoomEntry(const HotSpotID id, ZoomTable::Entry &zoomEntry) {
Norad::getZoomEntry(id, zoomEntry);
if (id == kNorad59WestSpotID && GameState.getNoradPlayedGlobeGame()) {
ExtraTable::Entry extraEntry;
getExtraEntry(kN59ZoomWithRobot, extraEntry);
zoomEntry.movieStart = extraEntry.movieStart;
zoomEntry.movieEnd = extraEntry.movieEnd;
}
}
void NoradDelta::loadAmbientLoops() {
/*
Logic:
loop sound 1:
if room == kNorad79West
if player globe game
play kNoradGlobeLoop2SoundNum
else
play kNoradRedAlertLoopSoundNum
else if room >= kNorad78 && room <= kNorad79
play kNoradGlobeLoop2SoundNum
else if gassed,
if room >= kNorad41 && room <= kNorad49South
play kNoradNewSubLoopSoundNum, kNoradWarningVolume
else if room >= kNorad59 && room <= kNorad60West
play kNoradSubControlLoopSoundNum, kNoradWarningVolume
else
play kNoradWarningLoopSoundNum, kNoradWarningVolume
else
play nothing
loop sound 2:
if gassed and not wearing air mask
if room == kNorad54North
play breathing unmanned loop
else
play breathing
else
if room == kNorad54North
play unmanned loop
else
play nothing
*/
if (GameState.getNoradArrivedFromSub()) {
RoomID room = GameState.getCurrentRoom();
if (room >= kNorad78 && room <= kNorad79West) {
if (GameState.getNoradPlayedGlobeGame()) {
// blitter moved clone2727's globe room loop fix up here
// since the original didn't play the red alert sound during the
// globe game.
// clone2727 added this fix so we can play the correct sound
// with the DVD version. This originally loaded it into slot 2,
// which in addition to having the corrupted sound on the disk,
// caused it to never play.
if (_vm->isDVD())
loadLoopSound1("Sounds/Norad/GlobAmb2.32K.AIFF");
else
loadLoopSound1("Sounds/Norad/GlobAmb2.22K.AIFF");
} else
loadLoopSound1("Sounds/Norad/RedAlert.22K.AIFF");
} else if (GameState.getNoradGassed()) {
if (room >= kNorad41 && room <= kNorad49South) {
if (_vm->isDVD())
loadLoopSound1("Sounds/Norad/NEW SUB AMB.44K.AIFF", kNoradWarningVolume * 3);
else
loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", kNoradWarningVolume * 3);
} else if (room >= kNorad59 && room <= kNorad60West) {
if (_vm->isDVD())
loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.32K.AIFF", kNoradWarningVolume * 3);
else
loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.22K.AIFF", kNoradWarningVolume * 3);
} else {
if (_vm->isDVD())
loadLoopSound1("Sounds/Norad/WARNING LOOP.32K.AIFF", kNoradWarningVolume);
else
loadLoopSound1("Sounds/Norad/WARNING LOOP.22K.AIFF", kNoradWarningVolume);
}
} else {
loadLoopSound1("");
}
if (GameState.getNoradGassed() && !g_airMask->isAirFilterOn()) {
if (room == kNorad54North)
loadLoopSound2("Sounds/Norad/Breathing Typing.22K.AIFF", 0x100 / 2);
else
loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", kNoradSuckWindVolume, 0, 0);
} else {
if (room == kNorad54North) {
if (_vm->isDVD())
loadLoopSound2("Sounds/Norad/N54NAS.32K.AIFF", 0x100 / 2);
else
loadLoopSound2("Sounds/Norad/N54NAS.22K.AIFF", 0x100 / 2);
} else
loadLoopSound2("");
}
} else {
// Start them off at zero...
if (GameState.getNoradGassed()) {
if (_vm->isDVD())
loadLoopSound1("Sounds/Norad/NEW SUB AMB.44K.AIFF", 0, 0, 0);
else
loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", 0, 0, 0);
}
if (!g_airMask->isAirFilterOn())
loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", 0, 0, 0);
}
}
void NoradDelta::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
switch (MakeRoomView(room, direction)) {
case MakeRoomView(kNorad41, kEast):
case MakeRoomView(kNorad49, kEast):
case MakeRoomView(kNorad49, kWest):
case MakeRoomView(kNorad61, kSouth):
case MakeRoomView(kNorad68, kEast):
case MakeRoomView(kNorad79, kWest):
makeContinuePoint();
break;
default:
break;
}
}
void NoradDelta::arriveAt(const RoomID room, const DirectionConstant direction) {
if (room != kNorad68)
GameState.setNoradRetScanGood(false);
Norad::arriveAt(room, direction);
FaderMoveSpec loop1Spec, loop2Spec;
ExtraTable::Entry entry;
switch (room) {
case kNorad41:
if (direction == kEast) {
if (!GameState.getNoradArrivedFromSub()) {
GameState.setNoradPlayedGlobeGame(false);
GameState.setNoradBeatRobotWithClaw(false);
GameState.setNoradBeatRobotWithDoor(false);
GameState.setNoradRetScanGood(false);
GameState.setScoringExitedSub(true);
getExtraEntry(kArriveFromSubChase, entry);
loop1Spec.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, 0, 0, entry.movieEnd -
entry.movieStart, kNoradWarningVolume);
loop1Spec.insertFaderKnot(7320, 0);
loop1Spec.insertFaderKnot(7880, kNoradWarningVolume);
loop2Spec.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, 0, 0, entry.movieEnd -
entry.movieStart, kNoradSuckWindVolume);
loop1Spec.insertFaderKnot(7320, 0);
loop1Spec.insertFaderKnot(7880, kNoradSuckWindVolume);
startExtraSequence(kArriveFromSubChase, kExtraCompletedFlag, kFilterNoInput);
startLoop1Fader(loop1Spec);
startLoop2Fader(loop2Spec);
} else {
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA08", kArthurNoradExitedSub);
}
}
break;
case kNorad54:
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA71", kArthurNoradApproachedDamagedDoor);
break;
case kNorad54North:
GameState.setScoringSawRobotAt54North(true);
break;
case kNorad68:
if (GameState.getNoradRetScanGood())
openDoor();
else if (!_vm->playerHasItemID(kRetinalScanBiochip) && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA39", kArthurNoradAtRetScanNoBiochip);
break;
case kNorad68West:
arriveAtNorad68West();
break;
case kNorad79West:
arriveAtNorad79West();
break;
default:
break;
}
}
void NoradDelta::doorOpened() {
Norad::doorOpened();
GameState.setNoradRetScanGood(false);
}
void NoradDelta::arriveAtNorad68West() {
playSpotSoundSync(kHoldForRetinalIn, kHoldForRetinalOut);
BiochipItem *retScan = _vm->getCurrentBiochip();
if (retScan != nullptr && retScan->getObjectID() == kRetinalScanBiochip) {
((RetScanChip *)retScan)->searchForLaser();
succeedRetinalScan();
} else {
failRetinalScan();
}
}
void NoradDelta::arriveAtNorad79West() {
if (!GameState.getNoradPlayedGlobeGame())
newInteraction(kNoradGlobeGameInteractionID);
}
void NoradDelta::turnTo(const DirectionConstant direction) {
Norad::turnTo(direction);
if (g_arthurChip) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kNorad54, kNorth):
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA71", kArthurNoradApproachedDamagedDoor);
break;
case MakeRoomView(kNorad68, kWest):
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA39", kArthurNoradApproachedDamagedDoor);
break;
}
}
}
void NoradDelta::bumpIntoWall() {
requestSpotSound(kDeltaBumpIntoWallIn, kDeltaBumpIntoWallOut, kFilterNoInput, 0);
Neighborhood::bumpIntoWall();
}
void NoradDelta::failRetinalScan() {
startExtraSequence(kNoradDeltaRetinalScanBad, kExtraCompletedFlag, kFilterNoInput);
}
void NoradDelta::succeedRetinalScan() {
startExtraSequence(kNoradDeltaRetinalScanGood, kExtraCompletedFlag, kFilterNoInput);
GameState.setNoradRetScanGood(true);
GameState.setScoringUsedRetinalChip(true);
}
void NoradDelta::getDoorEntry(const RoomID room, const DirectionConstant direction, DoorTable::Entry &entry) {
Norad::getDoorEntry(room, direction, entry);
if (room == kNorad68 && direction == kWest && !GameState.getNoradRetScanGood())
entry.flags = kDoorPresentMask | kDoorLockedMask;
}
void NoradDelta::finishedGlobeGame() {
GameState.setNoradPlayedGlobeGame(true);
_privateFlags.setFlag(kNoradPrivateFinishedGlobeGameFlag, true);
GameState.setScoringFinishedGlobeGame(true);
loadAmbientLoops();
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA63", kArthurNoradThreatenedByRobot);
if (_vm->isChattyAI())
g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN60WD1", false, kWarningInterruption);
updateViewFrame();
}
bool NoradDelta::playingAgainstRobot() {
return GameState.getNoradPlayedGlobeGame();
}
void NoradDelta::getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID, HotSpotID &clawControlSpotID, HotSpotID &pinchClawSpotID,
HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID, HotSpotID &moveClawLeftSpotID, HotSpotID &moveClawUpSpotID,
HotSpotID &clawCCWSpotID, HotSpotID &clawCWSpotID, uint32 &clawPosition, const uint32 *&clawExtraIDs) {
outSpotID = kNorad60MonitorOutSpotID;
prepSpotID = kNorad60LaunchPrepSpotID;
clawControlSpotID = kNorad60ClawControlSpotID;
pinchClawSpotID = kNorad60ClawPinchSpotID;
moveClawDownSpotID = kNorad60ClawDownSpotID;
moveClawRightSpotID = kNorad60ClawRightSpotID;
moveClawLeftSpotID = kNorad60ClawLeftSpotID;
moveClawUpSpotID = kNorad60ClawUpSpotID;
clawCCWSpotID = kNorad60ClawCCWSpotID;
clawCWSpotID = kNorad60ClawCWSpotID;
clawPosition = kClawAtC;
clawExtraIDs = _noradDeltaClawExtras;
}
void NoradDelta::playerBeatRobotWithDoor() {
GameState.setNoradBeatRobotWithDoor(true);
updateViewFrame();
GameState.setScoringStoppedNoradRobot(true);
if (_vm->isChattyAI())
g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN59WD", false, kWarningInterruption);
}
void NoradDelta::playerBeatRobotWithClaw() {
GameState.setNoradBeatRobotWithClaw(true);
updateViewFrame();
GameState.setScoringStoppedNoradRobot(true);
GameState.setScoringNoradGandhi(true);
if (_vm->isChattyAI())
g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN59WD", false, kWarningInterruption);
}
TimeValue NoradDelta::getViewTime(const RoomID room, const DirectionConstant direction) {
ExtraTable::Entry entry;
if (room == kNorad41 && direction == kSouth && !GameState.getNoradArrivedFromSub()) {
getExtraEntry(kArriveFromSubChase, entry);
return entry.movieStart;
}
if (GameState.getNoradBeatRobotWithDoor()) {
if (_privateFlags.getFlag(kNoradPrivateRobotHeadOpenFlag)) {
uint32 extraID = kN59Biochips111;
if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag))
extraID += 1;
if (_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag))
extraID += 2;
if (_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag))
extraID += 4;
getExtraEntry(extraID, entry);
return entry.movieStart;
}
getExtraEntry(kN59RobotHeadOpens, entry);
return entry.movieStart;
} else if (GameState.getNoradBeatRobotWithClaw()) {
if (_privateFlags.getFlag(kNoradPrivateRobotHeadOpenFlag)) {
uint32 extraID = kN60Biochips111;
if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag))
extraID += 1;
if (_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag))
extraID += 2;
if (_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag))
extraID += 4;
getExtraEntry(extraID, entry);
return entry.movieStart;
}
getExtraEntry(kN60RobotHeadOpens, entry);
return entry.movieStart;
}
return Norad::getViewTime(room, direction);
}
void NoradDelta::openDoor() {
if (GameState.getCurrentRoom() == kNorad59 && GameState.getCurrentDirection() == kWest && GameState.getNoradPlayedGlobeGame()) {
Input scratch;
InputHandler::_inputHandler->clickInHotspot(scratch, _vm->getAllHotspots().findHotspotByID(kNorad59WestSpotID));
} else {
Norad::openDoor();
}
}
void NoradDelta::cantMoveThatWay(CanOpenDoorReason reason) {
// WORKAROUND: The door outside the launch console room isn't treated as a door,
// so play the correct sound.
if (reason == kCantMoveBlocked && GameState.getCurrentRoomAndView() == MakeRoomView(kNorad67, kNorth)) {
cantOpenDoor(kCantOpenLocked);
return;
}
Neighborhood::cantMoveThatWay(reason);
}
void NoradDelta::activateHotspots() {
Norad::activateHotspots();
if (GameState.getCurrentRoom() == kNorad59West && GameState.getCurrentDirection() == kWest && GameState.getNoradBeatRobotWithDoor()) {
_vm->getAllHotspots().deactivateOneHotspot(kNorad59WestOutSpotID);
if (_privateFlags.getFlag(kNoradPrivateRobotHeadOpenFlag)) {
if (!_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag))
_vm->getAllHotspots().activateOneHotspot(kDelta59RobotShieldBiochipSpotID);
else
_vm->getAllHotspots().deactivateOneHotspot(kDelta59RobotShieldBiochipSpotID);
if (!_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag))
_vm->getAllHotspots().activateOneHotspot(kDelta59RobotOpMemBiochipSpotID);
else
_vm->getAllHotspots().deactivateOneHotspot(kDelta59RobotOpMemBiochipSpotID);
if (!_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag))
_vm->getAllHotspots().activateOneHotspot(kDelta59RobotRetinalBiochipSpotID);
else
_vm->getAllHotspots().deactivateOneHotspot(kDelta59RobotRetinalBiochipSpotID);
} else
_vm->getAllHotspots().activateOneHotspot(kDelta59RobotHeadSpotID);
} else if (GameState.getCurrentRoom() == kNorad60West && GameState.getCurrentDirection() == kWest &&
GameState.getNoradBeatRobotWithClaw()) {
_vm->getAllHotspots().deactivateOneHotspot(kNorad60MonitorOutSpotID);
if (_privateFlags.getFlag(kNoradPrivateRobotHeadOpenFlag)) {
if (!_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag))
_vm->getAllHotspots().activateOneHotspot(kDelta60RobotShieldBiochipSpotID);
else
_vm->getAllHotspots().deactivateOneHotspot(kDelta60RobotShieldBiochipSpotID);
if (!_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag))
_vm->getAllHotspots().activateOneHotspot(kDelta60RobotOpMemBiochipSpotID);
else
_vm->getAllHotspots().deactivateOneHotspot(kDelta60RobotOpMemBiochipSpotID);
if (!_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag))
_vm->getAllHotspots().activateOneHotspot(kDelta60RobotRetinalBiochipSpotID);
else
_vm->getAllHotspots().deactivateOneHotspot(kDelta60RobotRetinalBiochipSpotID);
} else {
_vm->getAllHotspots().activateOneHotspot(kDelta60RobotHeadSpotID);
}
} else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad50, kEast)) {
if (GameState.isCurrentDoorOpen())
_vm->getAllHotspots().deactivateOneHotspot(kNorad50DoorSpotID);
} else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad59, kWest)) {
if (GameState.isCurrentDoorOpen())
_vm->getAllHotspots().deactivateOneHotspot(kNorad59WestSpotID);
} else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad68, kWest)) {
// WORKAROUND: Make sure the retinal hotspot is disabled after the door opens.
// Fixes a bug in the original.
if (GameState.isCurrentDoorOpen())
_vm->getAllHotspots().deactivateOneHotspot(kNorad68WestSpotID);
}
}
void NoradDelta::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
switch (clickedSpot->getObjectID()) {
case kDelta59RobotHeadSpotID:
startExtraSequence(kN59RobotHeadOpens, kExtraCompletedFlag, kFilterNoInput);
break;
case kDelta60RobotHeadSpotID:
startExtraSequence(kN60RobotHeadOpens, kExtraCompletedFlag, kFilterNoInput);
break;
default:
Norad::clickInHotspot(input, clickedSpot);
break;
}
}
void NoradDelta::receiveNotification(Notification *notification, const NotificationFlags flags) {
Norad::receiveNotification(notification, flags);
if ((flags & kExtraCompletedFlag) != 0) {
RetScanChip *retScan;
Input dummy;
switch (_lastExtra) {
case kArriveFromSubChase:
GameState.setNoradArrivedFromSub(true);
GameState.setCurrentRoom(kNoRoomID);
GameState.setCurrentDirection(kNoDirection);
arriveAt(kNorad41, kEast);
break;
case kN59RobotHeadOpens:
case kN60RobotHeadOpens:
_privateFlags.setFlag(kNoradPrivateRobotHeadOpenFlag, true);
if (g_arthurChip) {
switch (_vm->getRandomNumber(2)) {
case 0:
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA36", kArthurNoradRobotHeadOpen);
break;
case 1:
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA37", kArthurNoradRobotHeadOpen);
break;
case 2:
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA40", kArthurNoradRobotHeadOpen);
break;
}
}
break;
case kNoradDeltaRetinalScanBad:
retScan = (RetScanChip *)_vm->getCurrentBiochip();
retScan->setItemState(kNormalItem);
playSpotSoundSync(kRetinalScanFailedIn, kRetinalScanFailedOut);
downButton(dummy);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA13", kArthurNoradAtRetScanNoBiochip);
break;
case kNoradDeltaRetinalScanGood:
retScan = (RetScanChip *)_vm->getCurrentBiochip();
retScan->setItemState(kNormalItem);
downButton(dummy);
break;
case kN59RobotDisappears:
case kN60RobotDisappears:
recallToTSASuccess();
break;
default:
break;
}
_interruptionFilter = kFilterAllInput;
} else if ((flags & kSpotSoundCompletedFlag) != 0) {
if (_spotSounds.getStart() == kToDeactivateIn && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB41", kArthurNoradStartGlobeGame);
}
g_AIArea->checkMiddleArea();
}
void NoradDelta::pickedUpItem(Item *item) {
switch (item->getObjectID()) {
case kShieldBiochip:
if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag) &&
_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag) &&
_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag)) {
GameState.setNoradFinished(true);
if (GameState.getCurrentRoom() == kNorad59West)
startExtraSequence(kN59RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
else
startExtraSequence(kN60RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
}
break;
case kRetinalScanBiochip:
if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag) &&
_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag) &&
_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag)) {
GameState.setNoradFinished(true);
if (GameState.getCurrentRoom() == kNorad59West)
startExtraSequence(kN59RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
else
startExtraSequence(kN60RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
}
break;
case kOpticalBiochip:
g_opticalChip->addPoseidon();
GameState.setScoringGotNoradOpMemChip();
if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag) &&
_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag) &&
_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag)) {
GameState.setNoradFinished(true);
if (GameState.getCurrentRoom() == kNorad59West)
startExtraSequence(kN59RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
else
startExtraSequence(kN60RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
}
break;
default:
break;
}
Norad::pickedUpItem(item);
}
void NoradDelta::takeItemFromRoom(Item *item) {
switch (item->getObjectID()) {
case kShieldBiochip:
_privateFlags.setFlag(kNoradPrivateGotShieldChipFlag, true);
break;
case kRetinalScanBiochip:
_privateFlags.setFlag(kNoradPrivateGotRetScanChipFlag, true);
break;
case kOpticalBiochip:
_privateFlags.setFlag(kNoradPrivateGotOpticalChipFlag, true);
break;
default:
break;
}
Norad::takeItemFromRoom(item);
}
void NoradDelta::dropItemIntoRoom(Item *item, Hotspot *hotspot) {
switch (item->getObjectID()) {
case kShieldBiochip:
_privateFlags.setFlag(kNoradPrivateGotShieldChipFlag, false);
break;
case kOpticalBiochip:
_privateFlags.setFlag(kNoradPrivateGotOpticalChipFlag, false);
break;
case kRetinalScanBiochip:
_privateFlags.setFlag(kNoradPrivateGotRetScanChipFlag, false);
break;
default:
break;
}
Norad::dropItemIntoRoom(item, hotspot);
}
Hotspot *NoradDelta::getItemScreenSpot(Item *item, DisplayElement *element) {
HotSpotID id = kNoHotSpotID;
switch (item->getObjectID()) {
case kShieldBiochip:
if (GameState.getNoradBeatRobotWithDoor())
id = kDelta59RobotShieldBiochipSpotID;
else
id = kDelta60RobotShieldBiochipSpotID;
break;
case kOpticalBiochip:
if (GameState.getNoradBeatRobotWithDoor())
id = kDelta59RobotOpMemBiochipSpotID;
else
id = kDelta60RobotOpMemBiochipSpotID;
break;
case kRetinalScanBiochip:
if (GameState.getNoradBeatRobotWithDoor())
id = kDelta59RobotRetinalBiochipSpotID;
else
id = kDelta60RobotRetinalBiochipSpotID;
break;
default:
break;
}
if (id != kNoHotSpotID)
return _vm->getAllHotspots().findHotspotByID(id);
return Norad::getItemScreenSpot(item, element);
}
Common::Path NoradDelta::getEnvScanMovie() {
return "Images/AI/Norad/XNE2";
}
uint NoradDelta::getNumHints() {
uint numHints = Neighborhood::getNumHints();
if (numHints == 0) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kNorad60, kWest):
if (GameState.getNoradPlayedGlobeGame())
numHints = 2;
else
numHints = 1;
break;
case MakeRoomView(kNorad59, kNorth):
case MakeRoomView(kNorad59, kSouth):
case MakeRoomView(kNorad59, kEast):
case MakeRoomView(kNorad59, kWest):
case MakeRoomView(kNorad60, kNorth):
case MakeRoomView(kNorad60, kSouth):
case MakeRoomView(kNorad60, kEast):
if (GameState.getNoradPlayedGlobeGame())
numHints = 2;
break;
case MakeRoomView(kNorad68, kWest):
if (_vm->playerHasItemID(kRetinalScanBiochip)) {
BiochipItem *retScan = _vm->getCurrentBiochip();
if (retScan == nullptr || retScan->getObjectID() != kRetinalScanBiochip)
numHints = 2;
} else if (!GameState.isCurrentDoorOpen()) {
numHints = 2;
}
break;
default:
break;
}
}
return numHints;
}
Common::Path NoradDelta::getHintMovie(uint hintNum) {
Common::Path movieName = Neighborhood::getHintMovie(hintNum);
if (movieName.empty()) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kNorad60, kWest):
if (GameState.getNoradPlayedGlobeGame()) {
if (hintNum == 1)
return "Images/AI/Norad/XN60WD2";
return "Images/AI/Norad/XN60WD3";
}
return "Images/AI/Globals/XGLOB1C";
case MakeRoomView(kNorad59, kNorth):
case MakeRoomView(kNorad59, kSouth):
case MakeRoomView(kNorad59, kEast):
case MakeRoomView(kNorad59, kWest):
case MakeRoomView(kNorad60, kNorth):
case MakeRoomView(kNorad60, kSouth):
case MakeRoomView(kNorad60, kEast):
if (hintNum == 1)
return "Images/AI/Norad/XN60WD2";
return "Images/AI/Norad/XN60WD3";
case MakeRoomView(kNorad68, kWest):
if (_vm->playerHasItemID(kRetinalScanBiochip)) {
if (hintNum == 1)
return "Images/AI/Globals/XGLOB1A";
return "Images/AI/Globals/XGLOB1C";
}
if (hintNum == 1)
return "Images/AI/Globals/XGLOB1B";
return "Images/AI/Globals/XGLOB3B";
default:
break;
}
}
return movieName;
}
void NoradDelta::closeDoorOffScreen(const RoomID room, const DirectionConstant) {
switch (room) {
case kNorad47:
case kNorad48:
case kNorad41:
case kNorad42:
playSpotSoundSync(kDeltaElevatorDoorCloseIn, kDeltaElevatorDoorCloseOut);
break;
default:
playSpotSoundSync(kDeltaRegDoorCloseIn, kDeltaRegDoorCloseOut);
break;
}
}
bool NoradDelta::canSolve() {
if (Norad::canSolve())
return true;
if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad68, kWest)) {
BiochipItem *biochip = _vm->getCurrentBiochip();
if (biochip != nullptr && biochip->getObjectID() != kRetinalScanBiochip)
return true;
}
return false;
}
void NoradDelta::doSolve() {
Norad::doSolve();
if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad68, kWest)) {
if (!_vm->playerHasItemID(kRetinalScanBiochip))
_vm->addItemToBiochips((BiochipItem *)_vm->getAllItems().findItemByID(kRetinalScanBiochip));
BiochipItem *biochip = _vm->getCurrentBiochip();
if (biochip != nullptr && biochip->getObjectID() != kRetinalScanBiochip && g_interface)
g_interface->setCurrentBiochipID(kRetinalScanBiochip);
Hotspot *spot = _vm->getAllHotspots().findHotspotByID(kNorad68WestSpotID);
Input scratch;
InputHandler::_inputHandler->clickInHotspot(scratch, spot);
}
}
void NoradDelta::setSoundFXLevel(const uint16 level) {
Neighborhood::setSoundFXLevel(level);
if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad54North, kNorth))
_loop2Fader.setMasterVolume(level);
}
Common::Path NoradDelta::getSoundSpotsName() {
return "Sounds/Norad/Norad Delta Spots";
}
Common::Path NoradDelta::getNavMovieName() {
return "Images/Norad Delta/Norad Delta.movie";
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,120 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_DELTA_NORADDELTA_H
#define PEGASUS_NEIGHBORHOOD_NORAD_DELTA_NORADDELTA_H
#include "pegasus/neighborhood/norad/norad.h"
namespace Pegasus {
class NoradDelta : public Norad {
public:
NoradDelta(InputHandler *, PegasusEngine *);
~NoradDelta() override {}
void init() override;
void start() override;
void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &) override;
void finishedGlobeGame();
GameInteraction *makeInteraction(const InteractionID) override;
void playClawMonitorIntro() override;
void getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID, HotSpotID &clawControlSpotID,
HotSpotID &pinchClawSpotID, HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID,
HotSpotID &moveClawLeftSpotID, HotSpotID &moveClawUpSpotID, HotSpotID &clawCCWSpotID,
HotSpotID &clawCWSpotID, uint32 &, const uint32 *&) override;
void playerBeatRobotWithClaw();
void playerBeatRobotWithDoor();
void loadAmbientLoops() override;
void setUpAIRules() override;
Common::Path getEnvScanMovie() override;
uint getNumHints() override;
Common::Path getHintMovie(uint) override;
void closeDoorOffScreen(const RoomID, const DirectionConstant) override;
void checkContinuePoint(const RoomID, const DirectionConstant) override;
bool canSolve() override;
void doSolve() override;
void setSoundFXLevel(const uint16) override;
void doorOpened() override;
protected:
enum {
kNoradPrivateArrivedFromSubFlag,
kNoradPrivateFinishedGlobeGameFlag,
kNoradPrivateRobotHeadOpenFlag,
kNoradPrivateGotShieldChipFlag,
kNoradPrivateGotOpticalChipFlag,
kNoradPrivateGotRetScanChipFlag,
kNumNoradPrivateFlags
};
static const uint32 _noradDeltaClawExtras[22];
void getExitEntry(const RoomID, const DirectionConstant, ExitTable::Entry &) override;
void getZoomEntry(const HotSpotID, ZoomTable::Entry &) override;
void arriveAt(const RoomID, const DirectionConstant) override;
void arriveAtNorad68West();
void arriveAtNorad79West();
void turnTo(const DirectionConstant) override;
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
void openDoor() override;
void cantMoveThatWay(CanMoveForwardReason) override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void receiveNotification(Notification *, const NotificationFlags) override;
void pickedUpItem(Item *item) override;
void takeItemFromRoom(Item *item) override;
void dropItemIntoRoom(Item *item, Hotspot *) override;
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
bool playingAgainstRobot() override;
void failRetinalScan();
void succeedRetinalScan();
void getDoorEntry(const RoomID, const DirectionConstant, DoorTable::Entry &) override;
void bumpIntoWall() override;
FlagsArray<byte, kNumNoradPrivateFlags> _privateFlags;
Common::Path getSoundSpotsName() override;
Common::Path getNavMovieName() override;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,299 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/inventory/airmask.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
#include "pegasus/neighborhood/norad/noradelevator.h"
#include "pegasus/neighborhood/norad/pressuredoor.h"
#include "pegasus/neighborhood/norad/subcontrolroom.h"
#include "pegasus/neighborhood/norad/subplatform.h"
namespace Pegasus {
const NotificationFlags kDoneWithPressureDoorNotification = 1;
const NotificationFlags kNoradNotificationFlags = kDoneWithPressureDoorNotification;
// This class handles everything that Norad Alpha and Delta have in common, such as
// oxygen mask usage, the elevator and the pressure doors.
Norad::Norad(InputHandler *nextHandler, PegasusEngine *vm, const Common::String &resName, NeighborhoodID id) :
Neighborhood(nextHandler, vm, resName, id), _noradNotification(kNoradNotificationID, vm) {
_elevatorUpSpotID = kNoHotSpotID;
_elevatorDownSpotID = kNoHotSpotID;
_elevatorUpRoomID = kNoHotSpotID;
_elevatorDownRoomID = kNoHotSpotID;
_subRoomEntryRoom1 = kNoRoomID;
_subRoomEntryDir1 = kNoDirection;
_subRoomEntryRoom2 = kNoRoomID;
_subRoomEntryDir2 = kNoDirection;
_upperPressureDoorRoom = kNoRoomID;
_lowerPressureDoorRoom = kNoRoomID;
_upperPressureDoorUpSpotID = kNoHotSpotID;
_upperPressureDoorDownSpotID = kNoHotSpotID;
_upperPressureDoorAbortSpotID = kNoHotSpotID;
_lowerPressureDoorUpSpotID = kNoHotSpotID;
_lowerPressureDoorDownSpotID = kNoHotSpotID;
_lowerPressureDoorAbortSpotID = kNoHotSpotID;
_pressureSoundIn = 0xffffffff;
_pressureSoundOut = 0xffffffff;
_equalizeSoundIn = 0xffffffff;
_equalizeSoundOut = 0xffffffff;
_accessDeniedIn = 0xffffffff;
_accessDeniedOut = 0xffffffff;
_platformRoom = kNoRoomID;
_subControlRoom = kNoRoomID;
_doneWithPressureDoor = false;
_noradNotification.notifyMe(this, kNoradNotificationFlags, kNoradNotificationFlags);
}
GameInteraction *Norad::makeInteraction(const InteractionID interactionID) {
PressureDoor *pressureDoor;
SubControlRoom *subControl;
switch (interactionID) {
case kNoradElevatorInteractionID:
return new NoradElevator(this, _elevatorUpRoomID, _elevatorDownRoomID, _elevatorUpSpotID, _elevatorDownSpotID);
case kNoradPressureDoorInteractionID:
if (GameState.getCurrentRoom() == _upperPressureDoorRoom)
pressureDoor = new PressureDoor(this, true, _upperPressureDoorUpSpotID, _upperPressureDoorDownSpotID,
_upperPressureDoorAbortSpotID, _pressureSoundIn, _pressureSoundOut, _equalizeSoundIn, _equalizeSoundOut);
else
pressureDoor = new PressureDoor(this, false, _lowerPressureDoorUpSpotID, _lowerPressureDoorDownSpotID,
_lowerPressureDoorAbortSpotID, _pressureSoundIn, _pressureSoundOut, _equalizeSoundIn, _equalizeSoundOut);
if (GameState.getCurrentRoom() == kNorad59West && playingAgainstRobot())
pressureDoor->playAgainstRobot();
return pressureDoor;
case kNoradSubControlRoomInteractionID:
subControl = new SubControlRoom(this);
if (GameState.getCurrentRoom() == kNorad60West && playingAgainstRobot())
subControl->playAgainstRobot();
return subControl;
case kNoradSubPlatformInteractionID:
return new SubPlatform(this);
default:
return nullptr;
}
}
void Norad::flushGameState() {
g_energyMonitor->saveCurrentEnergyValue();
}
void Norad::start() {
setUpAirMask();
Neighborhood::start();
}
void Norad::activateHotspots() {
Neighborhood::activateHotspots();
RoomID room = GameState.getCurrentRoom();
if (room == _elevatorUpRoomID)
_neighborhoodHotspots.activateOneHotspot(_elevatorDownSpotID);
else if (room == _elevatorDownRoomID)
_neighborhoodHotspots.activateOneHotspot(_elevatorUpSpotID);
}
void Norad::arriveAt(const RoomID room, const DirectionConstant direction) {
Neighborhood::arriveAt(room, direction);
if (GameState.getCurrentRoom() == _elevatorUpRoomID || GameState.getCurrentRoom() == _elevatorDownRoomID)
arriveAtNoradElevator();
else if (GameState.getCurrentRoom() == _upperPressureDoorRoom)
arriveAtUpperPressureDoorRoom();
else if (GameState.getCurrentRoom() == _lowerPressureDoorRoom)
arriveAtLowerPressureDoorRoom();
else if (GameState.getCurrentRoom() == _platformRoom)
arriveAtSubPlatformRoom();
else if (GameState.getCurrentRoom() == _subControlRoom)
arriveAtSubControlRoom();
if (_doneWithPressureDoor) {
_doneWithPressureDoor = false;
openDoor();
}
}
void Norad::arriveAtNoradElevator() {
if (_currentInteraction)
_currentInteraction->startOverInteraction();
else
newInteraction(kNoradElevatorInteractionID);
}
void Norad::arriveAtUpperPressureDoorRoom() {
newInteraction(kNoradPressureDoorInteractionID);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA69", kArthurNoradReachedPressureDoor);
}
void Norad::arriveAtLowerPressureDoorRoom() {
newInteraction(kNoradPressureDoorInteractionID);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA69", kArthurNoradReachedPressureDoor);
}
void Norad::arriveAtSubPlatformRoom() {
newInteraction(kNoradSubPlatformInteractionID);
}
void Norad::arriveAtSubControlRoom() {
newInteraction(kNoradSubControlRoomInteractionID);
}
int16 Norad::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
int16 result = Neighborhood::getStaticCompassAngle(room, dir);
if (room == _elevatorUpRoomID || room == _elevatorDownRoomID)
result += kElevatorCompassAngle;
else if (room == _platformRoom)
result += kSubPlatformCompassAngle;
else if (room == _subControlRoom)
result += kSubControlCompassAngle;
return result;
}
CanOpenDoorReason Norad::canOpenDoor(DoorTable::Entry &entry) {
if (((GameState.getCurrentRoom() == _subRoomEntryRoom1 && GameState.getCurrentDirection() == _subRoomEntryDir1) ||
(GameState.getCurrentRoom() == _subRoomEntryRoom2 && GameState.getCurrentDirection() == _subRoomEntryDir2)) &&
GameState.getNoradSubRoomPressure() != kNormalSubRoomPressure)
return kCantOpenBadPressure;
return Neighborhood::canOpenDoor(entry);
}
void Norad::cantOpenDoor(CanOpenDoorReason reason) {
bool firstLockedDoor;
if (reason == kCantOpenBadPressure)
playSpotSoundSync(_pressureSoundIn, _pressureSoundOut);
else
playSpotSoundSync(_accessDeniedIn, _accessDeniedOut);
if (g_arthurChip) {
firstLockedDoor = g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA65", kArthurNoradAttemptedLockedDoor);
if (!firstLockedDoor)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA68", kArthurNoradAttemptedLockedDoorAgain);
}
}
void Norad::startExitMovie(const ExitTable::Entry &exitEntry) {
if (GameState.getCurrentRoom() == _elevatorUpRoomID) {
if (exitEntry.exitRoom != _elevatorDownRoomID)
newInteraction(kNoInteractionID);
} else if (GameState.getCurrentRoom() == _elevatorDownRoomID) {
if (exitEntry.exitRoom != _elevatorUpRoomID)
newInteraction(kNoInteractionID);
} else {
newInteraction(kNoInteractionID);
}
Neighborhood::startExitMovie(exitEntry);
}
void Norad::startZoomMovie(const ZoomTable::Entry &zoomEntry) {
newInteraction(kNoInteractionID);
Neighborhood::startZoomMovie(zoomEntry);
}
void Norad::upButton(const Input &input) {
if (GameState.getCurrentRoom() != _elevatorUpRoomID && GameState.getCurrentRoom() != _elevatorDownRoomID)
Neighborhood::upButton(input);
}
void Norad::setUpAirMask() {
_airMaskCallBack.setNotification(&_neighborhoodNotification);
_airMaskCallBack.initCallBack(&_airMaskTimer, kCallBackAtExtremes);
_airMaskCallBack.setCallBackFlag(kAirTimerExpiredFlag);
_neighborhoodNotification.notifyMe(this, kAirTimerExpiredFlag, kAirTimerExpiredFlag);
_airMaskCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_airMaskTimer.setScale(1);
_airMaskTimer.setSegment(0, kNoradAirMaskTimeLimit);
checkAirMask();
}
void Norad::checkAirMask() {
// WORKAROUND: The original game forgot to handle the case where the canister would
// be removed, leading to the timer remaining active.
if (!GameState.getNoradGassed() || (g_airMask && g_airMask->isAirFilterOn())) {
_airMaskTimer.stop();
} else if (GameState.getNoradGassed() && !_airMaskTimer.isRunning()) {
_airMaskTimer.setTime(0);
_airMaskTimer.start();
}
loadAmbientLoops();
}
void Norad::receiveNotification(Notification *notification, const NotificationFlags flags) {
if (notification == &_neighborhoodNotification && (flags & kAirTimerExpiredFlag) != 0)
g_vm->die(kDeathGassedInNorad);
Neighborhood::receiveNotification(notification, flags);
if (notification == &_noradNotification) {
// Must be kDoneWithPressureDoorNotification...
Input scratch;
_doneWithPressureDoor = true;
downButton(scratch);
}
}
uint16 Norad::getDateResID() const {
return kDate2112ID;
}
Common::Path Norad::getBriefingMovie() {
return "Images/AI/Norad/XNO";
}
void Norad::pickedUpItem(Item *item) {
Neighborhood::pickedUpItem(item);
g_AIArea->checkMiddleArea();
}
void Norad::doneWithPressureDoor() {
_noradNotification.setNotificationFlags(kDoneWithPressureDoorNotification, kDoneWithPressureDoorNotification);
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,120 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_NORAD_H
#define PEGASUS_NEIGHBORHOOD_NORAD_NORAD_H
#include "pegasus/neighborhood/neighborhood.h"
namespace Pegasus {
// This is the code common to both Norad Alpha and Norad Delta
class Norad : public Neighborhood {
public:
Norad(InputHandler *, PegasusEngine *owner, const Common::String &resName, const NeighborhoodID);
~Norad() override {}
void flushGameState() override;
void start() override;
virtual void getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID,
HotSpotID &clawControlSpotID, HotSpotID &pinchClawSpotID,
HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID,
HotSpotID &moveClawLeftSpotID,HotSpotID &moveClawUpSpotID,
HotSpotID &clawCCWSpotID, HotSpotID &clawCWSpotID, uint32 &, const uint32 *&) = 0;
void checkAirMask() override;
uint16 getDateResID() const override;
GameInteraction *makeInteraction(const InteractionID) override;
Common::Path getBriefingMovie() override;
void pickedUpItem(Item *) override;
virtual void playClawMonitorIntro() {}
void doneWithPressureDoor();
protected:
CanOpenDoorReason canOpenDoor(DoorTable::Entry &) override;
void cantOpenDoor(CanOpenDoorReason) override;
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void startExitMovie(const ExitTable::Entry &) override;
void startZoomMovie(const ZoomTable::Entry &) override;
void upButton(const Input &) override;
void activateHotspots() override;
void arriveAt(const RoomID, const DirectionConstant) override;
virtual void arriveAtNoradElevator();
virtual void arriveAtUpperPressureDoorRoom();
virtual void arriveAtLowerPressureDoorRoom();
virtual void arriveAtSubPlatformRoom();
virtual void arriveAtSubControlRoom();
void setUpAirMask();
void receiveNotification(Notification *, const NotificationFlags) override;
virtual bool playingAgainstRobot() { return false; }
Notification _noradNotification;
bool _doneWithPressureDoor;
RoomID _elevatorUpRoomID;
RoomID _elevatorDownRoomID;
HotSpotID _elevatorUpSpotID;
HotSpotID _elevatorDownSpotID;
TimeBase _airMaskTimer;
NotificationCallBack _airMaskCallBack;
RoomID _subRoomEntryRoom1;
DirectionConstant _subRoomEntryDir1;
RoomID _subRoomEntryRoom2;
DirectionConstant _subRoomEntryDir2;
RoomID _upperPressureDoorRoom;
RoomID _lowerPressureDoorRoom;
HotSpotID _upperPressureDoorUpSpotID;
HotSpotID _upperPressureDoorDownSpotID;
HotSpotID _upperPressureDoorAbortSpotID;
HotSpotID _lowerPressureDoorUpSpotID;
HotSpotID _lowerPressureDoorDownSpotID;
HotSpotID _lowerPressureDoorAbortSpotID;
TimeValue _pressureSoundIn;
TimeValue _pressureSoundOut;
TimeValue _equalizeSoundIn;
TimeValue _equalizeSoundOut;
TimeValue _accessDeniedIn;
TimeValue _accessDeniedOut;
RoomID _platformRoom;
RoomID _subControlRoom;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,129 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
#include "pegasus/neighborhood/norad/noradelevator.h"
namespace Pegasus {
// Norad elevator PICTs:
static const ResIDType kElevatorLabelID = 200;
static const ResIDType kElevatorButtonsID = 201;
static const ResIDType kElevatorDownOnID = 202;
static const ResIDType kElevatorUpOnID = 203;
NoradElevator::NoradElevator(Neighborhood *handler, const RoomID upRoom, const RoomID downRoom,
const HotSpotID upHotspot, const HotSpotID downHotspot) : GameInteraction(kNoradElevatorInteractionID, handler),
_elevatorControls(kNoradElevatorControlsID), _elevatorNotification(kNoradElevatorNotificationID, g_vm) {
_timerExpired = false;
_upRoom = upRoom;
_downRoom = downRoom;
_upHotspot = upHotspot;
_downHotspot = downHotspot;
}
void NoradElevator::openInteraction() {
SpriteFrame *frame = new SpriteFrame();
frame->initFromPICTResource(g_vm->_resFork, kElevatorLabelID, true);
_elevatorControls.addFrame(frame, 0, 0);
frame = new SpriteFrame();
frame->initFromPICTResource(g_vm->_resFork, kElevatorButtonsID, true);
_elevatorControls.addFrame(frame, 0, 0);
frame = new SpriteFrame();
frame->initFromPICTResource(g_vm->_resFork, kElevatorDownOnID, true);
_elevatorControls.addFrame(frame, 0, 0);
frame = new SpriteFrame();
frame->initFromPICTResource(g_vm->_resFork, kElevatorUpOnID, true);
_elevatorControls.addFrame(frame, 0, 0);
_elevatorControls.setCurrentFrameIndex(0);
_elevatorControls.setDisplayOrder(kElevatorControlsOrder);
Common::Rect r;
frame->getSurfaceBounds(r);
r.moveTo(kNoradAlphaElevatorControlsLeft, kNoradAlphaElevatorControlsTop);
_elevatorControls.setBounds(r);
_elevatorControls.startDisplaying();
_elevatorControls.show();
}
void NoradElevator::initInteraction() {
_elevatorTimer.setScale(2);
_elevatorTimer.setSegment(0, 1);
_elevatorCallBack.initCallBack(&_elevatorTimer, kCallBackAtExtremes);
_elevatorCallBack.setCallBackFlag(1);
_elevatorCallBack.setNotification(&_elevatorNotification);
_elevatorNotification.notifyMe(this, 1, 1);
_elevatorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_elevatorTimer.start();
}
void NoradElevator::closeInteraction() {
_elevatorControls.stopDisplaying();
_elevatorControls.discardFrames();
_elevatorCallBack.releaseCallBack();
}
void NoradElevator::resetInteraction() {
_elevatorControls.setCurrentFrameIndex(1);
}
void NoradElevator::activateHotspots() {
GameInteraction::activateHotspots();
if (_timerExpired) {
if (GameState.getCurrentRoom() == _upRoom)
g_allHotspots.activateOneHotspot(_downHotspot);
else if (GameState.getCurrentRoom() == _downRoom)
g_allHotspots.activateOneHotspot(_upHotspot);
}
}
void NoradElevator::clickInHotspot(const Input &input, const Hotspot *spot) {
HotSpotID id = spot->getObjectID();
if (id == _upHotspot || id == _downHotspot) {
g_neighborhood->moveForward();
if (id == _downHotspot)
_elevatorControls.setCurrentFrameIndex(2);
else
_elevatorControls.setCurrentFrameIndex(3);
} else {
GameInteraction::clickInHotspot(input, spot);
}
}
void NoradElevator::receiveNotification(Notification *, const NotificationFlags) {
_elevatorControls.setCurrentFrameIndex(1);
_timerExpired = true;
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,66 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_NORADELEVATOR_H
#define PEGASUS_NEIGHBORHOOD_NORAD_NORADELEVATOR_H
#include "pegasus/interaction.h"
#include "pegasus/notification.h"
#include "pegasus/surface.h"
#include "pegasus/timers.h"
namespace Pegasus {
class Neighborhood;
class NoradElevator : public GameInteraction, private NotificationReceiver {
public:
NoradElevator(Neighborhood *, const RoomID, const RoomID, const HotSpotID, const HotSpotID);
~NoradElevator() override {}
protected:
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void resetInteraction() override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void receiveNotification(Notification *, const NotificationFlags) override;
RoomID _upRoom;
RoomID _downRoom;
HotSpotID _upHotspot;
HotSpotID _downHotspot;
Sprite _elevatorControls;
TimeBase _elevatorTimer;
NotificationCallBack _elevatorCallBack;
Notification _elevatorNotification;
bool _timerExpired;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,562 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
#include "pegasus/neighborhood/norad/pressuredoor.h"
#include "pegasus/neighborhood/norad/delta/noraddelta.h"
namespace Pegasus {
static const TimeValue kLevelsSplashStart = 0;
static const TimeValue kLevelsSplashStop = 1;
static const TimeValue kPressureBase = 1;
static const TimeValue kDoorSealedTime = 0;
static const TimeValue kEqualizeTime = 1;
static const TimeValue kMaxPressureLoopStart = 2;
static const TimeValue kMaxPressureLoopStop = 3;
static const TimeValue kOpeningDoorLoopStart = 3;
static const TimeValue kOpeningDoorLoopStop = 4;
static const TimeValue kIncreasingPressureTime = 4;
static const TimeValue kDecreasingPressureTime = 5;
static const TimeValue kCautionLoopStart = 6;
static const TimeValue kCautionLoopStop = 7;
static const NotificationFlags kSplashFinished = 1;
static const NotificationFlags kPressureDroppingFlag = kSplashFinished << 1;
static const NotificationFlags kPressureNotificationFlags = kSplashFinished |
kPressureDroppingFlag;
static const NotificationFlags kDoorJumpsUpFlag = 1;
static const NotificationFlags kDoorJumpsBackFlag = kDoorJumpsUpFlag << 1;
static const NotificationFlags kDoorCrushedFlag = kDoorJumpsBackFlag << 1;
static const NotificationFlags kUtilityNotificationFlags = kDoorJumpsUpFlag |
kDoorJumpsBackFlag |
kDoorCrushedFlag;
enum {
kPlayingRobotApproaching,
kRobotPunching,
kRobotComingThrough,
kRobotDying,
kRobotDead
};
const short kMaxPunches = 5;
enum {
kPlayingSplash,
kPlayingPressureMessage,
kPlayingEqualizeMessage,
kWaitingForPlayer,
kPlayingDoneMessage,
kGameOver
};
// Pressure values range from 0 to 11.
static const short kMinPressure = 0;
static const short kMaxPressure = 11;
static const TimeScale kNavTimeScale = 600;
static const TimeValue kNavFrameRate = 15;
static const TimeValue kNavTimePerFrame = kNavTimeScale / kNavFrameRate;
static const TimeValue kApproachPunchInTime = 122 * kNavTimePerFrame;
static const TimeValue kLoopPunchInTime = 38 * kNavTimePerFrame;
static const TimeValue kPunchThroughTime = 38 * kNavTimePerFrame;
// Pressure door PICTs:
static const ResIDType kUpperPressureUpOffPICTID = 400;
static const ResIDType kUpperPressureUpOnPICTID = 401;
static const ResIDType kUpperPressureDownOffPICTID = 402;
static const ResIDType kUpperPressureDownOnPICTID = 403;
static const ResIDType kLowerPressureUpOffPICTID = 404;
static const ResIDType kLowerPressureUpOnPICTID = 405;
static const ResIDType kLowerPressureDownOffPICTID = 406;
static const ResIDType kLowerPressureDownOnPICTID = 407;
PressureDoor::PressureDoor(Neighborhood *handler, bool isUpperDoor, const HotSpotID upSpotID, const HotSpotID downSpotID,
const HotSpotID outSpotID, TimeValue pressureSoundIn, TimeValue pressureSoundOut, TimeValue equalizeSoundIn,
TimeValue equalizeSoundOut) : GameInteraction(kNoradPressureDoorInteractionID, handler),
_levelsMovie(kPressureDoorLevelsID), _typeMovie(kPressureDoorTypeID), _upButton(kPressureDoorUpButtonID),
_downButton(kPressureDoorDownButtonID), _pressureNotification(kNoradPressureNotificationID, g_vm),
_doorTracker(this), _utilityNotification(kNoradUtilityNotificationID, g_vm) {
_neighborhoodNotification = handler->getNeighborhoodNotification();
_upHotspotID = upSpotID;
_downHotspotID = downSpotID;
_outHotspotID = outSpotID;
_pressureSoundIn = pressureSoundIn;
_pressureSoundOut = pressureSoundOut;
_equalizeSoundIn = equalizeSoundIn;
_equalizeSoundOut = equalizeSoundOut;
_playingAgainstRobot = false;
_isUpperDoor = isUpperDoor;
}
void PressureDoor::openInteraction() {
if (_isUpperDoor) {
_levelsMovie.initFromMovieFile("Images/Norad Alpha/Upper Levels Movie");
_levelsMovie.moveElementTo(kNoradUpperLevelsLeft, kNoradUpperLevelsTop);
} else {
_levelsMovie.initFromMovieFile("Images/Norad Alpha/Lower Levels Movie");
_levelsMovie.moveElementTo(kNoradLowerLevelsLeft, kNoradLowerLevelsTop);
}
_levelsScale = _levelsMovie.getScale();
_levelsMovie.setDisplayOrder(kPressureLevelsOrder);
_levelsMovie.startDisplaying();
_levelsMovie.setSegment(kLevelsSplashStart * _levelsScale, kLevelsSplashStop * _levelsScale);
_levelsMovie.setTime(kLevelsSplashStart * _levelsScale);
_levelsMovie.redrawMovieWorld();
_levelsMovie.show();
_pressureCallBack.setNotification(&_pressureNotification);
_pressureCallBack.initCallBack(&_levelsMovie, kCallBackAtExtremes);
_pressureCallBack.setCallBackFlag(kSplashFinished);
_pressureCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_pressureNotification.notifyMe(this, kPressureNotificationFlags, kPressureNotificationFlags);
if (_isUpperDoor) {
_typeMovie.initFromMovieFile("Images/Norad Alpha/Upper Type Movie");
_typeMovie.moveElementTo(kNoradUpperTypeLeft, kNoradUpperTypeTop);
} else {
_typeMovie.initFromMovieFile("Images/Norad Alpha/Lower Type Movie");
_typeMovie.moveElementTo(kNoradLowerTypeLeft, kNoradLowerTypeTop);
}
_typeScale = _typeMovie.getScale();
_typeMovie.setDisplayOrder(kPressureTypeOrder);
_typeMovie.startDisplaying();
_typeMovie.setTime(kDoorSealedTime * _typeScale);
_typeMovie.redrawMovieWorld();
SpriteFrame *frame = new SpriteFrame();
if (_isUpperDoor)
frame->initFromPICTResource(g_vm->_resFork, kLowerPressureUpOffPICTID);
else
frame->initFromPICTResource(g_vm->_resFork, kUpperPressureUpOffPICTID);
_upButton.addFrame(frame, 0, 0);
frame = new SpriteFrame();
if (_isUpperDoor)
frame->initFromPICTResource(g_vm->_resFork, kLowerPressureUpOnPICTID);
else
frame->initFromPICTResource(g_vm->_resFork, kUpperPressureUpOnPICTID);
_upButton.addFrame(frame, 0, 0);
_upButton.setCurrentFrameIndex(0);
_upButton.setDisplayOrder(kPressureUpOrder);
Common::Rect r;
frame->getSurfaceBounds(r);
if (_isUpperDoor)
r.moveTo(kNoradUpperUpLeft, kNoradUpperUpTop);
else
r.moveTo(kNoradLowerUpLeft, kNoradLowerUpTop);
_upButton.setBounds(r);
_upButton.startDisplaying();
_upButton.show();
frame = new SpriteFrame();
if (_isUpperDoor)
frame->initFromPICTResource(g_vm->_resFork, kLowerPressureDownOffPICTID);
else
frame->initFromPICTResource(g_vm->_resFork, kUpperPressureDownOffPICTID);
_downButton.addFrame(frame, 0, 0);
frame = new SpriteFrame();
if (_isUpperDoor)
frame->initFromPICTResource(g_vm->_resFork, kLowerPressureDownOnPICTID);
else
frame->initFromPICTResource(g_vm->_resFork, kUpperPressureDownOnPICTID);
_downButton.addFrame(frame, 0, 0);
_downButton.setCurrentFrameIndex(0);
_downButton.setDisplayOrder(kPressureDownOrder);
frame->getSurfaceBounds(r);
if (_isUpperDoor)
r.moveTo(kNoradUpperDownLeft, kNoradUpperDownTop);
else
r.moveTo(kNoradLowerDownLeft, kNoradLowerDownTop);
_downButton.setBounds(r);
_downButton.startDisplaying();
_downButton.show();
_utilityCallBack.setNotification(&_utilityNotification);
_utilityCallBack.initCallBack(&_utilityTimer, kCallBackAtTime);
_utilityNotification.notifyMe(this, kUtilityNotificationFlags, kUtilityNotificationFlags);
_utilityTimer.setMasterTimeBase(getOwner()->getNavMovie());
if (_playingAgainstRobot)
_neighborhoodNotification->notifyMe(this, kExtraCompletedFlag | kDelayCompletedFlag |
kSpotSoundCompletedFlag, kExtraCompletedFlag | kDelayCompletedFlag | kSpotSoundCompletedFlag);
else
_neighborhoodNotification->notifyMe(this, kDelayCompletedFlag | kSpotSoundCompletedFlag,
kDelayCompletedFlag | kSpotSoundCompletedFlag);
_gameState = kPlayingSplash;
}
void PressureDoor::initInteraction() {
_levelsMovie.start();
if (_playingAgainstRobot) {
ExtraTable::Entry entry;
_owner->getExtraEntry(kN59RobotApproaches, entry);
_utilityTimer.setSegment(entry.movieStart, entry.movieEnd);
_utilityCallBack.setCallBackFlag(kDoorJumpsUpFlag);
_punchInTime = kApproachPunchInTime + entry.movieStart;
_utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime, kNavTimeScale);
_utilityTimer.setTime(entry.movieStart);
_owner->startExtraSequence(kN59RobotApproaches, kExtraCompletedFlag, kFilterAllInput);
_utilityTimer.start();
_robotState = kPlayingRobotApproaching;
}
_levelsMovie.redrawMovieWorld();
}
void PressureDoor::closeInteraction() {
_pressureNotification.cancelNotification(this);
_pressureCallBack.releaseCallBack();
_utilityNotification.cancelNotification(this);
_utilityCallBack.releaseCallBack();
_neighborhoodNotification->cancelNotification(this);
}
void PressureDoor::playAgainstRobot() {
_playingAgainstRobot = true;
}
void PressureDoor::receiveNotification(Notification *notification, const NotificationFlags flags) {
Neighborhood *owner = getOwner();
if (notification == _neighborhoodNotification) {
if (_playingAgainstRobot && (flags & kExtraCompletedFlag) != 0) {
ExtraTable::Entry entry;
switch (_robotState) {
case kPlayingRobotApproaching:
_utilityTimer.stop();
if (GameState.getNoradSubRoomPressure() == kMaxPressure) {
owner->getExtraEntry(kN59PlayerWins1, entry);
_utilityTimer.setSegment(entry.movieStart, entry.movieEnd);
_utilityTimer.setTime(entry.movieStart);
_utilityCallBack.setCallBackFlag(kDoorJumpsUpFlag);
_punchInTime = kLoopPunchInTime + entry.movieStart;
_utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime, kNavTimeScale);
owner->startExtraSequence(kN59PlayerWins1, kExtraCompletedFlag, kFilterNoInput);
_utilityTimer.start();
_robotState = kRobotDying;
} else {
owner->getExtraEntry(kN59RobotPunchLoop, entry);
_utilityTimer.setSegment(entry.movieStart, entry.movieEnd);
_utilityTimer.setTime(entry.movieStart);
_utilityCallBack.setCallBackFlag(kDoorJumpsUpFlag);
_punchInTime = kLoopPunchInTime + entry.movieStart;
_utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime, kNavTimeScale);
owner->startSpotLoop(entry.movieStart, entry.movieEnd, kExtraCompletedFlag);
_utilityTimer.start();
_robotState = kRobotPunching;
_punchCount = 1;
}
break;
case kRobotPunching:
if (GameState.getNoradSubRoomPressure() == kMaxPressure) {
owner->startExtraSequence(kN59PlayerWins1, kExtraCompletedFlag, kFilterNoInput);
_robotState = kRobotDying;
} else if (++_punchCount >= kMaxPunches) {
_robotState = kRobotComingThrough;
owner->getExtraEntry(kN59RobotWins, entry);
_utilityTimer.stop();
_utilityTimer.setSegment(entry.movieStart, entry.movieEnd);
_utilityTimer.setTime(entry.movieStart);
_utilityCallBack.cancelCallBack();
_utilityCallBack.setCallBackFlag(kDoorCrushedFlag);
_utilityCallBack.scheduleCallBack(kTriggerTimeFwd, kPunchThroughTime + entry.movieStart, kNavTimeScale);
owner->startExtraSequence(kN59RobotWins, kExtraCompletedFlag, kFilterNoInput);
_utilityTimer.start();
} else {
_utilityCallBack.setCallBackFlag(kDoorJumpsUpFlag);
_utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime, kNavTimeScale);
owner->scheduleNavCallBack(kExtraCompletedFlag);
}
break;
case kRobotComingThrough:
g_system->delayMillis(2 * 1000);
g_vm->die(kDeathRobotThroughNoradDoor);
break;
case kRobotDying:
_robotState = kRobotDead;
_levelsMovie.stop();
_levelsMovie.setSegment((kNormalSubRoomPressure + kPressureBase) * _levelsScale,
(GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale + 1);
_levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
_pressureCallBack.setCallBackFlag(kPressureDroppingFlag);
_pressureCallBack.scheduleCallBack(kTriggerAtStart, 0, 0);
_typeMovie.stop();
_typeMovie.setSegment(0, _typeMovie.getDuration());
_typeMovie.setTime(kDecreasingPressureTime * _typeScale);
_typeMovie.redrawMovieWorld();
_typeMovie.show();
_downButton.show();
_downButton.setCurrentFrameIndex(1);
_gameState = kGameOver;
allowInput(false);
_levelsMovie.setRate(Common::Rational(-4, 3)); // Should match door tracker.
break;
case kRobotDead:
allowInput(true);
((NoradDelta *)owner)->playerBeatRobotWithDoor();
owner->requestDeleteCurrentInteraction();
break;
default:
break;
}
}
if ((flags & (kDelayCompletedFlag | kSpotSoundCompletedFlag)) != 0) {
switch (_gameState) {
case kPlayingPressureMessage:
_typeMovie.setTime(kEqualizeTime * _typeScale);
_typeMovie.redrawMovieWorld();
owner->requestDelay(1, 5, kFilterNoInput, 0);
owner->requestSpotSound(_equalizeSoundIn, _equalizeSoundOut, kFilterNoInput, 0);
owner->requestDelay(1, 5, kFilterNoInput, kDelayCompletedFlag);
_gameState = kPlayingEqualizeMessage;
break;
case kPlayingEqualizeMessage:
_gameState = kWaitingForPlayer;
stopChangingPressure();
break;
case kPlayingDoneMessage:
_gameState = kWaitingForPlayer;
_typeMovie.stop();
_typeMovie.setFlags(0);
_typeMovie.hide();
if (!_playingAgainstRobot)
((Norad *)_owner)->doneWithPressureDoor();
break;
default:
break;
}
}
} else if (notification == &_pressureNotification) {
switch (flags) {
case kSplashFinished:
_levelsMovie.stop();
_levelsMovie.setSegment(0, _levelsMovie.getDuration());
_levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
_levelsMovie.redrawMovieWorld();
if (GameState.getNoradSubRoomPressure() != kNormalSubRoomPressure) {
_typeMovie.show();
owner->requestDelay(1, 5, kFilterNoInput, 0);
owner->requestSpotSound(_pressureSoundIn, _pressureSoundOut, kFilterNoInput, 0);
owner->requestDelay(1, 5, kFilterNoInput, kDelayCompletedFlag);
_gameState = kPlayingPressureMessage;
} else {
_gameState = kWaitingForPlayer;
}
break;
case kPressureDroppingFlag:
_levelsMovie.stop();
_levelsMovie.hide();
_typeMovie.stop();
_typeMovie.hide();
_upButton.hide();
_downButton.hide();
owner->startExtraSequence(kN59PlayerWins2, kExtraCompletedFlag, kFilterNoInput);
break;
default:
break;
}
} else if (notification == &_utilityNotification) {
switch (flags) {
case kDoorJumpsUpFlag:
_utilityCallBack.setCallBackFlag(kDoorJumpsBackFlag);
_utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime + kNavTimePerFrame, kNavTimeScale);
_levelsMovie.hide();
_typePunched = _typeMovie.isVisible();
if (_typePunched == true)
_typeMovie.hide();
_upButton.hide();
_downButton.hide();
break;
case kDoorJumpsBackFlag:
_levelsMovie.show();
_upButton.show();
_downButton.show();
if (_typePunched)
_typeMovie.show();
break;
case kDoorCrushedFlag:
_levelsMovie.hide();
_typeMovie.hide();
_upButton.hide();
_downButton.hide();
break;
default:
break;
}
}
}
void PressureDoor::activateHotspots() {
GameInteraction::activateHotspots();
switch (_gameState) {
case kWaitingForPlayer:
g_allHotspots.activateOneHotspot(_upHotspotID);
g_allHotspots.activateOneHotspot(_downHotspotID);
if (!_playingAgainstRobot)
g_allHotspots.activateOneHotspot(_outHotspotID);
break;
default:
break;
}
}
void PressureDoor::clickInHotspot(const Input &input, const Hotspot *spot) {
HotSpotID id = spot->getObjectID();
if (id == _upHotspotID || id == _downHotspotID) {
if (id == _upHotspotID)
_doorTracker.setTrackParameters(spot, &_upButton);
else
_doorTracker.setTrackParameters(spot, &_downButton);
_doorTracker.startTracking(input);
} else {
GameInteraction::clickInHotspot(input, spot);
}
}
void PressureDoor::incrementPressure(const HotSpotID id) {
_typeMovie.stop();
_typeMovie.setSegment(0, _typeMovie.getDuration());
_typeMovie.setFlags(0);
if (id == _upHotspotID) {
if (GameState.getNoradSubRoomPressure() < kMaxPressure) {
GameState.setNoradSubRoomPressure(GameState.getNoradSubRoomPressure() + 1);
_levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
_levelsMovie.redrawMovieWorld();
_typeMovie.setTime(kIncreasingPressureTime * _typeScale);
_typeMovie.redrawMovieWorld();
_typeMovie.show();
g_AIArea->checkMiddleArea();
} else {
_typeMovie.hide();
}
} else if (id == _downHotspotID) {
if (GameState.getNoradSubRoomPressure() > kMinPressure) {
GameState.setNoradSubRoomPressure(GameState.getNoradSubRoomPressure() - 1);
_levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
_levelsMovie.redrawMovieWorld();
_typeMovie.setTime(kDecreasingPressureTime * _typeScale);
_typeMovie.redrawMovieWorld();
_typeMovie.show();
g_AIArea->checkMiddleArea();
} else {
_typeMovie.hide();
}
}
}
void PressureDoor::stopChangingPressure() {
Neighborhood *owner;
switch (GameState.getNoradSubRoomPressure()) {
case 11:
_typeMovie.setSegment(kMaxPressureLoopStart * _typeScale, kMaxPressureLoopStop * _typeScale);
_typeMovie.setFlags(kLoopTimeBase);
_typeMovie.show();
_typeMovie.start();
break;
case 10:
_typeMovie.setSegment(kCautionLoopStart * _typeScale, kCautionLoopStop * _typeScale);
_typeMovie.setFlags(kLoopTimeBase);
_typeMovie.show();
_typeMovie.start();
break;
case kNormalSubRoomPressure:
owner = getOwner();
_typeMovie.setSegment(kOpeningDoorLoopStart * _typeScale, kOpeningDoorLoopStop * _typeScale);
_typeMovie.setFlags(kLoopTimeBase);
_typeMovie.show();
_gameState = kPlayingDoneMessage;
owner->requestDelay(2, 1, kFilterNoInput, kDelayCompletedFlag);
_typeMovie.start();
break;
default:
_typeMovie.hide();
break;
}
}
bool PressureDoor::canSolve() {
if (_playingAgainstRobot)
return GameState.getNoradSubRoomPressure() < 11;
return GameState.getNoradSubRoomPressure() != kNormalSubRoomPressure;
}
void PressureDoor::doSolve() {
if (_playingAgainstRobot) {
GameState.setNoradSubRoomPressure(11);
_levelsMovie.setTime((11 + kPressureBase) * _levelsScale);
_levelsMovie.redrawMovieWorld();
_typeMovie.setSegment(kMaxPressureLoopStart * _typeScale, kMaxPressureLoopStop * _typeScale);
_typeMovie.setFlags(kLoopTimeBase);
_typeMovie.show();
_typeMovie.start();
g_AIArea->checkMiddleArea();
} else {
GameState.setNoradSubRoomPressure(kNormalSubRoomPressure);
_levelsMovie.setTime((kNormalSubRoomPressure + kPressureBase) * _levelsScale);
_levelsMovie.redrawMovieWorld();
_typeMovie.setSegment(kOpeningDoorLoopStart * _typeScale, kOpeningDoorLoopStop * _typeScale);
_typeMovie.setFlags(kLoopTimeBase);
_typeMovie.show();
Neighborhood *owner = getOwner();
owner->requestDelay(2, 1, kFilterNoInput, kDelayCompletedFlag);
_gameState = kPlayingDoneMessage;
_typeMovie.start();
g_AIArea->checkMiddleArea();
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,92 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_PRESSUREDOOR_H
#define PEGASUS_NEIGHBORHOOD_NORAD_PRESSUREDOOR_H
#include "pegasus/interaction.h"
#include "pegasus/movie.h"
#include "pegasus/notification.h"
#include "pegasus/neighborhood/norad/pressuretracker.h"
namespace Pegasus {
static const short kNormalSubRoomPressure = 2;
class PressureDoor : public GameInteraction, public NotificationReceiver {
public:
PressureDoor(Neighborhood *, bool isUpperDoor, const HotSpotID, const HotSpotID,
const HotSpotID, TimeValue pressureSoundIn, TimeValue pressureSoundOut,
TimeValue equalizeSoundIn, TimeValue equalizeSoundOut);
~PressureDoor() override {}
void incrementPressure(const HotSpotID);
void stopChangingPressure();
void playAgainstRobot();
bool canSolve() override;
void doSolve() override;
protected:
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void receiveNotification(Notification *, const NotificationFlags) override;
Movie _levelsMovie;
TimeScale _levelsScale;
Movie _typeMovie;
TimeScale _typeScale;
Sprite _upButton;
Sprite _downButton;
Notification _pressureNotification;
NotificationCallBack _pressureCallBack;
Notification *_neighborhoodNotification;
int _gameState;
HotSpotID _upHotspotID;
HotSpotID _downHotspotID;
HotSpotID _outHotspotID;
PressureTracker _doorTracker;
TimeValue _pressureSoundIn;
TimeValue _pressureSoundOut;
TimeValue _equalizeSoundIn;
TimeValue _equalizeSoundOut;
bool _isUpperDoor;
bool _playingAgainstRobot, _typePunched;
int _robotState, _punchCount;
TimeBase _utilityTimer;
Notification _utilityNotification;
NotificationCallBack _utilityCallBack;
TimeValue _punchInTime;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,87 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/hotspot.h"
#include "pegasus/pegasus.h"
#include "pegasus/neighborhood/norad/pressuredoor.h"
#include "pegasus/neighborhood/norad/pressuretracker.h"
namespace Pegasus {
PressureTracker::PressureTracker(PressureDoor *pressureDoor) {
_pressureDoor = pressureDoor;
_trackSpot = nullptr;
_trackTime = 0;
_trackButton = nullptr;
}
void PressureTracker::setTrackParameters(const Hotspot *trackSpot, Sprite *trackButton) {
_trackSpot = trackSpot;
_trackButton = trackButton;
_trackTime = 0;
}
void PressureTracker::activateHotspots() {
Tracker::activateHotspots();
if (_trackSpot)
g_allHotspots.activateOneHotspot(_trackSpot->getObjectID());
}
// For click-hold dragging.
bool PressureTracker::stopTrackingInput(const Input &input) {
return !JMPPPInput::isPressingInput(input);
}
void PressureTracker::continueTracking(const Input &input) {
Common::Point where;
input.getInputLocation(where);
if (g_allHotspots.findHotspot(where) == _trackSpot) {
trackPressure();
_trackButton->setCurrentFrameIndex(1);
} else {
_trackButton->setCurrentFrameIndex(0);
}
}
void PressureTracker::startTracking(const Input &input) {
Tracker::startTracking(input);
trackPressure();
}
void PressureTracker::stopTracking(const Input &input) {
_trackButton->setCurrentFrameIndex(0);
_pressureDoor->stopChangingPressure();
Tracker::stopTracking(input);
}
void PressureTracker::trackPressure() {
if (g_system->getMillis() - _trackTime > kPressureDoorTrackInterval * 1000 / 60) {
_pressureDoor->incrementPressure(_trackSpot->getObjectID());
_trackTime = g_system->getMillis();
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,68 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_PRESSURETRACKER_H
#define PEGASUS_NEIGHBORHOOD_NORAD_PRESSURETRACKER_H
#include "pegasus/input.h"
namespace Pegasus {
// This class assumes that the globe movie is built at 15 frames per second with a
// time scale of 600, yielding 40 time unit per frame.
enum PressureTrackDirection {
kTrackPressureUp,
kTrackPressureDown
};
static const int kPressureDoorTrackInterval = 45;
class PressureDoor;
class Sprite;
class PressureTracker : public Tracker {
public:
PressureTracker(PressureDoor *);
~PressureTracker() override {}
void setTrackParameters(const Hotspot *, Sprite *);
void continueTracking(const Input &) override;
void startTracking(const Input &) override;
void stopTracking(const Input &) override;
void activateHotspots() override;
bool stopTrackingInput(const Input &) override;
protected:
void trackPressure();
PressureDoor *_pressureDoor;
const Hotspot *_trackSpot;
Sprite *_trackButton;
long _trackTime;
};
} // End of namespace Pegasus
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,132 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_SUBCONTROLROOM_H
#define PEGASUS_NEIGHBORHOOD_NORAD_SUBCONTROLROOM_H
#include "pegasus/interaction.h"
#include "pegasus/notification.h"
namespace Pegasus {
static const uint32 kClawAtA = 0;
static const uint32 kClawAtB = 1;
static const uint32 kClawAtC = 2;
static const uint32 kClawAtD = 3;
static const int kNumClawButtons = 7;
class Norad;
class SubControlRoom : public GameInteraction, public NotificationReceiver {
public:
SubControlRoom(Neighborhood *);
~SubControlRoom() override {}
void playAgainstRobot();
void setSoundFXLevel(const uint16) override;
bool canSolve() override;
void doSolve() override;
protected:
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void receiveNotification(Notification *, const NotificationFlags) override;
void robotKillsPlayer(const uint32, Neighborhood *);
InputBits getInputFilter() override;
int findActionIndex(HotSpotID);
void dispatchClawAction(const int);
void performActionImmediately(const int, const uint32, Neighborhood *);
void hideEverything();
void showButtons();
void hideButtons();
void updateGreenBall();
void moveGreenBallToA();
void moveGreenBallToB();
void moveGreenBallToC();
void moveGreenBallToD();
void setControlMonitorToTime(const TimeValue, const int, const bool);
void playControlMonitorSection(const TimeValue, const TimeValue, const NotificationFlags,
const int, const bool);
void updateClawMonitor();
void setClawMonitorToTime(const TimeValue);
void playClawMonitorSection(const TimeValue, const TimeValue, const NotificationFlags,
const int, const bool);
Movie _subControlMovie;
TimeScale _subControlScale;
Notification _subControlNotification;
NotificationCallBack _subControlCallBack;
Movie _clawMonitorMovie;
NotificationCallBack _clawMonitorCallBack;
int _gameState;
uint32 _clawStartPosition;
uint32 _clawPosition;
uint32 _clawNextPosition;
const uint32 *_clawExtraIDs;
int _currentAction;
int _nextAction;
Sprite *_buttons[kNumClawButtons];
Sprite _pinchButton;
Sprite _downButton;
Sprite _rightButton;
Sprite _leftButton;
Sprite _upButton;
Sprite _ccwButton;
Sprite _cwButton;
Sprite _greenBall;
TimeBase _greenBallTimer;
Notification _greenBallNotification;
NotificationCallBack _greenBallCallBack;
HotSpotID _outSpotID;
HotSpotID _prepSpotID;
HotSpotID _clawControlSpotID;
HotSpotID _clawButtonSpotIDs[kNumClawButtons];
Notification *_neighborhoodNotification;
bool _playingAgainstRobot;
int _robotState;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,210 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/norad/norad.h"
#include "pegasus/neighborhood/norad/subplatform.h"
#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
namespace Pegasus {
// As usual, times here are in seconds.
static const TimeValue kNormalSplashStart = 0;
static const TimeValue kNormalSplashStop = 5;
static const TimeValue kPrepSubStart = 5;
static const TimeValue kPrepSubStop = 15;
static const TimeValue kPrepIncompleteStart = 15;
static const TimeValue kPrepIncompleteStop = 19;
static const TimeValue kDamagedStart = 19;
static const TimeValue kDamagedStop = 28;
static const NotificationFlags kNormalSplashFinished = 1;
static const NotificationFlags kPrepSubFinished = kNormalSplashFinished << 1;
static const NotificationFlags kPrepIncompleteFinished = kPrepSubFinished << 1;
static const NotificationFlags kDamagedFinished = kPrepIncompleteFinished << 1;
static const NotificationFlags kPlatformNotificationFlags = kNormalSplashFinished |
kPrepSubFinished |
kPrepIncompleteFinished |
kDamagedFinished;
static const uint16 kSubPreppedBit = (1 << 0);
static const uint16 kWaitingForPlayerBit = (1 << 1);
SubPlatform::SubPlatform(Neighborhood *handler) : GameInteraction(kNoradSubPlatformInteractionID, handler),
_platformMovie(kPlatformMonitorID), _platformNotification(kNoradSubPlatformNotificationID, g_vm) {
_neighborhoodNotification = handler->getNeighborhoodNotification();
}
void SubPlatform::openInteraction() {
_stateBits = 0;
// TODO: These next two lines seem unused?
if (GameState.getNoradSubPrepState() == kSubPrepped)
_stateBits |= kSubPreppedBit;
_stateBits |= kWaitingForPlayerBit;
_platformMovie.initFromMovieFile("Images/Norad Alpha/Platform Monitor Movie");
_platformMovie.setVolume(g_vm->getSoundFXLevel());
_platformMovie.moveElementTo(kNoradPlatformLeft, kNoradPlatformTop);
_platformScale = _platformMovie.getScale();
_platformMovie.setDisplayOrder(kPlatformOrder);
_platformMovie.startDisplaying();
_platformCallBack.setNotification(&_platformNotification);
_platformCallBack.initCallBack(&_platformMovie, kCallBackAtExtremes);
_platformNotification.notifyMe(this, kPlatformNotificationFlags, kPlatformNotificationFlags);
}
void SubPlatform::initInteraction() {
_neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
}
void SubPlatform::closeInteraction() {
_platformNotification.cancelNotification(this);
_platformCallBack.releaseCallBack();
_neighborhoodNotification->cancelNotification(this);
}
void SubPlatform::setSoundFXLevel(const uint16 fxLevel) {
_platformMovie.setVolume(fxLevel);
}
void SubPlatform::receiveNotification(Notification *notification, const NotificationFlags flags) {
FaderMoveSpec loop1Spec, loop2Spec;
ExtraTable::Entry entry;
Norad *owner = (Norad *)getOwner();
if (notification == &_platformNotification) {
switch (flags) {
case kNormalSplashFinished:
_platformMovie.stop();
switch (GameState.getNoradSubPrepState()) {
case kSubNotPrepped:
_platformMovie.setSegment(kPrepIncompleteStart * _platformScale, kPrepIncompleteStop * _platformScale);
_platformMovie.setTime(kPrepIncompleteStart * _platformScale);
_platformCallBack.setCallBackFlag(kPrepIncompleteFinished);
_platformCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_platformMovie.start();
break;
case kSubPrepped:
_platformMovie.setSegment(kPrepSubStart * _platformScale, kPrepSubStop * _platformScale);
_platformMovie.setTime(kPrepSubStart * _platformScale);
_platformCallBack.setCallBackFlag(kPrepSubFinished);
_platformCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
owner->startExtraSequence(kNorad19PrepSub, 0, kFilterNoInput);
_platformMovie.start();
break;
case kSubDamaged:
// Shouldn't happen.
default:
break;
}
break;
case kPrepSubFinished:
_platformMovie.stop();
_platformMovie.stopDisplaying();
owner->getExtraEntry(kNorad19ExitToSub, entry);
loop1Spec.makeTwoKnotFaderSpec(kNoradAlphaMovieScale, 0, kNoradWarningVolume,
entry.movieEnd - entry.movieStart, 0);
loop1Spec.insertFaderKnot(4560, kNoradWarningVolume);
loop1Spec.insertFaderKnot(5080, 0);
loop2Spec.makeTwoKnotFaderSpec(kNoradAlphaMovieScale, 0, kNoradSuckWindVolume,
entry.movieEnd - entry.movieStart, 0);
loop1Spec.insertFaderKnot(4560, kNoradSuckWindVolume);
loop1Spec.insertFaderKnot(5080, 0);
owner->startExtraSequence(kNorad19ExitToSub, kExtraCompletedFlag, kFilterNoInput);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA07", kArthurNoradEnteredSub);
owner->startLoop1Fader(loop1Spec);
owner->startLoop2Fader(loop2Spec);
break;
case kPrepIncompleteFinished:
((NoradAlpha *)owner)->setSubPrepFailed(true);
g_AIArea->checkMiddleArea();
// Fall through...
case kDamagedFinished:
_platformMovie.stop();
_platformMovie.hide();
_stateBits |= kWaitingForPlayerBit;
allowInput(true);
break;
default:
break;
}
} else if (notification == _neighborhoodNotification && !g_vm->isDVD()) {
allowInput(true);
g_vm->jumpToNewEnvironment(kNoradSubChaseID, kNoRoomID, kNoDirection);
GameState.setScoringEnteredSub(true);
}
}
void SubPlatform::activateHotspots() {
if (_stateBits & kWaitingForPlayerBit)
g_allHotspots.activateOneHotspot(kNorad19ActivateMonitorSpotID);
GameInteraction::activateHotspots();
}
void SubPlatform::clickInHotspot(const Input &input, const Hotspot *spot) {
if (spot->getObjectID() == kNorad19ActivateMonitorSpotID) {
if (GameState.getNoradSubPrepState() == kSubDamaged) {
_platformMovie.setSegment(kDamagedStart * _platformScale, kDamagedStop * _platformScale);
_platformMovie.setTime(kDamagedStart * _platformScale);
_platformCallBack.setCallBackFlag(kDamagedFinished);
} else {
_platformMovie.setSegment(kNormalSplashStart * _platformScale, kNormalSplashStop * _platformScale);
_platformMovie.setTime(kNormalSplashStart * _platformScale);
_platformCallBack.setCallBackFlag(kNormalSplashFinished);
}
_platformCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
_platformMovie.show();
_platformMovie.start();
_platformMovie.redrawMovieWorld();
_stateBits &= ~kWaitingForPlayerBit;
allowInput(false);
} else {
GameInteraction::clickInHotspot(input, spot);
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,62 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_NORAD_SUBPLATFORM_H
#define PEGASUS_NEIGHBORHOOD_NORAD_SUBPLATFORM_H
#include "pegasus/interaction.h"
#include "pegasus/movie.h"
#include "pegasus/notification.h"
#include "pegasus/timers.h"
namespace Pegasus {
class SubPlatform : public GameInteraction, public NotificationReceiver {
public:
SubPlatform(Neighborhood *);
~SubPlatform() override {}
void setSoundFXLevel(const uint16) override;
protected:
void openInteraction() override;
void initInteraction() override;
void closeInteraction() override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
void receiveNotification(Notification *, const NotificationFlags) override;
Movie _platformMovie;
TimeScale _platformScale;
Notification _platformNotification;
NotificationCallBack _platformCallBack;
Notification *_neighborhoodNotification;
uint16 _stateBits;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,816 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/compass.h"
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_action.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/ai/ai_condition.h"
#include "pegasus/ai/ai_rule.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/neighborhood/prehistoric/prehistoric.h"
namespace Pegasus {
static const int16 s_prehistoricCompass[kPrehistoric25 + 1][4] = {
{ 0, 170, 90, 270 }, // kPrehistoric01
{ 0, 180, 90, 270 }, // kPrehistoric02
{ 10, 180, 90, 270 }, // kPrehistoric03
{ 10, 190, 90, 270 }, // kPrehistoric04
{ 10, 195, 90, 270 }, // kPrehistoric05
{ 20, 210, 90, 270 }, // kPrehistoric06
{ 20, 200, 130, 276 }, // kPrehistoric07
{ 20, 176, 110, 260 }, // kPrehistoric08
{ 20, 200, 100, 270 }, // kPrehistoric09
{ 14, 186, 100, 280 }, // kPrehistoric10
{ 26, 206, 116, 296 }, // kPrehistoric11
{ 60, 226, 140, 320 }, // kPrehistoric12
{ 0, 180, 80, 270 }, // kPrehistoric13
{ 14, 200, 106, 286 }, // kPrehistoric14
{ -10, 174, 80, 260 }, // kPrehistoric15
{ 54, 236, 140, 210 }, // kPrehistoric16
{ -24, 160, 70, 250 }, // kPrehistoric17
{ 26, 206, 140, 296 }, // kPrehistoric18
{ -16, 160, 70, 250 }, // kPrehistoric19
{ -16, 160, 70, 250 }, // kPrehistoric20
{ -10, 160, 90, 250 }, // kPrehistoric21
{ -20, 160, 70, 244 }, // kPrehistoric22
{ -20, 160, 70, 244 }, // kPrehistoric22North
{ 60, 234, 150, 330 }, // kPrehistoric23
{ 50, 230, 140, 320 }, // kPrehistoric24
{ 60, 240, 140, 330 } // kPrehistoric25
};
static const TimeValue kPrehistoricFlashlightClickIn = 0;
static const TimeValue kPrehistoricFlashlightClickOut = 138;
static const TimeValue kPrehistoricBumpIntoWallIn = 138;
static const TimeValue kPrehistoricBumpIntoWallOut = 291;
static const TimeValue kBridgeRetractIn = 291;
static const TimeValue kBridgeRetractOut = 1499;
static const TimeValue kPrehistoricWarningTimeLimit = kTenMinutes;
Prehistoric::Prehistoric(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Prehistoric", kPrehistoricID) {
setIsItemTaken(kHistoricalLog);
}
uint16 Prehistoric::getDateResID() const {
return kDatePrehistoricID;
}
void Prehistoric::init() {
Neighborhood::init();
// Forces a stop so the flashlight can turn off...
forceStridingStop(kPrehistoric12, kSouth, kNoAlternateID);
}
void Prehistoric::start() {
if (g_energyMonitor) {
g_energyMonitor->stopEnergyDraining();
g_energyMonitor->restoreLastEnergyValue();
_vm->resetEnergyDeathReason();
g_energyMonitor->startEnergyDraining();
}
Neighborhood::start();
if (GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric02, kSouth) && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA01", kArthurGoToPrehistoric);
}
class FinishPrehistoricAction : public AIPlayMessageAction {
public:
FinishPrehistoricAction() : AIPlayMessageAction("Images/AI/Prehistoric/XP25W", false) {}
~FinishPrehistoricAction() override {}
void performAIAction(AIRule *) override;
};
void FinishPrehistoricAction::performAIAction(AIRule *rule) {
AIPlayMessageAction::performAIAction(rule);
g_vm->die(kPlayerWonGame);
}
void Prehistoric::setUpAIRules() {
Neighborhood::setUpAIRules();
if (g_AIArea) {
if (_vm->isDemo()) {
FinishPrehistoricAction *doneAction = new FinishPrehistoricAction();
AIHasItemCondition *hasLogCondition = new AIHasItemCondition(kHistoricalLog);
AIRule *rule = new AIRule(hasLogCondition, doneAction);
g_AIArea->addAIRule(rule);
}
if (!_vm->isOldDemo()) {
AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP1NB", false);
AILocationCondition *locCondition = new AILocationCondition(1);
locCondition->addLocation(MakeRoomView(kPrehistoric16, kNorth));
AIRule *rule = new AIRule(locCondition, messageAction);
g_AIArea->addAIRule(rule);
messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP2SB", false);
locCondition = new AILocationCondition(1);
locCondition->addLocation(MakeRoomView(kPrehistoric01, kSouth));
rule = new AIRule(locCondition, messageAction);
g_AIArea->addAIRule(rule);
messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP2SB", false);
locCondition = new AILocationCondition(1);
locCondition->addLocation(MakeRoomView(kPrehistoric08, kEast));
rule = new AIRule(locCondition, messageAction);
g_AIArea->addAIRule(rule);
messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP2SB", false);
locCondition = new AILocationCondition(1);
locCondition->addLocation(MakeRoomView(kPrehistoric25, kWest));
rule = new AIRule(locCondition, messageAction);
g_AIArea->addAIRule(rule);
messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP16NB", false);
locCondition = new AILocationCondition(1);
locCondition->addLocation(MakeRoomView(kPrehistoric23, kNorth));
rule = new AIRule(locCondition, messageAction);
g_AIArea->addAIRule(rule);
messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP18NB", false);
AITimerCondition *timerCondition = new AITimerCondition(kPrehistoricWarningTimeLimit, 1, true);
rule = new AIRule(timerCondition, messageAction);
g_AIArea->addAIRule(rule);
}
if (!_vm->isDemo()) {
AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP25W", false);
AIHasItemCondition *hasLogCondition = new AIHasItemCondition(kHistoricalLog);
AIRule *rule = new AIRule(hasLogCondition, messageAction);
g_AIArea->addAIRule(rule);
}
}
}
TimeValue Prehistoric::getViewTime(const RoomID room, const DirectionConstant direction) {
ExtraTable::Entry extra;
uint32 extraID = 0xffffffff;
switch (MakeRoomView(room, direction)) {
case MakeRoomView(kPrehistoric02, kSouth):
if (!GameState.getPrehistoricSeenTimeStream()) {
getExtraEntry(kPreArrivalFromTSA, extra);
return extra.movieStart;
}
break;
case MakeRoomView(kPrehistoric25, kEast):
if (_privateFlags.getFlag(kPrehistoricPrivateVaultOpenFlag)) {
if (_vm->itemInLocation(kHistoricalLog, kPrehistoricID, kPrehistoric25, kEast))
extraID = kPre25EastViewWithLog;
else
extraID = kPre25EastViewNoLog;
}
break;
default:
break;
}
if (extraID == 0xffffffff)
return Neighborhood::getViewTime(room, direction);
getExtraEntry(extraID, extra);
return extra.movieEnd - 1;
}
void Prehistoric::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &entry) {
Neighborhood::findSpotEntry(room, direction, flags, entry);
// The original strangely disabled the loop for the two volcano spots:
// (kPrehistoric01, kSouth) and (kPrehistoric25, kSouth)
// We don't do that here.
switch (MakeRoomView(room, direction)) {
case MakeRoomView(kPrehistoric01, kEast):
if (GameState.getPrehistoricSeenFlyer1())
entry.clear();
else
GameState.setPrehistoricSeenFlyer1(true);
break;
case MakeRoomView(kPrehistoric08, kEast):
if (GameState.getPrehistoricSeenFlyer2())
entry.clear();
else
GameState.setPrehistoricSeenFlyer2(true);
break;
default:
break;
}
}
int16 Prehistoric::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
if (room == kPrehistoricDeath)
return g_compass->getFaderValue();
return s_prehistoricCompass[room][dir];
}
void Prehistoric::getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) {
uint32 angle;
Neighborhood::getExitCompassMove(exitEntry, compassMove);
switch (MakeRoomView(exitEntry.room, exitEntry.direction)) {
case MakeRoomView(kPrehistoric01, kNorth):
compassMove.insertFaderKnot(exitEntry.movieStart + (exitEntry.movieEnd - exitEntry.movieStart) / 2, -10);
break;
case MakeRoomView(kPrehistoric06, kEast):
compassMove.insertFaderKnot(exitEntry.movieStart + (exitEntry.movieEnd - exitEntry.movieStart) / 4, 95);
compassMove.insertFaderKnot(exitEntry.movieStart + (exitEntry.movieEnd - exitEntry.movieStart) / 4 * 1, 100);
break;
case MakeRoomView(kPrehistoric18, kEast):
if (getCurrentAlternate() == kAltPrehistoricBridgeSet) {
compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 11, 145);
compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 26, 145);
compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 39, 148);
compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 114, 140);
} else {
compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 10, 140);
compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 16, 145);
compassMove.insertFaderKnot(exitEntry.movieEnd, 145);
}
break;
case MakeRoomView(kPrehistoric23, kWest):
angle = compassMove.getNthKnotValue(0);
compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 17, angle);
compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 32, angle - 90);
compassMove.insertFaderKnot(exitEntry.movieEnd, angle - 90);
break;
default:
break;
}
}
void Prehistoric::turnTo(const DirectionConstant newDirection) {
setCurrentAlternate(kAltPrehistoricNormal);
_privateFlags.setFlag(kPrehistoricPrivateVaultOpenFlag, false);
Neighborhood::turnTo(newDirection);
Item *keyCard;
bool doArthurFeelLikeYodelingMovie = false;
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kPrehistoric08, kEast):
case MakeRoomView(kPrehistoric10, kEast):
case MakeRoomView(kPrehistoric12, kEast):
case MakeRoomView(kPrehistoric14, kEast):
case MakeRoomView(kPrehistoric25, kWest):
doArthurFeelLikeYodelingMovie = true;
break;
case MakeRoomView(kPrehistoric18, kEast):
zoomToVault();
break;
case MakeRoomView(kPrehistoric18, kNorth):
case MakeRoomView(kPrehistoric18, kSouth):
if (_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag)) {
playSpotSoundSync(kBridgeRetractIn, kBridgeRetractOut);
_privateFlags.setFlag(kPrehistoricPrivateExtendedBridgeFlag, false);
loadAmbientLoops();
}
// fall through
case MakeRoomView(kPrehistoric25, kEast):
setCurrentActivation(kActivationVaultClosed);
if (GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric25, kEast) &&
!GameState.isTakenItemID(kHistoricalLog) && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA60", kArthurPrehistoricCrossedBridge);
break;
case MakeRoomView(kPrehistoric23, kWest):
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA59", kArthurPrehistoricSawEggs);
break;
case MakeRoomView(kPrehistoric16, kNorth):
case MakeRoomView(kPrehistoric21, kWest):
keyCard = _vm->getAllItems().findItemByID(kKeyCard);
if (keyCard->getItemState() == kFlashlightOff) {
keyCard->setItemState(kFlashlightOn);
playSpotSoundSync(kPrehistoricFlashlightClickIn, kPrehistoricFlashlightClickOut);
}
break;
case MakeRoomView(kPrehistoric16, kEast):
case MakeRoomView(kPrehistoric16, kWest):
case MakeRoomView(kPrehistoric21, kNorth):
case MakeRoomView(kPrehistoric21, kSouth):
keyCard = _vm->getAllItems().findItemByID(kKeyCard);
if (keyCard->getItemState() == kFlashlightOn) {
keyCard->setItemState(kFlashlightOff);
playSpotSoundSync(kPrehistoricFlashlightClickIn, kPrehistoricFlashlightClickOut);
}
break;
default:
break;
}
if (doArthurFeelLikeYodelingMovie && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA15", kArthurPrehistoricAtCliffEdge);
}
void Prehistoric::zoomToVault() {
if (!GameState.getPrehistoricSeenBridgeZoom())
startExtraSequence(kPre18EastZoom, kExtraCompletedFlag, kFilterNoInput);
}
void Prehistoric::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
switch (MakeRoomView(room, direction)) {
case MakeRoomView(kPrehistoric08, kEast):
case MakeRoomView(kPrehistoric18, kSouth):
case MakeRoomView(kPrehistoric16, kNorth):
case MakeRoomView(kPrehistoric21, kNorth):
case MakeRoomView(kPrehistoric25, kNorth):
makeContinuePoint();
break;
default:
break;
}
}
void Prehistoric::arriveAt(const RoomID room, const DirectionConstant direction) {
Item *keyCard;
bool doArthurLetsSpreadOutMovie, doArthurFeelLikeYodelingMovie;
if (MakeRoomView(room, direction) == MakeRoomView(kPrehistoric25, kEast) &&
_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag)) {
_navMovie.stop();
playSpotSoundSync(kBridgeRetractIn, kBridgeRetractOut);
_privateFlags.setFlag(kPrehistoricPrivateExtendedBridgeFlag, false);
}
Neighborhood::arriveAt(room, direction);
doArthurLetsSpreadOutMovie = false;
doArthurFeelLikeYodelingMovie = false;
switch (MakeRoomView(room, direction)) {
case MakeRoomView(kPrehistoricDeath, kNorth):
case MakeRoomView(kPrehistoricDeath, kSouth):
case MakeRoomView(kPrehistoricDeath, kEast):
case MakeRoomView(kPrehistoricDeath, kWest):
if (GameState.getLastRoom() == kPrehistoric23)
die(kDeathEatenByDinosaur);
else
die(kDeathFallOffCliff);
break;
case MakeRoomView(kPrehistoric02, kSouth):
if (!GameState.getPrehistoricSeenTimeStream()) {
GameState.setPrehistoricTriedToExtendBridge(false);
GameState.setPrehistoricSeenFlyer1(false);
GameState.setPrehistoricSeenFlyer2(false);
GameState.setPrehistoricSeenBridgeZoom(false);
GameState.setPrehistoricBreakerThrown(false);
startExtraSequence(kPreArrivalFromTSA, kExtraCompletedFlag, kFilterNoInput);
}
break;
case MakeRoomView(kPrehistoric06, kNorth):
case MakeRoomView(kPrehistoric13, kWest):
doArthurLetsSpreadOutMovie = true;
break;
case MakeRoomView(kPrehistoric22North, kNorth):
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB44", kArthurPrehistoricSawBreaker);
break;
case MakeRoomView(kPrehistoric10, kEast):
case MakeRoomView(kPrehistoric12, kEast):
case MakeRoomView(kPrehistoric14, kEast):
case MakeRoomView(kPrehistoric25, kWest):
doArthurFeelLikeYodelingMovie = true;
break;
case MakeRoomView(kPrehistoric18, kEast):
zoomToVault();
break;
case MakeRoomView(kPrehistoric16, kNorth):
keyCard = _vm->getAllItems().findItemByID(kKeyCard);
if (keyCard->getItemState() == kFlashlightOff) {
keyCard->setItemState(kFlashlightOn);
playSpotSoundSync(kPrehistoricFlashlightClickIn, kPrehistoricFlashlightClickOut);
}
if (g_AIArea)
g_AIArea->checkRules();
break;
case MakeRoomView(kPrehistoric01, kSouth):
case MakeRoomView(kPrehistoric23, kNorth):
if (g_AIArea)
g_AIArea->checkRules();
break;
case MakeRoomView(kPrehistoric13, kNorth):
doArthurLetsSpreadOutMovie = true;
// falls through
case MakeRoomView(kPrehistoric08, kSouth):
case MakeRoomView(kPrehistoric10, kSouth):
case MakeRoomView(kPrehistoric12, kSouth):
case MakeRoomView(kPrehistoric14, kSouth):
case MakeRoomView(kPrehistoric15, kNorth):
case MakeRoomView(kPrehistoric16, kSouth):
case MakeRoomView(kPrehistoric17, kNorth):
case MakeRoomView(kPrehistoric18, kSouth):
case MakeRoomView(kPrehistoric19, kNorth):
case MakeRoomView(kPrehistoric20, kNorth):
case MakeRoomView(kPrehistoric21, kEast):
keyCard = _vm->getAllItems().findItemByID(kKeyCard);
if (keyCard->getItemState() == kFlashlightOn) {
keyCard->setItemState(kFlashlightOff);
playSpotSoundSync(kPrehistoricFlashlightClickIn, kPrehistoricFlashlightClickOut);
}
break;
case MakeRoomView(kPrehistoric25, kEast):
setCurrentActivation(kActivationVaultClosed);
if (!GameState.isTakenItemID(kHistoricalLog) && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA60", kArthurPrehistoricCrossedBridge);
break;
case MakeRoomView(kPrehistoric23, kWest):
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA59", kArthurPrehistoricSawEggs);
break;
default:
break;
}
if (g_arthurChip) {
if (doArthurLetsSpreadOutMovie)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA20", kArthurPrehistoricReachedJunction);
else if (doArthurFeelLikeYodelingMovie)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA15", kArthurPrehistoricAtCliffEdge);
}
}
void Prehistoric::loadAmbientLoops() {
RoomID room = GameState.getCurrentRoom();
switch (room) {
case kPrehistoric02:
// 1/4 volume.
if (!GameState.getPrehistoricSeenTimeStream())
break;
// Fall through
case kPrehistoric01:
case kPrehistoric03:
case kPrehistoric04:
case kPrehistoric05:
case kPrehistoric06:
case kPrehistoric07:
case kPrehistoric09:
case kPrehistoric11:
case kPrehistoric13:
case kPrehistoric15:
case kPrehistoric17:
case kPrehistoric19:
case kPrehistoric20:
// 1/4 volume.
if (_vm->isDVD()) // Updated sound for the DVD version
loadLoopSound1("Sounds/Prehistoric/P02SAL00.32K.AIFF", 64);
else
loadLoopSound1("Sounds/Prehistoric/P02SAL00.22K.AIFF", 64);
break;
case kPrehistoric08:
case kPrehistoric10:
case kPrehistoric12:
case kPrehistoric14:
case kPrehistoric16:
case kPrehistoric18:
case kPrehistoric21:
// 3/16 volume.
if (_vm->isDVD()) // Updated sound for the DVD version
loadLoopSound1("Sounds/Prehistoric/P02SAL00.32K.AIFF", 48);
else
loadLoopSound1("Sounds/Prehistoric/P02SAL00.22K.AIFF", 48);
break;
case kPrehistoric25:
// 1/8 volume.
if (_vm->isDVD()) // Updated sound for the DVD version
loadLoopSound1("Sounds/Prehistoric/P02SAL00.32K.AIFF", 32);
else
loadLoopSound1("Sounds/Prehistoric/P02SAL00.22K.AIFF", 32);
break;
case kPrehistoric22:
case kPrehistoric22North:
case kPrehistoric23:
case kPrehistoric24:
case kPrehistoricDeath:
// 0 volume.
loadLoopSound1("");
break;
default:
break;
}
switch (room) {
case kPrehistoric02:
case kPrehistoric03:
case kPrehistoric04:
case kPrehistoric05:
case kPrehistoric06:
case kPrehistoric07:
case kPrehistoric08:
case kPrehistoric09:
case kPrehistoric10:
case kPrehistoric11:
case kPrehistoric12:
case kPrehistoric13:
case kPrehistoric14:
case kPrehistoric15:
case kPrehistoric16:
case kPrehistoric17:
case kPrehistoric19:
case kPrehistoric20:
case kPrehistoric21:
case kPrehistoricDeath:
loadLoopSound2("");
break;
case kPrehistoric01:
case kPrehistoric25:
if (_vm->isDVD())
loadLoopSound2("Sounds/Prehistoric/VolcLoop.32K.AIFF", 64);
else
loadLoopSound2("Sounds/Prehistoric/VolcLoop.22K.AIFF", 64);
break;
case kPrehistoric18:
if (_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag)) {
if (_vm->isDVD()) // Updated sound for the DVD version
loadLoopSound2("Sounds/Prehistoric/P18EAL00.44K.AIFF", 0x100, 0, 0);
else
loadLoopSound2("Sounds/Prehistoric/P18EAL00.22K.AIFF", 0x100, 0, 0);
} else {
loadLoopSound2("");
}
break;
case kPrehistoric23:
case kPrehistoric24:
case kPrehistoric22:
case kPrehistoric22North:
if (_vm->isDVD()) // Updated sound for the DVD version
loadLoopSound2("Sounds/Prehistoric/P24NAL00.32K.AIFF", 64);
else
loadLoopSound2("Sounds/Prehistoric/P24NAL00.22K.aiff", 64);
break;
default:
break;
}
}
void Prehistoric::activateHotspots() {
Neighborhood::activateHotspots();
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kPrehistoric18, kEast):
if (!_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag))
_vm->getAllHotspots().activateOneHotspot(kPre18EastSpotID);
break;
case MakeRoomView(kPrehistoric22North, kNorth):
_vm->getAllHotspots().activateOneHotspot(kPre22NorthBreakerSpotID);
break;
default:
break;
}
}
void Prehistoric::clickInHotspot(const Input &input, const Hotspot *spot) {
switch (spot->getObjectID()) {
case kPre18EastSpotID:
if (GameState.getPrehistoricBreakerThrown())
startExtraSequence(kPre18EastBridgeOn, kExtraCompletedFlag, kFilterNoInput);
else
startExtraSequence(kPre18EastBridgeOut, kExtraCompletedFlag, kFilterNoInput);
break;
case kPre22NorthBreakerSpotID:
startExtraSequence(kPre22ThrowBreaker, kExtraCompletedFlag, kFilterNoInput);
break;
default:
Neighborhood::clickInHotspot(input, spot);
break;
}
}
void Prehistoric::receiveNotification(Notification *notification, const NotificationFlags flags) {
Neighborhood::receiveNotification(notification, flags);
if ((flags & kExtraCompletedFlag) != 0) {
_interruptionFilter = kFilterAllInput;
switch (_lastExtra) {
case kPreArrivalFromTSA:
GameState.setPrehistoricSeenTimeStream(true);
loadAmbientLoops();
makeContinuePoint();
break;
case kPre18EastZoom:
startExtraSequence(kPre18EastZoomOut, kExtraCompletedFlag, kFilterNoInput);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA61", kArthurPrehistoricZoomedToVault);
break;
case kPre18EastZoomOut:
GameState.setPrehistoricSeenBridgeZoom(true);
break;
case kPre18EastBridgeOn:
_privateFlags.setFlag(kPrehistoricPrivateExtendedBridgeFlag, true);
setCurrentAlternate(kAltPrehistoricBridgeSet);
GameState.setPrehistoricTriedToExtendBridge(false);
loadAmbientLoops();
GameState.setScoringExtendedBridge(true);
if (g_arthurChip) {
if (_vm->getRandomBit())
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA10", kArthurPrehistoricExtendedBridge);
else
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA56", kArthurPrehistoricExtendedBridge);
}
break;
case kPre18EastBridgeOut:
GameState.setPrehistoricTriedToExtendBridge(true);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA58", kArthurPrehistoricAttemptedBridge);
if (g_AIArea)
g_AIArea->checkMiddleArea();
break;
case kPre22ThrowBreaker:
GameState.setPrehistoricBreakerThrown(true);
GameState.setScoringThrewBreaker(true);
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA57", kArthurPrehistoricBreakerThrown);
break;
case kPre25EastUnlockingVaultNoLog:
case kPre25EastUnlockingVaultWithLog:
if (!GameState.isTakenItemID(kHistoricalLog) && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA05", kArthurPrehistoricUnlockedVault);
_vm->addItemToInventory((InventoryItem *)_vm->getAllItems().findItemByID(kJourneymanKey));
break;
default:
break;
}
} else if ((flags & kSpotCompletedFlag) != 0 &&
GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric08, kEast)) {
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA15", kArthurPrehistoricAtCliffEdge);
}
g_AIArea->checkMiddleArea();
}
void Prehistoric::spotCompleted() {
Neighborhood::spotCompleted();
if (GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric08, kEast) && g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA15", kArthurPrehistoricAtCliffEdge);
}
Common::Path Prehistoric::getBriefingMovie() {
Common::Path movieName = Neighborhood::getBriefingMovie();
if (movieName.empty())
movieName = "Images/AI/Prehistoric/XPE";
return movieName;
}
Common::Path Prehistoric::getEnvScanMovie() {
Common::Path movieName = Neighborhood::getEnvScanMovie();
if (movieName.empty()) {
if (!_vm->isOldDemo()) {
switch (GameState.getCurrentRoom()) {
case kPrehistoric16:
case kPrehistoric23:
case kPrehistoric24:
return "Images/AI/Prehistoric/XP7WB";
default:
break;
}
}
return "Images/AI/Prehistoric/XP17NB";
}
return movieName;
}
uint Prehistoric::getNumHints() {
uint numHints = Neighborhood::getNumHints();
if (numHints == 0) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kPrehistoric18, kEast):
if (!GameState.getPrehistoricBreakerThrown() && GameState.getPrehistoricTriedToExtendBridge() &&
!_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag))
numHints = 1;
break;
case MakeRoomView(kPrehistoric25, kEast):
if (!_privateFlags.getFlag(kPrehistoricPrivateVaultOpenFlag))
numHints = 1;
break;
default:
break;
}
}
return numHints;
}
Common::Path Prehistoric::getHintMovie(uint hintNum) {
Common::Path movieName = Neighborhood::getHintMovie(hintNum);
if (movieName.empty()) {
switch (GameState.getCurrentRoomAndView()) {
case MakeRoomView(kPrehistoric18, kEast):
return "Images/AI/Prehistoric/XP18WD";
case MakeRoomView(kPrehistoric25, kEast):
return "Images/AI/Globals/XGLOB1A";
default:
break;
}
}
return movieName;
}
bool Prehistoric::canSolve() {
return GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric18, kEast) &&
!GameState.getPrehistoricBreakerThrown() &&
GameState.getPrehistoricTriedToExtendBridge() &&
!_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag);
}
void Prehistoric::doSolve() {
GameState.setPrehistoricBreakerThrown(true);
startExtraSequence(kPre18EastBridgeOn, kExtraCompletedFlag, kFilterNoInput);
}
Hotspot *Prehistoric::getItemScreenSpot(Item *item, DisplayElement *element) {
if (item->getObjectID() == kHistoricalLog)
return _vm->getAllHotspots().findHotspotByID(kPrehistoricHistoricalLogSpotID);
return Neighborhood::getItemScreenSpot(item, element);
}
void Prehistoric::pickedUpItem(Item *item) {
switch (item->getObjectID()) {
case kHistoricalLog:
GameState.setScoringGotHistoricalLog(true);
break;
default:
break;
}
Neighborhood::pickedUpItem(item);
}
void Prehistoric::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
switch (item->getObjectID()) {
case kJourneymanKey:
Neighborhood::dropItemIntoRoom(item, dropSpot);
if (GameState.isTakenItemID(kHistoricalLog))
startExtraLongSequence(kPre25EastUnlockingVaultNoLog, kPre25EastVaultOpenNoLog, kExtraCompletedFlag, kFilterNoInput);
else
startExtraLongSequence(kPre25EastUnlockingVaultWithLog, kPre25EastVaultOpenWithLog, kExtraCompletedFlag, kFilterNoInput);
_privateFlags.setFlag(kPrehistoricPrivateVaultOpenFlag, true);
setCurrentActivation(kActivationVaultOpen);
break;
default:
Neighborhood::dropItemIntoRoom(item, dropSpot);
break;
}
}
void Prehistoric::bumpIntoWall() {
requestSpotSound(kPrehistoricBumpIntoWallIn, kPrehistoricBumpIntoWallOut, kFilterAllInput, 0);
Neighborhood::bumpIntoWall();
}
Common::Path Prehistoric::getNavMovieName() {
return "Images/Prehistoric/Prehistoric.movie";
}
Common::Path Prehistoric::getSoundSpotsName() {
return "Sounds/Prehistoric/Prehistoric Spots";
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,158 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_PREHISTORIC_H
#define PEGASUS_NEIGHBORHOOD_PREHISTORIC_H
#include "pegasus/neighborhood/neighborhood.h"
namespace Pegasus {
static const TimeScale kPrehistoricMovieScale = 600;
static const TimeScale kPrehistoricFramesPerSecond = 15;
static const TimeScale kPrehistoricFrameDuration = 40;
// Alternate IDs.
static const AlternateID kAltPrehistoricNormal = 0;
static const AlternateID kAltPrehistoricBridgeSet = 1;
// Room IDs.
static const RoomID kPrehistoric01 = 0;
static const RoomID kPrehistoric02 = 1;
static const RoomID kPrehistoric03 = 2;
static const RoomID kPrehistoric04 = 3;
static const RoomID kPrehistoric05 = 4;
static const RoomID kPrehistoric06 = 5;
static const RoomID kPrehistoric07 = 6;
static const RoomID kPrehistoric08 = 7;
static const RoomID kPrehistoric09 = 8;
static const RoomID kPrehistoric10 = 9;
static const RoomID kPrehistoric11 = 10;
static const RoomID kPrehistoric12 = 11;
static const RoomID kPrehistoric13 = 12;
static const RoomID kPrehistoric14 = 13;
static const RoomID kPrehistoric15 = 14;
static const RoomID kPrehistoric16 = 15;
static const RoomID kPrehistoric17 = 16;
static const RoomID kPrehistoric18 = 17;
static const RoomID kPrehistoric19 = 18;
static const RoomID kPrehistoric20 = 19;
static const RoomID kPrehistoric21 = 20;
static const RoomID kPrehistoric22 = 21;
static const RoomID kPrehistoric22North = 22;
static const RoomID kPrehistoric23 = 23;
static const RoomID kPrehistoric24 = 24;
static const RoomID kPrehistoric25 = 25;
static const RoomID kPrehistoricDeath = 26;
// Hot Spot Activation IDs.
static const HotSpotActivationID kActivationVaultClosed = 1;
static const HotSpotActivationID kActivationVaultOpen = 2;
// Hot Spot IDs.
static const HotSpotID kPre18EastSpotID = 5000;
static const HotSpotID kPre22NorthSpotID = 5001;
static const HotSpotID kPre22NorthOutSpotID = 5002;
static const HotSpotID kPre22NorthBreakerSpotID = 5003;
static const HotSpotID kPrehistoricKeyDropSpotID = 5004;
static const HotSpotID kPrehistoricHistoricalLogSpotID = 5005;
// Extra sequence IDs.
static const ExtraID kPreArrivalFromTSA = 0;
static const ExtraID kPre18EastBridgeOut = 1;
static const ExtraID kPre18EastBridgeOn = 2;
static const ExtraID kPre18EastZoom = 3;
static const ExtraID kPre18EastZoomOut = 4;
static const ExtraID kPre22ThrowBreaker = 5;
static const ExtraID kPre25EastUnlockingVaultWithLog = 6;
static const ExtraID kPre25EastVaultOpenWithLog = 7;
static const ExtraID kPre25EastViewWithLog = 8;
static const ExtraID kPre25EastUnlockingVaultNoLog = 9;
static const ExtraID kPre25EastVaultOpenNoLog = 10;
static const ExtraID kPre25EastViewNoLog = 11;
class PegasusEngine;
class Prehistoric : public Neighborhood {
public:
Prehistoric(InputHandler *, PegasusEngine *);
~Prehistoric() override {}
uint16 getDateResID() const override;
void init() override;
void arriveAt(const RoomID, const DirectionConstant) override;
void activateHotspots() override;
void clickInHotspot(const Input &, const Hotspot *) override;
Common::Path getBriefingMovie() override;
Common::Path getEnvScanMovie() override;
uint getNumHints() override;
Common::Path getHintMovie(uint) override;
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
void dropItemIntoRoom(Item *, Hotspot *) override;
void pickedUpItem(Item *) override;
void start() override;
void bumpIntoWall() override;
void checkContinuePoint(const RoomID, const DirectionConstant) override;
bool canSolve() override;
void doSolve() override;
protected:
enum {
kPrehistoricPrivateVaultOpenFlag,
kPrehistoricPrivateExtendedBridgeFlag,
kNumPrehistoricPrivateFlags
};
void setUpAIRules() override;
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &) override;
void receiveNotification(Notification *, const NotificationFlags) override;
void spotCompleted() override;
void turnTo(const DirectionConstant) override;
void zoomToVault();
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &) override;
void loadAmbientLoops() override;
FlagsArray<byte, kNumPrehistoricPrivateFlags> _privateFlags;
Common::Path getNavMovieName() override;
Common::Path getSoundSpotsName() override;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,69 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "pegasus/neighborhood/spot.h"
namespace Pegasus {
void SpotTable::loadFromStream(Common::SeekableReadStream *stream) {
uint32 count = stream->readUint32BE();
_entries.resize(count);
for (uint32 i = 0; i < count; i++) {
_entries[i].room = stream->readUint16BE();
_entries[i].direction = stream->readByte();
_entries[i].srcFlags = stream->readByte();
_entries[i].altCode = stream->readByte();
stream->readByte(); // alignment
_entries[i].movieStart = stream->readUint32BE();
_entries[i].movieEnd = stream->readUint32BE();
_entries[i].dstFlags = stream->readByte();
stream->readByte(); // alignment
debug(0, "Spot[%d]: %d %d %d %d %d %d %d", i, _entries[i].room, _entries[i].direction,
_entries[i].srcFlags, _entries[i].altCode, _entries[i].movieStart,
_entries[i].movieEnd, _entries[i].dstFlags);
}
}
void SpotTable::clear() {
_entries.clear();
}
// Two SpotTable::Entries are equal if
// In addition to having their rooms, directions and alt codes identical...
// They are both either loops or once only animations AND
// They overlap in at least one of the on arrival, on turn and on door open bits.
SpotTable::Entry SpotTable::findEntry(RoomID room, DirectionConstant direction, SpotFlags srcFlags, AlternateID altCode) {
for (uint32 i = 0; i < _entries.size(); i++)
if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].altCode == altCode && (_entries[i].srcFlags & kSpotLoopsMask) == (srcFlags & kSpotLoopsMask) && ((_entries[i].srcFlags & srcFlags) & kSpotTriggers) != 0)
return _entries[i];
return Entry();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,96 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_SPOT_H
#define PEGASUS_NEIGHBORHOOD_SPOT_H
#include "common/array.h"
#include "common/endian.h"
#include "pegasus/constants.h"
namespace Common {
class SeekableReadStream;
}
namespace Pegasus {
typedef byte SpotFlags;
enum {
kSpotLoopsBit, // Loop or once only?
kSpotOnArrivalBit,
kSpotOnTurnBit,
kSpotOnDoorOpenBit
};
static const SpotFlags kNoSpotFlags = 0;
static const SpotFlags kSpotLoopsMask = 1 << kSpotLoopsBit;
static const SpotFlags kSpotOnArrivalMask = 1 << kSpotOnArrivalBit;
static const SpotFlags kSpotOnTurnMask = 1 << kSpotOnTurnBit;
static const SpotFlags kSpotOnDoorOpenMask = 1 << kSpotOnDoorOpenBit;
static const SpotFlags kSpotTriggers = kSpotOnArrivalMask | kSpotOnTurnMask | kSpotOnDoorOpenMask;
class SpotTable {
public:
SpotTable() {}
~SpotTable() {}
static uint32 getResTag() { return MKTAG('S', 'p', 'o', 't'); }
void loadFromStream(Common::SeekableReadStream *stream);
void clear();
struct Entry {
Entry() { clear(); }
bool isEmpty() { return movieStart == 0xffffffff; }
void clear() {
room = kNoRoomID;
direction = kNoDirection;
srcFlags = kNoSpotFlags;
altCode = kNoAlternateID;
movieStart = 0xffffffff;
movieEnd = 0xffffffff;
dstFlags = kNoSpotFlags;
}
RoomID room;
DirectionConstant direction;
SpotFlags srcFlags;
AlternateID altCode;
TimeValue movieStart;
TimeValue movieEnd;
SpotFlags dstFlags;
};
Entry findEntry(RoomID room, DirectionConstant direction, SpotFlags srcFlags, AlternateID altCode);
private:
Common::Array<Entry> _entries;
};
} // End of namespace Pegasus
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,175 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_TSA_FULLTSA_H
#define PEGASUS_NEIGHBORHOOD_TSA_FULLTSA_H
#include "pegasus/neighborhood/neighborhood.h"
namespace Pegasus {
class RipTimer : public IdlerAnimation {
public:
RipTimer(const DisplayElementID id) : IdlerAnimation(id) {}
~RipTimer() override {}
void initImage();
void releaseImage();
void draw(const Common::Rect &) override;
protected:
void timeChanged(const TimeValue) override;
CoordType _middle;
Surface _timerImage;
};
// Room IDs.
static const RoomID kTSA00 = 0;
static const RoomID kTSA22Red = 28;
static const RoomID kTSA37 = 42;
class FullTSA : public Neighborhood {
public:
FullTSA(InputHandler *, PegasusEngine *);
~FullTSA() override {}
void init() override;
void start() override;
uint16 getDateResID() const override;
void flushGameState() override;
void checkContinuePoint(const RoomID, const DirectionConstant) override;
void setSoundFXLevel(const uint16) override;
void setAmbienceLevel(const uint16) override;
bool canSolve() override;
void doSolve() override;
void updateCursor(const Common::Point &, const Hotspot *) override;
protected:
enum {
kTSAPrivateLogReaderOpenFlag,
kTSAPrivateKeyVaultOpenFlag,
kTSAPrivateChipVaultOpenFlag,
kTSAPrivatePlayingLeftComparisonFlag,
kTSAPrivatePlayingRightComparisonFlag,
kTSAPrivateSeenRobotWarningFlag,
kNumTSAPrivateFlags
};
Common::Path getBriefingMovie() override;
Common::Path getEnvScanMovie() override;
uint getNumHints() override;
Common::Path getHintMovie(uint) override;
void loadAmbientLoops() override;
void clickInHotspot(const Input &, const Hotspot *) override;
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *spot) override;
void activateHotspots() override;
void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &) override;
void dropItemIntoRoom(Item *, Hotspot *) override;
void downButton(const Input &) override;
void startDoorOpenMovie(const TimeValue, const TimeValue) override;
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
void showViewFrame(TimeValue) override;
void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &) override;
void turnTo(const DirectionConstant) override;
CanMoveForwardReason canMoveForward(ExitTable::Entry &) override;
void moveForward() override;
CanOpenDoorReason canOpenDoor(DoorTable::Entry &) override;
void bumpIntoWall() override;
void initializeTBPMonitor(const int, const ExtraID);
void playTBPMonitor();
void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &) override;
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
void openDoor() override;
void doorOpened() override;
void turnRight() override;
void turnLeft() override;
void closeDoorOffScreen(const RoomID, const DirectionConstant) override;
void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void playExtraMovie(const ExtraTable::Entry &, const NotificationFlags, const InputBits interruptionInput) override;
void startTurnPush(const TurnDirection, const TimeValue, const DirectionConstant) override;
void handleInput(const Input &, const Hotspot *) override;
void arriveAtTSA25Red();
void startUpComparisonMonitor();
void shutDownComparisonMonitor();
void initializeComparisonMonitor(const int, const ExtraID);
void playLeftComparison();
void playRightComparison();
void startRobotGame();
void setOffRipAlarm();
uint getHistoricalLogIndex();
void startUpRobotMonitor();
void shutDownRobotMonitor();
void pickedUpItem(Item *item) override;
void arriveFromPrehistoric();
void arriveFromNorad();
void arriveFromMars();
void arriveFromWSC();
InputBits getInputFilter() override;
void arriveAt(const RoomID, const DirectionConstant) override;
void initializePegasusButtons(bool);
void releaseSprites();
void showMainJumpMenu();
void arriveAtTSA37();
void receiveNotification(Notification *, const NotificationFlags) override;
void checkRobotLocations(const RoomID, const DirectionConstant);
void getExtraEntry(const uint32, ExtraTable::Entry &) override;
Movie _extraMovie;
NotificationCallBack _extraMovieCallBack;
Movie _blankMovie;
Sound _entranceMusic;
SoundFader _entranceFader;
bool _playedSolvedMusicCue;
Sound _solvedMusicCue;
Sprite _sprite1, _sprite2, _sprite3;
FuseFunction _utilityFuse;
RipTimer _ripTimer;
FlagsArray<byte, kNumTSAPrivateFlags> _privateFlags;
Common::Path getNavMovieName() override;
Common::Path getSoundSpotsName() override;
void dieUncreatedInTSA();
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,485 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/energymonitor.h"
#include "pegasus/gamestate.h"
#include "pegasus/pegasus.h"
#include "pegasus/ai/ai_area.h"
#include "pegasus/items/biochips/aichip.h"
#include "pegasus/items/biochips/arthurchip.h"
#include "pegasus/items/biochips/opticalchip.h"
#include "pegasus/neighborhood/mars/constants.h"
#include "pegasus/neighborhood/norad/constants.h"
#include "pegasus/neighborhood/tsa/tinytsa.h"
#include "pegasus/neighborhood/wsc/wsc.h"
namespace Pegasus {
static const int16 kCompassShift = 30;
enum {
kTinyTSAMovieScale = 600,
kTinyTSAFramesPerSecond = 15,
kTinyTSAFrameDuration = 40
};
// Alternate IDs.
enum {
kAltTinyTSANormal = 0
};
// Hot Spot Activation IDs.
enum {
kActivationTinyTSAJumpToNorad = 1,
kActivationTinyTSAJumpToMars = 2,
kActivationTinyTSAJumpToWSC = 3,
kActivationTinyTSAReadyForJumpMenu = 4,
kActivationTinyTSAMainJumpMenu = 5
};
// Hot Spot IDs.
enum {
kTinyTSA37NorthJumpToNoradSpotID = 5000,
kTinyTSA37NorthCancelNoradSpotID = 5001,
kTinyTSA37NorthJumpToMarsSpotID = 5002,
kTinyTSA37NorthCancelMarsSpotID = 5003,
kTinyTSA37NorthJumpToWSCSpotID = 5004,
kTinyTSA37NorthCancelWSCSpotID = 5005,
kTinyTSA37NorthJumpMenuSpotID = 5006,
kTinyTSA37NorthNoradMenuSpotID = 5007,
kTinyTSA37NorthMarsMenuSpotID = 5008,
kTinyTSA37NorthWSCMenuSpotID = 5009
};
// Extra sequence IDs.
enum {
kTinyTSA37PegasusDepart = 0,
kTinyTSA37TimeJumpToPegasus = 1,
kTinyTSA37RecallToDownload = 2,
kTinyTSA37ExitHilited = 3,
kTinyTSA37ExitToHorse = 4,
kTinyTSA37JumpMenu000 = 5,
kTinyTSA37JumpMenu001 = 6,
kTinyTSA37JumpMenu010 = 7,
kTinyTSA37JumpMenu011 = 8,
kTinyTSA37JumpMenu100 = 9,
kTinyTSA37JumpMenu101 = 10,
kTinyTSA37JumpMenu110 = 11,
kTinyTSA37JumpMenu111 = 12,
kTinyTSA37JumpToWSCMenu = 13,
kTinyTSA37CancelWSC = 14,
kTinyTSA37JumpToWSC = 15,
kTinyTSA37WSCToAI5 = 16,
kTinyTSA37PegasusAI5 = 17,
kTinyTSA37AI5ToWSC = 18,
kTinyTSA37WSCToDepart = 19,
kTinyTSA37JumpToMarsMenu = 20,
kTinyTSA37CancelMars = 21,
kTinyTSA37JumpToMars = 22,
kTinyTSA37MarsToAI6 = 23,
kTinyTSA37PegasusAI6 = 24,
kTinyTSA37AI6ToMars = 25,
kTinyTSA37MarsToDepart = 26,
kTinyTSA37JumpToNoradMenu = 27,
kTinyTSA37CancelNorad = 28,
kTinyTSA37JumpToNorad = 29,
kTinyTSA37NoradToAI7 = 30,
kTinyTSA37PegasusAI7 = 31,
kTinyTSA37AI7ToNorad = 32,
kTinyTSA37NoradToDepart = 33,
kTinyTSA37EnvironmentalScan = 34,
kTinyTSA37DownloadToMainMenu = 35,
kTinyTSA37DownloadToOpMemReview = 36,
kTinyTSA37OpMemReviewToMainMenu = 37
};
TinyTSA::TinyTSA(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Tiny TSA", kTinyTSAID) {
}
void TinyTSA::start() {
g_energyMonitor->stopEnergyDraining();
Neighborhood::start();
}
Common::Path TinyTSA::getBriefingMovie() {
Common::Path movieName = Neighborhood::getBriefingMovie();
if (movieName.empty()) {
switch (getCurrentActivation()) {
case kActivationTinyTSAJumpToNorad:
g_AIChip->showBriefingClicked();
startExtraSequenceSync(kTinyTSA37PegasusAI7, kHintInterruption);
startExtraSequenceSync(kTinyTSA37AI7ToNorad, kFilterNoInput);
g_AIChip->clearClicked();
movieName = "";
break;
case kActivationTinyTSAJumpToMars:
g_AIChip->showBriefingClicked();
startExtraSequenceSync(kTinyTSA37PegasusAI6, kHintInterruption);
startExtraSequenceSync(kTinyTSA37AI6ToMars, kFilterNoInput);
g_AIChip->clearClicked();
movieName = "";
break;
case kActivationTinyTSAJumpToWSC:
g_AIChip->showBriefingClicked();
startExtraSequenceSync(kTinyTSA37PegasusAI5, kHintInterruption);
startExtraSequenceSync(kTinyTSA37AI5ToWSC, kFilterNoInput);
g_AIChip->clearClicked();
movieName = "";
break;
default:
movieName = "Images/AI/TSA/XT04";
break;
}
}
return movieName;
}
Common::Path TinyTSA::getEnvScanMovie() {
Common::Path movieName = Neighborhood::getEnvScanMovie();
if (movieName.empty()) {
g_AIChip->showEnvScanClicked();
startExtraSequenceSync(kTinyTSA37EnvironmentalScan, kHintInterruption);
switch (getCurrentActivation()) {
case kActivationTinyTSAJumpToNorad:
startExtraSequenceSync(kTinyTSA37AI7ToNorad, kFilterNoInput);
showExtraView(kTinyTSA37JumpToNoradMenu);
break;
case kActivationTinyTSAJumpToMars:
startExtraSequenceSync(kTinyTSA37AI6ToMars, kFilterNoInput);
showExtraView(kTinyTSA37JumpToMarsMenu);
break;
case kActivationTinyTSAJumpToWSC:
startExtraSequenceSync(kTinyTSA37AI5ToWSC, kFilterNoInput);
showExtraView(kTinyTSA37JumpToWSCMenu);
break;
default:
showMainJumpMenu();
break;
}
g_AIChip->clearClicked();
}
return movieName;
}
void TinyTSA::loadAmbientLoops() {
if (_vm->isDVD()) // Updated sound in the DVD version
loadLoopSound1("Sounds/TSA/T01NAE.NEW.32K.AIFF");
else
loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
}
int16 TinyTSA::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
return Neighborhood::getStaticCompassAngle(room, dir) - kCompassShift;
}
uint16 TinyTSA::getDateResID() const {
return kDate2318ID;
}
InputBits TinyTSA::getInputFilter() {
// Can't move forward...
return Neighborhood::getInputFilter() & ~(kFilterUpButton | kFilterUpAuto);
}
void TinyTSA::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
if (clickedSpot) {
switch (clickedSpot->getObjectID()) {
case kTinyTSA37NorthJumpMenuSpotID:
// This hotspot isn't accessible from Tiny TSA
warning("jump menu spot");
return;
case kTinyTSA37NorthJumpToNoradSpotID:
GameState.setTSAState(kPlayerOnWayToNorad);
requestExtraSequence(kTinyTSA37JumpToNorad, 0, kFilterNoInput);
if (!GameState.getBeenToNorad()) {
requestExtraSequence(kTinyTSA37NoradToAI7, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37PegasusAI7, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37AI7ToNorad, 0, kFilterNoInput);
GameState.setBeenToNorad(true);
}
requestExtraSequence(kTinyTSA37NoradToDepart, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
return;
case kTinyTSA37NorthJumpToMarsSpotID:
GameState.setTSAState(kPlayerOnWayToMars);
requestExtraSequence(kTinyTSA37JumpToMars, 0, kFilterNoInput);
if (!GameState.getBeenToMars()) {
requestExtraSequence(kTinyTSA37MarsToAI6, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37PegasusAI6, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37AI6ToMars, 0, kFilterNoInput);
GameState.setBeenToMars(true);
}
requestExtraSequence(kTinyTSA37MarsToDepart, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
return;
case kTinyTSA37NorthJumpToWSCSpotID:
GameState.setTSAState(kPlayerOnWayToWSC);
requestExtraSequence(kTinyTSA37JumpToWSC, 0, kFilterNoInput);
if (!GameState.getBeenToWSC()) {
requestExtraSequence(kTinyTSA37WSCToAI5, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37PegasusAI5, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37AI5ToWSC, 0, kFilterNoInput);
GameState.setBeenToWSC(true);
}
requestExtraSequence(kTinyTSA37WSCToDepart, 0, kFilterNoInput);
requestExtraSequence(kTinyTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
return;
default:
break;
}
}
Neighborhood::clickInHotspot(input, clickedSpot);
}
void TinyTSA::showMainJumpMenu() {
ExtraID jumpMenuView = kTinyTSA37JumpMenu000;
if (GameState.getNoradFinished())
jumpMenuView += 4;
if (GameState.getMarsFinished())
jumpMenuView += 2;
if (GameState.getWSCFinished())
jumpMenuView += 1;
showExtraView(jumpMenuView);
setCurrentActivation(kActivationTinyTSAMainJumpMenu);
}
void TinyTSA::checkContinuePoint(const RoomID, const DirectionConstant) {
makeContinuePoint();
}
void TinyTSA::arriveAt(const RoomID room, const DirectionConstant direction) {
Neighborhood::arriveAt(room, direction);
switch (GameState.getTSAState()) {
case kPlayerOnWayToNorad:
case kPlayerOnWayToMars:
case kPlayerOnWayToWSC:
startExtraSequence(kTinyTSA37TimeJumpToPegasus, kExtraCompletedFlag, kFilterNoInput);
break;
case kPlayerLockedInPegasus:
showMainJumpMenu();
break;
default:
break;
}
}
void TinyTSA::receiveNotification(Notification *notification, const NotificationFlags flags) {
ExtraID lastExtra = _lastExtra;
Neighborhood::receiveNotification(notification, flags);
if ((flags & kExtraCompletedFlag) != 0) {
// Only allow input if we're not in the middle of series of queue requests.
if (actionQueueEmpty())
_interruptionFilter = kFilterAllInput;
switch (lastExtra) {
case kTinyTSA37PegasusDepart:
_vm->setLastEnergyValue(kFullEnergy);
switch (GameState.getTSAState()) {
case kPlayerOnWayToNorad:
_vm->jumpToNewEnvironment(kNoradAlphaID, kNorad01, kSouth);
GameState.setNoradSeenTimeStream(false);
GameState.setNoradGassed(true);
GameState.setNoradFillingStationOn(false);
GameState.setNoradN22MessagePlayed(false);
GameState.setNoradPlayedGlobeGame(false);
GameState.setNoradBeatRobotWithClaw(false);
GameState.setNoradBeatRobotWithDoor(false);
GameState.setNoradRetScanGood(false);
GameState.setNoradWaitingForLaser(false);
GameState.setNoradSubRoomPressure(9);
GameState.setNoradSubPrepState(kSubNotPrepped);
break;
case kPlayerOnWayToMars:
_vm->jumpToNewEnvironment(kMarsID, kMars0A, kNorth);
GameState.setMarsSeenTimeStream(false);
GameState.setMarsHeardUpperPodMessage(false);
GameState.setMarsRobotThrownPlayer(false);
GameState.setMarsHeardCheckInMessage(false);
GameState.setMarsPodAtUpperPlatform(false);
GameState.setMarsSeenThermalScan(false);
GameState.setMarsArrivedBelow(false);
GameState.setMarsSeenRobotAtReactor(false);
GameState.setMarsAvoidedReactorRobot(false);
GameState.setMarsLockFrozen(false);
GameState.setMarsLockBroken(false);
GameState.setMarsSecurityDown(false);
GameState.setMarsAirlockOpen(false);
GameState.setMarsReadyForShuttleTransport(false);
GameState.setMarsFinishedCanyonChase(false);
GameState.setMarsThreadedMaze(false);
GameState.setMarsSawRobotLeave(false);
break;
case kPlayerOnWayToWSC:
_vm->jumpToNewEnvironment(kWSCID, kWSC01, kWest);
GameState.setWSCSeenTimeStream(false);
GameState.setWSCPoisoned(false);
GameState.setWSCAnsweredAboutDart(false);
GameState.setWSCDartInAnalyzer(false);
GameState.setWSCRemovedDart(false);
GameState.setWSCAnalyzerOn(false);
GameState.setWSCAnalyzedDart(false);
GameState.setWSCSawMorph(false);
GameState.setWSCDesignedAntidote(false);
GameState.setWSCOfficeMessagesOpen(false);
GameState.setWSCSeenNerd(false);
GameState.setWSCHeardPage1(false);
GameState.setWSCHeardPage2(false);
GameState.setWSCHeardCheckIn(false);
GameState.setWSCDidPlasmaDodge(false);
GameState.setWSCSeenSinclairLecture(false);
GameState.setWSCBeenAtWSC93(false);
GameState.setWSCCatwalkDark(false);
GameState.setWSCRobotDead(false);
GameState.setWSCRobotGone(false);
break;
default:
break;
};
break;
case kTinyTSA37TimeJumpToPegasus:
if (g_energyMonitor)
g_energyMonitor->stopEnergyDraining();
switch (GameState.getTSAState()) {
case kPlayerOnWayToNorad:
arriveFromNorad();
break;
case kPlayerOnWayToMars:
arriveFromMars();
break;
case kPlayerOnWayToWSC:
arriveFromWSC();
break;
default:
break;
}
break;
case kTinyTSA37DownloadToOpMemReview:
if (_vm->itemInBiochips(kOpticalBiochip)) {
switch (GameState.getTSAState()) {
case kPlayerOnWayToNorad:
g_opticalChip->playOpMemMovie(kPoseidonSpotID);
break;
case kPlayerOnWayToMars:
g_opticalChip->playOpMemMovie(kAriesSpotID);
break;
case kPlayerOnWayToWSC:
g_opticalChip->playOpMemMovie(kMercurySpotID);
break;
default:
break;
}
}
if (((GameState.getNoradFinished() && !(GameState.getMarsFinished() || GameState.getWSCFinished())) ||
(GameState.getMarsFinished() && !(GameState.getNoradFinished() || GameState.getWSCFinished())) ||
(GameState.getWSCFinished() && !(GameState.getNoradFinished() || GameState.getMarsFinished()))) &&
g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBB43", kArthurTSASawFirstOpMemMovie);
requestExtraSequence(kTinyTSA37OpMemReviewToMainMenu, kExtraCompletedFlag, kFilterNoInput);
break;
case kTinyTSA37DownloadToMainMenu:
case kTinyTSA37OpMemReviewToMainMenu:
GameState.setTSAState(kPlayerLockedInPegasus);
showMainJumpMenu();
makeContinuePoint();
if (g_arthurChip)
g_arthurChip->playArthurMovieForEvent("Images/AI/Globals/XGLOBA22", kArthurTSAInPegasusNoVideo);
break;
case kTinyTSA37JumpToNoradMenu:
setCurrentActivation(kActivationTinyTSAJumpToNorad);
break;
case kTinyTSA37JumpToMarsMenu:
setCurrentActivation(kActivationTinyTSAJumpToMars);
break;
case kTinyTSA37JumpToWSCMenu:
setCurrentActivation(kActivationTinyTSAJumpToWSC);
break;
case kTinyTSA37CancelNorad:
case kTinyTSA37CancelMars:
case kTinyTSA37CancelWSC:
showMainJumpMenu();
break;
default:
break;
}
}
g_AIArea->checkMiddleArea();
}
void TinyTSA::arriveFromNorad() {
requestExtraSequence(kTinyTSA37RecallToDownload, 0, kFilterNoInput);
if (GameState.getNoradFinished() && !GameState.getScoringFinishedNorad()) {
GameState.setScoringFinishedNorad();
requestExtraSequence(kTinyTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
} else {
requestExtraSequence(kTinyTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
}
}
void TinyTSA::arriveFromMars() {
requestExtraSequence(kTinyTSA37RecallToDownload, 0, kFilterNoInput);
if (GameState.getMarsFinished() && !GameState.getScoringFinishedMars()) {
GameState.setScoringFinishedMars();
requestExtraSequence(kTinyTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
} else {
requestExtraSequence(kTinyTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
}
}
void TinyTSA::arriveFromWSC() {
requestExtraSequence(kTinyTSA37RecallToDownload, 0, kFilterNoInput);
if (GameState.getWSCFinished() && !GameState.getScoringFinishedWSC()) {
GameState.setScoringFinishedWSC();
requestExtraSequence(kTinyTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
} else {
requestExtraSequence(kTinyTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
}
}
Common::Path TinyTSA::getNavMovieName() {
return "Images/TSA/Tiny TSA.movie";
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,70 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_TSA_TINYTSA_H
#define PEGASUS_NEIGHBORHOOD_TSA_TINYTSA_H
#include "pegasus/neighborhood/neighborhood.h"
namespace Pegasus {
// Room IDs.
static const RoomID kTinyTSA37 = 0;
class TinyTSA : public Neighborhood {
public:
TinyTSA(InputHandler *, PegasusEngine *);
~TinyTSA() override {}
uint16 getDateResID() const override;
void start() override;
void checkContinuePoint(const RoomID, const DirectionConstant) override;
protected:
Common::Path getBriefingMovie() override;
Common::Path getEnvScanMovie() override;
void loadAmbientLoops() override;
void clickInHotspot(const Input &, const Hotspot *) override;
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void arriveFromNorad();
void arriveFromMars();
void arriveFromWSC();
InputBits getInputFilter() override;
void arriveAt(const RoomID, const DirectionConstant) override;
void showMainJumpMenu();
void receiveNotification(Notification *, const NotificationFlags) override;
Common::Path getNavMovieName() override;
Common::Path getSoundSpotsName() override { return Common::Path(); }
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,62 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "pegasus/neighborhood/turn.h"
namespace Pegasus {
void TurnTable::loadFromStream(Common::SeekableReadStream *stream) {
uint32 count = stream->readUint32BE();
_entries.resize(count);
for (uint32 i = 0; i < count; i++) {
_entries[i].room = stream->readUint16BE();
_entries[i].direction = stream->readByte();
_entries[i].turnDirection = stream->readByte();
_entries[i].altCode = stream->readByte();
stream->readByte(); // alignment
_entries[i].endDirection = stream->readByte();
stream->readByte(); // alignment
debug(0, "Turn[%d]: %d %d %d %d %d", i, _entries[i].room, _entries[i].direction,
_entries[i].turnDirection, _entries[i].altCode, _entries[i].endDirection);
}
}
void TurnTable::clear() {
_entries.clear();
}
TurnTable::Entry TurnTable::findEntry(RoomID room, DirectionConstant direction, TurnDirection turnDirection, AlternateID altCode) {
for (uint32 i = 0; i < _entries.size(); i++)
if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].turnDirection == turnDirection && _entries[i].altCode == altCode)
return _entries[i];
return Entry();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,68 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_TURN_H
#define PEGASUS_NEIGHBORHOOD_TURN_H
#include "common/array.h"
#include "common/endian.h"
#include "pegasus/constants.h"
namespace Common {
class SeekableReadStream;
}
namespace Pegasus {
class TurnTable {
public:
TurnTable() {}
~TurnTable() {}
static uint32 getResTag() { return MKTAG('T', 'u', 'r', 'n'); }
void loadFromStream(Common::SeekableReadStream *stream);
void clear();
struct Entry {
Entry() { endDirection = kNoDirection; }
bool isEmpty() { return endDirection == kNoDirection; }
RoomID room;
DirectionConstant direction;
TurnDirection turnDirection;
AlternateID altCode;
DirectionConstant endDirection;
};
Entry findEntry(RoomID room, DirectionConstant direction, TurnDirection turnDirection, AlternateID altCode);
private:
Common::Array<Entry> _entries;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,59 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "pegasus/neighborhood/view.h"
namespace Pegasus {
void ViewTable::loadFromStream(Common::SeekableReadStream *stream) {
uint32 count = stream->readUint32BE();
_entries.resize(count);
for (uint32 i = 0; i < count; i++) {
_entries[i].room = stream->readUint16BE();
_entries[i].direction = stream->readByte();
_entries[i].altCode = stream->readByte();
_entries[i].time = stream->readUint32BE();
debug(0, "View[%d]: %d %d %d %d", i, _entries[i].room, _entries[i].direction,
_entries[i].altCode, _entries[i].time);
}
}
void ViewTable::clear() {
_entries.clear();
}
ViewTable::Entry ViewTable::findEntry(RoomID room, DirectionConstant direction, AlternateID altCode) {
for (uint32 i = 0; i < _entries.size(); i++)
if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].altCode == altCode)
return _entries[i];
return Entry();
}
} // End of namespace pegasus

View File

@@ -0,0 +1,67 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_VIEW_H
#define PEGASUS_NEIGHBORHOOD_VIEW_H
#include "common/array.h"
#include "common/endian.h"
#include "pegasus/constants.h"
namespace Common {
class SeekableReadStream;
}
namespace Pegasus {
class ViewTable {
public:
ViewTable() {}
~ViewTable() {}
static uint32 getResTag() { return MKTAG('V', 'i', 'e', 'w'); }
void loadFromStream(Common::SeekableReadStream *stream);
void clear();
struct Entry {
Entry() { time = 0xffffffff; }
bool isEmpty() { return time == 0xffffffff; }
RoomID room;
DirectionConstant direction;
AlternateID altCode;
TimeValue time;
};
Entry findEntry(RoomID room, DirectionConstant direction, AlternateID altCode);
private:
Common::Array<Entry> _entries;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,126 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "pegasus/graphics.h"
#include "pegasus/neighborhood/wsc/moleculebin.h"
#include "pegasus/neighborhood/wsc/wsc.h"
namespace Pegasus {
static const CoordType kMoleculeBinWidth = 138;
static const CoordType kMoleculeBinHeight = 128;
static const CoordType kMoleculeWidth = 66;
static const CoordType kMoleculeHeight = 40;
static const CoordType kMoleculeBinLeft = kNavAreaLeft + 286;
static const CoordType kMoleculeBinTop = kNavAreaLeft + 96;
// Layouts:
MoleculeBin::MoleculeBin() : DisplayElement(kNoDisplayElement) {
_highlightColor = g_system->getScreenFormat().RGBToColor(0xff, 0xff, 102);
_selectedMolecule = -1;
}
void MoleculeBin::initMoleculeBin() {
if (!isDisplaying()) {
for (int i = 0; i < 6; i++)
_binLayout[i] = i;
resetBin();
_binImages.getImageFromPICTFile("Images/World Science Center/Molecules");
setDisplayOrder(kWSCMoleculeBinOrder);
setBounds(kMoleculeBinLeft, kMoleculeBinTop, kMoleculeBinLeft + kMoleculeBinWidth,
kMoleculeBinTop + kMoleculeBinHeight);
startDisplaying();
show();
}
}
void MoleculeBin::cleanUpMoleculeBin() {
if (isDisplaying()) {
stopDisplaying();
_binImages.deallocateSurface();
}
}
void MoleculeBin::setBinLayout(const uint32 *layout) {
for (int i = 0; i < 6; i++)
_binLayout[i] = layout[i];
}
void MoleculeBin::highlightMolecule(const uint32 whichMolecule) {
if (!_moleculeFlags.getFlag(whichMolecule)) {
_moleculeFlags.setFlag(whichMolecule, true);
triggerRedraw();
}
}
bool MoleculeBin::isMoleculeHighlighted(uint32 whichMolecule) {
return _moleculeFlags.getFlag(whichMolecule);
}
void MoleculeBin::selectMolecule(const int whichMolecule) {
if (_selectedMolecule != whichMolecule) {
_selectedMolecule = whichMolecule;
triggerRedraw();
}
}
void MoleculeBin::resetBin() {
_moleculeFlags.clearAllFlags();
_selectedMolecule = -1;
triggerRedraw();
}
void MoleculeBin::draw(const Common::Rect &) {
Common::Rect r1(0, 0, kMoleculeWidth, kMoleculeHeight);
Common::Rect r2 = r1;
for (int i = 0; i < 6; i++) {
r1.moveTo(i * (kMoleculeWidth * 2), 0);
if (_moleculeFlags.getFlag(_binLayout[i]))
r1.translate(kMoleculeWidth, 0);
r2.moveTo((_binLayout[i] & 1) * (kMoleculeWidth + 2) + _bounds.left + 2,
(_binLayout[i] >> 1) * (kMoleculeHeight + 2) + _bounds.top + 2);
_binImages.copyToCurrentPort(r1, r2);
}
if (_selectedMolecule >= 0) {
r2.moveTo((_selectedMolecule & 1) * (kMoleculeWidth + 2) + _bounds.left + 2,
(_selectedMolecule >> 1) * (kMoleculeHeight + 2) + _bounds.top + 2);
Graphics::Surface *screen = g_vm->_gfx->getWorkArea();
screen->frameRect(r2, _highlightColor);
r2.grow(1);
screen->frameRect(r2, _highlightColor);
}
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,71 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_WSC_MOLECULEBIN_H
#define PEGASUS_NEIGHBORHOOD_WSC_MOLECULEBIN_H
#include "pegasus/elements.h"
#include "pegasus/surface.h"
#include "pegasus/util.h"
namespace Pegasus {
enum {
kMolecule1,
kMolecule2,
kMolecule3,
kMolecule4,
kMolecule5,
kMolecule6
};
class MoleculeBin : public DisplayElement {
public:
MoleculeBin();
~MoleculeBin() override {}
void initMoleculeBin();
void cleanUpMoleculeBin();
void setBinLayout(const uint32 *);
void highlightMolecule(const uint32 whichMolecule);
void selectMolecule(const int whichMolecule);
void resetBin();
bool isMoleculeHighlighted(uint32);
protected:
void draw(const Common::Rect &) override;
Surface _binImages;
FlagsArray<byte, kMolecule6 + 1> _moleculeFlags;
int _selectedMolecule;
uint32 _binLayout[6];
uint32 _highlightColor;
};
} // End of namespace Pegasus
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,172 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_WSC_WSC_H
#define PEGASUS_NEIGHBORHOOD_WSC_WSC_H
#include "pegasus/neighborhood/neighborhood.h"
#include "pegasus/neighborhood/wsc/moleculebin.h"
namespace Pegasus {
static const DisplayOrder kWSCMoleculeBinOrder = kMonitorLayer;
static const DisplayOrder kWSCMoleculesMovieOrder = kWSCMoleculeBinOrder + 1;
static const RoomID kWSC01 = 0;
static const RoomID kWSC02Morph = 2;
static const RoomID kWSC02Messages = 3;
static const RoomID kWSC62 = 62;
class WSC : public Neighborhood {
public:
WSC(InputHandler *, PegasusEngine *);
~WSC() override;
void flushGameState() override;
uint16 getDateResID() const override;
bool okayToJump() override;
void checkContinuePoint(const RoomID, const DirectionConstant) override;
bool inSynthesizerGame();
bool canSolve() override;
void doSolve() override;
void setSoundFXLevel(const uint16) override;
void prepareForAIHint(const Common::Path &) override;
void cleanUpAfterAIHint(const Common::Path &) override;
void init() override;
void start() override;
protected:
enum {
kWSCDraggingAntidoteFlag,
kWSCPrivateLabMessagesOpenFlag,
kWSCPrivateInterruptedMorphFlag,
kWSCPrivateInMoleculeGameFlag,
kWSCPrivateSinclairOfficeOpenFlag,
kWSCPrivateOfficeLogOpenFlag,
kWSCPrivate58SouthOpenFlag,
kWSCPrivateClickedCatwalkCableFlag,
kWSCPrivateRobotHeadOpenFlag,
kWSCPrivateSeenPeopleAt17WestFlag,
kWSCPrivateSeenPeopleAt19NorthFlag,
kWSCPrivateSeenPeopleAt21SouthFlag,
kWSCPrivateSeenPeopleAt24SouthFlag,
kWSCPrivateSeenPeopleAt34EastFlag,
kWSCPrivateSeenPeopleAt36WestFlag,
kWSCPrivateSeenPeopleAt38NorthFlag,
kWSCPrivateSeenPeopleAt46SouthFlag,
kWSCPrivateSeenPeopleAt49NorthFlag,
kWSCPrivateSeenPeopleAt73WestFlag,
kWSCPrivateNeedPeopleAt17WestFlag,
kWSCPrivateNeedPeopleAt21SouthFlag,
kWSCPrivateNeedPeopleAt24SouthFlag,
kWSCPrivateNeedPeopleAt34EastFlag,
kWSCPrivateNeedPeopleAt36WestFlag,
kWSCPrivateNeedPeopleAt38NorthFlag,
kWSCPrivateNeedPeopleAt46SouthFlag,
kWSCPrivateNeedPeopleAt49NorthFlag,
kWSCPrivateNeedPeopleAt73WestFlag,
kWSCPrivateGotRetScanChipFlag,
kWSCPrivateGotMapChipFlag,
kWSCPrivateGotOpticalChipFlag,
kNumWSCPrivateFlags
};
void arriveAt(const RoomID, const DirectionConstant) override;
void turnTo(const DirectionConstant) override;
void receiveNotification(Notification *, const NotificationFlags) override;
void dropItemIntoRoom(Item *, Hotspot *) override;
void clickInHotspot(const Input &, const Hotspot *) override;
TimeValue getViewTime(const RoomID, const DirectionConstant) override;
void getZoomEntry(const HotSpotID, ZoomTable::Entry &) override;
CanMoveForwardReason canMoveForward(ExitTable::Entry &entry) override;
void cantMoveThatWay(CanMoveForwardReason reason) override;
CanTurnReason canTurn(TurnDirection turn, DirectionConstant &nextDir) override;
void zoomTo(const Hotspot *hotspot) override;
void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *) override;
void setUpMoleculeGame();
void nextMoleculeGameLevel();
void startMoleculeGameLevel();
void moleculeGameClick(const HotSpotID);
void loadAmbientLoops() override;
CanOpenDoorReason canOpenDoor(DoorTable::Entry &) override;
void cantOpenDoor(CanOpenDoorReason) override;
void pickedUpItem(Item *) override;
void doorOpened() override;
void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits) override;
void startDoorOpenMovie(const TimeValue, const TimeValue) override;
void getExtraEntry(const uint32, ExtraTable::Entry &) override;
void takeItemFromRoom(Item *item) override;
void checkPeopleCrossing();
void turnLeft() override;
void turnRight() override;
void moveForward() override;
Hotspot *getItemScreenSpot(Item *, DisplayElement *) override;
int16 getStaticCompassAngle(const RoomID, const DirectionConstant) override;
void getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) override;
void getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) override;
void bumpIntoWall() override;
void spotCompleted() override;
void activateHotspots() override;
void setUpAIRules() override;
Common::Path getBriefingMovie() override;
Common::Path getEnvScanMovie() override;
uint getNumHints() override;
Common::Path getHintMovie(uint) override;
void closeDoorOffScreen(const RoomID, const DirectionConstant) override;
void setUpPoison();
void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &) override;
void timerExpired(const uint32) override;
Common::Path getSoundSpotsName() override;
Common::Path getNavMovieName() override;
FlagsArray<byte, kNumWSCPrivateFlags> _privateFlags;
const Hotspot *_cachedZoomSpot;
Hotspot _biotechImplantSpot;
Movie _extraMovie;
NotificationCallBack _extraMovieCallBack;
MoleculeBin _moleculeBin;
int32 _moleculeGameLevel, _numCorrect;
Movie _moleculesMovie;
uint32 _levelArray[6];
Sprite *_argonSprite;
Sound _welcomeSound;
};
} // End of namespace Pegasus
#endif

View File

@@ -0,0 +1,73 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "pegasus/neighborhood/zoom.h"
namespace Pegasus {
void ZoomTable::loadFromStream(Common::SeekableReadStream *stream) {
uint32 count = stream->readUint32BE();
_entries.resize(count);
for (uint32 i = 0; i < count; i++) {
_entries[i].hotspot = stream->readUint16BE();
_entries[i].movieStart = stream->readUint32BE();
_entries[i].movieEnd = stream->readUint32BE();
_entries[i].room = stream->readUint16BE();
_entries[i].direction = stream->readByte();
debug(0, "Zoom[%d]: %d %d %d %d %d", i, _entries[i].hotspot, _entries[i].movieStart,
_entries[i].movieEnd, _entries[i].room, _entries[i].direction);
stream->readByte(); // alignment
}
}
void ZoomTable::clear() {
_entries.clear();
}
ZoomTable::Entry::Entry() {
clear();
}
void ZoomTable::Entry::clear() {
hotspot = kNoHotSpotID;
movieStart = 0xffffffff;
movieEnd = 0xffffffff;
room = kNoRoomID;
direction = kNoDirection;
}
ZoomTable::Entry ZoomTable::findEntry(HotSpotID hotspot) {
for (uint32 i = 0; i < _entries.size(); i++)
if (_entries[i].hotspot == hotspot)
return _entries[i];
return Entry();
}
} // End of namespace Pegasus

View File

@@ -0,0 +1,69 @@
/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PEGASUS_NEIGHBORHOOD_ZOOM_H
#define PEGASUS_NEIGHBORHOOD_ZOOM_H
#include "common/array.h"
#include "common/endian.h"
#include "pegasus/constants.h"
namespace Common {
class SeekableReadStream;
}
namespace Pegasus {
class ZoomTable {
public:
ZoomTable() {}
~ZoomTable() {}
static uint32 getResTag() { return MKTAG('Z', 'o', 'o', 'm'); }
void loadFromStream(Common::SeekableReadStream *stream);
void clear();
struct Entry {
Entry();
void clear();
bool isEmpty() { return movieStart == 0xffffffff; }
HotSpotID hotspot;
TimeValue movieStart;
TimeValue movieEnd;
RoomID room;
DirectionConstant direction;
};
Entry findEntry(HotSpotID hotspot);
private:
Common::Array<Entry> _entries;
};
} // End of namespace Pegasus
#endif