An issue regarding a custom code

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Timaeus
Posts: 12
Joined: Wed Jul 13, 2022 1:06 pm

An issue regarding a custom code

Post by Timaeus »

Hello. I have slowly learning to program my own custom codes for my Megaman 1 hack, focusing on attack patterns and movement patterns for bosses and normal enemies. However, one of my codes (one that makes the boss stay still for a determinated time before jumping to the next action) is showing a graphical glitch when Megaman fires certain weapons while the code is being executed. The code is as follows:

A9 2B 8D 01 04 = Reads the sprite 2b and call the sprite function
A9 00 8D 41 04 = Reads value 00 and call the hit state function
BD 40 06 = loads the delay/timer function with value 0
F0 09 = branch 9 bytes forward if equal
DE 40 06 = decrease 1 from the value for the delay/timer function that will be set ahead
D0 09 = branch 9 bytes if not equal
A9 05 85 3E = Jumps to the boss strategy code number 5
A9 5C 9D 40 06 = add value 5C to the delay/timer (which equals around 2 seconds of delay for the boss to stay idle)
60 = rts

I do believe that the problem lies in the decrement function, since I did swapped it with a rts as a test (making the boss stay idle forever) and the bug did not happened. I use Fceux for romhacking by the way.

Does anyone knows what can be wrong in my code template? Also, if it is possible to optimize it, does anybody know where can I simplify it?

Thanks and Peace~
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: An issue regarding a custom code

Post by Quietust »

Timaeus wrote: Wed Jul 13, 2022 1:15 pm Hello. I have slowly learning to program my own custom codes for my Megaman 1 hack, focusing on attack patterns and movement patterns for bosses and normal enemies. However, one of my codes (one that makes the boss stay still for a determinated time before jumping to the next action) is showing a graphical glitch when Megaman fires certain weapons while the code is being executed. The code is as follows:

A9 2B 8D 01 04 = Reads the sprite 2b and call the sprite function
A9 00 8D 41 04 = Reads value 00 and call the hit state function
BD 40 06 = loads the delay/timer function with value 0
F0 09 = branch 9 bytes forward if equal
DE 40 06 = decrease 1 from the value for the delay/timer function that will be set ahead
D0 09 = branch 9 bytes if not equal
A9 05 85 3E = Jumps to the boss strategy code number 5
A9 5C 9D 40 06 = add value 5C to the delay/timer (which equals around 2 seconds of delay for the boss to stay idle)
60 = rts

I do believe that the problem lies in the decrement function, since I did swapped it with a rts as a test (making the boss stay idle forever) and the bug did not happened. I use Fceux for romhacking by the way.

Does anyone knows what can be wrong in my code template? Also, if it is possible to optimize it, does anybody know where can I simplify it?
I'm not sure why you are calling those "codes", but some of them don't quite line up with your descriptions:

Code: Select all

	LDA #$2B	;"reads the sprite 2b"
	STA $0401	;"call the sprite function" (by writing a value to memory?)
	LDA #$00	;"reads value 00"
	STA $0441	;"call the hit state function" (see above)
	LDA $0640,X	;"loads the delay/timer function with value 0" (except it doesn't)
	BEQ label1	;(instead, it skips ahead if the value is already zero)
	DEC $0640,X	;"decrease 1 from the value for the delay/timer function that will be set ahead"
	BNE label2	;(if it decrements the value and it hasn't hit zero yet, then skip to the end)
	LDA #$05
	STA $3E		;"jumps to the boss strategy code number 5"
label1:	LDA #$5C	;"add value 5C to the delay/timer"
	STA $0640,X	;(which is only correct because, in order to get to this point, it had to be zero beforehand)
label2:	RTS
Some background on the underlying functionality of Megaman 1's game engine will be necessary to understand exactly what you're doing.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
Bavi_H
Posts: 193
Joined: Sun Mar 03, 2013 1:52 am
Location: Texas, USA
Contact:

Re: An issue regarding a custom code

Post by Bavi_H »

This was also recently posted at ROMhacking.net Forum: An issue regarding a custom 6502 assembly code. There, I raised the same concerns about the comments not quite matching the hex code and asked some questions. Timaeus explained they were working from bisqwit's Megaman 1 disassembly, which I found here: https://bisqwit.iki.fi/jutut/megamansource/maincode.txt

I found a likely spot in the bisqwit disassembly where the code starts in a similar way, but lost interest trying to figure out the details. If anyone else is interested, you can begin looking around this spot in bisqwit's disassembly:

Code: Select all

BombmanStrategyDecideNextAction
[...]
0001E0BA: A9 2B     lda #$2B
0001E0BC: 8D 01 04  sta ObjectSpriteNum+1
0001E0BF: A9 00     lda #$00
0001E0C1: 8D 41 04  sta ObjectUnknown440+1
0001E0C4: A9 1F     lda #$1F
0001E0C6: 8D 41 06  sta ObjectFireDelay+1
0001E0C9: 60        rts
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: An issue regarding a custom code

Post by Dwedit »

I think you need to set up an ASM6 project to make patching a lot easier. You'll be able to code in actual assembly rather than hex bytes. The benefit of using an ASM6 project is that you get the full feature set of the assembler, including labels.

Here was an example of how to set up a project for Contra.
This example makes one change in Bank 7:
At address $DAD1 (within bank 7), we change an instruction to "lda #3", and get the spread gun when we die.
See the template below. For the new version of Bank 7 (see below, you have to scroll code tags), we include all the code up until address $DAD1, put in our code, then include all the code up to the end of the bank.

Code: Select all

;NES header
.db "NES",$1A,8,0,$21,0,0,0,0,0,0,0,0,0

;PRG ROM

;bank 0
.org $8000
$ = $8000
;copy 8000 until C000 of that bank
incbin "contra.nes", $ - $8000 + (0*$4000) + $10, $C000 - $
.org $C000

;bank 1
$ = $8000
;copy 8000 until C000 of that bank
incbin "contra.nes", $ - $8000 + (1*$4000) + $10, $C000 - $
.org $C000

;bank 2
$ = $8000
;copy 8000 until C000 of that bank
incbin "contra.nes", $ - $8000 + (2*$4000) + $10, $C000 - $
.org $C000

;bank 3
$ = $8000
;copy 8000 until C000 of that bank
incbin "contra.nes", $ - $8000 + (3*$4000) + $10, $C000 - $
.org $C000

;bank 4
$ = $8000
;copy 8000 until C000 of that bank
incbin "contra.nes", $ - $8000 + (4*$4000) + $10, $C000 - $
.org $C000

;bank 5
$ = $8000
;copy 8000 until C000 of that bank
incbin "contra.nes", $ - $8000 + (5*$4000) + $10, $C000 - $
.org $C000

;bank 6
$ = $8000
;copy 8000 until C000 of that bank
incbin "contra.nes", $ - $8000 + (6*$4000) + $10, $C000 - $
.org $C000

;bank 7 (fixed bank C000-FFFF)
$ = $C000
;we are changing code at DAD1, so copy code until $DAD1
incbin "contra.nes", $ - $C000 + (7*$4000) + $10, $DAD1 - $
lda #3  ;get spread gun when you die
;rest of the bank until $10000
incbin "contra.nes", $ - $C000 + (7*$4000) + $10, $10000 - $

;finished
Mega Man 1 is also UxROM 128KB with vertical mirroring, so the same idea will work there too.

We don't use any "Rom File Address" nonsense here, just bank numbers and addresses within the bank.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
Timaeus
Posts: 12
Joined: Wed Jul 13, 2022 1:06 pm

Re: An issue regarding a custom code

Post by Timaeus »

I have no idea what this ASM6 is or how to set an assembler up. Also, I am very used to do things this way, since FCEUX let me see the results right away and I can have a better control of unused spaces, but thank you for the suggestion.

About my code, what way should I write it then? By using LDX and STX instead of setting stuff into the accumulator? I am new at creating templates of code lines so I do not know what difference there is by using the accumulator instead of the X register. I tried for weeks to study the code from the own bisqwit doc, but they are so damn hard to understand, due to the huge amount of unnecessary jumps and randomizations that the enemies and bosses do. I hope I do get better at this :p

thanks for the replies so far, guys. I truly appreciate them.
Last edited by Timaeus on Thu Jul 14, 2022 7:16 am, edited 1 time in total.
Fiskbit
Posts: 891
Joined: Sat Nov 18, 2017 9:15 pm

Re: An issue regarding a custom code

Post by Fiskbit »

Not to derail on this too much, but you really would benefit a lot from a patching assembler. I haven't used ASM6 for this task, but I have a lot of experience with snarfblasm, which has a .patch directive that can be used to have it output an IPS patch of just the changes you told it to make. I've done a substantial amount of ROM hacking over the years and I can speak from experience that proper tooling, particularly an assembler, makes a huge difference. Writing machine code directly really slows things down, results in worse documentation, leads to lower-quality code, and makes it much harder to update your code or fix bugs. Having to update branch targets by hand, for example, becomes a real chore as the code complexity grows. You can certainly do it, and there are ways to be disciplined about it to reduce the negative impact it has on the project, but the time spent learning a tool like snarfblasm will more than make up for itself in a higher-quality product and less time spent making it.
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: An issue regarding a custom code

Post by Quietust »

Timaeus wrote: Thu Jul 14, 2022 7:15 am About my code, what way should I write it then? By using LDX and STX instead of setting stuff into the accumulator? I am new at creating templates of code lines so I do not know what difference there is by using the accumulator instead of the X register.
You're presumably replacing code from the original ROM image with your new code, so you need to ensure that it obeys the same constraints as the original code. For example, if the original code expects the X and Y registers to be unchanged (e.g. if it loaded values into them before calling the code you're replacing, then after the RTS it expects them to have those same values), then modifying them with your own code will almost certainly cause things to break.

Given that your code already expects the X register to have a specific value coming in (since it does "LDA $0640,X", "DEC $0640,X", and "STA $0640,X" but doesn't have any "LDX" instructions), it's pretty safe to assume that using LDX/STX would result in catastrophic failure.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
Timaeus
Posts: 12
Joined: Wed Jul 13, 2022 1:06 pm

Re: An issue regarding a custom code

Post by Timaeus »

Then, how should I build it up? This graphical bug happens in other bosses too, so it might be a common change to fix. I am so lost at where to go and what to do. Should I make it so the game never calls X register then?

Also, I do not feel like using assembler right now. I already am overworking myself too much. I will try it for my next project after this one, maybe.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: An issue regarding a custom code

Post by Pokun »

ASM6 is a very simple and minimalistic assembler that is quick to set up though, just saying.
User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: An issue regarding a custom code

Post by Ben Boldt »

Timaeus wrote: Thu Jul 14, 2022 10:38 amShould I make it so the game never calls X register then?
It always depends on the situation. You can't just say that it is always safe or always bad to use X, or any other register. When in doubt, you can store registers on the stack and pull them back when you are done, basically restore them to their original values. X, Y, A and Status (SR) may or may not need to be stored, depending on the existing code.

There are only push and pull op-codes for A and SR. You have to transfer X and Y through A if you want to push and pull them. For example, if you wanted to store all of them:

PHP ; push status (SR)
PHA ; push A
TXA ; copy X into A
PHA ; push A (this pushed X since A = X.)
TYA ; copy Y into A
PHA ; push a (this pushed Y since A = Y.)

Then to get them all back:

PLA ; pull into A (A now contains the old Y.)
TAY ; Y = A
PLA ; pull into A (A now contains the old X.)
TAX ; X = A
PLA ; pull into A (A now contains the old A.)
PLP ; pull into status (SR)

That's not a fix-all because that takes a lot of cycles and it may make your game laggy or crash in some cases. If you are having bugs, you can try adding all those push/pulls though. It would be a useful thing to try. If it makes it work better, then it gives you a good clue that something needed to be stored.

The advantage of using ASM6 is that it will automatically allow you to just type those op-codes (PHP, PHA, etc), instead of looking all of that up in an instruction set, such as https://www.masswerk.at/6502/6502_instruction_set.html. If you don't know how to use the instruction set to convert op-codes, here is how you would convert the first part from above:

08 PHP ; PHP is op-code $08.
48 PHA ; PHA is op-code $48.
8A TXA ; TXA is op-code $8A.
48 PHA ; PHA is op-code $48.
98 TYA ; TYA is op-code $98.
48 PHA ; PHA is op-code $48.

So the bytes are:
08 48 8A 48 98 48

ASM6 will do this conversion / looking up for you. As well as a lot of other really helpful stuff especially when it comes to using labels with branches.
kuja killer
Posts: 130
Joined: Mon May 25, 2009 2:20 pm

Re: An issue regarding a custom code

Post by kuja killer »

Hey guys. I looked at this for him. asked for the mm 1 rom. My experience lies with megaman 3.

I found out there was "nothing" wrong with his code whatsoever at all. The timer works, everything is fine. It's just that those 640,x RAM was already "in-use" by something else like megaman's shots, which is why some of mm's shots on screen were showing glitched graphics. So 640-65F was probably some part of animation frames/data.

Like i did a "read" breakpoint on 644 for example, and got results for LDA's and STA's for that in other places in the ROM not related to this boss code.

So just moving it to a different memory region like 7E0,x fixed it. I dont think 7E0-7FF RAM is being used by anything in the game. So it's safe to use for boss fights temporarily.
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: An issue regarding a custom code

Post by Dwedit »

Whenever I'm looking for unused RAM, I usually pick the area before the stack.

Additionally, filling RAM with 55 AA 55 AA 55 AA 55 AA can help find unused memory.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: An issue regarding a custom code

Post by Ben Boldt »

I like the idea filling unused RAM with a 55AA watermark like that. It is also a great way to see worst case stack depth too.

Question: how much of the game do you typically play before you feel confident enough that the RAM isn’t used?
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: An issue regarding a custom code

Post by rainwarrior »

Ben Boldt wrote: Thu Jul 14, 2022 8:38 pmQuestion: how much of the game do you typically play before you feel confident enough that the RAM isn’t used?
When considering a ROMhack, I often find a TAS and run that in fast-forward as a quick first check for unused RAM/ROM. After I have some candidate areas, I'll try playing it for a bit with breakpoints to check.
User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: An issue regarding a custom code

Post by Ben Boldt »

I never thought of that. Great idea.
Post Reply