DRAGON MASHER SHELL What is it all about? Well like many Amiga users I was enthralled with Dragon Master and I thought it would be fun to write my own version. My initial endeavour using compiled Basic was scrapped when that excellent program AMOS appeared. The final masterpiece is still being completed but I thought it a good idea to make the operating shell available in the PD. What the shell does... In essence the shell carries out the basic processes in the game. The core of the shell is the logic which converts a map in the form of several arrays into a picture. The graphics are held in four IFF files (made using DPaint III) and are converted into blocks held in memory. The logic "looks" ahead of the player and draws a 3D view working from the back. The logic is quite simple but a lot of picture blocks are needed to allow for all the possible views. Even so, I have had to leave out some less important views simply to conserve space - you shouldn't notice the difference, however. The core uses a continuous loop to first scan for a move and then act accordingly. In simple terms, the logic is: SCAN FOR KEY PRESS OR-------- MOUSE PRESS | | | | | IF MOVE ACT | | | DRAW VIEW | |----------- The effects of teleports, walking into walls, going down stairs or pressing switches are built into this simple loop. ___________________________________________________________________________ Memory Management..... Regrettably the use of AMOS is limited if you have no memory expansion. You must therefore have at least 1 Meg to use DMS. Furthermore, because I haven't sorted out how AMOS handles memory, I've been quite miserly on the parts which probably need chip memory. 1. The graphics for nasties are limited to four (2 static and two animated) loaded only as required. This offers the possibility of a huge number of nasties but limits what can be displayed. More on this later. 2. I have included about 60k of sound samples (15 in all). You can dump these but you will have to weed out all "Sam Play" calls. __________________________________________________________________________ So lets get stuck into the listing There is an awful lot of rubbish spoutefd forth about structured programmimg - mostly from BBC owners. I`m afraid I`m not the worlds finest exponent of structured programming and I`m not afraid of GOTOs, so be warned. If you think about it, the best alternative to GOTO is a GOSUB followed by a test of a flag. Very messy! Whilst AMOS offers most structures its implementation of theIF....THEN....ELSE is eccentric to say the least. I have used multiline IF structures but thats about all. I`ve used a fair few Procedures so that they can be folded and locked. ___________________________________________________________________________ First some system variables are defined: NOPRIMS defines the number of graphics blocks. XM and YM keep track of your position in the maze on any given level. COMP holds the compass heading: COMP = 1 for north COMP = 2 for east COMP = 3 for south COMP = 4 for west XEND and YEND define the maze width and height respectively LV is the level you are currently on. CURRCOL specifies the display colour: NON holds the number of nasties and CURRNASTY gives the number of the current nasty pictures in memory. CURRCOL = 1 for grey CURRCOL = 2 for red CURRCOL = 3 for blue CURRCOL = 4 for green NOOBS is the number of objects in the game. Two screens are opened initially. The procedure BLOCKS loads the four IFF pictures into screen 1 and extracts 92 graphics blocks. To save space screen 1 is then closed and reopened at half its original size. The front display is then loaded. The next portion loads the data arrays. First the coordinates of the graphics blocks are read. These decide where the components of the display are drawn. The next four arrays define the map. These have three dimensions. The first relates to the level. The second relates to the Y coordinate and the third the X coordinate. I've done things this way because by having all levels in the machine at once you can have a switch on one level change something on another level. Nasty eh? It also allows movement between levels to be almost instantaneous. If memory is tight or you prefer a different approach, the disk also carries a version with two dimensional arrays so that only one level is held at a time....the choice is yours. Firstly, MAP() sets out the basic layout. The values currently supported are: 0 = passage 1 = wall 2 = stairs up 4 = stairs down 6 = wooden door 8 = portcullis 10 = hole in the ground 11 = secret passage 12 = larva pool 14 = water pool 16 = acid pool 18 = teleport The second array, OMAP(), locates objects and other bits and pieces. The first few values relate to switches: 1 = push button, un depressed 2,3 = key holes 5 = toggle switch up 6 = toggle switch down 7 = blue button 8 = green button 9 = key hole 10 = blue button in 11 = green button in 12 = number pad Values from 20 onwards refer to objects. The final array, SMAP(), specifies where switches are. Any cell holding a switch has four possible walls and you must know where the switch is. The values in the array define this: North wall = 2 East wall = 4 South Wall = 8 West wall = 16 Each direction uses a bit allowing multiple switches. So if you want switches on the north and west walls, you use a value of 2 + 16, or 18. Each time you move LOOKN, LOOKE, LOOKS and LOOKW scan the squares ahead. The last array, NMAP() holds details of the nasties in the maze. A zero value means no nasty, a value signifies the type of nasty, ___________________________________________________________________________ Looking around ....... The values for the squares are taken from map() are put into array A(). The squares are stored in the following elements: 12 9 10 11 13 6 7 8 3 4 5 1 * 2 A(4), for example shows the square immediately ahead and A(1) shows the square to the left. A(12 and A(13) are used to draw extreme left and right hand walls. PDRAW uses this array to draw your forward view. The drawing procedure is quite simple. A call is made to LOOK. This procedure zeroes arrays A() and N(). Depending on the direction faced, the A() array is filled. A call is then made to NCHECK to check the status of nasties. The procedure NCHECK makes a similar check for adjacent nasties. N() holds the contents of the adjoining elements of NMAP(): 3 2 10 1 4 9 * 5 8 7 6 N(1), N(2) and N(3) are used by PDRAW to show what is ahead. The others are available for checking in NATTACK to decide whether some attacks from behind or the sides. This is not built into the shell at present. That is for you to decide. If N(1) is different to Currnasty then the bobs for the new nasty are loaded. GENPIC is now called. This procedure sets up the hidden screen and then calles PDRAW. PDRAW creates the image on the hidden screen. First the walls are set up followed by traps, doors, teleports and distant nasties. Procedure BLIT is then called to transfer the hidden picture to the front screen. GENPIC finally draws the nasty if it is near to you. -------------------------------------------------------------------------- Mapping it.... To to bottom left of the screen is a vertical view or map of the area ahead and to the side. This is drawn by procedure STATS and reflects the information in A(). The shell calls STATS every move. There is no reason why this routine should be suppressed until a cartography spell or map are found. STATS makes heavy use of procedure GB[]. This procedure converts the values in A() into graphics primitives. Like PDRAW, STATS uses the hidden screen to double buffer the map display. --------------------------------------------------------------------------- Text....... There is a text window on the screen which is called by MESSAGE[O$]. O$ holds the text to be output. The procedure uses Garnet 9 point font so you must ensure that the following files are in the fonts directory of your boot disk: 1. A drawer named Garnet holding the 9 point file 2. The Garnet.font file. You can copy these off the distribution disk. --------------------------------------------------------------------------- Nasties....... As mentioned earlier, four patterns are used for each nasty. The IFF file "nasties" contains four example nasties. The programs "bobgen" convert the images to bobs and save them as individual bob files for each nasty. The current nasty is held in currnasty. When a nasty is encountered, the value of currnasty is checked. If the new nasty has a different value then the value of currnasty is updated and the bob file for the new nasty is loaded. This minimises the memory use but only allows one nasty in view at once. Furthermore, only the view ahead is given, not peripheral views. Bobs 1 and 2 are used to give the distant views. Bobs 3 and 4 give the animated view of the nasty attacking from the adjacent square to you. The coordinates of the nasty on the display are given by the values in the arrays NX() and NY(). You will have to work these out as you design your own nasties. There is to reason, of course, why you shouldn't set up your own system for displaying nasties. --------------------------------------------------------------------------- Loads of data....... You will notice loads of data statements at the back end of the program. The set following the label COORDS define the position of the graphics and are used by procedure PLACE[]. Each pair of coordinates relate to a block - The first pair for block 1, the next pair for block 2 and so on. PLACE[] is a short alternative to huge amounts of Put Block instructions. The next blocks relate to the maze data. The data statements starting at W1COORDS decide the position of the object at the place where you stand in the right hand window. The last lot decide the position of the nasties. One pair for each of the four nasty bobs. ___________________________________________________________________________ Sound samples....... A file called samples.abk is included on the disk. The sounds are also embodied in dms. If you don't want them, you will have to include the Erase instruction to loose them. Fifteen samples are available and many are called by appropriately named procedures. The list is: 1. Aaaargh.....a cry of pain 2. A spell casting effect 3. The sound of a wooden door being hit 4. The sound of a swishing sword 5. Metal on steel or stone 6. Movement of a clawed creature 7. A roar 8. An echoing roar 9. A short creaking noise 10. The sound of a machine 11. An explosion 12. The teleport sound 13. Another spell sound 14. A raspberry sound - sword hitting squashy nasty 15. Another explosion ___________________________________________________________________________ Saving levels....... Sooner or later you need to think about how to save the game. At present the shell holds the map arrays as data statements. This is inadequate for a full game since the data is being held twice in memory - once as data statements, once in the arrays. The obvious approach is to save the arrays as sequential files on disk. Easy to do but is a little slow if the levels are large. If, however, you are holding all levels at once, this method is good enough. A quicker method for loading individual levels is to use memory banks. What you do is build a program containing your map data in data statements. This is read and then DOKEd into a memory bank. Assume that you have 100 data points in the array Z(10,10). The following code will set up and save the bank: Erase 10 Reserve As data 10,100 MAPDATA=Start(10) For Y=1 TO 10 For X=1 TO 10 DOKE MAPDATA+COUNT,Z(Y,X) COUNT=COUNT+2 Next X Next Y Save "Data.abk",10 The next fragment pulls the data into your array: Dim Z(10,10) Erase 10 Reserve As data 10,100 MAPDATA=Start(10) Load "Data.abk",10 For Y=1 TO 10 For X=1 TO 10 Z(Y,X)=DEEK (MAPDATA+COUNT) COUNT=COUNT+2 Next X Next Y Before you shout, I know that this method also using memory twice (one for the Bank and one for the array). But the system loads and saves quickly even if the extraction of the data is a little slow. ___________________________________________________________________________ Go with the flow...... Now its time to look at the logic flow of the program. The loop starts at label KEYL. The first two checks decide whether a random noise is heard and whether any nasties attack. The mouse button is then checked and if pressed control jumps to CLICK. CLICK checks for the use of the movement icons. If none is attempted then AHEAD is checked for the presence of a lever, switch or keyhole ahead. The labels A1 to A12 then process any action. Consider A4. This checks for an attempt to move the switch by the wooden door. The first line checks if the pointer is on the switch. If it is, CHANGE[5] alters the OMAP() location ahead so that the value reflects the switch in its down position. A suitable noise is made. The next line checks which switch you are trying to activate (this time on level 1) and removes the door by zeroing the relevent MAP() element. The display is then updated before control is returned to KEYL. A5 reverses the process. If a movement icon has been used then MMOVE sets the value of S and jumps to KEYL2. After the mouse check is complete, the keyboard is checked and S is set to the key pressed. If "q" has been pressed, the game ends. The code following KEYL2 checks for a rotate right command, updates COMP (the compass value), zeroes the AHEAD and NS values, updates the compass display and jumps to MOVE. MOVE updates the view given your latest position. The code following K1 checks for a rotate left and does the same. The other labels do the following checks: K2 - Move forward K3 - Move backward K4 - Move right K5 - Move left C1,C2,C3 and C4 carry out the move to the north, east, south and west respectively. Let us consider C1. The contents of the square you are about to move onto (NS) and any nasty on that square (NN) are first obtained from the maze data arrays. The next line identifies whether a move can be made and jumps to MOVE if it can. The next line identifies whether to have walked into a wall and jumps to OUCH to make an appropriate noise. You will have to add any loss of strength to OUCH if required. The next two lines check for stairs and act accordingly. Finally, a trapdoor is checked for. C2,C3 and C4 do exactly the same. If you decide to create your own hazards then you will need to amend these routines to include them. MOVE first checks to see if there is an object on the square to are about to move onto (HERE). It then checks to see whether you are about to walk into a teleport and acts accordingly. The next two lines look for colour changes. The view and map are then updated. The next line looks for any hazards such as a larva pool. You will have to amend AAARGH to reduce the strength of your player. The routine finally puts a picture of the object at your feet into the object window. ___________________________________________________________________________ Over to you....... Well gievn the skeleton, what is there for you to do? The answer is lots. I deliberately left the shell loose to give you maximum freedom to develop your own routines. The obvious omissions are: * The take, drop, use routines. If you have enough chip memory, you could adopt the Dungeon Master system using changes to the pointer but it will require a lot of new graphics. Alternatively you could use the small object window and menus to carry out actions. * The monster attack and move routines. These should be pretty simple to set up. * Create routines to give your player or players attributes and display them. This is potentially the biggest item to set up but I prefer to leave the format to you rather than impose my ideas. * Game save. This must hinge on your game design. * Monster animation. AMAL specialists could have a field day with this. * Create routines to hand the use of keys * The trapdoor routine only handles a single floor fall. If needed, it could be extended to show you falling several floors. * Puzzles - all your problem. With imagination and devious programming you can achieve what you want. * Special effects - light changes as you lantern fades or gets stronger. Remember - Dungeon Master was written using a high level language. With the forthcoming compiler, DMS could be just as slick. Over to you .......... I hope these notes help you around the game. If any of you have any queries please drop me a line. Allen Webb 64 Forest Road Southport Merseyside PR8 6HZ