aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWalter van Niftrik2009-08-30 01:37:52 +0000
committerWalter van Niftrik2009-08-30 01:37:52 +0000
commitcf5483c3d862a1076943a9b7d986b38e3d1908de (patch)
tree6372128db94e25790d6701e48104e3207df1815a
parentfff023794f1f177fd4634d0153a6208a5bb2d8f4 (diff)
downloadscummvm-rg350-cf5483c3d862a1076943a9b7d986b38e3d1908de.tar.gz
scummvm-rg350-cf5483c3d862a1076943a9b7d986b38e3d1908de.tar.bz2
scummvm-rg350-cf5483c3d862a1076943a9b7d986b38e3d1908de.zip
SCI: Add SetCursor detection. Cleanup.
svn-id: r43812
-rw-r--r--engines/sci/engine/kgraphics.cpp110
-rw-r--r--engines/sci/engine/ksound.cpp12
-rw-r--r--engines/sci/engine/script.cpp1
-rw-r--r--engines/sci/engine/state.cpp130
-rw-r--r--engines/sci/engine/state.h18
-rw-r--r--engines/sci/engine/vm.h2
6 files changed, 138 insertions, 135 deletions
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 18017e0d08..89fed9d2d8 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -301,82 +301,62 @@ static gfx_color_t graph_map_color(EngineState *s, int color, int priority, int
return retval;
}
-reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) {
- SciVersion version = s->resourceManager->sciVersion();
+static reg_t kSetCursorSci0(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+ uint16 cursor = argv[0].toSint16();
+
+ if ((argc >= 2) && (argv[1].toSint16() == 0))
+ cursor = GFXOP_NO_POINTER;
+
+ GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state, cursor));
+
+ // Set pointer position, if requested
+ if (argc >= 4) {
+ Common::Point newPos = Common::Point(argv[2].toSint16() + s->port->_bounds.x, argv[3].toSint16() + s->port->_bounds.y);
+ GFX_ASSERT(gfxop_set_pointer_position(s->gfx_state, newPos));
+ }
+
+ return s->r_acc;
+}
+
+static reg_t kSetCursorSci11(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+ Common::Point *hotspot = NULL;
switch (argc) {
- case 1 :
- if (version < SCI_VERSION_1_LATE) {
- GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state, argv[0].toSint16()));
- } else if (version < SCI_VERSION_1_1) {
- if (argv[0].toSint16() <= 1) {
- // Newer (SCI1.1) semantics: show/hide cursor
- CursorMan.showMouse(argv[0].toSint16() != 0);
- } else {
- // Pre-SCI1.1: set cursor according to the first parameter
- GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state, argv[0].toSint16()));
- }
- } else {
- // SCI1.1: Show/hide cursor
- CursorMan.showMouse(argv[0].toSint16() != 0);
- }
- break;
- case 2 :
- if (version < SCI_VERSION_1_LATE) {
- GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state,
- argv[1].toSint16() == 0 ? GFXOP_NO_POINTER : argv[0].toSint16()));
- } else if (version < SCI_VERSION_1_1) {
- // Pre-SCI1.1: set cursor according to the first parameter, and toggle its
- // visibility based on the second parameter
- // Some late SCI1 games actually use the SCI1.1 version of this call (EcoQuest 1
- // and KQ5 CD, but I haven't seen this case happen), but we can determine the
- // semantics from the second parameter passed.
- // Rationale: with the older behavior, the second parameter can either be 0
- // (hide cursor) or 1/-1 (show cursor). This could be problematic if the engine
- // tries to place the cursor at (x, 0) or (x, 1), but no SCI1 game does that, as
- // this would open the menu on top. LSL5 is an exception, as the game can open
- // the menu when the player presses a button during the intro, but the cursor is
- // not placed on (x, 0) or (x, 1)
- if (argv[1].toSint16() <= 1) {
- GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state,
- argv[1].toSint16() == 0 ? GFXOP_NO_POINTER : argv[0].toSint16()));
- } else { // newer (SCI1.1) semantics: set pointer position
- GFX_ASSERT(gfxop_set_pointer_position(s->gfx_state,
- Common::Point(argv[0].toUint16(), argv[1].toUint16())));
- }
- } else {
- // SCI1.1 and newer: set pointer position
- GFX_ASSERT(gfxop_set_pointer_position(s->gfx_state,
- Common::Point(argv[0].toUint16(), argv[1].toUint16())));
- }
+ case 1:
+ CursorMan.showMouse(argv[0].toSint16() != 0);
break;
- case 4 :
- GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state,
- argv[0].toUint16() == 0 ? GFXOP_NO_POINTER : argv[0].toSint16()));
-
- // Set pointer position, if requested
- if (argc > 2) {
- Common::Point newPos = Common::Point(argv[2].toSint16() + s->port->_bounds.x, argv[3].toSint16() + s->port->_bounds.y);
- GFX_ASSERT(gfxop_set_pointer_position(s->gfx_state, newPos));
- }
+ case 2:
+ GFX_ASSERT(gfxop_set_pointer_position(s->gfx_state,
+ Common::Point(argv[0].toUint16(), argv[1].toUint16())));
break;
- case 3 :
- case 5 :
- case 9 :
- if (argc > 3) {
- Common::Point hotspot = Common::Point(argv[3].toSint16(), argv[4].toSint16());
- GFX_ASSERT(gfxop_set_pointer_view(s->gfx_state, argv[0].toUint16(), argv[1].toUint16(), argv[2].toUint16(), &hotspot));
- } else {
- GFX_ASSERT(gfxop_set_pointer_view(s->gfx_state, argv[0].toUint16(), argv[1].toUint16(), argv[2].toUint16(), NULL));
- }
+ case 5:
+ case 9:
+ hotspot = new Common::Point(argv[3].toSint16(), argv[4].toSint16());
+ // Fallthrough
+ case 3:
+ GFX_ASSERT(gfxop_set_pointer_view(s->gfx_state, argv[0].toUint16(), argv[1].toUint16(), argv[2].toUint16(), hotspot));
+ if (hotspot)
+ delete hotspot;
break;
default :
- error("kSetCursor: Unhandled case: %d arguments given", argc);
+ warning("kSetCursor: Unhandled case: %d arguments given", argc);
break;
}
return s->r_acc;
}
+reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+ switch (s->detectSetCursorType()) {
+ case SCI_VERSION_0_EARLY:
+ return kSetCursorSci0(s, funct_nr, argc, argv);
+ case SCI_VERSION_1_1:
+ return kSetCursorSci11(s, funct_nr, argc, argv);
+ default:
+ warning("Unknown SetCursor type");
+ return NULL_REG;
+ }
+}
+
reg_t kMoveCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) {
Common::Point newPos;
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp
index 514f063f7e..4c71120f50 100644
--- a/engines/sci/engine/ksound.cpp
+++ b/engines/sci/engine/ksound.cpp
@@ -206,7 +206,7 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their
}
-reg_t kDoSoundSci0(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+static reg_t kDoSoundSci0(EngineState *s, int funct_nr, int argc, reg_t *argv) {
SegManager *segManager = s->segmentManager;
reg_t obj = (argc > 1) ? argv[1] : NULL_REG;
uint16 command = argv[0].toUint16();
@@ -386,7 +386,7 @@ reg_t kDoSoundSci0(EngineState *s, int funct_nr, int argc, reg_t *argv) {
}
-reg_t kDoSoundSci1Early(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+static reg_t kDoSoundSci1Early(EngineState *s, int funct_nr, int argc, reg_t *argv) {
SegManager *segManager = s->segmentManager;
uint16 command = argv[0].toUint16();
reg_t obj = (argc > 1) ? argv[1] : NULL_REG;
@@ -677,7 +677,7 @@ reg_t kDoSoundSci1Early(EngineState *s, int funct_nr, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kDoSoundSci1Late(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+static reg_t kDoSoundSci1Late(EngineState *s, int funct_nr, int argc, reg_t *argv) {
SegManager *segManager = s->segmentManager;
uint16 command = argv[0].toUint16();
reg_t obj = (argc > 1) ? argv[1] : NULL_REG;
@@ -994,11 +994,11 @@ reg_t kDoSoundSci1Late(EngineState *s, int funct_nr, int argc, reg_t *argv) {
*/
reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) {
switch(s->detectDoSoundType()) {
- case EngineState::kDoSoundTypeSci0:
+ case SCI_VERSION_0_EARLY:
return kDoSoundSci0(s, funct_nr, argc, argv);
- case EngineState::kDoSoundTypeSci1Early:
+ case SCI_VERSION_1_EARLY:
return kDoSoundSci1Early(s, funct_nr, argc, argv);
- case EngineState::kDoSoundTypeSci1Late:
+ case SCI_VERSION_1_LATE:
return kDoSoundSci1Late(s, funct_nr, argc, argv);
default:
warning("Unknown DoSound type");
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 1534208d62..4dacd6b505 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -241,6 +241,7 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(parseLang);
FIND_SELECTOR(motionCue);
FIND_SELECTOR(egoMoveSpeed);
+ FIND_SELECTOR(setCursor);
}
void Kernel::dumpScriptObject(char *data, int seeker, int objsize) {
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index da14d460f1..ca4190df8e 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -119,7 +119,8 @@ EngineState::EngineState(ResourceManager *res, uint32 flags)
speedThrottler = new SpeedThrottler(res->sciVersion());
- _doSoundType = kDoSoundTypeUnknown;
+ _setCursorType = SCI_VERSION_AUTODETECT;
+ _doSoundType = SCI_VERSION_AUTODETECT;
}
EngineState::~EngineState() {
@@ -246,78 +247,97 @@ Common::String EngineState::strSplit(const char *str, const char *sep) {
return retval;
}
-EngineState::DoSoundType EngineState::detectDoSoundType() {
- if (_doSoundType == kDoSoundTypeUnknown) {
+int EngineState::methodChecksum(reg_t objAddress, Selector sel, int offset, uint size) const {
+ reg_t fptr;
+
+ Object *obj = obj_get(segmentManager, objAddress);
+ SelectorType selType = lookup_selector(this->segmentManager, objAddress, sel, NULL, &fptr);
+
+ if (!obj || (selType != kSelectorMethod))
+ return -1;
+
+ Script *script = segmentManager->getScript(fptr.segment);
+
+ if (!script->buf || (fptr.offset + offset < 0))
+ return -1;
+
+ fptr.offset += offset;
+
+ if (fptr.offset + size > script->buf_size)
+ return -1;
+
+ byte *buf = script->buf + fptr.offset;
+
+ uint sum = 0;
+ for (uint i = 0; i < size; i++)
+ sum += buf[i];
+
+ return sum;
+}
+
+SciVersion EngineState::detectDoSoundType() {
+ if (_doSoundType == SCI_VERSION_AUTODETECT) {
reg_t soundClass;
- const uint checkBytes = 6; // Number of bytes to check
if (!parse_reg_t(this, "?Sound", &soundClass)) {
- reg_t fptr;
-
- Object *obj = obj_get(segmentManager, soundClass);
- SelectorType sel = lookup_selector(this->segmentManager, soundClass, ((SciEngine*)g_engine)->getKernel()->_selectorMap.play, NULL, &fptr);
-
- if (obj && (sel == kSelectorMethod)) {
- Script *script = segmentManager->getScript(fptr.segment);
-
- if (fptr.offset > checkBytes) {
- // Go to the last portion of Sound::init, should be right before the play function
- fptr.offset -= checkBytes;
- byte *buf = script->buf + fptr.offset;
-
- // Check the call to DoSound's INIT_HANDLE function.
- // It's either subfunction 0, 5 or 6, depending on the version of DoSound.
- uint sum = 0;
- for (uint i = 0; i < checkBytes; i++)
- sum += buf[i];
-
- switch(sum) {
- case 0x1B2: // SCI0
- case 0x1AE: // SCI01
- _doSoundType = kDoSoundTypeSci0;
- break;
- case 0x13D:
- _doSoundType = kDoSoundTypeSci1Early;
- break;
- case 0x13E:
+ int sum = methodChecksum(soundClass, ((SciEngine *)g_engine)->getKernel()->_selectorMap.play, -6, 6);
+
+ switch(sum) {
+ case 0x1B2: // SCI0
+ case 0x1AE: // SCI01
+ _doSoundType = SCI_VERSION_0_EARLY;
+ break;
+ case 0x13D:
+ _doSoundType = SCI_VERSION_1_EARLY;
+ break;
+ case 0x13E:
#ifdef ENABLE_SCI32
- case 0x14B:
+ case 0x14B:
#endif
- _doSoundType = kDoSoundTypeSci1Late;
- }
- }
+ _doSoundType = SCI_VERSION_1_LATE;
}
}
- if (_doSoundType == kDoSoundTypeUnknown) {
+ if (_doSoundType == SCI_VERSION_AUTODETECT) {
warning("DoSound detection failed, taking an educated guess");
if (resourceManager->sciVersion() >= SCI_VERSION_1_MIDDLE)
- _doSoundType = kDoSoundTypeSci1Late;
+ _doSoundType = SCI_VERSION_1_LATE;
else if (resourceManager->sciVersion() > SCI_VERSION_01)
- _doSoundType = kDoSoundTypeSci1Early;
+ _doSoundType = SCI_VERSION_1_EARLY;
else
- _doSoundType = kDoSoundTypeSci0;
+ _doSoundType = SCI_VERSION_0_EARLY;
}
- debugCN(1, kDebugLevelSound, "Detected DoSound type: ");
-
- switch(_doSoundType) {
- case kDoSoundTypeSci0:
- debugC(1, kDebugLevelSound, "SCI0");
- break;
- case kDoSoundTypeSci1Early:
- debugC(1, kDebugLevelSound, "SCI1 Early");
- break;
- case kDoSoundTypeSci1Late:
- debugC(1, kDebugLevelSound, "SCI1 Late");
- break;
- default:
- break;
- }
+ debugC(1, kDebugLevelSound, "Detected DoSound type: %s", ((SciEngine *)g_engine)->getSciVersionDesc(_doSoundType).c_str());
}
return _doSoundType;
}
+SciVersion EngineState::detectSetCursorType() {
+ if (_setCursorType == SCI_VERSION_AUTODETECT) {
+ int sum = methodChecksum(game_obj, ((SciEngine *)g_engine)->getKernel()->_selectorMap.setCursor, 0, 21);
+
+ if ((sum == 0x4D5) || (sum == 0x552)) {
+ // Standard setCursor
+ _setCursorType = SCI_VERSION_0_EARLY;
+ } else if (sum != -1) {
+ // Assume that others use fancy cursors
+ _setCursorType = SCI_VERSION_1_1;
+ } else {
+ warning("SetCursor detection failed, taking an educated guess");
+
+ if (resourceManager->sciVersion() >= SCI_VERSION_1_1)
+ _setCursorType = SCI_VERSION_1_1;
+ else
+ _setCursorType = SCI_VERSION_0_EARLY;
+ }
+
+ debugC(0, kDebugLevelGraphics, "Detected SetCursor type: %s", ((SciEngine *)g_engine)->getSciVersionDesc(_setCursorType).c_str());
+ }
+
+ return _setCursorType;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 9fee7111a0..c822f88c41 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -164,13 +164,6 @@ public:
EngineState(ResourceManager *res, uint32 flags);
virtual ~EngineState();
- enum DoSoundType {
- kDoSoundTypeUnknown,
- kDoSoundTypeSci0,
- kDoSoundTypeSci1Early,
- kDoSoundTypeSci1Late
- };
-
virtual void saveLoadWithSerializer(Common::Serializer &ser);
kLanguage getLanguage();
@@ -283,7 +276,13 @@ public:
* Autodetects the DoSound type
* @return DoSound type
*/
- DoSoundType detectDoSoundType();
+ SciVersion detectDoSoundType();
+
+ /**
+ * Autodetects the SetCursor type
+ * @return SetCursor type
+ */
+ SciVersion detectSetCursorType();
/* Debugger data: */
Breakpoint *bp_list; /**< List of breakpoints */
@@ -315,8 +314,9 @@ public:
Common::String getLanguageString(const char *str, kLanguage lang) const;
private:
- DoSoundType _doSoundType;
+ SciVersion _doSoundType, _setCursorType;
kLanguage charToLanguage(const char c) const;
+ int methodChecksum(reg_t objAddress, Selector sel, int offset, uint size) const;
};
/**
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index a514b12370..f828de42e7 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -200,6 +200,8 @@ struct selector_map_t {
Selector printLang; /**< Used for i18n */
Selector subtitleLang;
Selector parseLang;
+
+ Selector setCursor; /** For autodetection */
};
// A reference to an object's variable.