Post by tsh73 on Mar 15, 2020 15:17:56 GMT -5
started off this thread
libertybasiccom.proboards.com/thread/957/contest-line-atari-basic-game
so my goals were:
A. rewrite the program making it readable and modifiable (: expandable/adaptable to other stories)
B. move logic to data, as much as possible.
So
*Instead of magic formula counting if move is valid, I have rooms table with number of the room we get by moving in N (E S W) direction
*Instead of GOSUB to subroutine with PRINTs describing thing, I have description line in the table
*Instead of arcane formula coding "you can open chest if you are in the PIT and have KEY" I made OPEN CHEST check that
1) we indeed have CHEST here
2) OPEN does work on CHEST
3) OPEN needs an object (KEY) and we indeed have it
I made OBJECT have LOCATION - and it could ROOM, other object (CONTAINER) or INVENTORY
I made OBJECT have VISIBLE attribute. So you cannot get key before you see it. And cannot see sword in closed chest.
I confess I cheated with chest - I used word "closed" in description as OBJECT STATE, and I just REPLSTR$ in with "opened"
The idea was "and so far program will be better modifiable".
I dunno if it is so - only way to prove it is to make another adventure based on it.
And code went up from 805 bytes to 11282 - but I prettied things up a bit (command aliases, descriptions, more checks)
As for checks - it (still?) pretends being wise:
It probably could mask that by saying "YOU DON'T SEE ANYTHING SPECIAL" but oh well
There is three commented flags at the top
and one special command showing OBJECTS table.
libertybasiccom.proboards.com/thread/957/contest-line-atari-basic-game
so my goals were:
A. rewrite the program making it readable and modifiable (: expandable/adaptable to other stories)
B. move logic to data, as much as possible.
So
*Instead of magic formula counting if move is valid, I have rooms table with number of the room we get by moving in N (E S W) direction
*Instead of GOSUB to subroutine with PRINTs describing thing, I have description line in the table
*Instead of arcane formula coding "you can open chest if you are in the PIT and have KEY" I made OPEN CHEST check that
1) we indeed have CHEST here
2) OPEN does work on CHEST
3) OPEN needs an object (KEY) and we indeed have it
I made OBJECT have LOCATION - and it could ROOM, other object (CONTAINER) or INVENTORY
I made OBJECT have VISIBLE attribute. So you cannot get key before you see it. And cannot see sword in closed chest.
I confess I cheated with chest - I used word "closed" in description as OBJECT STATE, and I just REPLSTR$ in with "opened"
The idea was "and so far program will be better modifiable".
I dunno if it is so - only way to prove it is to make another adventure based on it.
And code went up from 805 bytes to 11282 - but I prettied things up a bit (command aliases, descriptions, more checks)
As for checks - it (still?) pretends being wise:
You are in the room HALL
>look
You see great hall with some glitter in a walls
You see: DRAGON
You can go E S
You are in the room HALL
>look walls
YOU DON'T SEE WALLS
>look
You see great hall with some glitter in a walls
You see: DRAGON
You can go E S
You are in the room HALL
>look walls
YOU DON'T SEE WALLS
It probably could mask that by saying "YOU DON'T SEE ANYTHING SPECIAL" but oh well
There is three commented flags at the top
'hintShowExits=1
'hintShowRoomN=1
'hintShowNeedObj=1
and one special command showing OBJECTS table.
'text adventure project
'goal: recreate "10 lines adventure" in readable/modifiable form
'tsh73, March 2020
v=0.10
print " -=* Text adventure v.";using("##.##",v);" *=-"
dim room$(1,1) 'or compile barks on undefined arrays
dim obj(1,1), obj$(1,1), verb$(1,1)
'hintShowExits=1
'hintShowRoomN=1
'hintShowNeedObj=1
gosub [init]
'main loop
print "--------------------------------"
do
[nxtMove]
mov=mov+1
'print ".single step (";mov;")"
gosub [showPlace]
'get command
input ">";u$
u$=upper$(trim$(u$))
verb$=word$(u$,1): nown$=word$(u$,2)
'alias
if verb$="EXIT" or verb$="QUIT" then verb$="Q"
if verb$="TAKE" then verb$="GET"
if verb$="SEE" then verb$="LOOK"
if verb$="WALK" then verb$="GO"
if verb$="Q" then exit do
'special case: GO need direction, not object
if verb$="GO" then
if nown$<>"" then
direc=dirByName(nown$)
else
print verb$;" WHERE?"
goto [nxtMove]
end if
else
direc=dirByName(u$)
end if
if direc<>0 then gosub [processDirection]:goto [nxtMove]
'debug stuff
if verb$= "OBJ" then gosub [dbgShowObj]:goto [nxtMove]
v=0
for i= 1 to nVerbs
if verb$(i,vName)=verb$ then v=i: exit for
next
if not(v) then 'non-recognized verb
print "I DON'T KNOW HOW TO ";verb$
goto [nxtMove]
end if
if verb$(v, vObjs)<>"" and nown$="" then 'verb needs nown
print verb$;" WHAT?"
goto [nxtMove]
end if
'special case: we can ask for look on current room. It is same as simply "LOOK"
if verb$="LOOK" and nown$=room$(curRoom,rName) then nown$=""
if nown$<>"" then
gosub [findObjInARoom] 'sets found to obj
if not(found) then
print "YOU DON'T SEE ";nown$
goto [nxtMove]
end if
end if
if verb$(v, vObjs)<>"" and nown$<>"" then 'verb needs nown, nown supplied
'is this object could be processed by verb?
o=found
if findWord(verb$(v, vObjs), obj$(o,oName))=0 then
print "YOU CAN'T ";verb$;" ";nown$
goto [nxtMove]
end if
end if
if verb$(v,vNeeded)<>"" then
'do we have required object?
req=0
for o1 = 1 to nObj
if obj(o1,oLocation)=oInventory and obj$(o1,oName)=verb$(v,vNeeded) then req=1
next
end if
'verbs goes here. Most of the things is already checked??
'--------------------------------------------------------
select case verb$
case "INVENTORY"
print "You are carrying:"
found=0
for o = 1 to nObj
if obj(o,oLocation)=oInventory then print obj$(o,oName): found=o
next
if not(found) then print "NOTHING"
case "GET" 'get object. object is in found, object could be taken
o=found
obj(o,oLocation)=oInventory
print "YOU TOOK ";obj$(o,oName)
case "OPEN" 'open chest. chest is in found
o=found
if instr(upper$(obj$(o,oDescr)), "CLOSED")=0 then
print obj$(o,oName);" IS ALREADY OPENED"
goto [nxtMove]
end if
'do we have required object?
if not(req) then
if hintShowNeedObj then
print "YOU CAN'T ";verb$;" WITHOUT ";verb$(v,vNeeded)
else
print "YOU NEED SOMETHING TO DO THAT"
end if
else
'open that thing
obj$(o,oDescr)=repl.str$(obj$(o,oDescr), "closed", "opened")
print "OPENED"
end if
case "KILL" 'kill dragon. dragon is in found
o=found
'if we have required object?
req=0
for o1 = 1 to nObj
if obj(o1,oLocation)=oInventory and obj$(o1,oName)=verb$(v,vNeeded) then req=1
next
if not(req) then
if hintShowNeedObj then
print "YOU CAN'T ";verb$;" WITHOUT ";verb$(v,vNeeded)
else
print "YOU NEED SOMETHING TO DO THAT"
end if
print "DRAGON KILLS YOU"
print "YOU LOOSE"
done=1
else
'kill that thing
print "YOU KILL ";obj$(o,oName);" WITH ";verb$(v,vNeeded)
print "YOU WON"
done=1
end if
case "LOOK"
if nown$="" then 'plain LOOK
print room$(curRoom, rDescr)
seenSmth=0
for o = 1 to nObj
'print o, obj$(o,oName), obj(o,oLocation), obj(o,oVisible)
if obj(o,oLocation)=curRoom and obj(o,oVisible)=1 then
if not(seenSmth) then print "You see: ";
print obj$(o,oName)
seenSmth=1
end if
next
gosub [showExits]
else 'LOOK nown$, nown$ is in found
o=found
print obj$(o,oDescr)
if obj(o,oContainer) and _ 'not closed
instr(upper$(obj$(o,oDescr)), "CLOSED")=0 then 'see if something in it
seenSmth=0
for o1 = 1 to nObj
if not(seenSmth) then print "You see: ";
if obj(o1,oLocation)=o+oBase then obj(o1,oVisible)=1 :print obj$(o1,oName)
seenSmth=1
next
end if
end if
case else
print "ERR: You should NOT get here and see this"
end select
loop until done
'final message
print "--------------------------------"
print " * the quest is over * "
print " * in ";mov;" moves * "
end
[init]
'print ".Init"
gosub [readStuff]
gosub [setupStuff]
return
[readStuff]
'print "..readStuff"
gosub [roomData]
gosub [objData]
gosub [verbData]
return
[objData]
'let obects contain other objects. So obj has a field location, it could be room or other obj
'to distinguish, obj starts from 1000 (1000 rooms in big enough?)
'let's also make our Inventory a location number 1000000
'not sure I need container, But may need state (closed open) - ??
nObj=5
'number, name, location, isVisible, isContaner, descr
'actually "closed" is used word - do not remove
data 1001, "CHEST", 2, 1, 1, "It is old wooden chest. Looks pretty solid. It is closed"
data 1002, "DRAGON", 3, 1, 0, "The dragon is sleeping. I'd rather not disturb him withot reason."
data 1003, "CORPSE", 4, 1, 1, "It is a dead men lying. Looks like unfortunate adventurer"
data 1004, "KEY", 1003, 0, 0, "It is big rusty key. It sure might get handy?"
data 1005, "SWORD", 1001, 0, 0, "Ancient sword. Looks a bit glowing in a cave. Should be magic"
dim obj$(nObj,2), obj(nObj,3)
oLocation=1:oVisible=2:oContainer=3
oName=1:oDescr=2
oBase=1000
oInventory=1000000
RESTORE [objData]
for i =1 to nObj
read n
read tmp$:obj$(n-oBase,oName)=tmp$
read tmp:obj(n-oBase,oLocation)=tmp
read tmp:obj(n-oBase,oVisible)=tmp
read tmp:obj(n-oBase,oContainer)=tmp
read tmp$:obj$(n-oBase,oDescr)=tmp$
next
'gosub [dbgShowObj]
return
[dbgShowObj]
print "N","name","location","isVisible","isContainer","descr"
for i =1 to nObj
print i+oBase,obj$(i,oName),obj(i,oLocation),obj(i,oVisible),obj(i,oContainer),obj$(i,oDescr)
next
[roomData]
'number, room, number of rooms to N, E, S, W [up and down if desired], descr
nRooms=4
data 1, "CAVE",3,0,0,0,"This is the cave entrance. The deeper your go the darker it gets"
data 2, "PIT", 4,0,0,3,"It is very dark. You barely see a thing"
data 3, "HALL",0,2,1,0,"You see great hall with some glitter in a walls"
data 4, "LAKE",0,0,2,0,"There is a lake with dark waters"
dim room$(nRooms,2), mase(nRooms,4)
rName=1:rDescr=2
toN=1:toE=2:toS=3:toW=4
RESTORE [roomData]
for i = 1 to nRooms
read n
read tmp$: room$(n, rName)=tmp$
read tmp: mase(n, toN)=tmp
read tmp: mase(n, toE)=tmp
read tmp: mase(n, toS)=tmp
read tmp: mase(n, toW)=tmp
read tmp$: room$(n, rDescr)=tmp$
next
' for i = 1 to nRooms
' print i, room$(i, rName), mase(i, toN); mase(i, toE);mase(i, toS); mase(i, toW),room$(i, rDescr)
' next
return
[verbData]
'verb, obj(s); all if empty, needed in inventory
nVerbs=5
DATA "LOOK", "", ""
DATA "OPEN", "CHEST", "KEY"
DATA "KILL", "DRAGON", "SWORD"
DATA "GET", "KEY SWORD", ""
DATA "INVENTORY", "", ""
dim verb$(nVerbs,3)
vName=1:vObjs=2:vNeeded=3
restore [verbData]
for i =1 to nVerbs
read tmp$: verb$(i, vName)=tmp$
read tmp$: verb$(i, vObjs)=tmp$
read tmp$: verb$(i, vNeeded)=tmp$
next
'for i =1 to nVerbs
' print verb$(i, vName), verb$(i, vObjs),verb$(i, vNeeded)
'next
return
[setupStuff]
'print "..setupStuff"
mov=0
curRoom=1
return
[showPlace]
'print "..showPlace"
print "You are in the room ";
if hintShowRoomN then print "(";curRoom;") ";
print room$(curRoom, rName)
'show exits
if hintShowExits then gosub [showExits]
return
[showExits]
print "You can go ";
for d =toN to toW
if mase(curRoom, d) then print mid$("NESW", d, 1);" ";
next
print
return
[processDirection] 'in: u$, UPPERcase
'print "..processDirection"
'print direc
if mase(curRoom, direc) then
print "YOU WALK"
curRoom=mase(curRoom, direc)
else
print "CANNOT GO"
end if
return
[findObjInARoom] 'sets found to num obj by name nown$
'find obj
found=0
'but what about objects in objects in the room (ie chest)?
for o = 1 to nObj
if (obj(o, oLocation)=curRoom and obj(o,oVisible)=1) _
or obj(o, oLocation)=oInventory then
if nown$= obj$(o,oName) then found=o: exit for
'else look subobjects
if obj(o,oContainer) then 'see if something in it
for o1 = 1 to nObj
if obj(o1, oLocation)=o+oBase and obj(o1,oVisible)=1 _
and nown$= obj$(o1,oName) then found=o1: exit for
next
end if
end if
next
return
function dirByName(u$)
'[add up and down if desired]
if len(u$)=1 then
dirByName=instr("NESW", u$)
else
dirByName=findWord("NORTH EAST SOUTH WEST", u$)
end if
end function
function findWord(list$, w$)
if w$="" then exit function
do
i=i+1
ww$=word$(list$, i)
if ww$=w$ then findWord=i: exit function
loop until ww$=""
findWord=0
end function
function repl.str$(source$, old$, new$) 'LB 4.5 func for JB, by R Russel
'renamed to repl.str$ as to not conflict in LB 4.51
do
i = instr(source$, old$, i+1)
if i then
source$ = left$(source$,i-1);new$;mid$(source$,i+len(old$))
i = i + len(new$) - 1
end if
loop until i = 0
repl.str$ = source$
end function