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 ; http://parasyte.panicus.org/ ; ; 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 ;--constants MapXStart = $18 MapYStart = $38 MapPal = $01 MapFlashPal = $00 RoomTile = $6F NoRoomTile = $6E ;--pointers 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! ;--routines 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! pha jsr Adiv8 ;A >> 3 (Divide by 8) sta MapPointer+1 pla jsr Amul32 ;A << 5 (Multiply by 32) clc 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. clc adc #$08 sta MapX ;Update X-coordinte for next sprite. inx inx inx inx iny cpy #$03 ;Automap width. bne - lda MapY ;Increment Y-coordinate for next line of sprites. clc adc #$08 sta MapY dec Counter beq + ;Exit when complete. lda MapPointer ;Increment map pointer with new Y-Coordinate. clc 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!
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 why.) 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 http://www.zophar.net/utilities/nesdev.html 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 development.) 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. ;)