'Petr's modifications: Add TextCirlce& function [create hardware circle image],
' Rows: 127, 128, 161, 330, 331, 382
' #############################################################################
' This game is from:
'
' A QB64 roguelike in 50 lines
' https://nippycodes.com/coding/a-qb64-roguelike-in-50-lines/
'
' cleaned up and made prettier.
' ================================================================================================================================================================
' NOTES
' ================================================================================================================================================================
' The CSRLIN function returns the current text row position of the PRINT cursor.
' The POS function returns the current print cursor text column position.
' The SCREEN function returns the ASCII code of a text character or the color attribute at a set text location on the screen.
' codeorcolor% = SCREEN (row%, column% [, colorflag%])
' row and column are the INTEGER text coordinates of the SCREEN mode used.
' Optional colorflag INTEGER value can be omitted or 0 for ASCII code values or 1 for color attributes.
' ================================================================================================================================================================
' TO DO
' ================================================================================================================================================================
' Code improvements:
' * Remove GOTO statements and make code more modular.
' * Store terrain, players, objects, etc. in different arrays/layers for more complex interaction
' * Include a level editor (not just random levels).
' * Add combat and RPG features similar to Ultima 1-5
' * Quests
' * Towns, Castles, etc.
' Weapons:
' * Hands & Feet (default)
' * Club
' * Mace
' * Staff
' * Dagger
' * Sword
' * Great Sword
' * Spear
' * Bow / Arrow - player needs to find arrows
' * Sling - unlimited stones, can buy lead sling bullets for more damage
' Armor:
' * Skin (default)
' * Cloth
' * Leather
' * Chain Mail
' * Plate
' Armor (shields):
' * Leather Shield
' * Wood Shield
' * Small Metal Shield
' * Great Shield
' Objects:
' * Healing Potion - restore HP
' * Torches - allow player to see in dark areas
' Stats:
' * Food - decreases every n turns, if out of food player starves (loses HP)
' * Max HP - increases with higher levels
' Attributes that affect combat, etc.:
' * Strength
' * Agility
' * Stamina
' * Intelligence
' * Wisdom
' * Charisma
' * weapon attack skill (increases per weapon type as you use it)
' * weapon defense skill (increases per weapon each time you fight someone with it)
' Magic:
' ???
' Monsters / NPCs:
' * different races
' * have their own inventory of items, food, etc.
' * have different HP, attributes, etc.
' * can be interacted with or yell things
' Map:
' * include screens that are towns, not just random dungeons
' Store:
' * buy weapons/armor/food/healing
' * located in certain "civilized" areas
' ================================================================================================================================================================
' OPTIONS
' ================================================================================================================================================================
' ================================================================================================================================================================
' GLOBAL DECLARATIONS a$=string, i%=integer, L&=long, s!=single, d#=double
' ================================================================================================================================================================
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' UDFs
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' NEW:
' =============================================================================
' INITIALIZE
DC& = TextCircle&
' =============================================================================
' RUN THE MAIN PROGRAM
main ProgramName$
' =============================================================================
' FINISH
SYSTEM ' return control to the operating system PRINT ProgramName$
+ " finished."
' /////////////////////////////////////////////////////////////////////////////
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' VARIABLES
DIM arrGuy
(16) AS PlayerType
' ================================================================================================================================================================
' SHOW INSTRUCTIONS
COLOR cPeriwinkle&:
PRINT "-------------------------------------------------------------------------------" COLOR cCyan&:
PRINT "(a simple game based on " + CHR$(34) + "A QB64 roguelike in 50 lines" + CHR$(34) + " from nippycodes.com)" COLOR cPeriwinkle&:
PRINT "-------------------------------------------------------------------------------" COLOR cCyan&:
PRINT "If you touch a monster you will battle," COLOR cCyan&:
PRINT "and lose hit points but gain experience." COLOR cCyan&:
PRINT "Use the arrow keys to move around." COLOR cCyan&:
PRINT "Press the ESC key when you want to quit." COLOR cCyan&:
INPUT "Press ENTER to continue"; in$
' ================================================================================================================================================================
' START NEW GAME
' ================================================================================================================================================================
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
NewGame:
arrGuy(0).Gold = 0
arrGuy(0).HP = 100
arrGuy(0).XP = 0
arrGuy(0).Level = 1
'_FullScreen
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
NewLevel:
bNewCave = FALSE
arrGuy(0).X = 40
arrGuy(0).Y = 30
' DRAW BORDERS
' EMPTY OUT INSIDE
' CREATE RANDOM WALLS
FOR iLoop
= 0 TO (80 * 60 / 8) 'color cGray&
'Locate Int(52 * Rnd + 5), Int(72 * Rnd + 5)
'Print "#";
PutCharXY x%, y%, "#", cGray&
' SHOW PROGRESS
PRINT "Step 1+" + cstr$
(iLoop
) + " ";
' DROP RANDOM STUFF
' DRAW WALL
'color cGray&
'Locate iPosY, iPosX
'Print "#";
PutCharXY iPosX, iPosY, "#", cGray&
' DRAW EMPTY
'color cGray&
'Locate iPosY, iPosX
'Print ".";
PutCharXY iPosX, iPosY, ".", cGray&
' DRAW TREASURE
'color cYellow&
'Locate iPosY, iPosX
'Print "*";
PutCharXY iPosX, iPosY, "*", cYellow&
' DRAW EXIT
'color cWhite&
'Locate iPosY, iPosX
'Print "%";
PutCharXY iPosX, iPosY, "%", cWhite&
' SHOW PROGRESS
PRINT "Step 2+" + cstr$
(iLoop
) + " ";
' CLEAR SOME SPACE AROUND PLAYER
PutCharXY arrGuy(0).X - 1, arrGuy(0).Y - 1, ".", cGray&
PutCharXY arrGuy(0).X + 0, arrGuy(0).Y - 1, ".", cGray&
PutCharXY arrGuy(0).X + 1, arrGuy(0).Y - 1, ".", cGray&
PutCharXY arrGuy(0).X - 1, arrGuy(0).Y + 0, ".", cGray&
'PutCharXY arrGuy(0).X + 0, arrGuy(0).Y + 0, ".", cGray&
PutCharXY arrGuy(0).X + 1, arrGuy(0).Y + 0, ".", cGray&
PutCharXY arrGuy(0).X - 1, arrGuy(0).Y + 1, ".", cGray&
PutCharXY arrGuy(0).X + 0, arrGuy(0).Y + 1, ".", cGray&
PutCharXY arrGuy(0).X + 1, arrGuy(0).Y + 1, ".", cGray&
' PLACE MONSTERS
bMonsterPlaced = FALSE
'' Locate Y, X sets the current print position
'Locate Int(52 * Rnd + 5), Int(72 * Rnd + 5)
'' Screen(CsrLin, Pos(0)) returns the character code at the current print position
'If Screen(CsrLin, Pos(0)) = 46 Then
IF GetCharXY%
(x%
, y%
) = 46 THEN arrGuy(iLoop).X = x% ' Pos(0)
arrGuy(iLoop).Y = y% ' CsrLin
bMonsterPlaced = TRUE
' MAIN GAME LOOP
' GET KEYBOARD INPUT
' DRAW PLAYER
'color cLtGray&
'Locate arrGuy(0).Y, arrGuy(0).X
'Print "@";
PutCharXY arrGuy(0).X, arrGuy(0).Y, "@", cLtGray&
gPosX = arrGuy(0).X * 8 - 12 '-12 is for center image to text coordinate
gPosY = arrGuy(0).Y * 8 - 12
' WRITE SCORE + STATS
PRINT "Gold:"; arrGuy
(0).Gold
, "HP:"; arrGuy
(0).HP
, "Exp:"; arrGuy
(0).XP;
"/";
(4 + arrGuy
(0).Level
* 2), "Level:"; arrGuy
(0).Level;
' WRITE INSTRUCTIONS
PRINT "Arrows = Move", , "t = Teleport (-5HP on failure)";
' MOVE MONSTERS
IF arrGuy
(0).XP
>= (4 + arrGuy
(0).Level
* 2) THEN arrGuy(0).XP = arrGuy(0).XP - (4 + arrGuy(0).Level * 2)
arrGuy(0).Level = arrGuy(0).Level + 1
arrGuy(0).HP = arrGuy(0).HP + (arrGuy(0).Level * 5)
'color cGray&
'Locate arrGuy(iLoop).Y, arrGuy(iLoop).X
'Print ".";
PutCharXY arrGuy(iLoop).X, arrGuy(iLoop).Y, ".", cGray&
IF arrGuy
(iLoop
).X
< arrGuy
(0).X
AND SCREEN(arrGuy
(iLoop
).Y
, arrGuy
(iLoop
).X
+ 1) = 46 THEN arrGuy(iLoop).X = arrGuy(iLoop).X + 1
IF arrGuy
(iLoop
).X
> arrGuy
(0).X
AND SCREEN(arrGuy
(iLoop
).Y
, arrGuy
(iLoop
).X
- 1) = 46 THEN arrGuy(iLoop).X = arrGuy(iLoop).X - 1
IF arrGuy
(iLoop
).Y
< arrGuy
(0).Y
AND SCREEN(arrGuy
(iLoop
).Y
+ 1, arrGuy
(iLoop
).X
) = 46 THEN arrGuy(iLoop).Y = arrGuy(iLoop).Y + 1
IF arrGuy
(iLoop
).Y
> arrGuy
(0).Y
AND SCREEN(arrGuy
(iLoop
).Y
- 1, arrGuy
(iLoop
).X
) = 46 THEN arrGuy(iLoop).Y = arrGuy(iLoop).Y - 1
'color cGreen&
'Locate arrGuy(iLoop).Y, arrGuy(iLoop).X
'Print Chr$(142);
PutCharXY arrGuy
(iLoop
).X
, arrGuy
(iLoop
).Y
, CHR$(142), cGreen&
' ERASE OLD POSITION
'color cGray&
'Locate arrGuy(0).Y, arrGuy(0).X
'Print ".";
PutCharXY arrGuy(0).X, arrGuy(0).Y, ".", cGray&
' SET NEXT POSITION = CURRENT
iNewCol = arrGuy(0).X
iNewRow = arrGuy(0).Y
' GET INPUT
K$ = GetKey$
' PROCESS INPUT
IF K$
= CHR$(0) + "K" THEN iNewCol
= arrGuy
(0).X
- 1 IF K$
= CHR$(0) + "M" THEN iNewCol
= arrGuy
(0).X
+ 1 IF K$
= CHR$(0) + "P" THEN iNewRow
= arrGuy
(0).Y
+ 1 IF K$
= CHR$(0) + "H" THEN iNewRow
= arrGuy
(0).Y
- 1
' TELEPORT TO A RANDOM LOCATION
'color cWhite&
'Locate Int(52 * Rnd + 5), Int(72 * Rnd + 5)
'iNewCol = Pos(0)
'iNewRow = CsrLin
c% = GetCharXY%(iNewCol, iNewRow)
' IF YOU LAND ON NON-BLANK SPACE, LOSE HIT POINTS
'If Screen(CsrLin, Pos(0)) <> 46 Then
arrGuy(0).HP = arrGuy(0).HP - 5
' ATTACK MONSTER
'If Screen(iNewRow, iNewCol) = 142 Then
IF GetCharXY%
(iNewCol
, iNewRow
) = 142 THEN
' GET EXPERIENCE
arrGuy(0).XP = arrGuy(0).XP + 1
' SUSTAIN DAMAGE
arrGuy
(0).HP
= arrGuy
(0).HP
- INT(20 * RND + arrGuy
(0).Level
)
' ERASE OLD LOCATION
'color cGray&
'Locate iNewRow, iNewCol
'Print ".";
PutCharXY iNewCol, iNewRow, ".", cGray&
' DID MONSTERS REACH PLAYER?
IF arrGuy
(iLoop
).X
= iNewCol
AND arrGuy
(iLoop
).Y
= iNewRow
THEN ' NOT SURE WHAT THIS IS FOR
arrGuy(iLoop).X = -1
' PICK UP GOLD
arrGuy
(0).Gold
= arrGuy
(0).Gold
+ INT((15 * RND + 1) * RND + 1) 'color cGray&
'Locate iNewRow, iNewCol
'Print ".";
PutCharXY iNewCol, iNewRow, ".", cGray&
' EXIT CAVE
arrGuy(0).XP = arrGuy(0).XP + 5
bNewCave = TRUE
'color cGray&
'Locate iNewRow, iNewCol
'Print ".";
PutCharXY iNewCol, iNewRow, ".", cGray&
' MOVE TO EMPTY SPACE
arrGuy(0).X = iNewCol
arrGuy(0).Y = iNewRow
iNewRow = arrGuy(0).Y
iNewCol = arrGuy(0).X
' KEEP GOING UNTIL QUIT (HIT ESC), OR DEAD, OR NEW CAVE
' ================================================================================================================================================================
' IS PLAYER DEAD?
' GAME OVER MAN
PRINT "--== Game Over! ==--"
' ================================================================================================================================================================
' NEW CAVE
' NEXT CAVE
'KEYDELAY 0
' ================================================================================================================================================================
' GAME OVER
' PLAY AGAIN?
K$ = YesOrNo$
' /////////////////////////////////////////////////////////////////////////////
' Convert a value to string and trim it (because normal Str$ adds spaces)
'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
' /////////////////////////////////////////////////////////////////////////////
'Locate y%, x%
'GetCharXY% = Screen(CsrLin, Pos(0))
GetCharXY%
= SCREEN(y%
, x%
, 0) ' character code return parameter 0
' /////////////////////////////////////////////////////////////////////////////
GetColorXY&
= SCREEN(y%
, x%
, 1) ' character color return parameter 1
' /////////////////////////////////////////////////////////////////////////////
SUB PutCharXY
(x%
, y%
, char$
, myColor&
)
' /////////////////////////////////////////////////////////////////////////////
K$ = ""
GetKey$ = K$
' /////////////////////////////////////////////////////////////////////////////
bFinished% = FALSE
bFinished% = TRUE
YesOrNo$ = K$
' /////////////////////////////////////////////////////////////////////////////
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' COLOR CODE FUNCTIONS
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
cBlue& = 1
cGreen& = 2
cLtBlue& = 3
cRed& = 4
cPurple& = 5
cOrange& = 6
cWhite& = 7
cGray& = 8
cPeriwinkle& = 9
cLtGreen& = 10
cCyan& = 11
cLtRed& = 12
cPink& = 13
cYellow& = 14
cLtGray& = 15
FUNCTION TextCircle&
'create HARDWARE image, this can be placed also to SCREEN 0, but _DISPLAY must be always used!