A downloadable game

# Lader

## BASIC 10 Liner platformer for 8 bit computers

by **Marco Varesio** ( Marco's Retrobits (https://retrobits.itch.io/))

Download/play online (https://retrobits.itch.io/lader)

YouTube channel (https://www.youtube.com/@marcosretrobits)

English language blog (https://retrobits.altervista.org/)

Italian language blog (https://somebitsofme.altervista.org)

**Lader (https://retrobits.itch.io/lader)** (in Piedmontese language, *làder* means thief, robber) is a simplified version of the classic CP/M game called Ladder (https://en.wikipedia.org/wiki/Ladder_(video_game)). You are a treasure hunter who sneaked in an old ruined and abandoned mansion, in search of money and glory. In order to find the treasure, you'll have to walk on the platforms and climb the ladders in each room. But beware, the house is haunted by ghosts, whose touch is lethal!

Lader has been coded in **ugBASIC** (https://ugbasic.iwashere.eu/) for the 14th Edition (2025) of the **BASIC 10 Liner Contest** (https://www.homeputerium.de/), EXTREM-256 category and is currently available for the following 8 bit home computers: **Sinclair ZX Spectrum**, **Commodore 64** and **Atari**. In the ZX Spectrum version, there are at most 2 ghosts simultaneously on screen, while in the Commodore 64 and Atari versions there might be up to 4 ghosts. 


## Instructions,

The character controlled by the player is represented by a "p" when facing right, "q" when facing left. The aim of the game is to reach the treasure, represented by the character "$". To do this, the player must move on the platforms ("="), go up/down the ladders ("H") and climb over the walls ("|"), using the following keys:

* E: Up

* D: Down

* O: Left

* P: Right

* SPACE: Jump

Your task is made difficult by ghosts, represented by means of the character "o". Ghosts appear where the characters "V" are displayed and disappear near the asterisks "*". Contact with ghosts is lethal and will result in the loss of a life.

The current level number is displayed at the top left corner of the screen, while remaining lives counter is shown at the top right corner. When there are no more lives left, the game will start again from the 1st level.

Due to the contest constraints on the program length, the game features only 3 unique level screens.


## Program listing

Below is the full source code of the program, completed with comments explaining how it works in detail:

```basic

OPTION DEFAULT TYPE SIGNED BYTE : ' Set the default type of variables to signed byte

' Levels data

' For each level, data is encoded in the following way:

' The first 2 values contain the coordinates of the player start position

' -1 indicates that the following pairs of values contain the coordinates of the enemies start positions "V"

' -2 indicates that the following pair of values contain the coordinates of the treasure "$"

' -3 indicates that the following pairs of values contain the coordinates of the enemies stop positions "*"

' -4 indicates that the following pairs of values contain the coordinates of the walls "|"

' -5 indicates that the following triplets of values contain the coordinates and length of the platforms "="

' -6 indicates that the following triplets of values contain the coordinates and height of the ladders "H"

' -8 marks the end of level data

' -9 marks the end of all levels data

0 DATA _

1,22,-1,10,12,22,12,-2,31,22,-3,0,22,-5,0,23,32,-8, _

5,22,-1,14,0,-2,24,0,-3,0,22,31,22,-5,3,3,25,0,8,21,23,8,9,3,13,10,16,13,10,0,18,8,10,18,9,21,18,8,0,23,32,-6,5,3,6,5,12,6,11,7,3,11,13,1,24,1,2,24,7,6,24,17,6,-8, _

    3,22,-1,5,6,26,6,-2,30,4,-3,9,22,20,22,22,22,-4,4,6,9,17,9,18,12,10,16,21,16,22,27,6,-5,0,7,10,11,7,10,22,7,10,0,11,9,10,11,3,15,11,6,22,11,10,0,15,8,11,15,9,22,15,10,0,19,7,9,19,11,22,19,10,0,23,32,-6,1,6,5,1,14,5,30,5,2,30,10,5,30,18,5,-8,_

-9

' Some useful character codes

cH=ASC("H")

cBl=ASC(" ")

cDl=ASC("$")

cAs=ASC("*")

cV=ASC("V")

cq=ASC("q")

cp=ASC("p") 

cPi=ASC("|")

BORDER GREEN: PAPER BLACK: PEN GREEN: CLS : ' Good old green phosphor look and feel

' Screen initialization. The game can be compiled for virtually any platform supported by ugBASIC

' with at least 24 lines and 32 columns in text mode.

' On platforms with a greater screen resolution, the console command is used for centering

' the output on the screen.

IF SCREEN COLUMNS > 32 THEN:CONSOLE (SCREEN COLUMNS-32)/2, 0, (SCREEN COLUMNS-32)+32, 24:ENDIF

DIM t AS WORD : ' Used for timing

DIM d(2) : ' Player start position coordinates 

DIM e(2,2) : ' "Enemies" start positions coordinates 

DIM o(5,4) : ' Animated game objects: player (at index 0) and enemies (at indexes 1,2,3,4)

: ' The 2nd dimension contains: x and y coordinates, horizontal speed h, status s

: ' Horizontal speed can be: +1 (moving right), 0 (not moving horizontally), -1 (moving left).

' Status can be: 0:run/climb/still; 1:fall; 2:jump; 3:idle (only enemies can be idle)

n=4 : ' Max number of enemies simultaneously on screen

PROCEDURE z : ' This procedure limits the enemies number to 2.

  SHARED n : ' Since I noticed that on Z80 platforms (MSX,

  n=2 : ' ZX Spectrum) the game slows down with n>2, the

END PROC : ' procedure is invoked only for those platforms

z[] ON CPUZ80 : ' (ON CPUZ80)

DIM m(24,32) : ' Current level map (array of 32x24 character codes)

w=1 : ' Highest level reached (hi score)

DO : ' External endless loop. As soon as a game ends, a new one is immediately started

  l=5 : ' Initialize lives left

  k=0 : ' Initialize current level number

  f=0 : ' Used for reading platform length and ladder height data

  RESTORE 0 : ' Start reading level data from the beginning (1st level)

  DO : ' Levels loop. Executed until the player has no more lives left

CLS

' ----------------------

    ' Load and display level

    ' ----------------------

    INC k

' Clear current level map by initializing all items to blank " "

FOR x=0 TO 31

  FOR y=0 TO 22

    m(y,x)=cBl

  NEXT

NEXT  

a=0 : ' Which kind of level data is being read (ladders, walls, platforms...)

i=0 : ' Iterator used in for loops

ec=0 : ' Enemies count

DO : ' Loop through the g() array, decode level data and disply level on screen

: ' Decoded level data is used for initializing variables and filling current level map m() accordingly

  READ x:IF x=-9 THEN:RESTORE 0:READ x:ENDIF : ' Read the next value from levels data and store it into x. If the end 

  : ' of levels data list is reached, start again from the beginning

  IF x>=0 THEN : ' A value > 0 is a column number, so the next value is a line number  

  READ y:LOCATE x,y

    IF a=0 THEN : ' Reading the player start position

      d(0)=x:d(1)=y:c=cp : ' Store the player start position coordinates in d(0), d(1)

    ELSE IF a=-1 THEN : ' Reading the enemies start positions

      e(ec,0)=x:e(ec,1)=y:INC ec : ' Store the enemies start positions in the e() array

      c=cV:m(y,x)=c

    ELSE IF a=-2 THEN : ' Reading the treasure position

      c=cDl:m(y,x)=c

    ELSE IF a=-3 THEN : ' Reading the enemies stop positions

      c=cAs:m(y,x)=c

    ELSE IF a=-4 THEN : ' Reading the walls positions

      c=cPi:m(y,x)=c

    ELSE IF a=-5 THEN : ' Reading the platforms positions

      READ f:FOR i=x TO x+f-1:m(y,i)=ASC("="):PRINT"=";:NEXT

    ELSE IF a=-6 THEN : ' Reading the ladders positions

      READ f:c=cH:FOR i=y TO y+f-1:m(i,x)=c:LOCATE x,i:PRINT"H";:NEXT

    ENDIF

    IF a>-5 THEN:PRINT CHR$(c);:ENDIF

  ELSE

    a=x

    IF (x=-8)THEN:EXIT:ENDIF : ' -8 is the end of level data; exit loop

  ENDIF

LOOP

a=0 : ' Game status: 0:running; 1:level completed; 2:life lost

' ----------

' Play level

' ----------

DO

  ' Clear positions initially occupied by player or enemies

  ' and initialize player and enemies statuses

  FOR i=0 TO n

LOCATE o(i,0),o(i,1): PRINT CHR$(m(o(i,1),o(i,0)));

IF i=0 THEN : ' Player

  o(0,0)=d(0) : ' Set player initial x position

  o(0,1)=d(1) : ' Set player initial y position

  o(0,2)=1 : ' Set player horizontal speed (1: moving right)

  o(0,3)=0 : ' Set player status to 0 (run/climb/still)

ELSE : ' Enemy

  o(i,3)=3 : ' Set enemy status to 3 (idle)

ENDIF

  NEXT

  ' Print lives left count in the top right corner

  LOCATE 31,0:PRINT l;

  ' Print level number in the top left corner

  LOCATE 0,0:PRINT k;

  j=0 : ' Jump timer. Used to synchronize player jumps

  oc=0 : ' Enemies spawn timer. Used for spawning enemies

  DO : ' Game loop

t=TIMER : ' Timer. Used to control game speed

FOR i=0 TO n : ' Iterate over game objects

  x=o(i,0) : ' Read object x position

  y=o(i,1) : ' Read object y position

  h=o(i,2) : ' Read horizontal speed

  s=o(i,3) : ' Read status   

  v=0 : ' Vertical speed (1: moving down; 0: not moving vertically; -1: moving up)

  IF s=3 THEN : ' If the enemy is idle and the spawn timeout oc is 0, spawn enemy at a random start position in e()

IF oc=0 THEN:INC oc:r=0:IF ec>1 THEN:r=RND(2):ENDIF:o(i,0)=e(r,0):o(i,1)=e(r,1):o(i,2)=((i AND 1) = 1)-((i AND 1) = 0):o(i,3)=1:ENDIF

  ELSE

IF i<>0 THEN : ' Check if current object is an enemy and if it is hitting the player. 

  IF x=o(0,0) AND y=o(0,1) THEN:LOCATE x,y:PRINT "x";:a=2:EXIT 2:ENDIF : ' If so, set game status to 2 (life lost) and exit loop

ENDIF

IF s<2 THEN

  ' Not jumping

  c=m(y+1,x) : ' Check the position below the object

  IF c=cBl THEN : ' The position below the object is empty (blank space)...

s=1:v=1 : ' ...so the object is falling down

  ELSE : ' The position below the object is not empty

IF i<>0 THEN : ' Current object is an enemy

  IF c=cH THEN : ' The character below the enemy is a ladder

IF s=0 THEN : ' The enemy is passing over a ladder...

IF RND(2)=0 THEN:s=1:v=1:ENDIF : ' ...randomly choose whether the enemy will go down the ladder

ELSE : ' The enemy is already on a ladder....

s=1:v=1 : ' ...keep descending the ladder

ENDIF

  ELSE : ' The position below the enemy is neither empty nor a ladder

IF s=1 OR v=1 THEN : ' If the enemy was falling or descending a ladder...

r=RND(2):h=(r=0)-(r=1):v=0:s=0 : ' stop descending and choose a random horizontal direction

ENDIF

  ENDIF

ENDIF

IF i=0 THEN : ' Current object is the player

  s=0 : ' Move and update status according to the key pressed

  IF KEY STATE(KEY SPACE) AND s=0 AND j=0 THEN:j=-1:s=2:ENDIF : ' SPACE: jump

  IF KEY STATE(KEY E) THEN:IF m(y,x)=cH THEN:h=0:v=-1:ENDIF:ENDIF : ' e: if on a ladder, climb it

  IF KEY STATE(KEY D) THEN:IF c=cH THEN:h=0:v=1:ENDIF:ENDIF : ' d: if on a ladder, descend it

  IF KEY STATE(KEY P) THEN:h=1:ENDIF : ' p: go right

  IF KEY STATE(KEY O) THEN:h=-1:ENDIF : ' o: go left

ENDIF

  ENDIF

ELSE

  ' Jumping (only the player can jump)

  IF j<0 THEN

DEC j:IF j>-4 THEN:DEC v:ENDIF:IF j=-5 THEN:j=0:s=1:ENDIF : ' Update status and vertical speed based on the jump timer 

  ENDIF

ENDIF

IF s<>1 AND v<>1 THEN x=x+h : ' Update horizontal coordinate x : 'x=x-(h*(s<>1)):'bug?

IF x=32 OR x=-1 OR m(y,x)=cPi THEN:h=-h:x=x+h:ENDIF : ' If reaching the screen left or right border, go back

y=MAX(0,y+v) : ' Do not go beyond the top of the screen

IF i=0 THEN : ' Current object is the player...

  p=CHR$(cq+(h=1)) : ' ...display it using 'p' or 'q' depending on his horizontal direction

ELSE : ' Current object is an enemy...

  p="o" : ' ...display it using the 'o' character

ENDIF

LOCATE o(i,0),o(i,1): PRINT CHR$(m(o(i,1),o(i,0))); : ' "Delete" the object from its old position on the screen

LOCATE x,y: PRINT p; : ' Print the object to its new position

c=m(y,x) : ' Check character at current object position in the level map for collision detection

IF i=0 THEN : ' Player

  IF c=cDl THEN:a=1:EXIT 2:ENDIF : ' Player reached the treasure. Set game status to 1 (level completed) and exit loop

ELSE : ' Enemy

  IF c=cAs THEN:s=3:LOCATE x,y:PRINT "*";:ENDIF : ' Enemy reached a stop position. Become idle

  IF x=o(0,0) AND y=o(0,1) THEN : ' Enemy hits the player...

  LOCATE x,y:PRINT "x";:a=2:EXIT 2 : ' ...so, set game status to 2 (life lost) and exit loop

  ENDIF

ENDIF

' Update game object properties 

o(i,0)=x

o(i,1)=y

o(i,2)=h

o(i,3)=s

  ENDIF

NEXT  

INC oc:IF oc>=20 THEN oc=0 : ' Reset the enemy spawn timeout

WHILE ABS(TIMER-t)<4:WEND : ' Wait for (at least) 4 frames

  

  LOOP : 'Game loop end

  WAIT 1000 MS

  ' Check game status

      IF a=1 THEN:EXIT:ENDIF : ' Level completed. Exit loop so that next level is loaded

      IF a=2 THEN:DEC l : ' Life lost

        IF l=-1 THEN : ' No more lives...

  LOCATE 0,0:PRINT "GAME OVER" : ' Game is over

  IF k>w THEN:PRINT "LEVEL=";k;". CONGRATS!":w=k:ENDIF : ' Check if new hi score

  WAIT 1500 MS:EXIT 2 : ' Exit and start again from 1st level

ENDIF

  ENDIF

LOOP

  LOOP

LOOP

```

The source code has been stripped of comments and spaces and compressed using the language abbreviations. The resulting program is made up of 10 lines, each with a maximum length of less than 256 characters; therefore, it is eligible for the EXTREM-256 category:

```basic

0 OpDftTySgndBy:Da1,22,-1,10,12,22,12,-2,31,22,-3,0,22,-5,0,23,32,-8,5,22,-1,14,0,-2,24,0,-3,0,22,31,22,-5,3,3,25,0,8,21,23,8,9,3,13,10,16,13,10,0,18,8,10,18,9,21,18,8,0,23,32,-6,5,3,6,5,12,6,11,7,3,11,13,1,24,1,2,24,7,6,24,17,6,-8,3,22,-1,5,6,26,6,-2,30

1 Da4,-3,9,22,20,22,22,22,-4,4,6,9,17,9,18,12,10,16,21,16,22,27,6,-5,0,7,10,11,7,10,22,7,10,0,11,9,10,11,3,15,11,6,22,11,10,0,15,8,11,15,9,22,15,10,0,19,7,9,19,11,22,19,10,0,23,32,-6,1,6,5,1,14,5,30,5,2,30,10,5,30,18,5,-8,-9:cH=Ax("H"):cBl=Ax(" ")

2 cDl=Ax("$"):cAs=Ax("*"):cV=Ax("V"):cq=Ax("q"):cp=Ax("p"):cPi=Ax("|"):BoGre:PaBl:PnGre:Cl:IfScCms>32Th:Cns(ScCms-32)/2,0,(ScCms-32)+32,24:Ei:Dit AsWo:Did(2):Die(2,2):Dio(5,4):n=4:PROCEDURE z:Srn:n=2:EePrb:z[]ON CPUZ80:Dim(24,32):w=1:Do:l=5:k=0:f=0:Rer0

3 Do:Cl:INCk:Fox=0To31:Foy=0To22:m(y,x)=cBl:Nx:Nx:a=0:i=0:ec=0:Do:R#x:Ifx=-9Th:Rer0:R#x:Ei:Ifx>=0Th:R# y:Lcx,y:Ifa=0Th:d(0)=x:d(1)=y:c=cp:ElIfa=-1Th:e(ec,0)=x:e(ec,1)=y:INCec:c=cV:m(y,x)=c:ElIfa=-2Th:c=cDl:m(y,x)=c:ElIfa=-3Th:c=cAs:m(y,x)=c:ElIfa=-4Th

4 c=cPi:m(y,x)=c:ElIfa=-5Th:R#f:Foi=x Tox+f-1:m(y,i)=Ax("="):?"=";:Nx:ElIfa=-6Th:R#f:c=cH:Foi=y Toy+f-1:m(i,x)=c:Lcx,i:?"H";:Nx:Ei:Ifa>-5Th:?Ch(c);:Ei:El:a=x:If(x=-8)Th:Ex:Ei:Ei:Lp:a=0:Do:Foi=0Ton:Lco(i,0),o(i,1):?Ch(m(o(i,1),o(i,0)));:Ifi=0Th:o(0,0)=d(0)

5 o(0,1)=d(1):o(0,2)=1:o(0,3)=0:El:o(i,3)=3:Ei:Nx:Lc31,0:?l;:Lc0,0:?k;:j=0:oc=0:Do:t=Tmr:Foi=0Ton:x=o(i,0):y=o(i,1):h=o(i,2):s=o(i,3):v=0:Ifs=3Th:Ifoc=0Th:INCoc:r=0:Ifec>1Th:r=Rr(2):Ei:o(i,0)=e(r,0):o(i,1)=e(r,1):o(i,2)=((i An1)=1)-((i An1)=0):o(i,3)=1:Ei

6 El:Ifi<>0Th:Ifx=o(0,0)Any=o(0,1)Th:Lcx,y:?"x";:a=2:Ex2:Ei:Ei:Ifs<2Th:c=m(y+1,x):Ifc=cBl Th:s=1:v=1:El:Ifi<>0Th:Ifc=cH Th:Ifs=0Th:IfRr(2)=0Th:s=1:v=1:Ei:El:s=1:v=1:Ei:El:Ifs=1ORv=1Th:r=Rr(2):h=(r=0)-(r=1):v=0:s=0:Ei:Ei:Ei:Ifi=0Th:s=0

7 IfKyStt(KySp)Ans=0Anj=0Th:j=-1:s=2:Ei:IfKyStt(KyE)Th:Ifm(y,x)=cH Th:h=0:v=-1:Ei:Ei:IfKyStt(KyD)Th:Ifc=cH Th:h=0:v=1:Ei:Ei:IfKyStt(KyP)Th:h=1:Ei:IfKyStt(KyO)Th:h=-1:Ei:Ei:Ei:El:Ifj<0Th:Dcj:Ifj>-4Th:Dcv:Ei:Ifj=-5Th:j=0:s=1:Ei:Ei:Ei:Ifs<>1Anv<>1Thx=x+h

8 Ifx=32ORx=-1ORm(y,x)=cPi Th:h=-h:x=x+h:Ei:y=Mx(0,y+v):Ifi=0Th:p=Ch(cq+(h=1)):El:p="o":Ei:Lco(i,0),o(i,1):?Ch(m(o(i,1),o(i,0)));:Lcx,y:?p;:c=m(y,x):Ifi=0Th:Ifc=cDl Th:a=1:Ex2:Ei:El:Ifc=cAs Th:s=3:Lcx,y:?"*";:Ei:Ifx=o(0,0)Any=o(0,1)Th:Lcx,y:?"x";:a=2:Ex2

9 Ei:Ei:o(i,0)=x:o(i,1)=y:o(i,2)=h:o(i,3)=s:Ei:Nx:INCoc:Ifoc>=20Thoc=0:WhAb(Tmr-t)<4:We:Lp:Wt1000MS:Ifa=1Th:Ex:Ei:Ifa=2Th:Dcl:Ifl=-1Th:Lc0,0:?"GAME OVER":Ifk>w Th:?"LEVEL=";k;". CONGRATS!":w=k:Ei:Wt1500MS:Ex2:Ei:Ei:Lp:Lp:Lp:'Lader - Marco's Retrobits 2025

```

![Program length proof](img\Program_length_proof.png)

## Emulators instructions

Lader is available for several 8 bit computers, in emulators-friendly file formats:

* Commodore 64: **lader10l.c64.prg**

* Atari 400/800: **lader10l.atari.xex**

* ZX Spectrum: **lader10l.zx.tap**

Please follow the platform specific instructions in the sections below for details on how to load the desired version of Lader in the most popular emulators.

Once the program is loaded, the ugBASIC runtime will prompt you for a command:

```

ugBASIC Runtime version 1.XY.Z

READY

```

To start the game, type <kbd>run</kbd> and tap <kbd>Enter</kbd>.

To view the listing, type <kbd>list</kbd> and tap <kbd>Enter</kbd>.

### Platform specific instructions

#### Commodore 64 (VICE emulator)

* Start the VICE C64 executable (e.g. x64sc.exe)

* Either:

  * Open the lader10l.c64.prg file by choosing "File" -> "Smart attach...",

  * When the "READY" prompt is shown, type <kbd>run</kbd> followed by <kbd>Enter</kbd>.

* Or:

  * Drag the lader10l.c64.prg file and drop it into the VICE C64 window.

    This will automatically start the ugBASIC runtime.


#### Atari (Altirra emulator)

* Start the Altirra executable (e.g. Altirra64.exe)

* Either:

  * Open the lader10l.atari.xex file by choosing "File" -> "Boot Image...";

* Or:

  * Drag the lader10l.atari.xex file and drop it into the Altirra window.


#### Sinclair ZX Spectrum (FUSE - the Free Unix Spectrum Emulator)

* Start the Fuse executable (e.g. fuse.exe)

* Select the "Spectrum 48K" model in "Machine" -> "Select..."

* Make sure that automatic loading of tape image files is enabled, by checking the corresponding options in

  "Options" -> "Media..."

* Either:

  * Open the lader10l.zx.tap file by choosing "File" -> "Open...";

* Or:

  * Drag the lader10l.zx.tap file and drop it into the Fuse window.

If your emulator of choice does not support automatic tape loading, after mounting the tape image you

must manually issue the tape loading command, by pressing the J key, followed by CTRL + P twice (the SYMBOL SHIFT ZX Spectrum key is usually mapped to CTRL) and then by ENTER.


<style type="text/css">html {overflow-x: initial !important;}:root { --bg-color: #ffffff; --text-color: #333333; --select-text-bg-color: #B5D6FC; --select-text-font-color: auto; --monospace: "Lucida Console",Consolas,"Courier",monospace; --title-bar-height: 20px; }</style>
Updated 20 hours ago
Published 1 day ago
StatusReleased
AuthorBASIC 10Liner
GenreAction
Tags10iner, 8-Bit, atari, basic, Commodore 64, ZX Spectrum

Download

Download
Lader.pdf 267 kB
Download
lader10l.atari.xex 29 kB
Download
lader10l.bas 2.4 kB
Download
lader10l.c64.prg 49 kB
Download
lader10l.zx.tap 25 kB
Download
Lader.html 204 kB
Download
Lader.md 18 kB
Download
file_id.diz 1.1 kB
Download
lader.bas 11 kB

Comments

Log in with itch.io to leave a comment.

very good

thank you!!!