MaruMari: Project Outline

 

This is an outline for the MaruMari homebrew project I’m working on for NES. As of posting this outline, the game is very incomplete. Things are subject to change, and suggestions are welcome.

Neither the outline nor the spec are complete, but if you think I’ve overlooked something essential, please say so.

 

Things I Would Love To Have Help With

  • Artwork. Can be shamelessly plundered from metroid games, but some unique artwork might be nice, too.
  • Music. Famitone/Famitracker is probably the easiest and best approach, but music needs to be composed/extracted, and I have no experience with this toolset. I’ve already written a utility that can extract music data from Metroid.

 

Gameplay Outline

General Outline:

  • Game takes original metroid as its primary inspiration, with each level based on a level from the original game.
  • Player will play as samus in ball form.
  • Game will used forced downward scrolling.
  • The player loses by running out of health or getting crushed at the top.
    • It won’t be that hard to avoid getting crushed. The forced scrolling is to motivate the player to keep moving rather than taking a slow cautious approach at the game.
  • The game will include powerups and enemies inspired by other metroid games.
    • Enemies will probably be based strongly on enemies from the same level of the original game.
    • Powerups will be somewhat different from original game (outlined below)
  • Each level will end with a door bubble in the floor (as in Super Metroid)
    • Player will transition to next level with super-metroid style screen transition
      • When player enters door, music stops and screen fades to black, except for doorway and bubble.
      • Doorway scrolls to top, next level fades in, bubble opens, and player is dropped down
  • The game will not be overly difficult.
    • The player should not beat in on first couple tries, but:
      • The goal is to complete the game with the highest score possible
      • Maybe I can work a “completion percentage” type scoring system in for metroid-y goodness
      • Different difficulty settings are a possibility
      • Different endings!

Power-ups:

  • Bombs
    • Limited quantity.
    • Enemies may drop pickups, or they may be placed or randomly placed in levels, or both
      • A pickup will reward five bombs, player can carry max of eight.
        • Rational: This will create a situation where you can’t completely neglect collecting bombs, but you don’t have to hoard them and seek them out obsessively.
    • Varia
      • Temporary, reduces damage
    • Health
      • Exactly what it sounds like
    • Energy Tank
      • Permanently increases health capacity
    • Spring ball
      • Can work one of two ways:
        • Temporary. Lasts a certain amount of time, or jump height decreases gradually.
        • Cumulative. Each spring ball pickup increases player’s height
    • Charge bomb
      • Not really sure about this one
      • Player would be able to hold limit quantity (or they could be very rare)
      • Would be switched on with select like missiles in “Metroid”
      • A longer hold produces a larger blast and bounces player higher
    • Space Jump
      • Temporary. Allows player to jump from the air anytime he is falling downward.
      • Spring ball may or may not be prerequisite
    • Screw Attack
      • Temporary. Player in invincible and kills enemies on contact while moving upward from a jump.
      • Player does not have invincibility while falling down. He still needs to be careful.
    • Thoughts
      • It might be a good idea to have a plain-old invincibility power up.
      • It would be cool to have power bombs instead of/in addition to charge bombs, but how would these work on NES?

Enemies:

  • To be determined. Enemy lineup will probably be strongly based on Metroid.

 

Specifications

Scrolling:

  • The game will use a slow forced scrolling to motivate the player to keep moving, to emphasize this is an action game, not an exploration game.
  • Scrolling speed will increase with each level to marginal difficulty. Death-by-scroll-pinch isn’t meant to be the primary hazard.
    • If the game has difficulty levels, the scrolling could a much more serious hazard in hard difficulty.
  • There will be a “scroll line” about halfway down the screen.
    • When the player falls past this line, the screen will scroll more quickly to keep the player visually at or above this line.
    • This is so the player can proceed at his own pace, and so he can see what’s ahead (he will always be able to see at least 1/2 a screen ahead of the samus)
    • The engine will be limited to scrolling at 8 px per frame, so this is the maximum fall speed

Player physics: Movement

  • The player has 16-bit speed variables, and 8-bit position variables. Speed is a fixed-point number (i.e. [-]##.##, e.g. -01.C0)
    • Position will be stored as a 16-bit value as well.
  • The low bytes (fractional part) of speed are not applied to position, they are used only for gradual acceleration
  • When the player presses left or right
    • If his speed is 00.00, he assumes a speed of 01.00 in the pressed direction so there is no lag before movement.
      • For a speed of “01.00″ to the left, we’ll use FF.C0 (-00.40). This is because we always round DOWN rather than toward zero.
  • While the player continues to hold left or right
    • He accelerates at a rate of 00.40 in the appropriate direction, to a maximum of +/- 2 (FE.C0 to 02.00)
      • Note: the speed limit (2) might be a little low.
  • If the player exceeds a speed of 2 to the left or right from any yet unplanned mechanism (boost tile or something)
    • He decelerates at a rate of 00.40 until he reaches the normal max speed
  • If the player is not holding left or right
    • He decelerates at a rate of 00.40 until he stops
  • When the player jumps
    • His upward velocity is set based on current equipment, but assumes full speed instantly. There is no “bounce”.
  • When the player is “In-air”
    • His downward velocity increases at a constant speed (00.80?) until terminal velocity is reached (06?)
  • The player’s sprite should rotate in the direction he most recently moved (left or right)

Player physics: Collision

  • Player’s speed will be added to his position (movement) immediately before processing collision
    • Tiles with same physics will be stored in groups (consecutive indecies). Groups will appear in the following order.
      • Air
      • Damage: air-like (tile can be passed through)
      • Damage: solid-like (tile can not be passed through)
      • Solid
  • Vertical Collision
    • At any point the player will be in one of two modes. Each will have a different handler.
      • “On-ground”
        • If the player touches the top of the screen in the on-ground state, he loses (he has been pinched).
        • Each frame test ground below player, @ $4,$16 and C,$16. If neither one hits a solid tile, player transitions to in-air state with an initial veloctiy of 01.00
        • If the player jumps, he transitions to an in-air state with a negative velocity based on his equipment
      • “In-air”
        • Checks for collision above or below player, depending on the direction of his motion
        • Upward:
          • Test for collision at $4,-0 and $4C, -0.
          • Player will collide with top of screen
          • Upon collision with top, test collision beneath player. If player is touching ground, he loses (he has been pinched)
          • Upon collision, player is placed directly beneath the collided-with tile: playerY = (playerY + $F) & $F0
          • Player “bounces” downward by assuming a downward velocity that is a fraction of the previous upward velocity
        • Downward:
          • Test for collision at same points as ‘on-ground’. If a collision occurs:
            • Position player onto tile (this can be done by taking the players position, relative to the level grid, and ANDing Y-position with $F0)
            • Behavior depends on player’s downward velocity
              • If the player has sufficient velocity, “bounce” the player upward (remain in “In-air” mode) at a fraction of his previous speed
              • Otherwise, Transition to on-ground state
  • Sideways Collision
    • Collision is tested in the direction the player is moving (left/right). If the player has no sideways motion, no collision testing is needed.
    • Leftward collision points  are $4,0 and $4,$F. If the player collides:
      • place him $C pixels to the right of the tile that his left side occupies (playerX = (playerX & $F0) + $C)
      • Set horizontal speed to zero
    • Rightward collision points are $C,0 and $C,$F. If the player collides:
      • place him $4 pixels to the right of the tile that his left edge occupies (playerX = (playerX & $F0) + $4)
      • set horizontal speed to zero
  • Other
    • Background-based hazard detection (spikes, lava, etc) should be included in above collision logic.
    • Sprite-based objects (enemies, items) will be processed separately using a collision rectangle created by the collision points detailed above

 

Level Data Format/Compression:

  • Level data will be stored in the following format:
    • The data stream will alternate between attribute entries and pairs of row entries.
    • After every eighth attribute entry, there will be only one row entry instead of two.
    • An attribute entry will consist of eight bytes of raw attribute table (palette) data, enough to define palettes for two rows of 16×16 tiles.
    • A row entry will define sixteen tile numbers, using an RLE encoding scheme, where each byte in the stream has the format ATTT BTTT
      • The tile number is the value with bits A and B cleared (value AND $EE)
      • A and B make up a two-bit number (‘A’ being the low bit) which yields a number 0 to 3. Add 1 to this value to get the run length, in the range of 1 to 4.

Sprite animation data

  • Sprite animation data is stored in the form of “sprite layouts”, “sprite tile lists”, and “sprite animations”.
  • For each type of data (layouts, tile lists, and animations), there will be a pointer table that references each entry.
  • The index of the pointer to a piece of data will be referred to as that data’s ID.
  • Sprite Layout:
    • Contains a sequence of pairs of bytes that specify X and Y coordinates as signed bytes.
    • FF terminated.
  • Sprite Tile List:
    • Contains a sequence of non-zero tile numbers intermixed with “attribute modifications”
    • An attribute modification is a zero byte followed by a byte containing the following bit flags:
      • $01 – Add 1 to palette number
      • $02 – Add 2 to palette number
      • $40 – Toggle horizontal tile flip
      • $80 – Toggle vertical tile flip
    • FF terminated
  • Sprite Animation:
    • Contains a sequence of frame entries (3 bytes ea):
      • Layout ID
      • Tile list ID
      • Screen frames for this animation frame
    • FF terminated

 

Suite-NES 101

Since it seems like this project is never going to get finished, I’m going to release what I have so far. Maybe input from others will help me focus and get things done. Worst case, if I never finish the project, at least I’ll have released something. So, here’s a quick guide to Suite-NES.

Keep in mind that this project is incomplete. Comments, suggestions, and criticism are appreciated.

1. Projects

SuiteNES doesn’t work with plain ol’ ROMs. SuiteNES works with projects. A project consists of a ROM, project settings, and project files. But… if you’re doing something simple and don’t want to bother with a project, things are set up so you can basically ignore the whole project aspect of the program.

When you open a ROM, SuiteNES will create a new temporary project for you. You can use the various editors, modify the ROM, and save back to the ROM file without saving the whole project to disk. On the other hand, when you save your project, SuiteNES will remember which editors you have open and their settings. This means that when you open the project back up, it will remember how you had tiles organized in the arranger, how you had the table set up in the hex editor, and so on.

You can open more than one project at a time. Each project opens in its own window (MDI), and each project’s editors are shown within a tabbed interface. This can be handy for copying and pasting tiles or hex between two ROMs, or comparing them side-by-side. Rather than using a “Window” menu, when more than one project is opened, a document list appears at the bottom of the window.

2. Help

To see basic help for the active editor click SuiteNES->Editor Help in the menu. This menu option will be grayed out if help is not available for the current editor.

3. Files

Besides the ROM, a project can contain additional files. On the left side of a project window is a file manager with the files shown on top, and the properties of the selected file shown beneath. Click on the divider bar to collapse the file browser, and click again to show the file manager.

SuiteNES currently only has built-in support for editing and processing .ASM (assembly) and .GFX (graphic tile) files, but any file can be included in the project.

4. Building

SuiteNES uses a build system. Each time you build the project, SuiteNES will process your project files and patch them into a copy of your ROM (found in the \bin directory of the project).

.GFX and .BIN files are patched directly to the ROM. For the file properties, Action should be set to Embed, and Patch offset specifies where the data will be patched (in the 0x00000 hex format).

.ASM files are assembled and patched to the ROM. For assemblers, SuiteNES comes with ASM6 and snarfblASM built-in. To specify which assembler you would like to use, go to the file’s properties and specify ASM6 or snarfblasm as the Command.

External Programs

You can also use an external program to build a file. Suppose you prefer the Foobaz assembler over ASM6. Outside SuiteNES you would run Foobaz with the command Foobaz myfile.asm which will produce a file called myfile.bin.

To configure SuiteNES to use Foobaz to build the file, go to the file’s properties and change Action from Native build to Command line. Set Command appropriately to run Foobaz. For example: Foobaz %FILE%. (You will need to type the full path to Foobaz unless you add the directory that contains Foobaz.exe to the PATH includes in SuiteNES settings.) Build output file should be the name of the output file that Foobaz creates: %FILENAME%.bin. Patch offset specifies the location in the ROM to patch the assembled file (in hex).

5. Debugging

When you build and launch for project (Project->Launch in the menu, or F5), the result ROM is written in the \BIN folder, and then launched with the default .NES file launcher. If you use snarfblASM as your assembler, it will output files for FCEUX’s symbolic debugging. That means code like this:

; Save map data
; -------------
.PATCH 02:B000
SaveMapData:

    JSR PrepLoadSaveIndexers

*   LDA MapRam,X
    STA MapSaveRam,Y

    DEY
    DEX
    BPL -

    JMP SaveHijackReturn

; Load map data
; -------------
LoadMapData:
    JSR PrepLoadSaveIndexers

*   LDA MapSaveRam,Y
    STA MapRam,X

    DEY
    DEX
    BPL -

    JMP LoadHijackReturn

    ; Delete routines
; ---------------
DeleteMap_RegisterName:
    JSR DeleteMap
    JMP $A764       ; Return from hijack

DeleteMap_SecondQuest:
    JSR DeleteMap
    JMP $AF5A       ; Return from hijack

will look like this in the debugger:

02:B000:20 37 B0  JSR PrepLoadSaveIndexers
02:B003:BD 50 7F  LDA MapRam,X @ $804F = #$8D
02:B006:99 60 7F  STA MapSaveRam,Y @ $7F61 = #$FF
02:B009:88        DEY
02:B00A:CA        DEX
02:B00B:10 F6     BPL $B003
02:B00D:4C 2A 9D  JMP $9D2A
02:B010:20 37 B0  JSR PrepLoadSaveIndexers
02:B013:B9 60 7F  LDA MapSaveRam,Y @ $7F61 = #$FF
02:B016:9D 50 7F  STA MapRam,X @ $804F = #$8D
02:B019:88        DEY
02:B01A:CA        DEX
02:B01B:10 F6     BPL $B013
02:B01D:4C 25 E6  JMP $E625
02:B020:20 2C B0  JSR DeleteMap
02:B023:4C 64 A7  JMP $A764
02:B026:20 2C B0  JSR DeleteMap
02:B029:4C 5A AF  JMP $AF5A

 6. Plugins

The plugin system is not complete, and there really aren’t any plugins to use with the plugin system. The eventual goal of the plugin system is to allow new file editors and ROM data editors to be integrated into SuiteNES as well as file builders such as assemblers, text inserters, and anything else you can think of. Most of the plumbing is in place. What really needs work is the plugin managing part of the program.

7. Revisions

Ignore this.

FCEUX Debug File Format

Just in case anybody else ever needs to know the format for FCEUX’s debugger’s config files (.deb), here it is, based on the source code for version 2.1.5 (found in \src\drivers\win\pref.cpp) and the contents of actual .deb files. » Read more…

Editroid 3.0

Editroid 3.0 (beta) is ready and willing to satisfy all your Metroid hacking desires! You can download the editor or the source code.

  • Expands ROMs further
    • Converts to CHR ROM – allows animated background tiles
    • 15 KB per level for screens and structures (vs. about 3KB in the original game)
    • 256 combos
    • Up to 32 rooms per level with item-room-music (vs. 7 in the original game)
    • More space for item data than you can use
  • Added “NARPASSWORD” (invincibility/all equipment) to room testing feature
  • Improved map is larger and auto-hides
  • New “Screen Browser” and “Structure Browser” make it easy to find what you’re looking for
Editroid 3.0 Screenshot

Editroid 3.0 with the structure browser

Zelda Tech 3.4

Since the Zelda Tech section of the website is defunct and disused, and this part of the site is a lot easier to update, I’ll go ahead and put this here.

A minor update of Zelda Tech with two fewer bugs. :/

For completeness, I’ll link to the other downloads here as well.

In the unlikely event that you do not have the .NET Framework installed, you’ll need to get it to run these programs.

Metroid: Wavy-Ice

Wavy-Ice screenshot

Shootin' through stuff. Freezing stuff. Wavy-Ice can do it all!

I’ve decided to share my simple Wavy-Ice hack. It allows the player to combine the wave beam and ice beam in Metroid. Note that this only works on a ROM expanded by Editroid 2.1. It will not work on an unexpanded ROM or an Editroid 3.0 ROM (I’ll release an updated patch for Editroid 3.0).

I’ve put together a zip containing the code, an assembler, and a ready-to-go IPS patch. The code should be assembled with snarfblASM to produce an IPS file:

>snarfblasm wavyice.asm wavyice.ips -IPS:ON

» Read more…

Metroid Tuner

So I made this thing to edit Metroid (NES) music data, and I named it “Metroid Tuner,” because I didn’t feel like trying very hard to come up with a good name. Here is a download link to an alpha version of the utility that will crash and melt your computer and blow up your house and punch a kitten in the face. » Read more…

Zelda Automap 0.2 Source

Below is the source for the Zelda Automap hack (0.2). You can also download the source with the needed GFX file. The code should be assembled with snarfblASM. The resulting IPS file should be applied to the PRG0 version of the ROM (PRG1 appears to work as well, but the hack was created and tested on PRG0). Comments are welcome.

» Read more…

ReMaster: Editing Doors

It looks like there may be some confusion as to how door editing works in ReMaster, so here’s the how. (We’re referring to doors that bring the player from one level to the next, or from tank areas to overhead areas and vice-versa.) The very first thing you’ll want to do is select “Doors” as the editing mode in the top-right corner of the window. In the editor area on the left, doors are shown in yellow. On the right is a list of all the doorways in the game.

» Read more…

ReMaster: Better Late Than Never

The Blaster Master level editor, ReMaster, has been shared with some communities, but has yet to see a proper release until now.

DOWNLOAD IT

» Read more…