' Steve's RPG-like thing.
' Written in 2018.
' Version 0.1-dev (pre-alpha)
' Short term to do: figure out what's wrong with attack:, Add npc inventory, recognize death condition for npc, stop respawning npc every time player enters a room.
' Longer term goals: Get the non-weapon slots working. Show inventory. exchange weapons between slots. drop items.
DIM object
AS STRING ' For the parser, it's whatever is after the first word. DIM cmderror
AS INTEGER ' This is for parse. cmdeerror set to 1 when a command successfully executes. DIM WeaponTable
(5) AS weapon
' Weapons in the game. DIM curroom
AS room
' Room player is currently in. DIM curnpc
AS playertype
' Room NPC is currently in.
doneroom = 0
cmderror = 0
GOSUB roomsetup:
' Create starting room, intialize other rooms. GOSUB weapongen:
' Create the weapon table! GOSUB npcgen:
' Create the npc table! GOSUB playergen:
' Player Generation routine croom = 1 'starts in room 1.
GOSUB setroom:
' Set initial room properties.
Main: ' Main loop
INPUT "What do you do? ", res
IF cmderror
= 0 THEN PRINT "Invalid Command." ' This isn't working but it's to minor of a thing for me to dwell on at this stage.
GOTO Main:
' Shut up. I know.
parse:
phrase = "null"
object = "null"
IF phrase
= "null" THEN ' If phrase wasn't changed from null, that means the command is only one word. Set the word to be processed. phrase = res
phrase
= LCASE$(phrase
) ' Set it to be lowercase to avoid parsing issues.IF object
<> "null" THEN object
= LCASE$(object
) ' Only set to lowercase if it isn't null. ie, if an object was part of the command.
' This will be replaced with a SELECT CASE eventually.
IF phrase
= "xyzzy" THEN cmderror
= 1:
PRINT "Seriously? I don't think so." IF phrase
= "quit" OR phrase
= "exit" THEN cmderror
= 1:
GOSUB quit:
IF phrase
= "north" OR phrase
= "n" THEN cmderror
= 1:
GOSUB roomchange:
IF phrase
= "south" OR phrase
= "s" THEN cmderror
= 1:
GOSUB roomchange:
IF phrase
= "east" OR phrase
= "e" THEN cmderror
= 1:
GOSUB roomchange:
IF phrase
= "west" OR phrase
= "w" THEN cmderror
= 1:
GOSUB roomchange:
' I feel like there must be a better way to do this.
attack: ' Attacking isn't balanced and needs extensive work, but the very basic framework of a round is in place.
' npc in room 3 seems to have too many HP. Attack is buggy and weird in general.
DIM npcinit
AS INTEGER ' NPC's initiative. May change one of those names, they're real easy to confuse or mess up. DIM turn
AS INTEGER ' turn = 1 means player goes next, turn = 0 means npc goes next. DIM defense
AS INTEGER ' Defense role. Also used for player & pc
PRINT "There is nothing here to attack."
PRINT "Entering fight mode." PRINT "Your Initiative: "; pcinit;
" npc's Initiative: "; npcinit
IF pcinit
> npcinit
THEN turn
= 1 IF pcinit
< npcinit
THEN turn
= 0
FightLoop: ' Main fight loop. It's true turn based right now with no auto attack. npcs currently cannot initiate combat.
IF turn
= 1 THEN ' This is always the players' turn attack = rolldice%(1, 20)
' There'll eventually me modifiers based on class/race
defense = rolldice%(1, 20)
' Just d20 vs d20 now. Higher number wins.
damage = rolldice%(WeaponTable(pcinv.weapon1).dice, WeaponTable(pcinv.weapon1).sides)
curnpc.hp = curnpc.hp - damage
damage = 0
curnpc.hp = curnpc.hp - damage ' Done this way because there may evemtually be modifiers that add damage even if hit misses.
PRINT RTRIM$(curnpc.
name);
" took "; damage;
" and has "; curnpc.hp;
" left." IF pcinit
> npcinit
THEN turn
= 0 ' pcinit being higher means player went first. If it's lower, it means player is going second and doesn't need to trigger npc's turn. attack = rolldice%(1, 20)
' There'll eventually me modifiers based on class/race
defense = rolldice%(1, 20)
' Just d20 vs d20 now. Higher number wins.
damage = rolldice%(WeaponTable(pcinv.weapon1).dice, WeaponTable(pcinv.weapon1).sides) ' Uses player's weapon for now.
player.hp = player.hp - damage ' Player damage
damage = 0
player.hp = player.hp - damage ' Player damage
PRINT "You've taken "; damage;
" to your hitpoints! You now have "; player.hp;
" left." IF pcinit
< npcinit
THEN turn
= 1:
GOTO FightLoop:
' I can't figure out how to do this without using goto.
dance:
PRINT "You do that weird pointy dance people in leisure suits did in the 70s. Is this really becoming of an adventurer such as yourself?"
help:
PRINT "Game in Development. Move with standard cardinal directions. Do not, under any circmstances, attempt to dance. Quit or Exit to quit." cmderror = 1
look:
cmderror = 1
quit:
INPUT "Are you sure? (y/N) ", answer
dur
AS INTEGER ' Durability, aka basis of hitpoints
weapon1
AS INTEGER ' Corresponds to the WeaponTable entry. slot1
AS INTEGER ' Eventually there'll be a General Inventory table, not implemented yet.
sides
AS INTEGER ' number of sides of damage dice. d4, d6, etc. desc
AS STRING * 20 ' not used yet, but maybe some kind of descriptive name, such as "gleaming"
TYPE npc
' This is totally cosmetic. I'll figure out better stuff to put here later. name AS STRING * 25 ' Race name. eg, hobgoblin, kobold, dragon, etc. dur
AS INTEGER ' Durability, aka basis of hitpoints
npc
AS INTEGER ' Right now it supports 1 NPC per room. The number references the NPC Table. Will expand this in the future. weapon
AS INTEGER ' Game currently supports one weapon and one item in each room. item
AS INTEGER ' Item table not implemented yet. north
AS INTEGER ' Leads to this room number.
playergen:
' INPUT "What is your name? ", player.name
player.str = rolldice%(3, 6)
player.dur = rolldice%(3, 6)
player.hp = rolldice%(1, 10) ' Roll 1d10
PRINT "Strength: "; player.str;
" Stamina: "; player.dur;
" Hitpoints: "; player.hp
pcinv.weapon1 = 2 ' Starting weapon is a short sword.
PRINT "Press a key to start playing." _LIMIT 5 ' Don't need it eating up all the CPU.
weapongen:
' I really want this to be a Constant so it can't be modified accidentally, but that doesn't seem possible.
WeaponTable
(1).
name = "Long Sword"WeaponTable(1).sides = 8
WeaponTable(1).dice = 1
WeaponTable
(2).
name = "Short Sword"WeaponTable(2).sides = 6
WeaponTable(2).dice = 1
WeaponTable
(3).
name = "Mace"WeaponTable(3).sides = 4
WeaponTable(3).dice = 1
WeaponTable
(4).
name = "Dagger"WeaponTable(4).sides = 3
WeaponTable(4).dice = 1
WeaponTable
(5).
name = "Lance"WeaponTable(5).sides = 6
WeaponTable(5).dice = 2
npcgen: ' These numbers are all made up and are changing at some point.
NPCTable
(1).
name = "Kobold"NPCTable(1).str = rolldice%(3, 6) ' 3d6 is standard ability roll
NPCTable(1).dur = rolldice%(3, 6) ' 3d6
NPCTable(1).hp = rolldice%(1, 6) ' 1d6 for HP
NPCTable
(2).
name = "Hobgoblin"NPCTable(4).str = rolldice%(3, 6) ' 3d6 is standard ability roll
NPCTable(4).dur = rolldice%(3, 6) ' 3d6
NPCTable(4).hp = rolldice%(1, 6) ' 1d6
NPCTable(4).str = rolldice%(3, 6) ' 3d6 is standard ability roll
NPCTable(4).dur = rolldice%(3, 6) ' 3d6
NPCTable(4).hp = rolldice%(1, 6) ' 1d6
NPCTable
(4).
name = "Skeleton"NPCTable(4).str = rolldice%(3, 6) ' 3d6 is standard ability roll
NPCTable(4).dur = rolldice%(3, 6) ' 3d6
NPCTable(4).hp = rolldice%(1, 6) ' 1d6
NPCTable
(5).
name = "Gold Dragon"NPCTable(4).str = rolldice%(3, 6) + 2 ' Dragon gets 3d6 + 2
NPCTable(4).dur = rolldice%(3, 6) + 2
NPCTable(4).hp = rolldice%(4, 8) + 5 ' 4d8+5 because dragons be strong.
createnpc: ' Sets up NPCs based off NPCTable.
curnpc.
name = NPCTable
(curroom.npc
).
namecurnpc.hp = NPCTable(curroom.npc).hp
curnpc.dur = NPCTable(curroom.npc).dur
curnpc.str = NPCTable(curroom.npc).str
roomsetup:
gameworld(1).roomid = 1 ' Starting room. You always start in 1.
gameworld(1).shortd = "The start of a dungeon of fear"
gameworld(1).longd = "You see bones strewn about. This is surely the entrance to somewhere pretty horrible."
gameworld(1).south = 2
gameworld(1).west = 3
gameworld(2).roomid = 2
gameworld(2).shortd = "Another room of roominess"
gameworld(2).longd = "It's pretty scary here. You see a boogie woogie skeleton in the corner."
gameworld(2).npc = 4 ' Skeleton
gameworld(2).north = 1
gameworld(3).roomid = 3
gameworld(3).shortd = "The Armory"
gameworld(3).longd = "You stand in an old forgotten armory. Most the weapons look old and unusuable. This place hasn't been properly tended to in decades, if not centuries."
gameworld(3).weapon = 5
gameworld(3).east = 1
setroom:
curroom.roomid = gameworld(croom).roomid
curroom.shortd = gameworld(croom).shortd
curroom.longd = gameworld(croom).longd
curroom.npc = gameworld(croom).npc
curroom.weapon = gameworld(croom).weapon
curroom.item = gameworld(croom).item
curroom.north = gameworld(croom).north
curroom.south = gameworld(croom).south
curroom.east = gameworld(croom).east
curroom.west = gameworld(croom).west
IF curroom.npc
<> 0 THEN GOSUB createnpc:
' Bring the room's npc, if any, into existence. Drawback is npc respawns every time you enter room. Will fix that later. doneroom = 0
roomchange:
doneroom = 0 ' Make sure it's set to 0, which effectively means you can't exit.
IF LEFT$(phrase
, 1) = "n" AND curroom.north
<> 0 THEN croom
= curroom.north: doneroom
= 1 ' Done this way as the parser accepts either "north" or "n" to move. IF LEFT$(phrase
, 1) = "s" AND curroom.south
<> 0 THEN croom
= curroom.south: doneroom
= 1 IF LEFT$(phrase
, 1) = "e" AND curroom.east
<> 0 THEN croom
= curroom.east: doneroom
= 1 IF LEFT$(phrase
, 1) = "w" AND curroom.west
<> 0 THEN croom
= curroom.west: doneroom
= 1
pickup:
IF curroom.weapon
= 0 AND curroom.item
= 0 THEN PRINT "There is nothing here to get."
IF object
= RTRIM$(LCASE$(WeaponTable
(curroom.weapon
).
name)) THEN ' Such ugly code. make it all lower case and cut the extra spaces off so it (potentially) matches object. PRINT "You have no room for the ";
RTRIM$(WeaponTable
(curroom.weapon
).
name) pcinv.weapon1 = curroom.weapon
PRINT "You have placed the ";
RTRIM$(WeaponTable
(curroom.weapon
).
name);
" in slot 1." IF pcinv.weapon1
<> 0 AND pcinv.weapon2
= 0 THEN pcinv.weapon2 = curroom.weapon
PRINT "You have placed the ";
RTRIM$(WeaponTable
(curroom.weapon
).
name);
" in slot 2." ELSE PRINT "There is no "; object;
" here to pick up."
total
(counter
) = INT(RND * sides%
) + 1 ' total should now contain an array of all dice rolls. Now we add them up.
rolldice% = rolldice% + total(counter)
' I feel like there's probably a much better way of doing this.