Language…
15 users online:  Ahrion, CroNo, Dennsen86, Golden Yoshi, Green Jerry, Hammerer,  Lazy, MellyMellouange, Metal-Yoshi94, mtheordinarygamer, Nayfal, Neuromancer, OrangeRock57, signature_steve, slopcore - Guests: 334 - Bots: 367
Users: 64,795 (2,370 active)
Latest user: mathew

Displaying graphics on a timer

Hello, I'm having trouble with timed events that rely on a RAM address for it's timer. Specifically, I'm trying to get a sprite to copy the behavior of the popular Hammer Bro sprite, where it displays it's hammer for a brief moment before actually throwing it. After much deliberation, I came to my final dead end and realized that no matter how much recoding I did, the only revision of my sprite that worked anymore was before I started all this to begin with.

In my latest revision, I'm using $1570 as my timer (!HammerTimer) and decrementing it manually, and $1534 for the flag (!ThrowCheck) that checks if it should display the sprite. Neither of these addresses are used elsewhere in the sprite as far as I'm concerned and I'm indexing them both by x as they should be. But for some reason, much of the sprite code somehow goes ignore upon spawning, including collision with Mario, until the sprite goes off screen and then comes back on, in which case it works fine until it's destroyed, at which point the game hangs.

This is the code I use to decrement the timer and set the flag (where ... is where other timer decrementing code is that's short but irrelevant):
Code
	LDA !HammerTimer,x
	BEQ +
	DEC !HammerTimer,x
+
...
	LDA !HammerTimer,x
	CMP #$10
	BNE DontSetHammer
	LDA #$01
	STA !ThrowCheck,x
DontSetHammer:
	RTS


This is where the timer is used to determine when to throw a hammer (where ThrowHammer is a label for some basic spawn extended sprite code):
Code
	LDA !HammerTimer,x
	CMP #$00
	BEQ GetHammer
	RTS
GetHammer:
	LDA #$38
	STA !HammerTimer,x
	STZ !ThrowCheck,x
	JMP ThrowHammer


And this is the graphics routine, which I more or less lifted from mikeyk's Hammer Bro, though I looked through each command and understood it, and it even works correctly, so I can't believe it's really the problem:
Code
HAMMER_OFFSET:
	db $F6,$0A

	LDA !Flash,x
	CMP #$00
	BNE NO_SHOW
	LDA !ThrowCheck,x
	CMP #$01
	BNE NO_SHOW

	PHX

	LDA $00
	LDX $02
	CLC
	ADC HAMMER_OFFSET,x
	STA $0300,y
	
	LDA $01                 ; \ tile y position = sprite y location ($01) + tile displacement
	CLC                     ;  |
	ADC #$F2
	STA $0301,y             ; /

	LDA #$6D                ; \ store tile
	STA $0302,y             ; / 

	PHX
	TYA                     ; \ get index to sprite property map ($460)...
	LSR A                   ; |    ...we use the sprite OAM index...
	LSR A                   ; |    ...and divide by 4 because a 16x16 tile is 4 8x8 tiles
	TAX                     ; | 
	LDA #$02
	STA $0460,x             ; /  
	PLX     

	LDA #$07 
	CPX #$00
	BNE NO_FLIP_HAMMER     
	ORA #$40
NO_FLIP_HAMMER:
	ORA $64                 ;  | put in level properties
	STA $0303,y             ; / store tile properties

	PLX
	INY                     ;  | increase index to sprite tile map ($300)...
	INY                     ;  |    ...we wrote 1 16x16 tile...
	INY                     ;  |    ...sprite OAM is 8x8...
	INY                     ;  |    ...so increment 4 times

	LDY #$02
	LDA #$04
	JSL $01B7B3
	RTS

NO_SHOW:
	LDY #$02                ; \ 02, because we didn't write to 460 yet
	LDA #$03                ;  | A = number of tiles drawn - 1
	JSL $01B7B3             ; / don't draw if offscreen
	RTS                     ; return


I also had an earlier revision where I didn't use a ThrowCheck flag, and instead just used this code at the beginning of the graphics routine:
Code
	LDA !HammerTimer,x
	CMP #$02
	BCC NO_SHOW
	CMP #$10
	BCS NO_SHOW


This worked better then the later revision where I used a check flag, but it was just outright refusing to branch; the hammer tile would just always display regardless of the state of the timer (which led me to believe that BCC and BCS aren't as simple as tutorials would lead you to believe)

I have no clue what's wrong, and I would really appreciate any help given for this. I've looked through mikeyk's code on multiple occasions but I don't seem to understand what I'm doing wrong. Thanks in advance.
I take it, that the Graphics routine you posted is only used for adding the hammer to the already drwan sprite, no?

Seeing as the NO_SHOW label skips the entire routine.


So, just to make sure I understood everthing else.
In your first code, you reduce the timer manually by one, every time the code is executed until it hits zero.

Once the timer reached 10, you set the !ThrowCheck flag.

In your second code, you check again if the timer reached zero (CMP #$00 isn't neccessary btw) and if it did reach zero, you reset your timer and clear the flag.

What really gives me a headache here, are all the "RTS" you used.
RTS is used to reaturn from a subroutine and in most cases ends the code.
So I'm not sure, if you just placed them to give a clean ending to your different code segments for posting them here, or if they in fact are in your code.

In case of the later, you'd probably want to remove them and replace them with a
Code
BRA Labelname ;Branch Aways

To jumt to your desired codesegment.

Could you possibly post a link for the entire code?
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
The first code snippet is part of a subroutine that decrements all the timers I use in the sprite. The second code snippet is also part of a subroutine, and in fact the entire subroutine it comes from is just that snippet and the actual spawning of the hammer. The third code snippet is, as you guessed, only used for drawing the hammer itself and attaching it to the rest of the sprite, which is already drawn at that point, correctly might I add.

The sprite works fine with all those RTS commands there, as it's essentially the same thing in an earlier revision but with all references to the flag taken out, it just doesn't do the graphics writing any favors.

The actual asm file itself is rather huge as it's a boss script, and I haven't really organized it very well, so I'm probably going to clean it up before being forced to post it.
In that case, I don't really understand your graphics routine.

If you just add one 16x16 tile (the hammer, that is) why do you store A with #$04 (indeicating that you draw 4 tiles)?

Code
	LDY #$02
	LDA #$04
	JSL $01B7B3
	RTS


And when the code branches to the NO_SHOW label, you draw 3 tiles

Code
NO_SHOW:
	LDY #$02                ; \ 02, because we didn't write to 460 yet
	LDA #$03                ;  | A = number of tiles drawn - 1
	JSL $01B7B3             ; / don't draw if offscreen
	RTS 


If it's just used to add a hammer to the already working sprite, why don't you skip the entire routine all together, if it's not time to display the hamme yet

I did find another possible error though.
In your graphics routine, you pushed x on the stack twice (PHX), but you only pull it back one (PLX)

Unless you get it bakc elsewere, this will screw up all of the sprite's ram storege, where you index with X


Originally posted by SchwerMuta
so I'm probably going to clean it up before being forced to post it.


Nobody forces you. I just thought it would help. But if it is as you say, and all of those code snippets run in their own subroutine, it sould work fine
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
I misunderstood what you meant by 'already drawn.' It's already prepared and ready to be written to the OAM but not actually 'drawn drawn.' The JSL to $01B7B3 in NO_SHOW is the first time it's called if the hammer isn't drawn, and the graphic routine for the hammer has one for when it needs to be drawn. I was just trying to say that the sprite is already prepared and the code I posted just attaches the hammer to the prepared sprite and then draws all of it all at once, and it just draws the sprite without the hammer if displaying the hammer is skipped.

Originally posted by JackTheSpades
I did find another possible error though.
In your graphics routine, you pushed x on the stack twice (PHX), but you only pull it back one (PLX)

Unless you get it bakc elsewere, this will screw up all of the sprite's ram storege, where you index with X


Just looking at the code I posted I can see two PHX and two PLX commands so I have no idea what you're talking about.
Don't know how i missed that.

OK, fine, I give in.
I sure am not the best ASM coder out thereso chances are I'm missing something but as far as I'm concered, everything seems to be fine with the code you posted.

While I don't understand one part of your graphics routine...

Code
	PHX
	TYA                     ; \ get index to sprite property map ($460)...
	LSR A                   ; |    ...we use the sprite OAM index...
	LSR A                   ; |    ...and divide by 4 because a 16x16 tile is 4 8x8 tiles
	TAX                     ; | 
	LDA #$02
	STA $0460,x             ; /  
	PLX     

	LDA #$07 
	CPX #$00
	BNE NO_FLIP_HAMMER     
	ORA #$40
NO_FLIP_HAMMER:
	ORA $64                 ;  | put in level properties
	STA $0303,y             ; / store tile properties


You said that the sprite appears correctly, no?
So I don't thing the problem lies there.

My best guess is, that the error must be somewhere else within your code.

Alternativly, you could try using different RAM addresses for your timer and flag. I actually don't think that that's the problem, but there is no harm done in trying is ther?
Just for the record, I once coded a sprite where the RAM addresse for some reason didn't work... changing it fixed it.

As I said, I don't see any problems with the code snipets you posted. What makes you think they have anything to do with the error anyway?

Last but not least...
I don't know if it is intended, but you used JMP here.
Code
GetHammer:
	LDA #$38
	STA !HammerTimer,x
	STZ !ThrowCheck,x
	JMP ThrowHammer


As far as I know, JMP ignores everything that comes after it. Again, don't know if it is intended, just wanted to point it out.
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
I tried changing the RAM addresses I used before already but it produced the same exact results. Using JMP was intended in many places I put it in but I have tried replacing all of them with BRA and RTS... still nothing.

Even though the sprite displays just fine, removing the hammer from the graphics routine actually causes the sprite to work fine, without any errors and jamming the emulator CPU, so the error has to be there... but I can't see any obvious flaw in the code itself. That same exact code would run fine in any other sprite. I'm kind of clueless as to why it would be messing up.
You could use a message to check if your code actually reaches certain sections.

Code
LDA #$01  ;  Message to display.
STA $1426 ; Trigger message.


I often use it to check if RAM addresses actually change to the calue I want them to have and such.

I know it isnt really an anweser, but it could help you locate the section were your code stops working the way you want it to.
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
So after some experimenting I discovered how to fix it. In a very weird way.

This doesn't work:
Code
PLX                     ; pull, X = sprite index

	LDA !Flash,x
	CMP #$00
	BNE NO_SHOW
	LDA !ThrowCheck,x
	BEQ NO_SHOW
	CMP #$01
	BEQ SHOW_HAMMER_TOO
	RTS

NO_SHOW:
	LDY #$02                ; \ 02, because we didn't write to 460 yet
	LDA #$03                ;  | A = number of tiles drawn - 1
	JSL $01B7B3             ; / don't draw if offscreen
	RTS                     ; return


But this does:
Code
	LDA !Flash,x
	CMP #$00
	BNE NO_SHOW
	LDA !ThrowCheck,x
	BEQ NO_SHOW
	CMP #$01
	BEQ SHOW_HAMMER_TOO
	RTS

NO_SHOW:
	PLX
	LDY #$02                ; \ 02, because we didn't write to 460 yet
	LDA #$03                ;  | A = number of tiles drawn - 1
	JSL $01B7B3             ; / don't draw if offscreen
	RTS                     ; return


I can't explain why pulling X a few bytes later magically fixes things, this also means that the hammer graphics routine now has a PLX just before the JSL since the new PLX would get skipped if it was called.

Although now, the hammer isn't being drawn. The rest of the sprite draws just fine, it's only the hammer not being drawn with the sprite, as if the flag stopped working suddenly, even though I changed no other code then that piece of code right there and it worked before...

I don't know, I can't seem to make any attempt at understanding how SMW deals with graphics without getting a headache. I've went through so much ASM code without it failing on me and the moment I get into graphics it all seems to fall apart.
I guess the subroutine $01B7B3 needs X to contain the sprite index
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?
The flag not working was the RAM address I was using and upon using a new one, it all works fine, so I guess that ends that little adventure. Thanks a bunch for tolerating my silliness.
Originally posted by JackTheSpades
Alternativly, you could try using different RAM addresses for your timer and flag. I actually don't think that that's the problem, but there is no harm done in trying is ther?
Just for the record, I once coded a sprite where the RAM addresse for some reason didn't work... changing it fixed it.


#w{=P} Glad it worked out. ^^
Anime statistic on MyAnimeList:
400 animes completed ✓
6000 episodes completed ✓
100 Days completed ✓
... what even am I doing with my life?