Posts for Sand


1 2
5 6 7
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
feos wrote:
Where can I read that manual?
I'm not familiar with the game, but looks like there is a copy here: https://archive.org/download/msdos_Bio_Menace_1993/Bio_Menace_1993.zip/BioMenac%2FBM-HELP.TXT
                              ===================
                              SECRET BATTLE MOVES
                              ===================

■  There are four secret moves which give Snake valuable added weapons to
   help balance the scales against his evil foes!   They are:

   ■ SUPER PLASMA BOLT

     Hold the up arrow, (or up on the joystick), until you hear an electrical
     charge sound.  Once you hear this sound, press the fire button and a
     plasma beam will shoot in the direction you are facing burning through a
     whole line of enemies!  Beware, this is a powerful weapon and the toxic
     fume cloud it leaves behind inflicts one point of damage on Snake!  Use
     this weapon wisely!

   ■ FIRE BALL ATTACK

     Turn left to right, back and forth in succession about five or six turns
     rapidly and press the fire button.  Snake uses his secret energy pack to
     disperse six flaming fire balls, three in each direction, to toast those
     hard to get at enemies.

   ■ ELECTRON SHIELD

     Protects Snake and zaps any enemies daring to touch him for a limited
     amount of time.

   ■ INVINCIBILITY BURST

     Gives you a short burst of invincibility without having to find an
     invincibility potion.

We've left the Electron Shield and the Invincibility burst there for you to
experiment with, and find on your own.  We don't want to give EVERYTHING away,
now do we?  :)


                               =================
                               SECRET CHEAT KEYS
                               =================

There is an option cheat mode built into Bio Menace.  If you press these three
keys simultaneously, you will get the normal machine gun with 90 rounds of
ammunition, and 99 regular grenades.   The keys are [C] [A] [T].  This
combination can be used as many times as you wish, and only works on the
commercial version of the software.
Post subject: YouTube video showing possible memory corruption glitch
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
I found a video from 2007 that shows what looks like a memory corruption glitch caused by jumping out of bounds at the beginning of the space level. Maybe there are ACE possibilities. Link to video
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Up+Down and Left+Right presses are cancelled out. This makes building bytes that end on x3,x7,xB,xC,xD,xE, or xF impossible, limiting our choice of opcodes.
This is so great :)
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
I use the archive.org MKV download, because it says "modern." Otherwise I don't know what's different between the MKV and MP4 and probably couldn't distinguish them. Prefer not to use YouTube because we all need a little less Google in our lives. NoScript is set to disable JavaScript for non-https sites, so I usually don't even see the buttons shown in Post #481181 and forget that that option exists.
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Something I learned while doing the Mega Man DOS TAS: that game is not really CPU-limited. It is refresh-limited in the sense that once the CPU is fast enough to run the game at 70.09 fps, a faster CPU won't make the game run any faster. You can check this in DOSBox by pressing Ctrl+F12 to increase the cycles: above a certain threshold, Mega Man's blink rate doesn't increase. A faster CPU wouldn't shorten the TAS (except for load times, those would be shorter). You can look at it this way: the game is limited by both CPU and screen refresh. It seems to have been written with the assumption that the CPU would be the bottleneck; i.e., the game relies on there being constant lag to run at a playable speed. I tried increasing the CPU divider up to the maximum of 256, but it wasn't enough to cause lag. Gameplay ran at an identical rate, with the only difference being longer load times. I also considered using the in-game speed controls. Pressing F2 inserts busy-waits into the main game loop, in effect creating its own lag. This does slow down the game without distorting the sound effects. You can only slow the game down by discrete multiples of 1/2, 1/3, 1/4, etc., because of the nature of lag. I decided against using the in-game controls because it would have been annoying to TAS when 1 frame ≠ 1 gameplay loop, and would have been harder to compare to the previous TAS. A rule change (in any direction) wouldn't affect the speed of the Mega Man TAS other than load times, unless the CPU were made slower than JPC-RR currently supports. Maybe this is a minority case. I would guess that most games are properly refresh-limited at a reasonable speed, or else are not tied to refresh at all and therefore a faster CPU always makes the game faster.
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
DarkKobold wrote:
Awesome work, good to see one of my runs get slaughtered.
Thanks :) Your run was one of the first things I looked up when I started to get into this game.
DarkKobold wrote:
Are you going to attempt Mega Man 3 PC? It definitely needs a TAS as well.
No, I don't think so. I looked a little bit at the code and it seems to be a rather different game (different engine and file compression), so I don't know if much of my knowledge would transfer. Which, by the way, I'm hoping to make a GameResources page to present what are now just fragmentary notes in my source code. Stuff like memory addresses, the RNG, and enemy AI.
Post subject: Re: #6192: David Fifield's DOS Mega Man in 01:46.94
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Ferret Warlord wrote:
TASVideoAgent wrote:
If we had another E Tank, we would use it at one of these pits for another major skip. But we have only one E Tank, and it saves more time in Volt Man's stage than it would in this stage. We could farm a second E Tank in Sonic Man's stage (the only other E Tank in the game is in the middle of Volt Man's stage), but it would take more time to do that than it would save here (I think).
How easy is it to exit a completed level? Does the E tank reappear on death?
You can't re-enter a completed stage. The E Tank doesn't respawn on every death, but only on a continue (when you run out of lives and it forces you to start from the beginning of the stage or choose another stage). You have to die 3 times to make the E Tank respawn. Dying is pretty fast because you can suicide with Esc+F10. The death animation lasts about 65 frames, and it takes about 300 frames to reach the E Tank. So while the first E Tank is nearly free, each additional E Tank costs 3×65 + 300 = 495 frames. The skip in Dyna Man's stage would save a max of about 415 frames (probably less because you have to wait for a bee to damage you). It's close, but not quite worth it. I reached these figures by reading frame numbers off of my run.
  • start Sonic: 703
  • collect E Tank: 1001
  • above Dyna pit: 3870
  • below Dyna pit: 4285
There's another potential avenue to explore. Lizstar, who will be running the game at AGDQ next week, had a run where, in the corridor before the Volt Man refight, there was apparently no collision with enemies. The Force Field would normally kill the Met and the Spydroborgs, but she just walks right through them. https://www.twitch.tv/videos/351849325?t=01h40m58s I vaguely the same thing happening to me, but at the time I dismissed it as a bug in the enemy AI in this corridor. (Similar to how, in the Volt Man refight, contact with the shield staggers you but does 0 damage.) But it only happens sometimes, and I haven't been able to reproduce it. (Since it happens right after the Sonic Man refight, I wonder if it has something to do with the camera desync glitch that DarkKobold noted.) Anyway, if the glitch has something to do with collision, there's a chance that it could avoid collision-based death.
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
feos wrote:
Nice! Are you planning to do some further tests and checks before we actually publish this?
No, unless I get some sudden inspiration, I'm not planning to do any more tests.
Post subject: Re: Loading fdconfig.sys saves 55 frames
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Sand wrote:
I ran some tests at Post #479329 with the surprising outcome that loading fdconfig.sys and saying N to every line is faster than skipping fdconfig.sys with F5, and even faster than loading fdconfig.sys and saying Y to every line. I don't know why it is so. I only tested the title screen, but:
  • Skip fdconfig.sys with F5: 129 frames
  • Run fdconfig.sys, say Y: 122 frames
  • Run fdconfig.sys, say N: 120 frames
I reworked the whole run with this change, and it saves an additional 25 frames total.
Post subject: Sixth-draft TAS (saves 25 frames)
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Sand wrote:
At Post #478684 we wondered why loading fdconfig.sys shortens load times. I did some experiments, and here's something weird: running fdconfig.sys saves time even if you say N to every line in it. In fact, saying N to every line starts the game 2 frames faster than saying Y to every line.
I reworked the TAS with this change (loading fdconfig.sys but declining all the prompts). It saves 25 frames overall. As in the previous draft, there are no gameplay differences, only shorter load times. Download link. Link to video
#2247first draftdiffsecond draftdiffthird draftdifffourth draftdifffifth draftdiffsixth draftdiff
boot9159−3259059059064+5640
configuration menu32−12020202020
title screen127129+2129012901290122−7120−2
intro stage386382−4376−637603760375−13750
stage select SVD146154+81540153−11530145−8142−3
Sonic Man stage20401928−1121902−261901−1190101901019010
Sonic Man111102−9100−21000100010001000
stage select _VD352367+15368+1367−13670351−16344−7
Volt Man stage2125186−193918601860186018601860
Volt Man109100−998−2980980980980
stage select __D305314+93140313−13130301−12295−6
Dyna Man stage19881783−2051768−151767−1176701767017670
Dyna Man7757−2052−5520520520520
Wily title cards363374+113740373−13730357−16351−6
Wily stage17341686−481666−201667+11662−5166201661−1
Wily10440−6438−2380380380380
total100617663−23987586−777581−57676−57521−557496−25
Post subject: Re: Loading fdconfig.sys saves 55 frames
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Sand wrote:
I'm not able to do any tests just now, but after a few days I can try running lines of fdconfig.sys in isolation and see if there is a single one that affects load times.
I ran some tests at Post #479329 with the surprising outcome that loading fdconfig.sys and saying N to every line is faster than skipping fdconfig.sys with F5, and even faster than loading fdconfig.sys and saying Y to every line. I don't know why it is so. I only tested the title screen, but:
  • Skip fdconfig.sys with F5: 129 frames
  • Run fdconfig.sys, say Y: 122 frames
  • Run fdconfig.sys, say N: 120 frames
Post subject: fdconfig.sys options
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
At Post #478684 we wondered why loading fdconfig.sys shortens load times. I did some experiments, and here's something weird: running fdconfig.sys saves time even if you say N to every line in it. In fact, saying N to every line starts the game 2 frames faster than saying Y to every line. For reference, here are the 6 fdconfig.sys prompts:
dos=high[Y,n]?
lastdrive=z[Y,n]?
buffers=20[Y,n]?
files=40[Y,n]?
device=himem.exe[Y,n]?
shell=cmd80x86.com command.com /K autoexec.bat[Y,n]?
Here are the tests I ran. I tried enabling every line but the autoexec.bat one. Each test took either 120 or 122 frames to show the title screen and start the game—if you skip fdconfig.sys, it takes 129 frames. The latest draft says Y to all and is slow at 122 frames. I've marked the slow rows with *.
dos=highlastdrive=zbuffers=20files=40device=himemshellfinish config menutitle screen visiblegame starts
YYYYYn66144188*
nnnnnn66143186
Ynnnnn66143186
nYnnnn66143186
nnYnnn66143186
nnnYnn66143186
nnnnYn66143186
YYYYnn66143186
nYYYYn66143186
YnnnYn66144188*
Saying N to every line is fast. Saying Y to each line individually is fast. I didn't try all 32 possibilities, but it looks like you get the slow behavior when you say Y to both dos=high and device=himem.exe. As for why loading fdconfig.sys and then not running any of it saves time, I have no idea. I looked inside fdconfig.sys and it doesn't contain any hidden commands other than what it prompts for. i only tested through the title screen—perhaps other differences would manifest later on.
Post subject: Re: Loading fdconfig.sys saves 55 frames
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
DrD2k9 wrote:
FractalFusion wrote:
By the way, do you know why running fdconfig.sys saves 55 frames? Is it something that can be applied to other DOS games?
I don't know the exact reason, but fdconfig.sys contains a number of lines that mostly deal with memory usage. It's likely that processing fdconfig.sys allows the PC to use memory more efficiently thus minimizing the loading times later on in the run. Another possibility is the FILES=40 line. This allows DOS to utilize 40 files at once. I don't know how many it would be able to use without this line. (I have read that 30 is actually a more efficient number than 40 for this line).
Yes, I am not sure, but I suspect it is for one of those reasons: high memory, FILES, or possibly BUFFERS. I know that the memory addresses changed, because I had to update my scripts. This page says BUFFERS controls "the number of disk buffers that will be available for use during data input," which sounds like it could affect disk load times. The boot prompts, for each line of fdconfig.sys, whether you want to run it. I copied the choice of lines from [2247] DOS Mega Man by DarkKobold in 02:23.55 and didn't experiment with alternative selections. It was to say Y to every line, except don't run autoexec.bat.
dos=high[Y,n]?Y
lastdrive=z[Y,n]?Y
buffers=20[Y,n]?Y
files=40[Y,n]?Y
device=himem.exe[Y,n]?Y
shell=cmd80x86.com command.com /K autoexec.bat[Y,n]?N
A:\>\autoexec.bat [Yes=ENTER, No=ESC] ? n
I'm not able to do any tests just now, but after a few days I can try running lines of fdconfig.sys in isolation and see if there is a single one that affects load times. The game doesn't open very many files at once. I would guess that it has a maximum of 1 or 2 open file handles at a time. While loading a stage, it opens 4 files (.bin, .frm, .scn, .blk), but it closes one before opening the next; unless, of course there is a file handle leak I didn't notice, or some other detail I misunderstood.
Post subject: Loading fdconfig.sys saves 55 frames
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Sand wrote:
This run puts the game files on hard disk HDD rather than HDA (saves 27 frames) and skips fdconfig.sys and autoexec.bat (saves 5 frames), as recommended by the JPC-RR documentation.
Sand wrote:
You'll notice in the table of splits that the time between stages—title screen, stage select, and Wily intro—are a few frames slower compared to [2247] DOS Mega Man by DarkKobold in 02:23.55. I investigated but was not able to figure out why. Initially I thought it was because I put the game files on HDD rather than HDA, but I also tried putting the files on HDA and it only made the boot slower, without speeding up the between-stages times.
I finally figured out why my load times were longer than in [2247] DOS Mega Man by DarkKobold in 02:23.55. It's because DarkKobold ran fdconfig.sys during boot and I did not. Running fdconfig.sys costs 5 frames, but for whatever reason it saves 60 frames in load times later in the run. An updated encode (along with input files etc.) is here: https://archive.org/details/megamanpc-tas-1_47_298 The gameplay is the same as in the initial submission; the only difference is fdconfig.sys and shorter load times. Is there a way to replace the submission with this update? FractalFusion, just for you I made a 30 fps encode. That one should be roughly comparable in framerate with the slow encode of [2247] DOS Mega Man by DarkKobold in 02:23.55. Only the slowest encode has captions. The updated table of splits:
#2247thisdiff
boot9164−27
configuration menu32−1
title screen127122−5
intro stage386375−11
stage select SVD146145−1
Sonic Man stage20401901−139
Sonic Man111100−11
stage select _VD352351−1
Volt Man stage2125186−1939
Volt Man10998−11
stage select __D305301−4
Dyna Man stage19881767−221
Dyna Man7752−25
Wily title cards363357−6
Wily stage17341662−72
Wily10438−66
total100617521−2540
Post subject: Fifth-draft TAS (55 frames saved)
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Sand wrote:
Sand wrote:
Known deficiencies and potential improvements:
  • The intervals between the stages (when the game is loading resources from disk) are slightly slower than in [2247] DOS Mega Man by DarkKobold in 02:23.55. My best guess is that this has something to do with putting C: on HDD rather than HDA. If so, then it would be better to go back to HDA: the time saved between stages would more than make up for a slightly slower boot.
I investigated this issue, and changing C: from HDD to HDA doesn't help. It makes the boot 27 frames slower, and later on, through parts of the game that access the disk, that 27-frame deficit remains unchanged, rather than diminishing as I had hoped. So I don't know what accounts for the difference in time: maybe DarkKobold's disk image arranges the files differently than mine does; or maybe it is a JPC-RR version difference (though I've tested that mine syncs on 11.6 and 11.2).
I figured out the cause of the increased load times. DarkKobold ran fdconfig.sys during boot and I didn't. That is, at the prompt:
Press F8 to trace or F5 to skip FDCONFIG.SYS/AUTOEXEC.BAT
I pressed F5 to skip, but DarkKobold pressed F8 and then:
dos=high[Y,n]?Y
lastdrive=z[Y,n]?Y
buffers=20[Y,n]?Y
files=40[Y,n]?Y
device=himem.exe[Y,n]?Y
shell=cmd80x86.com command.com /K autoexec.bat[Y,n]?N
A:\>\autoexec.bat [Yes=ENTER, No=ESC] ? n
It takes 5 frames to run fdconfig.sys, but it pays off in faster load times. In fact, it's already caught up by the time the title screen loads. So here is a fifth draft. The only difference is shorter load times. The gameplay is the same. It changes all the memory addresses so I had to update my scripts. Download link. Link to video
#2247first draftdiffsecond draftdiffthird draftdifffourth draftdifffifth draftdiff
boot9159−3259059059064+5
configuration menu32−120202020
title screen127129+2129012901290122−7
intro stage386382−4376−637603760375−1
stage select SVD146154+81540153−11530145−8
Sonic Man stage20401928−1121902−261901−11901019010
Sonic Man111102−9100−2100010001000
stage select _VD352367+15368+1367−13670351−16
Volt Man stage2125186−19391860186018601860
Volt Man109100−998−2980980980
stage select __D305314+93140313−13130301−12
Dyna Man stage19881783−2051768−151767−11767017670
Dyna Man7757−2052−5520520520
Wily title cards363374+113740373−13730357−16
Wily stage17341686−481666−201667+11662−516620
Wily10440−6438−2380380380
total100617663−23987586−777581−57676−57521−55
Comparing [2247] DOS Mega Man by DarkKobold in 02:23.55 and this most recent draft directly, for the first time, the new one is faster in every segment:
#2247fifth draftdiff
boot9164−27
configuration menu32−1
title screen127122−5
intro stage386375−11
stage select SVD146145−1
Sonic Man stage20401901−139
Sonic Man111100−11
stage select _VD352351−1
Volt Man stage2125186−1939
Volt Man10998−11
stage select __D305301−4
Dyna Man stage19881767−221
Dyna Man7752−25
Wily title cards363357−6
Wily stage17341662−72
Wily10438−66
total100617521−2540
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
FractalFusion wrote:
I find that the normal encode is too fast and the slowed encode too slow. Is there one at a speed that is intermediate to the two?
There's a speed control on the video player. At 2x it is about 28 fps. For reference, the slow encode is 14 fps and the full-speed encode is 70 fps. For a proper encode, you would have to run the soundhack.py script with a different multiplier, import a new disk image, make a new dump, and pass an altered framerate to ffmpeg.
Post subject: Fourth-draft TAS (5 frames saved)
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Sand wrote:
  • Against Dyna Man, use the Mega Buster until close enough to use the Force Field. The Buster does 2 HP of damage and the Force Field does 6, but you can't use the Force Field until you are close. The boss has 32 HP, so shooting him 4 times with the Buster saves 2 uses of the Force Field (2 frames). Using the Buster only matters in the first Dyna Man fight, because the only goal is to kill the boss as quickly as possible. In the refight, the goal is to kill the boss and cross the screen, so the Buster doesn't give an advantage because you are limited by Mega Man's running speed anyway.
While I was writing up a submission, I realized I was mistaken in my assumption that using the Buster doesn't help in the Dyna Man refight. Here is a revision that saves 5 frames in the fight. Click through to enable captions. Link to video Three things go into this improvement:
  • RNG manipulation to get a low, fast jump from Dyna Man (just like in the first fight). It's complicated because we also need to manipulate the Volt Man fight, and there is not much flexibility in altering the RNG sequence (the only way to do it is by killing/not killing enemies, and there are not many in this area). I had to settle for a Dyna Man jump speed of 6, rather than his maximum of 7. Sadly, the RNG manipulation loses 2 1-up drops.
  • Shooting with the Mega Buster before getting close.
  • Controlling the phase of the Force Field (the size of its hitbox varies with phase).
#2247first draftdiffsecond draftdiffthird draftdifffourth draftdiff
boot9159−32590590590
configuration menu32−1202020
title screen127129+2129012901290
intro stage386382−4376−637603760
stage select SVD146154+81540153−11530
Sonic Man stage20401928−1121902−261901−119010
Sonic Man111102−9100−210001000
stage select _VD352367+15368+1367−13670
Volt Man stage2125186−1939186018601860
Volt Man109100−998−2980980
stage select __D305314+93140313−13130
Dyna Man stage19881783−2051768−151767−117670
Dyna Man7757−2052−5520520
Wily title cards363374+113740373−13730
Wily stage17341686−481666−201667+11662−5
Wily10440−6438−2380380
Here's an explanation of why my reasoning was wrong. Normalize time so that 1 is the time it takes for Mega Man to run across the screen. Let ε represent the time of one frame. The total time required by one of the boss refights can be expressed as T = M + abs(x − 0.5) + ε isaligned(x) + (1 − x) + C where M is the minimum time required to kill the boss and x is Mega Man's horizontal position when the boss dies (also normalized to lie between 0 and 1). abs(x − 0.5) represents the horizontal camera centering delay (longer the farther Mega Man is from the center of the screen), ε isaligned(x) represents the additional 1-frame camera recentering penalty if your horizontal position is not a multiple of 8 pixels, (1 − x) is the time needed to run to the exit door, and C is any other fixed costs such as the vertical camera recentering delay. If we take M, the time required to kill the boss, to be a fixed constant, as it is in the Sonic Man and Volt Man refights, then we find that the x's cancel, meaning that Mega Man's position doesn't matter, as long as he is on the far side of the screen (the side nearest the exit door) and has good alignment:
  • if x < 0.5 (Mega Man is on the near side of the screen): T = M + ε isaligned(x) + C + 1.5 − 2x
  • if x ≥ 0.5 (Mega Man is on the far side of the screen): T = M + ε isaligned(x) + C + 0.5
But, in the Dyna Man fight, we should not take M to be a constant. It's possible to kill Dyna Man without stopping running, so we should take M = x; i.e., the time taken to kill the boss is equal to the time it takes to run to the position we're at when the boss dies. In this case, the x's do not cancel. Instead we have:
  • if x < 0.5 (Mega Man is on the near side of the screen): T = ε isaligned(x) + C + 1.0 + (0.5 − x)
  • if x ≥ 0.5 (Mega Man is on the far side of the screen): T = ε isaligned(x) + C + 1.0 + (x − 0.5)
In both cases, the time is less, the closer Mega Man is to the center of the screen; the screen recentering delay is the only consideration. This is why the Dyna Man refight is different than the other two, why Mega Man's horizontal position at the end of the fight matters. This doesn't mean that you should stop running only to end the fight in the center of the screen; but it means that if you can finish the fight without stopping running, then the closer to the center of the screen you can finish the fight, the better.
Post subject: Re: TAS in 1:49.35
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Sand wrote:
Known deficiencies and potential improvements:
  • The intervals between the stages (when the game is loading resources from disk) are slightly slower than in [2247] DOS Mega Man by DarkKobold in 02:23.55. My best guess is that this has something to do with putting C: on HDD rather than HDA. If so, then it would be better to go back to HDA: the time saved between stages would more than make up for a slightly slower boot.
I investigated this issue, and changing C: from HDD to HDA doesn't help. It makes the boot 27 frames slower, and later on, through parts of the game that access the disk, that 27-frame deficit remains unchanged, rather than diminishing as I had hoped. So I don't know what accounts for the difference in time: maybe DarkKobold's disk image arranges the files differently than mine does; or maybe it is a JPC-RR version difference (though I've tested that mine syncs on 11.6 and 11.2). I only tested it through the end of Sonic Man's stage; I decided to not go any further because there had already been several disk accesses (logo.sta, secur.scn, secur.blk, secur.frm, select.frm, sonic.scn, sonic.blk). The frame numbers in this table are absolute, not relative; i.e., the diff is not cumulative.
HDDHDAdiff
boot000
configuration menu6188+27
title screen visible144171+27
begin SECUR190217+27
stage select SVD616643+27
begin SONIC719746+27
Sonic Man health26202647+27
Sonic Man dead27202747+27
Sonic Man weapon screen29082935+27
Sonic Man weapon screen29582985+27
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Dacicus wrote:
Why did you pause at approximately 5:00? Was it related to the vertical camera recentering delays? Or RNG manipulation?
That's to wait for the disappearing blocks. I tried, but wasn't able to hit an earlier cycle. The blocks' cycle starts when you hit the checkpoint on top of the most recent conveyor belt, so it's hard to see getting there any faster. You must either wait at the beginning or wait while on the disappearing blocks, and I preferred to wait at the beginning and show off jumping from a block on the frame after it has disappeared. Even though I wait until the last possible frame before starting the crossing, I still have to wait for about 20 frames before the second-to-last jump for the final block to appear. There's not much to do in the space between the checkpoint and the disappearing blocks. I tried jumping across the pit, then back, then across again, but there's not quite enough time for that. Mega Man accelerates in units of 2 pixels, so if you start on an even pixel you stay even, and if you start odd you stay odd, unless you meet some external influence like running into a wall. I tried using the downtime to change my odd alignment to even alignment, and that actually puts you 1 pixel ahead after passing the disappearing blocks—but that becomes 1 pixel behind after the next turnaround, and in any case the difference of 1 pixel is wiped out when you clamp onto the long ladder near the end of the stage. I tried it both ways. The RNG does advance once per frame, but I was lucky enough not to have to use waiting for RNG manipulation anywhere. All the manipulation I needed could be done by killing enemies without slowing down. (Killing an enemy advances the RNG by one step, to determine what item will drop.)
Post subject: Third-draft TAS (5 frames saved)
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
The third draft of the Mega Man TAS. This one applies the sub-frame input technique mentioned in Post #477849 to save 5 frames overall. The total time is 1:48:154 or 7581 frames. Now I'm out of ideas, so I'm planning to submit this one. This is the slowed-down "soundhack" encode. Click through and enable captions! The full-speed version, input files, scripts, etc. are also available through the link. Link to video The sub-frame input technique can save up to 1 frame during stage select or at the beginning of stages. Relative to the second draft, it saves 1 frame in each of these places:
  • stage select before Sonic Man's stage
  • beginning of Sonic Man's stage
  • stage select before Volt Man's stage
  • stage select before Dyna Man's stage
  • beginning of Dyna Man's stage
The same technique gives you control over Mega Man 1 frame sooner at the beginning of Volt Man's stage, too—but it doesn't save time because you must wait to be hit by the spark anyway. I had already used the technique at the beginning of Wily's stage in the second draft, so it doesn't save additional time here. (The Wily title cards finished one frame faster, so it was a wash.) Sonic Man's stage is more sensitive to RNG than any of the others, so starting the stage a frame earlier required reworking most of it. I still manage to get three 1-ups, but they are in different places. The other stages are pretty much copy-paste jobs from the second draft, with only minor changes. The extra frame enabled me to get an additional two 1-ups in Dyna Man's stage, and I threw in a quick demonstration of the zero-gravity tiles at the end of Wily's stage.
#2247first draftdiffsecond draftdiffthird draftdiff
boot9159−32590590
configuration menu32−12020
title screen127129+212901290
intro stage386382−4376−63760
stage select SVD146154+81540153−1
Sonic Man stage20401928−1121902−261901−1
Sonic Man111102−9100−21000
stage select _VD352367+15368+1367−1
Volt Man stage2125186−193918601860
Volt Man109100−998−2980
stage select __D305314+93140313−1
Dyna Man stage19881783−2051768−151767−1
Dyna Man7757−2052−5520
Wily title cards363374+113740373−1
Wily stage17341686−481666−201667+1
Wily10440−6438−2380
total100617663−23987586−777581−5
Post subject: Second-draft TAS (77 frames saved)
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
This is the second draft of my Mega Man TAS. Its time is 1:48.226 or 7586 frames, 77 frames faster than the first draft. I was planning to submit this version, but at the last minute I discovered a technique that can let you start moving 1 frame earlier at the beginning of some stages. I'm planning to rework the TAS to include the improvement; in the meantime consider this a WIP. This is the slowed-down "soundhack" encode. For the full-speed version, input files, scripts, etc., see https://archive.org/details/megamanpc-tas-1_48_226. Link to video My main motivation for doing a second draft was to machine-optimize certain tricky or tedious movements, such as jumps around corners, using a Lua script (more on this below). In addition, I found a few other minor time saves:
  • Kill the dog head-on in the intro stage. This requires you to pause for 1 frame in order to avoid colliding with the dog, but that's faster than having to turn around. The dog is unlike most (all?) other enemies in that it can only take damage once per frame, which means you have to space out your shots so that they land on different frames, which leaves less time to shoot all 8 necessary shots before the dog hits you.
  • Avoid vertical camera recentering delays caused by jumping from a lower to a higher platform. When Mega Man lands on a higher platform, he becomes frozen in place for a few frames while the camera scrolls vertically to recenter on him. (There are a few special cases in the underwater section of Sonic Man's stage where you can avoid the vertical recentering, but only if you touch the higher platform for just 1 frame.) The recentering delay doesn't occur when jumping from high to low or to an equal height. This means that if a sequence of platforms goes high–low–high, it's better to jump over the middle platform, rather than down and back up, even if you never stop running. You can see the benefit by comparing the lava section of Dyna Man's stage in this draft and the first draft.
  • Avoid horizontal camera recentering delays when exiting boss arenas. After each of the boss refights in the Wily stage, there is a delay while the camera recenters on Mega Man. The camera moves at 8 pixels per frame, which is equal to Mega Man's running speed. Therefore, contrary to intuition, there's no advantage to being closer to the exit door when the boss dies (as long as you are on the same half of the screen)—you have a shorter distance to run but the camera has a longer distance to scroll, and they cancel out. The exception to this is the camera's first frame of movement: if Mega Man's x position is not a multiple of 8, the camera's first movement will be less than 8, in order to align itself with Mega Man's position—costing 1 additional frame. You can avoid the extra frame by shuffling your feet to get the proper alignment before the camera starts moving. The best position to be in, after killing the boss, is aligned to a multiple of 8 pixels, moving towards the exit door at maximum speed—the specific x coordinate doesn't matter, as long as you are aligned and on the correct half of the screen. This technique only applies to the refights; the camera doesn't move after beating the bosses the first time.
  • In the room with wall blasters in Sonic Man's stage, shoot the wall blaster and allow its explosion to damage you. This is slightly faster than waiting for the wall blaster to shoot a bullet at you.
  • Against Dyna Man, use the Mega Buster until close enough to use the Force Field. The Buster does 2 HP of damage and the Force Field does 6, but you can't use the Force Field until you are close. The boss has 32 HP, so shooting him 4 times with the Buster saves 2 uses of the Force Field (2 frames). Using the Buster only matters in the first Dyna Man fight, because the only goal is to kill the boss as quickly as possible. In the refight, the goal is to kill the boss and cross the screen, so the Buster doesn't give an advantage because you are limited by Mega Man's running speed anyway.
  • Use the Nuclear Detonator in the Sonic Man refight. The Nuclear Detonator is a slow, awkward weapon: it doesn't shoot very far and there is a delay of 16 frames before you can detonate it. It is Sonic Man's weakness, doing 16 HP of damage (out of 32), but I had discounted the possibility of using it because shooting the Nuclear Detonator twice is slower than just spamming the Buster. That is, until until I saw this video by Psychedelic Eyeball, which showed me that you can hit Sonic Man twice with the same shot.
  • Take advantage of RNG manipulation. I reverse-engineered the AI of certain enemies including bosses. Volt Man's and Dyna Man's jumps are random: Volt Man's (xy) velocity is random in ({4, 6}, {14, 16}); similarly Dyna Man's is random in ({4, 5, 6, 7}, {7, 9, 11, 13}). Against Volt Man, only the y velocity is important: you want a short jump because he becomes vulnerable only after he lands (saves 2 frames). Against Dyna Man, both components matter: you want him to jump toward you at maximum speed so that you can use the Force Field sooner, and not to jump so high that he's out of reach. The Raptorbot that I kill in Volt Man's stage and the Sentry Bee I kill in Dyna Man's stage are sacrifices to get favorable RNG against the bosses.
Regarding entertainment, I tried to make as many 1-ups drop as possible (1/64 chance) without losing time. I managed to get 9 1-ups to drop, out of 35 kills. I also attempted to humanize the run a bit by avoiding 1-frame shots (press and release Space on the same frame) except where needed.
#2247first draftdiffsecond draftdiff
boot9159−32590
configuration menu32−120
title screen127129+21290
intro stage386382−4376−6
stage select SVD146154+81540
Sonic Man stage20401928−1121902−26
Sonic Man111102−9100−2
stage select _VD352367+15368+1
Volt Man stage2125186−19391860
Volt Man109100−998−2
stage select __D305314+93140
Dyna Man stage19881783−2051768−15
Dyna Man7757−2052−5
Wily title cards363374+113740
Wily stage17341686−481666−20
Wily10440−6438−2
total100617663−23987586−77
The optimization Lua script deserves special mention. A lot of the smooth movement in this TAS—just barely avoiding a bonk while going around corners—is due to computer optimization. The script takes as input a search space over sequences of keypresses, tests each one of them (repeatedly reloading an initial savestate), and outputs the one that gives the best result according to some metric function. Say, for example, you need to climb a ladder after running right through a corridor. You want to jump before grabbing the ladder because jumping is faster than climbing, except near the top of the jump where climbing is faster. If there's a low ceiling, you don't want to jump too early, or you'll bonk your head, but jumping too late wastes time. You may also need to stop moving right at some point, or you'll go past the ladder before reaching the full height of your jump. Here's a real example from the TAS:
-- Optimize jump and batcave exit ladder
-- Start at frame 2161, x=131.12
optimize(pattern(pad(12,
	overlay(
		concat(rep(0, 3, frame()), atom(KEY_J)), -- jump
		concat(rep(4, 6, frame()), atom(KEY_RIGHT)), -- stop moving right
		concat(rep(6, 10, frame()), atom(KEY_UP)) -- grab
	)
)), metric_going_up)
What this means is, try waiting between 0 and 3 frames before jumping (KEY_J). Try waiting 4 to 6 frames before releasing Right, and try waiting between 6 and 10 frames before pressing Up. (These bounds were found through manual experimentation.) Overlay these three input sequences so they happen concurrently. Pad all the inputs to a length of 12. Return the sequence that does the best according to the metric_going_up function, which is
function metric_going_up()
	return {-megaman_y(), -camera_y(), -megaman_dy()}
end
In this example, the script will test all 4×3×5=60 possibilities before outputting
-- best schedule is	{{}, {36}, {}, {}, {}, {}, {205, 200}}
-- best score is	{-563, -512, 0}
Which means: jump (keycode 36) on frame 2, and press Right (205) and Up (200) on frame 7; the best y position you can get after 12 frames is 563. I used this optimize script in 46 places. Some of the instances went through thousands and inputs and took a few hours to run, which accounts for the large number of rerecords. I found out about the horizontal camera recentering alignment issue when the script output some surprising sequences; the script figured out that you need to get your x alignment right. The script needs a patch to JPC-RR, or else it quickly deadlocks the whole process. A side effect of the patch is that you no longer get an instant screen refresh after loading a savestate, which is annoying but you get used to it 😄 In addition to the optimization script, I used a HUD script that shows HP and hitboxes, with additional information off to the side. The game draws the most recent frame while already having computed the next frame, so seeing the hitbox overlay is a little like seeing 1 frame into the future. The HUD script shows the RNG sequence, which is how I knew when a 1-up was approaching. The potential enhancement I mentioned at the beginning: Say a stage appears visually onscreen at frame X. So you try frames X and X−1 and find that the game actually starts accepting input at frame X−1. I had already done this in every stage. But it turns out that in some stages, you can actually start moving at frame X−2, if you place the input later in the frame and not right at the beginning. So at frame X−2 you might insert some padding inputs at the start of the frame before the input you want: Up Up Up Up Up Up Up Up Up Up Right, and sometimes this works.
Post subject: Deadlock in JPC-RR when restoring a savestate from Lua
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
I tried to using a Lua script to optimize a short segment of a game (find the best frame to jump within a window of 15 frames). The script I wrote reliably deadlocks JPC-RR: it sits at 0% CPU and the interface is unresponsive. A small patch to JPC-RR avoids the problem, but hinders interactive use. I'm using version 11.6-WIP, built from source based on commit bf3a341ad233439e21a32f33dffc1e730668121d. This sample script should be sufficient to reproduce the deadlock. It doesn't depend on any specific game. Just load any savestate and run it. You may have to press S to get it started. I'm not sure the wait_for_event function is the best way to do frame advance: that was some trial-and-error coding on my part.
function jump()
	-- Press a key, or do whatever is necessary to jump.
end

function get_metric()
	-- Read the character's y position.
	return jpcrr.read_word(0x1000)
end

-- Call jpcrr.wait_event until we get an event of the right type, taking care
-- of "lock" events meanwhile.
function wait_for_event(target_type)
	while true do
		local etype, emsg = jpcrr.wait_event()
		if etype == "lock" then
			jpcrr.release_vga()
		end
		if etype == target_type then
			return etype, emsg
		end
	end
end

-- Restore savestate, then run for n frames, initiating a jump at frame j.
function trial(savestate, j, n)
	-- Stop emulator, if running.
	if jpcrr.status().running then
		jpcrr.pc_stop()
		wait_for_event("stop")
	end

	-- Restore initial state.
	jpcrr.load_state_normal(savestate)
	wait_for_event("attach")

	jpcrr.pc_start()
	for i=0,n do
		if i == j then
			jump()
		end
		-- Advance frame.
		wait_for_event("lock")
	end
	print(j, get_metric())
end

local savestate = jpcrr.save_state("init.jrsr")
for j=0,14 do
	trial(savestate, j, 15)
end
jpcrr.pc_stop()
I did a little debugging of this. The deadlock is caused by several threads waiting on a synchronization monitor. I suspect there is a race condition because it is not completely deterministic: it usually happens on the first loop iteration, but may occasionally happen later. A thread dump (kill -QUIT $(pidof java)) shows many backtraces including these three that are waiting on a org.jpc.plugins.PCControl:
"VGA output cycle thread" #42 prio=6 os_prio=0 tid=0x00007f84a40b3800 nid=0x4b97 in Object.wait() [0x00007f84add9b000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x0000000085bcb4c0> (a org.jpc.output.OutputStatic)
        at java.lang.Object.wait(Object.java:502)
        at org.jpc.output.OutputStatic.waitReaders(OutputStatic.java:221)
        - locked <0x0000000085bcb4c0> (a org.jpc.output.OutputStatic)
        at org.jpc.output.OutputStatic.addFrame(OutputStatic.java:127)
        at org.jpc.output.Output.addFrame(Output.java:76)
        at org.jpc.output.OutputChannel.addFrame(OutputChannel.java:78)
        at org.jpc.output.OutputChannelVideo.addFrameVideo(OutputChannelVideo.java:47)
        at org.jpc.emulator.VGADigitalOut.holdOutput(VGADigitalOut.java:48)
        at org.jpc.plugins.PCControl.doCycleDedicatedThread(PCControl.java:1477)
        - locked <0x0000000085a9dd70> (a org.jpc.plugins.PCControl)
        at org.jpc.plugins.PCControl.access$1300(PCControl.java:80)
        at org.jpc.plugins.PCControl$9.run(PCControl.java:1486)
        at java.lang.Thread.run(Thread.java:748)

"Plugin thread for org.jpc.plugins.PCControl" #25 prio=5 os_prio=0 tid=0x00007f8510470800 nid=0x4b8b waiting for monitor entry [0x00007f84adc9a000]                                                                                                                                                                            
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.jpc.plugins.PCControl.main(PCControl.java:419)
        - waiting to lock <0x0000000085a9dd70> (a org.jpc.plugins.PCControl)
        at org.jpc.pluginsbase.Plugins$PluginThread.run(Plugins.java:485)

"AWT-EventQueue-1" #15 prio=6 os_prio=0 tid=0x00007f8510408800 nid=0x4b82 waiting for monitor entry [0x00007f84ad387000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at org.jpc.plugins.PCControl.start(PCControl.java:1261)
        - waiting to lock <0x0000000085a9dd70> (a org.jpc.plugins.PCControl)
        at org.jpc.plugins.PCControl$5.run(PCControl.java:484)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:301)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
        at java.awt.EventQueue.access$500(EventQueue.java:97)
        at java.awt.EventQueue$3.run(EventQueue.java:709)
        at java.awt.EventQueue$3.run(EventQueue.java:703)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
        at org.GNOME.Accessibility.AtkWrapper$5.dispatchEvent(AtkWrapper.java:700)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
I tried this simple patch to JPC-RR. It works, in that it allows the script to run without deadlocking, but it has the side effect of preventing the screen from being updated immediately after loading a savestate, which is awkward when working interactively.
--- a/org/jpc/plugins/PCControl.java
+++ b/org/jpc/plugins/PCControl.java
@@ -1483,7 +1483,7 @@ e.printStackTrace();
     {   
         final PC _xpc = _pc;
         cycleDone = false;
-        (new Thread(new Runnable() { public void run() { doCycleDedicatedThread(_xpc); }}, "VGA output cycle thread")).start();
+        // (new Thread(new Runnable() { public void run() { doCycleDedicatedThread(_xpc); }}, "VGA output cycle thread")).start();
         while(cycleDone)
             try {
                 synchronized(this) {
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Dacicus wrote:
Was it faster to jump over the weapon tank after the second Dyna Man fight than to pick it up, or why did you do that?
Yes, it's faster to jump over (or at least equally fast). I discarded most of my notes, but for descents like that I tested 1-frame jumps at various offsets, 2-frame jumps, etc. The rule of thumb is you want to jump as high as possible, because that gives you more time to accelerate downward before reaching the drop; and jump as early as possible without clipping the corner. In some corridors with a low ceiling it's better to jump as high as possible and bounce off the ceiling. A good jump versus a not-so-good jump only translates into a difference of maybe 8 pixels or less of y position. As Mega Man's maximum falling speed is 15 pixels/frame, a better jump may not always result in him actually hitting the ground sooner. I only optimized for y position and velocity at some fixed frame number on the descent. I wrote a little Lua script to automate optimizing these jumps, but it caused a deadlock in JPC-RR due to an apparent race condition. (I didn't investigate it thoroughly.) I was able to work around it by commenting out a line in JPC-RR that restores the display after loading a savestate, but that becomes annoying when working interactively, and it was too cumbersome to switch back and forth between the two versions. So I just optimized all the jumps manually. Maybe in a future revision.
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
First draft of a TAS incorporating the skip in Volt Man's stage and other improvements: Link to video But you may prefer this version that has been slowed down to a watchable speed (more on this below): Link to video More info and JRSR file: https://archive.org/details/megamanpc-tas-1_49_352 The file is 7663 frames or 01:49.34, which is about 24% faster than [2247] DOS Mega Man by DarkKobold in 02:23.55. The biggest single time save is skipping Volt Man's stage. Further gains are from general clean movement: pre-jumping down pits and avoiding hugging walls. Other specific improvements are:
  • Putting C: on HDD rather than HDA and skipping all the startup options, as recommended at Wiki: EmulatorResources/JPC, makes the boot faster.
  • You need to delay slightly to avoid getting hit by the dog; there's enough time to kill one dog while still saving a few frames overall.
  • The second wall in Sonic Man's stage can't be harmed while the first wall is exploding. (This applies to all such explosions: only one can exist at a time, so anything that might explode is invulnerable until an existing explosion is gone.) While waiting for the explosion to finish, we lure the Batvire to the left to open up some headroom. Jumping and shooting the second wall near the top causes the explosion to spawn up high, so that Man Man can walk under it.
  • Holding up in the vertical fan shaft reaches maximum vertical speed slightly faster.
  • One damage boost is enough to get past the Sewer Rat—it requires slowing down so the wall blasters can hit you first.
  • It pays to be out of the water as much as possible. Under water, Mega Man moves at 6 pixels/frame; above it, 8 pixels/frame. Jumping from a lower to a higher platform incurs a slight delay for camera recentering. You can sometimes avoid the recentering delay by jumping immediately after landing.
  • Jumping from the top of a ladder mitigates the camera recentering that occurs in the dark Batvire cave and elsewhere.
  • Taking the right ladder, rather than the left, is a faster way to exit the Batvire cave.
  • The Volt Shield makes Mega Man immune to many of the hazards in Dyna Man's stage: Sentry Bee nails, lava bubbles, and acid drops. Keeping it equipped throughout the stage means we almost never have to slow down.
  • It's possible to touch the backwards conveyor belts for only one frame between jumps. You need to press the jump button before Mega Man is visually on the ground. If you do it right, Mega Man will stay in the jumping animation and not enter the running animation.
  • Damage boosting through the hazards in Dyna Man's assembly line is faster than waiting: even while stunned, Mega Man moves at 6 pixels/frame because of the conveyor belt, compared to 8 pixels/frame when running normally.
  • The pause/weapon menu is free if it only appears for one frame. To switch to the Sonic Wave, for example: press S, press Esc, frame advance; release S, release Esc, frame advance.
  • Earlier first shots in a damageless Wily fight.
Known deficiencies and potential improvements:
  • The intervals between the stages (when the game is loading resources from disk) are slightly slower than in [2247] DOS Mega Man by DarkKobold in 02:23.55. My best guess is that this has something to do with putting C: on HDD rather than HDA. If so, then it would be better to go back to HDA: the time saved between stages would more than make up for a slightly slower boot.
  • Didn't jump out of the first ladder in Sonic Man's stage.
  • It would be better to get up to speed before equipping the Volt Shield in Dyna Man's stage.
  • In the first Dyna Man fight, I tested both Volt Shield and the buster, and the buster was faster. But in the refight, I found a fast way to do it with the Volt Shield that may also work in the first fight. The circumstances are not exactly the same, because in the refight your goal is not only to defeat the robot master but also to get to the right side of the screen as fast as possible.
2247thisdiff
boot9159−32
configuration menu32−1
title screen127129+2
intro stage386382−4
stage select146154+8
Sonic Man stage20401928−112
Sonic Man111102−9
stage select352367+15
Volt Man stage2125186−1939
Volt Man109100−9
stage select305314+9
Dyna Man stage19881783−205
Dyna Man7757−20
Wily title cards363374+11
Wily stage17341686−48
Wily10440−64
total100617663−2398
About the game's speed It's unfortunate that the game's speed is CPU-limited up to the display refresh rate. It means that the video plays back at a speed that is too fast to appreciate what is going on. What can be done about this?
  • [2247] DOS Mega Man by DarkKobold in 02:23.55 links to a separate video that is slowed down to 30 fps. It's a lot nicer to watch—the only problem is that the sound effects are longer in duration and lower-pitched than they should be.
  • Cranking JPC-RR's CPU frequency divider up to its maximum value of 256 doesn't help. It's not slow enough to make a frame take more than a refresh, so the gameplay speed is unchanged, while loading stages, etc. is slower.
  • The F1 and F2 keys are in-game speed controls. F2 decreases the game speed by inserting busy-waits into every iteration of the main game loop. Using F2, you can make the game run 2×, 3×, 4×, 5×, ... slower. It complicates timing because one iteration of the game loop now takes more than one JPC-RR "frame." The slowdown only affects the gameplay loop, not things like loading stages.
Above, I tried a compromise, which is a separate slowed-down "soundhack" video, named after the camhacks in e.g. [3584] Genesis Sonic the Hedgehog 2 by Zurggriff & Aglar in 17:40.08. The sound effects in Mega Man use the PC speaker and the programmable interval timer, which is clocked independently of the main CPU. The soundhack is a small modification to the game executable that increases the pitch and decreases the duration of all sound effects, so that they sound mostly correct when the video is slowed down. It's not perfect, because some of the high frequencies are lost, but it's much better than just slowing down all the audio. I chose to slow down the video by a factor of 5, to about 14.02 fps. I chose this speed, even though it feels a little too slow to me, because it's close to the speed you get when running in DOSBox with cycles=500, which is what speedrun.com RTA runs use. I measured the speed by counting blinks. Mega Man's blink cycle is 64 frames. I timed 10 blink cycles in DOSBox to take approximately 45.65 seconds, or 14.02 fps, which conveniently is almost exactly 1/5 of the natural framerate of a JPC-RR dump.
Post subject: Re: Stifling Sentry Bees
Sand
He/Him
Experienced Forum User, Published Author, Player (125)
Joined: 6/26/2018
Posts: 154
Sand wrote:
The Sentry Bee will fly overhead without dropping its nails—and no more Sentry Bees will spawn for the remainder of the opening section.
I figured out why this happens. Imagine that the stage is divided into vertical zones, each 8 tiles wide (128 pixels wide). The bee drops its bundle of nails as soon as it enters the zone that Mega Man is currently in. (Which means that the drop can be right on top of Mega Man's head, or up to 8 tiles away, or anywhere in between, depending on Mega Man's position in the zone.) If Mega Man, moving right, crosses from zone A to zone B in the same frame as the bee, moving left, crosses from zone B to zone A, then there is no frame in which they are both in the same zone, and nails never drop. The relevant code is at offset 0x1947 in dyna.bin:
0000:1947  268b07      mov ax, word es:[bx]     ; bx points to Mega Man's x position
0000:194a  2580ff      and ax, 0xff80           ; round down to a multiple of 128
0000:194d  8b1c        mov bx, word [si]        ; si points to the bundle's x position
0000:194f  83e380      and bx, 0xff80           ; round down to a multiple of 128
0000:1952  3bc3        cmp ax, bx               ; same zone?
0000:1954  7508        jne 0x195e               ; branch if not same zone
0000:1956  ff441a      inc word [si + 0x1a]       ; set bundle's y velocity to 1 (indicates it's now falling)
0000:1959  c744180000  mov word [si + 0x18], 0    ; set bundle's x velocity to 0
0000:195e
Or in pseudocode:
if (megaman.x / 128 == bundle.x / 128) {
        bundle.y_vel++;
        bundle.x_vel = 0;
}
Knowing this, I was able to prevent the drop in the second section where bees appear, too. The way respawning works is, there's really only one bee: there are five sprite slots for the bee, bundle, and four nails. (The bundle and one of the nails share a slot.) The next bee can spawn only when all five slots become empty (despawn). The bee itself despawns when it goes far enough offscreen, but the bundle only despawns when it hits the ground. Because the bundle never drops, it never hits the ground, and the next bee can never spawn. (Actually, if you wait long enough—several minutes—the bundle's x position will wrap around 16 bits, arrive once more in Mega Man's zone, finally drop, and restart the spawning cycle. I only noticed this because it happened in the background while I was writing this post.)
1 2
5 6 7