Jump to content
IGNORED

Quest of the Cranberry (WIP)


atari2600land

Recommended Posts

So I need to learn how to make 4k games. How hard is it? How hard is making an 8k game? Do I need to pick a bankswitching scheme or does it do it automatically? As you can probably tell, I have a lot of questions about making a big Atari 2600 game that's bigger than 2k in assembly. That's because I'm making a game called "Craig the Cranberry." In the end, I want it to be like Adventure, but bigger. This is all I have right now, but even this took about half a day's worth of coding (I can sit at the computer for like 2-3 hours at a time just typing away and testing stuff.)

cranberrytitle.png.fd9ea961c5f1aba106f582d0ec6edff4.png cranberry4_2.png.dda5ea1599f2d9ada9ed37371307a82c.png

Anyway, let me know what you think so far of my little project.

cranberry5.zip

Link to comment
Share on other sites

Making a 4K game is exactly like making a 2K game, but with a different starting address (no bankswitching required). In your file, you would change ORG $F800 to ORG $F000 to make it a 4K game:

 

                SEG code
                ORG $F000	; FC00 for a one k game

 

Anything larger than 4K requires that you pick a bankswitching scheme. How hard it is is a matter of opinion, but like anything else, once you get used to it, it's not difficult.  Using macros to make your life easier certainly helps.

Link to comment
Share on other sites

I am wondering if there is a simpler way to do if/then statements in assembly. Because right now I've got this:


        inc RoomNumber
        
        lda #20
        sta PlayerX+0

 

        lda RoomNumber  ; get position of player
        cmp #4            ; test for edge of screen
        beq Potion  

     

        lda #0
        sta PlayerY+1
        
        lda RoomNumber  ; get position of player
        cmp #3            ; test for edge of screen
        bne No_new_room       

 

Which is manageable now, but what about later in programming this? How would I go about doing this? How did Pitfall keep track of 255 screens and which one to display at which time?

Link to comment
Share on other sites

13 minutes ago, atari2600land said:

I am wondering if there is a simpler way to do if/then statements in assembly. Because right now I've got this:

 


        inc RoomNumber
        
        lda #20
        sta PlayerX+0

 

        lda RoomNumber  ; get position of player
        cmp #4            ; test for edge of screen
        beq Potion  

     

        lda #0
        sta PlayerY+1
        
        lda RoomNumber  ; get position of player
        cmp #3            ; test for edge of screen
        bne No_new_room       

 

 

Which is manageable now, but what about later in programming this? How would I go about doing this? How did Pitfall keep track of 255 screens and which one to display at which time?

 

One way is to use a vector table (or two, low/high) to point to routines to handle each condition.

Load x (or y) with your RoomNumber, then load the low/high bytes from the table into a zero page lo/hi variable.

Then jump indirect via the zero page variable.

 

VectorToRoomHandler
    ldx RoomNumber
    lda RoomVecLO,x
    sta vec                 ; 'vec' is a two-byte zero-page variable
    lda RoomVecHI,x
    sta vec+1
    jmp (vec)

RoomVecLO
    db <Handler0
    db <Handler1
    db <Handler2
    ;...etc
    
RoomVecHI
    db >Handler0
    db >Handler1
    db >Handler2
    ;...etc
    
    
Handler0
    ; do stuff here for RoomNumber==0
    rts
    
Handler1
    ; do stuff here for RoomNumber==1
    rts
    
Handler2
    ; do stuff here for RoomNumber==2
    rts
    

    
You can have a 'rts' at the end of each 'handler', if that makes sense in the context of your usage (ie., you jsr'd to VectorToRoomHandler)
OR, you can just put a simple jmp there, such as 'jmp FinishedHandler' and your code can continue fromthere.
Of course, you need to have an entry in the LOW/HIGH table for ALL possible values of RoomNumber!!

 

 

Edited by Andrew Davie
Link to comment
Share on other sites

13 minutes ago, atari2600land said:

Which is manageable now, but what about later in programming this? How would I go about doing this? How did Pitfall keep track of 255 screens and which one to display at which time?

 

A more 'general' answer to your question - use tables of data for everything that is different between rooms.

If you *have* to use conditional code, then use tables to vector to routines, as described above.

 

An even *more* general answer to your question is - don't special-case each room, but instead find some random routine that you can use which, when called, gives you consistent results that can be used to generate data for a room. As long as you start with the same 'seed' value for any room, your random routine will return the same 'random' numbers.  Use of random routines to "hold" room data means you can have a lot of rooms at almost zero ROM cost.

Link to comment
Share on other sites

I was getting kind of angry about why the vector table was working funny until I realized that it starts with 0 instead of 1. In my game, screen 0 is the title screen and screen 1 is the beginning. Well, now screen 1's info is in a jsr called "Room2". I bet there's an easy way to make this not so, but it works now.

 

And I don't want to risk breaking it because I made a big change: Now I can have pfblocks and sprites in the same screen! The only downside is that the sprites are bigger, but that's okay because they were kind of microscopic to begin with.

 

@Kiwi I know there's that, but I was looking for a way to reduce those kinds of statements.

cranberry10.bin

Link to comment
Share on other sites

15 hours ago, Kiwi said:

There's also Branch on PLus(bpl) for greater than.  And Branch on MInus(bmi) for less than if statement.  

These are for *signed* comparisons. Be careful if you're trying to use unsigned with these!

I nearly always use BCC (less than) and BCS (greater than).

For example, compare if variable greater than or equal to 200?

 

    lda var
    cmp #200
    bcs isGreaterEqual
    
    

 

  • Like 1
Link to comment
Share on other sites

2 minutes ago, atari2600land said:

How do you know if a variable is signed or not?

It's up to you. How do you think about it and use it?

They are all 8-bit numbers. An 8-bit number can be signed from -128 to +127 or unsigned from 0 to 255

-1 is exactly the same bit patten as 255.  The CPU has no idea they are any different. It's totally your call.

The difference comes with what YOU do with them. If you use signed comparisons, then you get the result as if they were signed numbers

If you use unsigned comparisons then the result is as if they were unsigned numbers.

 

Link to comment
Share on other sites

7 minutes ago, atari2600land said:

 

You're SLEEPing too long before setting PF2 on the affected lines. Change the SLEEP value to 5 and it'll work.

        SLEEP 5                 ; 6 45
        sta PF2                 ; 3 48 - @48 - update PF2 for right side of screen
        sta WSYNC               ; 3 53 - wait for end of scanline		

You have a reflected playfield which is why the timing is so sensitive.

Link to comment
Share on other sites

Is there another way to draw a 4-digit score easily? Anyway, I fixed the game, the solution was to add some sleep comments in just the right places. What I don't understand is if I add or take away something from the code, I also have to change the number in the sleep statements. Why wouldn't it just be the same even though it's not using all the code?

 

cranberry11a.bin

Link to comment
Share on other sites

1 hour ago, atari2600land said:

Is there another way to draw a 4-digit score easily? Anyway, I fixed the game, the solution was to add some sleep comments in just the right places. What I don't understand is if I add or take away something from the code, I also have to change the number in the sleep statements. Why wouldn't it just be the same even though it's not using all the code?

 

 

Sometimes the timing changes - for example, if you are branching to somewhere, and that "somewhere" happens to NOT be in the same page as the branch instruction, then there's a +1 cycle "penalty" for doing that. So as you shift code around, your branches can sometimes cross (or not cross) pages where they did (or didn't!) before. This can then change the timing of the code and cause shifts in tightly-timed stuff like kernels.

 

 

Link to comment
Share on other sites

So, you are using a reflected instead of a repeated playfield so that you only have to do two playfield register updates for your score? If that's the case, you can do that, and then switch to a repeated playfield once the score has been drawn. 

 

You can continue to use the reflected playfield for the rest of your screen if you prefer, but as mentioned before, the timing is more finicky. You need to update the reflected copy of PF2 exactly after the first copy has displayed, and before the reflected copy of PF2 has begun to display. 

 

Also, make sure you have a good timing chart like the one @Andrew Davie made. It's invaluable for making sure you are doing things on the right cycles. 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...