Romhacking.net

Romhacking => ROM Hacking Discussion => Topic started by: Euclid on July 08, 2012, 12:39:56 am

Title: bad coding in roms
Post by: Euclid on July 08, 2012, 12:39:56 am
So after staring at the following assembly for 20minutes just now, i finally figured out what it does.

Code: [Select]
$0D/FBDA AF 6C F3 7E LDA $7EF36C[$7E:F36C]
$0D/FBDE CF 6D F3 7E CMP $7EF36D[$7E:F36D]
$0D/FBE2 F0 09       BEQ $09    [$FBED]
$0D/FBE4 38          SEC
$0D/FBE5 E9 04       SBC #$04
$0D/FBE7 CF 6D F3 7E CMP $7EF36D[$7E:F36D]
$0D/FBEB B0 00       BCS $00    [$FBED]
$0D/FBED AF 6D F3 7E LDA $7EF36D[$7E:F36D]
$0D/FBF1 18          CLC                 
$0D/FBF2 69 03       ADC #$03             
$0D/FBF4 C2 30       REP #$30

Answer:
Spoiler:
first 7 lines are useless - great for us to insert custom code :woot!:

Wondering if other people doing assembly level hacks/translations have run into funny coding similar to this?

Normally roms (especially snes/nes ones i have played around with) seems to be fairly well coded and packed without much spare bits and bytes - sure there might be improvements which can be made to save some cpu cycles, but seeing this today... looks like bad coding existed ever since people wrote code  ;D
Title: Re: bad coding in roms
Post by: justin3009 on July 08, 2012, 12:58:42 am
Code: [Select]
9.  $C2/801A 9D 7E 31    STA $317E,x[$7E:3544]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/801D 9D 80 31    STA $3180,x[$7E:3546]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8020 9D 82 31    STA $3182,x[$7E:3548]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8023 9D 84 31    STA $3184,x[$7E:354A]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8026 9D 86 31    STA $3186,x[$7E:354C]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8029 9D 88 31    STA $3188,x[$7E:354E]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/802C 9D 8A 31    STA $318A,x[$7E:3550]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/802F 9D 8C 31    STA $318C,x[$7E:3552]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8032 9D 8E 31    STA $318E,x[$7E:3554]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8035 9D 90 31    STA $3190,x[$7E:3556]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8038 9D 92 31    STA $3192,x[$7E:3558]   A:0140 X:03C6 Y:2000 P:envmxdizc 
    $C2/803B 9D 94 31    STA $3194,x[$7E:355A]   A:0140 X:03C6 Y:2000 P:envmxdizc

Tales of Phantasia

It's used to erase item names when you scroll down the list.  Not sure why it was used like this.

Decided to write a mini loop for this sucker just to make it easier.
Title: Re: bad coding in roms
Post by: KingMike on July 08, 2012, 02:22:10 am
We're talking about most hilariously bad commercially-written code?

Maka-Maka graphics decompression.
It uses the DMA WRAM registers ($2180-2183) to write a single a byte to WRAM. Not only that but it reloads the address registers each time (including doing LDA $2183: ORA $01: STA $2183. As I have heard, only the lowest bit has any significance and the register should be write-only anyways, so it's essentially ensuring the lowest bit of some garbage value is 1, and writing that.)
Oh, and to clear WRAM, it uses a loop routine to clear 64KB one at a time, instead of the DMA registers. It's like the programmers had a completely backwards understanding of what that WRAM DMA register is for. That right there is part of the reason for the game's damn awful load times.
Not to mention how they released an RPG where on the field menus, if you try to use a magic spell, it will ask you which character should cast a spell AND THEN IGNORE YOUR INPUT AND ALWAYS CHOOSE THE PROTAGONIST ANYWAYS.
Well, we won't know who's at fault because the credit scroll is also broken. :P

And Jerry Boy 2's graphics decompression routine contains a bug that incorrectly detects bank boundaries (using HiROM addressing at $C00000+). If data crosses ROM address xx7FFF, the decompressor will jump 32KB forward in the ROM and continue decompression. Obvious the original devs' graphics compressor had to account for that. How the game managed to stay playable is amazing. (only serious flaw I know of is that the music freezes in the good ending credits, though I don't know if that happens on real hardware or just in emulation)
Title: Re: bad coding in roms
Post by: LostTemplar on July 08, 2012, 03:30:58 am
Yep, it was REALLY that bad.  Had to write a mini loop for this sucker just to make it easier.  It legitimately was one of the worst coding pieces I have ever seen ~_~.

Why is that bad coding? It's pretty common to unroll loops, it saves quite some cycles.

I've seen a lot of horrendous coding in commercial ROMs myself. Even in otherwise good games you sometimes encounter useless code like "REP #$20 : SEP #$20" or "BRA $00". I bet stuff like that stems from the developers using macros.

What's also not necessarily bad coding, but confusing as hell is manipulating the stack like this (Far East of Eden Zero):

Code: [Select]
$C0/075F 48          PHA

$C0/0760 A3 05       LDA $05,s
$C0/0762 18          CLC
$C0/0763 69 01       ADC #$01
$C0/0765 85 5E       STA $5E

$C0/0767 A3 06       LDA $06,s
$C0/0769 69 00       ADC #$00
$C0/076B 85 5F       STA $5F

$C0/076D A3 07       LDA $07,s
$C0/076F 69 00       ADC #$00
$C0/0771 85 60       STA $60

$C0/0773 68          PLA

$C0/0774 3A          DEC A
$C0/0775 18          CLC
$C0/0776 65 5E       ADC $5E
$C0/0778 83 04       STA $04,s
$C0/077A A5 5F       LDA $5F
$C0/077C 69 00       ADC #$00
$C0/077E 83 05       STA $05,s
$C0/0780 A5 60       LDA $60
$C0/0782 69 00       ADC #$00
$C0/0784 83 06       STA $06,s

$C0/0786 A7 5E       LDA [$5E]
$C0/0788 6B          RTL

Spoiler:
First, it gets the return address of the caller and stores it in a pointer. At that return address is stored data (that's very nice when you disassemble the code and suddenly there's data instead of code although there's nothing there to indicate it). It then goes on to adjust the return address to skip the data. It doesn't make things better that the data is stored TWO levels above the current routine (return address of the caller). Finally, it loads the first byte of data into the accumulator and returns that.

I've also seen a bug in a game recently that you won't notice unless you debug it. It has a long list of items of different types. For each menu screen, it adjusts the base index corresponding to the item's type and then only passes the relative index within this type (say items, or magic) when printing the name. But when you change to a different menu screen, it adjusts the base index, but still tries to print the previous menu's strings and thus indicies, which often leads to out-of-bounds indices (base index + relative index). You usually won't notice that because it's displayed only one frame long and affects only the tile map. However, I changed the font to a VWF, and this bug lead to my new code writing garbage all over the screen when changing to some menus. I fixed it by checking for valid indices.
Title: Re: bad coding in roms
Post by: justin3009 on July 08, 2012, 07:28:24 am
The thing is with Tales of Phantasia's junk, the game already lags to heck when you scroll anywhere with items as it has to reload the VWF, the item Image, stats, etc..  There's ALWAYS a mini lag that appears.  Adding that little loop didn't really cause anymore delay in the slightest, not too mention it saves room and it allows for easier expansion incase item names are longer than what someone would hope.

Hell, the game has such bad loading times at point that there's literally text in the item menu stating, 'Loading...'
Title: Re: bad coding in roms
Post by: LostTemplar on July 08, 2012, 07:59:54 am
It's a very small loop, so yes, it shouldn't really add that much of a overhead unless it's executed very, very often. For example, I once did an 8x16 VWF and unrolling the loop that shifts each line of the current character halfed the cycles required for the whole routine, which was critical.

Well, what I wanted to say is mainly that it's pretty common to have unrolled loops like that and that it's still easily understood what the code does. But of course using a loop nets you better maintainability and extensibility.

Title: Re: bad coding in roms
Post by: KingMike on July 08, 2012, 10:13:03 am
I've seen a lot of horrendous coding in commercial ROMs myself. Even in otherwise good games you sometimes encounter useless code like "REP #$20 : SEP #$20" or "BRA $00". I bet stuff like that stems from the developers using macros.
Intentional delays, I guess.
(one example I know of is for using the multiplication/division registers on the SNES. Code doing multiplication has to delay, apparently, at least 8 cycles before reading the result.)
Title: Re: bad coding in roms
Post by: LostTemplar on July 08, 2012, 10:29:33 am
That's of course true, but I encountered the examples I mentioned in contexts where no delay was necessary.

For instance, sometimes there's code like this, where the last BRA is completely unnecessary:

Code: [Select]
    ...
    BRA end
    ...
    BRA end
    ...
    BRA end ( = BRA $00)
end:
    ...

I've also seen BRA $FE (an infinite loop) being used for error states and other crazy stuff.
Title: Re: bad coding in roms
Post by: neige on July 08, 2012, 01:12:20 pm
The game Kingyo Chuuihou! Tobidase Game Gakuen is full of wasteful coding, like putting a 32Kb+ font in RAM, using pointer tables to access sequential fixed length data, etc.

I think that the gargantuan monster that was used to display answer choices was the worst offender (0x88B03 in the ROM if you want to check). The function used 1319 bytes of ROM and 668 bytes of RAM spanning 589 lines of codes in addition to a table of 560 16-bits pointers to look up the font characters. It started by copying the string to a temporary buffer then copied each character's graphic from the font to another buffer one by one (ie. without using a loop). Since the characters where 12 pixels wide, they shifted every odd character by 4 pixel, again without using a loop. Finally they copied and combined the character graphics to form the final output image.

Another weird thing I saw in another game was a strange looping construct, I don't remember the game but it was something like this:
Code: [Select]
; Code to set-up the A register
loop:
BIT #$68
PHA
; Code that changes the A register
B?? loop+1
Spoiler:
0x68 is the opcode of the PLA instruction. The BIT instruction was used as a no-op to avoid pulling A from the stack when first entering the loop, subsequent runs through the loop pulled A before pushing it again.
Title: Re: bad coding in roms
Post by: LostTemplar on July 08, 2012, 01:19:30 pm
Now that's weird and inscrutable. Using

Code: [Select]
    PHA
loop:
    PLA
    PHA
   ...
    B?? loop

was probably too mainstream ;)
Title: Re: bad coding in roms
Post by: neige on July 09, 2012, 11:14:22 am
Exactly, and they can't pretend it's a speed optimization since both the BIT and PLA/PHA take 2 cycles to execute (assuming the m flag is set).

Maybe it was used for obfuscation purposes because when I first tried to disassemble this, I was stumped :huh:.
Title: Re: bad coding in roms
Post by: KC on July 09, 2012, 11:25:32 am
Partly the result of wrong data types, and partly the result of probably compiling with debug settings:
Code: [Select]
    08033B8A (T)  ldr     r0,=3003A64h                            ;12 4404
    08033B8C (T)  ldrh    r1,[r0]                                 ;9  4413
    08033B8E (T)  mov     r2,1h                                   ;3  4416
    08033B90 (T)  mov     r0,r1                                   ;3  4419
    08033B92 (T)  and     r0,r2                                   ;3  4422
    08033B94 (T)  mov     r2,r0                                   ;3  4425
    08033B96 (T)  lsl     r1,r2,10h                               ;3  4428
    08033B98 (T)  lsr     r0,r1,10h                               ;3  4431
    08033B9A (T)  cmp     r0,0h                                   ;3  4434
Almost all of the Devil Children (GBA) code looks like this.
Title: Re: bad coding in roms
Post by: MathOnNapkins on July 09, 2012, 12:02:40 pm
Things that piss me off the most are coders choosing to intentionally use an endianness that is non native on the system in question. Not only does it impact performance somewhat, it also makes code harder to read when you go against the grain. I can only guess that these kinds of people just couldn't wrap their head around little endian.

Zero length branches and jumps used to irritate me more, but then I realized that they were probably written around code that didn't make it to the final binary, either due to comments or assemble time mechanisms (like #ifdef / #ifndef in CPP).

Some of the dumber things I've seen I've chalked up to macros, such as code that performs arithmetic operations to build up a constant. Example:

Code: [Select]
lda #$0030
add #$0100
ora #$8000

instead of:
Code: [Select]
lda #$8130

The truly unforgivable sins are those that impact performance in a strong way without incurring some kind of other benefit. In particular, I despise code that is heavy on comparisons and branches where a lookup table and / or jump table would have been more appropriate (and smaller!).
Title: Re: bad coding in roms
Post by: henke37 on July 09, 2012, 06:21:14 pm
Some of those are required on fixed length opcode systems. You really can't store a full 32 bit pointer + the instruction type + the destination register in 32 bits.
Title: Re: bad coding in roms
Post by: snarfblam on July 09, 2012, 06:36:05 pm
Now that's weird and inscrutable.

I know the BIT trick is pretty common in 6502, where programmers often need to save every byte and cycle possible, so I would expect it to show up in 65816 from time to time, if only out of habit. I've seen better examples (http://forum.6502.org/viewtopic.php?t=1614) of the BIT trick, though.
Title: Re: bad coding in roms
Post by: LostTemplar on July 09, 2012, 06:40:09 pm
That example makes more sense, yes.
Title: Re: bad coding in roms
Post by: Zoinkity on July 11, 2012, 10:57:46 am
Most of the crummier code in N64 games is tied to partially-removed debug features.  For instance, something that will read, format, and print debug info to a temporary buffer and then return without doing anything with it, or cases where you loop several times NOPping away. 

Worst offender of all was Datel's GameShark, although to be fair a part of that was due to the hardware itself.  Instead of using the PI to load ROM in large chunks, they copy short values using two different hardware addresses, one mirroring the upper halfword and the other grabbing the lower.  These are pushed and meshed into words, and this is done for each word in ROM.  Mnd you, although that is necessary for the GS's ROM, why they do it for cart ROMs is questionable.
This is especially annoying when doing a CRC calculation.  To switch CRCs (keycodes) it requires loading the entire ROM one short at a time, splicing them together, calcing the checksum, then compensating for the new base value.  This also happens when you upload a new BIOS, in which case it takes the BIOS you uploaded in rdram and reads it not as words but as shorts, calcs the new sum and sets it, needlessly reads its own BIOS and calculates that sum, then copies the new BIOS to hardware one short at a time and recalculates the sum again by reading it all back in.  On a failure, it writes back the original BIOS and recalcs again--which is really funny since a falure to write back properly will result in it writing not the original ROM but the replacement.  Naturally, they just return to the beginning of the process and read the current ROM (failed BIOS), treating the original as the replacement.
Oh, and the 'alternate hook' method will cause a permanent loop in virtually any commercial game.

As far as new code, you should see the mess that passes for reading controller input these days.
Title: Re: bad coding in roms
Post by: RedComet on July 12, 2012, 10:14:38 pm
My favorite is the in Zyuranger for the Famicom. The routine that writes data to the PPU has a block of repeating STA $2007 rather than a loop. There was no performance gain from unrolling the loop that I could see.
Title: Re: bad coding in roms
Post by: danke on July 12, 2012, 11:27:48 pm
My favorite is the in Zyuranger for the Famicom. The routine that writes data to the PPU has a block of repeating STA $2007 rather than a loop. There was no performance gain from unrolling the loop that I could see.

I was waiting for you to post about that here. Kinda bummed you didn't post the source code for all to see and laugh at.
Title: Re: bad coding in roms
Post by: Pennywise on July 12, 2012, 11:36:58 pm
I'm currently working on a game that probably 75% of the text pointers are hardcoded into the ROM. Granted, it's only a 16kb bank, but that's just bad no matter how you cut it. The worst offender is the battle text, which follows some sort of pattern and happens to compromise the bulk of the text, but yet the pointers are all hardcoded.
Title: Re: bad coding in roms
Post by: Zoinkity on July 13, 2012, 07:03:25 pm
Oh, completely forgot.  Animal Forest explicitly initializes somewhere around 0x250 bytes of data after the legal screen.  That's about 400 opcodes sucked down to do what can be done in about 20 opcodes--smaller if you're willing to take a hit on the compression factor by using nonredundant code.
Title: Re: bad coding in roms
Post by: assassin on November 15, 2012, 06:30:33 pm
from FF3us (also in FF6j, at C3/A348), including my comments:

Code: [Select]
C3/9B59: 20 2A 9C     JSR $9C2A      (Clear our list of eligible equipment by writing
                                      nine FFs to it)
C3/9B5C: 20 41 9C     JSR $9C41      (Setup equippability word)
C3/9B5F: A9 20        LDA #$20
C3/9B61: 85 29        STA $29        (set text color to white)
C3/9B63: A5 4B        LDA $4B        (which of four Equipment slots we're looking at)
C3/9B65: C9 02        CMP #$02
C3/9B67: F0 49        BEQ $9BB2      (branch if this is a Helmet slot)
C3/9B69: C9 03        CMP #$03
C3/9B6B: F0 02        BEQ $9B6F      (branch if this is an Armor slot)
C3/9B6D: 80 03        BRA $9B72      (otherwise, it's a hand slot, so list
                                      weapons and shields)
C3/9B6F: 4C EE 9B     JMP $9BEE      (Armor)
                                     (cripes, that's a lot of branch instructions.
                                      we can replace the three with "BNE $9B72 /
                                      JMP $9BEE / NOP / NOP" OR "NOP / NOP / BEQ $9BEE
                                      / NOP / NOP / NOP".  hell, just "BEQ $9BE9"
                                      would've worked to start, because that's where
                                      Function C3/9BEE would've begun without these 5
                                      extra bytes.  ay yay yay.)

so Square made one 2-byte branch into three branches totalling 7 bytes. :P

they do a LOT of dumb crap in Bank C3, most of which wasn't discovered by me (Lenophis, Novalia Spirit, and Imzogelmo have encountered their share).  it's our consensus that the programmers who coded Banks C3, C1, C0, etc. were dumber than those who coded C2 (the battle engine bank).  also, one commenter suspects that some of the C3 code was auto-generated somehow.
Title: Re: bad coding in roms
Post by: Ryusui on November 15, 2012, 06:49:48 pm
they do a LOT of dumb crap in Bank C3, most of which wasn't discovered by me (Lenophis, Novalia Spirit, and Imzogelmo have encountered their share).  it's our consensus that the programmers who coded Banks C3, C1, C0, etc. were dumber than those who coded C2 (the battle engine bank).  also, one commenter suspects that some of the C3 code was auto-generated somehow.

Maybe it was written in C/C++ or another language, and then compiled - badly.
Title: Re: bad coding in roms
Post by: LostTemplar on November 16, 2012, 06:24:10 am
From the few looks I took at FF6's code I can only tell that it's pretty much a mess.

But I've seen multiple games where there apparently was at least some form of automization, especially macros. It's not that they didn't have computers with compilers back then, so I'd guess if they could program for the SNES they could at least write some tool that generates code in some manner. Even if it sucked.

Furthermore, it seems to be often the case that different banks are coded by different people. In one game I worked on it was so obvious it hurt. The battle was programmed in such a different way from the rest of the game. That's kind of interesting, though.

Not entirely related, but some time ago I looked at a game that had some JSRs in it to addresses that only contained an RTS. I suspect that this was either some form of debug routine that was taken out, or that there was some feature that was removed. Or maybe it was just overlooked, who knows.
Title: Re: bad coding in roms
Post by: tryphon on November 16, 2012, 05:16:27 pm
I'm diving into the code of Phantasy Star Generations 2 (ps2) and I've noticed a couple of things strange, such as a call to a subroutine, which, as usual, stores its return values in v0 and v1, but registers v0 and v1 are overwritten before being stored anywhere.

I can delete the call without any consequence...

It's all the more strange that I suspect the original program to have been written in C/C++.
Title: Re: bad coding in roms
Post by: BRPXQZME on November 16, 2012, 07:18:26 pm
Not all compilers optimize (though this is getting much rarer than it was 20 years ago). And not all compilers that optimize do it well! :laugh:

Cruft left over from debug code can also leave puzzling artifacts, particularly if the developer was not that assembly-minded (or just didn’t care... I mean, sometimes it’s really just a few instructions on a processor that does millions a second and doesn’t mess up caching or anything).

In that case for PSG2, it’s possible that the return value wasn’t the point of that particular call to the function. It isn’t unusual to call a function that returns something when all you wanted was the function’s effect. But again, it could just be partially-dummied debug code. Only way to tell is to look and see what it does.
Title: Re: bad coding in roms
Post by: Carnivol on November 18, 2012, 10:44:42 am
(only serious flaw I know of is that the music freezes in the good ending credits, though I don't know if that happens on real hardware or just in emulation)

Know this was an old thread gettin' bumped, but I can tell you that the ending credits music locks up on hardware too. (Was that ever fixed by anyone? I only played the game like a decade ++ ago, whilst looking for games I wanted to see happen in English/Norwegian ...)
Title: Re: bad coding in roms
Post by: Pyriel on November 18, 2012, 11:31:39 am
Yeah, nobody usually cares about the return value from memset, but NOPing the call probably wouldn't be a good idea.

Suikoden II on the PSX is just loaded down with debug code.  The game is done in hundreds of modules that load at fixed addresses, and the modules will call various functions from the main executable via JALR register jumps.  I guess they solved the issue of dealing with common code via a ton of extern function pointers or something.  Regardless, every time one of these calls is done, you see:
Code: [Select]
la $trace_reg, ModuleTrace
sw $call_reg, $trace_reg
Since it uses these functions pretty regularly, there's probably about half a KB or more of wasted instructions in a lot of the modules.  These instructions are pretty trivial, so it hardly matters, and every time it happens I have 3 more op codes I can add without taking anything away.  I can take back more if I change all the JALRs to straight JALs.  All the debug prints they left in are slightly less trivial.

One really weird thing they did was having two sets of code for battles.  One runs during the first round of a fight, and the second set runs during the second round onward.  It's not that there's an "if" statement or something.  They actually overlay the code from FST.BIN with code from SEC.BIN while the battle animations run.  About 90% of the code is identical, so I guess they were worried a couple of overloaded or extra functions would overflow the 200 or so KB they allocated to hold the code.
Title: Re: bad coding in roms
Post by: KingMike on November 18, 2012, 11:32:22 am
Never verified if it (Jelly Boy 2 music crash) happened on hardware, just that it wasn't caused by the translation patch.
Title: Re: bad coding in roms
Post by: Zoinkity on November 19, 2012, 03:26:18 pm
Perfect Dark: the ROM space allocated for the first three (and largest) compressed files in the game happen to be sized for decompressed copies of this data.  In other words, there was no reason whatsoever to compress it.

GoldenEye and Perfect Dark also have multiple copies of zlib embedded, complete with all its registers.  GE only has two; the first is used only at boot before the second is decompressed, so you can at least understand to some degree how this could happen.  PD has at least three however, and I suspect a fourth, the only difference being what fileloader called the data they're decompressing, and the only difference in the fileloaders being one is effectively a macro for the other. 
Both games are rigged to test for at three different kinds of headers, except each of these tests use the same samples for the header test.  An enterprising individual can feed it Rare's other games' samples so they can open each other's data--or zlib headers for that matter.

Oh, and GE happens to have a complete 64DD I/O handler built in for no reason whatsoever.  That complements all the debug info it collects and discards rather nicely.
Title: Re: bad coding in roms
Post by: LostTemplar on November 19, 2012, 04:12:49 pm
I'm working on this weirdly programmed SNES game right now. Not sure if it can even be called bad, but it is certainly weird. It turns the NMI off and waits manually for vblank each frame to do its drawing; it NEVER uses 8-bit mode, only 16-bit; it uses long addressing (24-bit) way too often; it does this very simple variation of an LZ compression where it writes directly to VRAM and reads it back from VRAM for back references, etc.
Title: Re: bad coding in roms
Post by: Zoinkity on November 21, 2012, 08:19:27 pm
The official RNC decompression routine provided for N64 throws all the programming style out the window.  It uses only system variables, plays funny tricks with a 'false' stack, manually jumps and links instead of using the hardware provided method, and has to disable exceptions because if anything happened in the middle of this horrible winding spaghetti (such as playing audio, or video, or handling another thread, etc.) it would crash.

It was enough of a problem that Acclaim rewrote the thing with some rather tart comments about the original inserted for good measure.

Personally I don't see why anyone bothered with such a bizare compression scheme anyway when zlib was a smaller library, faster, didn't require licensing, and compressed faster and better.
Title: Re: bad coding in roms
Post by: Bond697 on November 26, 2012, 09:28:39 am
pokemon white 2 does some funny things in its breeding code.  to create an egg, they:

-create a full wild pokemon for the sole purpose of creating a free 220 byte block and a pointer to it(they have a memory allocation system that could easily do this)
-create a 34-element u32 array where they arrange a bunch of features that the egg will have(inherited ivs, inherited moves species, et al)(there's a good amount of extraneous data in this)
-use the previous pointer as a start in creating a second full wild pokemon
-after making the second full pokemon, write all the values from the egg data array into the correct spots, the  set some values for the egg, and finally set the marker that makes it an egg

in the end they generate 3 pids, 18 ivs, and loads of other extraneous values.  it's really kind of a mess.

e: almost forgot the best part.

breeding in bw2 uses its own special inline rng.  it uses a special seed they create when the game boots.  however, due to a programming mistake, every time you restart the game the first egg you breed will be identical aside from the species and pid. 


the way it works is when you start a new game, on loading into the world for the first time, the game creates a seed and saves it to your save file.  each time you restart a new seed is made and copied into the right spot for breeding.  after that, the old seed is read in front the save and written in.  then the old seed is written in a second time when the entire daycare block is copied into place.
Title: Re: bad coding in roms
Post by: BRPXQZME on November 26, 2012, 04:49:38 pm
e: almost forgot the best part.

...
amg

well, I guess it still takes care of what they wanted it to accomplish, but still

wow
Title: Re: bad coding in roms
Post by: Zoinkity on November 26, 2012, 09:13:55 pm
Funny thing about the N64: register R0 is always 0.  It can never change.
Turns out some games <cough>Forsaken64</cough> seem to think that's a great place to dump error codes.

800029B8, 800068D8, 80006A6C, 80007410, 800080C4, 80008150, 80008788, 800087F0, 80009D0C, 80009D44, 80009DC0, 80009E60, 80009F58, 8000A02C, 8000A118, 8000BBA8:
ADDIU   V0,R0,FFFF
SW   V0,0000 (R0)

Would be slightly less idiotic if they didn't test for error codes after each return, or if some of these routines weren't dedicated to testing for this error code.
Title: Re: bad coding in roms
Post by: BRPXQZME on November 26, 2012, 11:29:31 pm
I don’t see anything being dumped into R0 in that code....
Title: Re: bad coding in roms
Post by: LostTemplar on November 27, 2012, 04:18:50 am
My MIPS assembly is a bit rusty, but that's indirect addressing, isn't it? Meaning it would be

v0 <- 0xffff
address r0+0000=000000000 <- v0

I don't know what the N64 has at address 0, but it really doesn't seem like r0 itself.
Title: Re: bad coding in roms
Post by: Revenant on November 27, 2012, 05:03:32 am
edit: i shouldn't try to remember forgotten college courses while sleep deprived
Title: Re: bad coding in roms
Post by: BRPXQZME on November 27, 2012, 06:48:59 am
My MIPS assembly is a bit rusty, but that's indirect addressing, isn't it? Meaning it would be

v0 <- 0xffff
address r0+0000=000000000 <- v0

I don't know what the N64 has at address 0, but it really doesn't seem like r0 itself.
Close. In MIPS, immediate values for arithmetic are sign-extended 16-bit numbers, so (as posted) the code does

v0 := -1
M[0] := v0
Title: Re: bad coding in roms
Post by: Pyriel on November 27, 2012, 08:32:32 am
...if some of these routines weren't dedicated to testing for this error code.

What does this mean? After they store at 0(R0), they load it back sometime later to test it?  From your description of the oddity, it sounds like a few instructions later you're seeing them explicitly stick 1 on V0 and then test that against R0.
Title: Re: bad coding in roms
Post by: Zoinkity on November 27, 2012, 09:23:15 am
R0 is always zero.  0x0 isn't valid address space.  Any write to 0x0 fizzles, and any read of 0x0 throws an exception due to it being unreadable.  Every one of those writes sets an error code to a nonexistant address that can never be recovered.  Unless they custom editted the badvaddress handler reading would cause a fault.

Thing is, each of these routines is passed a variable that is expected to contain the returned error code.  There's some long-winded error handling routines that read these values, which are fairly pointless since they aren't passed.  At the least if you're going to fry all the error codes you might as well unlink their handlers.
It isn't like the values aren't that important; one attached to the PI returns if the thing is busy, if the request was sent, and if it finished.  As far as they're concerned it is always finished, which isn't just unsafe but explains why their decompressor is wrapped in a loop checking input and output checksums.  Simply handling the value avoids this mess.
Title: Re: bad coding in roms
Post by: Pyriel on November 27, 2012, 10:26:51 am
Yeah, I know what R0 is.  That's why I asked for clarification, because I wasn't sure how far the rabbit hole went.  I assumed they'd have to write that code directly in assembler to do what it sort of sounded like you were saying.  I'd like to think even the N64 SDKs would see something that essentially means if (1 == 0) and just throw it away.
Title: Re: bad coding in roms
Post by: BRPXQZME on November 27, 2012, 10:10:41 pm
Ah, now that sounds more like bad code someone might write. “Forget the error code pointers it runs fine guys.”

I don’t put any silly missed optimization opportunities past 90s compilers, but it’s possible they were essentially telling a C compiler to write values to NULL.
Title: Re: bad coding in roms
Post by: Mattrizzle on December 04, 2012, 10:52:46 am
Not the worst case, but a subroutine which starts at $BF/BF86 in Donkey Kong Country (v1.0)(U), called when swapping Kongs, has unneeded branches and some redundant lines:
Code: [Select]
...
$BF/C006: AD 6F 05     LDA $056F      (Load active Kong variable)
$BF/C009: C9 01 00     CMP #$0001
$BF/C00C: F0 06        BEQ $C014      (branch if Donkey Kong)
$BF/C00E: C9 02 00     CMP #$0002
$BF/C011: F0 14        BEQ $C027      (branch if Diddy Kong)
$BF/C013: 60           RTS            (this cannot be reached, as $056F is always either #$0001 or #$0002)
$BF/C014: A9 02 00     LDA #$0002
$BF/C017: 8D 6F 05     STA $056F      (set active Kong to Diddy)
$BF/C01A: A9 11 00     LDA #$0011
$BF/C01D: 8D 2B 10     STA $102B      (set D.K.'s behavior to #$0011)
$BF/C020: 8D 2D 10     STA $102D      (set Diddy's behavior to #$0011)
$BF/C023: 20 3A C0     JSR $C03A
$BF/C026: 60           RTS
$BF/C027: A9 01 00     LDA #$0001
$BF/C02A: 8D 6F 05     STA $056F      (set active Kong to D.K.)
$BF/C02D: A9 11 00     LDA #$0011
$BF/C030: 8D 2B 10     STA $102B      (set D.K.'s behavior to #$0011)
$BF/C033: 8D 2D 10     STA $102D      (set Diddy's behavior to #$0011)
$BF/C036: 20 3A C0     JSR $C03A
$BF/C039: 60           RTS

If the code snippet above was replaced with this...
Code: [Select]
...
AD 6F 05     LDA $056F      (Load active Kong variable, which is either 1 or 2)
3A           DEC            (decrease value in accumulator by 1, making it either 0 or 1)
49 01 00     EOR #$0001     ("toggle" bit 0, changing 0 to 1, or vice-versa)
1A           INC            (decrease value in accumulator by 1, making it either 2 or 1)
8D 6F 05     STA $056F      (store value to active Kong variable)
A9 11 00     LDA #$0011
8D 2B 10     STA $102B      (set D.K.'s behavior to #$0011)
8D 2D 10     STA $102D      (set Diddy's behavior to #$0011)
...
(the entire subroutine at $BF/C03A can go here, as this subroutine is the only one that calls it)
...
60           RTS
...13 (D.K.) to 17 (Diddy) CPU cycles and 32 bytes would be saved.
Title: Re: bad coding in roms
Post by: FAST6191 on December 04, 2012, 02:53:36 pm
Nice snippet Mattrizzle- I am drawn to wonder if that is possibly a crude bit of error handling or an indicator of there potentially being more characters at some point in development (or if riding characters were to count at some point), of course I am quite happy to believe bad coding as well (if if rather than if else).

As for the topic I have nothing especially worth sharing- a handful of packing formats that waste countless amounts of space throughout the header and then has everything byte aligned after that (most other formats will go to 32 bit or higher alignments) which would necessitate a whole bunch data handling after for it to be useful for the memory itself is about as good as it gets right now for me. That said if I dragged up some examples from when I have been playing sound hacker that gets a bit ugly- ultra low sample rates for voices sections despite hardware support for far higher sample rates and the game ultimately ended up only just above the power of 2 boundary for cart size anyway.
Title: Re: bad coding in roms
Post by: Jorpho on December 04, 2012, 10:04:17 pm
Nice snippet Mattrizzle- I am drawn to wonder if that is possibly a crude bit of error handling or an indicator of there potentially being more characters at some point in development (or if riding characters were to count at some point), of course I am quite happy to believe bad coding as well (if if rather than if else).
The switch is known to be extremely glitchable, with colorful results.
http://davidwonn.kontek.net/snes.html#D
Title: Re: bad coding in roms
Post by: Myria on December 11, 2012, 02:20:09 am
I love it when I see code that does something like:

SEP #$20
CLC
ADC.B #$12

Why not do this instead?

SEP #$21
ADC.B #$11
Title: Re: bad coding in roms
Post by: LostTemplar on December 11, 2012, 03:33:15 am
I guess that's kind of a "pattern". Furthermore, I've rarely seen SEP/REP being used for flags other than M/X... not sure if the developers didn't bother or just weren't aware, but probably just an oversight usually.
Title: Re: bad coding in roms
Post by: Mauron on December 11, 2012, 04:03:16 am
I've seen games use both this:

SEP #$20
CLC
ADC.B #$12

And in other situations:

REP #$21
ADC.W #$0012

I would guess it was for readability/consistency.
Title: Re: bad coding in roms
Post by: tryphon on December 11, 2012, 04:34:13 am
I'm pretty sure there's a reason to do it (so it's more likely bad understanding from me than bad coding) but I see often, in a PS2 game :

Code: [Select]
sll v1, a0, 16 ; v1 = a0 * $10000
sra a0, v1, 16 ; a0 = v1 / $10000

then v1 is discarded.

What makes me thing it may be stupid optimization is that nop-ing the 2 lines doesn't affect the game...
Title: Re: bad coding in roms
Post by: LostTemplar on December 11, 2012, 04:36:52 am
Looks like a bit-wise AND with $ffff (the effect, that is, which is discarding the 16 upper bits).
Title: Re: bad coding in roms
Post by: tryphon on December 11, 2012, 05:57:42 am
Yes, but I forgot to add that a0 is always 2 bytes long.
Title: Re: bad coding in roms
Post by: KC on December 11, 2012, 07:21:08 am
Compilers will automatically insert that when you use a (in this case, signed) 16 bit integer type.  They cannot know that the data is always valid, and have to take measures to ensure that.
Title: Re: bad coding in roms
Post by: RedComet on December 11, 2012, 11:38:08 am
I love it when I see code that does something like:

SEP #$20
CLC
ADC.B #$12

Why not do this instead?

SEP #$21
ADC.B #$11

Because then you would be setting the carry flag instead of clearing it. ;)
Title: Re: bad coding in roms
Post by: LostTemplar on December 11, 2012, 11:50:15 am
That's why he's adding 11 instead of 12 ;)
Title: Re: bad coding in roms
Post by: RedComet on December 11, 2012, 12:04:36 pm
That's why he's adding 11 instead of 12 ;)

Hah. I completely missed that. :P
Title: Re: bad coding in roms
Post by: tryphon on December 11, 2012, 02:06:14 pm
Compilers will automatically insert that when you use a (in this case, signed) 16 bit integer type.  They cannot know that the data is always valid, and have to take measures to ensure that.

I suspected something like that. So it's a bad design of the C code ? (in the case I refer to a0 is unsigned)
Title: Re: bad coding in roms
Post by: BRPXQZME on December 11, 2012, 06:48:40 pm
On MIPS, 16-bit-ness has to be enforced if you’re going to have it. Whether it is bad design kind of depends, but it probably isn’t. I can’t think of a way you would just accidentally or mistakenly choose a to use a 16-bit value, unless the programmer was seriously not informed that making it 16-bit will not make the calculation faster like it might on some older platforms (for example).

Either way, it’s only a couple of shifts... it probably doesn’t hurt anything.
Title: Re: bad coding in roms
Post by: Pyriel on December 11, 2012, 06:52:53 pm
It's two operations created by the compiler to enforce type; they're not slowing anything down.  Without more code, it's not even apparent that $a0 is unsigned, but even if it is, there can be any of number of reasons for casting it as signed.
Title: Re: bad coding in roms
Post by: tryphon on December 12, 2012, 04:09:09 am
I don't say bad design because of 16 bits value, but because it considers it signed whereas it isn't (and so the shifts are useless).

Of course, I'm aware it won't really slow down the process. The main drawback is that the compiled code is less readable, especially when you're not accustomed to compiled code :)

But now it makes more sense, thanks :)
Title: Re: bad coding in roms
Post by: Myria on December 17, 2012, 09:37:11 pm
Silly MIPS trick to do absolute value in 8 bytes instead of 12:

bgtz a0, label
label:
subu a0, zero, a0

Funny story with the delay slot stuff:  When I was in college/university, our required class on assembly language had MIPS as the processor of choice.  By this point, I had been hacking PS1 games for a few years, so I was well-versed in MIPS.  Because I was reverse engineering MIPS code, I was used to the delay slot.  In forward programming of MIPS assembly code, most people seem to rely on the assembler's default reordering of instructions - including the way that the professor taught the class.

When I turned in my written final, the professor gave me a bad grade because my code didn't look like it could possibly work.  He actually didn't even know about the MIPS delay slot, and I had to explain it - and how assemblers hide it.
Title: Re: bad coding in roms
Post by: BRPXQZME on December 17, 2012, 09:52:59 pm
Silly MIPS trick to do absolute value in 8 bytes instead of 12:

bgtz a0, label
label:
subu a0, zero, a0
(but that should...

no wait...)

>witchcraft.gif

edit: When I did MIPS for a class in high school, we actually did have to know about the delay slot. When I took the same class at college level (because there simply isn’t anything that transfers like that), we had to program like it didn’t exist and I was like aw come onnnn!

Of course, my guess is you would want to avoid a branch on a modern pipelining processor but I’m no expert or anything.
Title: Re: bad coding in roms
Post by: henke37 on December 17, 2012, 11:53:33 pm
Nice trick, I shall remember it for the time I need to do it. Too bad that all modern processors already have an abs instruction.
Title: Re: bad coding in roms
Post by: BRPXQZME on December 18, 2012, 12:33:12 am
Modern processors like what? :huh:

Anyway, this implementation is really only for architectures with branch slot delay like MIPS and... SPARC, I guess, out of all the things you’re likely to ever code on. For performance purposes, branching is something to avoid in general unless you are seriously starved for bytes (in which case, why are you using a RISC processor anyway?). For most uses nowadays a generic integer absolute is best accomplished by something like:
Code: [Select]
long abs(long x) {
long temp = x >> LONGSIGNBITSHIFT; // (sizeof(long)<<3)-1, which is 31 on a lot of current archs
return (x^temp)-temp;
}
which inlines to three instructions on most architectures if you don’t need to save anything.
Title: Re: bad coding in roms
Post by: assassin on December 18, 2012, 01:54:50 am
^ how does that work?  First off, I'm assuming you want temp to be (x >> LONGSIGNBITSHIFT) << LONGSIGNBITSHIFT .  If not, I'm utterly lost.  In my test of input value -3, assuming longs are 16 bits, I get a return value of 32765 - 32768 = -3 .  If you flip it so temp-(x^temp) is returned, negative input values seem to work, but positive ones won't.
Title: Re: bad coding in roms
Post by: BRPXQZME on December 18, 2012, 02:08:38 am
examples:
x = 0 = 0x00000000
temp = x >> 31 = 0x00000000
x^temp-temp = (0^0)-0 = 0-0 = 0

x = 1 = 0x00000001
temp = x >> 31 = 0x00000000
(x^temp)-temp = (1^0)-0 = 1-0 = 1

x = -1 = 0xFFFFFFFF
temp = x >> 31 = 0xFFFFFFFF
(x^temp)-temp = (0xFFFFFFFF^0xFFFFFFFF)-0xFFFFFFFF = 0-(-1) = 1

x = -3 = 0xFFFD
temp = x >> 15 = 0xFFFF
(x^temp)-temp = (0xFFFD^0xFFFF)-0xFFFF = 0x0002-(-1) = 3

^ is a bitwise XOR in C, in case that isn’t clear.

Basically, it all works off several ideas:
- To negate a number in two’s complement, you flip the bits and add 1.
- XOR changes a value if you mask with a 1, and leaves alone if you mask with a 0.
- For a non-negative number, shift-extending the sign bit throughout all bits gives you a mask of all zeroes or ones
- Thus, XORing all bits in a number with its sign bits will flip the bits if the number is negative, and let it be otherwise
- Subtracting by negative one is the same as adding by negative one; adding zero wastes a little time but hurts nothing.
- You’re only bothering to do these extra operations because the time cost is peanuts compared to what branching might do. In general, on modern pipelining / branch-predicting architectures, it is worth replacing a single if statement with a couple of arithmetic statements if you can manage it.
Title: Re: bad coding in roms
Post by: Myria on December 18, 2012, 02:19:08 am
^ how does that work?  First off, I'm assuming you want temp to be (x >> LONGSIGNBITSHIFT) << LONGSIGNBITSHIFT .  If not, I'm utterly lost.  In my test of input value -3, assuming longs are 16 bits, I get a return value of 32765 - 32768 = -3 .  If you flip it so temp-(x^temp) is returned, negative input values seem to work, but positive ones won't.

It's based on an identity from two's complement integer arithmetic: for all x, -x == ~x + 1.  Also, note that ~x == x ^ -1, and that ~x + 1 == ~x - (-1).

The first statement with the "temp" is using signed shifting.  It's copying the sign bit into all other bits.  In short, it means: long temp = (x < 0) ? -1 : 0;

If x is positive or zero, temp becomes zero.  XORing with 0 and subtracting 0 both do nothing, so it returns x.
If x is negative, temp becomes -1.  XORing with -1, as noted above, is equivalent to NOTing.  Subtracting -1 is equivalent to adding 1.  The follows the identity -x == ~x + 1, so the result in this case is -x.
Title: Re: bad coding in roms
Post by: assassin on December 18, 2012, 02:19:57 am
Ah, thanks.  I was assuming the right shift was logical versus arithmetic, getting nonsense results, then figuring you needed a left shift in there.  :-[

The XOR was an early hang up, which I eventually got past.  ("The exponent isn't making any sense, and there's no way he'd save speed with that anyway.  So that symbol must be an OR, because I remember what AND is.")

Pascal and 65816 assembly are the only two languages I've used in years, so clarifying that symbol was a good call on your part.  :)
Title: Re: bad coding in roms
Post by: BRPXQZME on December 18, 2012, 02:27:10 am
>> is logical or arithmetic depending on the signedness of a variable.

I thought I had clarified that, but it turns out it got deleted at one of the draft stages. I’m in finals mode and shouldn’t be posting at the moment :P
Title: Re: bad coding in roms
Post by: Myria on December 18, 2012, 01:42:48 pm
branching is something to avoid in general unless you are seriously starved for bytes (in which case, why are you using a RISC processor anyway?).

I was making GameShark codes, where each extra instruction was two full codes the player had to enter.  This led to other optimization techniques, such as NOPing an instruction with a single GameShark code by overwriting the high word with 0x2400, which converts the instruction to "addiu zero, zero, 0xABCD".
Title: Re: bad coding in roms
Post by: Bongo` on December 18, 2012, 01:55:22 pm
I'm working on this weirdly programmed SNES game right now. Not sure if it can even be called bad, but it is certainly weird. It turns the NMI off and waits manually for vblank each frame to do its drawing; it NEVER uses 8-bit mode, only 16-bit; it uses long addressing (24-bit) way too often; it does this very simple variation of an LZ compression where it writes directly to VRAM and reads it back from VRAM for back references, etc.
That game sounds like Gaia Saver. :)
Title: Re: bad coding in roms
Post by: assassin on December 27, 2012, 12:18:55 pm
from Secret of Evermore:
Code: [Select]
8F/804E: A9 00 01     LDA #$0100
8F/8051: 8D 07 0B     STA $0B07    (Dog attack = Level 1:0)
8F/8054: A9 00 01     LDA #$0100   (will set weapon level to 1, and advancement
                                    within level to 0)
8F/8057: 8D DD 0A     STA $0ADD    (bare hands [you can't ever fight with them] = Level 1:0)
8F/805A: 8D DF 0A     STA $0ADF    (Bone Crusher = Level 1:0)
8F/805D: 8D E1 0A     STA $0AE1    (Gladiator Sword = Level 1:0)
8F/8060: 8D E3 0A     STA $0AE3    (Crusader Sword = Level 1:0)
8F/8063: 8D E5 0A     STA $0AE5    (Neutron Blade = Level 1:0)
8F/8066: 8D E7 0A     STA $0AE7    (Spider's Claw = Level 1:0)
8F/8069: 8D E9 0A     STA $0AE9    (Bronze Axe = Level 1:0)
8F/806C: 8D EB 0A     STA $0AEB    (Knight Basher = Level 1:0)
8F/806F: 8D ED 0A     STA $0AED    (Atom Smasher = Level 1:0)
8F/8072: 8D EF 0A     STA $0AEF    (Horn Spear = Level 1:0)
8F/8075: 8D F1 0A     STA $0AF1    (Bronze Spear = Level 1:0)
8F/8078: 8D F3 0A     STA $0AF3    (Lance = Level 1:0)
8F/807B: 8D F5 0A     STA $0AF5    (Laser Lance = Level 1:0)
                                   (oops, what about the Bazooka?  leaving it at its
                                    default of 0 causes bugs with the computer-controlled
                                    character and with Energize.)

this is just done when you start a new game, so there's no reason to have unrolled the loop.  however, as with a couple of prior posters' examples, it presents an opportunity to fix something without extra space usage: there's a bug resulting from the game never setting $0AF7 to 0100h to initialize the Bazooka's level. :)
Title: Re: bad coding in roms
Post by: LostTemplar on January 02, 2013, 07:59:37 am
I just noticed a game that uses the usual 12x12 fixed-width font approach for its Japanese text. That means that the rendering differs between characters on odd and even positions; however, instead of checking this in advance the game always renders the character as if it were on an even position, and then goes on to overwrite it with the odd version if the position actually is odd. So the character is actually rendered twice every second time!
Title: Re: bad coding in roms
Post by: Zoinkity on January 05, 2013, 12:14:17 am
Compilers Gone Wild!

ADDIU   SP,SP,FFF8
SW   S8,0000 (SP)
ADDU   S8,SP,R0
SW   A0,0008 (S8)
ADDU   SP,S8,R0
LW   S8,0000 (SP)
ADDIU   SP,SP,0008
JR   RA
NOP

The value isn't even used (dummied out debug routine most likely) but seriously?  At the least they could write:
JR   RA
SW   A0,0000 (SP)

It isn't just this either.  A lot of this title copies SP to S8 before copying it back and correcting it.  This just happened to be the shortest (and most ridiculous) example.
Title: Re: bad coding in roms
Post by: KingMike on April 01, 2013, 05:39:56 pm
I suppose it's not so much bad as weird.

Famicom Board Game bankswap code:

Code: [Select]
00:830C:A9 00     LDA #$00
 00:830E:2C A9 01  BIT $01A9 = #$00
 00:8311:2C A9 02  BIT $02A9 = #$00
 00:8314:2C A9 03  BIT $03A9 = #$00
 00:8317:84 01     STY $0001 = #$00
 00:8319:A8        TAY
 00:831A:B9 23 83  LDA $8323,Y @ $8323 = #$DC
 00:831D:99 23 83  STA $8323,Y @ $8323 = #$DC
 00:8320:A4 01     LDY $0001 = #$00
 00:8322:60        RTS

Strange that it would use odd values for bank numbers.
Code: [Select]
DC 11011100
D9 11011001
D6 11010110
D3 11010011
Looks like the last two bits are the CHR bank to swap in, and D2-D3 are an inverted copy. I suspect it has something to do with bus-conflicts, but why the odd values?

Using the BIT instruction to essentially auto-ignore an instruction. The game would jump to the line that LDA (A9 xx) the appropriate bank number to swap in.
Title: Re: bad coding in roms
Post by: Bisqwit on April 04, 2013, 12:54:55 pm
Famicom Board Game bankswap code:
Code: [Select]
00:830C:A9 00     LDA #$00
 00:830E:2C A9 01  .DB $2C : LDA #$01
 00:8311:2C A9 02 . DB $2C : LDA #$02
 00:8314:2C A9 03 . DB $2C : LDA #$03
If it weren't so widely known and used by now, I would call that code clever, not weird or bad.

The LDA+STA pair is odd, though. Which mapper is this?
Title: Re: bad coding in roms
Post by: KingMike on April 04, 2013, 01:20:36 pm
CNROM (mapper 3)
Title: Re: bad coding in roms
Post by: justin3009 on April 04, 2013, 01:23:58 pm
Load Klarth
Code: [Select]
$C0/6D75 E2 20       SEP #$20                A:0000 X:0000 Y:6B91 P:envmxdiZc
$C0/6D77 B9 1B 00    LDA $001B,y[$7E:6BAC]   A:0000 X:0000 Y:6B91 P:envMxdiZc - Loads PC2 Status
$C0/6D7A 89 06       BIT #$06                A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6D7C F0 03       BEQ $03    [$6D81]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6D81 B9 18 00    LDA $0018,y[$7E:6BA9]   A:0000 X:0000 Y:6B91 P:envMxdiZc - Loads if poison is active
$C0/6D84 89 80       BIT #$80                A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6D86 F0 03       BEQ $03    [$6D8B]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6D8B AD 67 06    LDA $0667  [$7E:0667]   A:0000 X:0000 Y:6B91 P:envMxdiZc - Checks Victory status
$C0/6D8E F0 04       BEQ $04    [$6D94]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6D94 B9 BA 00    LDA $00BA,y[$7E:6C4B]   A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6D97 D0 07       BNE $07    [$6DA0]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6D99 A9 00       LDA #$00                A:0000 X:0000 Y:6B91 P:envMxdiZc - Loads idle animation
$C0/6D9B 99 79 00    STA $0079,y[$7E:6C0A]   A:0000 X:0000 Y:6B91 P:envMxdiZc - Stores to character animation
$C0/6D9E 80 04       BRA $04    [$6DA4]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6DA4 C2 20       REP #$20                A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/6DA6 64 0A       STZ $0A    [$00:000A]   A:0000 X:0000 Y:6B91 P:envmxdiZc
$C0/6DA8 64 0C       STZ $0C    [$00:000C]   A:0000 X:0000 Y:6B91 P:envmxdiZc
$C0/6DAA B9 00 00    LDA $0000,y[$7E:6B91]   A:0000 X:0000 Y:6B91 P:envmxdiZc - Character position in battle (Where do they stand)
$C0/6DAD 29 FF 00    AND #$00FF              A:0601 X:0000 Y:6B91 P:envmxdizc
$C0/6DB0 0A          ASL A                   A:0001 X:0000 Y:6B91 P:envmxdizc
$C0/6DB1 AA          TAX                     A:0002 X:0000 Y:6B91 P:envmxdizc
$C0/6DB2 BD 4F 06    LDA $064F,x[$7E:0651]   A:0002 X:0002 Y:6B91 P:envmxdizc - Load X coordinates in battle
$C0/6DB5 85 04       STA $04    [$00:0004]   A:0070 X:0002 Y:6B91 P:envmxdizc
$C0/6DB7 AD 05 06    LDA $0605  [$7E:0605]   A:0070 X:0002 Y:6B91 P:envmxdizc
$C0/6DBA 38          SEC                     A:0090 X:0002 Y:6B91 P:envmxdizc
$C0/6DBB ED 4F 06    SBC $064F  [$7E:064F]   A:0090 X:0002 Y:6B91 P:envmxdizC
$C0/6DBE 18          CLC                     A:0000 X:0002 Y:6B91 P:envmxdiZC
$C0/6DBF 65 04       ADC $04    [$00:0004]   A:0000 X:0002 Y:6B91 P:envmxdiZc
$C0/6DC1 10 01       BPL $01    [$6DC4]      A:0070 X:0002 Y:6B91 P:envmxdizc
$C0/6DC4 85 04       STA $04    [$00:0004]   A:0070 X:0002 Y:6B91 P:envmxdizc
$C0/6DC6 D9 04 00    CMP $0004,y[$7E:6B95]   A:0070 X:0002 Y:6B91 P:envmxdizc - PC 2 X coordinates
$C0/6DC9 F0 20       BEQ $20    [$6DEB]      A:0070 X:0002 Y:6B91 P:envmxdiZC
$C0/6DEB C2 20       REP #$20                A:0070 X:0002 Y:6B91 P:envmxdiZC
$C0/6DED 22 DE AF C1 JSL $C1AFDE[$C1:AFDE]   A:0070 X:0002 Y:6B91 P:envmxdiZC

Load Mint
Code: [Select]
$C0/46D5 E2 20       SEP #$20                A:0000 X:0000 Y:6B91 P:envmxdiZc
$C0/46D7 B9 1B 00    LDA $001B,y[$7E:6BAC]   A:0000 X:0000 Y:6B91 P:envMxdiZc - Loads PC2 Status
$C0/46DA 89 06       BIT #$06                A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/46DC F0 03       BEQ $03    [$46E1]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/46E1 B9 18 00    LDA $0018,y[$7E:6BA9]   A:0000 X:0000 Y:6B91 P:envMxdiZc - Loads if poison is active
$C0/46E4 89 80       BIT #$80                A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/46E6 F0 03       BEQ $03    [$46EB]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/46EB AD 67 06    LDA $0667  [$7E:0667]   A:0000 X:0000 Y:6B91 P:envMxdiZc - Checks Victory status
$C0/46EE F0 04       BEQ $04    [$46F4]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/46F4 B9 BA 00    LDA $00BA,y[$7E:6C4B]   A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/46F7 D0 07       BNE $07    [$4700]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/46F9 A9 00       LDA #$00                A:0000 X:0000 Y:6B91 P:envMxdiZc - Loads idle animation
$C0/46FB 99 79 00    STA $0079,y[$7E:6C0A]   A:0000 X:0000 Y:6B91 P:envMxdiZc - Stores to character animation
$C0/46FE 80 04       BRA $04    [$4704]      A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/4704 C2 20       REP #$20                A:0000 X:0000 Y:6B91 P:envMxdiZc
$C0/4706 64 0A       STZ $0A    [$00:000A]   A:0000 X:0000 Y:6B91 P:envmxdiZc
$C0/4708 64 0C       STZ $0C    [$00:000C]   A:0000 X:0000 Y:6B91 P:envmxdiZc
$C0/470A B9 00 00    LDA $0000,y[$7E:6B91]   A:0000 X:0000 Y:6B91 P:envmxdiZc - Character position in battle (Where do they stand)
$C0/470D 29 FF 00    AND #$00FF              A:0201 X:0000 Y:6B91 P:envmxdizc
$C0/4710 0A          ASL A                   A:0001 X:0000 Y:6B91 P:envmxdizc
$C0/4711 AA          TAX                     A:0002 X:0000 Y:6B91 P:envmxdizc
$C0/4712 BD 4F 06    LDA $064F,x[$7E:0651]   A:0002 X:0002 Y:6B91 P:envmxdizc - Load X coordinates in battle
$C0/4715 85 04       STA $04    [$00:0004]   A:0070 X:0002 Y:6B91 P:envmxdizc
$C0/4717 AD 05 06    LDA $0605  [$7E:0605]   A:0070 X:0002 Y:6B91 P:envmxdizc
$C0/471A 38          SEC                     A:0090 X:0002 Y:6B91 P:envmxdizc
$C0/471B ED 4F 06    SBC $064F  [$7E:064F]   A:0090 X:0002 Y:6B91 P:envmxdizC
$C0/471E 18          CLC                     A:0000 X:0002 Y:6B91 P:envmxdiZC
$C0/471F 65 04       ADC $04    [$00:0004]   A:0000 X:0002 Y:6B91 P:envmxdiZc
$C0/4721 10 01       BPL $01    [$4724]      A:0070 X:0002 Y:6B91 P:envmxdizc
$C0/4724 85 04       STA $04    [$00:0004]   A:0070 X:0002 Y:6B91 P:envmxdizc
$C0/4726 D9 04 00    CMP $0004,y[$7E:6B95]   A:0070 X:0002 Y:6B91 P:envmxdizc - PC 2 X coordinates
$C0/4729 F0 20       BEQ $20    [$474B]      A:0070 X:0002 Y:6B91 P:envmxdiZC
$C0/474B C2 20       REP #$20                A:0070 X:0002 Y:6B91 P:envmxdiZC
$C0/474D 22 DE AF C1 JSL $C1AFDE[$C1:AFDE]   A:0070 X:0002 Y:6B91 P:envmxdiZC

Old data that I'm starting to take a look at.  This is an example of loading the character's battle data, coordinates, etc..

This is a chunk of data between Klarth and Mint.  Hilariously, they share the EXACT same code in this chunk.  All the other PC's share something extremely similar as well.  Same data just completely different location in banks.  I even took the liberty awhile ago to re-write that bit for a few PC's and bumped all this similar code to a new area then had each of their routines JSL to it.  They still worked flawlessly.

Not really 'bad coding', but more or less it's just a huge waste of room.
Title: Re: bad coding in roms
Post by: Bisqwit on April 04, 2013, 11:24:03 pm
Maybe they used some kind of code generator / set of macros...
Or had an intern doing copypaste coding :-)
Title: Re: bad coding in roms
Post by: Xenesis on April 07, 2013, 09:30:20 pm
I see this a lot in Intelligent System's coding. It irks me because it wastes a *lot* of space (One 32-bit pointer per possible input) and if it somehow ever got a value out of range it'd jump to a garbage address.

Code: [Select]
08085430 0080     lsl     r0,r0,#0x2 ;Input here is lsl'd by four
08085432 4903     ldr     r1,=#0x8085444 ;A list of pointers here
08085434 1840     add     r0,r0,r1
08085436 6800     ldr     r0,[r0]
08085438 4687     mov     r15,r0 ;Then just updates the program counter. ;_;

This particular example is from Advance Wars 2. Although it seems to be in a lot of IS' GUI code. :|
Title: Re: bad coding in roms
Post by: Normmatt on April 08, 2013, 01:55:08 am
I see this a lot in Intelligent System's coding. It irks me because it wastes a *lot* of space (One 32-bit pointer per possible input) and if it somehow ever got a value out of range it'd jump to a garbage address.

Code: [Select]
08085430 0080     lsl     r0,r0,#0x2 ;Input here is lsl'd by four
08085432 4903     ldr     r1,=#0x8085444 ;A list of pointers here
08085434 1840     add     r0,r0,r1
08085436 6800     ldr     r0,[r0]
08085438 4687     mov     r15,r0 ;Then just updates the program counter. ;_;

This particular example is from Advance Wars 2. Although it seems to be in a lot of IS' GUI code. :|

That isn't bad coding. That is simply how jump tables are handled on arm. The default case (if the index is out of bounds etc) is generally handled before this segment of code so it's perfectly safe.
Title: Re: bad coding in roms
Post by: Bisqwit on April 10, 2013, 01:05:38 am
In Simon's Quest:

Code: [Select]
PlotAction05_RunGameMaybe
        $CC24  A5 2C:       lda PlotAction05_GameLoop_WhichAction
        $CC26  C9 03:       cmp #$03
        $CC28  D0 0B:       bne +               ; $CC35
        $CC2A  20 15 C6:    jsr RenderHPbar
        $CC2D  20 08 D3:    jsr GameLoop_CheckIfPauseEnteredOrActive
        $CC30  A5 26:       lda GamePaused
        $CC32  F0 01:       beq +               ; $CC35
        $CC34  60:          rts

+       $CC35  A5 2C:       lda PlotAction05_GameLoop_WhichAction
        $CC37  20 BB C5:    jsr JumpWithParams
_JumpPointerTable_1CC3A
        $CC3A  54 CC:       .word (PlotAction05_Action00_ShowGameBeginScreenWithRemainingLives
        $CC3C  7E CC:       .word (PlotAction05_Action01_LevelLoad_ResetNPCs) ;CC7E (1CC7E) ()
        $CC3E  9A CC:       .word (PlotAction05_Action02_LevelLoad_Part2) ;CC9A (1CC9A) ()
        $CC40  D5 CD:       .word (PlotAction05_Action03_GameActive) ;CDD5 (1CDD5) ()
        $CC42  A2 CE:       .word (PlotAction05_Action04_NightTimeTransition_Begin) ;CEA2 (1CE
        $CC44  B8 CE:       .word (PlotAction05_Action05_NightTimeTransition_FadeOutLoop) ;CEB
        $CC46  CF CE:       .word (PlotAction05_Action06_NightTimeTransition_Middle) ;CECF (1C
        $CC48  F4 CE:       .word (PlotAction05_Action07_NightTimeTransition_FadeInLoop) ;CEF4
        $CC4A  8C CF:       .word (PlotAction05_Action08_RelocateSimonLevelBeginningMaybe) ;CF
        $CC4C  3A D0:       .word (PlotAction05_Action09_EnterOrExitRoom) ;D03A (1D03A) ()
        $CC4E  75 D0:       .word (PlotAction05_Action0A_RelocateSimonLevelBeginningMaybe) ;D0
        $CC50  03 D0:       .word (PlotAction05_Action0B) ;D003 (1D003) ()
        $CC52  79 CE:       .word (PlotAction05_Action0C) ;CE79 (1CE79) () 

For some unidentified reason, the game does an explicit check here whether the state is #3, and if it is, runs RenderHPbar, GameLoop_CheckIfPauseEnteredOrActive, and a check for GamePaused, and then anyway proceeds to branch using a jump table depending on the state number, instead of doing that stuff in the beginning of PlotAction05_Action03_GameActive, the routine that would be called if state indeed is #3. (And this is indeed the only location that accesses PlotAction05_Action03_GameActive).
Title: Re: bad coding in roms
Post by: Dwedit on April 10, 2013, 10:32:08 pm
Some of the dumber things I've seen I've chalked up to macros, such as code that performs arithmetic operations to build up a constant. Example:

Code: [Select]
lda #$0030
add #$0100
ora #$8000

instead of:
Code: [Select]
lda #$8130


On ARM, you pretty much have to build constants that way, since you can only fit 8 shifted bits of value into a constant.  The code would be two instructions to store 0x8130 into a register.
But this makes no sense on a 6502-style processor.
Title: Re: bad coding in roms
Post by: Xenesis on April 11, 2013, 08:18:29 pm
That isn't bad coding. That is simply how jump tables are handled on arm. The default case (if the index is out of bounds etc) is generally handled before this segment of code so it's perfectly safe.

I'm aware of that, but it's so incredibly wasteful - it's a jump table with only 10 values that do anything and over a hundred null values.

Also, using mov r15 instead of bx always feels hacky.
Title: Re: bad coding in roms
Post by: FinS on April 14, 2013, 01:03:25 pm
Here's an easy one for SNES.
Code: [Select]
$03/BB5F A5 15       LDA $15   
$03/BB61 8D 04 42    STA $4204 
$03/BB64 9C 05 42    STZ $4205 
$03/BB67 A9 03       LDA #$03   
$03/BB69 8D 06 42    STA $4206 
$03/BB6C 20 B8 BF    JSR $BFB8 

$03/BFB8 EA          NOP       
$03/BFB9 60          RTS       

$03/BB6F 7B          TDC       
$03/BB70 AD 14 42    LDA $4214 
$03/BB73 0A          ASL A     
$03/BB74 AA          TAX       
$03/BB75 FA          PLX       
$03/BB76 7A          PLY       
$03/BB77 A9 3F       LDA #$3F   
It could have been more effectively written.
Code: [Select]
$03/BB5F 80 14       BRA 20
(NOP X 20 or fill in the blank)
$03/BB75 FA          PLX       
$03/BB76 7A          PLY       
$03/BB77 A9 3F       LDA #$3F 
Title: Re: bad coding in roms
Post by: KingMike on April 14, 2013, 01:46:12 pm
I understand a delay is needed when using the multiplication/division registers, but when it seems to completely throw out the results at the end, what's the point of the code?
Title: Re: bad coding in roms
Post by: FinS on April 14, 2013, 02:13:31 pm
I understand a delay is needed when using the multiplication/division registers, but when it seems to completely throw out the results at the end, what's the point of the code?

Exactly. The only thing I can think is that they were originally trying to do something with it then decided against it but failed to clean up the code.
Title: Re: bad coding in roms
Post by: KC on October 25, 2013, 03:18:51 pm
I found the perfect code to revive this topic: http://puu.sh/4ZjgS/af6ace21f3.png
The function jal jumps to is computing the length of the string given in a0: http://puu.sh/4Zk2B/dbb47c98f8.png

So the function in the first picture pretty much does...
Code: [Select]
int func(char* str)
{
int k = 0;
while (strlen(str) > k) k++;
return k;
}
Title: Re: bad coding in roms
Post by: BRPXQZME on October 27, 2013, 05:49:59 am
It’s not a ROM, and it’s not an O(n2) strlen, but the XL Engline people recently found something similarly pointless (http://xlengine.com/missing-code/) in Daggerfall.

Silly compilers think alike, perhaps? One would hope, but you never know... ;)
Title: Re: bad coding in roms
Post by: FinS on March 02, 2014, 11:02:24 am
I have no idea what's going on here but the game appears to have successfully jumped into and navigated a pointer table.
Congrats! Densetsu no Ogre Battle!

I found this in my hack and looked at the original to see it was in there even before translation.

It occurs at the end of the opening sequence story.

Code: [Select]
$00/D86B A5 0A       LDA $0A    [$00:000A]   A:0AC0 X:006C Y:5501 P:envmxdizC
$00/D86D 20 D2 F5    JSR $F5D2  [$00:F5D2]   A:0200 X:006C Y:5501 P:envmxdizC
**********
$00/F5D2 A2 01 FF    LDX #$FF01              A:0200 X:006C Y:5501 P:envmxdizC
$00/F5D5 A0 E0 00    LDY #$00E0              A:0200 X:FF01 Y:5501 P:eNvmxdizC
$00/F5D8 C9 7F D0    CMP #$D07F              A:0200 X:FF01 Y:00E0 P:envmxdizC
$00/F5DB 1E EB A9    ASL $A9EB,x[$00:A8EC]   A:0200 X:FF01 Y:00E0 P:envmxdizc
$00/F5DE 80 85       BRA $85    [$F565]      A:0200 X:FF01 Y:00E0 P:eNvmxdizC
$00/F565 DE C0 DE    DEC $DEC0,x[$00:DDC1]   A:0200 X:FF01 Y:00E0 P:eNvmxdizC
$00/F568 C1 DE       CMP ($DE,x)[$00:FFD3]   A:0200 X:FF01 Y:00E0 P:eNvmxdizC
$00/F56A C2 DE       REP #$DE                A:0200 X:FF01 Y:00E0 P:eNvmxdizc
$00/F56C C3 DE       CMP $DE,s  [$00:20CE]   A:0200 X:FF01 Y:00E0 P:envmxdizc
$00/F56E C4 DE       CPY $DE    [$00:00DE]   A:0200 X:FF01 Y:00E0 P:envmxdizc
$00/F570 B3 DE       LDA ($DE,s),y[$00:5635] A:0200 X:FF01 Y:00E0 P:eNvmxdizc
$00/F572 CA          DEX                     A:8408 X:FF01 Y:00E0 P:eNvmxdizc
$00/F573 DE CB DE    DEC $DECB,x[$00:DDCB]   A:8408 X:FF00 Y:00E0 P:eNvmxdizc
$00/F576 CC DE CD    CPY $CDDE  [$00:CDDE]   A:8408 X:FF00 Y:00E0 P:envmxdizc
$00/F579 DE CE DE    DEC $DECE,x[$00:DDCE]   A:8408 X:FF00 Y:00E0 P:eNvmxdizc
$00/F57C CA          DEX                     A:8408 X:FF00 Y:00E0 P:eNvmxdizc
$00/F57D DF CB DF CC CMP $CCDFCB,x[$CC:DECA] A:8408 X:FEFF Y:00E0 P:eNvmxdizc
$00/F581 DF CD DF CE CMP $CEDFCD,x[$CE:DECC] A:8408 X:FEFF Y:00E0 P:envmxdizC
$00/F585 DF 86 02 A5 CMP $A50286,x[$A5:0185] A:8408 X:FEFF Y:00E0 P:envmxdizC
$00/F589 49 85 04    EOR #$0485              A:8408 X:FEFF Y:00E0 P:envmxdizC
$00/F58C A0 00 00    LDY #$0000              A:808D X:FEFF Y:00E0 P:eNvmxdizC
$00/F58F 64 05       STZ $05    [$00:0005]   A:808D X:FEFF Y:0000 P:envmxdiZC
$00/F591 7B          TDC                     A:808D X:FEFF Y:0000 P:envmxdiZC
$00/F592 B7 02       LDA [$02],y[$08:6E00]   A:0000 X:FEFF Y:0000 P:envmxdiZC
$00/F594 C9 20 B0    CMP #$B020              A:0808 X:FEFF Y:0000 P:envmxdizC
$00/F597 12 AA       ORA ($AA)  [$00:5500]   A:0808 X:FEFF Y:0000 P:envmxdizc
$00/F599 BD B2 F5    LDA $F5B2,x[$00:F4B1]   A:5D5D X:FEFF Y:0000 P:envmxdizc
$00/F59C F0 11       BEQ $11    [$F5AF]      A:5722 X:FEFF Y:0000 P:envmxdizc


Looks like it was supposed to enter that subroutine with an 8-bit accumulator. Following seems to have fixed it.
Code: [Select]
$00/D867 E2 20       SEP #$20   
$00/D869 A9 60       LDA #$60   
$00/D86B 85 0A       STA $0A   
$00/D86D 20 D2 F5    JSR $F5D2 
Title: Re: bad coding in roms
Post by: Scio on March 03, 2014, 10:55:12 am
There was this one Master System game that used a routine to read 3 bytes from the beginning of a text block (like 0A CA 80), and then placed a portrait of the character who was talking on the dialogue box. The thing is, these bytes only set the position onscreen (it's the next byte that changes the portrait)... but the portrait never moves from that position at all. Wouldn't it be easier to assume the portrait was always going to be in that position, instead of wasting 3 bytes in every line and a few processor cycles?

There was also a PSX game that read a 7-byte value to place a portrait (I think it was Rhapsody), where the first 4 bytes were entirely useless. Probably something left from the debug phase?
Title: Re: bad coding in roms
Post by: cret on March 03, 2014, 04:36:44 pm
Code: [Select]
╒ (fcn) sym.Interrupt_LCDC_Status 6
│                                 0x00000048   4        af           xor a
│                                 ;  Ramswitch
│                                 0x00000049  16        ea0040       ld [0x4000], a
│                                 0x0000004c   4        fb           ei
╘                                 0x0000004d  16        c9           ret

pokemon green, why are they doing ei. it doesn't do anything because ret from an interrupt disables it
Title: Re: bad coding in roms
Post by: Drenn on March 03, 2014, 09:52:30 pm
ret doesn't re-enable interrupts, reti does. Instead of "ei, ret" it could be just "reti". But of course, one opcode will hardly make a difference.
Title: Re: bad coding in roms
Post by: KingMike on March 03, 2014, 09:55:36 pm
Isn't Pokemon Red/Green pretty broken anyways?
SELECT Pokemon corruption! :P
Title: Re: bad coding in roms
Post by: OneCrudeDude on March 04, 2014, 02:47:52 pm
I wonder, has anyone been able to pinpoint the reason why Contra Force suffers from so much slowdown?  There has to be something that's not coded right, aside from the entire game.

And another, more well known example (not sure if it's been mentioned) is Ghostbusters for the NES.  The Select button acts as the pause button, but here's the thing.  You can actually "pause" the title screen, and it will just keep flashing the press start text until it is unpaused.  Same as before, if you pause the "copyright info" screen that shows up after the title, you can pause that to indefinitely stay on that screen.  Finally, when the busters cross the streams, they turn into a pile of weird shapes.  That's because the game erroneously calls the beam graphics, which are located one 'line' above the actual "falling down" sprite that's in the game.  Finally, the in-game music likes to spit and sputter, which some people have said is a result due to PCM artifacting.

I have no code sources or the like, I found out most of them by pure luck.
Title: Re: bad coding in roms
Post by: KingMike on March 04, 2014, 10:23:16 pm
Maybe Contra Force wasn't meant to be a Contra game? The canceled Japanese version was called Arc Hound.

Ghostbusters was probably just broken. If you went through all the trouble of beating the Japanese version,
your ending is a black screen with (eventually) two characters of glitch text.
Title: Re: bad coding in roms
Post by: Gideon Zhi on March 04, 2014, 11:05:42 pm
Maybe Contra Force wasn't meant to be a Contra game? The canceled Japanese version was called Arc Hound.

This still doesn't explain how Contra 3 is Contra 3 when there are three NES Contra games (Contra, Contra Force, and Super C). It's not even numbered as such in Japan! *brain hurts*
Title: Re: bad coding in roms
Post by: Scio on March 04, 2014, 11:21:34 pm
From what I gather, it's because they tried to do a lot of complicated things, and didn't finish them properly.

- The game has 4 selectable characters, all with different stats. You can change them during the stage, whenever a player loses a continue.
- The game has side-view and top-view stages.
- It has an AI system, if you don't have someone else to play as Player 2.

Are there any other NES games that use an AI system for player 2? I mean, something more code-intensive, like shooting in all directions and jumping, not just moving around. My best guess is that this part is the bottleneck, they probably didn't clean the code, and ended up wasting a ton of cycles for AI.
Title: Re: bad coding in roms
Post by: OneCrudeDude on March 05, 2014, 12:10:11 am
@KingMike:  Supposedly the Japanese version has the same ending as the American version, but, unbelievably, it had one more typo; "great" was written as "grate".  I wouldn't be surprised if the people who programmed NES GhostBusters eventually went on to develop the Pokemon games.  The sheer magnitude of game breaking bugs present in GB and Pokemon Green is too much to be a mere coincidence.  Amazingly, Bits Laboratory co-developed Brawl for the Wii, and is probably their last game.

I was hoping that someone would've been able to unearth some of the code, and see why it's tied up.  Considering what Scio said about it being "very technical" and how the game was cancelled in Japan, it wouldn't be surprising if the game was just finalized so that they could get it out there.  Wasn't there a bootleg version of the game that supposedly fixes some of the slowdown?
Title: Re: bad coding in roms
Post by: KingMike on March 05, 2014, 01:42:05 am
This still doesn't explain how Contra 3 is Contra 3 when there are three NES Contra games (Contra, Contra Force, and Super C). It's not even numbered as such in Japan! *brain hurts*
Operation C was released before Contra 3 (and considering the recently released "Contra IV" proto, maybe Konami did consider the GB game officially third at one point), Contra Force was released after.
It would've been great to consider OC the third game, giving the C a double-meaning. :D
Title: Re: bad coding in roms
Post by: snarfblam on March 05, 2014, 05:44:30 pm
In most cases, a game with significant slowdown is probably just poorly programmed, or outright asking too much of the hardware. I've heard that the FDS versions of Metroid and Zelda exhibit less slowdown. I don't know if that's true, but if it is, there's really no excuse for worse NES performance other than a hurried port.

Are there any other NES games that use an AI system for player 2? I mean, something more code-intensive, like shooting in all directions and jumping, not just moving around.

In Conquest of the Crystal Palace, when you summon your little dog buddy, he runs all around the screen attacking enemies and avoiding obstacles, and he seems to do a pretty decent job too. He even seems to be able to traverse moving platforms with some success. No slow down to speak of, either.
Title: Re: bad coding in roms
Post by: OneCrudeDude on March 06, 2014, 12:48:56 pm
To be completely fair, Contra Force doesn't have a whole lot going on in the first place.  The enemies don't do anything spectacular, just sit there and throw grenades, and there rarely appears to be more than two enemies on screen.  There's less going on in this game than there is in Contra and Super C, both of which push a lot of action with minimal and short lived slowdown.  And game speeds up as soon as the enemies die, so maybe their attacking processes are incredibly unoptimized.
Title: Re: bad coding in roms
Post by: gauveldt on March 07, 2014, 06:13:12 am
Code: [Select]
9.  $C2/801A 9D 7E 31    STA $317E,x[$7E:3544]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/801D 9D 80 31    STA $3180,x[$7E:3546]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8020 9D 82 31    STA $3182,x[$7E:3548]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8023 9D 84 31    STA $3184,x[$7E:354A]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8026 9D 86 31    STA $3186,x[$7E:354C]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8029 9D 88 31    STA $3188,x[$7E:354E]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/802C 9D 8A 31    STA $318A,x[$7E:3550]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/802F 9D 8C 31    STA $318C,x[$7E:3552]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8032 9D 8E 31    STA $318E,x[$7E:3554]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8035 9D 90 31    STA $3190,x[$7E:3556]   A:0140 X:03C6 Y:2000 P:envmxdizc
    $C2/8038 9D 92 31    STA $3192,x[$7E:3558]   A:0140 X:03C6 Y:2000 P:envmxdizc 
    $C2/803B 9D 94 31    STA $3194,x[$7E:355A]   A:0140 X:03C6 Y:2000 P:envmxdizc

Tales of Phantasia

It's used to erase item names when you scroll down the list.  Not sure why it was used like this.

Decided to write a mini loop for this sucker just to make it easier.

This has the appearance of loop unrolling.  You might have to give the programmers slack here as they were probably dealing with performance issues throughout the game due to the potential for audio streaming to occur at any time and were probably living in machine cycles the entire coding process.  In that case their mindset would have been on fast code over compact code and lots of loop unrolling is what you get.

March 07, 2014, 06:45:58 am - (Auto Merged - Double Posts are not allowed before 7 days.)
Because then you would be setting the carry flag instead of clearing it. ;)

I think it's intended in the example since the first example is a sep #MEM8 : clc : adc #CONSTANT where the second is sep #MEM8+CARRY : adc #CONSTANT-1 (carry==1 cancels the -1).  The CONSTANT-1 math would be done in the assembler (so it has no effect on runtime cycles).  The former example adds 1 byte of ROM space and several clock cycles for the clc where the second example is a good optimization that eliminates the extra byte and saves cycles.  The second example would be far preferable in anything being looped or otherwise frequently utilized, say like IRQ or NMI handlers.
Title: Re: bad coding in roms
Post by: oziphantom on July 27, 2015, 11:57:29 am
Ok Thread resurrection!
Seeing as what I'm about to post is
a.) in line with this topic and starting another one when there was this one seems wrong
b.) features a lot of IS bashing which is what I'm going to be posting
c.) we are not suppose to post large reams of code, but this post is about large reams of code..
I think it is valid...

Panel De Pon/ Tetris Attack
OH DEAR, somebody had ROM to burn and was not afraid to do it...

Some highlights include
Code: [Select]
_noOverflow                      rep #$20 ;a 16 bit
                                 asl 
                                 asl 
                                 asl 
                                 sep #$20 ;a 8 bit
                                 lsr 
                                 lsr 
                                 lsr 
                                 xba 
                                 pha 

Or this, which I put down to being  a macro but they could have done better than this
Code: [Select]
                                 ldy #$A952
                                 jsr addVRAMtoDMATable
                                 plb 
                                 bra _skipCode
                                 .long $7E2800
                                 .word $06C0,$0080
                                 .byte $78
_skipCode                        bra j80A971

Most of the time the bra jumps to an RTS. Clearly written by a different programmer than the Decompress routine as that is master class.
Code: [Select]
One calls it like so
                                 jsr decompress_src_dest ;will make pc+6 for return
                                 .long $94AF3B,$7F5D00
                                 phb 
And then the start of the function is as such
decompress_src_dest              php 
                                 rep #$30 ;a,x,y 16 bit
                                 phb 
                                 phx 
                                 phy 
                                 sep #$20 ;a 8 bit
                                 lda $09,s ;read calling bank
                                 pha 
                                 plb  ;set to be data bank r
                                 rep #$20 ;a 16 bit
                                 lda $07,s ;read calling address
                                 tax 
                                 clc 
                                 adc #$0006 ;skip 6 src,dest bytes
                                 sta $07,s ;save back into stack to fix return address

July 27, 2015, 12:07:58 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Due to post char limits ...

Lets plot the blocks shall we?
Code: [Select]
pltBlock_ABlock_YMapIndex        phx 
                                 phy 
                                 rep #$30 ;a,x,y 16 bit
                                 phb 
                                 phk 
                                 plb 
                                 ldx CurrentRowToVRAMLUTPtr
                                 stx jl7E0024
                                 and #$00FF
                                 asl 
                                 tax 
                                 lda Player1_Tile_Map_00_0,y
                                 bit #tileType.bounceMode2
                                 bne _rock
                                 bit #tileType.solidBlock
                                 bne _isSolidBlock
                                 bit #tileType.darkPallete
                                 bne _isDarkPallete
                                 bit #tileType.shockFace
                                 bne _isShockFace
                                 bit #invalid
                                 bne _isBounceMode
                                 bit #tileType.bounceMode
                                 bne _isBounceMode
                                 tya 
                                 and #$FEFF
                                 tay 
                                 lda (jl7E0024),y
                                 tay 
                                 jsr (plotNormalLUT,x)
                                 jmp _exit
_isDarkPallete                   tya 
                                 and #$FEFF
                                 tay 
                                 lda (jl7E0024),y
                                 tay 
                                 jsr (plotDarkLUT,x)
                                 jmp _exit
_isShockFace                     tya 
                                 and #$FEFF
                                 tay 
                                 lda (jl7E0024),y
                                 tay 
                                 jsr (plotWinceLUT,x)
                                 jmp _exit
_flash                           tya 
                                 and #$FEFF
                                 tay 
                                 lda (jl7E0024),y
                                 tay 
                                 jsr (plotFlashLUT,x)
                                 jmp _exit
_isBounceMode                    tya 
                                 and #$FEFF
                                 tay 
                                 lda (jl7E0024),y
                                 tay 
                                 jsr (PlotBounceLUT,x)
                                 jmp _exit
_rock                            tya 
                                 and #$FEFF
                                 tay 
                                 lda (jl7E0024),y
a85859C                          tay 
a85859D                          jsr (plotRockLUT,x)
                                 jmp _exit
_isSolidBlock                    tya 
                                 and #$FEFF
a8585A7                          tay 
a8585A8                          lda (jl7E0024),y
                                 tay 
                                 lda a7E0354
                                 bne b8585B6
                                 jsr (jp858EAB,x)
                                 jmp _exit
b8585B6                          jsr (jp858EF5,x)
                                 jmp _exit
_exit                            plb 
                                 ply 
                                 plx 
                                 rtl 
.snip.
Code: [Select]
plotNormalLUT                    .word <>clearTile ,<>plotHeart ,<>plotCircle ,<>plotUpTriangle
                                 .word <>plotStar ,<>plotDiamond ,<>plotDownTriangle ,<>plotExclamationBlock
plotDarkLUT                      .word <>clearTile ,<>plotDarkHeart ,<>plotDarkCircle ,<>plotDarkTriangle
                                 .word <>plotDarkStar ,<>plotDarkDiamond ,<>plotDarkDownTriangle ,<>plotDarkExclamationBlock
plotWinceLUT                     .word <>clearTile ,<>plotWinceHeart ,<>plotWinceCircle ,<>plotWinceUpTriangle
                                 .word <>plotWinceStar ,<>plotWinceDiamond ,<>plotWinceDownTriangle ,<>plotFlashExclamationBlock
plotFlashLUT                     .word <>clearTile ,<>plotFlashHeart ,<>plotFlashCircle ,<>plotFlashUpTriangle
                                 .word <>plotFlashStar ,<>plotFlashDiamond ,<>plotFlashDownTriangle ,<>plotSolidBlock
PlotBounceLUT                    .word <>clearTile ,<>plotFullyRaisedHeart ,<>plotFullyRaisedCircle ,<>plotFullyRaisedTriangle
                                 .word <>plotFullyRaisedStar ,<>plotFullyRaisedDiamond ,<>plotFullyRaisedDownTriangle ,<>plotFullyRaiseExclamationBlock
                                 .word <>plotRaisedHeart ,<>plotRaisedCircle ,<>plotRaisedTriangle ,<>plotRaisedStar
                                 .word <>plotRaisedDiamond ,<>plotRaisedDownTriangle ,<>plotRaisedExclamationBlock ,<>plotHeart2
                                 .word <>plotCircle2 ,<>plotUpTriangle2 ,<>plotStar2 ,<>plotDiamond2
                                 .word <>plotDownTriangle ,<>plotExclamationBlock2 ,<>plotSquishedHeart ,<>plotSquishedCircle
                                 .word <>plotSquishedTriangle ,<>plotSquishedStar ,<>plotSquishedDiamond ,<>plotSquishedDownTriangle
                                 .word <>plotSquishedExclamationBlock ,<>plotHeart ,<>plotCircle ,<>plotUpTriangle
                                 .word <>plotStar ,<>plotDiamond ,<>plotDownTriangle ,<>plotExclamationBlock
plotRockLUT                      .word <>plotSingleRockBlock ,<>plotLeftEdgeRockBlock ,<>plotMiddleRockBlock ,<>plotEndRockBlock
plotSolidLUT                     .word <>plotSolidBlock
And then there is the actual plot code - brace yourself I have left the HEX in so you can see the patterns as well
Code: [Select]
85/87AC BB          clearTile                        tyx 
85/87AD A9 00 00                                     lda #$0000
85/87B0 9F 00 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_0,x
85/87B4 9F 02 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_1,x
85/87B8 9F 40 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_0,x
85/87BC 9F 42 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_1,x
85/87C0 60                                           rts 
85/87C1 BB          plotHeart                        tyx 
85/87C2 A9 A0 04                                     lda #blockTileMap.heart_TL
85/87C5 9F 00 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_0,x
85/87C9 A9 A1 04                                     lda #blockTileMap.heart_TR
85/87CC 9F 02 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_1,x
85/87D0 A9 A2 04                                     lda #blockTileMap.heart_BL
85/87D3 9F 40 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_0,x
85/87D7 A9 A3 04                                     lda #blockTileMap.heart_BR
85/87DA 9F 42 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_1,x
85/87DE 60                                           rts 
85/87DF BB          plotCircle                       tyx 
85/87E0 A9 A4 04                                     lda #blockTileMap.circle_TL
85/87E3 9F 00 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_0,x
85/87E7 A9 A5 04                                     lda #blockTileMap.circle_TR
85/87EA 9F 02 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_1,x
85/87EE A9 A6 04                                     lda #blockTileMap.circle_BL
85/87F1 9F 40 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_0,x
85/87F5 A9 A7 04                                     lda #blockTileMap.circle_BR
85/87F8 9F 42 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_1,x
85/87FC 60                                           rts 
85/87FD BB          plotUpTriangle                   tyx 
85/87FE A9 A8 04                                     lda #blockTileMap.upTriangle_TL
85/8801 9F 00 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_0,x
85/8805 A9 A9 04                                     lda #blockTileMap.upTriangle_TR
85/8808 9F 02 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_1,x
85/880C A9 AA 04                                     lda #blockTileMap.upTriangle_BL
85/880F 9F 40 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_0,x
85/8813 A9 AB 04                                     lda #blockTileMap.upTriangle_BR
85/8816 9F 42 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_1,x
85/881A 60                                           rts 
85/881B BB          plotStar                         tyx 
85/881C A9 AC 04                                     lda #blockTileMap.star_TL
85/881F 9F 00 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_0,x
85/8823 A9 AD 04                                     lda #blockTileMap.star_TR
85/8826 9F 02 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_1,x
85/882A A9 AE 04                                     lda #blockTileMap.star_BL
85/882D 9F 40 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_0,x
85/8831 A9 AF 04                                     lda #blockTileMap.star_BR
85/8834 9F 42 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_1,x
85/8838 60                                           rts 
85/8839 BB          plotDiamond                      tyx 
85/883A A9 B0 08                                     lda #blockTileMap.diamond_TL
85/883D 9F 00 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_0,x
85/8841 A9 B1 08                                     lda #blockTileMap.diamond_TR
85/8844 9F 02 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_1,x
85/8848 A9 B2 08                                     lda #blockTileMap.diamond_BL
85/884B 9F 40 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_0,x
85/884F A9 B3 08                                     lda #blockTileMap.diamond_BR
85/8852 9F 42 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_1,x
85/8856 60                                           rts 
85/8857 BB          plotDownTriangle                 tyx 
85/8858 A9 B4 08                                     lda #blockTileMap.downTriangle_TL
85/885B 9F 00 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_0,x
85/885F A9 B5 08                                     lda #blockTileMap.downTriangle_TR
85/8862 9F 02 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_0_1,x
85/8866 A9 B6 08                                     lda #blockTileMap.downTriangle_BL
85/8869 9F 40 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_0,x
85/886D A9 B7 08                                     lda #blockTileMap.downTriangle_BR
85/8870 9F 42 20 7E                                  sta BG1_VRAM_TMAP_MIRROR_1_1,x
85/8874 60                                           rts 

Title: Re: bad coding in roms
Post by: NES Boy on May 01, 2017, 06:27:47 pm
I just discovered an instance of bad coding in the first Mega Man game.

At the end of the battle with CWU-01P, the color $3D is loaded into the sprite palette line. How did this happen? Well, the battle with CWU-01P calls for a series of colors in offset 0x01F520-0x01F525, with the next color being loaded with each incarnation of CWU-01P destroyed. Destroying the last CWU-01P has the game attempt to load a color at offset 0x01F526, which has a native byte of BD.
Title: Re: bad coding in roms
Post by: Kea on May 01, 2017, 10:06:23 pm
You could fill a book writing about mysterious coding decisions by TOSE, who (among other projects) were responsible for the GBA  Final Fantasy ports. Some examples from their work on Final Fantasy I & II: Dawn of Souls:

-There are separate routines for copying party member's stats from general to battle RAM, for the start of battle and between every action respectively; but the second routine is called soon after the first, before these stats are used for anything, rendering it almost completely redundant. Also, in the first routine the Monk's unarmed critical rate is calculated as Stamina; in the second it's Level*2.

-Many data tables are duplicated. For instance, there are four identical copies of the monster stats table scattered throughout the ROM. All four are used by different areas of the game's code.

-Continuing with monster stats, each entry in the table has a byte indicating the AI that monster uses, however it is never read. Instead a separate table for monster AI bytes is used whenever the game needs to find a monster's AI.

-Similarly, entries in the spell data table have an 'animation byte' indicating what animation to play when cast. This byte is read only when a player character casts a spell; when monsters cast spells they use the spell's ID to index to the animation tables.

-Many routines are in the ROM, but are never called or referenced. Often their effects have been incorporated into routine(s) that might have called them.
-A few routines will load a RAM value into a register then immediately overwrite it with a constant or second RAM value.

-In general, there's quite a few vestigial leftovers of NES/PSX-era formulas. For instance, damage spells roughly operate off a formula of: (Int+Luck)/2 + (Int/10 *  SpellPow). At the same time, it also replicates the original 'doubling' mechanic, where a spell's accuracy is compared against the target's Magic Resistance - except instead of doubling damage, if the spell 'hits' it adds a measly Intellect/5 to damage.

(Oh, and player characters with over 200 Resistance take take 25% damage from spells; those with 199-100 take 50% damage; and those with <100 take 87.5% of normal damage. Monsters' Resistance stat doesn't apply in this way.)
Title: Re: bad coding in roms
Post by: FAST6191 on May 02, 2017, 02:33:57 am
While some of those speak to many coders, odd porting and bad coding I do also have to wonder if some of those are anti cheat. I know many of their games were not trivial to make cheats for.

On spell animations does it do anything to account for bosses or large sprites? If all the PCs are the same height and with same broad sprite animation types it could make for an animation that looks odd on a massive sprite.

The many tables thing has me curious. Would it line up with the size of banks in an earlier system at all? I am still quite prepared to believe multiple coders created their own array/table/incbined a table independently of each other -- it is poor coding form  but it is not like you have to be nice to ROM hackers.
Title: Re: bad coding in roms
Post by: Mugi on May 02, 2017, 05:03:37 am
honestly, this is my favourite so far...

(https://dl.dropboxusercontent.com/s/9jp453hsjjca9qw/ULJM05410_00057.png)

the birthday string, instead of being %s: %02d.%02d, decided that it's better if it's %s: %d%d.%d%d and has no less than 8 branches on the code that prints it to ensure things like hiding the digits that are 0, ofcourse, regardless of the fact that this game has a routine to align text per screen, or per relative location (think a text area laid on the screen) it was decided that the better way to do it is to manually define the position of each string, and digit, and their shadows. It literally took me a week to fix this thing simply due to the fact that realigning the numbers required rewriting X and Y for each number and each number's shadow separately, then remove the code that hides the first digits if they're 0 and some praying later it works.

this game is an infinite source of ....interesting programming solutions :P
Title: Re: bad coding in roms
Post by: Kea on May 02, 2017, 08:42:59 am
While some of those speak to many coders, odd porting and bad coding I do also have to wonder if some of those are anti cheat. I know many of their games were not trivial to make cheats for.

On spell animations does it do anything to account for bosses or large sprites? If all the PCs are the same height and with same broad sprite animation types it could make for an animation that looks odd on a massive sprite.

The many tables thing has me curious. Would it line up with the size of banks in an earlier system at all? I am still quite prepared to believe multiple coders created their own array/table/incbined a table independently of each other -- it is poor coding form  but it is not like you have to be nice to ROM hackers.

For spell animations, differences between monster and PCs are handled in the animation script and script processing code themselves; both use the same scripts overall. A lot of the effects are general enough to work for both small PCs and big monsters, f.x. "animate this tile in the center of the target's sprite", or "play this animation in the center of the targets' side of the field". A few spells play very different animations depending on who's casting (Thundaga's is much shorter when cast by monsters), but again that's taken care of inside the script.

The monster data tables are located at 0x1DE044, 0x223F4C, 0x227054, and 0x22A880. I'm not familiar enough with segmented-memory systems to know if that fits with any previous FF1 port's banks, but I do think this was probably a case of multiple coders including the same table. The first is used for the Bestiary, the second is used to update monster stats mid-battle, the third is used when generating monster stats at the start of battle, and the fourth is used when checking if a monster is Regenerating type at the end of each round.

It might be that some of these things were deliberate, if so it seems like a pretty crude anti-cheat. Most likely they didn't mind if they had redundant data or used up extra ROM space by accident so long as it worked - 16MB is plenty of space.
Title: Re: bad coding in roms
Post by: Chronosplit on May 02, 2017, 11:11:01 am
Isn't Pokemon Red/Green pretty broken anyways?
SELECT Pokemon corruption! :P
Now that's a hallmark in bad coding.  I tip my hat to Red++ actually fixing bugs because that's a long road even with the disassembly, especially for something with a remake that uses a completely different non-crap engine.

Some things that are not-so-well-known:
-With the correct sequence, you can walk through walls all the way past Mt. Moon before beating Brock.  Without codes.
-Beating the optional first match with Gary before a certain point will have Prof. Oak give you Poke Balls when you talk to him (5, which became what you get all the time at the start).  This prompt is scrambled to heck.
-If you combine the missingno glitch and the seafoam shore glitch, even weirder things will happen.
Title: Re: bad coding in roms
Post by: nesrocks on May 02, 2017, 01:13:11 pm
(http://i.imgur.com/0AeQcJb.png)

What is this monstrosity you ask? It's a list of positions for the lava balls in Super Pitfall. Basically, it's a "rendered" arc animation with small pseudo-random jittering. Seriously, instead of using a simple formula for arc motion the programmers decided screw math and wrote the positions for each frame manually. There are dozens of other examples for that game, but this is the dirtiest one. The section with the arc motion isn't depicted here as it doesn't fit, this is just the jitter section.
Title: Re: bad coding in roms
Post by: Madsiur on May 24, 2017, 04:54:33 am
Not really bad coding but more lazy behavior, all thew SNES FF3us dummy code has been ported to FF6 Advance. The next thing might not be bad coding either since my knowledge of GBA Thumb is limited but they seems to have taken FF3us code and maybe use an 65816 / Thumb converter because code is the exact same structure and registers IDs used are generally the same except that for 10 SNES instructions you have 30 Thumb instructions... (even SPC registers like $13XX are used for music calls, likely switching to GBA audio registers later).
Title: Re: bad coding in roms
Post by: Kallisto on May 24, 2017, 01:47:00 pm
Lot of you guys should do extra-pay work for these companies to fully repair their old codes in games.
Title: Re: bad coding in roms
Post by: NES Boy on June 08, 2018, 10:04:54 pm
I was looking up information regarding the Rockman Complete Works games when I stumbled upon some trivia in this walkthrough (https://gamefaqs.gamespot.com/ps/575618-rockman/faqs/30644). Apparently due to a coding bug, this hint at the beginning of Fire Man's stage in Navi Mode doesn't show up:

(https://gamefaqs.akamaized.net/faqs/44/30644-56.png)

Interestingly, this was translated (not quite well, I may add) in Mega Man Anniversary Collection, despite the bug not being fixed:
Quote
Fireballs from the ground can be transformed by the ice weapon, but the Magma below is all gone!