User Tools

Site Tools

“Don't worry, Zeke is agree!”


Table of Contents

Metroid Minimap Hack

By Parasyte.

This code is written for x816. It should assemble with ASM6 with little modification. The resulting binary code should copied to the ROM at 0x01CA45. For an expanded ROM the code may need to be placed at a different address, and the game engine bank will appear at 0x3C010 instead of 0x1C010.


; This code builds and displays a Super Metroid-like automap for Metroid (NES)
; Copyright 2002-2004 Parasyte
; Notes:
; Simply overwrite the data at file address 0x01CA45 (192 bytes, max)
; with this code. Then set the hook by patching 0x01CB68 to 0x35,0xCA

.org $CA35		;assemble our code to run at this (CPU) address
.mem 8			;setup accumulator and index regs for NES code
.index 8

MapXStart	= $18
MapYStart	= $38
MapPal		= $01
MapFlashPal	= $00
RoomTile	= $6F
NoRoomTile	= $6E

MapPointer	= $00		;These are our temporary variables.
Counter		= $02
MapY		= $03
MapX		= $04

FrameCount	= $2D
Ypos		= $4F		;Samus' Y-Coordinate on Map.
Xpos		= $50		;Samus' X-Coordinate on Map.

CurSprite	= $5B		;Current sprite pointer. The game's sprite engine handles this.

SpriteBuf	= $0200		;Where all the sprites are!

Adiv32		= $C2BE		;Power-of-two division.
Adiv16		= $C2BF
Adiv8		= $C2C0
Amul32		= $C2C4		;Power-of-two multiplication.
Amul16		= $C2C5
Amul8		= $C2C6

;--Entry Point
; Inputs:	None
; Outputs:	None
; Description:	Builds a map display using sprites, based on the currently loaded room number

	dec Ypos		;These will be incremented again before leaving the routine.
	dec Xpos

	lda Ypos		;Calculate map position address, too lazy to explain how it works!
	jsr Adiv8		;A >> 3 (Divide by 8)
	sta MapPointer+1
	jsr Amul32		;A << 5 (Multiply by 32)
	adc Xpos
	sta MapPointer
	lda MapPointer+1
	adc #$00
	ora #$70
	sta MapPointer+1

	lda #$03		;Automap height.
	sta Counter
	lda #MapYStart
	sta MapY
	ldx CurSprite

--	ldy #$00		;Begin drawing map to spr-ram page at $0200.
	lda #MapXStart
	sta MapX

-	lda (MapPointer),y	;Get room number.
	cmp #$FF
	beq +			;Branch if null room number. (#$FF)

	lda #RoomTile
	bne ++			;Branch always.
+	lda #NoRoomTile

++	sta SpriteBuf+1,x	;Sprite tile index.
	lda MapY
	sta SpriteBuf,x		;Sprite Y-coordinate.
	lda #MapPal
	sta SpriteBuf+2,x	;Sprite palette.
	lda MapX
	sta SpriteBuf+3,x	;Sprite X-coordinate.
	adc #$08
	sta MapX		;Update X-coordinte for next sprite.
	cpy #$03		;Automap width.
	bne -

	lda MapY		;Increment Y-coordinate for next line of sprites.
	adc #$08
	sta MapY
	dec Counter
	beq +			;Exit when complete.

	lda MapPointer		;Increment map pointer with new Y-Coordinate.
	adc #$20
	sta MapPointer
	lda MapPointer+1
	adc #$00
	sta MapPointer+1
	jmp --			;Drawing complete.

+	lda FrameCount		;Change palette of middle map sprite every 8 frames.
	and #$08
	bne +
	ldy CurSprite
	lda #MapFlashPal
	sta SpriteBuf+(4*4)+2,y
+	stx CurSprite		;Update current sprite position.
	inc Ypos		;See above ... I told you so!
	inc Xpos

	jmp $E0C1		;And we're outta here!

Read Me

Metroid AutoMap patch v1.0
Copyright 2002-2004 Parasyte

What's new?

v1.0 (06-11-04):
 * Initial release.

What is it?

  The Metroid AutoMap patch is a very small assembly hack for the original NES
Metroid. It build's and displays a Super Metroid-like AutoMap in realtime
using the map data stored in memory. The purpose of this patch is to make it
somewhat easier to navigate Metroid or hacks by giving you some indication of
where you are, and where you are going.

How does it work?

  I have included the complete, commented source code for the assembly routine
for this very reason; to show you how it works. The basic idea is that the game
engine already does most of the work. For example, when the game first boots,
it will copy the entire world map into NES memory. The game also keeps track of
things such as Samus' current position on the map. It actually does all of this
to make loading rooms easier as you traverse the world.
  The AutoMap routine takes these things into account, and uses them to it's
advantage. Without the game keeping track of such things, it would have been a
much larger, and more difficult routine to create.

  There is a two-byte patch described in the source code notes which is what
actually allows the AutoMap routine to run. The patch replaces a "jsr $E0C1"
instruction with "jsr $C035." $C035 is the address where the routine is written
in the ROM. (Also notice the AutoMap routine ends with "jmp $E0C1" -- this is
  The routine at $E0C1 is what displays all of the other status information,
such as energy and missiles. By hooking this call, we're able to draw the
AutoMap at the perfect time. Sprites will be free to use, and the routine will
never get called at a bad point in the game. (Like at the title screen)

  When the AutoMap routine begins, it will first calculate the memory address
of the world map where it must begin loading from. It does this using Samus'
current position on the map, and 'allocates' a range of 3x3 rooms around her
position. Next, it begins to draw the AutoMap sprites by setting the sprite
positions and palettes, but also selecting the tile to draw based on the room
number loaded from that 3x3 grid. A room number of $FF indicates no room. In
this case, an 'empty' tile is drawn, showing no room. For anything else, a
'full' tile is drawn. By default, the routine draws the empty and full energy
tank tiles for the AutoMap. Feel free to change that to whatever you like in
the source and re-assemble!

How can I assemble the source code?

  Using the best 6502 assembler ever written, of course: X816! Download it from if you have not already. To
assemble, run x816 from the commandline like so: x816 -l met-map.asm

(Note to Windows XP users: I've included a file called "x816.pif" in the zip.
 You must place this file in the same directory with x816.exe to get the
 program to run. Failure to do so will result in the program crashing, or just
 plain not working at all.)

  After assembling the source, you will have a nice new binary file named
"met-map.bin". This file contains all the data which you need to copy into the
Metroid ROM. (See source notes for more information.) Please keep in mind that
the routine MUST NOT exceed 192 bytes.

Can I use this patch in my hack?

  You certainly can! Just apply the ips patch over your hacked ROM, and have
fun with it. All I ask in return is that I'm given credit for the AutoMap in
your readme, in the ROM, or both. Take your pick.
  You are also free to modify the AutoMap source code however you see fit, with
just one exception: the copyright notice may not be changed or removed.
Everything else is open to change.

What other uses does this patch have?

  This patch can be applied to nearly every Metroid ROM hack ever created. The
two parts of the ROM which must be changed for it to work will not be changed
by any editor, and except for the hooked JSR instruction, the game does not
even use the data in that 192-byte space. (The data there is an unused routine,
probably something left over from a debug build, or a feature removed during
  What this means is almost all of your favorite Metroid hacks can have an
AutoMap with just the simple use of an IPS patch. In some cases, you may have
to do some extra work, such as changing the tile numbers used for the AutoMap,
and creating new tiles specifically for the map. But that stuff isn't too hard.
Just change the tile numbers in the source code, re-assemble, and apply the
patches by hand in a hex editor. Then get out your favorite NES tile editor,
make the desired changes, and call it a day.
  Unfortunately, some Metroid hacks are bound to not work after applying the
patch. It all depends on what the author of the hack has done with the data
needed by the AutoMap routine.

  Important side-nide: The patch will not work with my upcoming Metroid hack.
But no worries, it will have it's own AutoMap feature. And it will be a bit
better than this one.

Special Thanks

  Thanks to Kent Hanson (SnowBro) for his work on the Metroid disassembly
source. He's saved me some valuable time hacking this game. ;)
metroid/asm/minimap.txt · Last modified: 2015/02/28 22:59 (external edit)