What does this section of a subroutine do?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

What does this section of a subroutine do?

Post by SusiKette »

I found this subroutine in RECCA. Based on when this subroutine is used it calculates the direction from object to player and shifts the result left x times. The part I don't get is from $ECB9 to $ECD3. My best guess is that it is supposed to normalize the values, but still, I don't understand why it is doing things as it is. Like, why subtract #$01 from the high byte, why compare #$FE and why branch to the locations they do after the comparisons.

Code: Select all

$EC91
		STA result_shift_count
		LDA player_pos_y
		SEC
		SBC obj_pos_y,X
		STA object_player_y_distance_low
		LDA #$00
		SBC #$00
		STA object_player_y_distance_high
		LDA player_pos_x
		SEC
		SBC obj_pos_x,X
		STA object_player_x_distance_low
		LDA #$00
		SBC #$00
		STA object_player_x_distance_high
		ORA object_player_x_distance_low
		ORA object_player_y_distance_low
		ORA object_player_y_distance_high
		BEQ $ECE1
		
$ECB9
		ASL object_player_x_distance_low
		ROL object_player_x_distance_high
		ASL object_player_y_distance_low
		ROL object_player_y_distance_high
		LDA object_player_x_distance_high
		SEC
		SBC #$01
		CMP #$FE
		BCC $ECD3
		
		LDA object_player_y_distance_high
		SEC
		SBC #$01
		CMP #$FE
		BCS $ECB9
		
$ECD3
		ASL object_player_x_distance_low
		ROL object_player_x_distance_high
		ASL object_player_y_distance_low
		ROL object_player_y_distance_high
		DEC result_shift_count
		BPL $ECD3
		
		LDA #$01
		
$ECE1
		RTS ; ------------------------------------------------
I left the CPU addresses in so you can find it in the subroutine. The subroutine uses "temporary" variables, but I replaced them with more descriptive names to make it easier to read.
Avatar is pixel art of Noah Prime from Astral Chain
Fiskbit
Posts: 891
Joined: Sat Nov 18, 2017 9:15 pm

Re: What does this section of a subroutine do?

Post by Fiskbit »

Looks to me like it's checking if the distance is within 255 units, positive or negative, after the multiply by 4 (so, 64 units on the original scale). If the high byte were 0, subtracting 1 would give #$FF and the check would pass. If it were #$FF, subtracting 1 would give #$FE and the check would pass. Anything outside that range is further than 255 units and will fail the check.
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: What does this section of a subroutine do?

Post by Oziphantom »

Code: Select all

$EC91
		STA result_shift_count
		LDA player_pos_y
		SEC
		SBC obj_pos_y,X
		STA object_player_y_distance_low
		LDA #$00
		SBC #$00
		STA object_player_y_distance_high    ; yDist = player.y-object.y
		LDA player_pos_x
		SEC
		SBC obj_pos_x,X
		STA object_player_x_distance_low
		LDA #$00
		SBC #$00
		STA object_player_x_distance_high    ; xDist = player.x-object.x
		ORA object_player_x_distance_low     ; if xDist == 0
		ORA object_player_y_distance_low     ; and
		ORA object_player_y_distance_high    ; yDist == 0
		BEQ $ECE1                            ; then return 0

$ECB9
		ASL object_player_x_distance_low     ; xDist *= 2
		ROL object_player_x_distance_high
		ASL object_player_y_distance_low     ; yDist *= 2
		ROL object_player_y_distance_high
		LDA object_player_x_distance_high    ; if xDist
		SEC                                  ; >= 256
		SBC #$01
		CMP #$FE
		BCC $ECD3                            ; then shift

		LDA object_player_y_distance_high    ; if yDist
		SEC                                  ; < 256
		SBC #$01
		CMP #$FE
		BCS $ECB9                            ; then mul again

$ECD3
		ASL object_player_x_distance_low     ; xDist * scalar
		ROL object_player_x_distance_high
		ASL object_player_y_distance_low
		ROL object_player_y_distance_high    ; yDist * scalar
		DEC result_shift_count
		BPL $ECD3

		LDA #$01                             ; return 1
		
$ECE1
		RTS 
; ------------------------------------------------
but what does that mean?
Well you are taking the distance between both objects and then you doing div two until one of the values is 1 or -1. So effectively you are normalizing the heading vector from the object to the player. ( or what the code actually does is /8 and then mul 2 until one of them crosses becomes +/- 1)
then you multiple the heading vector by a scalar value.

I'm going to guess that RECCA is a shoot-em-up and this is the "fire bullet with speed A towards the player" routine.
User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: What does this section of a subroutine do?

Post by SusiKette »

I'm assuming this way of normalizing the vector is not accurate, but rather a approximation. I have noticed that bullets fired at player are fired at double speed at certain distances between the player and the enemy that fired it. I'm assuming this is a side effect of the approximation.
Avatar is pixel art of Noah Prime from Astral Chain
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: What does this section of a subroutine do?

Post by Oziphantom »

yeah very inaccurate. Its just first past 1, so if you have $100 and $0Fe or $100 and $001 it doesn't matter it just first past 1,it just x2 until one of them hits $100 it doesn't pay any attentive to the actual length of both values. Both can hit "over 1" if they are close enough 45 degrees rather than say 0.5, 0.5 which is what you actually want. This is why in a lot of games its faster to move diagonally than forwards.
Post Reply