SCI: Fix pseudo mouse in various SCI1 games like e.g. Larry5

Pseudo mouse was functionality in SCI1+ games, that allowed the
user to control the mouse via keyboard cursor keys.

This new class only worked, when a tiny difference inside
the keyboard driver happened on kMapKeyToDir calls. We previously
tried to enable this behavior depending on cursor type, but
this didn't work correctly (Larry 5 for example was not detected
as such, but had PseudoMouse support).
This commit is contained in:
Martin Kiewitz 2016-08-13 14:58:07 +02:00
parent 409772ea1f
commit c270b30a79
4 changed files with 67 additions and 4 deletions

@ -489,6 +489,7 @@ bool Console::cmdGetVersion(int argc, const char **argv) {
debugPrintf("Lofs type: %s\n", getSciVersionDesc(_engine->_features->detectLofsType()));
debugPrintf("Move count type: %s\n", (_engine->_features->handleMoveCount()) ? "increment" : "ignore");
debugPrintf("SetCursor type: %s\n", getSciVersionDesc(_engine->_features->detectSetCursorType()));
debugPrintf("PseudoMouse ability: %s\n", _engine->_features->detectPseudoMouseAbility() == kPseudoMouseAbilityTrue ? "yes" : "no");
#ifdef ENABLE_SCI32
if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE))
debugPrintf("SCI2.1 kernel table: %s\n", (_engine->_features->detectSci21KernelType() == SCI_VERSION_2) ? "modified SCI2 (old)" : "SCI2.1 (new)");

@ -45,6 +45,7 @@ GameFeatures::GameFeatures(SegManager *segMan, Kernel *kernel) : _segMan(segMan)
if (!ConfMan.getBool("use_cdaudio"))
_usesCdTrack = false;
_forceDOSTracks = false;
_pseudoMouseAbility = kPseudoMouseAbilityUninitialized;
}
reg_t GameFeatures::getDetectionAddr(const Common::String &objName, Selector slc, int methodNum) {
@ -605,4 +606,50 @@ bool GameFeatures::useAltWinGMSound() {
}
}
// PseudoMouse was added during SCI1
// PseudoMouseAbility is about a tiny difference in the keyboard driver, which sets the event type to either
// 40h (old behaviour) or 44h (the keyboard driver actually added 40h to the existing value).
// See engine/kevent.cpp, kMapKeyToDir - also script 933
// SCI1EGA:
// Quest for Glory 2 still used the old way.
//
// SCI1EARLY:
// King's Quest 5 0.000.062 uses the old way.
// Leisure Suit Larry 1 demo uses the new way, but no PseudoMouse class.
// Fairy Tales uses the new way.
// X-Mas 1990 uses the old way, no PseudoMouse class.
// Space Quest 4 floppy (1.1) uses the new way.
// Mixed Up Mother Goose uses the old way, no PseudoMouse class.
//
// SCI1MIDDLE:
// Leisure Suit Larry 5 demo uses the new way.
// Conquests of the Longbow demo uses the new way.
// Leisure Suit Larry 1 (2.0) uses the new way.
// Astro Chicken II uses the new way.
PseudoMouseAbilityType GameFeatures::detectPseudoMouseAbility() {
if (_pseudoMouseAbility == kPseudoMouseAbilityUninitialized) {
if (getSciVersion() < SCI_VERSION_1_EARLY) {
// SCI1 EGA or earlier -> pseudo mouse ability is always disabled
_pseudoMouseAbility = kPseudoMouseAbilityFalse;
} else if (getSciVersion() == SCI_VERSION_1_EARLY) {
// For SCI1 early some games had it enabled, some others didn't.
// We try to find an object called "PseudoMouse". If it's found, we enable the ability otherwise we don't.
reg_t pseudoMouseAddr = _segMan->findObjectByName("PseudoMouse", 0);
if (pseudoMouseAddr != NULL_REG) {
_pseudoMouseAbility = kPseudoMouseAbilityTrue;
} else {
_pseudoMouseAbility = kPseudoMouseAbilityFalse;
}
} else {
// SCI1 middle or later -> pseudo mouse ability is always enabled
_pseudoMouseAbility = kPseudoMouseAbilityTrue;
}
}
return _pseudoMouseAbility;
}
} // End of namespace Sci

@ -34,6 +34,12 @@ enum MoveCountType {
kIncrementMoveCount
};
enum PseudoMouseAbilityType {
kPseudoMouseAbilityUninitialized,
kPseudoMouseAbilityFalse,
kPseudoMouseAbilityTrue
};
class GameFeatures {
public:
GameFeatures(SegManager *segMan, Kernel *kernel);
@ -110,6 +116,12 @@ public:
*/
void forceDOSTracks() { _forceDOSTracks = true; }
/**
* Autodetects, if Pseudo Mouse ability is enabled (different behavior in keyboard driver)
* @return kPseudoMouseAbilityTrue or kPseudoMouseAbilityFalse
*/
PseudoMouseAbilityType detectPseudoMouseAbility();
private:
reg_t getDetectionAddr(const Common::String &objName, Selector slc, int methodNum = -1);
@ -130,6 +142,8 @@ private:
bool _usesCdTrack;
bool _forceDOSTracks;
PseudoMouseAbilityType _pseudoMouseAbility;
SegManager *_segMan;
Kernel *_kernel;
};

@ -258,11 +258,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) {