SCI: Add SetCursor detection. Cleanup.
svn-id: r43812
This commit is contained in:
parent
fff023794f
commit
cf5483c3d8
6 changed files with 137 additions and 134 deletions
|
@ -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();
|
||||
|
||||
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())));
|
||||
}
|
||||
break;
|
||||
case 4 :
|
||||
GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state,
|
||||
argv[0].toUint16() == 0 ? GFXOP_NO_POINTER : 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 > 2) {
|
||||
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:
|
||||
CursorMan.showMouse(argv[0].toSint16() != 0);
|
||||
break;
|
||||
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));
|
||||
}
|
||||
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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
reg_t soundClass;
|
||||
const uint checkBytes = 6; // Number of bytes to check
|
||||
|
||||
if (!parse_reg_t(this, "?Sound", &soundClass)) {
|
||||
int EngineState::methodChecksum(reg_t objAddress, Selector sel, int offset, uint size) const {
|
||||
reg_t fptr;
|
||||
|
||||
Object *obj = obj_get(segmentManager, soundClass);
|
||||
SelectorType sel = lookup_selector(this->segmentManager, soundClass, ((SciEngine*)g_engine)->getKernel()->_selectorMap.play, NULL, &fptr);
|
||||
Object *obj = obj_get(segmentManager, objAddress);
|
||||
SelectorType selType = lookup_selector(this->segmentManager, objAddress, sel, NULL, &fptr);
|
||||
|
||||
if (!obj || (selType != kSelectorMethod))
|
||||
return -1;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
// 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++)
|
||||
for (uint i = 0; i < size; i++)
|
||||
sum += buf[i];
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
SciVersion EngineState::detectDoSoundType() {
|
||||
if (_doSoundType == SCI_VERSION_AUTODETECT) {
|
||||
reg_t soundClass;
|
||||
|
||||
if (!parse_reg_t(this, "?Sound", &soundClass)) {
|
||||
int sum = methodChecksum(soundClass, ((SciEngine *)g_engine)->getKernel()->_selectorMap.play, -6, 6);
|
||||
|
||||
switch(sum) {
|
||||
case 0x1B2: // SCI0
|
||||
case 0x1AE: // SCI01
|
||||
_doSoundType = kDoSoundTypeSci0;
|
||||
_doSoundType = SCI_VERSION_0_EARLY;
|
||||
break;
|
||||
case 0x13D:
|
||||
_doSoundType = kDoSoundTypeSci1Early;
|
||||
_doSoundType = SCI_VERSION_1_EARLY;
|
||||
break;
|
||||
case 0x13E:
|
||||
#ifdef ENABLE_SCI32
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue