EUG PD


Using The Assembler 06

 
Published in EUG #23

As promised, I will now describe the making of maps for arcade-type games as I want to publish my version of Mr. Miner (originally published as a hybrid (BASIC plus M/code) program in Electron User September '87).

This is really the same as in BASIC but the DATA is loaded to an address within the M/code file.

A map consists of data for the various characters represented by letters or numbers. In this game, the letters A to I are used to represent:

A- Brick wall
B- Rock
C- Diamond
D- Mushroom
E- Earth
F- Space
G- Man
H- Safe (containing a diamond)
I- Flashing key

I have included a program ("MAZELD") that LOADs and SAVEs the original levels. These are SAVEd as MAZE1. It asks for the suffix number before the file is SAVEd. The files are saved for loading at &1EE0 as is needed for the M/code file. You can access it directly from the Utilities Menu.

The data lines are arranged in 25 lines of 18 characters, which is the size of the play area for each level, so that you may be able to see how the map will appear on the screen by comparing the codes used. You can alter these lines and re-SAVE the file with a different suffix number to see the effect.

I will now describe how I have made up the M/code for the game and comment on the routines used.

Due to the length of the assembler listings, the code is assembled in two parts and then these are LOADed together and SAVEd as one file with the short program "MINERldr". This run be RUN at &E00. Do not run this program without first setting up the code with MINsrc2 as P% will not be set at the end of the code.

In both parts, I found it more convenient to assemble the code below PAGE and the assembler programs must be RUN with PAGE at &1D00. The code is then assembled at &E00 but as if assembled at the correct address. This is done by using OPT 4 - 7 instead of OPT 0 - 3. This assembles at O% but with addresses as for P%.

PAGE must be initially at &E00 so ADFS users will not be able to use these programs (unless they use tape) but can LIST them to see how they are made up. Also, the length of the second part needs HIMEM to be raised too. I have included a short program (U.MINs2rn) which sets PAGE and HIMEM before CHAINing"MINsrc2" for those with 32K Elks who might like to experiment with these.

Both programs are set to RUN at &1D00 by line 50 in each program.

Program 1 ("MINsrc1") is the assembler listing of the original M/code and DATA though I have altered the addresses so as to combine the code into one file which is to be loaded to &1D00. This saves the file MIN1 (addresses &1D00 to &2B7C).

Line 60 loads the sprite data to &1D00, DATA lines 140 - 200.

Lines v70-90 loads the map data to &1EE0, DATA lines 210 - 320.

Line 100 loads the tune data to &27AA, DATA lines 330 - 360.

The PROCassem is then called to assemble the code at &2885. I will not describe this in too much detail, partly because I have not studied it enough to do so but I want to say more about what I have done in the second part. I hope the following brief notes will be of interest. I will refer to the lines of the assembler listing which produce the code for each routine.

Subroutine Z% (lines 450-470) is the code for the tune at &2885. This loads the value for pitch and duration, depending on the value of the variable p, which are loaded into the sound buffer at &AF0 (line 460). The value of p decreases by each time the code is called so producing a different note. Because the event vector is set to Z%, the tune will start by using *FX 14 4 and continue until *FX 13 4 is used.

Subroutine S% (lines 480-830) reads the character number from the data and, after the comparison, loads the address of the character data into &80 and &81. This is then used by the print subroutine to print the sprite. This routine was explained in a series of articles in EU (February - September 1988).

Subroutine R% (840-1060) is concerned with the falling of rocks and squashing of mushrooms and whether you lose a life.

Subroutine T% (1070-1120) replaces safes with diamonds when the key is collected.

Program 2 ("MINsrc2") is my additional M/code and includes several routines already described. This creates file "MIN2" for loading to &2B7D. It is arranged in three sections as in the program for the tutorial.

  1. Main loop (lines 80 - 470)
  2. Subroutines (lines 480 - 1570)
  3. Data (lines 1580 - 2090)

I will first write notes on the subroutines.

p (480,490) is the loop given last time for giving the commands in the data lines as was explained.

dh (500-520) is the double size printing routine as given earlier.

choose (530-670) responds to the key pressed.

  P ends the procedure to start the game.
L calls the subroutine mload for loading other maze files.
S and Q call the subroutines for turning the sound on/off.
1, 2 and 3 set the value the variable spd to set the speed of the game as explained in an earlier article.

I had to experiment with the number of ASL As and also add the SBC in line 630 to get a good choice of speeds. Those who are able to reassemble the code may like to experiment with this.

init (680-740) sets the variables. Loads &5300 to &56FF with the brick character number (224) in lines 700 and 710. This is done so that, when each level is loaded over this area, there is a border three bricks wide around the play area. The routine also loads &5700 to &57FF with space characters (229) and calls the subroutine env for setting up the sound envelopes.

sdoff and sdon (750, 760) are the m/code equivalents of *FX 210 1 and *FX 210 0.

sond1 to sond6 (770-820) when called, give the sounds needed. The values of A, X and Y need to be preserved each time and therefore PUSHed and PULLed from the stack. The sound is given by using osword with register A loaded with 7 and the address of the data in X and Y registers. The data needed are the four sound parameters entered as words (EQUW), DATA lines 1880-1930.

env (830-850) set up the three envelopes. Each is set up with osword in the same way but with A register loaded with 8 and DATA lines with the 14 parameters entered as bytes (EQUB), DATA lines 1850-1870.

delsp, dels and dell (860-880) are delay routines and are simply nested loops as given in an earlier article. dels and dell are short and long delays and delsp depends on the value of the variable spd which has been selected. Again, this number NOPs could be varied if anyone wishes to do this.

lives (890-920) print the man at the top of the screen by transferring the data from &1E20 to the screen area at &5A38 and from &1E38 to &5B78. This is followed by printing the data dat (line 1940) using the dh routine.

lev (930-950) sets the level and prints Thinking.

load (960-1010) first checks the level, doubles it (ASL A) and subtracts two (DEX:DEX) so the value in X register is 0, 2, 4, 6 or 8. This is used as an index to select the data address from the data table in line 1950. The data is then loaded from that address adding 159 each time to convert to the character numbers. Line 980 calls the subroutine to save the key address. Line 990 counts the number of diamonds, earth and mushrooms and stores these in maxdi%, maxea% and maxsq%. Line 1000 loads the level data over the memory area &534B onwards as explained earlier.

set (1020) sets the variables MX% and MY% for the man's position.

set2 (1030) sets x% and y% in the same way.

sc1 and sc2 (1040-1070) print the score. sc (1060-1070) is the routine for printing decimal from the hex value in the variable digits. sc1 adds 3 each time for earth collected and sc2 adds 10 for diamonds.

prt (1100) together with the following routines to line 1150 print the number of diamonds, earth and mushrooms remaining. h, t and u calculate the hundreds, tens and units of the value stored at &70. di, ea and sq set the values and print co-ordinates for each one.

ki (1160-1180) flashes the key by printing character 232 or 233. The characters alternating to produce the flashing.

kyaddr (1190) uses routine cal to find the address of the key from its co-ordinates and saves this in the variable kad.

eas (1200) and dis (1210) count the earth and diamonds collected and call sc1 or sc2 to add to the score.

chk1 (1220, 1230) checks whether you have lost a life or completed a level. Also when all levels are completed.

ss% (1240) sets data to D% and addr to &6390.

ded (1250, 1260) flashes the man, decreases li% and increases deadman when you lose a life.

move (1270-1330) reads the keys. With A register loaded with 129, Y with &FF and X with the negative INKEY value, after the call to osbyte, Y=0 if the key is not pressed and -1 when pressed. If no keys are pressed, all comparisons are equal and the routine ends. If a key is pressed, the routine for that key is called as the comparison is not equal.

Keys Q and S call the routines sdoff and sdon as explained.

The ESCAPE key calls the routine ded and replaces the data address with a space.

The four movement routines (1340-1440) are somewhat complex.

It is first necessary to check the address of the position to which movement is to be made. For left and right movement this is -1 and +1 relative to the position of the man and for up and down they are -24 and +24. I used the indexed addressing LDA(mp),Y to do this and to avoid the negative values, which are not permissible, I set Y to 48 so that the address in mp +48 points to the address of the man. The address held in mp is calculated as the address of the man minus 48. With Y=47 will then point to the position on the left and Y=49 that on the right. Similarly, Y=24 points to the one above and Y=72 to the one below.

Each routine first calculates the address to be held in mp with the routine mpos and checks the relevant address as explained above. Then the following comparisons are made:

  CMP#231 (safe)-if equal, cannot move
  if greater (carry flag set) ie Key collected - jump chg to call T%
CMP#224 (brick)-if equal, cannot move
CMP#225 (rock)-if up or down and equal - cannot move
if left or right, check next address
if not 229 (space), cannot move
else move rock
CMP#227 (mushroom)-if equal, JMP ded
CMP#226 (diamond)-if equal, JSRdis, move
CMP#228 (earth)-if equal, JSReas, move
else move

When a move is made, the character in memory is replaced with a space character and the variables re-calculated and the display redrawn.

rep (1450) waits for space to be pressed.

gamend (1460-1480) prints the final message (DATA lines 1980-2010), starts the tune with *FX 14 4 and asks if you want another game. Then waits for Y or N to be pressed.

mload (1490-1570) first print a message asking for the suffix number (1-5). After pressing the number key, the number is inserted in the loading message (DATA line 2080) and in the loading command (DATA line 2090) for the file to be loaded.

Lines 1580 - 1610 make space for the variables.

The main loop (190) first sets the event vector to Z% (&2885) for the tune as already explained.

dat1 codes (1620) are set up by line 200. These give the commands for Mode 5, cursor 5, VDU 19,3,2;0; to change white to screen, VDU17,1 changes the print colour red and the print position is then set to TAB(5,5). The title (630) is then printed using the dh routine.

dat2 codes (1640) are set by line 210. The underline character CHR$(250) is set up using VDU23, VDU17,2 gives the colour yellow and then the print position to TAB(5,7). The underlines (1650) are then printed with the dh routine.

dat3 codes (1660-1750) print the menu options (line 220) first changing the colour to green then to yellow for the lower underlines.

Line 230 returns the print colour to green.

The value of spd is set at line 240 to give the middle speed.

The routine choose is then called (250).

?&358 is loaded with 90 and the screen cleared. This gives the orange screen. ?&358 is then returned to zero as normal (260).

dat2 codes (1760-1810) are set_at line 270. The three windows are set up and printing needed.

dell is called three times (290) to give a pause between levels.

The load routine is called (300)_to_set_up_the_data_for the level as explained.

The tune is turned off at line 310.

Line 320 calls calc to calculate D% from MX% and MY% for setting up the display. These are saved as sD%, smx% and smy% for returning to the start position after losing a life.

Lines 340 to 390 are the main game loop. As this involves the original coding, I cannot explain this fully.

The speed delay is called at line 360.

The remaining totals are printed at line 370.

In line 380:

  If kt%=255, key not collected, routine ki is called if cn%=0, cn% is increased each time to provide a delay for the flashing key.
If kt%=0 when the key_ is collected the program branches to fin at the end of the line and ki is not called.

chk1 is called at line 490:

If lvend, level completed, branch to nexlev.

If deadman, lose a life, branch to lose and reset display to start position else move.

Then if li%=0 branch to endgame else to game1 to continue.

nexlev (400) resets the variables to zero and clears the display area by printing spaces (data at &5700) and returns to st1 to continue the game.

endgame (400-470): line 420 resets li% and clears the display as above.
endat (1960,1970) message is given at line 430.
The tune is started at line 440.
Line 450 waits for space to be pressed by routine rep.
The tune is stopped and keyboard buffer cleared at line 460.
Then the program returns to st1 to restart the game.

I hope that I have given a reasonable description of the coding. If there is any more I can add, I will do so next time. Also I hope to have the start of a little adventure game written in M/code which I hope to explain.

Richard Dimond, EUG #23

Richard Dimond