A downloadable game

Magic Carpet Ride - BASIC 10Liner Contest 2024

==============================================

Author:   Eric Carr

Language: Atari BASIC Rev B/C

Platform: Atari 8-bit

Category: PUR-80


Video:


Requirements:

System: Atari 8-bit w/ 48KB+ memory (XL/XE) w/ Joystick

Emulator: Atari800MacX (on Mac) or Altirra (Windows)

BASIC ROM Cartridge if on emulator - REV B attached with submission


Background

==========

Inspired by Disney's Aladdin movie, I came up with the idea of a Aladdin riding a carpet, dodging arrows and collecting hearts. I ran out of space for hearts, but still arrived at a fun little endless dodging game that starts slow and quickly gets difficult.


Gameplay

========

The game starts immediately. Use your joystick to dodge up/down, and press joystick button on game end to start again.


Code Overview

=============

I brainstormed a method to quickly move a large character (24x18 pixels in this case) in built-in Atari BASIC:

1. Shift entire screen up/down by a single POKE to the display list screen memory pointer.

2. Since this makes the entire main screen move, I use the text window mode to show the score on the bottom. 

3. Use player/missile graphics to shoot arrows to player

4. Animate the carpet to make it look like it is flying (flapping in the wind). I use a custom charset for the player

5. To accomplish this, I use a custom location for the charset and screen locations, using Atari Strings to control the game graphics


Line by Line explanation

========================

Lines 0-5: Initialize the game

Lines 6-9: Game loop

0 GR.13:SE.0,2,4:POKE40311,71:POKE40314,75::DI.Z$(128),Y$(17032-ADR(Z$)),B$(4000)

  1. Set graphics mode 13

  2. Set color register 0

  3. Update Display List to convert bottom text window to different font size and hide rest of window

  4. Dimension Z$ (empty array buffer, used to clear Player/Missile memory for arrows)

  5. Dimension a dummy Y$ string array to position our $B buffer where I need it in memory.

     The custom charset starts at 16384, and the custom screen memory follows afterward.

     The B$ buffer (the part we overwrite with the custom characters starts at 17032)

1 B$=".":B$(4000)=B$:B$(2)=B$:Z$=B$:F.I=16513TO16591:POKEI,PEEK(40960+I):N.I:X=99

  1. Clear the B$ buffer 

  2. Set Z$ to the clear B$ buffer as well

  3. Copy the 0-9 numbers from character ROM to our custom charset location

  4. Set initial arrow X position. The arrow is not drawn yet, so this serves as a little delay before the first arrow comes.

2 B$(8)="..."

  1. Set custom charset (Our character riding on the magic carpet)

3 POKE88,231:POKE89,68:SE.1,0,0:B$(86)="..."

  1. Update our custom screen location to memory 88,89, so PRINT #6 statements work

  2. Set color register 1

  3. Set rest of custom charset (Our character riding on the magic carpet)

4 POKE54279,72:POKE559,46:POKE756,64:P=53252:POKEP+25,2:POKEP+26,0:D=9:M=1:C=238

 1. Set Player Missile Base to 72

 2. Set SDMCTL to 46: Standard playfield width, enable Player/Missiles

 3. Set custom character base to 64 (256*64=16384)

 4. Store memory location to check for collisions (53252)

 6. Set GRACTL(53277)to 2 (Turn on Players)

 7. Clear the collision register (POKE 53278 or P+26,0)

 8. Initialize arrow speeD var (D), Carpet Animation flap vars C and M

5 SE.2,0,14:SE.3,1,12:SE.4,7,8:POKE40301,68:?#6,"   abc":?#6,"akefgh":?#6,"ijdlmn"

 1. Set color registers 2,3, and 4

 2. Set the display list significant byte (40301) to point to our custom screen location (68*256)

 3. Print our hero on the screen using the custom character set

== Start of game loop ==

6 POKE40300,Y*40:L=STICK(0)/2:T=L/2+.25:POKE17733+G,M+C-G*127:G=NOTG:IFG THENM=-M

 1. Set character Y position by updating where the Display List Points to as the start of screen memory

 2. Read the joystick into L. L will be even for upleft/up/upright stick positions.

 3. Compute T - it will be even if it is left/right/middle (DOWN not pressed)

 4. Poke the appropriate screen location to animate the carpet. I alternate between two characters,

    in two screen locations: 11 12 22 21, repeat

 5. Toggle G which helps in animating the carpet characters

7 Y=Y+SGN((L=INT(L))*6+(T=INT(T))*3-Y):IFPEEK(P)THENSE.4,0,0:ONSTRIG(0)GOTO7:RUN

 1. Move the player Y (vertical position) toward its target value:

    Joystick UP: 6 (L is even)

    Joystick left/right/center: 3 (T is even)

    Joystick DOWN: 0 (Neither L or T are even)

 2. Check for collision with arrow (P). If so, darken screen and wait for button press to restart. 

8 X=X-D:POKE53248,X:ONX>30GOTO6:SO.0,150-D,10,8:D=D+.5*(D<18):IFF THENB$(1809)=Z$

 1. Move the arrow toward the player.

 2. If the arrow is still onscreen, GOTO 6 (continue game loop)

 3. Otherwise:

  1. Play a sound, increase arrow speed for the next arrow (D) up to a max of 18

  2. Every alternate round, if flag F is set, clear the player/missile area (set to Z$). 

     Instead of clearing every round, I do this every other round to allow for the possibility 

     of two arrows being shot to add to the challenge.

9 X=220:F=NOTF:?"[esc][delete]";S;:S=S+10:B$(1809+INT(RND(0)*3)*24)="ARROW SPRITE":SO.0,0,0,0:GOTO6

 This continues the code from line 8 which runs after an arrow goes offscreen

 1. Reset the arrow position to the right of the screen

 2. Toggle if we should clear arrow player/missile next round (flag F)

 3. Print the score. I use [esc][delete] char to clear the current text line when updating the score

 4. Increment the score. I increment it after printing, so the first print will display "0".

 5. Copy the arrow sprite at one of three locations (randomly) in player/missile memory.

 5. Finally, clear sound, then GOTO 6 to resume normal game loop


TOOLS / SOURCES

===============

- Atari FontMaker - Defining chars as block sprites (Game character)

  https://github.com/matosimi/atari-fontmaker

- SprEd - Player Missile Graphics Sprite editor (Arrows)

  https://bocianu.gitlab.io/spred

- Atari800MacX and Altirra - Emulators

- Aladdin sprite sheet (I modified/added the carpet)

  https://www.spriters-resource.com/game_boy_gbc/aladdingameboycolor/sheet/45559/

- Aladdin image for game manual sourced from:

  https://www.pinterest.com/pin/553450241704560250/

Download

Download
MagicCarpet.atr 130 kB
Download
MagicCarpet-MANUAL.png 477 kB
Download
MagicCarpet-readme.txt 7 kB
Download
MC.BAS 1 kB
Download
MC-ALTIRRA.BAS 1 kB
Download
XE-BASIC-REVC.ROM 8 kB
Download
XE-OS-co61598b.ROM 16 kB

Install instructions

Starting the game - Real Hardware

=================================

Simply boot the ATR, and enter: RUN "D:MC.BAS"


Starting the game - Emulator - Quick and easy

===================================

Altirra's default OS and BASIC run much faster than real hardware, so I made MC-ALTIRRA.BAS, which is the same code size but the arrows has a slower initial and max speed to make up for the higher framerate in Altirra OS/BASIC.

1. Start Altirra, set system to 130XE, PAL

2. Drag/drop MC-ALTIRRA.BAS on Altirra to start the game


Starting the game - Emulator - Authentic

===================================

To run the emulator to match real hardware speed, you need to set Altirra to use a real OS ROM (Not Altirra OS). You also need to use a REV B/C Basic ROM, not Altirra BASIC.

I have included an OS and BASIC ROM for 130XE if you want to match the speed in my video.

1. Start Emulator (Altirra or Atari800MacX), Set to 130XE, PAL.

2. Go to System config>Firmware and set XE-OS ROM.

3. Setup BASIC Cartridge. Drag XE-BASIC-REVC.ROM onto emulator.

3. Mount/Attach "MagicCarpet.atr" to Drive 1. 

   NOTE: In Altirra, if you drag/drop, choose *MOUNT Image*. Do NOT "BOOT Image" or it will remove the BASIC cartridge.

4. Cold reset the emulator (Shift+F5)

5. At the READY prompt, type in and press enter: RUN "D:MC.BAS"

Comments

Log in with itch.io to leave a comment.

I´m trying to load direct from dos but after choose load file what have I to do ?

You don't have to load the DOS menu, because it' s a Basic file. Boot it with Basic enabled, then type LOAD"D:MC.BAS"

Nice game, but the custom charset is allowed? it's not defined into the listing, as what I see

(1 edit)

Thank you! Yes, the custom charset is set into B$ in lines 2 and 3.  It's a pretty standard way of setting them using one character per byte instead of a list of numbers in a DATA statement, which consume much more code.

See below:

Wow, Sorry for the question, but coming from c64 , where you have to struggle a lot to change the charset, it didn't seem a possible thing! I confirm my compliments and wish you a good challenge.

Thank you!  I found someone doing a similar trick on c64 to put PETSCII chars in a string, and pointed the charset to the start of the program, though there may be a limit on which values can be encoded like this:

https://www.reddit.com/r/c64/comments/1214xwo/10print_with_custom_characters_and... 

Probably there's a little misunderstood, when I read "custom charset" I thought you were talking about replacing stock chars with new designed ones, and this is a slow and space consuming operation in basic on c64. You were talking, instead,about putting stock chars in a variable, and this is normal also for C64. 

So kudos for the Aladdin pixel art made with stock chars,it's resembling a lot the original one.

(1 edit)

No, it is replacing the stock with custom characters. It works the same for C64 and Atari:

1. Put your custom charset bytes (8 bytes per char) somewhere in RAM. The traditional slow way is a bunch of data statements and a loop to POKE to some location.

2. Tell computer the new charset location


For step 1 here, I save space and time by positioning the actual string at a spot in memory that I tell the computer the charset is located. I fill the string with special chars to represent each of the 8 bytes per custom char. Therefore no DATA, looping, POKEing required.

This works in Atari since a string can be thousands of bytes long, unlike C64 which must be 255 or less. I create a dummy string that takes up useless ram but positions the very next string right where I need it. This was a typical Atari BASIC trick from back in the day.