diff options
author | Colin Snover | 2017-09-19 01:37:44 -0500 |
---|---|---|
committer | Colin Snover | 2017-09-19 19:54:30 -0500 |
commit | 6af5133061997093a4470931b84124ecf22ddd7a (patch) | |
tree | 7bbc49b3adfb2acc812c2a58340ab7db0dacb3bf /engines/sci | |
parent | 682b8790fd24449286a5a5dc8332c7c7570164b6 (diff) | |
download | scummvm-rg350-6af5133061997093a4470931b84124ecf22ddd7a.tar.gz scummvm-rg350-6af5133061997093a4470931b84124ecf22ddd7a.tar.bz2 scummvm-rg350-6af5133061997093a4470931b84124ecf22ddd7a.zip |
SCI32: Put superclass address in r_acc for SCI3 super calls
This fixes a problem in Lighthouse 2.0a where the mini-sub would
fail to start playing the animation of the shipwreck when clicking
on the throttle.
In SSCI, in SCI3 only, r_acc was (inadvertently?) set to the
superclass object ID whenever a super call was made. This happened
because OP_super would call to get the superclass object ID, the
calling conventions of the compiler put this return value into EAX,
and then the PMachine message processing code put whatever was in
EAX into r_acc before each message was processed.
In the game code, there are a sequence of steps that look like
this:
* First, throttle::doVerb is called when throttle is clicked on;
* Which calls getRobot::doit to tell the shipwreck robot to start
playing;
* Which calls wreckBot::init to reset the Robot for the animation;
* Which calls Hiliter::hotVerbs(0) to remove cursor hotspots;
* Which calls Hiliter::dispose to clean up since it is not used;
* Which causes Hiliter::verbList to get set to 0.
* Later, verbList is loaded into r_acc, and it is still 0;
* Then, Hiliter::dispose makes a super call to Obj::dispose;
* Then, Obj::dispose does nothing except call kDisposeClone,
which does not mutate r_acc, so r_acc is still 0 from verbList;
* Then we return back through 5 calls to throttle::doVerb;
* Then throttle::doVerb checks that r_acc is non-zero, and if so,
adds wreckBot to theDoits global, allowing the animation to
occur.
In ScummVM, without setting r_acc in the super call, the non-zero
check failed and the wreckBot didn't get put into theDoits, so the
entire sequence fell apart. In SSCI, the non-zero check happened
to succeed because the Obj::dispose super call put the Obj class
into the accumulator. So now we do that too, and now Lighthouse
2.0a works here.
Earlier versions of SSCI used EAX for other things in between the
OP_super call and the message processing, so would set r_acc from
different data, so this change does not apply to those versions.
Diffstat (limited to 'engines/sci')
-rw-r--r-- | engines/sci/engine/vm.cpp | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index b169e0ec11..785f92bf4a 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -1056,6 +1056,14 @@ void run_vm(EngineState *s) { if (!r_temp.isPointer()) error("[VM]: Invalid superclass in object"); else { + // SCI3 sets r_acc to whatever was in EAX at the start of a + // send. In the case of a super call this is the object ID of + // the superclass, as determined by the interpreter, rather than + // by the game scripts + if (getSciVersion() == SCI_VERSION_3) { + s->r_acc = r_temp; + } + s_temp = s->xs->sp; s->xs->sp -= ((opparams[1] >> 1) + s->r_rest); // Adjust stack |