A downloadable game

# Roguelike 10

This game was written for the Basic 10-Liner Contest 2023 in the PUR-80 category. It's written for Commodore 64/128 computers.


## Aim of the game

As in all rogue-like games, your aim is to explore as many randomly generated dungeons as possible, not get slain and find as much gold as you can carry!

With joystick in port 2, your hero character can move and attack only in 4 directions while creatures can move and attack also diagonally.

To attack a creature, move towards its position on the screen. In melee combat, you lose 1 HP (hit point).

It takes only one hit to kill a creature. When you are on one a field next to the creature, you will also lose 1 HP.

Get 1 HP back with each health potion you collect.

Good luck in your quest! And may your name be remembered!


## What's on the screen

In the top left part of the screen you can see remaining hit points, current dungeon level and amount of gold.

For example, `9HP 5L 6G` indicates that hero has 9 hit points remaining, is currently exploring 5th level of dungeons and has 6 pieces of gold.

The rest of the screen contains current level dungeon. Only the area surrounding your hero is revealed, so be careful where you move!

- your hero is represented with the "X" character

- floor is represented with the chessboard pattern

- health potions are represented with the plus sign ("+")

- creatures are represented with the white spade character

- gold is represented with the diamond character

- stairs to the next level are represented with the equal sign character ("=")



## Constants and variables

A - global constant, start of the screen memory (1024)

A$ - string used to position cursor back left on a single dungeon chamber vertical draw

B - on dungeon generation, prints row of single chamber vertically up to Y

B - on dungeon reveal, used to iteratate in horizontal position 

B$ - global constant, string with dungeon floor pattern used while drawing a single chamber

C - on main loop, joystick position state (-1 for left, 1 for right, otherwise 0)

C$ - string used to position cursor back up on dungeon chamber draw so the next chamber can be drawn next to it

D - on main loop, joystick position state (-1 for up, 1 for down, otherwise 0)

D$ - on dungeon generation, builds one row of a dungeon chamber with randomised object

E - global variable, player position, reset to screen memory location 1270 for each level

E$ - string with all objects in the following order: floor (102), gold (90), creature (65), health potion (43), stairs (61)

F - global constant of 40

F$ - global constant, sets position and light blue colour for the HUD

G - on dungeon generation, used to iterate for the first or the second row of chambers

G - on creature movement, switch between 0 and 1 to slow down creature movement

H - on player move, calculates destination position in order to see if player can move there

I - on dungeon generation, increments until 5 chambers are drawn horizontally

I - on dungeon reveal, used to iterate in vertical position

J - global variable, value of joystick port 2

K - screen colour address offset by the starting position of player

L - on dungeon reveal, calculates position to reveal in order to check if there's any creature to activate

M - global variable, amount of gold

N - global variable, hit points (or eNergy)

O - on creature movement, calculate new position of creature that follows player (combines horizontal and vertical sign in range -41:41 to 41:41)

P - on creature movement, check if relative position of creature and player are different horizontally

Q - on creature movement, result of PEEKing a screen character to check if creature can move there, or if player to attack is there

R - global variable, dungeon level

S - global constant, floor character (102)

T - on player move, gets screen value for player destination position to see if player can move there

U - on creature movement, round player's vertical position against screen grid (40 blocks per row resolution)

V - global constant, screen border colour address

W - on creature movement, round creature's vertical position against screen grid (40 blocks per row resolution)

X - on dungeon generation, randomised size of a chamber (min: 2, max: 6)

X$ - clear screen and offset position to draw a dungeon level

Y - on dungeon generation, randomised size of a chamber (min: 2, max: 6)

Z - global constant, joystick port 2 address


## Scopes

- on dungeon generation

- on main loop

- on player move

- on dungeon reveal

- on creature movement


## Creature movement

Simplified condition to move to a field if PEEK(screen) > 61

Do not move if:

- player (24)

- wall (32)

- health potion (43)

- stairs (61)

Move if:

- another creature (65)

- gold (90)

- floor (102)


## Code line by line

Line 0:

- Define function to return randomised number within the range 1 to N

- Initialise global constants in the following order: A, F, K, S, V, Z, A$, B$, C$, E$, X$

- Set screen colour and border to black

- Set initial hit points to N=10

- Define in Z$ the position and the colour of HUD


### Line 1 (dungeon generation):

- Set initial position of player's character to E=1270

- Dungeon generation begins

- Clear the screen and set the position of dungeon (set in X$, then TAB(6))

- Increase dungeon level by 1 with R=R+1

- Outer `FOR G=0 TO 1` loop to generate inner loop twice (for two rows of chambers)

- Inner `FOR I=1 TO 5` loop to generate 5 chambers horizontally

- Randomise width (X) and height (Y) of a single chamber

- DATA line for global constants `A`, `F` and `K`


### Line 2:

- Set in D$ a single row of a chamber

- In the middle of a chamber, one of the first 4 objects is randomly set (1 = floor, 2 = gold, 3 = creature, 4 = health potion) if it's not the last chamber in the row (result of `-(I<5)*FNR(4)`)

- Exceptionally, for the last chamber in a row, stairs object (5) is always set (result of `-(I=5)*5` is `-1`)

- Nested `FOR B=1 TO Y` loop to draw a single chamber vertically

- Print string of floor characters determined by chamber width (`X`) followed by printing an object only if it's the second row of a chamber (`-(B=2)+1`)


### Line 3:

- Continue printing the last floor object followed by moving cursor to the beginning of the next row determined by chamber width (`X`)

- Next loop for `B` to continue drawing chamber vertically

- Position cursor up to glue the next chamber to the previous one (using `C$`)

- Next loop for `I` to continue the next chamber

- Moving cursor at the start of the second row of 5 chambers - it starts in the different position thanks to randomisation width of 5 chambers from the first row

- Next loop for `G` to continue drawing the second row of 5 chambers

- As there was no free variable left, re-use variable `G` for slowing down creature movement, as it's out of the dungeon generation scope, setting it to 0

- Jump to line 5 to reveal initially a surrounding area


### Line 4 (main loop):

- Print HUD with the following information: HP (hit points), L (current dungeon level), G (gold)

- Read joystick in port 2

- Set in variable `C` if joystick has been pushed in horizontal position

- Set in variable `D` if joystick has been pushed in vertical position

- If joystick directions not pressed, go to line 4


### Line 5:

- Check if player can move in the desired position by reading character from screen memory

- No matter if player can move, clear it from the position by drawing the floor character (`POKE E,S`) and set colour to blue (`POKE K+E,6`)

- Set new player position if field to enter is different than space character, otherwise it remains the same (`E=E-(T<>32)*(H-E)`)

- Set player's colour (`POKE K+E,8`) and (`POKE E,24`) at the new screen position

- Increment gold by 1 in case player steps on the gold object (`M=M-(T=90)`)


### Line 6:

- Increment player's hit points by 1 in case player steps on the health potion (`43`) and decrease by 1 if player gets into the fight with a creature (`65`) (calculated in one equation: `N=N-(T=43)+(T=65)`)

- In case player steps on the stairs, go to line 1 to generate the next dungeon (`ON -(T=61) GOTO 1`)

- Dungeon reveal starts here, by revealing 5x5 fields around the player character

- Outer `FOR I=0 TO 4` loop to iterate vertically

- Inner `FOR B=0 TO 4` loop to iterate horizontally

- Calculate offset starting from the top-left corner (`L=I*F+B+E-82`), `82` because it offsets two fields up and left from current player's screen position  (`40 * 2 + 2 = 82`)

- If creature character found during reveal, jump to line 8 to move creature towards the player (`ON -(PEEK(L)=65) GOTO 8`)


### Line 7:

- Set colour of an object character on the screen (`POKE K+L,PEEK(L)`), by re-using character code as a colour (see: Tricks and notes, point 1)

- Next loop for `B` to continue revealing area horizontally

- Next loop for `I` to continue revealing area vertically

- Use simple enable / disable mechanism to slow down creature's movement every second move of player (`G=1-G`)

- Check if player has any hit points left, if yes, go to the main loop in line 4 (`ON -(N>0) GOTO 4`)

- Otherwise, display RIP and `END` the program

- DATA line for global constants `S`, `V`,`Z` and`A$`


### Line 8:

- Calculate new position of creature to follow player character's screen position when in visible range, X and Y are extracted separately from single screen position value

- Store screen character in `Q` variable

- Draw floor on the screen in the place where creature character is (`POKE L,S`)


### Line 9:

- Set the colour of the floor so there's no artefact of creature's colour left on the screen on movement (`POKE K+L,6`)

- In case creature can move to the given position, set it if movement (switched in `G`) is enabled (`L=L-(G>61)*O*G`)

- Draw creature character on the screen, note that `L` might be updated now (`POKE L,65`)

- In case creature wanted to move to the position of player character, decrease player's hit points by 1 (`N=N+(Q=24)`)

- Go back to line 7 (used are some sort of a RETURN to continue loop, see: Tricks and notes, point 3)

- Data line for global constants `B$`, `C$`, `E$` and `X$`


## Tricks and notes

1. I had no space to set colours of different objects, but displaying everything in grey looked really dull. I used a trick to re-use the

character and set it as the colour of the object. The result was better than I expected. The whole revealed area of the dungeon turned

to blue, and all other objects, especially creatures, are visible.

2. I determined which objects (screen characters) are the best to group them into one that creature can walk in or not. This way

I improved a logic of checking if character is one of 3 (e.g. `-(Q=24 AND Q=32 AND Q=61)`) just into greater than a certain value (`-(Q>61)`, see: line 9)

Lot of characters saved!

3. In line 6 I used `GOSUB` initially so I can get back to the loop, but then when game over was added, there is no way in BASIC to

use `ON` in combination with `RETURN`. What helped was to use `GOTO` in line 6, and return to line 7 just with `GOTO`. I just

needed to be sure that there won't be anything else remaining in the line 6 after the jump.

StatusReleased
Rating
Rated 5.0 out of 5 stars
(1 total ratings)
AuthorBASIC 10Liner
GenreAdventure
Tags8-Bit, basic, basic10liner, Commodore 64

Download

Download
README.md 11 kB
Download
roguelike10.d64 170 kB
Download
roguelike10.prg 760 bytes
Download
roguelike10-petcat.txt 1 kB

Install instructions

## Loading and running the game

Double click on the d64 image when using emulation. The program should be autoloaded. On the real hardware, just load with:

LOAD"*",8

RUN

To play again after a game over, you have to type `RUN:` followed by `Return` key again.

The game was tested on a real hardware and with WinVice 2.4 emulator.

Comments

Log in with itch.io to leave a comment.

A rogue like in 10 lines. Impressive!