This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

comprehensive SMB1 disassembly

comprehensive SMB1 disassembly
by on (#22079)
Some of you out there in the #nesdev channel may already know about this, but under the sage advice of Memblers, I have decided to post it here. (The old link at the geocities page no longer works for obvious reasons.)

http://www.romhacking.net/docs/344/

As-is, it will work with x816 without any modifications. I have gotten it to work with cc65's assembler, ca65. However, you need to make some modifications to make it work properly.

First, you gotta change all the ".dw" to ".word", and ".db" to ".byte". Then you gotta make a small modification to the directives portion of the file.

Code:
;-------------------------------------------------------------------------------------
;DIRECTIVES

   ;    .index 8   <-- either remove these two or comment them out
   ;    .mem 8

       .p02 <-- you need to add this directive
   
       .org $8000

;-------------------------------------------------------------------------------------


Once you assemble the file, you will end up with an object file. In order to get the binary out of it, you need to run ld65. However, ld65 requires a config file to link to the object file properly. So create a text file with any name and put this in it:

Code:
MEMORY {
         ROM0: start = $8000, size = $8000, file = "smbdis.bin" ;
       }

SEGMENTS {
          CODE: load = ROM0, type = ro;
         }


Then run the linker and you should end up with the appropriate binary. If you want to, you can change the name of the filename in the "file" portion of the MEMORY config section, but the rest of it must be left as-is.

I hope this has been helpful.

by on (#22083)
Very interesting reading. Thanks for sharing.

by on (#22084)
This isn't the same as the SMB1 disassembly made by darkcode with a bit of my help, is it?

by on (#22086)
No. Although it is true I did compare notes between both my disassembly and that one (mostly in regards to the level data format), my disassembly was built completely from scratch using a disassembly run on the program rom with tracer.exe written by koitsu, with no distinction between data and code.

There are some other files on this page that are related to smbnotes.zip (and one of them is a much older copy of smbnotes.asm)

Link removed because it was broken.

by on (#22087)
We can always use more of these. Personally, I'd like to see someone take apart Final Fantasy or another RPG (Dragon Warrior, maybe, it's only 80KB.)

by on (#22088)
commodorejohn wrote:
We can always use more of these. Personally, I'd like to see someone take apart Final Fantasy or another RPG (Dragon Warrior, maybe, it's only 80KB.)

I went through Final Fantasy some time ago (in a hex editor). The code for its menus and playfield mode is pretty straightforward, but its battle system is a HUGE mess (no wonder it had so many bugs). You can tell that the battle system was written by a different group of programmers and that the group had very limited 6502 experience (lots of zero-page accesses in absolute addressing mode, arithmetic operations done in very inefficient ways, and even some basic assembly errors that contribute to problems like the LOCK spell not working). Frankly, it's amazing to me that the battle system worked at all.

The code in Final Fantasy 2 and 3 (for NES) is much cleaner, although both suffer from a bad pseudo-random number generator (affecting battle mode only), and both still have their share of bugs (the infamous level-up chear in FF2 and the "item upgrade" cheat in FF3).

by on (#22089)
Quote:
Personally, I'd like to see someone take apart Final Fantasy or another RPG (Dragon Warrior, maybe, it's only 80KB.)

I've taken apart a considerable amount of the last two banks of Final Fantasy (the second-to last is holing all the menu stuff, and the last does the field engine amont other general-purpose stuff). However, I did it for myself, and now I think all my notes about it are lost and I really don't remember where they are since I've changed my PC.
However, FF2 and FF3's code are very similar to FF1's (down to the loaction of some variables), but the only one I traced seriously was FF1. I've also traced some stuff in Hanjuku Hero, but it wasn't getting too well, because the game is constantly testing variable it is never writing to, and writing to variables it will never test, and that makes it very confusing. I tried tracing Just Breed a very little bit, but it was incredibly confusing.

by on (#22097)
Bregalad wrote:
However, FF2 and FF3's code are very similar to FF1's (down to the loaction of some variables), but the only one I traced seriously was FF1.

There are a lot of similarities between FF1 and FF2/3 in the playfield engine, but the engine was significantly enhanced (particularly regarding dialogue and cutscenes, which are very primitive in FF1). Menus have a more structured approach in FF2 and FF3, allowing for more flexibility. Having said that, the biggest change (by far) is the battle system, which was completely rewritten, seemingly from scratch.

by on (#22103)
I traced FF1's menu wich allow a lot of flexibility : Each window can be positionned and sized independantly. However, a few thing, like the cursor position and the orb's attribute in the main menu, are 'hard coded', and need to be manually chnaged if desired. I remember doing a FF1 hack with a completely different menu setup (the winow were positionned on the left and the menu on the right, like recent FF games).
FF3 allowed the same system to work even more easily, because the cursor's position is calculated from the windows position. I don't know about FF2, but it shouldn't be very different.

I haven't traced any battle stuff for any of the 3 games, so I don't know. The only thing I think I traced is that sound effect from battle were handled by a simple sound effect engine, while the other ones were just hard-coded APU writes with a variable disabling the Square 2 channel begin used.

by on (#22105)
Well, good luck with that if you decide to pluck at it some more.

by on (#22107)
Thanks for sharing it! A really nice RE work, with enough comments so that even the lazy ones among us can easily learn what made the old classic tick. A must read on a rainy day! :)

by on (#22117)
Glad you guys like it :-)

by on (#22694)
One bug, on line 7162, I think the beq $bcea should read as beq ExitPUp. Other than that, this is excellent! Thank you for this!

by on (#22702)
Wow, awfully keen eyes you have there. I did not notice that myself. The address was correct, I just forgot to change it to a label. Anyway, correction made.

by on (#22718)
And don't mean to be picky, but other one bug at line number 11,469: I think jsr $e02f should read as jsr SetStun.

^_^

Still, thank you for this!

EDIT: BTW, what was your methodology for doing this disassembly?

by on (#22749)
Oh, goddamnit. These things are coming out of the woodwork.

Yeah, I went ahead and fixed that. Then I ran a complete check on every branch and jump in the file, and could find no others. But anyway, thanks again for finding those bugs.

My methodology was simple: I ran a disassembler on the program rom, then started at the beginning (reset vector) and traced out all the code. The first version of this file I uploaded was full of gaping code and data holes.

Anyway, sometimes I would trace out more code, sometimes I would go over the code with both FCEU and my intuition to figure out what the code did, and sometimes I did both at the same time. I was able to expedite the process of figuring out the level data format by comparing notes with others who had done SMB1 hacking in the past, and I was able to actually verify that, for the most part, their own ideas were correct. Some other parts, like enemy data, I had sparse information on. For the rest of the code, however, I was for the most part completely on my own.

It became fully functional (meaning it could be assembled) sometime in February I believe. But although it was filled with comments, it was almost completely devoid of labels. So I went back and replaced all the memory locations with addresses. Some of the values which would have led to confusion I replaced with constants. This was the part I call the clean-up phase. Still, I'm only human, and even I overlooked some of them, apparently.

Anyway, that's pretty much how I did it. It's not something that anyone else with a lot of free time and a shitload of patience couldn't do.

by on (#22755)
Can it be reassembled and still work even if you move parts of the program and data around within the 32 KiB PRG space? If so, rom hackers will have a new tool for making even more total conversions. Imagine moving all the level data and enemy logic to $8000-$BFFF so that S*ROM or U*ROM can switch it out when needed.

by on (#22758)
tepples,

Yes. I converted it to being assembleable with CA65 and then modularized it and then moved the modules around. This was how I discovered those bugs. But once I fixed the 2 bugs I mentioned here, it's a good build! ^_^

EDIT: Additionally, I wonder what is the best method for modularizing so that you could add in extra switchable banks so that you can add more data in?

-----------------------------------------------

doppelganger,

I've been eying doing disassemblies of smb2J and smb3 (Japanese version), but I realize they would be much tougher because of the bank switching. Nevertheless, though I'm still trying to figure out the data loading/saving mechanisms of the FDS, I think I'm making decent progress in planning how I'm going to do the smb3 disassembly.

Basically, I made some modifications to FCEUXD SP v1.07 having added an Address Use Logger, which among other things logs the exact PRG (as opposed to just ROM) addresses accessed by opcodes. I'm not done obviously, but I think that if used in conjunction with the Code/Data Logger you can get a pretty good idea of how this is to be disassembled and how you're going to apply labels to each of the referenced addresses.

by on (#22759)
Good job. Now all we have to do is write a freely licensed replacement for each of the modules, like LAME did, and we'll have bootstrapped ourselves a complete side-scroller engine free of Nintendo copyright. Who's up for the task? Or is it too big?

by on (#22761)
tepples,

Or just use it for a ROM Hack--though the IPS file for that would probably contain a lot of the original game code--, or just use it as a guide to learn how to write your own sidescroller.

EDIT:

For a ROM Hack, you might just want to distribute the source code and the INES header (with possibly the CHR-ROM if it's heavily modified) along with instructions for how to assemble it.

by on (#22782)
I am curious to see how you modularized it. It was pretty chaotic to do, I bet.

by on (#22802)
I've tried everything to get it to assemble.

X112F doesn't do anything, when I try to use it it says "not enough memory"

And I tried the other assembler and did all the changes, but it still gets errors.

by on (#22806)
CKY-2K/Clay Man wrote:
And I tried the other assembler and did all the changes, but it still gets errors.

Which "the other assembler", and which errors?

by on (#22809)
Clay Man,

Quote:
X112F doesn't do anything, when I try to use it it says "not enough memory"


If you're using Windows XP, then you probably want to get something like DOSBox (Google it) so that you can have an environment under which the assembler can be run.

All,

Has the source code to the assembler been released?

by on (#22812)
CKY-2K/Clay Man wrote:
X112F doesn't do anything, when I try to use it it says "not enough memory"


I don't think you need DOSbox for this. I can run it in 2k just fine... after I change its memory settings.

Right click on the exe and go to properties. In the Memory tab, you have to change one of the settings to give it more mem (I forget which kind of mem, though).

by on (#22843)
Disch,

I was having the issue on my school's computers (which have XP) and I had set the memory settings to max. So in response I got DOSBox. But whatever gets it working for the person... ^_^

by on (#22849)
Perhaps I should break this thing up into smaller pieces.

by on (#22850)
Yeah, Windows XP seriously pisses me off. I can only run pure DOS things under command promt.

One of the reasons why I was urging my mom to install Windows 98 on our old computer.

by on (#22851)
Make it for the CA65 toolchain, and everyone will be happy. CA65 is ported to Linux, to Windows, and to PC DOS.

by on (#22853)
It works fine. Perfectly done. This is my first time really trying out compilers/assemblers and all. Same exact hex.

All I need to do after I compile it is add an iNES header and the graphics.

Good job.

by on (#22996)
doppelganger,

LOL, one more thing that could be an issue. At line 3525, I found something that could be an issue if you moved the code around. That dummy entry actually seemed like it was used. I found when I modularized it, I had the game freeze when there was looping. You should make sure that line 3525 references the code at line 3453 rather than putting a bare address. Adding the reference prevented the game from freezing. *

* The freezing occured in World 4-4.

Beyond this, there is probably not much else that is at issue. I'm writing a program the checks for non-label references to $8000-$FFFF range in the assembly source.

by on (#22999)
4-4? Does it also occur in 7-4?

To test all the data in the maze levels, you have to fail each checkpoint once then pass each section. Play the corresponding levels in Super Mario All-Stars to find the checkpoints.

by on (#23001)
tepples,

I'm just referring to his disassembly. I moved the code around, which caused problems with bare address references to the $8000-$ffff range, so I had to fix those.

doppelganger,

Another more complex one takes place at lines 645, 14421, and 14466. It's a bit more difficult to fix because the game does a weird piece of code. My solution was to comment out line 645, replace the SwimTileRepOffset on line 14421 with SwimTile+6, and add SwimTile: as a label to the beginning of line 14466. You may be able to come up with a better solution.

Anyway, here is the C source code to the program I wrote that checks for bare address references to the $8000-$ffff range (the 2 I recently posted were all it found aside from the bare address interrupt reference and the .org):

Code:
#include <stdio.h>
#include <string.h>

#define MAX_SIZE    1001
#define MIN_CHECK   0x8000  /*in case checking FDS code*/
#define MAX_CHECK   0xffff  /*defaults to NES code type*/
#define CHARTEST(c) ((c==0) || (c==';'))

char *tonext(char *string) {
    while(isspace(*string))
        string++;
    return string;
}

int main(int argc, char **argv) {
char tokens[MAX_SIZE], token[MAX_SIZE];
char token2;
char *cur = NULL;
int linecount, othertoken, temp, cflag;
FILE *file = NULL;
    if(argc < 2) {
        printf("addrchk <asm-file>\n");
        return 0;
    }
    if(argc > 2) {
        printf("addrchk <asm-file>\n");
        perror("Too many parameters!\n");
        return 1;
    }
    file = fopen(argv[1], "rt");
    if(file==NULL) {
        perror("Error opening file!\n");
        return 2;
    }
    linecount = 0;
    while(!feof(file)&&!ferror(file)) {
        tokens[0] = token[0] = token2 = 0;
        cur = tokens;
        linecount++;
        if(fgets(cur, MAX_SIZE, file)==NULL) break;
        do {
            cflag = 1;
            cur = tonext(cur); /*get pointer to next non-whitespace*/
            if(CHARTEST(*cur)) break; /*if comment, end, whatever*/
            sscanf(cur, "%s", token);
            cur += temp = strlen(token); /*push pointer forward*/
            if(CHARTEST(token[temp-1])) break;
            cflag = 0;  /*passed all tests for line*/
        } while(token[temp-1]==':'||token[0]=='@'); /*while still label references*/
        if(cflag) continue;
        if(*tonext(cur)=='=') /*if assignment*/ cur = tonext(cur) + 1;
        do {
            cflag = 1;
            cur = tonext(cur);
            if(CHARTEST(*cur)) break;
            sscanf(cur, "%s", token);
            cur += temp = strlen(token);
            othertoken = 0;
            sscanf(token, "%c%X", &token2, &othertoken); /*get value if available*/
            if(token2!='$') continue; /*not hex address reference*/
            if((othertoken < MIN_CHECK) || (othertoken > MAX_CHECK)) continue;
            cflag = 0; /*passed all checks*/
            break;
        } while(token[temp-1]==','); /* while there is one more item to be read */
        if(cflag) continue;
        /*output if passed:*/
        printf("Line #%i:\n\t%s\n", linecount, tokens);
    }
    fclose(file);
    printf("%i rainu yonda\n", linecount);
    printf("Zubari owaru deshou!\n\n");
    return 0;
}


^_^

by on (#23004)
doppelganger,

Basically, I think that for now all the addressing issues making it difficult to modularize the disassembly have been found. I think from the way you wrote the disassembly, the program should have found every instance where there was a bare address that was 0x8000 < x < 0x10000.

So, good job! :D

by on (#23005)
re: the loop command

I'm not sure, at this point, whether I commented the entry ".db $9645" as a dummy entry because it wasn't being used, or whether I did so because it didn't lead anywhere useful as far as the game was concerned...but I do see how that could cause problems in modularization. Fixed it.

re: the swim tile replacement offset

This isn't really a bug, per se, because it works perfectly fine for what I designed SMBDis for. However, seeing as how it will cause problems if the table is moved elsewhere, I went ahead and fixed it by simply modifying SwimTileRepOffset's definition. It will work fine as long as the player's graphics table isn't split up for whatever reason.

I don't really think the IRQ vector warrants fixing, since the game never uses IRQs.

Anyway, I fixed those two problems and uploaded it again. The link is still the same as it ever was.

by on (#23014)
doppelganger,

About the IRQ's and the ORG's, I understood those (they just appeared as output in the program). Basically, this was the program output:

Code:
Line #645:
        SwimTileRepOffset     = $eeb5

Line #669:
               .org $8000

Line #3525:
              .dw $9645 ;dummy entry

Line #16351:
              .dw $fff0  ;unused

16352 rainu yonda
Zubari owaru deshou!


Basically, it just spits it out and lets you decide what to do with it. (On my 366MHz computer, with it compiled into a Win32 Console with MinGW, it took less than a second to run.)

Anyway, now I think we can be pretty confident that this is modularizeable! ^_^

by on (#23044)
It should only be spitting out the ORG and the IRQ now that I updated it yesterday. That output looks like it was from before. I compiled your C code on Turbo C just now and ran it on smbdis.asm...it gave me this output...

Code:
Line #670:
               .org $8000

Line #16352:
              .dw $fff0  ;unused
16352 rainu yonda
Zubari owaru deshou!


And with that, modularization is indeed possible! :-)

by on (#23062)
And a thorough testing of the new build of the (modularized) game reveals no errors (though the minus world looks different--it looks like it uses 8-4's swimming stage now).

by on (#23063)
There's not much that can be done about that. Since I have yet to see exactly how you modularized it, I will have to assume you moved the levels' enemy and area data elsewhere, which would naturally cause the addresses to change...and since the game attempts to fetch data for world 36-1 in entry to the minus world (and finds it in one of the address tables), any address changes here may cause the minus world to be different.

However, considering the whole goddamned minus world is one big glitch, I'd say leave it be. :-P

by on (#23068)
doppelganger,

I was just bringing it up. It's not biggie.

Anyway, I guess now we should consider what we would do with this. LOL. ^_^

by on (#23072)
I can see a few goals ahead:
  1. Convert absolute addresses in $0000-$07FF to CA65 .res statements so that RAM can be modularized.
  2. Write a disassembler that takes the (copyrighted) ROM and spits out a modularized disassembly.
  3. Port it to UNROM/S*ROM/T*ROM. We'll have to decide what needs to be in the fixed bank and what needs to be in the switchable bank, so as to allow a hacker to add separate block types.
  4. Add features from SMB2J.
  5. Make a project to rewrite each module from scratch, like LAME.

by on (#23119)
The following 3 are both requests (If it is Possible) and/or ideas that I might do myself with is someday:

1: Recreate it for the SNES

(There was one for the Super Mario ALL*STARS but can NOT make a
seperate rom out of it yet. This is so that it is a fresh project instead of
making a rip-off!)

2. Possibly RE-Makeit for the PC.

(Then must rename SMB to SUPER PC BROS or something it so no copyright infrigment could not happen)

3. Create a DISassembler (could either be 1st or last) I am going to request the creator of DISTELLA (see link below) to give me the source
so I can create a recompileable ASM generetor for NES instead of the ATARI VCS/2600 (the OLD 1BPP graphic screen supported console)

*both NES and ATARI VCS/2600 are 6502 and is supported by DASM

Distella (6502 Disassembler for Atari programming in DASM) website:

http://members.cox.net/rcolbert1/distella.htm

Sorry if being a little off topic, but I just need to make a new NES
disassembler that is going to help more ROMhackers and NES developers!

-Hamtaro126

by on (#23144)
The short answer: No, we don't take requests here.
short answer
by on (#23208)
doppelganger wrote:
The short answer: No, we don't take requests here.
You know MARIO?

by on (#23257)
Quote:
2. Possibly RE-Makeit for the PC.

(Then must rename SMB to SUPER PC BROS or something it so no copyright infrigment could not happen)


Search for "Great Giana Sisters." Yup, no trouble with copyrights there!

Quote:
You know MARIO?


Mario who? The R&B singer? Can't say that I do, sorry. :lol:
Re: short answer
by on (#23258)
Bohan wrote:
You know MARIO?

Some time ago there was a widely known joke (a retarded one at that) here in Brazil that started with this exact question, but it makes no sense at all in english...

EDIT: Just to stay on topic: I think disassemblies are great to learn from (research), but I don't see the point in recoding the game...

by on (#23260)
The point in recoding the game from scratch piece by piece is to produce a Free game engine on which 100% legal homebrew NES side-scrollers can be built.

by on (#23262)
I don't know, maybe it's just me, but I don't believe in the reuse of side-scrolling engines... If a person does not know how to make their own, I doubt they can adapt one. And if they do know how to make one... well... I am against using code that isn't mine, but I guess some people don't mind...

by on (#23264)
tokumaru wrote:
I don't know, maybe it's just me, but I don't believe in the reuse of side-scrolling engines... If a person does not know how to make their own, I doubt they can adapt one.

Tell that to Lunar Magic users and their total conversions of Super Mario World.

by on (#23265)
To each his own, as I always say. This comprehensive disassembly is only for those who might be interested in how Super Mario Bros. works. It isn't going to create interest in disinterested people, and I don't expect it to. And this modularization effort beneficii has put forth is just one of many possible things that could offshoot from it.

by on (#23274)
I 100& agree with Tokumaru. I'm against using any code by anyone else if you don't understand it, and if you understand this then make your own because you should be able to do it.
Also, I'm for game engines being optimized to the particular game they're written for. The only reason to re-use a game engine as it would be to make a similar sequel or a different version a game. Quake fans will say the opposite, but since I'm 100% against Quake-like games I'm still coherent in my own ideas.

by on (#23275)
Bregalad wrote:
I'm against using any code by anyone else if you don't understand it, and if you understand this then make your own because you should be able to do it.

What operating system and what web browser have you written lately?

by on (#23278)
Stupid joke. I meant using code directly for your own project and without using it for learning purpose.

by on (#23296)
Heh, I guess Bregalad and I are a special case of "control freaks"... I'd never be able to call "mine" something I didn't know how it worked bit by bit. It's just not mine then. I'd like to be able to say in the end: "This is 100% mine".

It's like, I don't know, a person who decorates cakes, but can not bake one. If by any chance they are required to make a cake from the start, they'll not be able to. So they can't really say they know how to make cakes, although they may have finished many of them. Same thing happens with games, I guess.

Some people, however, are only interested in finishing games, and don't want to go through all the trouble of coding it all. I guess they are the target audience of such re-usable engines.

I don't think this is a bad thing, it's just not for me.

by on (#23306)
How would I edit it so that the fireflower doesn't use h-flipping for the right half of the sprite?

I really want to know this and I think an example of how to change something would help me a little.

by on (#23326)
doppelganger wrote:
Oh, goddamnit. These things are coming out of the woodwork.

Yeah, I went ahead and fixed that. Then I ran a complete check on every branch and jump in the file, and could find no others. But anyway, thanks again for finding those bugs.

My methodology was simple: I ran a disassembler on the program rom, then started at the beginning (reset vector) and traced out all the code. The first version of this file I uploaded was full of gaping code and data holes.

Anyway, sometimes I would trace out more code, sometimes I would go over the code with both FCEU and my intuition to figure out what the code did, and sometimes I did both at the same time. I was able to expedite the process of figuring out the level data format by comparing notes with others who had done SMB1 hacking in the past, and I was able to actually verify that, for the most part, their own ideas were correct. Some other parts, like enemy data, I had sparse information on. For the rest of the code, however, I was for the most part completely on my own.

It became fully functional (meaning it could be assembled) sometime in February I believe. But although it was filled with comments, it was almost completely devoid of labels. So I went back and replaced all the memory locations with addresses. Some of the values which would have led to confusion I replaced with constants. This was the part I call the clean-up phase. Still, I'm only human, and even I overlooked some of them, apparently.

Anyway, that's pretty much how I did it. It's not something that anyone else with a lot of free time and a shitload of patience couldn't do.


Actually, I'm curious, what did you do to add the labels? Did you just work them in manually, or did you have a program that added as you disassembled the code?

Additionally, what do you think of using a code data logger to help disassemble?

by on (#23342)
tokumaru wrote:
It's like, I don't know, a person who decorates cakes, but can not bake one. If by any chance they are required to make a cake from the start, they'll not be able to. So they can't really say they know how to make cakes, although they may have finished many of them. Same thing happens with games, I guess.

Yeah, but even someone who know to bake cakes needs some prior ingredients such as that poder made from cereals I have no idea how it's called in english, and you don't want to make your own each time you make a cake, because this would need your own field of weater and you'll have to cultivate it just to make poder from it to eventually bake cakes.

by on (#23346)
Powder made from grain/cereal is called flour, pronounced like "flower".
Re: short answer
by on (#23352)
tokumaru wrote:
Bohan wrote:
You know MARIO?

Some time ago there was a widely known joke (a retarded one at that) here in Brazil that started with this exact question, but it makes no sense at all in english...

EDIT: Just to stay on topic: I think disassemblies are great to learn from (research), but I don't see the point in recoding the game...

Mind repeating it in Portuguese? I'm just curious.

Also, I agree with you about code reuse and calling it your work, although limited code pasting can help for educational purposes (my first NES programs had chunks lifted from the MagicKit demo code, then over time I used that as a reference to figure out how everything worked.)
Re: short answer
by on (#23353)
commodorejohn wrote:
Mind repeating it in Portuguese? I'm just curious.

It's too stupid... so, I ask that any other brazilian members around forgive me for propagating something so stupid...

It goes something like:
-Conhece o Mario?
-Que Mario?
-Aquele que te comeu atrás do armário!

Which translates to:
-Do you know Mario? (kids used to ask other kids this question)
-What Mario? (this was the most likely answer)
-The one that banged you behind the closet! (the first kid, feeling so smart, replied with this)

It only "makes sense" because "armário" rhymes with "Mario"... Just search Google Images for "Conhece o Mario?" for some graphical renderings of this "joke". Those are somewhat funny.

Quote:
although limited code pasting can help for educational purposes

Sure, but I think people should understand exactly what goes on with a piece of code that was copied and pasted. If they don't, there might just be a case where this code misbehaves (when compared to their expectations) and they are just buying themselves some nasty bugs, while they could have coded something specifically tailored to their needs, and have no nasty surprises.
Re: short answer
by on (#23355)
tokumaru wrote:
It only "makes sense" because "armário" rhymes with "Mario"

This joke works in Spanish too, where "closet" is also armario. A variation might work in English:

-Do you know Hubbard?
-What Hubbard?
-The one that banged you behind the cupboard!

Quote:
I think people should understand exactly what goes on with a piece of code that was copied and pasted. If they don't, there might just be a case where this code misbehaves (when compared to their expectations) and they are just buying themselves some nasty bugs, while they could have coded something specifically tailored to their needs, and have no nasty surprises.

Code designed to be copied and pasted is called a library, and the ability of a piece of code to act as a library is called modularity. Yes, people who write libraries should state the pre- and post-conditions of each function (whether defined, implementation-defined, unspecified, or undefined), and people who use libraries should understand the pre- and post-conditions of each function and should not depend on any behavior that isn't defined. Otherwise, you get DLL hell when people depend on undocumented behaviors of the library.
Re: short answer
by on (#23356)
tepples wrote:
-Do you know Hubbard?

But I don't really know any Hubbard... Mario is famous! =) That, in fact, makes it hard for people to answer "What Mario?"... ¬¬! "Luigi's brother?" is a more common answer, I guess! =)

Quote:
Yes, people who write libraries should state the pre- and post-conditions of each function (whether defined, implementation-defined, unspecified, or undefined), and people who use libraries should understand the pre- and post-conditions of each function and should not depend on any behavior that isn't defined.

I get it. This makes a lot more sense in today's complicated architectures though... Which is one of the reasons I don't like to program for the PC anymore. It used to be really fun to program in DOS, but windows ruined it all.

Yeah, I'm a control freak, I want to know everything that goes on with my programs. I admit this is a personal issue, and I can acknowledge libraries (even for the NES) as useful things for people that don't want to (or can't) program the whole thing.
Re: short answer
by on (#23358)
tokumaru wrote:
commodorejohn wrote:
Mind repeating it in Portuguese? I'm just curious.

It's too stupid... so, I ask that any other brazilian members around forgive me for propagating something so stupid...

It goes something like:
-Conhece o Mario?
-Que Mario?
-Aquele que te comeu atrás do armário!

Which translates to:
-Do you know Mario? (kids used to ask other kids this question)
-What Mario? (this was the most likely answer)
-The one that banged you behind the closet! (the first kid, feeling so smart, replied with this)

It only "makes sense" because "armário" rhymes with "Mario"...

That's okay, English has loads of jokes like that =)
Although I find it a little odd that "comeu" is used as slang for that...I'm pretty sure that whatever the connection is, I don't want to know it.

by on (#23370)
beneficii wrote:
Actually, I'm curious, what did you do to add the labels? Did you just work them in manually, or did you have a program that added as you disassembled the code?

Additionally, what do you think of using a code data logger to help disassemble?


I worked them in manually. The only things I used were a text editor and a lot of cut and paste, and find and replace. My method was probably very slow and inefficient, but it was simple enough for my purposes. I wasn't trying to re-invent SMB, only figure out what made it tick.

A code data logger would probably only help as far as the actual reverse-engineering phase is concerned. But that can only speed up the process, so I'd be for it, I guess.

by on (#23468)
What exactly is a closet ? (just because I'm frustrated making no sense of this). So that I could build up a french version of the joke.

by on (#23470)
Bregalad wrote:
What exactly is a closet ?

Oh boy, I knew I shouldn't have said anything about the joke! >_<

Take a look at what the dictionary has to say. "Closet" seems to be more of a small room where you store clothes, but "armário" is more of a standalone, tall piece of furniture for the same purpose. I don't know, maybe "wardrobe" would be a better translation for "armário"?

I'm really really sorry for these latest messages about famous characters having sex behind furniture, it's just that when I saw the question "You know MARIO?" I couldn't avoid thinking about the joke. And I just realized that someone tried to do this in english already...

Sorry, sorry! Is it possible for the joke part of this thread to be split and moved to general stuff? We shouldn't be ruining the discussion about this great disassembly job...

by on (#23481)
It's difficult to split a topic that talks about subject A and digression B when almost every post that mentions B also mentions A.

by on (#23507)
I'll go ahead and post a french version of the joke (repacing Mario by Luigi so that it rhymes).

- Tu connais Luigi ?
- Quel Luigi ?
- Celui qui te frappe derriere l'armoire à habits.


... I still don't get much fun from it.

by on (#23508)
That's all well and good, except in the middle of digression B I think you guys forgot what subject A is. :-P

by on (#23510)
So will the RAM use of this SMB1 disassembly be modularized (e.g. to ".res" statements in segment BSS), or not?

by on (#23512)
I'm not doing it. Too busy right now. And probably for the next few months. Why don't you do it?

by on (#23513)
I'll take a look at it.

EDIT: Now that I look at the RAM map on datacrystal, it doesn't appear as complete as this one.

by on (#23525)
k nevermind. You could at least say "no".

by on (#23532)
I get the feeling we missed something.

<goes over thread again>

Are you referring to this:

CKY-2K/Clay Man wrote:
How would I edit it so that the fireflower doesn't use h-flipping for the right half of the sprite?

I really want to know this and I think an example of how to change something would help me a little.


or something else?

re: that, the only thing you really have to do is change the branch the game uses when it finds a fire flower to go elsewhere, like so...

This is the way it looks normally:
Code:
        ldx $00
        dex                        ;check power-up type for fire flower
        beq FlipPUpRightSide       ;if found, skip this part
        sta Sprite_Attributes+8,y  ;otherwise set new palette bits  for bottom left
        sta Sprite_Attributes+12,y ;and bottom right sprites as well for star only

This is what you would do if you wanted to stop the fire flower from horizontally flipping on the right side:
Code:

        ldx $00
        dex                        ;check power-up type for fire flower
        beq PUpOfs       <--- change third line to this
        sta Sprite_Attributes+8,y  ;otherwise set new palette bits  for bottom left
        sta Sprite_Attributes+12,y ;and bottom right sprites as well for star only


Doing this will cause the game to skip the horizontal flip part of the power-up graphics handler used to flip fire flowers and stars and go straight to offscreen handling instead. It will still flip star power-ups, due to the condition checking.

You should bear in mind, though, that the fire flower will probably look messed up unless you change the graphics.

by on (#23537)
Yeah, thanks man!

Thanks to your asm I could make these neat pipes for my project.

Image

by on (#23611)
I have a question: Is the SpriteShuffler subroutine the one that deals with the can't have more than 8 sprites on a scanline problem? I'm not sure I entirely understand it.

by on (#23614)
Yes. It effectively shuffles around in memory which sprites get used for enemy, fireball, air bubble, block and misc objects so that one sprite object never stays in either a low or high-numbered sprite set for longer than a frame. The sprite offsets get shuffled every NMI (long, long after the DMA of sprite data to OAM), and all the sprite Y positions in the sprite data (except sprite #0) are moved offscreen by default. The sprite data is written to $0200-$02ff, and only the sprites actually being used are assigned onscreen Y positions. Then the sprite data is used on the next frame upon NMI.

The only sprites that do not get shuffled are the sprites used by the player (right after sprite #0), and sprite #0. I think the reasons are obvious.

I believe the whole thing about lower-numbered sprites overlapping higher-numbered ones is merely symptomatic of the rendering order of the sprite evaluation mid-scanline, and this may play some part in which sprites appear on the screen with the 8 sprites per scanline limitation. My knowledge of the NES PPU is not perfect, however.

by on (#23772)
Hmm, just as a let you know, I am trying to do the same thing you did for SMB2J. With your permission, I'm more or less copy-and-pasting a lot of your disassembly into this one, as I am noticing (especially with regards to direct interaction with the PPU and the joypads) a lot of the code is more or less the same (the UpdateScreen function for example I notice is exactly the same). I'm also stealing your label names for cross-compatibility as the two games are so similar. :p

I hope that's OK.

Now, this game has different "files" on the disk, and when it gets to certain points (World 5, the Princess/World 9, and World A), it loads a new file over on top of some of the old one (because there is not enough room for all of the data). I'm not sure if some of the functions are used multiple times yet (I'm just working on the "SM2MAIN " file for right now), but there are some interesting things. The "JumpEngine" is there, and they've got an interesting function for loading files, which I was spending time working up:

Code:
;starting at MEM address $C0CA

ChkNumFiles:
   tya
   ldy $07F7  ;current loadlist to use
   cmp NumFiles,Y
   rts

VerificationData:
    .byte $01
   .byte $53, $4D, $42, $20 ;"SMB "
   .byte $00, $00, $00, $00, $00

LoadList_Low:
   .byte <LoadList1, <LoadList2, <LoadList3, <LoadList4
   
LoadList_High:
   .byte >LoadList1, >LoadList2, >LoadList3, >LoadList4
   
LoadList1:
    .byte $01, $05, $0F     ;char data, main program (this and worlds 1-4), save
    .byte $FF               ;terminator
   
LoadList2:
   .byte $20               ;program part 2 (worlds 5-8)
    .byte $FF
   
LoadList3:   
   .byte $10, $30, $0F     ;princess char data, data 3 (princess and world 9), save
    .byte $FF
   
LoadList4:
   .byte $40               ;data 4 (worlds a-d)
    .byte $FF
   
NumFiles:
   .byte $03               ;loadlist1
   .byte $01               ;loadlist2
   .byte $03               ;loadlist3
   .byte $01               ;loadlist4

LoadFiles:
   ldx $07F7               ;current loadlist to use
   lda LoadList_Low,X
   sta LoadList
   lda LoadList_High,X
   sta LoadList+1
   jsr $E1F8      ;FDS_LoadFiles

DiskID:
   .addr VerificationData
LoadList:
   .addr LoadList1      ;rw (this gets written to)
   rts


This is all FDS-specific, but I think I am starting to make progress on it. ^_^

by on (#23885)
Well, good luck with that. I don't really mind if you use smbdis.asm to do smb2j, just as long as you give credit where it's due.

How are you going to organize this? Will it be by the files themselves?

by on (#23888)
doppelganger,

It would seem to make the most sense. Perhaps to avoid copyright issues, I should make people have to get a hold of the CHR data themselves.

Other than that, it seems like it's a pretty long task. ^_^ How long did it take you again? :D

EDIT: Though the RAM addresses are almost completely the same, there are some differences:

Code:
DisplayDigits         = $07d7
TopScoreDisplay       = $07d7
ScoreAndCoinDisplay   = $07dd
PlayerScoreDisplay    = $07dd
GameTimerDisplay      = $07ec
DigitModifier         = $0134

FDS_WaitCycles        = $077b  ; currently waiting for IRQ
CurrentLoadList       = $07f7  ; current files to load
World9Check           = $07fa  ; if set to #$ff, then meets qualifications for world 9
LetterWorld           = $07fb  ; currently in worlds a-d if set


They got rid of the second player's score display and moved the GameTimerDisplay up, and that made room for the current load list and the A-D check.

The UpdateTopScore function was slightly changed due to this:

Code:
UpdateTopScore:
   ldx #$05
   ldy #$05
   sec
GetScoreDiff:
   lda PlayerScoreDisplay,X
   sbc TopScoreDisplay,Y
   dex
   dey
   bpl GetScoreDiff
   bcc NoTopSc
   inx
   iny
CopyScore:
   lda PlayerScoreDisplay,X
   sta TopScoreDisplay,Y
   inx
   iny
   cpy #$06
   bcc CopyScore
NoTopSc:   
   rts


And here are the offsets, with World 9 added:

Code:
WorldAddrOffsets:
   .byte World1Areas-AreaAddrOffsets, World2Areas-AreaAddrOffsets
   .byte World3Areas-AreaAddrOffsets, World4Areas-AreaAddrOffsets
   .byte World5Areas-AreaAddrOffsets, World6Areas-AreaAddrOffsets
   .byte World7Areas-AreaAddrOffsets, World8Areas-AreaAddrOffsets
   .byte World9Areas-AreaAddrOffsets
; see "SM2DATA4" for worlds A-D
   
AreaAddrOffsets:
World1Areas:
   .byte $20, $29, $40, $21, $60
   
World2Areas:
   .byte $22, $23, $24, $61

World3Areas:
   .byte $25, $29, $00, $26, $62

World4Areas:
   .byte $27, $28, $2A, $63

World5Areas:
   .byte $2B, $29, $43, $2C, $64
   
World6Areas:
   .byte $2D, $29, $01, $2E, $65
   
World7Areas:
   .byte $2F, $30, $31, $66
   
World8Areas:
   .byte $32, $35, $36, $67
   
World9Areas:
   .byte $38, $06, $68, $07

by on (#23891)
beneficii wrote:
doppelganger,

It would seem to make the most sense. Perhaps to avoid copyright issues, I should make people have to get a hold of the CHR data themselves.

Other than that, it seems like it's a pretty long task. ^_^ How long did it take you again? :D

EDIT: Though the RAM addresses are almost completely the same, there are some differences:

Umm, removed the code here so it wouldn't clog the forum unnecessarily.



Re: the CHR data, that's what I did. But then again, it was all neatly tucked away in a CHR-ROM. You would probably need to make notes on where CHR data was stored depending on how haphazardly it's stored on the disk (or disk image).

Re: how long it took me, I'd say it took me about four months to do the actual reverse-engineering, then a few weeks for the clean-up phase (I tend to work slowly). But what you have to bear in mind is that I did most of the work on SMB on my own (level data format, I had some help with, was able to verify the work others did on it).

It was pretty clever of them to use the extra space where player 2's score would have been for that. Perhaps the data at $0761-$0767 also got used for a different purpose? Perhaps not, but that's something to speculate on. Anyway it looks like your efforts are coming along nicely. :-)

by on (#23901)

by on (#23903)
loopy,

Interesting. One thing I noticed though, is that starting with World 4, the right-side up Pirhana plants did not change to red. In fact only the upside down Pirhana plants did. Did you take it out?

Still, very useful to distinguish between what's code and not. What was your methodology for the conversion?

by on (#23906)

by on (#23919)
doppelganger wrote:
beneficii wrote:
doppelganger,

It would seem to make the most sense. Perhaps to avoid copyright issues, I should make people have to get a hold of the CHR data themselves.

Other than that, it seems like it's a pretty long task. ^_^ How long did it take you again? :D

EDIT: Though the RAM addresses are almost completely the same, there are some differences:

Umm, removed the code here so it wouldn't clog the forum unnecessarily.



Re: the CHR data, that's what I did. But then again, it was all neatly tucked away in a CHR-ROM. You would probably need to make notes on where CHR data was stored depending on how haphazardly it's stored on the disk (or disk image).

Re: how long it took me, I'd say it took me about four months to do the actual reverse-engineering, then a few weeks for the clean-up phase (I tend to work slowly). But what you have to bear in mind is that I did most of the work on SMB on my own (level data format, I had some help with, was able to verify the work others did on it).

It was pretty clever of them to use the extra space where player 2's score would have been for that. Perhaps the data at $0761-$0767 also got used for a different purpose? Perhaps not, but that's something to speculate on. Anyway it looks like your efforts are coming along nicely. :-)


Re: CHR data, I've already mapped it out. It wasn't scattered all over the disk: Just stored in two files "SM2CHAR1" and "SM2CHAR2". The first file is from the range $0000-$1fff and is the full file more or less; the second file is just from the range $0760-$079f and contains the data for the Princess, replacing the door to the Princess's room data in the first file.

If you don't mind me using your stuff and loopy doesn't mind me using his stuff as bases for this, then perhaps it could be done a bit quicker. Right now, I'm just going a bit here and a bit there, as I haven't really come up with a good system (and probably won't) for putting this all on. I checked the "bankx" asm files in Loopy's NES implementation and they seem to resemble for each of the files the whole $C000-$DFFF range in the PRG-RAM. Part of this project is tracing out things and seeing how they work, then marking it in a memory map to see how it's done, so I can change it later; another part is reading through doppelganger's SMB1 disassembly and trying to find similar pieces of code in this game. Maybe by June-ish, I will get it done?

Regarding player 2 data, as far as I know, the space (in RAM) from $0761-$0767 is not used in anyway in SMB2J.

by on (#23920)
(Sorry for the double post, for some reason edit button isn't working.)

Here is the code I used to "break apart" and analyze the FDS file so to speak:

http://nesdev.com/bbs/viewtopic.php?t=3203

by on (#23921)
after you design the smb2k dissasembly, maybe you can create a recompilation that will work in a cart without any issues (althought i have loopy's smb2j on a cart currently). that way there aren't the red pirhana bugs and stuff like that.

-DanSS

by on (#23923)
daniel,

Daniel Boik I presume? Regarding the red pirhana plant issue, that was the only issue I noticed with the game (aside from the decreased sound quality of the ending theme, but that's because the NES can't support as good sound quality as the FDS), and I think I have a way of fixing it. ^_^

by on (#23924)
beneficii wrote:
daniel,

Daniel Boik I presume? [...]


nope, not me, but that's okay.

I usually hang out in the nesdev irc channel under DanSS.

I was just curious if you'd be doing a recompile for carts, thats all

by on (#23926)
OK, regardless, I fixed the red piranha plant issue. And sigh, since there seems to be no easy way to upload this to the server, you can get it here. Extract it to a folder and run make.bat:

http://www.geocities.com/beneficii/smb2jsrc.zip

It was a bit to fix, though I only had to change 6000.asm. Basically, the original game would write to the PRG-RAM in a weird way. It wrote to 2 places:

B517

and

9FFE

B517 is part of a table that gets loaded (though the game checks that value specially) and 9FFE is part of the instruction at 9FFD: CMP #$21 (which gets to CMP #$13 when it's time to do the red plants). Basically, I created 2 new variables at $51 and $50: oldb517 and old9ffe (which can be found declared at the top of the 6000.asm file). I just did a whole bunch of redirecting to those 2 variables. It appears that in the normal course of the game $50 and $51 don't really get written to, and I've tested it through, but I could still get surprised. So the purpose is to make it easily modifiable. It needs to be somewhere on the zeropage for space reasons.

by on (#23927)

by on (#23949)
So this is compatable with Pocketnes, and the world select thing and plant bug is now fixed?

by on (#23951)
If it works in Nintendulator, then the defect is in PocketNES.

Now is there a way that I can take the original .fds file and turn it into the MMC3 version?

by on (#23955)
tepples,

Did you not see loopy's page?

loopy,

One other problem that I noticed (I couldn't notice any others) that's really minor: That jumpsprings in worlds that allow very high jumping are green, not red. In this NES port, they are red in all cases. I'm still trying to figure out exactly how the FDS version turns them green in the first place, and why it doesn't work in the NES port. (It's probably the same as the pirhana plant problem, and issue with writing to PRG-RAM, which doesn't exist on the NES except for the pseudo PRG-RAM at $6000-$7fff set up by this port.

by on (#24349)
On loopy's new SMB2J thing, does it give you those stars for each time you beat the game without warping like on the FDS version?

Where if you have 8 you can access world A-D I think?

Also would it be possible to add that triangle wave skidding sound to the original SMB?

by on (#24781)
How many bytes of code are there in SMB ?
That will give me an idea about the amount of work needed to disassemble (and comment) Super Mario Kart (SNES) :

Code : 68867 bytes : 13.1 %
Data : 437495 bytes : 83.4 %
Mixed : 1830 bytes : 0.3 %
Unknown : 16096 bytes : 3.1 %

Total : 524288 bytes : 100.0 %

by on (#25181)
HEY does anyone know where the address is to change the duration of what a second is in the timer?

by on (#25182)
The relevant RAM location:
Code:
GameTimerCtrlTimer    = $0787


The code that writes a value to it:
Code:
ResGTCtrl: lda #$18                   ;reset game timer control
           sta GameTimerCtrlTimer

So put a watch on $0787 to find code like this.

by on (#25186)
Two ASM questions:

How do you make the Goomba use 2 animation frames?

and

How can you make Mario use extended animation frames while running?(like Sonic the Hedgehog)

by on (#25192)
I ment the HEX address of the file. I found it though. I wanted to correct the timer to an actual second.

If you wanna know what it is search the value 18 thoughout the file.
It's over the 1000th address I know for sure.

But now another question, how could I make the second digit loop back to the number 5 instead of 9?

by on (#25273)
CKY-2K/Clay Man wrote:
I ment the HEX address of the file. I found it though. I wanted to correct the timer to an actual second.

If you wanna know what it is search the value 18 thoughout the file.
It's over the 1000th address I know for sure.

But now another question, how could I make the second digit loop back to the number 5 instead of 9?


I suppose you could check to see if, before subtracting 1 from the game timer, the second and last digits of the game timer are set to 0. If they are, you'd have to set the digit modifiers to subtract 4 from the second digit and 1 from the last digit, thus making it 59 instead of 99.

I'll leave it up to you to figure out how to make room for that.

by on (#25607)
CKY-2K/Clay Man wrote:
Also would it be possible to add that triangle wave skidding sound to the original SMB?


Anything is possible if you have room for it, if you catch my drift.

Seriously though, if you consider adding the triangle wave skidding sound to SMB, I would suggest adding it to the third sfx engine (the one that handles noise channel sfx), and putting a JSR in between the conditional check for the skidding sound and the noise bit checking, so they work autonomously.

by on (#25613)
And you have room for anything if you're willing to expand SMB1 to UNROM. Heck, that way, you could probably put SMB1 and the Lost Levels into one huge 20-world adventure.

by on (#25624)
That would rock.

by on (#25631)
I need help with the PlayerEndLevel branch.

I want it to skip the stuff that checks if your player collided with the castle brick and the part that makes mario behind the background, but instead start doing the score time total as soon as you leave the flag, so it appears that you are walking to the next level.

by on (#25854)
You want to have the time count down as soon as the player leaves the flag to make it appear as though the player is walking to the next level? And you want to eliminate the brick that keeps the player from walking endlessly? But how would you explain the discontinuity between levels (an endless plain in one level and the castle appearing at the beginning of the next level)? And what about the fireworks?

by on (#25862)
doppelganger wrote:
You want to have the time count down as soon as the player leaves the flag to make it appear as though the player is walking to the next level?

In fact, counting down the time could be done while the flag is being lowered, especially if it counts the ones, tens, and hundreds digits separately like Super Mario Bros. 3 does.

Quote:
And you want to eliminate the brick that keeps the player from walking endlessly?

As I understand it, we want to leave the brick there (to trigger the next level), but don't hide Mario's sprite and don't show the black screen with "WORLD 1-2" after act breaks. Super Mario Bros. as it stands has a structure like that of the later Sonic the Hedgehog and Sonic 2 for Genesis, which fade to black between acts; hacker wants to approximate Sonic 3.

Quote:
And what about the fireworks?

Can those be done during the timer countdown?

by on (#29369)
doppelganger wrote:
You want to have the time count down as soon as the player leaves the flag to make it appear as though the player is walking to the next level?

tepples wrote:
In fact, counting down the time could be done while the flag is being lowered, especially if it counts the ones, tens, and hundreds digits separately like Super Mario Bros. 3 does.


That would require a rewrite of AwardGameTimerPoints, which is one of the many subroutines run by the star flag object ($31). As for doing it as soon as the player touches the flagpole, I believe that would require some modification to the PlayerEndLevel subroutine...the game timer doesn't actually count down until the star flag object code is activated...and the star flag object code doesn't actually activate until the player object collides with the brick in front of the castle entrance.

doppelganger wrote:
And you want to eliminate the brick that keeps the player from walking endlessly?

tepples wrote:
As I understand it, we want to leave the brick there (to trigger the next level), but don't hide Mario's sprite and don't show the black screen with "WORLD 1-2" after act breaks. Super Mario Bros. as it stands has a structure like that of the later Sonic the Hedgehog and Sonic 2 for Genesis, which fade to black between acts; hacker wants to approximate Sonic 3.


Hoo boy. This would require some significant change in the way the game handles starting a new area, as well as a little modification to the actual game area data (taking out the castle object at the beginning of many areas comes to mind). The transition from levels -3 to the castle levels in -4 would also have to be taken into consideration, although if I were implementing a hack like this, I would do it the regular way between levels -3 and -4.

doppelganger wrote:
And what about the fireworks?

tepples wrote:
Can those be done during the timer countdown?


Perhaps by moving the fireworks code in RaiseFlagSetoffFWorks (which starts at the label SetOffF) to somewhere in AwardGameTimerPoints, it could be done (also you'd have to send that branch to SetOffF to DrawStarFlag instead). Though you would then have to deal with how to separate the timer tick sound from the fireworks/gunfire sound, since they both play on the same sound engine and channel.

Sorry it took me so long to reply to this, but I haven't looked at my own disassembly for a while, and, well, you know how it is when you haven't looked at your own work for a while. Needless to say, by now it should be obvious that some hacks to SMB will be harder to implement than others.

by on (#34702)
Does anyone have the area data offsets for Worlds A to D in regards to the SMB2J disassembly guide?

~Ben

by on (#34726)
I really have a problem with disabling the SPRITE 0 code. It seems that if I do that, I either get Corruption of the screen and palettes, Sprites not deleteing properly, and shaking/flickering from the status bar. I have been trying to get an MMC3 IRQ routine working. But It won't act right without Sprite 0 being disabled

There is One hack - Mario VS Airman (by ATA, get from acmlm.kafuka.org). There is also SMB2j MMC3. I tried. Both of them failed

by on (#34732)
I made a hack to SMB using Dopple's doc, but my sights were aimed very low - changed the byte at $D12B to 0 to make Bowser throw hammers in world 1-5 (which works, but his flames often break the sprite limit and vanish).

by on (#34777)
Hamtaro126 wrote:
I really have a problem with disabling the SPRITE 0 code. It seems that if I do that, I either get Corruption of the screen and palettes, Sprites not deleteing properly, and shaking/flickering from the status bar. I have been trying to get an MMC3 IRQ routine working. But It won't act right without Sprite 0 being disabled

There is One hack - Mario VS Airman (by ATA, get from acmlm.kafuka.org). There is also SMB2j MMC3. I tried. Both of them failed


Just For a Reminder.

-Hamtaro126

by on (#34834)
I have no idea what you're trying to do, Hamtaro126, and I'm not sure I want to, either. And by the way, reposting the same information that is only located two posts away makes you look VERY stupid.

by on (#34837)
He's trying to get a screen split in SMB1 using MMC3's IRQ, rather than sprite zero hit. "Reminder" is just his way of saying "someone do it for me."

by on (#34838)
doppelganger wrote:
I have no idea what you're trying to do, Hamtaro126, and I'm not sure I want to, either. And by the way, reposting the same information that is only located two posts away makes you look VERY stupid.


Sorry, Can you please look to see if you can remove sprite 0 for me. I have tried very hard.

And Another thing:

;-------------------------------------------------------------------------------------
;$00 - temp vram buffer offset
;$01 - temp metatile buffer offset
;$02 - temp metatile graphics table offset
;$03 - used to store attribute bits
;$04 - used to determine attribute table row
;$05 - used to determine attribute table column
;$06 - metatile graphics table address low
;$07 - metatile graphics table address high

; Insert Attributes for New Engine Below

Attributes:
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF

RenderAreaGraphics:
lda CurrentColumnPos ;store LSB of where we're at
and #$01
sta $05
ldy VRAM_Buffer2_Offset ;store vram buffer offset
sty $00
lda CurrentNTAddr_Low ;get current name table address we're supposed to render
sta VRAM_Buffer2+1,y
lda CurrentNTAddr_High
sta VRAM_Buffer2,y
lda #$9a ;store length byte of 26 here with d7 set
sta VRAM_Buffer2+2,y ;to increment by 32 (in columns)
lda #$00 ;init attribute row
sta $04
tax
DrawMTLoop: stx $01 ;store init value of 0 or incremented offset for buffer
lda MetatileBuffer,x
and #%11000000
sta $03
asl ;note that metatile format is:
rol ;%xx000000 - attribute table bits,
rol ;%00xxxxxx - metatile number
tay ;rotate bits to d1-d0 and use as offset here
lda MetatileGraphics_Low,y ;get address to graphics table from here
sta $06
lda MetatileGraphics_High,y
sta $07
lda Attributes,y
sta $03
lda MetatileBuffer,x ;get metatile number again
asl ;multiply by 4 and use as tile offset
asl
sta $02
lda AreaParserTaskNum ;get current task number for level processing and
and #%00000001 ;mask out all but LSB, then invert LSB, multiply by 2
eor #%00000001 ;to get the correct column position in the metatile,
asl ;then add to the tile offset so we can draw either side
adc $02 ;of the metatiles
tay
ldx $00 ;use vram buffer offset from before as X
lda ($06),y
sta VRAM_Buffer2+3,x ;get first tile number (top left or top right) and store
iny
lda ($06),y ;now get the second (bottom left or bottom right) and store
sta VRAM_Buffer2+4,x
ldy $04 ;get current attribute row
lda $05 ;get LSB of current column where we're at, and
bne RightCheck ;branch if set (clear = left attrib, set = right)
lda $01 ;get current row we're rendering
lsr ;branch if LSB set (clear = top left, set = bottom left)
bcs LLeft
rol $03 ;rotate attribute bits 3 to the left
rol $03 ;thus in d1-d0, for upper left square
rol $03
jmp SetAttrib
RightCheck: lda $01 ;get LSB of current row we're rendering
lsr ;branch if set (clear = top right, set = bottom right)
bcs NextMTRow
lsr $03 ;shift attribute bits 4 to the right
lsr $03 ;thus in d3-d2, for upper right square
lsr $03
lsr $03
jmp SetAttrib
LLeft: lsr $03 ;shift attribute bits 2 to the right
lsr $03 ;thus in d5-d4 for lower left square
NextMTRow: inc $04 ;move onto next attribute row
SetAttrib: lda AttributeBuffer,y ;get previously saved bits from before
ora $03
sta AttributeBuffer,y ;the old, and store
inc $00 ;increment vram buffer offset by 2
inc $00
ldx $01 ;get current gfx buffer row, and check for
inx ;the bottom of the screen
cpx #$0d
bcc DrawMTLoop ;if not there yet, loop back
ldy $00 ;get current vram buffer offset, increment by 3
iny ;(for name table address and length bytes)
iny
iny
lda #$00
sta VRAM_Buffer2,y ;put null terminator at end of data for name table
sty VRAM_Buffer2_Offset ;store new buffer offset
inc CurrentNTAddr_Low ;increment name table address low
lda CurrentNTAddr_Low ;check current low byte
and #%00011111 ;if no wraparound, just skip this part
bne ExitDrawM
lda #$80 ;if wraparound occurs, make sure low byte stays
sta CurrentNTAddr_Low ;just under the status bar
lda CurrentNTAddr_High ;and then invert d2 of the name table address high
eor #%00000100 ;to move onto the next appropriate name table
sta CurrentNTAddr_High
ExitDrawM: jmp SetVRAMCtrl ;jump to set buffer to $0341 and leave


I made the new Attribute engine partly working. But It doesn't let all the attributes in. There is only one attribute working right now!

The Format should be 00,55,AA,FF, Representing a 16x16 metatile

by on (#34851)
<sigh>...some people just never learn.

by on (#34853)
doppelganger wrote:
<sigh>...some people just never learn.


I guess sprite 0 will stay forever, I just tried removing it for over a year now. Sprite 0 is really a pain :x

I still need help with the above routine, Please?

by on (#34864)
Have you tried making a split screen demo from scratch using your own graphics? And why do you want to get SMB working without sprite 0?

-It's how the game times its updates
-It was designed from the ground up to work this way
-When you waste a lot of time not getting something done, it's best to move on to something doable

by on (#34869)
First find a free memory address in RAM. Have the vblank code clear it to 0 when it sets up the status bar scrolling, and then have the MMC3 IRQ routine set it to 0x40. Finally, make the sprite 0 wait routine spin on that address instead of PPUSTATUS.

by on (#34873)
tepples wrote:
First find a free memory address in RAM. Have the vblank code clear it to 0 when it sets up the status bar scrolling, and then have the MMC3 IRQ routine set it to 0x40. Finally, make the sprite 0 wait routine spin on that address instead of PPUSTATUS.


YES! It worked!

Thank you so much :D

by on (#34889)
tepples wrote:
MMC3 IRQ routine


Hamtaro126 wrote:
YES! It worked!


Now I'm really confused. What just happened, and/or did I miss or forget something from earlier in the thread?

by on (#34900)
As far as I can tell, Hamtaro126 was trying to convert SMB1 from NROM to T*ROM, and one of the steps apparently included changing from a sprite 0 based screen split to an MMC3 IRQ based screen split. So I explained how to make the MMC3 IRQ simulate a sprite 0 hit.

by on (#41562)
(a man steps out of the shadows and enters the room)

Where were all you guys when I first started the SMB Hacking Project????

I must say, doppelganger, I don't why you wouldn't use my code as a base (well I do....), but I'm impressed and glad that somebody final figured everything out. Although I wish your code would explain how certain sections worked in depth or made some narration as to the going on's in the code instead of having every stinking line commented. :) Really, I'm just a wee bit jealous. But hey, thanks for giving me credit!

I just recently started looking at my project just a few days ago after years of being buried on my hard drive, and was amazed how easy it was to pick up right where I left off... A couple of years ago, I did a bunch of work on it, but never got around to uploading it.

A little background for those who are curious:

The project was first started back in '99. There were a bunch of reasons for starting it. I had recently gotten into reverse engineering and wanted a reasonably sized project to work with. I was also into game development both of the PC and the NES. Mario became the prime choice for in-depth study. I stumbled across a disassembler which would trace through the code exposing as much as it could which worked perfectly for this project. It took about 4 or 5 iterations before I had enough of a symbol table to expose and separate all the code and data. I tried to get some community help, but only three people ever ended up taking interest in the project. I got tired hit a small stumbling block and gave up mainly because of all the little side projects I had started along the way :) (Mario for the Apple ][, Mario for the PC, a better disassembler, a better assembler, my own NES game, several PC games, etc... typical ADD) that and it was time for college! I only touched the code a little during college in which I made it able to compile in NESasm, and then again only recently.

And that is the story... *coming soon to a theater near you*

It is probably one of the most interesting pieces of code ever written.

It's good to see the project reincarnated.

by on (#41600)
I don't deny that I could have done certain things better (commenting every line seems to be a common pet peeve) and explained things a bit more in-depth...but what you have to realize is that this was my first ever reverse-engineering work, and it was written back when I was still somewhat wet behind the ears concerning coding techniques in games. I've gotten a little older and wiser since then. If and when time permits, I might consider updating it...

by on (#41606)
Changing the RAM mapping from EQU-style (specifying each RAM label's address individually) to RES-style (allocating most stuff out of a BSS segment) might help. That way, people could rearrange the RAM to keep related data together or change the size of some buffers.
Re: comprehensive SMB1 disassembly
by on (#103212)
ca65 style .res memory layout:

Code:
.segment "ZEROPAGE"

temp_byte:                      .res  8 ; local  temp pointers and vars
ObjectOffset:                   .res  1
FrameCounter:                   .res  1
A_B_Buttons:                    .res  1
Up_Down_Buttons:                .res  1
Left_Right_Buttons:             .res  1
PreviousA_B_Buttons:            .res  1
GameEngineSubroutine:           .res  1
Enemy_Flag:                     .res  7
Enemy_ID :                      .res  7
Player_State:                   .res  1
Enemy_State:                    .res  6
Fireball_State:                 .res  2
Block_State:                    .res  4
Misc_State:                     .res  9
PlayerFacingDir:                .res  1
FirebarSpinDirection:
DestinationPageLoc:             .res  1
VictoryWalkControl:             .res  4
PowerUpType:                    .res  1
FireballBouncingFlag:           .res  2
HammerBroJumpTimer:             .res  9
Player_MovingDir:               .res  1
Enemy_MovingDir:                .res  17

SprObject_X_Speed:
Player_X_Speed:                 .res  1

Enemy_X_Speed:
LakituMoveSpeed:
PiranhaPlant_Y_Speed:
ExplosionGfxCounter:
Jumpspring_FixedYPos:
RedPTroopaCenterYPos:
BlooperMoveSpeed:
XMoveSecondaryCounter:
CheepCheepMoveMFlag:
FirebarSpinState_Low:
YPlatformCenterYPos:            .res 6

Fireball_X_Speed:               .res 2
Block_X_Speed:                  .res 4
Misc_X_Speed:                   .res 9

SprObject_PageLoc:
Player_PageLoc:                 .res  1

Enemy_PageLoc:                  .res  6
Fireball_PageLoc:               .res  2
Block_PageLoc:                  .res  4
Misc_PageLoc:                   .res  9
Bubble_PageLoc:                 .res  3

SprObject_X_Position:
Player_X_Position:              .res  1

Enemy_X_Position:               .res  6
Fireball_X_Position:            .res  2
Block_X_Position:               .res  4
Misc_X_Position:                .res  9
Bubble_X_Position:              .res  3

Player_Y_Speed:
SprObject_Y_Speed:              .res  1

FirebarSpinState_High:
XMovePrimaryCounter:
BlooperMoveCounter:
Enemy_Y_Speed:
LakituMoveDirection:
ExplosionTimerCounter:
PiranhaPlant_MoveFlag:          .res  6

Fireball_Y_Speed:               .res  2
Block_Y_Speed:                  .res  4
Misc_Y_Speed:                   .res  9

SprObject_Y_HighPos:
Player_Y_HighPos:               .res  1

Enemy_Y_HighPos:                .res  6
Fireball_Y_HighPos:             .res  2
Block_Y_HighPos:                .res  4
Misc_Y_HighPos:                 .res  9
Bubble_Y_HighPos:               .res  3

Player_Y_Position:
SprObject_Y_Position:           .res  1

Enemy_Y_Position:               .res  6
Fireball_Y_Position:            .res  2
Block_Y_Position:               .res  4
Misc_Y_Position:                .res  9
Bubble_Y_Position:              .res  3

AreaData:
AreaDataLow:                    .res  1

AreaDataHigh:                   .res  1

EnemyData:
EnemyDataLow:                   .res  1

EnemyDataHigh:                  .res  6
NoteLenLookupTblOfs:            .res  1
Square1SoundBuffer:             .res  1
Square2SoundBuffer:             .res  1
NoiseSoundBuffer:               .res  1
AreaMusicBuffer:                .res  1

MusicData:
MusicDataLow:                   .res  1

MusicDataHigh:                  .res  1
MusicOffset_Square2:            .res  1
MusicOffset_Square1:            .res  1
MusicOffset_Triangle:           .res  1
PauseSoundQueue:                .res  1
AreaMusicQueue:                 .res  1
EventMusicQueue:                .res  1
NoiseSoundQueue:                .res  1
Square2SoundQueue:              .res  1
Square1SoundQueue:              .res  1



.segment "STACK"
; start $0100

blank_stack:                    .res  9 ; not used
VerticalFlipFlag:               .res  4
FlagpoleFNum_Y_Pos:             .res  1
FlagpoleFNum_YMFDummy:          .res  1
FlagpoleScore:                  .res  1
FloateyNum_Control:             .res  7
FloateyNum_X_Pos:               .res  7
FloateyNum_Y_Pos:               .res  7
ShellChainCounter:              .res  7
FloateyNum_Timer:               .res  8
DigitModifier:                  .res  6


.segment "OAMRAM"
; start $0200

Sprite_Data:
Sprite_Y_Position:              .res  1
Sprite_Tilenumber:              .res  1
Sprite_Attributes:              .res  1
Sprite_X_Position:              .res  1

.segment "BSS"
; start $0300

VRAM_Buffer1_Offset:            .res  1
VRAM_Buffer1:                   .res  63
VRAM_Buffer2_Offset:            .res  1
VRAM_Buffer2:                   .res  34

BowserBodyControls:             .res  1
BowserFeetCounter:              .res  1
BowserMovementSpeed:            .res  1
BowserOrigXPos:                 .res  1
BowserFlameTimerCtrl:           .res  1
BowserFront_Offset:             .res  1
BridgeCollapseOffset:           .res  1
BowserGfxFlag:                  .res  30

FirebarSpinSpeed:               .res  16

VineFlagOffset:                 .res  1
VineHeight:                     .res  1
VineObjOffset:                  .res  3
VineStart_Y_Position:           .res  3

BalPlatformAlignment:           .res  1
Platform_X_Scroll:              .res  1

HammerThrowingTimer:
PlatformCollisionFlag:          .res  11

Player_Rel_XPos:
SprObject_Rel_XPos:             .res  1

Enemy_Rel_XPos:                 .res  1
Fireball_Rel_XPos:              .res  1
Bubble_Rel_XPos:                .res  1
Block_Rel_XPos:                 .res  2
Misc_Rel_XPos:                  .res  5
SprObject_Rel_YPos:
Player_Rel_YPos:                .res  1
Enemy_Rel_YPos:                 .res  1
Fireball_Rel_YPos:              .res  1
Bubble_Rel_YPos:                .res  1
Block_Rel_YPos:                 .res  2
Misc_Rel_YPos:                  .res  6

Player_SprAttrib:
SprObject_SprAttrib:            .res  1

Enemy_SprAttrib:                .res  11

SprObject_OffscrBits:
Player_OffscreenBits:           .res  1

Enemy_OffscreenBits:            .res  1
FBall_OffscreenBits:            .res  1
Bubble_OffscreenBits:           .res  1
Block_OffscreenBits:            .res  2
Misc_OffscreenBits:             .res  2
EnemyOffscrBitsMasked:          .res  12
Block_Orig_YPos:                .res  2
Block_BBuf_Low:                 .res  2
Block_Metatile:                 .res  2
Block_PageLoc2:                 .res  2
Block_RepFlag:                  .res  2
SprDataOffset_Ctrl:             .res  2
Block_ResidualCounter:          .res  1
Block_Orig_XPos:                .res  8
AttributeBuffer:                .res  7
SprObject_X_MoveForce:          .res  1

Enemy_X_MoveForce:
YPlatformTopYPos:
RedPTroopaOrigXPos:             .res  21

SprObject_YMF_Dummy:
Player_YMF_Dummy:               .res  1

Enemy_YMF_Dummy:
BowserFlamePRandomOfs:
PiranhaPlantUpYPos:             .res  21

Bubble_YMF_Dummy:               .res  7

Player_Y_MoveForce:
SprObject_Y_MoveForce:          .res  1

CheepCheepOrigYPos:
Enemy_Y_MoveForce:
PiranhaPlantDownYPos:           .res  8

Block_Y_MoveForce:              .res  20
MaximumLeftSpeed:               .res  6
MaximumRightSpeed:              .res  20

Whirlpool_Offset:
Cannon_Offset:                  .res  1

Whirlpool_PageLoc:
Cannon_PageLoc:                 .res  6

Cannon_X_Position:
Whirlpool_LeftExtent:           .res  6

Whirlpool_Length:
Cannon_Y_Position:              .res  6

Cannon_Timer:
Whirlpool_Flag:                 .res  6

BowserHitPoints:                .res  1
StompChainCounter:              .res  12
Player_CollisionBits:           .res  1
Enemy_CollisionBits:            .res  8

Player_BoundBoxCtrl:
SprObj_BoundBoxCtrl:            .res  1

Enemy_BoundBoxCtrl:             .res  6
Fireball_BoundBoxCtrl:          .res  2
Misc_BoundBoxCtrl:              .res  10

BoundingBox_UL_XPos:
BoundingBox_UL_Corner:          .res  1

BoundingBox_UL_YPos:            .res  1

BoundingBox_DR_XPos:
BoundingBox_LR_Corner:          .res  1

BoundingBox_DR_YPos:            .res  1
EnemyBoundingBoxCoord:          .res  80
Block_Buffer_1:                 .res  208
Block_Buffer_2:                 .res  208
BlockBufferColumnPos:           .res  1
MetatileBuffer:                 .res  13
HammerEnemyOffset:              .res  9
JumpCoinMiscOffset:             .res  5
BrickCoinTimerFlag:             .res  2
Misc_Collision_Flag:            .res  13
EnemyFrenzyBuffer:              .res  1
SecondaryHardMode:              .res  1
EnemyFrenzyQueue:               .res  1
FireballCounter:                .res  1
DuplicateObj_Offset:            .res  2
LakituReappearTimer:            .res  2
NumberofGroupEnemies:           .res  1
ColorRotateOffset:              .res  1
PlayerGfxOffset:                .res  1
WarpZoneControl:                .res  1
FireworksCounter:               .res  2
MultiLoopCorrectCntr:           .res  1
MultiLoopPassCntr:              .res  1
JumpspringForce:                .res  1
MaxRangeFromOrigin:             .res  1
BitMFilter:                     .res  1
ChangeAreaTimer:                .res  2
SprShuffleAmtOffset:            .res  1
SprShuffleAmt:                  .res  3

SprDataOffset:
Player_SprDataOffset:           .res  1

Enemy_SprDataOffset:            .res  7

Alt_SprDataOffset:
Block_SprDataOffset:            .res  2

Bubble_SprDataOffset:           .res  3
FBall_SprDataOffset:            .res  2
Misc_SprDataOffset:             .res  9

SavedJoypad1Bits:
SavedJoypadBits:                .res  1

SavedJoypad2Bits:               .res  2
Player_X_Scroll:                .res  1
Player_XSpeedAbsolute:          .res  1
FrictionAdderHigh:              .res  1
FrictionAdderLow:               .res  1
RunningSpeed:                   .res  1
SwimmingFlag:                   .res  1
Player_X_MoveForce:             .res  1
DiffToHaltJump:                 .res  1
JumpOrigin_Y_HighPos:           .res  1
JumpOrigin_Y_Position:          .res  1
VerticalForce:                  .res  1
VerticalForceDown:              .res  1
PlayerChangeSizeFlag:           .res  1
PlayerAnimTimerSet:             .res  1
PlayerAnimCtrl:                 .res  1
JumpspringAnimCtrl:             .res  1
FlagpoleCollisionYPos:          .res  1
PlayerEntranceCtrl:             .res  1
FireballThrowingTimer:          .res  1
DeathMusicLoaded:               .res  1
FlagpoleSoundQueue:             .res  1
CrouchingFlag:                  .res  1
GameTimerSetting:               .res  1
DisableCollisionDet:            .res  1
DemoAction:                     .res  1
DemoActionTimer:                .res  1
PrimaryMsgCounter:              .res  1

ScreenEdge_PageLoc:
ScreenLeft_PageLoc:             .res  1

ScreenRight_PageLoc:            .res  1

ScreenEdge_X_Pos:
ScreenLeft_X_Pos:               .res  1

ScreenRight_X_Pos:              .res  1
ColumnSets:                     .res  1
AreaParserTaskNum:              .res  1
CurrentNTAddr_High:             .res  1
CurrentNTAddr_Low:              .res  1
Sprite0HitDetectFlag:           .res  1
ScrollLock:                     .res  2
CurrentPageLoc:                 .res  1
CurrentColumnPos:               .res  1
TerrainControl:                 .res  1
BackloadingFlag:                .res  1
BehindAreaParserFlag:           .res  1
AreaObjectPageLoc:              .res  1
AreaObjectPageSel:              .res  1
AreaDataOffset:                 .res  1
AreaObjOffsetBuffer:            .res  3
AreaObjectLength:               .res  3
AreaStyle:                      .res  1
StaircaseControl:               .res  1
AreaObjectHeight:               .res  1
MushroomLedgeHalfLen:           .res  3
EnemyDataOffset:                .res  1
EnemyObjectPageLoc:             .res  1
EnemyObjectPageSel:             .res  1
ScreenRoutineTask:              .res  1
ScrollThirtyTwo:                .res  2
HorizontalScroll:               .res  1
VerticalScroll:                 .res  1
ForegroundScenery:              .res  1
BackgroundScenery:              .res  1
CloudTypeOverride:              .res  1
BackgroundColorCtrl:            .res  1
LoopCommand:                    .res  1
StarFlagTaskControl:            .res  1
TimerControl:                   .res  1
CoinTallyFor1Ups:               .res  1
SecondaryMsgCounter:            .res  1
JoypadBitMask:                  .res  4
AreaType:                       .res  1
AreaAddrsLOffset:               .res  1
AreaPointer:                    .res  1
EntrancePage:                   .res  1
AltEntranceControl:             .res  1
CurrentPlayer:                  .res  1
PlayerSize:                     .res  1
Player_Pos_ForScroll:           .res  1
PlayerStatus:                   .res  1
FetchNewGameTimerFlag:          .res  1
JoypadOverride:                 .res  1
GameTimerExpiredFlag:           .res  1

OnscreenPlayerInfo:
NumberofLives:                  .res  1

HalfwayPage:                    .res  1
LevelNumber:                    .res  1
Hidden1UpFlag:                  .res  1
CoinTally:                      .res  1
WorldNumber:                    .res  1
AreaNumber:                     .res  1

OffscreenPlayerInfo:
OffScr_NumberofLives:           .res  1

OffScr_HalfwayPage:             .res  1
OffScr_LevelNumber:             .res  1
OffScr_Hidden1UpFlag:           .res  1
OffScr_CoinTally:               .res  1
OffScr_WorldNumber:             .res  1
OffScr_AreaNumber:              .res  1
ScrollFractional:               .res  1
DisableIntermediate:            .res  1
PrimaryHardMode:                .res  1
WorldSelectNumber:              .res  5
OperMode:                       .res  2
OperMode_Task:                  .res  1
VRAM_Buffer_AddrCtrl:           .res  1
DisableScreenFlag:              .res  1
ScrollAmount:                   .res  1
GamePauseStatus:                .res  1
GamePauseTimer:                 .res  1
Mirror_PPU_CTRL:                .res  1
Mirror_PPU_MASK:                .res  1
NumberOfPlayers:                .res  5
IntervalTimerControl:           .res  1

Timers:
SelectTimer:                    .res  1
PlayerAnimTimer:                .res  1
JumpSwimTimer:                  .res  1
RunningTimer:                   .res  1
BlockBounceTimer:               .res  1
SideCollisionTimer:             .res  1
JumpspringTimer:                .res  1
GameTimerCtrlTimer:             .res  2
ClimbSideTimer:                 .res  1
EnemyFrameTimer:                .res  5
FrenzyEnemyTimer:               .res  1
BowserFireBreathTimer:          .res  1
StompTimer:                     .res  1
AirBubbleTimer:                 .res  3
ScrollIntervalTimer:            .res  1
EnemyIntervalTimer:             .res  7
BrickCoinTimer:                 .res  1
InjuryTimer:                    .res  1
StarInvincibleTimer:            .res  1
ScreenTimer:                    .res  1
WorldEndTimer:                  .res  1
DemoTimer:                      .res  5
PseudoRandomBitReg:             .res  9
MusicOffset_Noise:              .res  1
EventMusicBuffer:               .res  1
PauseSoundBuffer:               .res  1
Squ2_NoteLenBuffer:             .res  1
Squ2_NoteLenCounter:            .res  1
Squ2_EnvelopeDataCtrl:          .res  1
Squ1_NoteLenCounter:            .res  1
Squ1_EnvelopeDataCtrl:          .res  1
Tri_NoteLenBuffer:              .res  1
Tri_NoteLenCounter:             .res  1
Noise_BeatLenCounter:           .res  1
Squ1_SfxLenCounter:             .res  2
Squ2_SfxLenCounter:             .res  1
Sfx_SecondaryCounter:           .res  1
Noise_SfxLenCounter:            .res  1
DAC_Counter:                    .res  1
NoiseDataLoopbackOfs:           .res  3
NoteLengthTblAdder:             .res  1
AreaMusicBuffer_Alt:            .res  1
PauseModeFlag:                  .res  1
GroundMusicHeaderOfs:           .res  3
AltRegContentFlag:              .res  13

TopScoreDisplay:
DisplayDigits:                  .res  6

PlayerScoreDisplay:
ScoreAndCoinDisplay:            .res  27

GameTimerDisplay:               .res  4
WorldSelectEnableFlag:          .res  1
ContinueWorld:                  .res  2
WarmBootValidation:             .res  1



Some of the tabs are messed up, looks okay in my editor, but otherwise it should work. :)

Edit: Fixed tabs.
Re: comprehensive SMB1 disassembly
by on (#106884)
Read through the entire thing line by line and started to understand assembly (thanks to the comments, no way I would have otherwise), this is a huge effort and I greatly appreciate it, thanks doppelganger.

I wonder how much they changed the physics between SMB1 and SMB3, it's basically the same code with a lot more junk added, right?
Re: comprehensive SMB1 disassembly
by on (#106902)
Mario 3 feels different enough that it must have been recoded from scratch. Features like the P-meter would not have been easily integrated into the old code.

While taking a look at the AreaParser routines to understand them better, I started following the game in a debugger just to understand a variable called 'BackloadingFlag' (Which stores the page where the player respawns after dying past the checkpoint and is used to set the AreaData offset at the correct byte). This makes me a little tempted to really analyze the code and recomment it (Giving credit to the original reverse engineer, of course), mainly by breaking the code into subsystems and explaining the program flow and giving a more detailed explanation of the variables.
Re: comprehensive SMB1 disassembly
by on (#106913)
That would be cool. I'd like to see a breakdown of the hard-coded speed values and some pseudocode for the movement/physics routines for both SMB1 and SMB3 (perhaps the most popular and well-known platformers).

There are just too many bad mario clones out there because nobody knows how to get the movement right.
From reading the source, it isn't even very complicated.
Re: comprehensive SMB1 disassembly
by on (#106915)
Honestly, most clones that have horrible physics are like that because they don't bother implementing acceleration properly (or at all). Yes, gravity included (that's downwards acceleration). Seriously, it's so simple to implement it isn't fun how many games get it wrong. The other issue is control lag, which again I don't get (implementing lagless controls is easier and simpler, seriously o_O just react as soon as the input comes).
Re: comprehensive SMB1 disassembly
by on (#106916)
From what I can tell, SMB1 doesn't really have "correct" physics at all, just some hardcoded limits based on a modifier (if running faster than [magic number], jump [magic number] height) and arbitrary force values that clamp at a limit, probably whatever felt the best to the designers.

I actually went into thinking it was going to be some fairly complex physics equations but it looks like a bit of a hackjob to me.
Re: comprehensive SMB1 disassembly
by on (#106917)
I'm going to guess that you don't know how to program NES, but the reason the game doesn't have hugely complex physics is because the NES is a 1.78Mhz machine. Programming is an art. And putting a full sized physics equation to code doesn't mean it's better programmed at all, most people here would say it's worse. I know I would. That's one thing about programming games back then, you had to find a happy medium between complexity and what result you envisioned. They found a simple, easy way to do it that worked just fine and wasn't hard for the NES to run. Why overcomplicate it? It gains you nothing, and you only lose CPU+RAM. :)
Re: comprehensive SMB1 disassembly
by on (#106931)
A more readable smb PlayerPhysicsSub: http://mynesdev.blogspot.ca/2013/01/dai ... ost-7.html

I'm going to release the entire HL converted source soon, maybe tomorrow. I am finished converting it, I would just like to name some local variables.
Re: comprehensive SMB1 disassembly
by on (#106934)
Movax12 wrote:
A more readable smb PlayerPhysicsSub


That's fantastic! The assembly commands still take me some time to decipher/look up/get my head around, but this is very readable for noobs like me.
When this is complete perhaps I'll take a shot at porting it to a C-like, so it can be referenced for other platforms.
Re: comprehensive SMB1 disassembly
by on (#106938)
Sik wrote:
The other issue is control lag, which again I don't get (implementing lagless controls is easier and simpler, seriously o_O just react as soon as the input comes).

Perhaps it's that the operating system itself isn't designed around low latency. Some touch screens, for example, sample multiple times to ensure more accurate position readings. Keyboard input is often heavily processed based on an assumption, valid most of the time, that the keyboard is used for inputting text in any of several languages, some of them with fairly complex writing systems. And some adapters from classic SPI controllers to USB add latency as well. Furthermore, video and audio latency contribute to the perception of lag; an operating system's media subsystem may be geared toward the CPU-efficient and/or battery-efficient playback of noninteractive music and video more than toward gaming.
Re: comprehensive SMB1 disassembly
by on (#106951)
One thing that might be interesting to do is to still try to make SMB use 1-screen mirror for scrolling left-right for future expansion, Even though the code cannot let me do that due to it being a bit of terrible code!

This way, You can usually port to systems that have scrolling but only have capability of 1-screen mirroring only... like Commodore 64, *Sega Master System, *Game Boy, etc

* I can try to convert code after I figure out how to display only one screen, of which needs a new renderer
Re: comprehensive SMB1 disassembly
by on (#106984)
tepples wrote:
Sik wrote:
The other issue is control lag, which again I don't get (implementing lagless controls is easier and simpler, seriously o_O just react as soon as the input comes).

Perhaps it's that the operating system itself isn't designed around low latency. Some touch screens, for example, sample multiple times to ensure more accurate position readings. Keyboard input is often heavily processed based on an assumption, valid most of the time, that the keyboard is used for inputting text in any of several languages, some of them with fairly complex writing systems. And some adapters from classic SPI controllers to USB add latency as well. Furthermore, video and audio latency contribute to the perception of lag; an operating system's media subsystem may be geared toward the CPU-efficient and/or battery-efficient playback of noninteractive music and video more than toward gaming.

The biggest offenders tend to be unlicensed games on consoles though =P
Re: comprehensive SMB1 disassembly
by on (#107011)
Hamtaro126 wrote:
One thing that might be interesting to do is to still try to make SMB use 1-screen mirror for scrolling left-right for future expansion, Even though the code cannot let me do that due to it being a bit of terrible code!

This way, You can usually port to systems that have scrolling but only have capability of 1-screen mirroring only... like Commodore 64, *Sega Master System, *Game Boy, etc

* I can try to convert code after I figure out how to display only one screen, of which needs a new renderer


A proper, non giana-sisters port of SMB to the Commodore 64 would be awesome.
Re: comprehensive SMB1 disassembly
by on (#112301)
Hey doppelganger,

Not sure if this has been mentioned already. Line 15317:

Code:
        stx $f1                 ;and stop making the sfx

...could be changed to:

Code:
        stx Square1SoundBuffer                 ;and stop making the sfx
Re: comprehensive SMB1 disassembly
by on (#112389)
Would be interesting to read some "behind the scenes" information on how this was done?
Re: comprehensive SMB1 disassembly
by on (#112553)
Picture a man in his 30's at his computer, pouring through a disassembly of the program ROM, typing by hand everything in notepad.exe, stepping through the program in certain areas where it was more confusing, and comparing notes with the Super Mario Bros hacking project disassembly that was made further back in order to verify certain known things like the foreground object data format, and you have a pretty accurate picture of the behind-the-scenes stuff. There's not really much more to tell, unless you count a rough sequence of what got reverse-engineered...
Re: comprehensive SMB1 disassembly
by on (#112579)
I'm really interested in the bits of unused code sprinkled about. Why does the game have a brick counter? Why are broken brick pieces changed into white balls when you touch the flagpole? The world may never know... :\

(though my theory for the latter is that fireworks were originally going to use the brick-breaking routine, just with the brick graphics changed to something more firework-like)
Re: comprehensive SMB1 disassembly
by on (#112596)
I'll take a wild guess that you first looked at the vram writes and went backwards to find the area parser stuff.