diff options
Diffstat (limited to 'engines/sci/engine/kevent.cpp')
-rw-r--r-- | engines/sci/engine/kevent.cpp | 162 |
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 |