Git Product home page Git Product logo

scumm-nes's Introduction

SCUMM-NES

An app to explore and modify the game Maniac Mansion on NES.

What is this?

This tool is a web app to explore and modify the resources contained in the Maniac Mansion game on NES. The goal is to encourage the ROM hacking community to modify the game and create new hacks.

This app only works with Maniac Mansion on NES, it won't work with SCUMM files from other platforms or other NES games.

Portion of the code comes from ScummVM and Maniac Mansion Decoded.

What does it do?

It currently support:

  • Rooms (partially)
  • Room graphics
  • Costumes (not yet exposed to the UI)
  • Prepositions
  • Title screens

The following version are supported:

  • American English
  • European English
  • French
  • German
  • Italian
  • Spanish
  • Swedish
  • American English prototype (partial support)

The Japanese version is not supported.

What does it NOT do?

The app doesn't use the runtime code used by the NES to start and play the game. It only works with the SCUMM resources stored in the ROM files.

How to use it?

On top of the app, there is a command line interface to export the resources to JSON. This is useful to do process or compare the data.

node index.js --input path/to/rom --output resources.json

Options:

  • --input, -i Path to a ROM or PRG file.
  • --base-rom, -b The base ROM version of the input ROM.
  • --output, -o Path to a JSON filename to be created.
  • --version, -v Print the version number.

How to contribute?

To run it locally, make sure that node v20 or higher is installed, clone the repo, and install the dependencies:

npm install

Start the dev server with:

npm run dev

Production build

Create a production build with:

npm run build

Then deploy the content of the dist folder.

Future improvements

  • Use Typescript.
  • Write more tests.
  • Parse more resource types (sprites, sounds...).
  • QoF improvements (store the ROM files locally...)

Out of scope for now

  • Cover other SCUMM versions.

scumm-nes's People

Contributors

gmarty avatar pau-tomas avatar

Stargazers

 avatar

Watchers

 avatar  avatar

scumm-nes's Issues

Implement parent state

I think this is the problem with the cassette tape mentioned here:
#4 (comment)

The parent object index is stored at 0x0a in the object data. This is a one (not zero) based index to an object in the same room. It seems to be used primarily to hide objects that are behind doors like the refrigerator or the cabinet. The parent state is also stored in the upper 3 bits of byte 0x08 in the object data, but it seems to always have a value of 4 when present (there two instances of 7 in the code but not in combination with the parent index byte) , so not sure it really matters.

Basically the object needs to be hidden when the parent object is in the closed state, at least for the initial rendering.

Looks like this is also affecting the arcade room.

Make boxes editable

This would be one of the most useful features for editing since it's fairly difficult to do by hand. Editing existing boxes is enough for this request. Adding boxes is a longer term goal since that requires data size changes.

Allow arrow keys to navigate items in panels

If I click a room in the Rooms panel and then use the arrow keys, it activates the scrollbar. It would be more useful to change the selected item instead of being forced to use the mouse to change items. This applies to the Objects and Room Gfx panels as well.

Make palettes editable

Data-wise this is probably one of the easiest writes to make, so it could be a good start for allowing edits. It might be fun to roll a nes color picker as well.

Link object IDs in scripts

Currently script IDs are cross linked in the scripts panel. It would be useful to also link objects for the relevant scumm functions. A tooltip on hover showing the object name would also be nice.

Apply attribute table values on state change

Check the garage door objects in room 16 to close the garage door and the attribute table is not updated correctly. Same issue with the shower curtain in room 24, the sarcophagus in room 25, and the refrigerator in room 7, maybe others.

The attribute data is not straightforward to deal with If I recall correctly.

Reorganise the data for more flexilbility

The ROM files of Maniac Mansion are pretty much full of data. It means any modification (e.g. changing the nametable, adding new tiles or new objects...) is unlikely to fit in the original size.
To get more flexibility with the editing process, the ROM needs to be expanded and the data reorganised. After a few discussions with @gzip, it looks like the easiest route to take is to do something similar to what Maniac Mansion Decoded does.

This requires:

  • Expanding the ROM to add 256k (done in 2768736)
  • Moving nametable and attributes from the room payloads to the new banks and update their offsets (WIP branch relocate-nametable-attrs)
  • Patch the NES runtime to use the new bank

The last point is the tricky one.

The runtime ASM patch needs to be compiled to an IPS patch. In an ideal world, the patch would be compiled on commit to avoid having 2 files out of sync (the original ASM code and the IPS patch).
Maniac Mansion Decoded uses snarfblasm and I don't know if it can compile on Mac.
Once the patch is checked in, it can be applied with RomPatcher.js.

The patch needs to be compatible with all the different versions of the original ROM. That means we may end up needing one patch per version.

In order to break this down as much as possible, the reorganising of the tiles and the title screen data can be done later.

Display additional object properties

It would be nice to see the various object properties in a panel. Info such as x, y, width, height, walk to x/y, player face direction, and preposition. The UI should anticipate support for editing later on. Info like rom offest and payload size might be helpful.

Don't force a known hash

Currently if I try to load a rom that has been modified in any way I get an error "Upload one of the ROMs of Maniac Mansion on NES". Not sure how you want to handle this but one option might be to have a link like "Load anyway" with a select box for the version.

Highlight selected tile

In the tileset tab on the rooms page it would be nice to highlight the clicked/hovered tile in the room which gets rendered above.

Make attribute tables editable

I manually edited an attribute table today and was reminded of how nice it would be to have a UI for this. We talked about it a bit already... a simple UI would be to cycle through the background palettes when each 16x16 area is clicked on.

Use correct object initialization states

For example, in room 1 (front of house) the package, film, and tombstones shouldn't be displayed by default. It might be helpful to inspect the initial object states which are stored at 2CA21 in rom, offset by the object id (these get stored in ram starting at 660A). This is just a nice to have.

Display room mask

It would be nice to be able to see the room mask, something similar to the boxes.

I don't think the mask format is documented yet but I've picked it apart a bit. Let's use room 29 (under the house) as an example since it might be the most complicated mask. The RLE mask data for this room is stored in the rom at 225BA-22618 and gets decoded to ram at 6D7C. (In Mesen's Memory Viewer you can watch the bytes get accessed a column at a time as you walk through the screen.) Ignoring the rows of 0s, the mask is decoded as:

FC F0 C3 0F FC F0 03 00
78 E0 81 07 38 E0 00 00
30 C0 00 03 30 C0 00 00
30 C0 00 03 30 C0 00 00
30 C0 00 03 30 C0 00 00
30 C0 00 03 30 C0 00 00
30 C0 00 03 30 C0 00 00
38 E0 80 03 38 E0 00 00
38 E0 80 03 38 E0 00 00

This is bitmap data where each bit corresponds to a single tile, so a single byte covers a row of 8 tiles. A bit value of 1 = masked (background priority), and 0 = unmasked (sprite priority). We can visualize the bits in the above data to reveal the mask for a bunch of pillars under the house.

F    C      F    0      C    3      0    F      F    C      F    0      0    3      0    0
1111 1100   1111 0000   1100 0011   0000 1111   1111 1100   1111 0000   0000 0011   0000 0000

7    8      E    0      8    1      0    7      3    8      E    0      0    0      0    0
0111 1000   1110 0000   1000 0001   0000 0111   0011 1000   1110 0000   0000 0000   0000 0000

3    0      C    0      0    0      0    3      3    0      C    0      0    0      0    0
0011 0000   1100 0000   0000 0000   0000 0011   0011 0000   1100 0000   0000 0000   0000 0000

3    0      C    0      0    0      0    3      3    0      C    0      0    0      0    0
0011 0000   1100 0000   0000 0000   0000 0011   0011 0000   1100 0000   0000 0000   0000 0000

3    0      C    0      0    0      0    3      3    0      C    0      0    0      0    0
0011 0000   1100 0000   0000 0000   0000 0011   0011 0000   1100 0000   0000 0000   0000 0000

3    0      C    0      0    0      0    3      3    0      C    0      0    0      0    0
0011 0000   1100 0000   0000 0000   0000 0011   0011 0000   1100 0000   0000 0000   0000 0000

3    0      C    0      0    0      0    3      3    0      C    0      0    0      0    0
0011 0000   1100 0000   0000 0000   0000 0011   0011 0000   1100 0000   0000 0000   0000 0000

3    8      E    0      8    0      0    3      3    8      E    0      0    0      0    0
0011 1000   1110 0000   1000 0000   0000 0011   0011 1000   1110 0000   0000 0000   0000 0000

3    8      E    0      8    0      0    3      3    8      E    0      0    0      0    0
0011 1000   1110 0000   1000 0000   0000 0011   0011 1000   1110 0000   0000 0000   0000 0000

The only tricky part is that the bits in each byte are first reversed (or read right to left if you prefer). So the first two bytes for example get applied as:

0011 1111 0000 1111

As for the UI, when the mask byte is set (offset stored at 0x0E in the room data) it might make sense to create a separate canvas object that contains a black and white mask image to overlay the main room image (just an idea, maybe there's a better way).

Other rooms with masks are 22, 23, 40, 44, and 46, maybe others.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.