View Page Source

Revision (current)
Last Updated by Sand on 10/29/2023 1:29 AM
Back to Page

%%TOC%%

!!! Game speed

Mega Man is one of those games that just [Forum/Posts/473252|runs too fast].
It technically ''is'' screen refresh–limited,
but its "natural" speed of one frame per refresh is too fast to be humanly playable.
[Forum/Posts/480224|Ilari explained it]: "There are games that fail to sensibly limit themselves, and altough the effective framerate saturates at some point, that saturation point is unplayably fast."
A faster CPU setting would reduces load times, but not increase the speed of gameplay.

To produce an encode that runs slower and is more pleasant to watch,
without messing up the sound effects too much,
you can use the "soundhack" script under [GameResources/DOS/MegaMan#Resources|Resources].

By the way, for casual play, you can fix the game's speed with
Brad Smith's [https://github.com/bbbradsmith/mmpatch|speed patch].

!!! Emulator settings and boot

In the [EmulatorResources/JPC#AssemblingTheVirtualSystem|JPC-RR assembly window],
put the Mega Man image on Hdd and FreeDOS on fda.
Clear the "Modules" box—this game doesn't need need sound card, FPU, MIDI.

At the prompt
%%SRC_EMBED
Press F8 to trace or F5 to skip FDCONFIG.SYS/AUTOEXEC.BAT
%%END_EMBED
press F8 to run fdconfig.sys, then answer ''n'' to all of the prompts.
%%SRC_EMBED
 dos=high[Y,n]?n
 lastdrive=z[Y,n]?n
 buffers=20[Y,n]?n
 files=40[Y,n]?n
 device=himem.exe[Y,n]?n
 shell=cmd80x86.com command.com /K autoexec.bat[Y,n]?n
 A:\>\autoexec.bat [Yes=ENTER, No=ESC] ? n
%%END_EMBED
For some reason, running fdconfig.sys and declining all the options shortens load times between stages.
More info: [Forum/Posts/479329], [Forum/Posts/478684].

The setup menu (where you choose VGA and disable the joystick)
is not frame-oriented, unlike the game itself.
It's just a loop that polls a global variable that is set by the keyboard interrupt handler.
This means that you can provide inputs much faster than one per frame—but you have to go slow enough that the loop notices one of your inputs before you provide the next one.
The setupmenu.lua script under [GameResources/DOS/MegaMan#Resources|Resources] can automatically optimize this menu.

!!! Between stages

You can press and release Space right after finishing the setup menu.
You don't have to wait for the title screen to appear.

The stage select screen recognizes inputs when you ''release'' a key.
So if you want to select Sonic Man, you should press Left and Enter
''before'' the stage select appears, then release at the earliest moment at which the game recognizes the input.
This is not necessarily on a frame boundary, so you need to use sub-frame inputs.
Find the earliest frame at which the input is recognized, then load a savestate
and go back to one frame earlier.
Try pressing/releasing the Up key 9 times before releasing Left and Enter.
If it works, try again with pressing/releasing Up 8 times, and so on.
Each press/release of Up takes about 1/10th of a frame—this
is an easy way push inputs later in a frame, if they are not recognized at the beginning of a frame.

The same rule applies at the beginning of each stage.
It may appear that you can start moving 1 frame before the stage appears onscreen.
But usually you can start moving 1.''x'' frames before the stage appears,
by using sub-frame inputs in the frame prior.

Sub-frame inputs don't seem to help at the "weapon get" screen.

After defeating a Robot Master, jumping to collect the card key
will shorten the animation of it falling to you.

!!! Boss order

The [GameResources/DOS/MegaMan#VoltSkip|Volt skip] requires an E Tank from
Sonic Man's stage, so Sonic must come before Volt.
Therefore the only orders worth considering are:
* Sonic, Volt, Dyna
* Sonic, Dyna, Volt
* Dyna, Sonic, Volt
Current runs use SVD. SDV seems strictly inferior to SVD,
because Dyna Man's stage benefits from the Force Field
but Volt Man's stage doesn't benefit from the Nuclear Detonator.
DSV is worth considering: the Dyna stage and boss fight would be slower,
but the Sonic boss fight would be faster.

!!! Mechanics

!! Shooting

Press and release Space in the same frame in order to shoot every frame.

!! Physics

Mega Man accelerates horizontally at 2 pixels/frame/frame
up to a maximum speed of 8 pixels/frame.
Releasing an arrow key, or pressing the opposite direction,
sets your horizontal speed to 0 immediately (instant deceleration).

In most places, vertical acceleration due to gravity is 3 pixels/frame/frame.
Mega Man stops accelerating when he reaches a speed of 15 pixels/frame downwards.
When jumping down a ledge, it's usually best to jump
as early and as high as possible,
so that you're already falling down at maximum speed when you reach the ledge.

Mega Man's apparent position lags 1 frame behind his actual position
(use the HUD script under [GameResources/DOS/MegaMan#Resources|Resources] to see this).
When landing from a jump, you can jump again
as soon as Mega Man's within-tile ''y'' position is 3;
e.g. a ''y'' position of 819 is 51 3/16 when expressed in terms of tiles.
If you do it right, Mega Man will jump again
without ever entering his running animation.
This matters, for example, on backwards conveyors,
which slow you down as long as you are on the ground.

[https://www.bamsoftware.com/computers/tasvideos/mmdos-conveyor-jump.gif|alt=An animation of Mega Man jumping forward over a backwards conveyor, comparing the earliest possible jumps with jumps that are 1 frame slower.]

Some tiles are programmed to push Mega Man horizontally.
Solid pusher tiles (conveyor belts) only push while you are standing on them;
passable pusher tiles (like underwater in Sonic Man's stage)
push as you pass through them.
On either side of every conveyor there are single passable tiles
that push in the same direction as the conveyor.
Examples are highlighted in the screenshot below.
Avoid touching these tiles when they push backwards.

[https://www.bamsoftware.com/computers/tasvideos/mmdos-conveyor-extension.png|alt=A screenshot of a conveyor belt, with the non-solid tiles at either end highlighted with arrows to show that they push in the same direction as the conveyor.]

Some places have lower gravitational acceleration than 3 pixels/frame/frame,
for instance underwater in Sonic Man's stage.
Whenever gravity is [https://tcrf.net/Mega_Man_(DOS)#Gravity|zero or negative],
you can affect Mega Man's vertical speed by pressing the Up and Down keys.
This is only useful in one place: the vertical fan shaft in Sonic Man's stage.
Hold the Up key to accelerate to maximum speed 1 frame faster.

!! Sub-tile alignment

Tiles are 16 pixels wide.
Because Mega Man accelerates in units of 2 pixels,
This means that under normal circumstances, if you have even pixel alignment, it will stay even;
and if you have odd alignment, it will stay odd.
The only way to change your alignment is to run into a wall
(going left makes the alignment even; going right makes it odd)
or grab a ladder (makes it even).

Having the right sub-tile alignment may allow you to,
for example,
start accelerating horizontally 1 frame earlier when exiting a vertical shaft.
Changing your ''x'' position by any amount other than 8 pixels
requires slowing down, so it's only worth doing when you are otherwise
stopped from making immediate progress.

To adjust your position by:
* 2 pixels: press Right, release Right, frame advance.
* 4 pixels: press Right, release Right, frame advance, frame advance, press Right, release Right, frame advance.
* 6 pixels: press Right, frame advance, frame advance, release Right, frame advance.
* 8 pixels: just keep running; this is Mega Man's running speed.

!! Vertical camera recentering delay

Whenever Mega Man lands a jump from a lower to a higher platform,
he freezes in place while the camera recenters on him vertically.
It doesn't happen when jumping downward.
The following animation stabilizes the camera
to show the freezing effect.
The only difference between the two examples is that
the top one avoids low-to-high jumps as much as possible.

[https://www.bamsoftware.com/computers/tasvideos/mmdos-lava-jump.gif|alt=An animation of Mega Man jumping across platforms, demonstrating how he freezes in place whenever the camera recenters itself.]

Vertical camera recentering delay
also affects the tops of ladders.
You can diminish the delay by jumping at the top of the ladder,
which partially scrolls the camera up,
leaving it less distance to move when you touch the ground again.
it doesn't help unless Mega Man has a certain amount of headroom.

[https://www.bamsoftware.com/computers/tasvideos/mmdos-ladder-jump.gif|alt=A split-screen animation comparing Mega Man jumping at the top of a ladder, and not jumping. The jumping one is a tile and a half faster.]

!! Horizontal camera recentering delay

The only time horizontal camera recentering delay matters
is after each of the Robot Master refights in Wily's stage.
At the moment the camera starts moving, you want to be:
* on the half of the screen nearest the exit gate
* moving at full speed
* with sub-tile alignment of 0 or 8
If you have bad alignment, the camera will take an extra frame to recenter itself. More info: [Forum/Posts/478286].

!! Item drops

An item drop iterates the [GameResources/DOS/MegaMan#RNG|RNG] once and chooses the item based on the most significant byte:
|0 ≤ ''x'' < 4 |1-up |
|4 ≤ ''x'' < 24 |large health |
|24 ≤ ''x'' < 48 |large weapon energy |
|48 ≤ ''x'' < 88 |small health |
|88 ≤ ''x'' < 128 |small weapon energy |
|128 ≤ ''x'' < 256 |nothing |

!! Weapon select screen

You can switch weapons without losing time.
To switch to Sonic Wave, for example:
press S, press Esc, frame advance; release S, release Esc, frame advance.
Mega Man will continue moving at full speed during both of these frames.

!!! Volt skip

You can skip most of Volt Man's stage
using the E Tank from Sonic Man's stage
to heal past a death barrier.
Take damage from a spark while facing right,
so that you stagger backwards into the wall.
Press Escape on the frame before you lose all your health.
On the next frame the weapon select menu will be open and you will have zero health.
Use an E Tank and then select a weapon to close the weapon select menu.

[https://www.bamsoftware.com/computers/tasvideos/mmdos-voltman-death-barrier.png|alt=A screenshot of Mega Man falling toward the death barrier in Volt Man's stage, with the death tiles highlighted.]

[https://www.bamsoftware.com/computers/tasvideos/mmdos-voltman-1etank-skip.gif|alt=Animation showing Volt skip.] 

[Forum/Posts/471887|Forum post] [https://archive.org/details/Mega_Man_DOS_speedrun_11_21_20180711_David_Fifield|RTA documentation]

The same trick would work to pass a death barrier in Dyna Man's stage,
but you would have to farm a second E Tank and
[Forum/Posts/479471|it's not quite worth it].

!!! Weapons

!! Damage chart

||Enemy ||HP ||||P ||S ||V ||D ||
|Guard dog | 8| 1| 1| 1| 1|
|Sewer Rat | 2| 1| 0| ∞| ∞|
|Sonic Man |32| 1| 0| 2|16|
|Volt Man  |32| 1| 6| 0| 2|
|Dyna Man  |32| 2| 1| 6| 0|
|Crorq     |32| 1| 6| 2| 4|
|Wily      |32| 1| 2| 8| 4|

!! Nuclear Detonator

When you shoot the Nuclear Detonator, it starts a {{weapon_counter}} timer.
After 16 frames, you can manually detonate it.
After 96 frames, it will detonate automatically.

!!! Enemy AI

!! RNG

The random number generator is duplicated for each stage,
a copy of it appearing in each .bin file.
It is the same algorithm everywhere (a linear congruential generator),
but with a different seed in each stage.

%%SRC_EMBED c
uint16_t rng() {
    static uint16_t rng_state = RNG_SEED;
    rng_state = rng_state * 0xe51d + 0x3619;
    return rng_state;
}
%%END_EMBED

||stage || seed||
|SECUR | 0x7536|
|SONIC | 0x5f27|
|VOLT  | 0x3a05|
|DYNA  | 0x9d86|
|WILEY | 0xd975|

The fixed RNG per stage is convenient for TASing.
It means that RNG from earlier stages does not carry over into later stages;
the RNG is always in a known state at the beginning of a stage.
When the game samples from the RNG,
it tends to use the high-order bits,
perhaps as mitigation against the weaknesses of a linear congruential generator.

The RNG iterates at least once per frame.
Enemy AI, item drops, and other random events may iterate it more.

!! Data structures

Enemies, pickups, and other objects use a common 28-byte data structure.
Each stage (.bin file) contains an array of these data structures,
with one element for each thing that can appear in the stage.
Fields may have different meanings for different types of enemies.

%%SRC_EMBED c
struct actor {
/*  +0 */   uint16_t    x_pos;
/*  +2 */   uint16_t    y_pos;
/*  +4 */   struct frm *current_frm;   // pointer to current bitmap and hitbox
/*  +6 */   uint8_t     hp;
    // damage_amount is how much Mega Man is damaged by contact.
    // If the actor is a pickup, damage_amount instead indicates what kind:
    // 1 = 1-up, 2 = E Tank, 3 = large health, 4 = small health, 5 = big weapon, other = small weapon
/*  +7 */   uint8_t     damage_amount;
/*  +8 */   uint8_t     unknown_0; // ???
/*  +9 */   uint8_t     flags;     // (flags&0x80)!=0 => spawned/active
    // The next 4 fields define a bounding box which the enemy will stay inside of.
/* +10 */   uint16_t    x_max;
/* +12 */   uint16_t    x_min;
/* +14 */   uint16_t    y_min;
/* +16 */   uint16_t    y_max;
/* +18 */   uint8_t     counter_0; // Used for animation, and for timing the death explosion.
/* +19 */   uint8_t     counter_1; // Sewer Rats use this counter while walking.
/* +20 */   uint8_t     counter_2; // Sewer Rats use this counter while standing.
/* +21 */   int8_t      facing;    // negative = facing left; otherwise facing right
/* +22 */   uint16_t    unknown_1; // ???
    // Volt Man and Dyna Man use extra_0 and extra_0 to store horizontal and vertical speed.
/* +24 */   int16_t     extra_0;
/* +26 */   int16_t     extra_1;
};
%%END_EMBED

The 18-byte data structure that {{current_frm}} points to contains the actor's current bitmap,
and also hitbox dimensions.

%%SRC_EMBED c
struct frm {
/*  +0 */   int16_t box_left;   // <= 0
/*  +2 */   int16_t box_right;  // >= 0
/*  +4 */   int16_t box_top;    // <= 0
/*  +6 */   int16_t box_bottom; // >= 0
/*  +8 */   int16_t unknown_0;  // ???
/* +10 */   int16_t unknown_1;  // ???
/* +12 */   int16_t unknown_2;  // ???
/* +14 */   int16_t unknown_3;  // ???
/* +16 */   int16_t unknown_4;  // ???
};
%%END_EMBED

!! Guard dog

The guard dog's AI subroutine starts at offset 0x56c in SECUR.BIN.

The guard dog in the intro stage is unlike other enemies
in that it can only be damaged once per frame.

!! Sewer Rat

The Sewer Rat AI subroutine starts at offset 0x1912 in SONIC.BIN.

%%SRC_EMBED c
static uint8_t global_flag_7de;

void ai_rat(struct actor *rat)
{
    if ((rat->flags & 0x80) == 0)
        // Ignore if not currently spawned.
        return;
    }
    blit(rat, rat->current_frm);
    // A global flag at BIN_AREA+0x7de, referred to in many AI
    // subroutines.
    if ((global_flag_7de & 0x80) != 0)
        return;
    if (rat->hp == 0) {
        // Rat is dead, now playing explosion animation. The animation
        // lasts for 5 frames, but there are only 3 bitmaps.
        // counter_0 == 5: O
        // counter_0 == 4: o
        // counter_0 == 3: o
        // counter_0 == 2: o
        // counter_0 == 1: .
        // counter_0 == 0: done
        rat->counter_0--;
        if (rat->counter_0 != 0) {
            // Death animation is finished.
            unspawn_actor_and_drop_item(rat); // Unsets rat->flags & 0x80
        } else if (rat->counter_0 == 3 || rat->counter_0 == 0) {
            // Advance explosion animation.
            rat->current_frm--;
        }
    } else {
        // Rat is alive. counter_1 is the walk counter; counter_2 is the
        // stand counter.
        int16_t x_vel = 0;
        if (rat->current_frm == FRM_RAT_STANDING && --rat->counter_2 != 0) {
            // Rat is in standing state. Roll a random walk counter for
            // when we transition to walking state. NB: the counter is
            // re-rolled every frame while standing, but only the final
            // one before transitioning to walking matters.
            uint16_t r = rng();
            rat->counter_1 = (((r << 4) | (r >> 12)) & 0x1f) + 32; // rand(32, 64)
        } else {
            // Rat is in walking state.
            rat->counter_1--;
            if (rat->counter_1 != 0) {
                // Still walking.
                x_vel = 4;
                if (rat->counter_1 % 2 == 0)
                    rat->current_frm = FRM_RAT_WALKING_EVEN;
                else
                    rat->current_frm = FRM_RAT_WALKING_ODD;
            } else {
                // Done walking. Roll a random stand counter.
                rat->counter_2 = (rng() >> 13) & 0x07 + 8; // rand(8, 16)
                rat->current_frm = FRM_RAT_STANDING;
            }
        }

        // Reverse velocity if facing left.
        if (rat->facing < 0) {
            x_vel = -x_vel;
        }
        if (check_collision(rat, x_vel)) {
            // Will the rat hit something?
            rat->facing = ~rat->facing;
        }
        rat->x_pos += x_vel;
        // Keep within this rat's boundary.
        if (rat->x_pos > rat->x_max)
            rat->facing = -1;
        else if (rat->x_pos < rat->x_min)
            rat->facing = 0;

        // Now check for collision with player bullets.
        // check_player_shot_collision returns the number of bullets
        // that hit the rat on this frame.
        uint8_t num_hits = check_player_shot_collision(rat);
        uint8_t i;
        for (i = 0; i < num_hits; i++) {
            if (current_weapon == WEAPON_P) {
                rat->hp--;
            }
            if (rat->hp <= 0
                || current_weapon == WEAPON_V
                || current_weapon == WEAPON_D) {
                rat->hp = 0;
                // Initialize death animation.
                rat->current_frm = FRM_DEATH_BUBBLE_LARGE;
                rat->counter_0 = 5;
                break;
            }
        }
    }
}
%%END_EMBED

!! Volt Man

Volt Man's AI subroutine starts at offset 0x2204 in VOLT.BIN,
or offset 0x235b in WILEY.BIN.

Volt Man's initial jump is random.
The ''x'' speed is random in {−4, −6} (or {+4, +6} in the Wily-stage refight).
The ''y'' speed is random in {−14, −16}.
The ''x'' speed doesn't matter, but the smaller jump is 2 frames faster.

!! Dyna Man

Dyna Man's AI subroutine starts at offset 0x1fdb in DYNA.BIN,
or offset 0x2a1a in WILEY.BIN.

Dyna Man's initial jump is random.
The ''x'' speed is random in {−4, −5, −6, −7}.
The ''y'' speed is random in {−7, −9, −11, −13}.
Ideally, you want him to jump towards you as fast as possible
(so he gets close enough to use the Force Field on him),
and low enough that he remains in reach of Mega Man's jump.

!!! Underexplored glitches

!! Lack of collision with Force Field

Sometimes, in the corridor before Volt Man in Wily's stage,
the Force Field will pass through enemies rather than destroying them.
It's not known why this happens or under what circumstances,
except that it has something to do with having used the Nuclear Detonator.
You can see it in Lizstar's AGDQ 2019 run:
* https://www.youtube.com/watch?v=tbs6PEgXEJg&t=665s

!! Death warp

Trigger tiles are special map tiles that do something when Mega Man passes over them,
for example spawning the enemies for the next room or activating a checkpoint.
You can see the trigger tiles with the [GameResources/DOS/MegaMan#Resources|HUD script]
or in the annotated [GameResources/DOS/MegaMan#Maps|Maps].
A minor death warp is possible with a least one checkpoint,
where the checkpoint is located a tiny bit farther ahead in the stage.

[https://www.bamsoftware.com/computers/tasvideos/mmdos-sonicman-death-warp.gif|alt=An animation of Mega Man entering the bat cave in Sonic Man's stage, dying with F10, and respawning a few tiles down and to the left of where he was.]

!! Trigger tile reentrancy

I found a bug having to do with activating a trigger tile twice.
After the fan shaft in Sonic Man's stage,
there is a trigger tile in the downward tube at coordinates (79, 15)
that spawns the Sewer Rat and makes the wall blasters start shooting.
The [GameResources/DOS/MegaMan#SewerRat|Sewer Rat AI] is supposed to work like this:
walk for {{rand(32, 64)}} frames, stand for {{rand(8, 16)}} frames, repeat.
If you jump straight down into the room (touching the trigger tile only once),
that is the behavior you'll see.
But if you walk off the edge at an angle (touching the trigger tile twice),
you'll instead see the rat walk for about 256 frames before starting
its normal cycle.
It happens because the rat gets reinitialized after it has already started its AI cycle,
and an integer underflow occurs.
Abusing the glitch doesn't help here,
because you want the rat to stand anyway
so it's easier to damage-boost past it.
But possibly there are other such bugs in other places.

The trigger tile callback in question starts at offset 0x9f5 in SONIC.BIN.
The portion having to do with the Sewer Rat is:
%%SRC_EMBED c
rat->flags |= 0x80; // spawn
rat->hp = 2;
rat->damage_amount = 6;
rat->current_frm = FRM_RAT_WALKING_EVEN;
rat->x_pos = 0x3f8; // tile position 63 8/16
rat->y_pos = 0x1db; // tile position 29 11/16
rat->x_min = 0x3e8; // tile position 62 8/16
rat->x_max = 0x4a0; // tile position 82 8/16
%%END_EMBED
The first time Mega Man hits the trigger tile,
the rat is in the walking state with {{counter_1}} = 0.
The first call to the [GameResources/DOS/MegaMan#SewerRat|Sewer Rat AI]
underflows {{counter_1}} = 255 and transitions to the standing state.
But then if Mega Man hits the trigger tile a second time,
it forces the rat back into the walking state,
but without resetting {{counter_1}}.
So now the rat will walk for 255 frames.

!! Wall clip

While climbing a ladder, hold Right and J (jump).
At the top of the ladder, release Up, and you'll clip one tile into the solid wall on the right.
It doesn't work going left.

[https://www.bamsoftware.com/computers/tasvideos/mmdos-ladder-clip.gif|alt=An animation of Mega Man reaching the top of the long ladder in Dyna Man's stage, and clipping into the solid tile on the right.]

!! Out of bounds

After traversing the death barrier in Volt Man's stage,
if you go left rather than right
you'll end up out of bounds,
off the left edge of the stage.
There are some invisible solid platforms there.

[https://www.bamsoftware.com/computers/tasvideos/mmdos-voltman-1etank-skip.gif|alt=An animation of Mega Man traversing the death barrier in Volt Man's stage using the E Tank trick, and moving left to stand atop the pole at the left of the stage.]

!!! Maps

* [https://www.bamsoftware.com/computers/tasvideos/mmdos-secur.map.16.png?|SECUR] ([https://www.bamsoftware.com/computers/tasvideos/mmdos-secur.map-annotated.16.png?|annotated])
* [https://www.bamsoftware.com/computers/tasvideos/mmdos-sonic.map.16.png?|SONIC] ([https://www.bamsoftware.com/computers/tasvideos/mmdos-sonic.map-annotated.16.png?|annotated])
* [https://www.bamsoftware.com/computers/tasvideos/mmdos-volt.map.16.png?|VOLT] ([https://www.bamsoftware.com/computers/tasvideos/mmdos-volt.map-annotated.16.png?|annotated])
* [https://www.bamsoftware.com/computers/tasvideos/mmdos-dyna.map.16.png?|DYNA] ([https://www.bamsoftware.com/computers/tasvideos/mmdos-dyna.map-annotated.16.png?|annotated])
* [https://www.bamsoftware.com/computers/tasvideos/mmdos-wiley.map.16.png?|WILEY] ([https://www.bamsoftware.com/computers/tasvideos/mmdos-wiley.map-annotated.16.png?|annotated])

Static maps don't tell the whole story.
For example, in Sonic Man's stage,
if you use the Nuclear Detonator to break into the large secret chamber,
the game will build a wall inside it,
preventing you from going all the way through.

Annotations (see map/main.go under [GameResources/DOS/MegaMan#Resources|Resources] for details about flags):
* center gray: tile ID
* upper-left magenta: Flags0: animation/destructibility
* upper-right yellow: Flags1: solidity, 0x80=trigger, 0x40=masked, 0x01=climbable
* lower-left red: Flags2: contact damage
* lower-right cyan: Flags3: physics, upper nibble is horizontal push, lower nibble is vertical gravity

!!! Memory addresses

Base memory addresses differ depending on whether you
have loaded HIMEM during boot.
As far as we can tell, it's faster ''not'' to load HIMEM.

Without HIMEM:
|{{SEG_000}}  | 0x2f970|
|{{MAP_AREA}} | 0x3859e|
|{{BIN_AREA}} | 0x5f870|

With HIMEM:
|{{SEG_000}}  | 0x5380|
|{{MAP_AREA}} | 0xdfae|
|{{BIN_AREA}} | 0x35280|

|{{camera_x}} | word {{SEG_000}} + 0x8c04|
|{{camera_y}} | word {{SEG_000}} + 0x8c0a|
|{{camera_target_x}} | word {{SEG_000}} + 0x8c16|
|{{camera_target_y}} | word {{SEG_000}} + 0x8c1c|
|{{megaman_x}} | word {{SEG_000}} + 0x10db7|
|{{megaman_y}} | word {{SEG_000}} + 0x10db9|
|{{megaman_frm}} (current bitmap)| ptr {{SEG_000}} + 0x10dbb|
|{{megaman_hp}} | byte {{SEG_000}} + 0x10dbd|
|{{megaman_x_vel}} | word {{SEG_000}} + 0x10dcf|
|{{megaman_y_vel}} | word {{SEG_000}} + 0x10dd1|
|{{player_shot_1.x}} | word {{SEG_000}} + 0x10dd3|
|{{player_shot_1.y}} | word {{SEG_000}} + 0x10dd5|
|{{player_shot_2.x}} | word {{SEG_000}} + 0x10def|
|{{player_shot_2.y}} | word {{SEG_000}} + 0x10df1|
|{{player_shot_3.x}} | word {{SEG_000}} + 0x10e0b|
|{{player_shot_3.y}} | word {{SEG_000}} + 0x10e0d|
|{{weapon_counter}} (used for Nuclear Detonator timer) | byte {{SEG_000}} + 0x10de7|
|{{explosion_counter}} | byte {{SEG_000}} + 0x10f15|
|{{num_lives}} | byte {{SEG_000}} + 0x115b1|
|{{num_etanks}} | byte {{SEG_000}} + 0x115b2|
|{{stages_finished}} 0x40=SECUR 0x01=SONIC 0x02=VOLT 0x04=DYNA | byte {{SEG_000}} + 0x115b3|
|{{current_weapon}} 0=P 1=S 2=V 3=D | byte {{SEG_000}} + 0x115b5|
|{{weapon_energy_S}} | byte {{SEG_000}} + 0x115b7|
|{{weapon_energy_V}} | byte {{SEG_000}} + 0x115b8|
|{{weapon_energy_D}} | byte {{SEG_000}} + 0x115b9|
|{{setup_menu_settings}} | byte {{SEG_000}} + 0x18b90|

{{setup_menu_settings}} bit 0x08 is a global invincibility flag.
It can be convenient to set that bit when you're trying something out
without wanting to worry about damage.

|{{stage_width}} | word {{MAP_AREA}} + 0x0|
|{{stage_height}} | word {{MAP_AREA}} + 0x4|

The per-stage variables are relative to {{BIN_AREA}} and vary across stages.

||variable || ||SECUR ||SONIC ||VOLT ||DYNA ||WILEY ||
|{{rng_state}} |word {{BIN_AREA}} +|0x2fc |0x7d5 |0xbf4 |0xb01 |0xb00 |
|{{ACTORS}} array |{{BIN_AREA}} +|0x1ac |0x2ba |0x340 |0x3a4 |0x4a0 |
|SONIC 1st wall HP |byte {{BIN_AREA}} +|N/A |0x793 |N/A |N/A |N/A |
|SONIC 2nd wall HP |byte {{BIN_AREA}} +|N/A |0x799 |N/A |N/A |N/A |

Some of the notable actors in each stage:

|SECUR guard dog |{{ACTORS[[10]]}} |
|VOLT Volt Man |{{ACTORS[[40]]}} |
|DYNA Dyna Man |{{ACTORS[[60]]}} |
|WILEY Volt Man |{{ACTORS[[24]]}} |
|WILEY Dyna Man |{{ACTORS[[47]]}} |

!!! Resources

Unorganized resources and reverse engineering tools,
including a HUD script and an automatic optimization script.

%%SRC_EMBED
git clone https://www.bamsoftware.com/git/megamanpc.git
%%END_EMBED