aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/kevent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/kevent.cpp')
-rw-r--r--engines/sci/engine/kevent.cpp162
1 files changed, 123 insertions, 39 deletions
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index cb81da2279..9250e0fc13 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -24,15 +24,19 @@
#include "sci/sci.h"
#include "sci/engine/features.h"
-#include "sci/engine/state.h"
-#include "sci/engine/selector.h"
#include "sci/engine/kernel.h"
+#include "sci/engine/savegame.h"
+#include "sci/engine/selector.h"
+#include "sci/engine/state.h"
#include "sci/console.h"
#include "sci/debug.h" // for g_debug_simulated_key
#include "sci/event.h"
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/cursor.h"
#include "sci/graphics/maciconbar.h"
+#ifdef ENABLE_SCI32
+#include "sci/graphics/frameout.h"
+#endif
namespace Sci {
@@ -41,6 +45,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[1];
SciEvent curEvent;
int modifier_mask = getSciVersion() <= SCI_VERSION_01 ? SCI_KEYMOD_ALL : SCI_KEYMOD_NO_FOOLOCK;
+ uint16 modifiers = 0;
SegManager *segMan = s->_segMan;
Common::Point mousePos;
@@ -56,10 +61,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
if (g_debug_simulated_key && (mask & SCI_EVENT_KEYBOARD)) {
// In case we use a simulated event we query the current mouse position
mousePos = g_sci->_gfxCursor->getPosition();
-#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1)
- g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
-#endif
+
// Limit the mouse cursor position, if necessary
g_sci->_gfxCursor->refreshPosition();
@@ -71,17 +73,27 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
g_debug_simulated_key = 0;
return make_reg(0, 1);
}
-
+
curEvent = g_sci->getEventManager()->getSciEvent(mask);
+ if (s->_delayedRestoreGame) {
+ // delayed restore game from ScummVM menu got triggered
+ gamestate_delayedrestore(s);
+ return NULL_REG;
+ }
+
// For a real event we use its associated mouse position
- mousePos = curEvent.mousePos;
#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1)
- g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
+ if (getSciVersion() >= SCI_VERSION_2)
+ mousePos = curEvent.mousePosSci;
+ else {
+#endif
+ mousePos = curEvent.mousePos;
+ // Limit the mouse cursor position, if necessary
+ g_sci->_gfxCursor->refreshPosition();
+#ifdef ENABLE_SCI32
+ }
#endif
- // Limit the mouse cursor position, if necessary
- g_sci->_gfxCursor->refreshPosition();
if (g_sci->getVocabulary())
g_sci->getVocabulary()->parser_event = NULL_REG; // Invalidate parser event
@@ -93,7 +105,25 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
// question. Check GfxCursor::setPosition(), for a more detailed
// explanation and a list of cursor position workarounds.
if (s->_cursorWorkaroundRect.contains(mousePos.x, mousePos.y)) {
- s->_cursorWorkaroundActive = false;
+ // For OpenPandora and possibly other platforms, that support analog-stick control + touch screen
+ // control at the same time: in case the cursor is currently at the coordinate set by the scripts,
+ // we will count down instead of immediately disabling the workaround.
+ // On OpenPandora the cursor position is set, but it's overwritten shortly afterwards by the
+ // touch screen. In this case we would sometimes disable the workaround, simply because the touch
+ // screen hasn't yet overwritten the position and thus the workaround would not work anymore.
+ // On OpenPandora it would sometimes work and sometimes not without this.
+ if (s->_cursorWorkaroundPoint == mousePos) {
+ // Cursor is still at the same spot as set by the scripts
+ if (s->_cursorWorkaroundPosCount > 0) {
+ s->_cursorWorkaroundPosCount--;
+ } else {
+ // Was for quite a bit of time at that spot, so disable workaround now
+ s->_cursorWorkaroundActive = false;
+ }
+ } else {
+ // Cursor has moved, but is within the rect -> disable workaround immediately
+ s->_cursorWorkaroundActive = false;
+ }
} else {
mousePos.x = s->_cursorWorkaroundPoint.x;
mousePos.y = s->_cursorWorkaroundPoint.y;
@@ -103,7 +133,27 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x);
writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y);
- //s->_gui->moveCursor(s->gfx_state->pointer_pos.x, s->gfx_state->pointer_pos.y);
+ // Get current keyboard modifiers, only keep relevant bits
+ modifiers = curEvent.modifiers & modifier_mask;
+ if (g_sci->getPlatform() == Common::kPlatformDOS) {
+ // We are supposed to emulate SCI running in DOS
+
+ // We set the higher byte of the modifiers to 02h
+ // Original SCI also did that indirectly, because it asked BIOS for shift status
+ // via AH=0x02 INT16, which then sets the shift flags in AL
+ // AH is supposed to be destroyed in that case and it's not defined that 0x02
+ // is still in it on return. The value of AX was then set into the modifiers selector.
+ // At least one fan-made game (Betrayed Alliance) requires 0x02 to be in the upper byte,
+ // otherwise the darts game (script 111) will not work properly.
+
+ // It seems Sierra fixed this behaviour (effectively bug) in the SCI1 keyboard driver.
+ // SCI32 also resets the upper byte.
+
+ // This was verified in SSCI itself by creating a SCI game and checking behavior.
+ if (getSciVersion() <= SCI_VERSION_01) {
+ modifiers |= 0x0200;
+ }
+ }
switch (curEvent.type) {
case SCI_EVENT_QUIT:
@@ -118,34 +168,21 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
writeSelectorValue(segMan, obj, SELECTOR(message), curEvent.character);
// We only care about the translated character
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), modifiers);
break;
case SCI_EVENT_MOUSE_RELEASE:
case SCI_EVENT_MOUSE_PRESS:
-
// track left buttton clicks, if requested
- if (curEvent.type == SCI_EVENT_MOUSE_PRESS && curEvent.data == 1 && g_debug_track_mouse_clicks) {
+ if (curEvent.type == SCI_EVENT_MOUSE_PRESS && curEvent.modifiers == 0 && g_debug_track_mouse_clicks) {
g_sci->getSciDebugger()->debugPrintf("Mouse clicked at %d, %d\n",
mousePos.x, mousePos.y);
}
if (mask & curEvent.type) {
- int extra_bits = 0;
-
- switch (curEvent.data) {
- case 2:
- extra_bits = SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT;
- break;
- case 3:
- extra_bits = SCI_KEYMOD_CTRL;
- default:
- break;
- }
-
writeSelectorValue(segMan, obj, SELECTOR(type), curEvent.type);
writeSelectorValue(segMan, obj, SELECTOR(message), 0);
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), (curEvent.modifiers | extra_bits) & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), modifiers);
s->r_acc = make_reg(0, 1);
}
break;
@@ -154,7 +191,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
// Return a null event
writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_NONE);
writeSelectorValue(segMan, obj, SELECTOR(message), 0);
- writeSelectorValue(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), modifiers);
s->r_acc = NULL_REG;
}
@@ -224,11 +261,12 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
if (readSelectorValue(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard
uint16 message = readSelectorValue(segMan, obj, SELECTOR(message));
uint16 eventType = SCI_EVENT_DIRECTION;
- // Check if the game is using cursor views. These games allowed control
- // of the mouse cursor via the keyboard controls (the so called
- // "PseudoMouse" functionality in script 933).
- if (g_sci->_features->detectSetCursorType() == SCI_VERSION_1_1)
+ // It seems with SCI1 Sierra started to add the SCI_EVENT_DIRECTION bit instead of setting it directly.
+ // It was done inside the keyboard driver and is required for the PseudoMouse functionality and class
+ // to work (script 933).
+ if (g_sci->_features->detectPseudoMouseAbility() == kPseudoMouseAbilityTrue) {
eventType |= SCI_EVENT_KEYBOARD;
+ }
for (int i = 0; i < 9; i++) {
if (keyToDirMap[i].key == message) {
@@ -246,14 +284,13 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
- reg_t planeObject = argc > 1 ? argv[1] : NULL_REG; // SCI32
SegManager *segMan = s->_segMan;
if (obj.getSegment()) {
int16 x = readSelectorValue(segMan, obj, SELECTOR(x));
int16 y = readSelectorValue(segMan, obj, SELECTOR(y));
- g_sci->_gfxCoordAdjuster->kernelGlobalToLocal(x, y, planeObject);
+ g_sci->_gfxCoordAdjuster->kernelGlobalToLocal(x, y);
writeSelectorValue(segMan, obj, SELECTOR(x), x);
writeSelectorValue(segMan, obj, SELECTOR(y), y);
@@ -265,14 +302,13 @@ reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv) {
reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
- reg_t planeObject = argc > 1 ? argv[1] : NULL_REG; // SCI32
SegManager *segMan = s->_segMan;
if (obj.getSegment()) {
int16 x = readSelectorValue(segMan, obj, SELECTOR(x));
int16 y = readSelectorValue(segMan, obj, SELECTOR(y));
- g_sci->_gfxCoordAdjuster->kernelLocalToGlobal(x, y, planeObject);
+ g_sci->_gfxCoordAdjuster->kernelLocalToGlobal(x, y);
writeSelectorValue(segMan, obj, SELECTOR(x), x);
writeSelectorValue(segMan, obj, SELECTOR(y), y);
@@ -287,4 +323,52 @@ reg_t kJoystick(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
+#ifdef ENABLE_SCI32
+reg_t kGlobalToLocal32(EngineState *s, int argc, reg_t *argv) {
+ const reg_t result = argv[0];
+ const reg_t planeObj = argv[1];
+
+ bool visible = true;
+ Plane *plane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(planeObj);
+ if (plane == nullptr) {
+ plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObj);
+ visible = false;
+ }
+ if (plane == nullptr) {
+ error("kGlobalToLocal: Plane %04x:%04x not found", PRINT_REG(planeObj));
+ }
+
+ const int16 x = readSelectorValue(s->_segMan, result, SELECTOR(x)) - plane->_gameRect.left;
+ const int16 y = readSelectorValue(s->_segMan, result, SELECTOR(y)) - plane->_gameRect.top;
+
+ writeSelectorValue(s->_segMan, result, SELECTOR(x), x);
+ writeSelectorValue(s->_segMan, result, SELECTOR(y), y);
+
+ return make_reg(0, visible);
+}
+
+reg_t kLocalToGlobal32(EngineState *s, int argc, reg_t *argv) {
+ const reg_t result = argv[0];
+ const reg_t planeObj = argv[1];
+
+ bool visible = true;
+ Plane *plane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(planeObj);
+ if (plane == nullptr) {
+ plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObj);
+ visible = false;
+ }
+ if (plane == nullptr) {
+ error("kLocalToGlobal: Plane %04x:%04x not found", PRINT_REG(planeObj));
+ }
+
+ const int16 x = readSelectorValue(s->_segMan, result, SELECTOR(x)) + plane->_gameRect.left;
+ const int16 y = readSelectorValue(s->_segMan, result, SELECTOR(y)) + plane->_gameRect.top;
+
+ writeSelectorValue(s->_segMan, result, SELECTOR(x), x);
+ writeSelectorValue(s->_segMan, result, SELECTOR(y), y);
+
+ return make_reg(0, visible);
+}
+#endif
+
} // End of namespace Sci