[Scummvm-git-logs] scummvm master -> 5fe1e3b2faf01bd3ef06808031ac853f72aa0ceb
elasota
noreply at scummvm.org
Tue Mar 7 07:37:52 UTC 2023
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
5fe1e3b2fa VCRUISE: Add gyros
Commit: 5fe1e3b2faf01bd3ef06808031ac853f72aa0ceb
https://github.com/scummvm/scummvm/commit/5fe1e3b2faf01bd3ef06808031ac853f72aa0ceb
Author: elasota (ejlasota at gmail.com)
Date: 2023-03-07T02:33:35-05:00
Commit Message:
VCRUISE: Add gyros
Changed paths:
engines/vcruise/runtime.cpp
engines/vcruise/runtime.h
engines/vcruise/script.cpp
engines/vcruise/script.h
diff --git a/engines/vcruise/runtime.cpp b/engines/vcruise/runtime.cpp
index 856b8c52049..e955d426bfb 100644
--- a/engines/vcruise/runtime.cpp
+++ b/engines/vcruise/runtime.cpp
@@ -69,7 +69,7 @@ const MapScreenDirectionDef *MapDef::getScreenDirection(uint screen, uint direct
return screenDirections[screen][direction].get();
}
-ScriptEnvironmentVars::ScriptEnvironmentVars() : lmb(false), panInteractionID(0), fpsOverride(0) {
+ScriptEnvironmentVars::ScriptEnvironmentVars() : lmb(false), lmbDrag(false), panInteractionID(0), fpsOverride(0) {
}
void Runtime::RenderSection::init(const Common::Rect ¶mRect, const Graphics::PixelFormat &fmt) {
@@ -81,13 +81,47 @@ void Runtime::RenderSection::init(const Common::Rect ¶mRect, const Graphics:
Runtime::OSEvent::OSEvent() : type(kOSEventTypeInvalid), keyCode(static_cast<Common::KeyCode>(0)) {
}
+Runtime::Gyro::Gyro() {
+ reset();
+}
+
+void Runtime::Gyro::reset() {
+ currentState = 0;
+ requiredState = 0;
+}
+
+Runtime::GyroState::GyroState() {
+ reset();
+}
+
+void Runtime::GyroState::reset() {
+ for (uint i = 0; i < kNumGyros; i++)
+ gyros[i].reset();
+
+ completeInteraction = 0;
+ failureInteraction = 0;
+ frameSeparation = 1;
+
+ activeGyro = 0;
+ dragMargin = 0;
+ maxValue = 0;
+
+ negAnim = AnimationDef();
+ posAnim = AnimationDef();
+ isVertical = false;
+
+ dragBasePoint = Common::Point(0, 0);
+ dragBaseState = 0;
+ isWaitingForAnimation = false;
+}
+
Runtime::Runtime(OSystem *system, Audio::Mixer *mixer, const Common::FSNode &rootFSNode, VCruiseGameID gameID)
: _system(system), _mixer(mixer), _roomNumber(1), _screenNumber(0), _direction(0), _havePanAnimations(0), _loadedRoomNumber(0), _activeScreenNumber(0),
_gameState(kGameStateBoot), _gameID(gameID), _havePendingScreenChange(false), _havePendingReturnToIdleState(false), _scriptNextInstruction(0),
_escOn(false), _debugMode(false), _panoramaDirectionFlags(0),
_loadedAnimation(0), _animPendingDecodeFrame(0), _animDisplayingFrame(0), _animFirstFrame(0), _animLastFrame(0), _animStopFrame(0),
_animFrameRateLock(0), _animStartTime(0), _animFramesDecoded(0), _animDecoderState(kAnimDecoderStateStopped),
- _animPlayWhileIdle(false), _idleIsOnInteraction(false), _idleInteractionID(0),
+ _animPlayWhileIdle(false), _idleIsOnInteraction(false), _idleHaveClickInteraction(false), _idleHaveDragInteraction(false), _idleInteractionID(0),
_lmbDown(false), _lmbDragging(false), _lmbReleaseWasClick(false), _lmbDownTime(0),
_panoramaState(kPanoramaStateInactive) {
@@ -145,11 +179,15 @@ void Runtime::loadCursors(const char *exeName) {
}
if (_gameID == GID_REAH) {
- _namedCursors["CUR_TYL"] = 13; // Tyl = back
+ // For some reason most cursors map to their resource IDs, except for these
+ _scriptCursorIDToResourceIDOverride[13] = 35; // Points to finger (instead of back up)
+ _scriptCursorIDToResourceIDOverride[22] = 13; // Points to back up (instead of up arrow)
+
+ _namedCursors["CUR_TYL"] = 22; // Tyl = back
//_namedCursors["CUR_NIC"] = ? // Nic = nothing
//_namedCursors["CUR_WEZ"] = 50 // Wez = call? FIXME
_namedCursors["CUR_LUPA"] = 21; // Lupa = magnifier, could be 36 too?
- _namedCursors["CUR_NAC"] = 35; // Nac = top? Not sure. But this is the finger pointer.
+ _namedCursors["CUR_NAC"] = 13; // Nac = top? Not sure. But this is the finger pointer.
_namedCursors["CUR_PRZOD"] = 1; // Przod = forward
// CUR_ZOSTAW is in the executable memory but appears to be unused
@@ -203,6 +241,12 @@ bool Runtime::runFrame() {
case kGameStateWaitingForFacing:
moreActions = runWaitForFacing();
break;
+ case kGameStateGyroIdle:
+ moreActions = runGyroIdle();
+ break;
+ case kGameStateGyroAnimation:
+ moreActions = runGyroAnimation();
+ break;
default:
error("Unknown game state");
return false;
@@ -259,18 +303,22 @@ bool Runtime::runIdle() {
if (_debugMode)
drawDebugOverlay();
- detectPanoramaMouseMovement();
+ uint32 timestamp = g_system->getMillis();
+ detectPanoramaMouseMovement(timestamp);
OSEvent osEvent;
while (popOSEvent(osEvent)) {
if (osEvent.type == kOSEventTypeMouseMove) {
+ detectPanoramaMouseMovement(osEvent.timestamp);
+
bool changedState = dischargeIdleMouseMove();
if (changedState)
return true;
+
+
} else if (osEvent.type == kOSEventTypeLButtonUp) {
PanoramaState oldPanoramaState = _panoramaState;
_panoramaState = kPanoramaStateInactive;
- _idleIsOnInteraction = false;
if (_lmbReleaseWasClick) {
bool changedState = dischargeIdleClick();
@@ -280,13 +328,20 @@ bool Runtime::runIdle() {
// If the released from panorama mode, pick up any interactions at the new mouse location, and change the mouse back
if (oldPanoramaState != kPanoramaStateInactive) {
- debug(1, "Changing cursor to arrow due to panorama deactivation");
changeToCursor(_cursors[kCursorArrow]);
+ // Clear idle interaction so that if a drag occurs but doesn't trigger a panorama or other state change,
+ // interactions are re-detected here.
+ _idleIsOnInteraction = false;
+
bool changedState = dischargeIdleMouseMove();
if (changedState)
return true;
}
+ } else if (osEvent.type == kOSEventTypeLButtonDown) {
+ bool changedState = dischargeIdleMouseDown();
+ if (changedState)
+ return true;
}
}
@@ -384,6 +439,122 @@ bool Runtime::runWaitForFacing() {
return false;
}
+bool Runtime::runGyroIdle() {
+ if (!_lmbDown) {
+ exitGyroIdle();
+ return true;
+ }
+
+ int32 deltaCoordinate = 0;
+
+ if (_gyros.isVertical)
+ deltaCoordinate = _mousePos.y - _gyros.dragBasePoint.y;
+ else
+ deltaCoordinate = _gyros.dragBasePoint.x - _mousePos.x;
+
+
+ // Start the first step at half margin
+ int32 halfDragMargin = _gyros.dragMargin / 2;
+ if (deltaCoordinate < 0)
+ deltaCoordinate -= halfDragMargin;
+ else
+ deltaCoordinate += halfDragMargin;
+
+ int32 deltaState = deltaCoordinate / static_cast<int32>(_gyros.dragMargin);
+ int32 targetStateInitial = static_cast<int32>(_gyros.dragBaseState) + deltaState;
+
+ int32 targetState = 0;
+ if (targetStateInitial > 0) {
+ targetState = targetStateInitial;
+ if (static_cast<uint>(targetState) > _gyros.maxValue)
+ targetState = _gyros.maxValue;
+ }
+
+ Gyro &gyro = _gyros.gyros[_gyros.activeGyro];
+ if (targetState < gyro.currentState) {
+ AnimationDef animDef = _gyros.negAnim;
+
+ animDef.firstFrame += ((_gyros.maxValue - gyro.currentState) * _gyros.frameSeparation);
+ animDef.lastFrame = animDef.firstFrame + _gyros.frameSeparation;
+
+ changeAnimation(animDef, false);
+
+ gyro.currentState--;
+ _gameState = kGameStateGyroAnimation;
+ return true;
+ } else if (targetState > gyro.currentState) {
+ AnimationDef animDef = _gyros.posAnim;
+
+ animDef.firstFrame += gyro.currentState * _gyros.frameSeparation;
+ animDef.lastFrame = animDef.firstFrame + _gyros.frameSeparation;
+
+ changeAnimation(animDef, false);
+
+ gyro.currentState++;
+ _gameState = kGameStateGyroAnimation;
+ return true;
+ }
+
+ OSEvent evt;
+ while (popOSEvent(evt)) {
+ if (evt.type == kOSEventTypeLButtonUp) {
+ exitGyroIdle();
+ return true;
+ }
+ }
+
+ // Yield
+ return false;
+}
+
+bool Runtime::runGyroAnimation() {
+ bool animEnded = false;
+ continuePlayingAnimation(false, false, animEnded);
+
+ if (animEnded) {
+ _gameState = kGameStateGyroIdle;
+ return true;
+ }
+
+ // Yield
+ return false;
+}
+
+void Runtime::exitGyroIdle() {
+ bool succeeded = true;
+ for (uint i = 0; i < GyroState::kNumGyros; i++) {
+ const Gyro &gyro = _gyros.gyros[i];
+ if (gyro.currentState != gyro.requiredState) {
+ succeeded = false;
+ break;
+ }
+ }
+
+ // Activate the corresponding failure or success interaction if present
+ if (_scriptSet) {
+ RoomScriptSetMap_t::const_iterator roomScriptIt = _scriptSet->roomScripts.find(_roomNumber);
+ if (roomScriptIt != _scriptSet->roomScripts.end()) {
+ const ScreenScriptSetMap_t &screenScriptsMap = roomScriptIt->_value->screenScripts;
+ ScreenScriptSetMap_t::const_iterator screenScriptIt = screenScriptsMap.find(_screenNumber);
+ if (screenScriptIt != screenScriptsMap.end()) {
+ const ScreenScriptSet &screenScriptSet = *screenScriptIt->_value;
+
+ ScriptMap_t::const_iterator interactionScriptIt = screenScriptSet.interactionScripts.find(succeeded ? _gyros.completeInteraction : _gyros.failureInteraction);
+ if (interactionScriptIt != screenScriptSet.interactionScripts.end()) {
+ const Common::SharedPtr<Script> &script = interactionScriptIt->_value;
+ if (script) {
+ activateScript(script, ScriptEnvironmentVars());
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ _havePendingReturnToIdleState = true;
+ _gameState = kGameStateIdle;
+}
+
void Runtime::continuePlayingAnimation(bool loop, bool useStopFrame, bool &outAnimationEnded) {
outAnimationEnded = false;
@@ -462,6 +633,9 @@ void Runtime::continuePlayingAnimation(bool loop, bool useStopFrame, bool &outAn
Common::Rect copyRect = Common::Rect(0, 0, surface->w, surface->h);
+ if (!_animConstraintRect.isEmpty())
+ copyRect = copyRect.findIntersectingRect(_animConstraintRect);
+
Common::Rect constraintRect = Common::Rect(0, 0, _gameSection.rect.width(), _gameSection.rect.height());
copyRect = copyRect.findIntersectingRect(constraintRect);
@@ -556,6 +730,7 @@ bool Runtime::runScript() {
DISPATCH_OP(Dup);
DISPATCH_OP(Say3);
DISPATCH_OP(SetTimer);
+ DISPATCH_OP(GetTimer);
DISPATCH_OP(LoSet);
DISPATCH_OP(LoGet);
DISPATCH_OP(HiSet);
@@ -747,7 +922,7 @@ void Runtime::changeToScreen(uint roomNumber, uint screenNumber) {
_activeScreenNumber = screenNumber;
if (changedRoom) {
- // Scripts are not allowed
+ // This shouldn't happen when running a script
assert(!_activeScript);
_scriptSet.reset();
@@ -771,6 +946,8 @@ void Runtime::changeToScreen(uint roomNumber, uint screenNumber) {
}
if (changedScreen) {
+ _gyros.reset();
+
if (_scriptSet) {
RoomScriptSetMap_t::const_iterator roomScriptIt = _scriptSet->roomScripts.find(_roomNumber);
if (roomScriptIt != _scriptSet->roomScripts.end()) {
@@ -806,6 +983,8 @@ void Runtime::returnToIdleState() {
}
_idleIsOnInteraction = false;
+ _idleHaveClickInteraction = false;
+ _idleHaveDragInteraction = false;
// Do this before detectPanoramaMouseMovement so continuous panorama keeps the correct cursor
changeToCursor(_cursors[kCursorArrow]);
@@ -813,7 +992,7 @@ void Runtime::returnToIdleState() {
detectPanoramaDirections();
_panoramaState = kPanoramaStateInactive;
- detectPanoramaMouseMovement();
+ detectPanoramaMouseMovement(g_system->getMillis());
(void) dischargeIdleMouseMove();
}
@@ -848,6 +1027,8 @@ bool Runtime::dischargeIdleMouseMove() {
if (_idleIsOnInteraction && (!isOnInteraction || interactionID != _idleInteractionID)) {
// Mouse left the previous interaction
_idleIsOnInteraction = false;
+ _idleHaveClickInteraction = false;
+ _idleHaveDragInteraction = false;
changeToCursor(_cursors[kCursorArrow]);
}
@@ -891,26 +1072,32 @@ bool Runtime::dischargeIdleMouseMove() {
return false;
}
-bool Runtime::dischargeIdleClick() {
- const MapScreenDirectionDef *sdDef = _map.getScreenDirection(_screenNumber, _direction);
+bool Runtime::dischargeIdleMouseDown() {
+ if (_idleIsOnInteraction && _idleHaveDragInteraction) {
+ // Interaction, is there a script?
+ Common::SharedPtr<Script> script = findScriptForInteraction(_idleInteractionID);
- Common::Point relMouse(_mousePos.x - _gameSection.rect.left, _mousePos.y - _gameSection.rect.top);
+ _idleIsOnInteraction = false; // ?
- bool isOnInteraction = false;
- uint interactionID = 0;
- if (sdDef) {
- for (const InteractionDef &idef : sdDef->interactions) {
- if (idef.rect.contains(relMouse)) {
- isOnInteraction = true;
- interactionID = idef.interactionID;
- break;
- }
+ if (script) {
+ ScriptEnvironmentVars vars;
+ vars.lmbDrag = true;
+
+ activateScript(script, vars);
+ return true;
}
}
- if (isOnInteraction) {
+ // Didn't do anything
+ return false;
+}
+
+bool Runtime::dischargeIdleClick() {
+ if (_idleIsOnInteraction && _idleHaveClickInteraction) {
// Interaction, is there a script?
- Common::SharedPtr<Script> script = findScriptForInteraction(interactionID);
+ Common::SharedPtr<Script> script = findScriptForInteraction(_idleInteractionID);
+
+ _idleIsOnInteraction = false; // ?
if (script) {
ScriptEnvironmentVars vars;
@@ -1030,6 +1217,7 @@ void Runtime::changeAnimation(const AnimationDef &animDef, uint initialFrame, bo
_animPendingDecodeFrame = initialFrame;
_animFirstFrame = animDef.firstFrame;
_animLastFrame = animDef.lastFrame;
+ _animConstraintRect = animDef.constraintRect;
_animFrameRateLock = 0;
if (consumeFPSOverride) {
@@ -1048,6 +1236,11 @@ AnimationDef Runtime::stackArgsToAnimDef(const StackValue_t *args) const {
def.firstFrame = args[1];
def.lastFrame = args[2];
+ def.constraintRect.left = args[3];
+ def.constraintRect.top = args[4];
+ def.constraintRect.right = args[5];
+ def.constraintRect.bottom = args[6];
+
return def;
}
@@ -1059,6 +1252,11 @@ void Runtime::pushAnimDef(const AnimationDef &animDef) {
_scriptStack.push_back(animDef.animNum);
_scriptStack.push_back(animDef.firstFrame);
_scriptStack.push_back(animDef.lastFrame);
+
+ _scriptStack.push_back(animDef.constraintRect.left);
+ _scriptStack.push_back(animDef.constraintRect.top);
+ _scriptStack.push_back(animDef.constraintRect.right);
+ _scriptStack.push_back(animDef.constraintRect.bottom);
}
void Runtime::activateScript(const Common::SharedPtr<Script> &script, const ScriptEnvironmentVars &envVars) {
@@ -1088,14 +1286,11 @@ bool Runtime::parseIndexDef(IndexParseType parseType, uint roomNumber, const Com
uint lastFrame = 0;
if (sscanf(value.c_str(), "%i, %u, %u", &animNum, &firstFrame, &lastFrame) != 3)
error("Malformed room animation def '%s'", value.c_str());
-
- AnimationDef animDef;
+ AnimationDef &animDef = _roomDefs[roomNumber]->animations[key];
animDef.animNum = animNum;
animDef.firstFrame = firstFrame;
animDef.lastFrame = lastFrame;
-
- _roomDefs[roomNumber]->animations[key] = animDef;
} break;
case kIndexParseTypeRRoom: {
Common::String name;
@@ -1109,7 +1304,9 @@ bool Runtime::parseIndexDef(IndexParseType parseType, uint roomNumber, const Com
int numValuesRead = sscanf(value.c_str(), "%i, %i, %i, %i", &left, &top, &width, &height);
if (numValuesRead == 4) {
- _roomDefs[roomNumber]->rects[key] = Common::Rect(left, top, left + width, top + height);
+ AnimationDef &animDef = _roomDefs[roomNumber]->animations[key];
+
+ animDef.constraintRect = Common::Rect(left, top, left + width, top + height);
} else {
// Line 4210 in Reah contains an animation def instead of a rect def, so we need to tolerate invalid values here
warning("Invalid rect def in logic index '%s'", value.c_str());
@@ -1227,8 +1424,8 @@ void Runtime::detectPanoramaDirections() {
_panoramaDirectionFlags |= kPanoramaHorizFlags;
}
-void Runtime::detectPanoramaMouseMovement() {
- if (_panoramaState == kPanoramaStateInactive && (_lmbDragging || (_lmbDown && (g_system->getMillis() - _lmbDownTime) >= 500)))
+void Runtime::detectPanoramaMouseMovement(uint32 timestamp) {
+ if (_panoramaState == kPanoramaStateInactive && (_lmbDragging || (_lmbDown && (timestamp - _lmbDownTime) >= 500)))
panoramaActivate();
}
@@ -1378,7 +1575,14 @@ void Runtime::scriptOpAngle(ScriptArg_t arg) {
_scriptStack.push_back((stackArgs[0] == static_cast<StackValue_t>(_direction)) ? 1 : 0);
}
-OPCODE_STUB(AngleGGet)
+void Runtime::scriptOpAngleGGet(ScriptArg_t arg) {
+ TAKE_STACK(1);
+
+ if (stackArgs[0] < 0 || stackArgs[0] >= static_cast<StackValue_t>(GyroState::kNumGyros))
+ error("Invalid gyro index in angleGGet op");
+
+ _scriptStack.push_back(_gyros.gyros[stackArgs[0]].currentState);
+}
void Runtime::scriptOpSpeed(ScriptArg_t arg) {
TAKE_STACK(1);
@@ -1495,7 +1699,24 @@ void Runtime::scriptOpAnimF(ScriptArg_t arg) {
}
OPCODE_STUB(AnimN)
-OPCODE_STUB(AnimG)
+
+void Runtime::scriptOpAnimG(ScriptArg_t arg) {
+ TAKE_STACK(kAnimDefStackArgs * 2 + 1);
+
+ _gyros.posAnim = stackArgsToAnimDef(stackArgs + 0);
+ _gyros.negAnim = stackArgsToAnimDef(stackArgs + kAnimDefStackArgs);
+ _gyros.isVertical = (stackArgs[kAnimDefStackArgs * 2 + 0] != 0);
+
+ if (_gyros.isVertical)
+ changeToCursor(_cursors[_panCursors[kPanCursorDraggableUp | kPanCursorDraggableDown]]);
+ else
+ changeToCursor(_cursors[_panCursors[kPanCursorDraggableHoriz]]);
+
+ _gyros.dragBasePoint = _mousePos;
+ _gyros.dragBaseState = _gyros.gyros[_gyros.activeGyro].currentState;
+
+ _gameState = kGameStateGyroIdle;
+}
void Runtime::scriptOpAnimS(ScriptArg_t arg) {
TAKE_STACK(kAnimDefStackArgs + 2);
@@ -1567,7 +1788,13 @@ void Runtime::scriptOpSetCursor(ScriptArg_t arg) {
if (stackArgs[0] < 0 || static_cast<uint>(stackArgs[0]) >= _cursors.size())
error("Invalid cursor ID");
- changeToCursor(_cursors[stackArgs[0]]);
+ uint resolvedCursorID = stackArgs[0];
+
+ Common::HashMap<StackValue_t, uint>::const_iterator overrideIt = _scriptCursorIDToResourceIDOverride.find(resolvedCursorID);
+ if (overrideIt != _scriptCursorIDToResourceIDOverride.end())
+ resolvedCursorID = overrideIt->_value;
+
+ changeToCursor(_cursors[resolvedCursorID]);
}
void Runtime::scriptOpSetRoom(ScriptArg_t arg) {
@@ -1577,15 +1804,25 @@ void Runtime::scriptOpSetRoom(ScriptArg_t arg) {
}
void Runtime::scriptOpLMB(ScriptArg_t arg) {
- if (!_scriptEnv.lmb)
+ if (!_scriptEnv.lmb) {
+ _idleHaveClickInteraction = true;
terminateScript();
+ }
}
void Runtime::scriptOpLMB1(ScriptArg_t arg) {
- warning("LMB1 script op not implemented");
+ if (!_scriptEnv.lmbDrag) {
+ _idleHaveDragInteraction = true;
+ terminateScript();
+ }
}
-OPCODE_STUB(SoundS1)
+void Runtime::scriptOpSoundS1(ScriptArg_t arg) {
+ TAKE_STACK(1);
+
+ warning("Sound play not implemented yet");
+ (void)stackArgs;
+}
void Runtime::scriptOpSoundL2(ScriptArg_t arg) {
TAKE_STACK(2);
@@ -1617,25 +1854,43 @@ void Runtime::scriptOpMusicDn(ScriptArg_t arg) {
void Runtime::scriptOpParm1(ScriptArg_t arg) {
TAKE_STACK(3);
- warning("Parm1 is not implemented");
- (void)stackArgs;
+ if (stackArgs[0] < 0 || static_cast<uint>(stackArgs[0]) >= GyroState::kNumGyros)
+ error("Invalid gyro index for Parm1");
+
+ uint gyroIndex = stackArgs[0];
+
+ Gyro &gyro = _gyros.gyros[gyroIndex];
+ gyro.currentState = stackArgs[1];
+ gyro.requiredState = stackArgs[2];
}
void Runtime::scriptOpParm2(ScriptArg_t arg) {
TAKE_STACK(3);
- warning("Parm2 is not implemented");
- (void)stackArgs;
+ _gyros.completeInteraction = stackArgs[0];
+ _gyros.failureInteraction = stackArgs[1];
+ _gyros.frameSeparation = stackArgs[2];
+
+ if (_gyros.frameSeparation <= 0)
+ error("Invalid gyro frame separation");
}
-void Runtime::scriptOpParm3(ScriptArg_t arg) {
+OPCODE_STUB(Parm3)
+
+void Runtime::scriptOpParmG(ScriptArg_t arg) {
TAKE_STACK(3);
- warning("Parm3 is not implemented");
- (void)stackArgs;
-}
+ int32 gyroSlot = stackArgs[0];
+ int32 dragMargin = stackArgs[1];
+ int32 maxValue = stackArgs[2];
+
+ if (gyroSlot < 0 || static_cast<uint>(gyroSlot) >= GyroState::kNumGyros)
+ error("Invalid gyro slot from ParmG op");
-OPCODE_STUB(ParmG)
+ _gyros.activeGyro = gyroSlot;
+ _gyros.dragMargin = dragMargin;
+ _gyros.maxValue = maxValue;
+}
void Runtime::scriptOpVolumeUp3(ScriptArg_t arg) {
TAKE_STACK(3);
@@ -1694,6 +1949,18 @@ void Runtime::scriptOpSetTimer(ScriptArg_t arg) {
_timers[static_cast<uint>(stackArgs[0])] = g_system->getMillis() + static_cast<uint32>(stackArgs[1]) * 1000u;
}
+void Runtime::scriptOpGetTimer(ScriptArg_t arg) {
+ TAKE_STACK(1);
+
+ bool isCompleted = false;
+
+ Common::HashMap<uint, uint32>::const_iterator timerIt = _timers.find(stackArgs[0]);
+ if (timerIt != _timers.end())
+ isCompleted = (g_system->getMillis() >= timerIt->_value);
+
+ _scriptStack.push_back(isCompleted ? 1 : 0);
+}
+
void Runtime::scriptOpLoSet(ScriptArg_t arg) {
scriptOpVerticalPanSet(_havePanDownFromDirection);
}
diff --git a/engines/vcruise/runtime.h b/engines/vcruise/runtime.h
index 4f38d8ca169..8cdc64d9a47 100644
--- a/engines/vcruise/runtime.h
+++ b/engines/vcruise/runtime.h
@@ -66,6 +66,8 @@ enum GameState {
kGameStateQuit, // Quitting
kGameStateIdle, // Waiting for input events
kGameStateScript, // Running a script
+ kGameStateGyroIdle, // Waiting for mouse movement to run a gyro
+ kGameStateGyroAnimation, // Animating a gyro
kGameStatePanLeft,
kGameStatePanRight,
@@ -77,11 +79,12 @@ struct AnimationDef {
int animNum; // May be negative if reversed
uint firstFrame;
uint lastFrame; // Inclusive
+
+ Common::Rect constraintRect;
};
struct RoomDef {
Common::HashMap<Common::String, AnimationDef> animations;
- Common::HashMap<Common::String, Common::Rect> rects;
Common::HashMap<Common::String, uint> vars;
Common::HashMap<Common::String, int> values;
Common::HashMap<Common::String, Common::String> texts;
@@ -116,6 +119,7 @@ struct ScriptEnvironmentVars {
ScriptEnvironmentVars();
bool lmb;
+ bool lmbDrag;
uint panInteractionID;
uint fpsOverride;
};
@@ -169,6 +173,41 @@ private:
void init(const Common::Rect ¶mRect, const Graphics::PixelFormat &fmt);
};
+ struct Gyro {
+ int32 currentState;
+ int32 requiredState;
+
+ Gyro();
+
+ void reset();
+ };
+
+ struct GyroState {
+ GyroState();
+
+ void reset();
+
+ static const uint kNumGyros = 4;
+
+ Gyro gyros[kNumGyros];
+
+ uint completeInteraction;
+ uint failureInteraction;
+ uint frameSeparation;
+
+ uint activeGyro;
+ uint dragMargin;
+ uint maxValue;
+
+ AnimationDef negAnim;
+ AnimationDef posAnim;
+ bool isVertical;
+
+ Common::Point dragBasePoint;
+ uint dragBaseState;
+ bool isWaitingForAnimation;
+ };
+
enum OSEventType {
kOSEventTypeInvalid,
@@ -221,6 +260,9 @@ private:
bool runScript();
bool runWaitForAnimation();
bool runWaitForFacing();
+ bool runGyroIdle();
+ bool runGyroAnimation();
+ void exitGyroIdle();
void continuePlayingAnimation(bool loop, bool useStopFrame, bool &outEndedAnimation);
void drawSectionToScreen(const RenderSection §ion, const Common::Rect &rect);
void commitSectionToScreen(const RenderSection §ion, const Common::Rect &rect);
@@ -236,6 +278,7 @@ private:
void returnToIdleState();
void changeToCursor(const Common::SharedPtr<Graphics::WinCursorGroup> &cursor);
bool dischargeIdleMouseMove();
+ bool dischargeIdleMouseDown();
bool dischargeIdleClick();
void loadMap(Common::SeekableReadStream *stream);
@@ -256,7 +299,7 @@ private:
Common::SharedPtr<Script> findScriptForInteraction(uint interactionID) const;
void detectPanoramaDirections();
- void detectPanoramaMouseMovement();
+ void detectPanoramaMouseMovement(uint32 timestamp);
void panoramaActivate();
bool computeFaceDirectionAnimation(uint desiredDirection, const AnimationDef *&outAnimDef, uint &outInitialFrame, uint &outStopFrame);
@@ -302,6 +345,7 @@ private:
void scriptOpDup(ScriptArg_t arg);
void scriptOpSay3(ScriptArg_t arg);
void scriptOpSetTimer(ScriptArg_t arg);
+ void scriptOpGetTimer(ScriptArg_t arg);
void scriptOpLoSet(ScriptArg_t arg);
void scriptOpLoGet(ScriptArg_t arg);
void scriptOpHiSet(ScriptArg_t arg);
@@ -343,12 +387,15 @@ private:
uint _panCursors[kPanCursorMaxCount];
Common::HashMap<Common::String, StackValue_t> _namedCursors;
+ Common::HashMap<StackValue_t, uint> _scriptCursorIDToResourceIDOverride;
OSystem *_system;
uint _roomNumber; // Room number can be changed independently of the loaded room, the screen doesn't change until a command changes it
uint _screenNumber;
uint _direction;
+ GyroState _gyros;
+
AnimationDef _panLeftAnimationDef;
AnimationDef _panRightAnimationDef;
bool _havePanAnimations;
@@ -407,12 +454,15 @@ private:
uint _animLastFrame;
uint _animStopFrame;
uint _animFrameRateLock;
+ Common::Rect _animConstraintRect;
uint32 _animStartTime;
uint32 _animFramesDecoded;
uint _loadedAnimation;
bool _animPlayWhileIdle;
bool _idleIsOnInteraction;
+ bool _idleHaveClickInteraction;
+ bool _idleHaveDragInteraction;
uint _idleInteractionID;
Audio::Mixer *_mixer;
@@ -440,7 +490,7 @@ private:
Common::Array<OSEvent> _pendingEvents;
- static const uint kAnimDefStackArgs = 3;
+ static const uint kAnimDefStackArgs = 7;
static const uint kCursorArrow = 0;
diff --git a/engines/vcruise/script.cpp b/engines/vcruise/script.cpp
index f8bdb1ebd72..c32a56b8936 100644
--- a/engines/vcruise/script.cpp
+++ b/engines/vcruise/script.cpp
@@ -340,6 +340,7 @@ static ScriptNamedInstruction g_namedInstructions[] = {
{"dup", ProtoOp::kProtoOpScript, ScriptOps::kDup},
{"say3", ProtoOp::kProtoOpScript, ScriptOps::kSay3},
{"setTimer", ProtoOp::kProtoOpScript, ScriptOps::kSetTimer},
+ {"getTimer", ProtoOp::kProtoOpScript, ScriptOps::kGetTimer},
{"lo!", ProtoOp::kProtoOpScript, ScriptOps::kLoSet},
{"lo@", ProtoOp::kProtoOpScript, ScriptOps::kLoGet},
{"hi!", ProtoOp::kProtoOpScript, ScriptOps::kHiSet},
diff --git a/engines/vcruise/script.h b/engines/vcruise/script.h
index ddf6cc84f46..1976606a3ce 100644
--- a/engines/vcruise/script.h
+++ b/engines/vcruise/script.h
@@ -81,6 +81,7 @@ enum ScriptOp {
kDup,
kSay3,
kSetTimer,
+ kGetTimer,
kLoSet,
kLoGet,
kHiSet,
More information about the Scummvm-git-logs
mailing list