aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Snover2017-09-19 01:37:44 -0500
committerColin Snover2017-09-19 19:54:30 -0500
commit6af5133061997093a4470931b84124ecf22ddd7a (patch)
tree7bbc49b3adfb2acc812c2a58340ab7db0dacb3bf
parent682b8790fd24449286a5a5dc8332c7c7570164b6 (diff)
downloadscummvm-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.
-rw-r--r--engines/sci/engine/vm.cpp8
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