diff options
Diffstat (limited to 'engines')
-rwxr-xr-x | engines/pegasus/neighborhood/exit.h | 4 | ||||
-rwxr-xr-x | engines/pegasus/neighborhood/hotspotinfo.h | 4 | ||||
-rw-r--r-- | engines/pegasus/neighborhood/neighborhood.cpp | 864 | ||||
-rw-r--r-- | engines/pegasus/neighborhood/neighborhood.h | 186 | ||||
-rw-r--r-- | engines/pegasus/pegasus.cpp | 13 | ||||
-rw-r--r-- | engines/pegasus/pegasus.h | 12 | ||||
-rwxr-xr-x | engines/pegasus/types.h | 7 |
7 files changed, 1053 insertions, 37 deletions
diff --git a/engines/pegasus/neighborhood/exit.h b/engines/pegasus/neighborhood/exit.h index cd7bec41d1..671f30738f 100755 --- a/engines/pegasus/neighborhood/exit.h +++ b/engines/pegasus/neighborhood/exit.h @@ -68,6 +68,10 @@ public: Entry findEntry(tRoomID room, tDirectionConstant direction, tAlternateID altCode); + typedef Common::Array<Entry>::iterator iterator; + iterator begin() { return _entries.begin(); } + iterator end() { return _entries.end(); } + private: Common::Array<Entry> _entries; }; diff --git a/engines/pegasus/neighborhood/hotspotinfo.h b/engines/pegasus/neighborhood/hotspotinfo.h index a9acfe7b21..3c958c9e35 100755 --- a/engines/pegasus/neighborhood/hotspotinfo.h +++ b/engines/pegasus/neighborhood/hotspotinfo.h @@ -64,6 +64,10 @@ public: Entry findEntry(tHotSpotID hotspot); + typedef Common::Array<Entry>::iterator iterator; + iterator begin() { return _entries.begin(); } + iterator end() { return _entries.end(); } + private: Common::Array<Entry> _entries; }; diff --git a/engines/pegasus/neighborhood/neighborhood.cpp b/engines/pegasus/neighborhood/neighborhood.cpp index cba6fd96ee..f92c2b76dd 100644 --- a/engines/pegasus/neighborhood/neighborhood.cpp +++ b/engines/pegasus/neighborhood/neighborhood.cpp @@ -27,9 +27,13 @@ #include "common/stream.h" #include "pegasus/compass.h" +#include "pegasus/cursor.h" +#include "pegasus/energymonitor.h" #include "pegasus/gamestate.h" #include "pegasus/input.h" +#include "pegasus/interface.h" #include "pegasus/pegasus.h" +#include "pegasus/ai/ai_area.h" #include "pegasus/neighborhood/neighborhood.h" namespace Pegasus { @@ -48,7 +52,8 @@ Neighborhood *g_neighborhood = 0; Neighborhood::Neighborhood(InputHandler *nextHandler, PegasusEngine *vm, const Common::String &resName, tNeighborhoodID id) : InputHandler(nextHandler), IDObject(id), _vm(vm), _resName(resName), _navMovie(kNavMovieID), _stridingCallBack(this), - _neighborhoodNotification(kNeighborhoodNotificationID, (NotificationManager *)vm) { + _neighborhoodNotification(kNeighborhoodNotificationID, (NotificationManager *)vm), _pushIn(kNoDisplayElement), + _turnPush(kTurnPushID), _croppedMovie(kCroppedMovieID) { GameState.setOpenDoorLocation(kNoRoomID, kNoDirection); _currentAlternate = 0; _interruptionFilter = kFilterAllInput; @@ -115,9 +120,39 @@ void Neighborhood::init() { delete stream; createNeighborhoodSpots(); + + // TODO: Load _navMovie + _navMovie.setVolume(_vm->getSoundFXLevel()); + loadSoundSpots(); + _spotSounds.setVolume(_vm->getSoundFXLevel()); + + _navMovie.setDisplayOrder(kNavMovieOrder); + _navMovie.startDisplaying(); - // TODO: AI, movies, notifications, buncha other stuff + Common::Rect bounds; + _navMovie.getBounds(bounds); + _pushIn.allocateSurface(bounds); + + _turnPush.setInAndOutElements(&_pushIn, &_navMovie); + _turnPush.setDisplayOrder(kTurnPushOrder); + _turnPush.startDisplaying(); + _navMovieCallBack.initCallBack(&_navMovie, kCallBackAtExtremes); + _stridingCallBack.initCallBack(&_navMovie, kCallBackAtTime); + _turnPushCallBack.initCallBack(&_turnPush, kCallBackAtExtremes); + _delayCallBack.initCallBack(&_delayTimer, kCallBackAtExtremes); + + // TODO + //_spotSoundCallBack.initCallBack(&_spotSounds, kCallBackAtExtremes); + + setUpAIRules(); + + if (g_compass) + g_compass->setFaderValue(getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection())); + + _soundLoop1.attachFader(&_loop1Fader); + _soundLoop2.attachFader(&_loop2Fader); + startIdling(); } void Neighborhood::start() { @@ -127,14 +162,54 @@ void Neighborhood::start() { } void Neighborhood::receiveNotification(Notification *, const tNotificationFlags flags) { + if ((flags & (kNeighborhoodMovieCompletedFlag | kTurnCompletedFlag)) != 0 && g_AIArea) + g_AIArea->unlockAI(); if (flags & kMoveForwardCompletedFlag) arriveAt(GameState.getNextRoom(), GameState.getNextDirection()); - - // TODO: Other types + if (flags & kTurnCompletedFlag) + turnTo(GameState.getNextDirection()); + if (flags & kSpotCompletedFlag) + spotCompleted(); + if (flags & kDoorOpenCompletedFlag) + doorOpened(); + if (flags & kActionRequestCompletedFlag) + popActionQueue(); + if (flags & kDeathExtraCompletedFlag) + die(_extraDeathReason); } void Neighborhood::arriveAt(tRoomID room, tDirectionConstant direction) { - // TODO + // TODO: Map + + GameState.setCurrentNeighborhood(getObjectID()); + + _currentActivation = kActivateHotSpotAlways; + _interruptionFilter = kFilterAllInput; + + if (room != GameState.getCurrentRoom() || direction != GameState.getCurrentDirection()) { + GameState.setCurrentRoom(room); + GameState.setCurrentDirection(direction); + loadAmbientLoops(); + activateCurrentView(room, direction, kSpotOnArrivalMask); + } else { + loadAmbientLoops(); + showViewFrame(getViewTime(GameState.getCurrentRoom(), GameState.getCurrentDirection())); + } + + if (GameState.getOpenDoorRoom() != kNoRoomID) { + // Arriving always closes a door. + loadAmbientLoops(); + closeDoorOffScreen(GameState.getOpenDoorRoom(), GameState.getOpenDoorDirection()); + GameState.setOpenDoorLocation(kNoRoomID, kNoDirection); + } + + if (g_compass) + g_compass->setFaderValue(getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection())); + + if (g_AIArea) + g_AIArea->checkMiddleArea(); + + checkContinuePoint(room, direction); } // These functions can be overridden to tweak the exact frames used. @@ -172,11 +247,11 @@ void Neighborhood::getDoorEntry(const tRoomID room, const tDirectionConstant dir doorEntry = _doorTable.findEntry(room, direction, kNoAlternateID); } -tDirectionConstant Neighborhood::getTurnEntry(const tRoomID room, const tDirectionConstant direction, const tTurnDirection turn) { - TurnTable::Entry turnEntry = _turnTable.findEntry(room, direction, turn, _currentAlternate); +tDirectionConstant Neighborhood::getTurnEntry(const tRoomID room, const tDirectionConstant direction, const tTurnDirection turnDirection) { + TurnTable::Entry turnEntry = _turnTable.findEntry(room, direction, turnDirection, _currentAlternate); if (turnEntry.isEmpty()) - turnEntry = _turnTable.findEntry(room, direction, turn, kNoAlternateID); + turnEntry = _turnTable.findEntry(room, direction, turnDirection, kNoAlternateID); return turnEntry.turnDirection; } @@ -230,8 +305,8 @@ tCanMoveForwardReason Neighborhood::canMoveForward(ExitTable::Entry &entry) { return kCanMoveForward; } -tCanTurnReason Neighborhood::canTurn(tTurnDirection turn, tDirectionConstant &nextDir) { - nextDir = getTurnEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), turn); +tCanTurnReason Neighborhood::canTurn(tTurnDirection turnDirection, tDirectionConstant &nextDir) { + nextDir = getTurnEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), turnDirection); if (nextDir == kNoDirection) return kCantTurnNoTurn; @@ -393,6 +468,23 @@ void Neighborhood::requestSpotSound(const TimeValue in, const TimeValue out, con requestAction(kSpotSoundRequest, 0xFFFFFFFF, in, out, interruptionFilter, flags); } +void Neighborhood::playSpotSoundSync(const TimeValue in, const TimeValue out) { + // Let the action queue play out first... + while (!actionQueueEmpty()) { + _vm->refreshDisplay(); + _vm->checkNotifications(); + _vm->_system->delayMillis(10); + } + + _spotSounds.stopSound(); + _spotSounds.playSoundSegment(in * 1000 / 600, out * 1000 / 600); + + while (_spotSounds.isPlaying()) { + _vm->refreshDisplay(); + _vm->_system->delayMillis(10); + } +} + void Neighborhood::requestDelay(const TimeValue delayDuration, const TimeScale delayScale, const tInputBits interruptionFilter, const tNotificationFlags flags) { requestAction(kDelayRequest, 0xFFFFFFFF, delayDuration, delayScale, interruptionFilter, flags); } @@ -530,4 +622,756 @@ void Neighborhood::scheduleStridingCallBack(const TimeValue strideStop, tNotific _stridingCallBack.scheduleCallBack(kTriggerTimeFwd, strideStop, _navMovie.getScale()); } +void Neighborhood::moveNavTo(const tCoordType h, const tCoordType v) { + tCoordType oldH, oldV; + _navMovie.getLocation(oldH, oldV); + + tCoordType offH = h - oldH; + tCoordType offV = v - oldV; + + _navMovie.moveElementTo(h, v); + _turnPush.moveElementTo(h, v); + + if (offH != 0 || offV != 0) + for (HotspotList::iterator it = _neighborhoodHotspots.begin(); it != _neighborhoodHotspots.end(); it++) + if ((*it)->getHotspotFlags() & kNeighborhoodSpotFlag) + (*it)->moveSpot(offH, offV); +} + +void Neighborhood::activateHotspots() { + InputHandler::activateHotspots(); + + for (HotspotInfoTable::iterator it = _hotspotInfoTable.begin(); it != _hotspotInfoTable.end(); it++) { + HotspotInfoTable::Entry entry = *it; + + if (entry.hotspotRoom == GameState.getCurrentRoom() && entry.hotspotDirection == GameState.getCurrentDirection() + && (entry.hotspotActivation == _currentActivation || entry.hotspotActivation == kActivateHotSpotAlways)) { + Hotspot *hotspot = g_allHotspots.findHotspotByID(entry.hotspot); + if (hotspot) + activateOneHotspot(entry, hotspot); + } + } +} + +void Neighborhood::clickInHotspot(const Input &input, const Hotspot *clickedSpot) { + tHotSpotFlags flags = clickedSpot->getHotspotFlags(); + + if ((flags & (kPickUpItemSpotFlag | kPickUpBiochipSpotFlag)) != 0) { + tItemID itemID = kNoItemID; + + for (HotspotInfoTable::iterator it = _hotspotInfoTable.begin(); it != _hotspotInfoTable.end(); it++) { + if (it->hotspot == clickedSpot->getObjectID()) { + itemID = it->hotspotItem; + break; + } + } + + if (itemID != kNoItemID) { + Item *draggingItem = g_allItems.findItemByID(itemID); + + if (draggingItem) { + takeItemFromRoom(draggingItem); + + if ((flags & kPickUpItemSpotFlag) != 0) + _vm->dragItem(input, draggingItem, kDragInventoryPickup); + else + _vm->dragItem(input, draggingItem, kDragBiochipPickup); + } + } + } else { + // Check other flags here? + if ((flags & kZoomSpotFlags) != 0) { + zoomTo(clickedSpot); + } else if ((flags & kPlayExtraSpotFlag) != 0) { + HotspotInfoTable::Entry hotspotEntry; + getHotspotEntry(clickedSpot->getObjectID(), hotspotEntry); + startExtraSequence(hotspotEntry.hotspotExtra, kExtraCompletedFlag, kFilterNoInput); + } else if ((flags & kOpenDoorSpotFlag) != 0) { + openDoor(); + } else { + InputHandler::clickInHotspot(input, clickedSpot); + } + } +} + +void Neighborhood::cantMoveThatWay(tCanMoveForwardReason reason) { + switch (reason) { + case kCantMoveDoorClosed: + case kCantMoveDoorLocked: + openDoor(); + break; + case kCantMoveBlocked: + zoomUpOrBump(); + break; + default: + bumpIntoWall(); + break; + } +} + +void Neighborhood::cantOpenDoor(tCanOpenDoorReason) { + bumpIntoWall(); +} + +void Neighborhood::turnTo(const tDirectionConstant direction) { + // TODO: Map + + _pushIn.copyToCurrentPort(); + + // Added 2/10/97. Shouldn't this be here? Shouldn't we set the current activation to + // always when turning to a new view? + _currentActivation = kActivateHotSpotAlways; + + _interruptionFilter = kFilterAllInput; + + if (direction != GameState.getCurrentDirection()) { + GameState.setCurrentDirection(direction); + activateCurrentView(GameState.getCurrentRoom(), direction, kSpotOnTurnMask); + } else { + showViewFrame(getViewTime(GameState.getCurrentRoom(), GameState.getCurrentDirection())); + } + + if (GameState.getOpenDoorRoom() != kNoRoomID) { + // Turning always closes a door. + loadAmbientLoops(); + closeDoorOffScreen(GameState.getOpenDoorRoom(), GameState.getOpenDoorDirection()); + GameState.setOpenDoorLocation(kNoRoomID, kNoDirection); + } + + if (g_AIArea) + g_AIArea->checkMiddleArea(); + + checkContinuePoint(GameState.getCurrentRoom(), direction); + + _vm->_cursor->hideUntilMoved(); +} + +void Neighborhood::spotCompleted() { + _interruptionFilter = kFilterAllInput; + showViewFrame(getViewTime(GameState.getCurrentRoom(), GameState.getCurrentDirection())); +} + +void Neighborhood::doorOpened() { + _interruptionFilter = kFilterAllInput; + + // 2/23/97 + // Fixes funny bug with doors that are opened by dropping things on them... + setCurrentActivation(kActivateHotSpotAlways); + + GameState.setOpenDoorLocation(GameState.getCurrentRoom(), GameState.getCurrentDirection()); + + SpotTable::Entry entry; + findSpotEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), kSpotOnDoorOpenMask, entry); + + if (entry.dstFlags & kSpotOnDoorOpenMask) { + startSpotOnceOnly(entry.movieStart, entry.movieEnd); + } else { + findSpotEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), kSpotOnDoorOpenMask | kSpotLoopsMask, entry); + + if (entry.dstFlags & kSpotOnDoorOpenMask) + startSpotLoop(entry.movieStart, entry.movieEnd); + } + + loadAmbientLoops(); + + // TODO: Map + + if (g_AIArea) + g_AIArea->checkMiddleArea(); +} + +void Neighborhood::moveForward() { + ExitTable::Entry exitEntry; + tCanMoveForwardReason moveReason = canMoveForward(exitEntry); + + if (moveReason == kCanMoveForward) + startExitMovie(exitEntry); + else + cantMoveThatWay(moveReason); +} + +void Neighborhood::turn(const tTurnDirection turnDirection) { + tDirectionConstant nextDir; + tCanTurnReason turnReason = canTurn(turnDirection, nextDir); + + if (turnReason == kCanTurn) + startTurnPush(turnDirection, getViewTime(GameState.getCurrentRoom(), nextDir), nextDir); + else + cantTurnThatWay(turnReason); +} + +void Neighborhood::turnLeft() { + turn(kTurnLeft); +} + +void Neighborhood::turnRight() { + turn(kTurnRight); +} + +void Neighborhood::turnUp() { + turn(kTurnUp); +} + +void Neighborhood::turnDown() { + turn(kTurnDown); +} + +void Neighborhood::openDoor() { + DoorTable::Entry door; + tCanOpenDoorReason doorReason = canOpenDoor(door); + + if (doorReason == kCanOpenDoor) + startDoorOpenMovie(door.movieStart, door.movieEnd); + else + cantOpenDoor(doorReason); +} + +void Neighborhood::zoomTo(const Hotspot *hotspot) { + ZoomTable::Entry zoomEntry; + getZoomEntry(hotspot->getObjectID(), zoomEntry); + if (!zoomEntry.isEmpty()) + startZoomMovie(zoomEntry); +} + +void Neighborhood::updateViewFrame() { + showViewFrame(getViewTime(GameState.getCurrentRoom(), GameState.getCurrentDirection())); +} + +void Neighborhood::startSpotLoop(TimeValue startTime, TimeValue stopTime, tNotificationFlags flags) { + _turnPush.hide(); + startMovieSequence(startTime, stopTime, flags, true, kFilterAllInput); +} + +void Neighborhood::showViewFrame(TimeValue viewTime) { + if ((int32)viewTime >= 0) { + _turnPush.hide(); + _navMovie.stop(); + _navMovie.setFlags(0); + _navMovie.setSegment(0, _navMovie.getDuration()); + _navMovie.setTime(viewTime); + + Common::Rect pushBounds; + _turnPush.getBounds(pushBounds); + + _navMovie.moveElementTo(pushBounds.left, pushBounds.top); + _navMovie.show(); + _navMovie.redrawMovieWorld(); + } +} + +void Neighborhood::startExtraSequence(const tExtraID extraID, const tNotificationFlags flags, const tInputBits interruptionFilter) { + ExtraTable::Entry entry; + getExtraEntry(extraID, entry); + + if (entry.movieStart != 0xffffffff) + playExtraMovie(entry, flags, interruptionFilter); +} + +bool Neighborhood::startExtraSequenceSync(const tExtraID extraID, const tInputBits interruptionFilter) { + InputHandler::getCurrentInputDevice()->waitInput(interruptionFilter); + return prepareExtraSync(extraID) && waitMovieFinish(&_navMovie, interruptionFilter); +} + +void Neighborhood::loopExtraSequence(const uint32 extraID, tNotificationFlags flags) { + ExtraTable::Entry entry; + getExtraEntry(extraID, entry); + + if (entry.movieStart != 0xffffffff) { + _lastExtra = extraID; + startSpotLoop(entry.movieStart, entry.movieEnd, flags); + } +} + +bool Neighborhood::navMoviePlaying() { + return _navMovie.isRunning(); +} + +void Neighborhood::playDeathExtra(tExtraID extra, tDeathReason deathReason) { + _extraDeathReason = deathReason; + startExtraSequence(extra, kDeathExtraCompletedFlag, kFilterNoInput); +} + +void Neighborhood::die(const tDeathReason deathReason) { + loadLoopSound1(""); + loadLoopSound2(""); + _vm->die(deathReason); +} + +void Neighborhood::setSoundFXLevel(const uint16 fxLevel) { + if (_navMovie.isSurfaceValid()) + _navMovie.setVolume(fxLevel); + if (_spotSounds.isSoundLoaded()) + _spotSounds.setVolume(fxLevel); + // TODO + //if (_currentInteraction) + // _currentInteraction->setSoundFXLevel(fxLevel); +} + +void Neighborhood::setAmbienceLevel(const uint16 ambientLevel) { + if (_soundLoop1.isSoundLoaded()) + _loop1Fader.setMasterVolume(_vm->getAmbienceLevel()); + if (_soundLoop2.isSoundLoaded()) + _loop2Fader.setMasterVolume(_vm->getAmbienceLevel()); + // TODO + //if (_currentInteraction) + // _currentInteraction->setAmbienceLevel(ambientLevel); +} + +// Force the exit taken from (room, direction, alternate) to come to a stop. +void Neighborhood::forceStridingStop(const tRoomID room, const tDirectionConstant direction, const tAlternateID alternate) { + ExitTable::Entry entry = _exitTable.findEntry(room, direction, alternate); + + if (entry.movieStart != 0xffffffff) { + TimeValue strideStop = entry.exitEnd; + TimeValue exitStop = entry.movieEnd; + + if (strideStop != exitStop) { + for (ExitTable::iterator it = _exitTable.begin(); it != _exitTable.end(); it++) { + entry = *it; + + if (entry.exitEnd == strideStop && entry.movieEnd <= exitStop) { + entry.exitEnd = exitStop; + *it = entry; + } + } + } + } +} + +// Restore the exit taken from (room, direction, alternate) to stride. +void Neighborhood::restoreStriding(const tRoomID room, const tDirectionConstant direction, const tAlternateID alternate) { + ExitTable::Entry entry = _exitTable.findEntry(room, direction, alternate); + + if (entry.movieStart != 0xffffffff) { + TimeValue strideStop = entry.exitEnd; + TimeValue exitStop = entry.movieEnd; + + if (strideStop != entry.originalEnd) { + for (ExitTable::iterator it = _exitTable.begin(); it != _exitTable.end(); it++) { + entry = *it; + + if (entry.exitEnd == strideStop && entry.movieEnd <= exitStop) { + entry.exitEnd = entry.originalEnd; + *it = entry; + } + } + } + } +} + +HotspotInfoTable::Entry *Neighborhood::findHotspotEntry(const tHotSpotID id) { + for (HotspotInfoTable::iterator it = _hotspotInfoTable.begin(); it != _hotspotInfoTable.end(); it++) + if (it->hotspot == id) + return &(*it); + + return 0; +} + +void Neighborhood::hideNav() { + _isRunning = _navMovie.isRunning(); + _navMovie.stop(); + _navMovie.hide(); + _turnPush.stopFader(); + _turnPush.hide(); +} + +void Neighborhood::showNav() { + _navMovie.show(); + _turnPush.hide(); + if (_isRunning) + _navMovie.start(); +} + +void Neighborhood::startExitMovie(const ExitTable::Entry &exitEntry) { + FaderMoveSpec compassMove; + + if (g_compass) + getExitCompassMove(exitEntry, compassMove); + + GameState.setNextRoom(exitEntry.exitRoom); + GameState.setNextDirection(exitEntry.exitDirection); + + if (exitEntry.movieEnd == exitEntry.exitEnd) // Just a walk. + startMovieSequence(exitEntry.movieStart, exitEntry.movieEnd, kMoveForwardCompletedFlag, kFilterNoInput, false); + else // We're stridin'! + startMovieSequence(exitEntry.movieStart, exitEntry.exitEnd, kStrideCompletedFlag, kFilterNoInput, false, exitEntry.movieEnd); + + if (g_compass) + g_compass->startFader(compassMove); +} + +void Neighborhood::startZoomMovie(const ZoomTable::Entry &zoomEntry) { + FaderMoveSpec compassMove; + + if (g_compass) + getZoomCompassMove(zoomEntry, compassMove); + + GameState.setNextRoom(zoomEntry.room); + GameState.setNextDirection(zoomEntry.direction); + + startMovieSequence(zoomEntry.movieStart, zoomEntry.movieEnd, kMoveForwardCompletedFlag, kFilterNoInput, false); + + if (g_compass) + g_compass->startFader(compassMove); +} + +void Neighborhood::startDoorOpenMovie(const TimeValue startTime, const TimeValue stopTime) { + startMovieSequence(startTime, stopTime, kDoorOpenCompletedFlag, kFilterNoInput, false); +} + +void Neighborhood::startTurnPush(const tTurnDirection turnDirection, const TimeValue newView, const tDirectionConstant nextDir) { + if (g_AIArea) + g_AIArea->lockAIOut(); + + _vm->_cursor->hide(); + + GameState.setNextDirection(nextDir); + + _interruptionFilter = kFilterNoInput; + _turnPush.stopFader(); + + // Set up callback. + _turnPushCallBack.setCallBackFlag(kTurnCompletedFlag); + _turnPushCallBack.scheduleCallBack(kTriggerAtStop, 0, 0); + + // Stop nav movie. + _navMovie.stop(); + _navMovie.setFlags(0); + + // Set segment of nav movie to whole movie, so that subsequent initFromMovieFrame + // will work. + _navMovie.setSegment(0, _navMovie.getDuration()); + + // TODO + //_pushIn.initFromMovieFrame(_navMovie.getMovie(), newView, kNoMask); + + _navMovie.hide(); + + switch (turnDirection) { + case kTurnLeft: + _turnPush.setSlideDirection(kSlideRightMask); + break; + case kTurnRight: + _turnPush.setSlideDirection(kSlideLeftMask); + break; + case kTurnUp: + _turnPush.setSlideDirection(kSlideDownMask); + break; + case kTurnDown: + _turnPush.setSlideDirection(kSlideUpMask); + break; + } + + _turnPush.show(); + + FaderMoveSpec moveSpec; + moveSpec.makeTwoKnotFaderSpec(60, 0, 0, 15, 1000); + _turnPush.startFader(moveSpec); + + if (g_compass) { + _turnPush.pauseFader(); + + int32 startAngle = getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection()); + int32 stopAngle = getStaticCompassAngle(GameState.getCurrentRoom(), nextDir); + + if (turnDirection == kTurnLeft) { + if (startAngle < stopAngle) + startAngle += 360; + } else { + if (stopAngle < startAngle) + stopAngle += 360; + } + + FaderMoveSpec turnSpec; + _turnPush.getCurrentFaderMove(turnSpec); + + FaderMoveSpec compassMove; + compassMove.makeTwoKnotFaderSpec(turnSpec.getFaderScale(), turnSpec.getNthKnotTime(0), startAngle, turnSpec.getNthKnotTime(1), stopAngle); + g_compass->startFader(compassMove); + } + + _turnPushCallBack.cancelCallBack(); + _turnPush.continueFader(); + + do { + _vm->refreshDisplay(); + _vm->_system->delayMillis(10); + } while (_turnPush.isFading()); + + _turnPush.stopFader(); + _neighborhoodNotification.setNotificationFlags(kTurnCompletedFlag, kTurnCompletedFlag); +} + +void Neighborhood::playExtraMovie(const ExtraTable::Entry &extraEntry, const tNotificationFlags flags, const tInputBits interruptionInput) { + FaderMoveSpec compassMove; + + if (g_compass) + getExtraCompassMove(extraEntry, compassMove); + + _lastExtra = extraEntry.extra; + _turnPush.hide(); + startMovieSequence(extraEntry.movieStart, extraEntry.movieEnd, flags, false, interruptionInput); + + if (g_compass) + g_compass->startFader(compassMove); +} + +void Neighborhood::activateCurrentView(const tRoomID room, const tDirectionConstant direction, tSpotFlags flag) { + SpotTable::Entry entry; + findSpotEntry(room, direction, flag, entry); + + if (entry.dstFlags & flag) { + startSpotOnceOnly(entry.movieStart, entry.movieEnd); + } else { + findSpotEntry(room, direction, flag | kSpotLoopsMask, entry); + + if (entry.dstFlags & flag) + startSpotLoop(entry.movieStart, entry.movieEnd); + else + showViewFrame(getViewTime(room, direction)); + } +} + +void Neighborhood::activateOneHotspot(HotspotInfoTable::Entry &entry, Hotspot *hotspot) { + switch (_vm->getDragType()) { + case kDragInventoryUse: + if ((hotspot->getHotspotFlags() & kDropItemSpotFlag) != 0 && + _vm->getDraggingItem()->getObjectID() == entry.hotspotItem) + hotspot->setActive(); + break; + case kDragInventoryPickup: + case kDragBiochipPickup: + // Do nothing -- neighborhoods activate no hot spots in this case... + break; + default: + if ((hotspot->getHotspotFlags() & kPickUpBiochipSpotFlag) != 0) { + Item *item = g_allItems.findItemByID(entry.hotspotItem); + if (item && item->getItemNeighborhood() == getObjectID()) + hotspot->setActive(); + } else { + tHotSpotFlags flags = hotspot->getHotspotFlags(); + + if ((flags & kNeighborhoodSpotFlag) != 0) { + if (flags & kOpenDoorSpotFlag) { + if (!GameState.isCurrentDoorOpen()) + hotspot->setActive(); + } else if ((flags & (kZoomSpotFlags | kClickSpotFlag | kPlayExtraSpotFlag)) != 0) { + hotspot->setActive(); + } else if ((flags & kPickUpItemSpotFlag) != 0) { + // Changed this 2/19/96 + // Should only light up this hot spot if the item's taken flag is not + // set. It's not based on neighborhood ID since that can be reset by the + // destroying process. + + if (!GameState.isTakenItemID(entry.hotspotItem)) + hotspot->setActive(); + } + } + } + break; + } +} + +void Neighborhood::startSpotOnceOnly(TimeValue startTime, TimeValue stopTime) { + _turnPush.hide(); + startMovieSequence(startTime, stopTime, kSpotCompletedFlag, kFilterNoInput, false); +} + +void Neighborhood::startMovieSequence(const TimeValue startTime, const TimeValue stopTime, tNotificationFlags flags, bool loopSequence, + const tInputBits interruptionInput, const TimeValue strideStop) { + if (!loopSequence && g_AIArea) + g_AIArea->lockAIOut(); + + _interruptionFilter = interruptionInput; + + // Stop the movie before doing anything else + _navMovie.stop(); + + Common::Rect pushBounds; + _turnPush.getBounds(pushBounds); + + _navMovie.moveElementTo(pushBounds.left, pushBounds.top); + _navMovie.show(); + _navMovie.setFlags(0); + _navMovie.setSegment(startTime, stopTime); + _navMovie.setTime(startTime); + + if (loopSequence) + _navMovie.setFlags(kLoopTimeBase); + else + flags |= kNeighborhoodMovieCompletedFlag; + + if (strideStop != 0xffffffff) + // Subtract a little slop from the striding stop time to keep from "pumping" at the + // end of a walk. + // 40 is one frame (scale == 600, 15 fps). + scheduleStridingCallBack(strideStop - kStridingSlop, flags); + else + scheduleNavCallBack(flags); + + _navMovie.start(); +} + +void Neighborhood::throwAwayInterface() { + _doorTable.clear(); + _exitTable.clear(); + _extraTable.clear(); + _hotspotInfoTable.clear(); + _spotTable.clear(); + _turnTable.clear(); + _viewTable.clear(); + _zoomTable.clear(); + + _navMovie.stopDisplaying(); + _navMovie.releaseMovie(); + _pushIn.deallocateSurface(); + _turnPush.stopDisplaying(); + _turnPush.setInAndOutElements(0, 0); + _turnPush.disposeAllCallBacks(); + + for (HotspotList::iterator it = _neighborhoodHotspots.begin(); it != _neighborhoodHotspots.end(); it++) + g_allHotspots.remove(*it); + + _neighborhoodHotspots.deleteHotspots(); + _spotSounds.disposeSound(); + _delayTimer.disposeAllCallBacks(); + + if (g_AIArea) { + g_AIArea->saveAIState(); + g_AIArea->removeAllRules(); + } + + // TODO: Interaction + + _croppedMovie.releaseMovie(); + + loadLoopSound1(""); + loadLoopSound2(""); + + if (g_energyMonitor) { + g_energyMonitor->stopEnergyDraining(); + g_energyMonitor->saveCurrentEnergyValue(); + } + + delete g_interface; +} + +bool Neighborhood::prepareExtraSync(const tExtraID extraID) { + ExtraTable::Entry extraEntry; + FaderMoveSpec compassMove; + + if (g_compass) { + getExtraEntry(extraID, extraEntry); + getExtraCompassMove(extraEntry, compassMove); + } + + ExtraTable::Entry entry; + getExtraEntry(extraID, entry); + bool result; + + if (entry.movieStart != 0xffffffff) { + _turnPush.hide(); + + // Stop the movie before doing anything else + _navMovie.stop(); + + Common::Rect pushBounds; + _turnPush.getBounds(pushBounds); + _navMovie.moveElementTo(pushBounds.left, pushBounds.top); + + _navMovie.show(); + _navMovie.setFlags(0); + _navMovie.setSegment(entry.movieStart, entry.movieEnd); + _navMovie.setTime(entry.movieStart); + _navMovie.start(); + result = true; + } else { + result = false; + } + + if (result && g_compass) + g_compass->startFader(compassMove); + + return result; +} + +bool Neighborhood::waitMovieFinish(Movie *movie, const tInputBits interruptionFilter) { + Input input; + bool result = true; + bool saveAllowed = _vm->swapSaveAllowed(false); + bool openAllowed = _vm->swapLoadAllowed(false); + + while (movie->isRunning()) { + InputHandler::getCurrentInputDevice()->getInput(input, interruptionFilter); + + if (input.anyInput() || _vm->shouldQuit()) { + result = false; + break; + } + + _vm->refreshDisplay(); + _vm->_system->delayMillis(10); + } + + movie->stop(); + _vm->swapSaveAllowed(saveAllowed); + _vm->swapLoadAllowed(openAllowed); + + return result; +} + +tInputBits Neighborhood::getInputFilter() { + return _interruptionFilter & InputHandler::getInputFilter(); +} + +void Neighborhood::getZoomCompassMove(const ZoomTable::Entry &zoomEntry, FaderMoveSpec &compassMove) { + int32 startAngle = getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection()); + int32 stopAngle = getStaticCompassAngle(zoomEntry.room, zoomEntry.direction); + + if (startAngle > stopAngle) { + if (stopAngle + 180 < startAngle) + stopAngle += 360; + } else { + if (startAngle + 180 < stopAngle) + startAngle += 360; + } + + compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), zoomEntry.movieStart, startAngle, zoomEntry.movieEnd, stopAngle); +} + +void Neighborhood::getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &compassMove) { + compassMove.makeOneKnotFaderSpec(g_compass->getFaderValue()); +} + +void Neighborhood::setUpAIRules() { + // TODO +} + +void Neighborhood::newInteraction(const tInteractionID interactionID) { + // TODO +} + +void Neighborhood::bumpIntoWall() { + // TODO +} + +void Neighborhood::zoomUpOrBump() { + // TODO +} + +void Neighborhood::loadLoopSound1(const Common::String &soundName, uint16 volume, TimeValue fadeOut, TimeValue fadeIn, TimeScale fadeScale) { + // TODO +} + +void Neighborhood::loadLoopSound2(const Common::String &soundName, uint16 volume, TimeValue fadeOut, TimeValue fadeIn, TimeScale fadeScale) { + // TODO +} + +void Neighborhood::takeItemFromRoom(Item *item) { + item->setItemRoom(kNoNeighborhoodID, kNoRoomID, kNoDirection); + // Also set the taken item flag. Do this before updating the view frame. + GameState.setTakenItem(item, true); + updateViewFrame(); +} + } // End of namespace Pegasus diff --git a/engines/pegasus/neighborhood/neighborhood.h b/engines/pegasus/neighborhood/neighborhood.h index 5d3e75bf3a..b06fb7532a 100644 --- a/engines/pegasus/neighborhood/neighborhood.h +++ b/engines/pegasus/neighborhood/neighborhood.h @@ -36,6 +36,7 @@ #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" @@ -64,6 +65,10 @@ const tNeighborhoodID kNoradDeltaID = 8; // to allow an easy transition out of Norad Alpha. const tNeighborhoodID kNoradSubChaseID = 1000; +const TimeScale kDefaultLoopFadeScale = kThirtyTicksPerSecond; +const TimeValue kDefaultLoopFadeOut = kHalfSecondPerThirtyTicks; +const TimeValue kDefaultLoopFadeIn = kHalfSecondPerThirtyTicks; + enum tQueueRequestType { kNavExtraRequest, kSpotSoundRequest, @@ -101,7 +106,7 @@ protected: typedef Common::Queue<tQueueRequest> NeighborhoodActionQueue; -class Neighborhood : public IDObject, public NotificationReceiver, public InputHandler { +class Neighborhood : public IDObject, public NotificationReceiver, public InputHandler, public Idler { friend class StriderCallBack; public: @@ -110,27 +115,83 @@ public: virtual void init(); void start(); + virtual void moveNavTo(const tCoordType, const tCoordType); + virtual void checkContinuePoint(const tRoomID, const tDirectionConstant) = 0; - void arriveAt(tRoomID room, tDirectionConstant direction); - - virtual void getExitEntry(const tRoomID room, const tDirectionConstant direction, ExitTable::Entry &entry); - virtual TimeValue getViewTime(const tRoomID room, const tDirectionConstant direction); - virtual void getDoorEntry(const tRoomID room, const tDirectionConstant direction, DoorTable::Entry &doorEntry); - virtual tDirectionConstant getTurnEntry(const tRoomID room, const tDirectionConstant direction, const tTurnDirection turn); - virtual void findSpotEntry(const tRoomID room, const tDirectionConstant direction, tSpotFlags flags, SpotTable::Entry &spotEntry); - virtual void getZoomEntry(const tHotSpotID id, ZoomTable::Entry &zoomEntry); - virtual void getHotspotEntry(const tHotSpotID id, HotspotInfoTable::Entry &hotspotEntry); - virtual void getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry); + virtual void activateHotspots(); + virtual void clickInHotspot(const Input &, const Hotspot *); tCanMoveForwardReason canMoveForward(ExitTable::Entry &entry); tCanTurnReason canTurn(tTurnDirection turn, tDirectionConstant &nextDir); tCanOpenDoorReason canOpenDoor(DoorTable::Entry &entry); + virtual void cantMoveThatWay(tCanMoveForwardReason); + virtual void cantTurnThatWay(tCanTurnReason) {} + virtual void cantOpenDoor(tCanOpenDoorReason); + virtual void arriveAt(tRoomID room, tDirectionConstant direction); + virtual void turnTo(const tDirectionConstant); + virtual void spotCompleted(); + virtual void doorOpened(); + virtual void closeDoorOffScreen(const tRoomID, const tDirectionConstant) {} + + virtual void moveForward(); + virtual void turn(const tTurnDirection); + 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 tExtraID, const tNotificationFlags, const tInputBits interruptionFilter); void requestSpotSound(const TimeValue, const TimeValue, const tInputBits interruptionFilter, const tNotificationFlags); + void playSpotSoundSync(const TimeValue in, const TimeValue out); void requestDelay(const TimeValue, const TimeScale, const tInputBits interruptionFilter, const tNotificationFlags); + Notification *getNeighborhoodNotification() { return &_neighborhoodNotification; } + + virtual void getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry); + virtual void startSpotLoop(TimeValue, TimeValue, tNotificationFlags = 0); virtual bool actionQueueEmpty() { return _actionQueue.empty(); } + virtual void showViewFrame(TimeValue); + virtual void findSpotEntry(const tRoomID room, const tDirectionConstant direction, tSpotFlags flags, SpotTable::Entry &spotEntry); + virtual void startExtraSequence(const tExtraID, const tNotificationFlags, const tInputBits interruptionFilter); + bool startExtraSequenceSync(const tExtraID, const tInputBits); + virtual void loopExtraSequence(const uint32, tNotificationFlags = 0); + int32 getLastExtra() const { return _lastExtra; } + virtual void scheduleNavCallBack(tNotificationFlags); + + Movie *getNavMovie() { return &_navMovie; } + bool navMoviePlaying(); + + void setCurrentAlternate(const tAlternateID alt) { _currentAlternate = alt; } + tAlternateID getCurrentAlternate() const { return _currentAlternate; } + + void setCurrentActivation(const tHotSpotActivationID a) { _currentActivation = a; } + tHotSpotActivationID getCurrentActivation() { return _currentActivation; } + + virtual void playDeathExtra(tExtraID, tDeathReason); + virtual void die(const tDeathReason); + + virtual void setSoundFXLevel(const uint16); + virtual void setAmbienceLevel(const uint16); + + void forceStridingStop(const tRoomID, const tDirectionConstant, const tAlternateID); + void restoreStriding(const tRoomID, const tDirectionConstant, const tAlternateID); + + HotspotInfoTable::Entry *findHotspotEntry(const tHotSpotID); + + Push *getTurnPush() { return &_turnPush; } + Picture *getTurnPushPicture() { return &_pushIn; } + + void hideNav(); + void showNav(); + + virtual void loadAmbientLoops() {} + + virtual void flushGameState() {} virtual Common::String getBriefingMovie(); virtual Common::String getEnvScanMovie(); @@ -149,29 +210,81 @@ public: virtual void shieldOn() {} virtual void shieldOff() {} - virtual void scheduleNavCallBack(tNotificationFlags); + virtual void loadLoopSound1(const Common::String &, const uint16 volume = 0x100, + const TimeValue fadeOut = kDefaultLoopFadeOut, const TimeValue fadeIn = kDefaultLoopFadeIn, + const TimeScale fadeScale = kDefaultLoopFadeScale); + virtual void loadLoopSound2(const Common::String &, const uint16 volume = 0x100, + const TimeValue fadeOut = kDefaultLoopFadeOut, const TimeValue fadeIn = kDefaultLoopFadeIn, + const TimeScale fadeScale = kDefaultLoopFadeScale); + + virtual void takeItemFromRoom(Item *); protected: PegasusEngine *_vm; Common::String _resName; + + virtual void loadSoundSpots(); + // Notification function. virtual void receiveNotification(Notification *, const tNotificationFlags); - virtual void createNeighborhoodSpots(); - virtual void loadSoundSpots(); + // Map info functions. + virtual void getExitEntry(const tRoomID room, const tDirectionConstant direction, ExitTable::Entry &entry); + virtual TimeValue getViewTime(const tRoomID room, const tDirectionConstant direction); + virtual void getDoorEntry(const tRoomID room, const tDirectionConstant direction, DoorTable::Entry &doorEntry); + virtual tDirectionConstant getTurnEntry(const tRoomID room, const tDirectionConstant direction, const tTurnDirection turn); + virtual void getZoomEntry(const tHotSpotID id, ZoomTable::Entry &zoomEntry); + virtual void getHotspotEntry(const tHotSpotID id, HotspotInfoTable::Entry &hotspotEntry); // Nav movie sequences. - virtual void checkStriding(); + 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, tNotificationFlags flags); + virtual void startZoomMovie(const ZoomTable::Entry &); + virtual void startDoorOpenMovie(const TimeValue, const TimeValue); + virtual void startTurnPush(const tTurnDirection, const TimeValue, const tDirectionConstant); + virtual void playExtraMovie(const ExtraTable::Entry &, const tNotificationFlags, const tInputBits interruptionFilter); + + virtual void activateCurrentView(const tRoomID, const tDirectionConstant, tSpotFlags); + + virtual void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *); + + virtual void startSpotOnceOnly(TimeValue, TimeValue); + + virtual void startMovieSequence(const TimeValue, const TimeValue, tNotificationFlags, + bool loopSequence, const tInputBits interruptionFilter, const TimeValue strideStop = 0xffffffff); + + virtual void createNeighborhoodSpots(); + + void resetLastExtra() { _lastExtra = -1; } + + virtual void throwAwayInterface(); // Action queue stuff void popActionQueue(); void serviceActionQueue(); void requestAction(const tQueueRequestType, const tExtraID, const TimeValue, const TimeValue, const tInputBits, const tNotificationFlags); + virtual bool prepareExtraSync(const tExtraID); + virtual bool waitMovieFinish(Movie *, const tInputBits); + + virtual tInputBits getInputFilter(); + + // Misc. + virtual uint16 getStaticCompassAngle(const tRoomID, const tDirectionConstant 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 newInteraction(const tInteractionID); + virtual void bumpIntoWall(); + virtual void zoomUpOrBump(); + // Navigation Data DoorTable _doorTable; ExitTable _exitTable; @@ -181,26 +294,57 @@ protected: TurnTable _turnTable; ViewTable _viewTable; ZoomTable _zoomTable; - virtual uint16 getStaticCompassAngle(const tRoomID, const tDirectionConstant dir); - virtual void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &); + tAlternateID _currentAlternate; + tHotSpotActivationID _currentActivation; + + int32 _lastExtra; + tDeathReason _extraDeathReason; // Graphics Movie _navMovie; + Picture _pushIn; + Push _turnPush; // Callbacks Notification _neighborhoodNotification; NotificationCallBack _navMovieCallBack; StriderCallBack _stridingCallBack; + NotificationCallBack _turnPushCallBack; + NotificationCallBack _spotSoundCallBack; + NotificationCallBack _delayCallBack; - tAlternateID _currentAlternate; - + // Hotspots HotspotList _neighborhoodHotspots; - NeighborhoodActionQueue _actionQueue; - + // Sounds Sound _spotSounds; + // Action queue + NeighborhoodActionQueue _actionQueue; + TimeBase _delayTimer; + + // Interruptibility... tInputBits _interruptionFilter; + + // Nav hiding (for info support...) + bool _isRunning; + + // TODO + //GameInteraction *_currentInteraction; + bool _doneWithInteraction; + Movie _croppedMovie; + + Sound _soundLoop1; + Common::String _loop1SoundString; + SoundFader _loop1Fader; + + Sound _soundLoop2; + Common::String _loop2SoundString; + SoundFader _loop2Fader; + + // The event timer... + FuseFunction _eventTimer; + uint32 _timerEvent; }; extern Neighborhood *g_neighborhood; diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp index 3a8e868d2d..60d5b9aa39 100644 --- a/engines/pegasus/pegasus.cpp +++ b/engines/pegasus/pegasus.cpp @@ -63,6 +63,8 @@ PegasusEngine::PegasusEngine(OSystem *syst, const PegasusGameDescription *gamede _gameMenu = 0; _deathReason = kDeathStranded; _neighborhood = 0; + _FXLevel = 0x80; + _ambientLevel = 0x80; } PegasusEngine::~PegasusEngine() { @@ -873,11 +875,6 @@ void PegasusEngine::resetEnergyDeathReason() { _deathReason = kDeathStranded; } -uint16 PegasusEngine::getSoundFXLevel() { - // TODO - return 0x100; -} - bool PegasusEngine::playerHasItem(const Item *item) { return playerHasItemID(item->getObjectID()); } @@ -1042,4 +1039,10 @@ void PegasusEngine::throwAwayEverything() { // TODO } +void PegasusEngine::dragItem(const Input &, Item *, tDragType) { + // TODO +} + + + } // End of namespace Pegasus diff --git a/engines/pegasus/pegasus.h b/engines/pegasus/pegasus.h index b01e1929f6..550761f4f5 100644 --- a/engines/pegasus/pegasus.h +++ b/engines/pegasus/pegasus.h @@ -114,7 +114,8 @@ public: void die(const tDeathReason); // Volume - uint16 getSoundFXLevel(); + uint16 getSoundFXLevel() { return _FXLevel; } + uint16 getAmbienceLevel() { return _ambientLevel; } // Items bool playerHasItem(const Item *); @@ -145,6 +146,11 @@ public: // Neighborhood void jumpToNewEnvironment(const tNeighborhoodID, const tRoomID, const tDirectionConstant); + // Dragging + void dragItem(const Input &, Item *, tDragType); + tDragType getDragType() const { return (tDragType)0; } // TODO + Item *getDraggingItem() const { return 0; } // TODO + protected: Common::Error run(); @@ -205,6 +211,10 @@ private: // Neighborhood Neighborhood *_neighborhood; + + // Sound + uint16 _ambientLevel; + uint16 _FXLevel; }; } // End of namespace Pegasus diff --git a/engines/pegasus/types.h b/engines/pegasus/types.h index 6c51c930eb..ed227847e4 100755 --- a/engines/pegasus/types.h +++ b/engines/pegasus/types.h @@ -180,6 +180,13 @@ enum tAirQuality { kAirQualityVacuum }; +enum tDragType { + kDragNoDrag, + kDragInventoryPickup, + kDragBiochipPickup, + kDragInventoryUse +}; + } // End of namespace Pegasus #endif |