Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Newcomers DBPro Corner / Create Zork - Tutorial Part I

Author
Message
pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 31st Oct 2008 03:04 Edited at: 31st Oct 2008 04:52
Quote: "The problem I'm having now is that if you are in the living room and 'go down' you are in the celler without having to move the rug or open the trapdoor."


To fix that, what we need to do is prevent the player from moving down at that location until we have checked the trapdoor to see if it is open.

So, starting out, let's set the Living Room's 'down' number to 0. The zero tells the program not to allow any movement down from the current location (living room).

So, you're data statement should look something like this:

data "Living Room", 0,0,5,-3,0,0

I know you have added 4 other directions, so your data statement will be a bit longer but just change that 'down' position to a 0 to prevent the player from moving down. In the data statement above, the 'down' is the last 0 at the end.

Now, as soon as the player 'opens' the trapdoor, we change the living room's 'down' from a 0 to the number of the new location.

For instance, moving down leads to the 'celler'. Let's say the 'celler' is location number 8. When the player enters the command to 'open trapdoor', we then change the living room down number to an 8, like this:

LOC_ARRAY(6).DOWN = 8

What this means is:

Moving down from location 6 (living room) puts the player at location 8 (celler).

Now, when the player tries to move down, the program will check the living room's 'down' number and will find an 8 instead of a 0, and will automatically put the player at location 8.

How do we check the trapdoor?

First we have to know what the object number of the trapdoor is. Let's say the trapdoor is object number 5. All we have to do is make an IF statement that says, If Object5 is open then Living Room 'down' equals 8.

The code should be placed right inside of the OPEN_OBJ: routine. So find that routine in the code and place your IF statement there, like this:

REM OPEN_OBJ
OPEN_OBJ:

REM -IF OBJECT IS TRAPDOOR THE PLAYER JUST OPENED THEN MAKE
REM -LIVING ROOM 'DOWN' EQUAL TO 8 (CELLER)

IF OBJECT1 = 5
LOC_ARRAY(6).DOWN = 8
ENDIF


This is how you should handle those situations. Check to see if the status of an object has changed, such as the trapdoor or the rug has moved, or the loose panel and so on. If it has, then change the appropriate variable. In the case of the trapdoor we had to change the living room's 'down' variable to allow downward movement.

In some cases the object may not have any variable that is related to what you need to do. That's ok. We simply make a new variable for the object! Any variable that is related to an object, we call it an attribute. So we simply add another attribute to it. Try doing this for the loose panel and let's see how you do.

About the bug/error. If it is still causing you trouble I can take a look at it. You can post the code here or email it to me, either way is fine. Don't get discouraged, I have those days too. Sometimes the solution is right in front of me but I don't see it for some reason. It happens to the best of us. Keep up the good work. At this rate you might have the original Zork game in DBPro by the time your done!
pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 1st Nov 2008 04:26 Edited at: 1st Nov 2008 17:27
Fangs,

The solution to the 'trapdoor/going down' that I presented above is so common in Zork and other games, it is actually what makes the game come 'alive' as it were. Well, I'd like to show you a better way to manage this.

In a text adventure like Zork, the player does things which 'triggers' or sets off a flag. For example, if the player presses a button, a secret compartment is revealed, or the player pulls a lever and an iron gate three rooms away opens up. Anytime the player does something, that changes the gameworld, we call it a trigger. The player has 'triggered' an action and some part of the game world has changed as a result.

These triggers make the game work.

As it turns out, there is a very easy and simple way to deal with all triggers!

Place all of them together, and everytime the player enters a command, no matter what the command is, the program will look at every trigger in the game. If the player's command has activated a trigger then make the appropriate change in the game world. Make that change on the spot.

In fact this is the easiest way to constantly update the gameworld.
The nice thing about it is you don't have to place different triggers in different places throughout the program. Instead, they are all in one place and easy to manage.

Right now, the basic logic in the program looks like this:


Begin Game Loop

Get Command from Player

Process the Command

Display Results

Goto Beginning of Game Loop



All we have to do is add triggers to that logic. I like to call it 'Update Game World'

So, if we add that new logic it looks like this:


Begin Game Loop

Get Command from Player

Process the Command

Display Results

Update Game World

Goto Beginning of Game Loop



Now, let's use the 'trapdoor/down' trigger that we coded earlier and place that code in the 'Update Game World'. The code for that trigger was:

IF OBJ_ARRAY(5).OPEN = 2
LOC_ARRAY(6).DOWN = 8
ELSE
LOC_ARRAY(6).DOWN = 0
ENDIF


Now, the game logic looks like this:

Begin Game Loop

Get Command from Player

Process the Command

Display Results

Update Game World
If trapdoor is open then room.down = TRUE Else room.down = FALSE

Goto Beginning of Game Loop



So, everytime the game loops, it is constantly checking that trigger. It is always checking that trapdoor to see if it is open, and if so it changes the room.down to true, otherwise it sets room.down to false. You don't have to worry about checking it when the player first opens the trapdoor because it is automatically checked every single turn!

Also, it doesn't matter where the player is or what the player is doing, the trigger is checked every single time a command is entered. ALL triggers are checked like this, and that is how you update the game world. It makes it easy. You don't have to worry about what the player is doing, you just check the status of all triggers no matter what.

Here is the 'Update Game World' code with one the 'trapdoor/down' trigger:



Every trigger can go here one below another. It's just that simple!

Add that routine on to the end of the program or any free spot you prefer, doesn't matter.

You must call that routine from the inside of the main game loop, right before the 'sync' command, add this line:

GOSUB UPDATE_GAMEWORLD

I've added it to the main loop in the program as a reference:

pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 1st Nov 2008 17:31 Edited at: 1st Nov 2008 17:32
IMPORTANT UPDATE

This line of code was not correct in the previous posting:

IF OBJECT1 = 5

It Should be:

IF OBJ_ARRAY(5).OPEN = 2

I went back and changed it to the correct line. Your 'UPDATE_GAMEWORLD' Routine should look like this:

Fangs
14
Years of Service
User Offline
Joined: 24th Oct 2008
Location: 40 some miles North of the Emerald Coast
Posted: 1st Nov 2008 18:37
Hi Pluto

I think I'm about a half step in front of you. In those places where there is a lot going on (The Livingroom) the room description needs to be updated to reflect any new action taking place in the room.

[b]IF PLR_LOC = 6 ' In the livingroom
PRINT "You are in the living room. There is a doorway to the East, a wooden door with"
PRINT "strange gothic lettering to the west, which appears to be nailed shut, and a "
PRINT "trophy case standing against the North wall. " ;

' Move the rug to expose the trapdoor to the celler
IF OBJ_ARRAY(17).LOCATION <> PLR_LOC AND rugflag = 1
PRINT " There is a trapdoor in the floor."
else
if rugflag = 2
print "The trapdoor in the floor is open revealing "
print "steps going down.";
endif
endif

' Add open changed trophy case condition to the room description
if caseflag = 1
print "The trophy case is open."
else
print "The trophy case is closed."
endif
ENDIF[b]

I don't see any reason why the direction codes wouldn't work here also.

so far all of my code works although there are places that need work.

later!

The Fangman
pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 1st Nov 2008 19:33
Excellent work Fangs!

Looks like you are on top of it.

This brings me to talk about the different methods of coding the game. I noticed you used a flag for the rug. That is a method that actually works fine and I also use that method as well, nothing wrong with it at all.

The trigger method is an alternative to using flags, it's just another way to do the same thing. I like the trigger method because I can keep most of the stuff in one code block and it's easier for me to manage. Yet, either way is ok, as long as it does the job! I just wanted you to know about the other methods so that way you can have another tool at your disposal.

I have added the 'MOVE' command to the latest build of the zork engine. I coded a trigger management system that monitors the rug, the kitchen window and the trapdoor. The system is simply a small subroutine that I put right after the main gameloop. You are welcome to take a look at it and take whatever you want from it. It's completely up to you. Anyway, you are doing great as it is!

pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 1st Nov 2008 21:15 Edited at: 1st Nov 2008 21:29
Before creating a flag variable, you may find that you already have a variable for what you are trying to do.

For example, you made a caseflag variable when the case is open or closed, for the location description.

The nice thing is, you already have an attribute variable for that:

OBJ_ARRAY(OBJECT).OPEN

So that:

IF OBJ_ARRAY(OBJECT#).OPEN = 2
print "The trophy case is open."
else
print "The trophy case is closed."
endif
ENDIF


Usually you can just check the object's attribute variable, and also you can change the object's attribute variable at anytime. So, if you coded:

OBJ_ARRAY(OBJECT#).OPEN = 1

Now the trapdoor is closed.

For the rug, I made a new attribute called 'MOVE'. If OBJ_ARRAY(OBJECT#).MOVE = 2 then I know the rug has been moved.

Basically, that's all the UPDATE_GAMEWORLD subroutine does. When the player enters a new command his actions may have changed an object in some way. All I do is scan every object and if I find a change in it's attribute variable then I change the gameworld. As an example:

The player opens the kitchen window.

I scan the objects in the UPDATE_GAMEWORLD subroutine and find that the kitchen window is open, [b]OBJ_ARRAY(OBJECT#).OPEN = 2


The player should be able to go east now because the window is open. So, I set the location attribute of the kitchen to allow eastward movement/b]

LOC_ARRAY(5).EAST = 3

From Room5 (kitchen) the player can now go to room3 (east of house)

The code would look like this:



That code statement scans the kitchen window object after every single turn and changes the movement attribute accordingly. It doesn't matter if the player is even in the kitchen. The window is scanned every turn to see if is open or closed, and makes any changes on the fly.

And that's all there is to it. Look at the objects, if an attribute has changed then make any needed change to the gameworld.

Of course, the location descriptions need to be updated too, and I see you have been able to figure that out pretty well. I usually do them a little later after I have some of the other parts in place, but I can see you are on the right track there, good work!
Fangs
14
Years of Service
User Offline
Joined: 24th Oct 2008
Location: 40 some miles North of the Emerald Coast
Posted: 2nd Nov 2008 00:50
Hey Pluto;

You've been busy today! I had to get away from it for a while. My attention span sometimes shrinks to an unusable state.

I had thought about having a 'move' routine, but hadn't got to it. Moving the 'rug' and moving the 'loose panel' is a lot better than taking and opening.

The other routine I've been wanting to get at is 'read' so that the 'leaflet', 'note' on the iron door blocking access to Zork II, and the 'sign' I placed in the meadow.

My code is out to somewhere around 1400 lines now and it's only going to get bigger. I have to careful not to let the thing overwhelm me.

Any way...Thank you for the kind words!

Onward and upward!

The Fangman
pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 2nd Nov 2008 04:54 Edited at: 2nd Nov 2008 05:01
I know what you mean, it's a lot of code!

It helps me to remember that the code is broken down into subroutines each performing it's own task. Think of it as modular and it gets a bit easier to deal with.

Yes, the read command needs to be added. Every new command that is added is usually about an object. For instance, the TAKE command is about taking objects.

So, anytime I make a new command I always addon a new attribute to the object list. Just like we have the Object.Location, we can add an Object.Read. Whatever Object.Read is equal to, it's the number of the text message, i.e. whatever is written on the leaflet or book, or any object that can be read.

So, the idea is this:

If Object1.Read = 0 then Object Cannot be Read

If Object1.Read = 1 then Print Text Message 1

If Object1.Read = 2 then Print Text Message 2


Actually, the READ command is one of the easiest to do. I always enjoy doing that because I can type in all the text stuff and get a break from some of the more difficult coding.

Anyway, that's how I normally approach it, but as always it's not the only way to do it, so feel free to work it out in a style that you're comfortable with. That's the most important thing.

They say the sky is the limit, but really the only limit is your imagination!
Fangs
14
Years of Service
User Offline
Joined: 24th Oct 2008
Location: 40 some miles North of the Emerald Coast
Posted: 2nd Nov 2008 15:16
Hi Pluto

I implemented your move routine and while setting the 'move' code up, I thought that while was there I might as well set it up for a 'read' cmd also.

I used your 'cmd_move' routine framework for my 'cmd_read' routine. Since I only have one readable at the moment and it is in PLR_LOC 1, it was easy to test.

If you try to read leaflet before taking it from the mailbox you get 'You don't have leaflet' message.

And, what does the leaflet say, you ask! "Written in a strange cursive script, the leaflet says BEWARE OF THE WUMPUS!"

As you said in your last post, the read routine was easy.



The Fangman
pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 2nd Nov 2008 23:12 Edited at: 2nd Nov 2008 23:14
Looks like you are getting a good feel for how different parts of the program work. You are making very good progress!

So, has the WUMPUS come to the land of Zork? Even the GRUES must beware! That’s an interesting idea to have the WUMPUS lurking around in the great underground empire.

I wanted to mention another command that is similar to the READ command and generally simple to plug into the program. It’s the EXAMINE command, and it works in much the same way. Usually whenever the player examines an object, a related message that describes the object or the status of the object is displayed. For example, the command and message may look something like this:

'Examine Knife'

‘The knife has strange markings engraved on its blade.’


If the knife is magical and glows when there is a WUMPUS nearby…

‘The knife has strange markings engraved on its blade and is glowing red.’

Some messages should inform the player of the status of an object…

‘The lamp is turned on.’

Perhaps the object is ordinary…

‘There is nothing special about the key.’

Something about the object may be useful in solving part of the game…

‘This ring is the official ring of the wizard’s clan, and the one wearing this ring will be allowed entrance.’

Always remember to make your messages and descriptions interesting. Even if the message is not particularly useful it can still be just as important. A good description gets the player’s attention and draws him into the story like nothing else can. What is more interesting, this:

‘There is nothing special about the staff’

Or this…

‘The ancient staff was hewn from wood of the Hagmarsh forest many ages ago. Possessed by dark powers from its old master, this cursed and twisted artifact is no mere walking stick. All knowledge of how to use it has faded and lost from history.’

A good description of the objects and the locations make the game come alive and the player becomes a part of the story.
Fangs
14
Years of Service
User Offline
Joined: 24th Oct 2008
Location: 40 some miles North of the Emerald Coast
Posted: 3rd Nov 2008 02:56
Hey Pluto;

Actually, the Wumpus thing came to mind when I needed text to test my read routine, and recalling your mention of the 'Hunt The Wumpus' game.

Today has been a pretty good one. Everything works, but by no means complete. I've got a to do list a mile long. There a lot of details to fill out to finish the 'move' and 'read' commands. And yes, I was thinking about the need for 'Examine' too.

I put in a couple of traps: Go down the trapdoor without the lamp and you fall and break your neck...End of game! The other is going through the panel in the trophy case without the lamp and you get 'hopelessly lost'...End of game. Since the living room is the only 'room' to have any detail put into it, you can see the potential for the other 24 (or more?) rooms.

Of course, this brings up another 'nongame' aspect to the program. A menu with a starting static Game graphic and the usual 'new game', 'save game', 'load game', and 'quit' options. Right now, my two game ending events; for the neck breaker I put in a 'wait key, 'cls', and an 'end'. For the 'lost' I didn't have to do anything...I blocked the two moveable directions.

There was a time a very long time ago, when I first started with my Atari 800 which I played Zork I on, I was going to write the consumate computer text based game in a week-end...Yeah, right!

Be assured, my friend, I could never have got this far without your Zork Engine and help.

The Fangman
pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 4th Nov 2008 03:04 Edited at: 4th Nov 2008 03:35
I think you'll continue to have more good days like this because you have a stronger understanding of the program now. All the work you are doing is paying off in a big way. Your knowledge has continued to grow and you will find it easier by the day to make your game.

I see you have put in a couple of nifty traps! Of course there is a lot of potential for the other rooms. Keep in mind that not all locations need to be as complicated as the house. It's good to make some areas mostly empty, like the woods, hallways, passages, and other locations. It helps to balance the game and it makes your job a little easier because you don't have to spend a lot of time on every location.

A menu system with a starting graphic would be a nice touch. I even thought about putting in some atmospheric music for different parts of the game.

I remember the Atari days, my friend had one. I had a c64. I'll never forget the first game I wrote was called Fantastic Voyage like the movie. I thought I could do it all in a weekend and it ended up taking me two weeks, for a very, very simple text game to say the least.

My first attempt at making a Zork-type game was rough. I was able to make a two-word command parser but I had trouble making the inventory and programming the objects. It was funny because the player could pick up an object that was not there. Objects would remain in the players inventory even after he dropped them and some objects would duplicate. Container objects were a nightmare to figure out. Once I learned how to code the objects I then spent my time working on the parser. It took me several years before I figured out how to make a complete Zork game!

I'm glad to help out. Programming a game like this is fun but can be a challenge even for experienced programmers. Sooner or later it starts to get easy and just like anything else, once you realize how to go about it, then there really is nothing to it.

You may already know this, but there is a Darkbasic Text Adventure Contest held every year with prizes.

http://forum.thegamecreators.com/?m=forum_view&t=80522&b=19
Fangs
14
Years of Service
User Offline
Joined: 24th Oct 2008
Location: 40 some miles North of the Emerald Coast
Posted: 4th Nov 2008 22:27
Hi Pluto

I didn't post anything yesterday. It was one of those "make 20, stumble and lose 50" things.

I do have 'move' (yours), 'read', 'use', 'examine', and 'attack' routines in and working. So far I've only tested read, examine, and attack on one item each.

The 'use' routine will turn the lamp on the first time it is called
and turn the lamp off the second time it is called. For the sword, the first 'use' puts the sword in your hand, while the second 'use' puts the sword away. And, of course, you can't attack without using the sword first.

For the 'attack' routine, I put a huge rat in the cellar. When you attack, you have a 10% chance of being killed and eaten, a 40% chance of missing your target, and a 50% chance of hitting it. If you win the fight and do a look you get the room description with "there is a dead rat here" instead of "there is a huge rat here.

The 'combat' routine I used here was very basic and simple. I can definately see a combat subroutine where all sorts of parameters could be brought into focus. I might think more about that further down the line.

In fact, most all of what I've done is very basic. You have crawl before you can learn to walk, and I am learning a whole lot of neat stuff. If I didn't have your parse routine I would really be in a trick

I don't know if I'm ready for the Darkbasic Text Adventure Contest yet. Maybe next year.

Later!

The Fangman
pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 5th Nov 2008 05:15 Edited at: 5th Nov 2008 05:23
That's some pretty cool stuff your putting in the game. It's fun to place the monsters, creatures and other beasties into different locations. You can even sprinkle a few NPCs here and there.

In Zork, the combat was mostly simple. They really focused more on the puzzles in the game. It would be neat to make a game that had great storytelling, great puzzles that made sense and are part of the story, and a more sophisticated combat system. Even a player leveling system like D&D could be worked out.

It is true, you do have to crawl before you walk. I think everyone has to go through that process. It will take time but you will have fun along the way. I am actually looking forward to playing your game when its finished or when you have a demo.

I wouldn't worry about getting that sophisticated right now. Anyway, I think there has never been a text game produced that had all of that stuff in one game! I have thought about making it myself, the granddaddy of all text adventures! The programming for me is not hard, coming up with the story and the game design is more of a challenge for me.
Fangs
14
Years of Service
User Offline
Joined: 24th Oct 2008
Location: 40 some miles North of the Emerald Coast
Posted: 5th Nov 2008 23:33
Hi Pluto;

Do I hear 'collaboration' talk?

You've got the nuts and bolts and I have the imagination and writing skills. I've never done any software design work, but from what I've read, I think I could handle it.

Anyway, back to work!

I haven't done anything with the game today, but I have a menu up and running. The trouble is, I don't know how to tie it into the game. The following is what I think I need:

1. Some way to access the menu from the game (to savegame, start newgame, or quit).

2. Some way to gather the 'game state' to write to a save file (savegame).

3. Some way to start the game with a saved 'game state' (loadgame).

4.(Now that I think about it) A way to return to a game in progress (returntogame--NOT implemented yet).

This seems like a lot of work, but it's all part of the game. I will email you a copy of the executable, and the source code once I get it cleaned up (I used it to set up and do read and write data to the disk, and haven't cleaned out all of the trash yet).

The Fangman
pluto
14
Years of Service
User Offline
Joined: 18th May 2008
Location:
Posted: 6th Nov 2008 04:04 Edited at: 6th Nov 2008 04:54
This could be really worthwhile to collaborate on a game if your willing. We'll need to come up with a setting such as sci-fi, fantasy, mystery, etc... Then we'll need a plot, sort of a background story for the game. Finally, the game design, locations, puzzles, and traps.

If you can work most of the game design then I can do the more difficult programming. We can both contribute to the story and plot. I can also help with the design when needed, and of course we'll both share our ideas.

If we are successful, we could even create a website for the game. It would be cool to see it take off. Perhaps even make a series out of the game, if it does well.

Imagine adding some eerie music for different locations and sound effects like a creaking door when opening a gate or trapdoor. Add in a nice graphics at the start of the game. With a great story line, setting and a sophisticated parser, this game could really rock.

So if your up for it, I'm willing to give it a shot.

About the game menu items, the easiest way to handle the save game is to gather all game variables and write them to disk in the game directory. To make it interesting, you could allow saves only at certain locations or with limited number of save slots. The load game reads all game variables from the disk at somewhere near the beginning of the main game loop. Darkbasic has very nice file writing commands that make it fairly easy task. You can do the commands in a menu system or you make them a natural part of the game as in zork, where the player actually types in 'Load Game'.

I know it does seem like a lot of work, but each time around becomes less of a job. I'll keep an eye out for your code in the email.

Login to post a reply

Server time is: 2023-02-08 08:05:26
Your offset time is: 2023-02-08 08:05:26