A few quick ASM questions and one big one.

Hey!
Programming isn't typically that hard in my opinion, as long as you know the basic syntax. However, its also key to know how said language represents its mathematical functions. With asm, its all 3 letter opcodes, so it can be hard or not as obvious what corresponds to what.

So that leads to my first question: How would I make the following comparisons: Greater than, Less than, Greater than or equal to, and Less than or equal to. I know CMP and AND act as comparisons, but as far as I understand, they will only do equal to.

Additionally, I was wondering how I could set an object I just created with CreateObject using a stored value. Not quite sure how to do this.

Now for the bigger fish:
How would I go about having certain screen types cause certain effects when they are loaded?
EX: Set the players action type to a certain value for an overworld map.

Ive already tampered a little with the screen loading code, in order to fix a minor bug with projectiles (If you exit a room while firing, the bullet object never sets the can shoot variable back to zero), but this is on a much higher level, and I'm not sure my level of ASM experience will suffice :? .

All help is appreciated!
 

dale_coop

Moderator
Staff member
I think the comparisons are:
Code:
LDA myVariable
CMP myValue
BEQ goToLabel ;; if equal 
BCC goToLabel ;; if less 
BCS goToLabel ;; if greater
BNE goToLabel ;; if not equal
 

chronosv2

New member
Those comparisons are correct.
Worth noting with AND: And isn't used with conditional statements in the way one would think -- AND isn't used as "If ___ AND ___", it's a binary operation that ANDs together the bits in the accumulator with the supplied value.
If the Accumulator holds #$1A and you AND #$26...
Code:
ACC   00011010 (#$1A)
AND   00100110 (#$26)
ACC   00000010 (#$02)
You end up with the result #$02.
I've actually been working on NESMaker ASM tutorials. I've got the next one ready to record and put out, and then they'll cover all the non-NES-specific basics of 6502 ASM.
There are also a few more things that I think I'm going to touch on.

If you'd like to give them a look (and take part in the post-tutorial challenges) the thread covering them is in the Randomness forum.
http://nesmakers.com/viewtopic.php?f=16&t=953
I plan on trying to get specifically into NESMaker stuff once 4.1.0 hits. I don't think it's smart teaching one thing only to go over it again because it's changed.

Hopefully it proves helpful! If you have any questions or comments please feel free to give feedback. :)
 

jorotroid

Member
A couple of things that I would like to add to what everyone else has said. First, BCS actually means Greater Than or Equal To. If you want just Greater Than, then you'll need to first to a BEQ to account for equal. So second, here is a quick reference I use because I never seem to memorize difference between the branch statements. It also includes what to do for signed numbers which is helpful if your are doing stuff with Object Speeds. Scroll down to the chart called "Use of Branch Instructions with Compare":
http://www.6502.org/tutorials/compare_instructions.html

Karakara | Karetro said:
Additionally, I was wondering how I could set an object I just created with CreateObject using a stored value. Not quite sure how to do this.

I'm not sure if I understand your question. Can you rephrase?


Karakara | Karetro said:
Now for the bigger fish:
How would I go about having certain screen types cause certain effects when they are loaded?
EX: Set the players action type to a certain value for an overworld map.

I think it would really depend on what sort of effect you want, but to go with your example, I would first try going to where you fixed the bullet canFire thing, load player1_object into X, and then call the ChangeObjectState Macro.
 

Kasumi

New member
As jorotroid said, bcs is greater than or equal, not greater than. You can't really do greater than in one step, nor less than or equal to in one step.


For Greater Than
Code:
lda variable
cmp value
beq notactuallygreaterthan;If they're equal, "greater than" isn't true.
bcs greaterthan
notactuallygreaterthan:
;If here, the variable was less than or equal to the value.
Another thing you can do is add one to the value.
Code:
;Imagine value is 2
inc value;Now value is 3
lda variable
cmp value;branch if greater than or equal to 3
bcs greaterthan
The reason this works is that
if value >= 3
is the same as
if value is > 2
(for integer values, which these are.)

The second one (adding an extra to the value) is bad if you want to test if something is greater than 255, but at that point one a 16 bit compare is probably warranted anyway.

Less than or equal to is similar
Code:
lda variable
cmp value
bcc lessthanorequal
beq lessthanorequal
;If here, the value was greater
lessthanorequal:

Code:
inc value
lda variable
cmp value;branch if less than value + 1
bcc lessthanorequal
if value <= 2
is the same as
if value is < 3

Hopefully I didn't screw those up.
But note! Branches are somewhere reversed from if statements.
Code:
if(variable == value){
//If the if statement is true, the code underneath the if statement will run

}
But in 6502
Code:
lda variable
cmp value
beq equal
;If the branch condition is FALSE the code underneath the branch will be run.
;Code here
equal:

I may as well go deeper while I'm here. What cmp does is subtract without storing the result. The carry flag gets set if the result would have been less than zero.

So 3-3 = 0. Since it didn't need to go lower than 0. So the carry is set afterwards.
4-3 = 1. Again, it didn't need to go lower than 0. So the carry is set afterwards.
2-3= -1. Since the result was lower than zero, the carry flag is clear afterwards.
 
jorotroid said:
Karakara | Karetro said:
Additionally, I was wondering how I could set an object I just created with CreateObject using a stored value. Not quite sure how to do this.

I'm not sure if I understand your question. Can you rephrase?
So for a weapon, I'm using CreateObject to spawn it. And I noticed when you create a projectile, you can use a temp value and store it to object movement to make it move in the desired direction. I was wondering how I would go about making it not move a given direction but instead FACE a given direction.
And my bad, yeah that was pretty bad phrasing.
Thanks!

And thanks a bunch Kasumi, that really helps :D
 
jorotroid said:
I think it would really depend on what sort of effect you want, but to go with your example, I would first try going to where you fixed the bullet canFire thing, load player1_object into X, and then call the ChangeObjectState Macro.
I guess the better question would be how would I check the screens type because the CanFire variable resetter simply is:
Code:
LDA #$00
STA CanFire
Sorry for replying twice, I only realized this when I went to follow your advice on it :p
 

dale_coop

Moderator
Staff member
If you want to reset your CanFire variable each time you change/load a screen, add your code in the "Routines\System\HanldScreenLoads.asm" script for example, like:
Code:
DoneWithThisScreenLoad:	
	;; if you do not want triggers to go away
	;;; comment out this sub routine.
	;;; make this a screen bit.
	JSR updateNametable_checkForTriggers
	JSR countAllMonsters

	;; reset the canFire :	
	LDA #$00
	STA CanFire  

	LDA #$00
	STA update_screen
 

jorotroid

Member
Karakara | Karetro said:
So for a weapon, I'm using CreateObject to spawn it. And I noticed when you create a projectile, you can use a temp value and store it to object movement to make it move in the desired direction. I was wondering how I would go about making it not move a given direction but instead FACE a given direction.
And my bad, yeah that was pretty bad phrasing.
Thanks!

Ah, I think you want the FaceDirection Macro. It works the similar to the StartMoving Macro, but instead of using the MOVE_* constants, it uses the FACE_* constants. You can see them both in use in the StartMovingPlayer input scripts.



Karakara | Karetro said:
I guess the better question would be how would I check the screens type because the CanFire variable resetter simply is:
Code:
LDA #$00
STA CanFire
Sorry for replying twice, I only realized this when I went to follow your advice on it :p

Screen type is stored in the screenType variable. So you can do something like this if you wanted it to happen on say screen type 200:
Code:
	LDA screenType
	CMP #$C8
	BNE DontChangePlayerAction
		LDX player1_object
		ChangeObjectState #$03, #$00
		
DontChangePlayerAction:
	;; code continues on as normal from here
 
So I got the facing thing working, I used the binary versions of FACE_* from the macros.asm file and stored that directly to the Object_Movement variable when the object was created.

Also, if I use the BNE method you showed above, could I use BNE + to avoid adding another pointer (if that's what they are called) to the code?
 

jorotroid

Member
Karakara | Karetro said:
So I got the facing thing working, I used the binary versions of FACE_* from the macros.asm file and stored that directly to the Object_Movement variable when the object was created.

Also, if I use the BNE method you showed above, could I use BNE + to avoid adding another pointer (if that's what they are called) to the code?

Somebody else should probably clarify the advantages of using the + label. I personally haven't been using them. But it doesn't really affect things once the game is compiled as far as I know. The compiler basically just looks at the label and sees which address it ended up at and puts that address in where ever you call for that label. The only thing I can think of is if you are running into an issue with naming labels for similar concepts, but I personally haven't really run into that issue. I find it helpful to keep my labels fairly descriptive for me for quickly understanding what a piece of code is for.
 

dale_coop

Moderator
Staff member
I am afraid it doesn't exist, in assempbly. You will have to code routines to implement the calculs.
 

chronosv2

New member
Give me a few hours. I'll have my Assembly tutorial that covers (basic) multiplication and division up. :)

Edit:
Tutorial is up, but the short answer is the ASL and LSR commands can be used for power-of-two multiplication and division.
There are other (slower) ways I go over in my tutorial for non-power-of-two operations, but I'm not sure I'd recommend them for NES Game Making.
 
chronosv2 said:
Give me a few hours. I'll have my Assembly tutorial that covers (basic) multiplication and division up. :)

Edit:
Tutorial is up, but the short answer is the ASL and LSR commands can be used for power-of-two multiplication and division.
There are other (slower) ways I go over in my tutorial for non-power-of-two operations, but I'm not sure I'd recommend them for NES Game Making.
Thanks! This works for my purposes too. I wanted to make a move slow that would limit its maximum speed to half the entities max speed. :D
 

Kasumi

New member
Various math functions in 6502 including several multiplication snippets: http://codebase64.org/doku.php?id=base:6502_6510_maths

Here's a bunch of division by a constant routines: https://forums.nesdev.com/viewtopic.php?f=2&t=11336

They work by magic. This post explains why the divide by 7 works: http://atariage.com/forums/topic/113254-fast-divide-by-seven/?p=1659889

You can do a similar trick for divide by any power of 2 minus one. Usually one just designs around not having multiplication, though. But if you want to do it in the simple way, it's repeated addition. What's 3*2?
3+3. (3 added to zero two times.)
Or
2+2+2 (2 added to zero three times.)
So one of the values you're multiplying is how many times you loop, and the other is what you add to zero within the loop:
Code:
lda #3
sta mult1

lda #0
ldy #2
loop:
clc
adc mult1
dey
bne loop
So to make it generic:
Code:
;jsr to multsub with one value to multiply in mult1 and the other in Y
;Doesn't work properly if the value in Y is zero (the result may not be zero)
multsub:
lda #0
loop:
clc
adc mult1
dey
bne loop
You can make it faster by moving the clc out of the loop
Code:
;jsr to multsub with one value to multiply in mult1 and the other in Y
;Doesn't work properly if the value in Y is zero (the result may not be zero)
multsub:
lda #0
clc
loop:
adc mult1
dey
bne loop
Because if the result goes above 255, it's not that useful anyway. You'd want a 16bit multiply at that point.
The above routine is not that great, but it's easy to understand.

Whiteflame's routine: http://codebase64.org/doku.php?id=base:8bit_multiplication_8bit_product
Actually works based on a similar concept to how decimal multiplication is taught in schools except with powers of 2, not powers of 10.
Code:
315
x 7
7*5=35
7*1=7. Then multiply by 10 because that 1 is in the tens place. = 70
7*3=21. Then multiply by 100 because that 3 is in the hundreds place. = 2100

0035
+
0070
+
2100
=2205
But instead of multiplying by 10 and 100, it's multiplying by 2 and 4.

Edit: Division is counting how many subtractions are possible before zero is crossed. 10/5=2
10-5=5. One subtraction
5-5=0. Two subtractions.
10/3=3. (For this kind of division remainder isn't kept track of.)
10-3=7. One subtraction.
7-3=4. Two subtractions.
4-3=1. Three subtractions.

Even though 1 is not 0, 1-3 would go below zero.

Code:
lda #10
ldx #$FF;Start at one less than zero because there will always be one loop

sec
loop:
inx
sbc #3
bcs loop
The carry gets clear when a subtraction's result would be less than zero. We start the count at #$FF because one will always get added to X (which keeps track of how many subtracts were possible) even if you do something like 1 divided by 40. (Which should be zero.)

Edit: More edits... if you do end up wanting the remainder, you just add the denominator again after the loop. The carry is even already clear for you to do so!
Code:
bcs loop
;clc;Because the bcs didn't branch, it means the carry is already clear
adc #3

Edit Again: One more tiny fact. Most people have seen jokes about computers not being able to divide by zero. That loop actually shows why that is true sometimes.

Code:
lda #10
ldx #$FF;Start at one less than zero because there will always be one loop
sec
loop:
inx
sbc #0
bcs loop
10-0 will always be 10, so the loop never ends.

That said, the only time I can recall using non power of two multiplies and divides was when I did sonic style slope physics.

While I'm here, a super cute multiply by three.
Code:
sta temp
asl a;multiply by two
clc
adc temp;add one more to get three adds!
Actually, I've definitely used the cute multiply by three before. But dividing and multiplying by two arbitrary numbers is pretty uncommon. Usually one number is known (will always be three, or 7 or whatever) and so you just look up a fast routine for the unchanging number.
 
Top Bottom