[Scummvm-tracker] [ScummVM :: Bugs] #13354: MI1: Guybrush can hold his breath for longer than 10 minutes.

ScummVM :: Bugs trac at scummvm.org
Tue Mar 29 12:05:11 UTC 2022


#13354: MI1: Guybrush can hold his breath for longer than 10 minutes.
-------------------+------------------------------
Reporter:  ffyte   |       Owner:  eriktorbjorn
    Type:  defect  |      Status:  new
Priority:  normal  |   Component:  Engine: SCUMM
 Version:          |  Resolution:
Keywords:          |        Game:  Monkey Island 1
-------------------+------------------------------
Comment (by AndywinXp):

 Hiya! An update on my end: I've been researching SCUMM (v0-8) timers from
 scratch during the last two weeks, and I'm working towards making a PR
 which expands on the work done by eriktorbjorn.

 Whenever I mention a ''divisor'' in the following notes, I'm talking about
 the divisor for this operation:
 **1193182Hz / divisor**,
 which yields the target frequency of the Programmable Interrupt Timer
 (PIT) in Hz.

 Right now I have taken these notes from my own disasms:
 - MANIAC **v0** sets the PIT only when playing sound, and when it's not
 doing that the divisor is defaulted to 0, which means 65536; this would
 yield a game frequency of about 18.21Hz, which is very slow, but the
 reality is that ''SCUMM works with quarter frames'' and ''the game
 processes three game frames for each engine frame'', so we have to
 multiply 18.21 by 4 * 3, finally obtaining about 218.48Hz which matches
 the original speed (this was compared on DosBox);
 - **v1-4** games all appear to run on PIT in which the divisor is 0x13B1
 (5041); this is true also for the shake effects, but be aware that the
 game timer and the shake timer ''are different entities'' and are not
 interchangeable (unlike UrQuan did on his implementation); I was able to
 match DosBox time very accurately when drowning Guybrush in MI1 EGA and
 VGA.
 - Starting from **v5**, the interpreters set up some kind of timer
 orchestrator which handles several "sub-timers"; the base timer seems to
 be the iMUSE timer (divisor: 0x1000 or 4096 in decimal, yielding about
 291.3042 Hz) ''which is used as the shake timer as well''. The game timer
 was a bit tricky to obtain, here's the algorithm for reference:

 ----

 1) Launch the timer orchestrator at a rate of **1193182.0 / 4096 ==
 291.3042Hz**, whose interrupt will call a function which we'll call
 advanceGameTimers() for convenience.
 2) At each run of advanceGameTimers() a global counter will be increased
 by 3433;
 3) If the global counter is lower than 4166 (or in some games 4167... I
 have to recheck my disasms) goto 4a, else goto 4b;

 4a) Exit the interrupt function.
 4b) We've reached the moment in which we have to mark the quarter frame
 tick: decrement the global counter by 4166 (or, again, 4167) and increment
 the SCUMM quarter frame tick count.

 ----

 * Given what happens above, I found the frequency to be calculated like
 this: **(1193182.0 / 4096) * (3433 / 4166) == 240.049Hz**; testing the
 drowning scene in MI1 CD yields accurate-to-frame timings with respect to
 DosBox. ''Remember, the shake time is regulated only by the 4096 iMUSE
 divisor set in the IMS driver'';

 - **v6** games appear to do the same thing, only with 4167 in place of
 4166 (at least this is what the Sam&Max disasm tells me). I still have to
 do some heavy testing to see if this is accurate. I recall, for some
 reason, DOTT and S&M to be slower than the other games (about 236Hz) but I
 have no evidence for this right now;
 - **v7** games do something similar, again, but set up a base timer with a
 divisor equal to 3977, and the subtimer has a count of 4971, which means:
 **1193182.0 / 3977 * 3977 / 4971 = 240.029Hz**. I haven't checked the
 shake timer for this version yet but I suppose they are using the
 1193182.0 / 3977 == 300Hz base frequency. Also, both DIG and FT do
 something strange in the SCUMM main loop when fetching the whole frame
 timer counter... anybody know what the heck is this? It seems to decrement
 something out of the quarter ticks counter every time it wraps around the
 negative numbers...


 {{{
 VARS(VAR_TIMER) = (qTicks - (__CFSHL__(qTicks >> 32, 2) + 4 * (qTicks >>
 32))) >> 2;
 }}}


 - **v8** appears to run perfectly as-is :-) COMI is a Windows game after
 all, and it just uses the Win95 equivalent of the timer routines we
 already use (targeting a base rate of 60Hz, or 240Hz when thinking quarter
 frames).
-- 
Ticket URL: <https://bugs.scummvm.org/ticket/13354#comment:7>
ScummVM :: Bugs <https://bugs.scummvm.org>
ScummVM


More information about the Scummvm-tracker mailing list