' ' OUBLIETTE v1.02 by James Wilkinson 20/04/2016 ' ' Source code provided as is - feel free to use any techniques or adapt ' it for your own programs. I am a member of the AMOS Factory forum and ' AMOS Professional FB Group, so hit me up if anything isn't very clear ' or you want to know more about any of the routines. ' ' Full game available from game/actio/Oubliette.adf on AmiNET ' 'open up our main screen Screen Open 0,320,256,16,Lowres Hide : Flash Off : Curs Off : Cls 0 'switch off CTRl+C ending program Break Off 'screen 1 is used for drawing the radar Screen Open 1,320,256,16,Lowres Screen Hide 1 'screen 2 is used to create a playfield mask for collision checks Screen Open 2,320,256,2,Lowres Screen Hide 2 'make sure hardware sprites are maximum height for use with computed sprites Set Sprite Buffer 256 'this command is supposed to speed up compiled program Comp Test Off 'font location assigned in disk startup sequence Get Disc Fonts 'grabbing dpaint 5pt font Set Font 1 'our arrays for the game Dim MAP(20,16),LMAP(11,11,1),SBASE(21,13),ABASE(21,6),MBASE(6,8),HSCORE$(1,8),TE$(25) 'MAP - onscreen playfield 'LMAP - randomised level, 3rd dimension stores flag to denote a location 'has been visited 'SBASE - SpritedataBASE stores info on game objects 'THE X AXIS '0: P1 '1: P1 Sword '2: P1 Fireball '3: P2 '4: P2 Sword '5: P2 Fireball '6-11: Monster 1 through 6 '12-17: Monster Fireball for Monster 1-6 '18-21: Pick-Ups, coins, health, 1up etc 'THE Y AXIS '0: Corresponding sprite number using range 8-50 '1: Timer - If this is higher than 0 and sprite is off, it will be decreased 'until it hits 0, at which point, set to -1 and switch sbase(x,2) to 255 '2: Display flag, 255 for on, 0 for off '3: X Position onscreen '4: Y Position onscreen '5: Image number '6: Sub-type (what type on enemy or pickup) '7: X Speed, Set to -3 or 3 for fireballs, -1 or 1 for players, monsters '8: Y Speed, Set to -3 or 3 for fireballs, -1 or 1 for players, monsters '9: Unused '10: Invicibility timer after being attacked '11: Timer for player attack, monster health '12: Flag to indicate if player/monster has an active fireball onscreen '13: Type: Set to 1 for player, 2 for fireball, 3 for monster ' 'ABASE - AnimationdataBASE stores which animation to run 'THE X AXIS - Exactly the same SBASE, 1 anim record for each sprite 'THE Y AXIS '0: Flag if animation is switched on '1: Image for current frame '2: Delay between frames '3: Timer counting down to switch frame based on value in 2 '4: First animation frame '5: Second animation frame '6: Repeat flag, set to 0 for loop, 1 for stop on last frame, 2 for stop 'animation and switch off the sprite ' 'MBASE -MovementdataBASE stores details of movement type for monsters 'THE X AXIS '1-6 correspond to entries 6-11 in SBASE 'THE Y AXIS '0: Flag if movement channel is active '1: Timer, when this hits 0 the movement routine runs '2: Pause, when movement routine completes add this value to 1 '3: X Position destination '4: Y Position destination '5: Distance to move in multiples of 16, set to 1 for a 16 pixel move '6: Firing flag, 255 if monster can throw fireballs, 0 if not '7: Moving flag, 255 if movement on, 0 if off '8: Movement type, 0 if roaming, 255 if bouncing ' 'HSCORE$ - Highscores loaded from a sequential file 'X AXIS '0: 3 character name '1: Score padded with leading zero's ' 'TE$ - TExt strings 'THE Y AXIS '0-25: Correspond to a letter of the alphabet A,B,C, etc ' 'Variables to hold current location in level grid, Z axis denote level no Global LEVX,LEVY,LEVZ 'Globalise all our arrays Global MAP(),LMAP(),SBASE(),ABASE(),MBASE(),HSCORE$(),TE$() 'Global some incidental variables, GameMODE,GotBLOCK Flag, NUMber_PLAYers 'NUMber_MONsters on the map, SPRiteCOLLIDed with playfield flag Global GMODE,GBLOCK,NUM_PLAY,NUM_MON,SPRCOLLIDE 'Global some variables for the players stats - HitPoints, ManaPoints, SCore '1UP's, INputs, Delay, DeathDelay, CollectionCounter, KillCounter Global P1HP,P1MP,P1SC,P1UP,P1IN,P1D,P1DD,P1CC,P1KC Global P2HP,P2MP,P2SC,P2UP,P2IN,P2D,P2DD,P2CC,P2KC 'initate game procedure - loads data and such INITGAME 'draw some graphics and text on screen and grab into banks for blocks and 'cblocks GBLOCK 'main game loop Do 'the title screen If GMODE=0 'run title procedure TITLE End If 'a game is in session If GMODE=1 'check for input on the keyboard KEYINPUT 'check which players are active and check for joystick input If SBASE(0,2)=255 and P1D=255 : J1INPUT : End If If SBASE(3,2)=255 and P2D=255 : J2INPUT : End If 'animation routine ANISPRITE 'collision with playfield routine AUTOCOL 'monster movement routine AUTOMOVE 'monster firing routine AUTOFIRE 'sprite 2 sprite collision routine S2SCOL 'update sprite position routine MOVESPRITE 'draw sprite routine BLITSPRITE 'wait for a vertical blank Wait Vbl 'clear player movement vectors so holding joystick in direction is 'required to sustain movement SBASE(0,7)=0 : SBASE(0,8)=0 SBASE(3,7)=0 : SBASE(3,8)=0 'game houskeeping routine GAMECTRL End If Loop Procedure LEVEL_START 'this routine displays the level map at the start of a new level 'so players have a brief glimpse of the general direction of the exit LEVZ$=Str$(LEVZ) Ink 3,0 : Text 138,50,"LEVEL"+LEVZ$ Wait 50 Screen Copy 1,35,35,78,78 To 0,132,60 Wait 50 Text 80,115,"FIND THE EXIT AND KILL THE DRAGON" Wait 200 BLITSCREEN[0] End Proc Procedure TE 'this routines loads letters into the TExt array TE$(0)="A" TE$(1)="B" TE$(2)="C" TE$(3)="D" TE$(4)="E" TE$(5)="F" TE$(6)="G" TE$(7)="H" TE$(8)="I" TE$(9)="J" TE$(10)="K" TE$(11)="L" TE$(12)="M" TE$(13)="N" TE$(14)="O" TE$(15)="P" TE$(16)="Q" TE$(17)="R" TE$(18)="S" TE$(19)="T" TE$(20)="U" TE$(21)="V" TE$(22)="W" TE$(23)="X" TE$(24)="Y" TE$(25)="Z" End Proc Procedure GAMECTRL 'game housekeeping routine 'check to see if the players DeathDelay timer is greater than 0 and 'decrease by 1 if so If P1DD>0 Then Dec P1DD If P2DD>0 Then Dec P2DD 'check to see if all the monsters in the level have been killed If NUM_MON=0 'if so, set the NUMberMONsters to -1 and run routine to create exits NUM_MON=-1 CREATE_EXITS End If 'if the NUMberMONsters is equal to -1, then our exits are open 'we need to check sprite positions of our players to detect if they 'are attempting to leave the screen and deal with that If NUM_MON=-1 'checks here are for player 1 If SBASE(0,2)=255 'checking to see if he's heading up If SBASE(0,4)<24 'decrease y position LEVY=LEVY-1 'wrap the Y position if outside of array area If LEVY=0 : LEVY=10 : End If 'run the screen wipe routine. parameter 0 indicates which direction to 'swipe SWIPE[0] 'set a flag to indicate the screen has been wiped. rest of code from this 'point on checks differant players moving in differant directions until 'the next comment SCRWP=-1 End If If SBASE(0,4)>240 LEVY=LEVY+1 If LEVY=11 : LEVY=1 : End If SWIPE[2] SCRWP=-1 End If If SBASE(0,3)<8 LEVX=LEVX-1 If LEVX=0 : LEVX=10 : End If SWIPE[1] SCRWP=-1 End If If SBASE(0,3)>312 LEVX=LEVX+1 If LEVX=11 : LEVX=1 : End If SWIPE[3] SCRWP=-1 End If End If If SBASE(3,2)=255 If SBASE(3,4)<24 LEVY=LEVY-1 If LEVY=0 : LEVY=10 : End If SWIPE[0] SCRWP=-1 End If If SBASE(3,4)>240 LEVY=LEVY+1 If LEVY=11 : LEVY=1 : End If SWIPE[2] SCRWP=-1 End If If SBASE(3,3)<8 LEVX=LEVX-1 If LEVX=0 : LEVX=10 : End If SWIPE[1] SCRWP=-1 End If If SBASE(3,3)>312 LEVX=LEVX+1 If LEVX=11 : LEVX=1 : End If SWIPE[3] SCRWP=-1 End If End If 'if the screen has been wiped If SCRWP=-1 'make sure we flag the new location as visited LMAP(LEVX,LEVY,1)=1 'pull the screen data for the current location out of memory into the MAP 'array BANKTOMAP[LMAP(LEVX,LEVY,0)] 'run the wave initialisation routine INITWAVE 'blit the screen - parameter -1 indicates we want to generate a random 'colour for this screen BLITSCREEN[-1] End If End If 'checking on the health of the players and dealing with death 'If health is empty and the sprite is still active If P1HP<1 and SBASE(0,2)=255 'If the delay flag is set to 255 If P1D=255 'set it to 0 P1D=0 'set the death delay timer P1DD=25 'define the explosion animation for the sprite ANIDEF[0,1,58,2,4,58,59,2] End If End If 'so if the sprite is switched off but still has lives left they need 'to come back If SBASE(0,2)=0 and P1UP>0 'make sure the dealy timer has finished it's countdown If P1DD=0 'set the delay flag back to 255 P1D=255 'switch the sprite back on SBASE(0,2)=255 'define an animation of flashing arms in the arm ANIDEF[0,1,17,2,4,17,41,0] 'fill the HP back to max P1HP=62 'fill the MP back to max P1MP=62 'decrease the amount of lives left Dec P1UP 'run the routine to update the HUD at the top of the screen BLITHUDINFO End If End If 'now do the same thing for player 2 If P2HP<1 and SBASE(3,2)=255 If P2D=255 P2D=0 P2DD=25 ANIDEF[3,1,58,2,4,58,59,2] End If End If If SBASE(3,2)=0 and P2UP>0 If P2DD=0 P2D=255 SBASE(3,2)=255 ANIDEF[3,1,37,2,4,37,41,0] P2HP=62 P2MP=62 Dec P2UP BLITHUDINFO End If End If 'check to see if both players are switched off and have run out of lives If SBASE(0,2)=0 and P1UP=0 and SBASE(3,2)=0 and P2UP=0 'run the game over routine GAME_OVER End If End Proc Procedure GBLOCK 'this routine sets up some text blocks to pull into memory locations 'for the title screen menu Screen 1 Set Font 1 Flash Off Colour 14,$FFF Colour 13,$100 Set Pattern 2 Ink 6,0 : Bar 0,0 To 320,7 : Ink 14,6 : Text 136,5,"1 PLAYER" Get Block 1,0,0,320,7 Ink 6,0 : Bar 0,0 To 320,7 : Ink 14,6 : Text 136,5,"2 PLAYER" Get Block 2,0,0,320,7 Ink 6,0 : Bar 0,0 To 320,7 : Ink 14,6 : Text 130,5,"HIGH SCORE" Get Block 3,0,0,320,7 Ink 6,0 : Bar 0,0 To 320,7 : Ink 14,6 : Text 144,5,"QUIT" Get Block 4,0,0,320,7 Set Pattern 0 Ink 0 : Bar 0,0 To 320,7 : Ink 3,0 : Text 144,5,"PAUSED" Get Block 7,0,0,320,7 'this routine draws the high score table and puts it in memory HSCRTAB Screen 0 End Proc Procedure HSCRTAB 'this routine draws the high score table and puts it in memory Screen 1 Get Icon Palette Set Font 1 Colour 14,$FFF Colour 13,$100 Cls 13 Ink 14,13 For Y=0 To 8 For M=1 To 3 Text M*5,7+Y*7,Mid$(HSCORE$(0,Y),M,1) Next M For M=1 To 9 Text 25+M*5,7+Y*7,Mid$(HSCORE$(1,Y),M,1) Next M Next Y Box 2,0 To 76,66 Get Block 5,2,0,75,67,1 Screen 0 End Proc Procedure TITLE 'switch off sprites, set Choice to 1, unpack title screen graphics 'play the opening music, change some colours, set up a nice flash 'grab part of the screen background where the high score table is 'displayed Sprite Off C=1 Track Play 40 Unpack 23 To 0 Colour 14,$FFF Flash 15,"(300,3)(400,3)(500,3)(600,3)(700,3)(600,3)(500,3)(400,3)" Get Block 6,115,80,80,67 'a little loop to monitor joystick input and cycle up and down 'through menu choices. we exit when firebutton is pressed Repeat Wait Vbl Put Block C,0,160 J=Joy(1) If J>0 If Joy(1)=1 and C>1 : Dec C : End If If Joy(1)=2 and C<4 : Inc C : End If Wait 25 End If If C=3 and SS=0 SS=1 Put Block 5,115,80 End If If C<>3 and SS=1 SS=0 Put Block 6,115,80 End If Until J=16 and C<>3 'switch off flash, clear screen, kill music Flash Off Cls 0 Track Stop 'fill SBASE with the default values held in memory BANKTOSBASE 'find out what choice the player selected, C=1 for 1Player, 'C=2 for 2Player, C=4 for quit 'for C=1 and C=2 set up the game If C=1 NUM_PLAY=1 SBASE(0,2)=255 SBASE(3,2)=0 ANIDEF[0,1,17,2,4,17,41,0] P1HP=62 : P1MP=62 : P1SC=0 : P1UP=2 : P1D=255 : P1KC=0 : P1CC=0 P2HP=0 : P2MP=0 : P2SC=0 : P2UP=0 : P2D=0 : P2KC=0 : P2CC=0 End If If C=2 NUM_PLAY=2 SBASE(0,2)=255 SBASE(3,2)=255 ANIDEF[0,1,17,2,4,17,41,0] ANIDEF[3,1,37,2,4,37,41,0] P1HP=62 : P1MP=62 : P1SC=0 : P1UP=2 : P1D=255 : P1KC=0 : P1CC=0 P2HP=62 : P2MP=62 : P2SC=0 : P2UP=2 : P2D=255 : P2KC=0 : P2CC=0 End If 'if player chose to quit then goto the quit routine If C=4 : QUIT : End If 'clear level position data LEVX=0 : LEVY=0 : LEVZ=0 'sort the palette out Get Icon Palette Get Sprite Palette 'initialise the level INITLEVEL 'pull the current level position from memory into MAP array BANKTOMAP[LMAP(LEVX,LEVY,0)] 'initialise a monster wave INITWAVE 'blit the screen with a random colour BLITSCREEN[-1] 'run the level start routine LEVEL_START 'set GameMODE to 1 to indicate play in session GMODE=1 End Proc Procedure J1INPUT 'this routine monitors player 1 input. the same set of checks are made 'in J2INPUT so i won't repeat the comments there 'before we accept an input to move the player sprite, we need to make sure 'it is not in the middle of attacking If SBASE(0,11)=0 'reading the bitmap of joy - this indicates pushing up If Joy(1)=1 'run the sprite collision routine to make sure we can move up SPRCOL[SBASE(0,0),SBASE(0,3),SBASE(0,4),0] 'if the playfield looks clear above If SPRCOLLIDE=0 'set our Y movement vector to -1 SBASE(0,8)=-1 'check to see if our last recorded input variable is not 1 If P1IN<>1 'and if so set it to 1 P1IN=1 'and define our moving up animation ANIDEF[0,1,9,6,6,9,10,0] End If End If End If 'so we are now doing this for the other three movement directions until 'comments continue If Joy(1)=2 SPRCOL[SBASE(0,0),SBASE(0,3),SBASE(0,4),2] If SPRCOLLIDE=0 SBASE(0,8)=1 If P1IN<>2 P1IN=2 ANIDEF[0,1,1,6,6,1,2,0] End If End If End If If Joy(1)=4 SPRCOL[SBASE(0,0),SBASE(0,3),SBASE(0,4),1] If SPRCOLLIDE=0 SBASE(0,7)=-1 If P1IN<>3 P1IN=3 ANIDEF[0,1,5,6,6,5,6,0] End If End If End If If Joy(1)=8 SPRCOL[SBASE(0,0),SBASE(0,3),SBASE(0,4),3] If SPRCOLLIDE=0 SBASE(0,7)=1 If P1IN<>4 P1IN=4 ANIDEF[0,1,13,6,6,13,14,0] End If End If End If 'checking to see if we've hit the firebutton. bitmap 16 indicates that the 'firebutton has been pressed but the joystick is centered If Joy(1)=16 'set our little attack flag to 10, player can't move now until this hits 'zero SBASE(0,11)=10 'based on the players last recorded input we can determine where we need to 'create the sword sprite 'so in this case if it was up If P1IN=1 or P1IN=5 P1IN=5 'run the sprite definition routine to create our sword SPRDEF[1,0,255,SBASE(0,3),SBASE(0,4)-16,12,0,0,0,0,0,0,0] 'define an animation for the sword so it flashes onscreen briefly then 'turns off and setting this animation to repeat type 2 means once the 'animation completes, the sprite will be auto switched off ANIDEF[1,1,12,1,10,12,41,2] 'define the thrusting animation for the player ANIDEF[0,1,11,1,10,11,9,1] End If 'now we do the same thing for the other directions so comments will resume If P1IN=2 or P1IN=6 P1IN=6 SPRDEF[1,0,255,SBASE(0,3),SBASE(0,4)+16,4,0,0,0,0,0,0,0] ANIDEF[1,1,4,1,10,4,41,2] ANIDEF[0,1,3,1,10,3,1,1] End If If P1IN=3 or P1IN=7 P1IN=7 SPRDEF[1,0,255,SBASE(0,3)-16,SBASE(0,4),8,0,0,0,0,0,0,0] ANIDEF[1,1,8,1,10,8,41,2] ANIDEF[0,1,7,1,10,7,5,1] End If If P1IN=4 or P1IN=8 P1IN=8 SPRDEF[1,0,255,SBASE(0,3)+16,SBASE(0,4),16,0,0,0,0,0,0,0] ANIDEF[1,1,16,1,10,16,41,2] ANIDEF[0,1,15,1,10,15,13,1] End If End If 'let's check to see if our player wants to throw a fireball, so is the 'joy bitmap greater than 16? If Joy(1)>16 'if so, do we have enough MP to throw a fireball If P1MP>1 'now we check for definite direction, in this case, up If Joy(1)=17 'We check to see if we have not already fired If SBASE(0,12)=0 'and if so set a flag to indicate we have now SBASE(0,12)=2 'reduce our MP P1MP=P1MP-2 'boost our score by five points P1SC=P1SC+5 'define a sprite for the fireball SPRDEF[2,0,255,SBASE(0,3),SBASE(0,4),19,0,0,-3,0,0,0,0] 'define an animation for the fireball ANIDEF[2,1,19,4,4,19,20,0] 'and update the HUD to show less MP and more score BLITHUDINFO End If End If 'then we do that for the other directions and comments will resume If Joy(1)=18 If SBASE(0,12)=0 SBASE(0,12)=2 P1MP=P1MP-2 P1SC=P1SC+5 SPRDEF[2,0,255,SBASE(0,3),SBASE(0,4),19,0,0,3,0,0,0,0] ANIDEF[2,1,19,4,4,19,20,0] BLITHUDINFO End If End If If Joy(1)=20 If SBASE(0,12)=0 SBASE(0,12)=2 P1MP=P1MP-2 P1SC=P1SC+5 SPRDEF[2,0,255,SBASE(0,3),SBASE(0,4),19,0,-3,0,0,0,0,0] ANIDEF[2,1,19,4,4,19,20,0] BLITHUDINFO End If End If If Joy(1)=24 If SBASE(0,12)=0 SBASE(0,12)=2 P1MP=P1MP-2 P1SC=P1SC+5 SPRDEF[2,0,255,SBASE(0,3),SBASE(0,4),19,0,3,0,0,0,0,0] ANIDEF[2,1,19,4,4,19,20,0] BLITHUDINFO End If End If End If End If End If 'and if our attack flag is greater than zero, well, decrease the timer If SBASE(0,11)>0 Then Dec SBASE(0,11) End Proc Procedure J2INPUT 'same as J1INPUT - please see that routine for comments If SBASE(3,11)=0 If Joy(0)=1 SPRCOL[SBASE(3,0),SBASE(3,3),SBASE(3,4),0] If SPRCOLLIDE=0 SBASE(3,8)=-1 If P2IN<>1 P2IN=1 ANIDEF[3,1,29,6,6,29,30,0] End If End If End If If Joy(0)=2 SPRCOL[SBASE(3,0),SBASE(3,3),SBASE(3,4),2] If SPRCOLLIDE=0 SBASE(3,8)=1 If P2IN<>2 P2IN=2 ANIDEF[3,1,21,6,6,21,22,0] End If End If End If If Joy(0)=4 SPRCOL[SBASE(3,0),SBASE(3,3),SBASE(3,4),1] If SPRCOLLIDE=0 SBASE(3,7)=-1 If P2IN<>3 P2IN=3 ANIDEF[3,1,25,6,6,25,26,0] End If End If End If If Joy(0)=8 SPRCOL[SBASE(3,0),SBASE(3,3),SBASE(3,4),3] If SPRCOLLIDE=0 SBASE(3,7)=1 If P2IN<>4 P2IN=4 ANIDEF[3,1,33,6,6,33,34,0] End If End If End If If Joy(0)=16 SBASE(3,11)=10 If P2IN=1 or P2IN=5 P2IN=5 SPRDEF[4,0,255,SBASE(3,3),SBASE(3,4)-16,32,0,0,0,0,0,0,3] ANIDEF[4,1,32,1,10,32,41,2] ANIDEF[3,1,31,1,10,31,29,1] End If If P2IN=2 or P2IN=6 P2IN=6 SPRDEF[4,0,255,SBASE(3,3),SBASE(3,4)+16,24,0,0,0,0,0,0,3] ANIDEF[4,1,24,1,10,24,41,2] ANIDEF[3,1,23,1,10,23,21,1] End If If P2IN=3 or P2IN=7 P2IN=7 SPRDEF[4,0,255,SBASE(3,3)-16,SBASE(3,4),28,0,0,0,0,0,0,3] ANIDEF[4,1,28,1,10,28,41,2] ANIDEF[3,1,27,1,10,27,25,1] End If If P2IN=4 or P2IN=8 P2IN=8 SPRDEF[4,0,255,SBASE(3,3)+16,SBASE(3,4),36,0,0,0,0,0,0,3] ANIDEF[4,1,36,1,10,36,41,2] ANIDEF[3,1,35,1,10,35,33,1] End If End If If Joy(0)>16 If P2MP>1 If Joy(0)=17 If SBASE(3,12)=0 SBASE(3,12)=5 P2MP=P2MP-2 P2SC=P2SC+5 SPRDEF[5,0,255,SBASE(3,3),SBASE(3,4),39,0,0,-3,0,0,0,3] ANIDEF[5,1,39,4,4,39,40,0] BLITHUDINFO End If End If If Joy(0)=18 If SBASE(3,12)=0 SBASE(3,12)=5 P2MP=P2MP-2 P2SC=P2SC+5 SPRDEF[5,0,255,SBASE(3,3),SBASE(3,4),39,0,0,3,0,0,0,3] ANIDEF[5,1,39,4,4,39,40,0] BLITHUDINFO End If End If If Joy(0)=20 If SBASE(3,12)=0 SBASE(3,12)=5 P2MP=P2MP-2 P2SC=P2SC+5 SPRDEF[5,0,255,SBASE(3,3),SBASE(3,4),39,0,-3,0,0,0,0,3] ANIDEF[5,1,39,4,4,39,40,0] BLITHUDINFO End If End If If Joy(0)=24 If SBASE(3,12)=0 SBASE(3,12)=5 P2MP=P2MP-2 P2SC=P2SC+5 SPRDEF[5,0,255,SBASE(3,3),SBASE(3,4),39,0,3,0,0,0,0,3] ANIDEF[5,1,39,4,4,39,40,0] BLITHUDINFO End If End If End If End If End If If SBASE(3,11)>0 Then Dec SBASE(3,11) End Proc Procedure SPRDEF[X,A,B,C,D,E,F,G,H,I,J,K,L] 'a sprite definition routine. see notes at the top on what the Y AXIS of 'SBASE represents 'the paramters for this routine fill the corresponding X entry in SBASE SBASE(X,1)=A SBASE(X,2)=B SBASE(X,3)=C SBASE(X,4)=D SBASE(X,5)=E SBASE(X,6)=F SBASE(X,7)=G SBASE(X,8)=H SBASE(X,9)=I SBASE(X,10)=J SBASE(X,11)=K SBASE(X,12)=L End Proc Procedure ANIDEF[X,A,B,C,D,E,F,G] 'an animation definition routine. see notes at the top on what the Y AXIS 'of ABASE represents 'the paramters for this routine fill the corresponding X entry in ABASE ABASE(X,0)=A ABASE(X,1)=B SBASE(X,5)=B ABASE(X,2)=C ABASE(X,3)=D ABASE(X,4)=E ABASE(X,5)=F ABASE(X,6)=G End Proc Procedure ANISPRITE 'the automatic animation routine 'iterate this loop 22 times For X=0 To 21 'check to see if the animation channel of X is on If ABASE(X,0)=1 'if so decrease the time Dec ABASE(X,3) 'if the timer has finished If ABASE(X,3)=0 'the timer will refill using the value held in delay ABASE(X,3)=ABASE(X,2) 'check to see is the current frame is equal to the first frame If ABASE(X,1)=ABASE(X,4) 'if so, set the current frame to the second frame and update the field 'in the corresponding SBASE entry with the next animation frame ABASE(X,1)=ABASE(X,5) SBASE(X,5)=ABASE(X,5) 'jump out of this loop Goto CUT End If 'check to see if the current frame is equal to the second frame If ABASE(X,1)=ABASE(X,5) 'check to see what type of repeat this animation is supposed to have 'if it is meant to be an endless loop If ABASE(X,6)=0 'set the current frame to the first frame in bothe the ABASE and the 'corresponding SBASE field ABASE(X,1)=ABASE(X,4) SBASE(X,5)=ABASE(X,4) End If 'if the animation was meant to just stop If ABASE(X,6)=1 'switch off the animation channel ABASE(X,0)=0 End If 'if the animation was supposed to stop and then kill the sprite If ABASE(X,6)=2 'switch off the animation ABASE(X,0)=0 'switch off the sprite SBASE(X,2)=0 'if the sprite we have switched off was the dragon If SBASE(X,6)=9 'run the level complete routine LEVEL_COMPLETE End If End If End If End If End If CUT: Next X End Proc Procedure BLITSPRITE 'this routine draws sprites on screen 'iterate this loop 22 times For X=0 To 21 'if the sprite is acitve If SBASE(X,2)=255 'draw it onscreen using the values stored in SBASE for this sprite Sprite SBASE(X,0),X Hard(SBASE(X,3)),Y Hard(SBASE(X,4)),SBASE(X,5) 'if the sprite happens to be the dragon If SBASE(X,6)=9 'do a bob for the dragons body Bob 1,SBASE(6,3)-8,SBASE(6,4),74 End If End If 'if the sprite is switched off If SBASE(X,2)=0 'make sure it is bloody well truely off Sprite Off SBASE(X,0) End If Next X End Proc Procedure MOVESPRITE 'this routine updates sprite positions in SBASE based on the values of 'their movement vectors also held in SBASE 'iterate a loop 22 times For X=0 To 21 'if the sprite is being displayed If SBASE(X,2)=255 'do the maths to change their position SBASE(X,3)=SBASE(X,3)+SBASE(X,7) SBASE(X,4)=SBASE(X,4)+SBASE(X,8) End If Next X End Proc Procedure AUTOCOL 'this routine checks for collisions between monsters/playfield and 'monster fireballs/playfield. sprite to sprite collisions are handled 'elsewhere 'iterate a loop 22 times For X=0 To 21 'if the sprite type is 1=Monster If SBASE(X,13)=1 'define a cheeky variable to hold the corresponding position in MBASE M=X-5 'check the MBASE to see if the movement routine for this monster 'is active If MBASE(M,0)=255 'check what direction the monster is moving, in this case up If SBASE(X,8)<0 'run the sprite collision routine to check above the monster SPRCOL[2,SBASE(X,3),SBASE(X,4),0] 'if there has been a collsion If SPRCOLLIDE=-1 'set the movement vector to 0 SBASE(X,8)=0 'if the monster is a roamer If MBASE(M,8)=0 'set the movement destination to current position +1. this will have the 'effect of bouncing back the monster by 1 pixel, aligning it to the grid 'and resetting the movement routine MBASE(M,4)=SBASE(X,4)+1 'set the movement vector to reverse direction SBASE(X,8)=1 'skip ahead to check collisions on X axis Goto EOYC End If 'if the monster was a bouncer If MBASE(M,8)=255 'invert the movement vector SBASE(X,8)=1 End If End If End If 'we are going to do this for other directions so comments will resume 'after If SBASE(X,8)>0 SPRCOL[2,SBASE(X,3),SBASE(X,4),2] If SPRCOLLIDE=-1 SBASE(X,8)=0 If MBASE(M,8)=0 MBASE(M,4)=SBASE(X,4)-1 SBASE(X,8)=-1 End If If MBASE(M,8)=255 SBASE(X,8)=-1 End If End If End If EOYC: If SBASE(X,7)<0 SPRCOL[2,SBASE(X,3),SBASE(X,4),1] If SPRCOLLIDE=-1 SBASE(X,7)=0 If MBASE(M,8)=0 MBASE(M,3)=SBASE(X,3)+1 SBASE(X,7)=1 Goto EOXC End If If MBASE(M,8)=255 SBASE(X,7)=1 End If End If End If If SBASE(X,7)>0 SPRCOL[2,SBASE(X,3),SBASE(X,4),3] If SPRCOLLIDE=-1 SBASE(X,7)=0 If MBASE(M,8)=0 MBASE(M,3)=SBASE(X,3)-1 SBASE(X,7)=-1 End If If MBASE(M,8)=255 SBASE(X,7)=-1 End If End If End If EOXC: End If End If 'we are now checking player and monster fireballs If SBASE(X,13)=2 'if the fireball is switched on If SBASE(X,2)=255 'a shortened version of the sprite to playfield routine which checks 'point values of the playfield mask on screen 2 Screen 2 'based on the sprites x an y position, check the very middle of the 16x16 'sprite to detect if the point value at that co-ordinate is >0 If Point((SBASE(X,3)+8),(SBASE(X,4)+8))>0 'and if it is, switch the projectile off and switch off the flag in the 'SBASE of the sprite that fired it, which denotes that sprite can fire 'again SBASE(X,2)=0 SBASE(SBASE(X,12),12)=0 End If Screen 0 End If End If Next X End Proc Procedure SPRCOL[SPRNUM,SPRX,SPRY,SPRDIR] 'a routine to test if a sprite has collided with the playfield mask held 'on screen 2. 'Parameters are: 'SPRNUM - The sprite you want to test in terms of SBASE index 'SPRX - The X position of the sprite you want to test 'SPRY - The Y position of the sprite you want to test 'SPRDIR - The direction you want to test in ' 'SPRCOLLIDE is a global variable that is set to 0 at the 'start of this routine and is set to -1 if a collision is detected SPRCOLLIDE=0 Screen 2 'determine what direction we want to test in, in this case up If SPRDIR=0 'test three points on playfield mask to denote the top left, top middle 'and top right of the sprite to see if any of them are greater than zero '*NB: These points map a hitbox square location inside the 16x16 sprite box 'This is because if you test EXACT top left, top middle, top right it is 'difficult for the player to manouver through single space gaps on the map 'Monsters are bounced back one pixel when they collide to line them up on 'the grid in the AUTOCOL routine If Point(SPRX+2,SPRY+1)>0 or Point(SPRX+8,SPRY+1)>0 or Point(SPRX+13,SPRY+1)>0 'if the test results in a collision, set SPRCOLLIDE to -1 to be read by code 'after this routine call. I choose this method of passing back a variable 'instead of returning a Param as it is cited as being significantly faster 'and I did notice a differance in game speed SPRCOLLIDE=-1 End If End If 'we now test the other directions and resume comments after If SPRDIR=1 If Point(SPRX+1,SPRY+2)>0 or Point(SPRX+1,SPRY+8)>0 or Point(SPRX+1,SPRY+13)>0 SPRCOLLIDE=-1 End If End If If SPRDIR=2 If Point(SPRX+2,SPRY+15)>0 or Point(SPRX+8,SPRY+15)>0 or Point(SPRX+13,SPRY+15)>0 SPRCOLLIDE=-1 End If End If If SPRDIR=3 If Point(SPRX+15,SPRY+2)>0 or Point(SPRX+15,SPRY+8)>0 or Point(SPRX+15,SPRY+13)>0 SPRCOLLIDE=-1 End If End If Screen 0 End Proc Procedure S2SCOL 'a routine to test collisions between player, monsters, swords and 'fireballs 'we are checking to see if the 'Player has been attacked' timer is greater 'than zero and decreasing it if so. this prevents monsters draining HP 'like collisions in turrican and gives our player a short window of 'temporary invincability If SBASE(0,10)>0 Dec SBASE(0,10) End If 'and same for p2 If SBASE(3,10)>0 Dec SBASE(3,10) End If 'and same for the monsters! 'iterate a loop 6 times in range 6 to 11 For X=6 To 11 If SBASE(X,10)>0 Dec SBASE(X,10) End If Next X 'time to start collision checking for player 1. these checks are repeated 'later in the routine for player 2 and won't be commented 'if player one is acive If SBASE(0,2)=255 'check for a sprite collision between sprite number 8 (SBASE index 0) and 'sprite range 44-50 (SBASE index 17-21). this checks to see if the player 'has collided with a pick-up If Sprite Col(8,44 To 50)=-1 'so we know there is a collision. how to we obtain index number of the 'sprite player collided with? HERE'S HOW! 'set up some variables for our loop T=44 MTC=0 'this loop will find the sprite number Repeat 'increment value of T Add T,2 'check to see if the col function returns a true arguement against sprite 'number held in T C=Col(T) 'if C=-1 then T holds the value of the sprite player collided with Until C=-1 'set up some more variables for another loop MTC=0 SPR=17 'this loop will find the SBASE index of the collided sprite Repeat 'we check SBASE positions 18 through 21 until Y AXIS 0 = T 'then flag MTC=-1 to end the loop Inc SPR If SBASE(SPR,0)=T : MTC=-1 : End If Until MTC=-1 'at this point, variable SPR holds the index in SBASE we need to manipulate 'and variable T holds the sprite number we collided with 'so we are going to test the value in SBASE of SPR,6 to see what sub-type 'of pick up we have. this is placed in SBASE by the MAKEPICKUP routine 'the pickup is a coin If SBASE(SPR,6)=0 Add P1SC,250 Add P1CC,1 End If 'the pickup is a diamon If SBASE(SPR,6)=1 Add P1SC,500 Add P1CC,2 End If 'the pickup is a treasurebox If SBASE(SPR,6)=2 Add P1SC,1000 Add P1CC,3 End If 'the pickup is a heart for extra health If SBASE(SPR,6)=3 Add P1SC,2500 Add P1HP,10 'make sure we don't overfill on health If P1HP>62 P1HP=62 End If End If 'the pickup is a mana potion If SBASE(SPR,6)=4 Add P1SC,2500 Add P1MP,10 'make sure we don't overfill on mana If P1MP>62 P1MP=62 End If End If 'this pickup is an extra life If SBASE(SPR,6)=5 Add P1SC,5000 Inc P1UP 'limit extra lives to 3. 3 IS ENOUGH. If P1UP>3 P1UP=3 End If End If 'now we simply switch off the pickup sprite SBASE(SPR,2)=0 'and update the HUD infor to update score, hp, mana, lives ETCETERA BLITHUDINFO End If 'so that's the good collisions out of the way, now it's time to check if we 'run into anything NASTY 'so, we again check sprite 8 this time against range 20 to 42, which is 'SBASE index 6 to 17 covering all monsters and monster fireballs If Sprite Col(8,20 To 42)=-1 'and if true we need to find out the name of the dog that bit us, so again 'we are using the little Repeat Until loop to determine SPR, the SBASE index 'and T, the sprite number T=18 MTC=0 Repeat Add T,2 C=Col(T) Until C=-1 MTC=0 SPR=5 Repeat Inc SPR If SBASE(SPR,0)=T : MTC=-1 : End If Until MTC=-1 'now if the sprite number is less than 32 it means we collided with a 'monster and not a fireball If T<32 'these checks will reverse the monster direction. at this point, the 'monster is outside of it's defined movement channel parameters. this means 'it will flee on an opposite movement vector until it hits something else, 'most likely a wall which will reset the movement routine If SBASE(SPR,7)=1 SBASE(SPR,7)=-1 Goto EXC End If If SBASE(SPR,7)=-1 SBASE(SPR,7)=1 End If EXC: If SBASE(SPR,8)=1 SBASE(SPR,8)=-1 Goto EXY End If If SBASE(SPR,8)=-1 SBASE(SPR,8)=1 End If EXY: 'we are checking here to determine is the player CAN be hit. if invincable 'the collision will do no damage If SBASE(0,10)=0 'if they are not invincable, we decrease the HP and set an invincable delay SBASE(0,10)=25 Add P1HP,-2 'and blit the HUD info to indicate a reduction in HP BLITHUDINFO End If End If 'and if it's greate than 30 then we got hit by a fireball and not a monster If T>30 'we'll need to find out if we can deflect the fireball with our shield 'based on if we are facing the fireball 'so set a deflect flag variable to 0 D=0 'and we are checking the direction the fireball was moving in, in this case 'was it moving right across the screen? If SBASE(SPR,7)=3 'if it was moving right, is our player facing to the left? we know because 'we have the value of the last recorded player input in P1IN If P1IN=1 or P1IN=5 'so if we were facing left, reverse the movement of the fireball, increase 'the player score and set our deflect flag to 255 for yes SBASE(SPR,7)=-3 Add P1SC,10 D=255 Goto EXCM End If End If 'now lets check the other directions the fireball might be moving in against 'player input, perform the same operations and resume comments at the end of 'checks If SBASE(SPR,7)=-3 If P1IN=4 or P1IN=8 SBASE(SPR,7)=3 Add P1SC,10 D=255 End If End If EXCM: If SBASE(SPR,8)=3 If P1IN=1 or P1IN=5 SBASE(SPR,8)=-3 Add P1SC,10 D=255 Goto EXYM End If End If If SBASE(SPR,8)=-3 If P1IN=2 or P1IN=6 SBASE(SPR,8)=3 Add P1SC,10 D=255 End If End If EXYM: 'if we did not manage to deflect the fireball (D=0) the fireball will 'damage the player If D=0 'decrease the HP Add P1HP,-4 'switch off the fireball SBASE(SPR,2)=0 'set the fired flag on the sprite that fired the fireball back to 0 so 'they can fire again SBASE(SBASE(SPR,12),12)=0 End If 'update our HUD to show the decrease in health BLITHUDINFO End If End If 'now it's time to detect if our sword has hit a monster If Sprite Col(10,20 To 30)=-1 'our little routine to determine sprite index and number of the monster 'the sword hit T=18 MTC=0 Repeat Add T,2 C=Col(T) Until C=-1 MTC=0 SPR=5 Repeat Inc SPR If SBASE(SPR,0)=T : MTC=-1 : End If Until MTC=-1 'let's make sure our monster doesn't have invincability active If SBASE(SPR,10)=0 'and if not 'set a short pause on monster movement by setting a timer MBASE(SPR-5,1)=15 'and switching off the moving flag MBASE(SPR-5,7)=0 'and switching off the movement vectors in SBASE SBASE(SPR,7)=0 SBASE(SPR,8)=0 'and decrease the monster's health Add SBASE(SPR,11),-1 'now we'll check if the monster has any health left If SBASE(SPR,11)>0 'and if it does 'set an invicability timer SBASE(SPR,10)=20 'set the sprite image to be a white flash so the player knows 'their hit landed SBASE(SPR,5)=SBASE(SPR,6)+59 'and if we have hit the dragon, theirs a differant formula for 'determining the flash image If SBASE(SPR,6)=9 SBASE(SPR,5)=76 End If End If 'if the monster doesn't have any health left If SBASE(SPR,11)=0 'increase the player score, increase the player kill count, decrease 'the number of monsters left onscreen Add P1SC,SBASE(SPR,6)*25 Inc P1KC Dec NUM_MON 'update our HUD to show increased score BLITHUDINFO 'define an animation for the death of our monster ANIDEF[SPR,1,58,2,4,58,59,2] 'switch off the movement routine MBASE(SPR-5,0)=0 'find out if we should make a pick up at the monsters location MAKEPICKUP[SBASE(SPR,3),SBASE(SPR,4)] End If End If End If 'now we test to see if our fireball hit a monster If Sprite Col(12,20 To 30)=-1 T=18 MTC=0 'same loops to find out index and sprite numbers Repeat Add T,2 C=Col(T) Until C=-1 MTC=0 SPR=5 Repeat Inc SPR If SBASE(SPR,0)=T : MTC=-1 : End If Until MTC=-1 'switch off player fireball SBASE(2,2)=0 SBASE(2,12)=0 'switch off the flag that indicates player can't fire SBASE(0,12)=0 'set a delay timer for the movement routine of the monster we hit MBASE(SPR-5,1)=15 'switch off the mmonster moving flag MBASE(SPR-5,7)=0 'switch off movement vectors for the monster SBASE(SPR,7)=0 SBASE(SPR,8)=0 'decrease the monsters health Add SBASE(SPR,11),-1 'if the monster has health left If SBASE(SPR,11)>0 'flashing the monster white SBASE(SPR,5)=SBASE(SPR,6)+59 'extra check if we hit the dragon If SBASE(SPR,6)=9 SBASE(SPR,5)=76 End If End If 'if the monster has no health left If SBASE(SPR,11)=0 'increase score, kill counter, decrease number of monsters Add P1SC,SBASE(SPR,6)*25 Inc PIKC Dec NUM_MON 'bit the HUD to show increase in score BLITHUDINFO 'define a death animation for the monster ANIDEF[SPR,1,58,2,4,58,59,2] 'switch of the movement routine MBASE(SPR-5,0)=0 'see if we should make a pick up MAKEPICKUP[SBASE(SPR,3),SBASE(SPR,4)] End If End If End If 'now we are going to do all the above but this time checking player '2 and comments will resume after those checks If SBASE(3,2)=255 If Sprite Col(14,44 To 50)=-1 T=44 MTC=0 Repeat Add T,2 C=Col(T) Until C=-1 MTC=0 SPR=17 Repeat Inc SPR If SBASE(SPR,0)=T : MTC=-1 : End If Until MTC=-1 If SBASE(SPR,6)=0 Add P2SC,250 Add P2CC,1 End If If SBASE(SPR,6)=1 Add P2SC,500 Add P2CC,2 End If If SBASE(SPR,6)=2 Add P2SC,1000 Add P2CC,3 End If If SBASE(SPR,6)=3 Add P2SC,2500 Add P2HP,10 If P2HP>62 P2HP=62 End If End If If SBASE(SPR,6)=4 Add P2SC,2500 Add P2MP,10 If P2MP>62 P2MP=62 End If End If If SBASE(SPR,6)=5 Add P2SC,5000 Inc P2UP If P2UP>3 P2UP=3 End If End If SBASE(SPR,2)=0 BLITHUDINFO End If If Sprite Col(14,20 To 42)=-1 T=18 MTC=0 Repeat Add T,2 C=Col(T) Until C=-1 MTC=0 SPR=5 Repeat Inc SPR If SBASE(SPR,0)=T : MTC=-1 : End If Until MTC=-1 If T<32 If SBASE(SPR,7)=1 SBASE(SPR,7)=-1 Goto EXCP2 End If If SBASE(SPR,7)=-1 SBASE(SPR,7)=1 End If EXCP2: If SBASE(SPR,8)=1 SBASE(SPR,8)=-1 Goto EXYP2 End If If SBASE(SPR,8)=-1 SBASE(SPR,8)=1 End If EXYP2: If SBASE(3,10)=0 SBASE(3,10)=25 Add P2HP,-2 BLITHUDINFO End If End If If T>30 D=0 If SBASE(SPR,7)=3 If P2IN=1 or P2IN=5 SBASE(SPR,7)=-3 Add P2SC,10 D=255 Goto EXCMP2 End If End If If SBASE(SPR,7)=-3 If P2IN=4 or P2IN=8 SBASE(SPR,7)=3 Add P2SC,10 D=255 End If End If EXCMP2: If SBASE(SPR,8)=3 If P2IN=1 or P2IN=5 SBASE(SPR,8)=-3 Add P2SC,10 D=255 Goto EXYMP2 End If End If If SBASE(SPR,8)=-3 If P2IN=2 or P2IN=6 SBASE(SPR,8)=3 Add P2SC,10 D=255 End If End If EXYMP2: If D=0 Add P2HP,-4 SBASE(SPR,2)=0 SBASE(SBASE(SPR,12),12)=0 End If BLITHUDINFO End If End If If Sprite Col(16,20 To 30)=-1 T=18 MTC=0 Repeat Add T,2 C=Col(T) Until C=-1 MTC=0 SPR=5 Repeat Inc SPR If SBASE(SPR,0)=T : MTC=-1 : End If Until MTC=-1 If SBASE(SPR,10)=0 MBASE(SPR-5,1)=15 MBASE(SPR-5,7)=0 SBASE(SPR,7)=0 SBASE(SPR,8)=0 Add SBASE(SPR,11),-1 If SBASE(SPR,11)>0 SBASE(SPR,10)=20 SBASE(SPR,5)=SBASE(SPR,6)+59 If SBASE(SPR,6)=9 SBASE(SPR,5)=76 End If End If If SBASE(SPR,11)=0 Add P2SC,SBASE(SPR,6)*25 Inc P2KC Dec NUM_MON BLITHUDINFO ANIDEF[SPR,1,58,2,4,58,59,2] MBASE(SPR-5,0)=0 MAKEPICKUP[SBASE(SPR,3),SBASE(SPR,4)] End If End If End If If Sprite Col(18,20 To 30)=-1 T=18 MTC=0 Repeat Add T,2 C=Col(T) Until C=-1 MTC=0 SPR=5 Repeat Inc SPR If SBASE(SPR,0)=T : MTC=-1 : End If Until MTC=-1 SBASE(5,2)=0 SBASE(5,12)=0 SBASE(3,12)=0 MBASE(SPR-5,1)=15 MBASE(SPR-5,7)=0 SBASE(SPR,7)=0 SBASE(SPR,8)=0 Add SBASE(SPR,11),-1 If SBASE(SPR,11)>0 SBASE(SPR,5)=SBASE(SPR,6)+59 If SBASE(SPR,6)=9 SBASE(SPR,5)=76 End If End If If SBASE(SPR,11)=0 Add P2SC,SBASE(SPR,6)*25 Inc P2KC Dec NUM_MON BLITHUDINFO ANIDEF[SPR,1,58,2,4,58,59,2] MBASE(SPR-5,0)=0 MAKEPICKUP[SBASE(SPR,3),SBASE(SPR,4)] End If End If End If End Proc Procedure MAKEPICKUP[SPRX,SPRY] 'this routine determines if a pickup should be created and what the 'pickup should be and it's position in SBASE ' 'Parameters are: 'SPRX: X position to make a pickup 'SPRY: Y position to make a pickup ' 'local variable set to zero to determine which slot to place a pickup 'in the SBASE if we decide to make a pickup S=0 'iterate through SBASE index range 18 to 21 and check value of Y AXIS 2 'to see if the slot is free. Pickups are created in reverse order as a result 'using index 21 first For X=18 To 21 If SBASE(X,2)=0 Then S=X Next X 'so if a free slot was located, S is now equal to the index number of where 'we will place the info If S>0 'let's randomise! 'first - shall we make a pickup at all? 50/50 chance PU=Rnd(1) If PU=1 'what sort of pickup shall we make? PU=Rnd(99) '80% chance is a treasure type pickup If PU<80 '0=coin, 1=diamond, 3=treasure PC=Rnd(2) End If '20% chance it's a powerup If PU>79 and PU<99 '4=health, 5=mana PC=Rnd(1)+3 End If '1% chance it's an 1UP If PU=99 PC=5 End If 'fill our chosen SBASE index with details about the pickup SBASE(S,2)=255 SBASE(S,3)=SPRX SBASE(S,4)=SPRY SBASE(S,6)=PC 'define a long animation with first frame of pickup image for 8 seconds 'that auto switches off with second frame a blank image only lasting for 'a single game loop ANIDEF[S,1,PC+68,1,400,PC+68,41,2] End If End If End Proc Procedure PAUSE 'routine to handle pressing the 'p' key during play. places a "Paused" 'message onscreen and repeats until key state of 'P' key is pressed 'again Sprite Off Put Block 7,0,128 Wait 25 Repeat Until Key State(25) BLITSCREEN[0] End Proc Procedure KEYINPUT 'routine to check two keypresses, 'P' for pause and 'ESC' for quit If Key State(69) Then QUIT If Key State(25) Then PAUSE End Proc Procedure INITGAME 'routine to initate the game 'run TE routine to fill TE$ array with letters TE 'load our sprite data and make a mask so sprite collision is not all blocky 'and crap Load "dat0.obj",1 Make Mask 'load our icons for HUD and playfield Load "dat0.blx",2 'make a mask for the heart icon Make Icon Mask 31 'iterate a loop range 1 to 11 to load map data into memory banks For QX=1 To 11 'the routine to load data into a bank LODBANK["map",QX,".dpk",QX+9] Next QX 'load our default template SBASE data LODBANK["sbase",0,".dpk",30] 'load the title image - by cesarloose Ppload "img1.dpk",23 'load up our music - by TobbX Ppload "mus1.dpk",40 Ppload "mus2.dpk",41 Ppload "mus3.dpk",42 Ppload "mus4.dpk",43 'open up our sequential highscore data file and read it into 'HSCORE$ array Open In 1,"hsc0.dat" For Y=0 To 8 For X=0 To 1 Input #1,I$ HSCORE$(X,Y)=I$ Next X Next Y Close 1 'sort our colours out Get Icon Palette : Get Sprite Palette 'get some cblocks Hide : Get Cblock 21,0,16,320,240 'do some setup on screen 1 & 2 Screen 1 : Put Cblock 21 : Get Icon Palette : Get Sprite Palette Screen 2 : Put Cblock 21 : Colour 1,$0 : Colour 2,$FFF End Proc Procedure INITLEVEL 'randomise the locations in our level 'start some music Track Play 41 'iterate a loop through range 0 to 11 For X=0 To 11 'and within that loop iterate another loop range 0 to 11 For Y=0 To 11 'fill our LAMP array with value 1 in Z AXIS 0, and value 0 in Z AXIS 1 LMAP(X,Y,0)=1 LMAP(X,Y,1)=0 Next Y Next X 'increase the LEVZ variable. game initialises with this set to zero so we want it to be 1 on first run and increased each level after that Inc LEVZ 'check our level isn't higher than 9, if it is, warp back to level 1 If LEVZ>9 Then LEVZ=1 'iterate a loop through range 1 to 10 For X=1 To 10 'and within that loop iterate another loop through range 1 to 10 For Y=1 To 10 'generate a random number between 1 and 9 XRND=Rnd(8)+1 'set the current position in our LMAP array to the random number LMAP(X,Y,0)=XRND Next Y Next X 'generate a random start position XRND=Rnd(9)+1 YRND=Rnd(9)+1 'set the start position in LMAP array LMAP(XRND,YRND,0)=0 LMAP(XRND,YRND,1)=1 LEVX=XRND LEVY=YRND 'generate a random exit position XRND=Rnd(9)+1 YRND=Rnd(9)+1 'set the exit position in LAMP array LMAP(XRND,YRND,0)=10 LMAP(XRND,YRND,1)=2 'initate a monster wave INITWAVE End Proc Procedure INITWAVE 'this routine generates a random wave of monsters. there can be one type of 'between 1-6 monsters, or two types of 3 monsters generated 'firstly, make sure the SBASE, ABASE and MBASE entries for the monsters 'are reset to zero 'using this loop iterating between range 6 to 11 For X=6 To 11 SPRDEF[X,0,0,0,0,0,0,0,0,0,0,0,0] ABASE(X,0)=0 MOVEDEF[X-5,0,0,0,0,0,0,0,0,0] Next X 'make sure we are not trying to initiate a wave on the exit room, we'll 'handle that seperately because we'll create a dragon there If LMAP(LEVX,LEVY,0)<10 'if there are no dragons lurking.... 'heres our routine to randomly generate the type of wave NT=Rnd(1)+1 NM=Rnd(5)+1 If NT=2 : NM=3 : End If If NT=2 : NM=6 : End If 'and this loop will determine random start positions on the playfield for 'monsters to start and define a sprite with that start position and health 'of 1 + the current LEVZ value. 2 health level 1, 3 health level 2 etc For X=1 To NM Repeat XRND=1+Rnd(17) YRND=2+Rnd(12) Until MAP(XRND+1,YRND+1)=0 SPRDEF[5+X,0,255,XRND*16,YRND*16,0,0,0,0,0,0,1+LEVZ,0] Next X 'now we randomise the type on monster to be on screen MTA=Rnd(7)+1 MTB=Rnd(7)+1 'and set that value in the SBASE For X=1 To NM SBASE(5+X,6)=MTA Next X If NT=2 For X=1 To NM SBASE(8+X,6)=MTB Next X End If 'now we define animation and movement routines based on what monsters 'we have created by iterating through SBASE monster locations, checking 'to see if the sprite has been activated and what type has been set in 'previous loops For X=1 To 6 If SBASE(X+5,2)=255 'definitions for a SLIME If SBASE(5+X,6)=1 SBASE(5+X,5)=42 ANIDEF[5+X,1,42,3,3,42,43,0] MOVEDEF[X,255,50,50,0,0,1,0,0,0] End If 'definitions for a CAVEMAN If SBASE(5+X,6)=2 SBASE(5+X,5)=44 ANIDEF[5+X,1,44,6,6,44,45,0] MOVEDEF[X,255,50,50,0,0,3,0,0,0] End If 'definitions for a SKELETON If SBASE(5+X,6)=3 SBASE(5+X,5)=46 ANIDEF[5+X,1,46,6,6,46,47,0] MOVEDEF[X,255,50,0,0,0,3,0,0,0] End If 'definitions for a BAT If SBASE(5+X,6)=4 SBASE(5+X,5)=48 ANIDEF[5+X,1,48,6,6,48,49,0] MOVEDEF[X,255,50,0,0,0,0,0,0,255] End If 'definitions for an ENT If SBASE(5+X,6)=5 SBASE(5+X,5)=50 ANIDEF[5+X,1,50,6,6,50,51,0] MOVEDEF[X,255,50,200,0,0,2,255,0,0] End If 'definitions for a BEHOLDER If SBASE(5+X,6)=6 SBASE(5+X,5)=52 ANIDEF[5+X,1,52,6,6,52,53,0] MOVEDEF[X,255,50,0,0,0,0,255,0,255] End If 'definitions for a DEVIL If SBASE(5+X,6)=7 SBASE(5+X,5)=54 ANIDEF[5+X,1,54,6,6,54,55,0] MOVEDEF[X,255,50,50,0,0,3,255,0,0] End If 'definitions for a SMALL DRAGON If SBASE(5+X,6)=8 SBASE(5+X,5)=56 ANIDEF[5+X,1,56,6,6,56,57,0] MOVEDEF[X,255,50,0,0,0,3,255,0,0] End If End If Next X 'set the NUM_MON variable to the total numbers we created in this wave NUM_MON=NM End If 'but, if we are on the exit/boss area If LMAP(LEVX,LEVY,0)=10 'build the dragon NUM_MON=1 'with a random start position Repeat XRND=1+Rnd(17) YRND=2+Rnd(12) Until MAP(XRND+1,YRND+1)=0 'play the boss music Track Play 42 'define the sprite, it's animations and movement routines SPRDEF[6,0,255,XRND*16,YRND*16,75,9,0,0,0,0,6*LEVZ,0] ANIDEF[6,1,75,2,2,75,77,0] MOVEDEF[1,255,50,0,0,0,0,255,0,255] End If End Proc Procedure MOVEDEF[X,A,B,C,D,E,F,G,H,I] 'this routine defines a movement routine in MBASE 'the parameters are outlined in detail at the top of the code MBASE(X,0)=A MBASE(X,1)=B MBASE(X,2)=C MBASE(X,3)=D MBASE(X,4)=E MBASE(X,5)=F MBASE(X,6)=G MBASE(X,7)=H MBASE(X,8)=I End Proc Procedure AUTOMOVE 'this routine automatically moves monsters if their movement routine 'is active 'first iterate a loop through range 1 to 6 For X=1 To 6 'check to see if the movement channel is active If MBASE(X,0)=255 'check to see if the timer is active If MBASE(X,1)>0 'and if so, decrease it Dec MBASE(X,1) End If 'check to see if the timer is sat at zero If MBASE(X,1)=0 'check to see if the monster is currently moving If MBASE(X,7)=0 'if it isn't, we need to set it moving, first check to see if it is a 'roaming type monster If MBASE(X,8)=0 'if it is, let's set the moving flag to 255 MBASE(X,7)=255 'set the X & Y destinations in the movement routine to equal the current 'X and Y position in the SBASE - effectively zeroing the movement MBASE(X,3)=SBASE(X+5,3) MBASE(X,4)=SBASE(X+5,4) 'now we random define a direction DR=Rnd(3) 'let's check to see what direction we have selected and then set our 'destination co-ords based on MBASE 5*16 and set the movement vector 'in SBASE to get our sprite moving If DR=0 : MBASE(X,4)=SBASE(X+5,4)-MBASE(X,5)*16 : SBASE(X+5,8)=-1 : End If If DR=1 : MBASE(X,3)=SBASE(X+5,3)-MBASE(X,5)*16 : SBASE(X+5,7)=-1 : End If If DR=2 : MBASE(X,4)=SBASE(X+5,4)+MBASE(X,5)*16 : SBASE(X+5,8)=1 : End If If DR=3 : MBASE(X,3)=SBASE(X+5,3)+MBASE(X,5)*16 : SBASE(X+5,7)=1 : End If End If 'if our monster movement type is defined as being a bouncer If MBASE(X,8)=255 'set the movement on MBASE(X,7)=255 'define our movemetn vector as diagonal and heading to top left 'NB*: our destination co-ords will be defined as 0,0 which is a location 'bouncers cannot reach, so their movement will continue indefinitely SBASE(X+5,7)=-1 SBASE(X+5,8)=-1 End If End If 'if the sprite is moving If MBASE(X,7)=255 'let's check to see if it has reached it's destination If SBASE(X+5,3)=MBASE(X,3) and SBASE(X+5,4)=MBASE(X,4) 'if so let's just double check it's not a bouncer (we know it isn't) If MBASE(X,8)=0 'and switch off our movement routine. we have now completed a routine 'and we need to reset the timers based on whatever we defined as the 'pause which depends on what monster type it is MBASE(X,7)=0 MBASE(X,1)=MBASE(X,2) 'also switch off the movement vector in the SBASE SBASE(X+5,7)=0 SBASE(X+5,8)=0 End If End If End If End If End If Next X End Proc Procedure AUTOFIRE 'this routine handles automatic firing of fireballs by our monsters 'iterate a loop through range 1 to 6 For M=1 To 6 'set a cheeky variable to hold the SBASE index that corresponds to our 'selected movement routine X=M+5 'check to see if the movement channel is active If MBASE(M,0)=255 'check to see if the movement routine indicates the monster can fire If MBASE(M,6)=255 'if it can, check corresponding SBASE entry to see if the monster is 'free to fire If SBASE(X,12)=0 'if it is, let's find out if the monster wants to fire 'NB* if we don't do this the monster fires continuously and makes 'the game far too difficult FB=Rnd(99) '1% chance of firing. sounds very slim but as you'll see when you play the 'game i think it creates a reasonably fair challenge If FB=1 'randomise what direction we want to fire in FDIR=Rnd(3) 'based on the result, in this case up If FDIR=0 'define a sprite for our fireball SPRDEF[X+6,0,255,SBASE(X,3),SBASE(X,4),18,0,0,-3,0,0,0,X] 'if the monster firing is a dragon, create two additional fireballs at angle 'to the first If SBASE(X,6)=9 SPRDEF[X+7,0,255,SBASE(X,3),SBASE(X,4),18,0,-1,-3,0,0,0,X] SPRDEF[X+8,0,255,SBASE(X,3),SBASE(X,4),18,0,1,-3,0,0,0,X] End If End If 'step through all the directions we could have selected to create fireballs 'and resume comments after If FDIR=1 SPRDEF[X+6,0,255,SBASE(X,3),SBASE(X,4),18,0,-3,0,0,0,0,X] If SBASE(X,6)=9 SPRDEF[X+7,0,255,SBASE(X,3),SBASE(X,4),18,0,-3,-1,0,0,0,X] SPRDEF[X+8,0,255,SBASE(X,3),SBASE(X,4),18,0,-3,1,0,0,0,X] End If End If If FDIR=2 SPRDEF[X+6,0,255,SBASE(X,3),SBASE(X,4),18,0,0,3,0,0,0,X] If SBASE(X,6)=9 SPRDEF[X+7,0,255,SBASE(X,3),SBASE(X,4),18,0,-1,3,0,0,0,X] SPRDEF[X+8,0,255,SBASE(X,3),SBASE(X,4),18,0,1,3,0,0,0,X] End If End If If FDIR=3 SPRDEF[X+6,0,255,SBASE(X,3),SBASE(X,4),18,0,3,0,0,0,0,X] If SBASE(X,6)=9 SPRDEF[X+7,0,255,SBASE(X,3),SBASE(X,4),18,0,3,-1,0,0,0,X] SPRDEF[X+8,0,255,SBASE(X,3),SBASE(X,4),18,0,3,1,0,0,0,X] End If End If 'set the corresponding entry in SBASE to record which fireball was 'fired by which monster SBASE(X,12)=X+6 'define the fireballs animation ANIDEF[X+6,1,18,1,1,18,38,0] End If End If End If End If Next M End Proc Procedure BANKTOMAP[BTM] 'this routine pulls a bank out of memory and writes it into the MAP array 'Parameter: 'BTM: Indicates which bank number to pull IX_ADDR=Start(BTM+10) For X=1 To 20 For Y=1 To 16 MAP(X,Y)=Peek(IX_ADDR) Inc IX_ADDR Next Y Next X End Proc Procedure BANKTOSBASE 'this routine pulls the default SBASE template data from memory and 'writes it into the SBASE array IX_ADDR=Start(30) For X=0 To 21 For Y=0 To 13 SBASE(X,Y)=Peek(IX_ADDR) Inc IX_ADDR Next Y Next X End Proc Procedure LODBANK[LFN$,LFILE,LEXT$,LB] 'this routine loads a ppacked bank into memory 'Parameters: 'LFN$: first part of filename 'LFILE: number 'LEXT$: filename extension 'LB: selected bank to load file into F$=Str$(LFILE) FILE$=LFN$+F$+LEXT$ FILE$=FILE$-" " Ppload FILE$,LB End Proc Procedure CREATE_EXITS 'this routine makes holes in the walls of the playfield and reblits the 'screen to create exits once all the monsters have been killed MAP(10,2)=0 MAP(11,2)=0 MAP(10,16)=0 MAP(11,16)=0 MAP(1,8)=0 MAP(1,9)=0 MAP(20,8)=0 MAP(20,9)=0 BLITSCREEN[0] End Proc Procedure BLITSCREEN[LD] 'this routine paints the main screen 'Parameters: 'LD: 0 for refresh, -1 to change colour of playfield icons 'if LD was -1 then run the routine to randomise colour's 1 & 2 If LD=-1 : RICONCOLOUR : End If 'select screen 2, clear it with a cblock and define colour 1 as white Screen 2 : Put Cblock 21 : Colour 1,$FFF : Ink 1 'iterate through the MAP array For Y=0 To 15 For X=0 To 19 'if the map is a wall If MAP(X+1,Y+1)>0 'paint a white block for our playfield mask Bar X*16,Y*16 To X*16+16,Y*16+16 End If Next X Next Y 'switch to main screen and clear it with a cblock Screen 0 : Put Cblock 21 'setup a colour, not sure why on this one, probably couldn't be arsed 'to redo my graphics with a palette change after i made a mistake on 'colour selection Colour 10,$111 'set the font again - if I do keep doing this the font keeps defaulting Set Font 1 'iterate through the MAP array For Y=1 To 15 For X=0 To 19 'firstly, paste a floor icon Paste Icon X*16,Y*16,16 'secondly paste any wall icons If MAP(X+1,Y+1)>0 Paste Icon X*16,Y*16,MAP(X+1,Y+1) End If Next X Next Y switch to screen 1 and clear it Screen 1 Cls 0 'iterate through the LMAP array and paint icons based on the 1 Z AXIS 'this is painting the radar on the screen For Y=1 To 11 For X=1 To 11 If LMAP(X,Y,1)=0 : Paste Icon X*4+32,Y*4+32,17 : End If If LMAP(X,Y,1)=1 : Paste Icon X*4+32,Y*4+32,18 : End If If LMAP(X,Y,1)=2 : Paste Icon X*4+32,Y*4+32,19 : End If Next X Next Y 'back to screen zero and copy the area surrounding the current player 'location into the HUD area at the top of the screen Screen 0 Screen Copy 1,LEVX*4+28,LEVY*4+28,LEVX*4+41,LEVY*4+41 To 0,145,1 'now paint the HUD BLITHUD End Proc Procedure BLITHUD 'this routine paints the background graphics of the HUD using icons IND=20 Paste Icon 0,0,20 Paste Icon 160,0,30 For X=1 To 7 Paste Icon X*16,0,IND+X Paste Icon X*16+160,0,IND+X Next X Paste Icon 304,0,LEVZ+31 BLITHUDINFO End Proc Procedure BLITHUDINFO 'this routine paints the information onto the HUD regarding score, 'HP, MP, Lives for player one and player two Set Font 1 'blank out all areas on the HUD Ink 0 : Bar 32,2 To 94,4 Ink 0 : Bar 120,8 To 142,14 Ink 0 : Bar 280,8 To 302,14 Ink 0 : Bar 192,2 To 254,4 Ink 0 : Bar 32,10 To 94,12 Ink 0 : Bar 192,10 To 254,12 Ink 0 : Bar 98,1 To 142,7 Ink 0 : Bar 258,1 To 302,7 if player one is active If SBASE(0,2)=255 If P1HP>1 : Ink 4 : Bar 32,2 To 32+P1HP,4 : End If If P1MP>1 : Ink 11 : Bar 32,10 To 32+P1MP,12 : End If 'here we a using PADSCORE routine which creates a text string of the 'players score with leading zeros added so it looks all arcadey PADSCORE[P1SC] : Ink 3,0 : Text 98,5,Param$ If P1UP>0 For X=1 To P1UP Paste Icon X*8+113,9,31 Next X End If End If 'do the same business for player two if switched on - comments to continue 'afterwards If SBASE(3,2)=255 If P2HP>1 : Ink 4 : Bar 192,2 To 192+P2HP,4 : End If If P2MP>1 : Ink 11 : Bar 192,10 To 192+P2MP,12 : End If PADSCORE[P2SC] : Ink 3,0 : Text 258,5,Param$ If P2UP>0 For X=1 To P2UP Paste Icon X*8+273,9,31 Next X End If End If End Proc Procedure SWIPE[SDIR] 'this routine handles the screen wipe animation 'Parameters: 'SDIR: Direction we want to swipe in 'switch off sprites and make sure all pickups are cleared 'if you leave them behind they are gone Sprite Off For X=18 To 21 SBASE(X,2)=0 Next X Ink 0 'depending on the direction of the swipe, in this case up If SDIR=0 'do this animation routine with cblocks to perform the screenwipe effect Get Cblock 22,16,16,288,16 SW=24 Repeat Put Cblock 22,16,SW Bar 17,SW-8 To 303,SW-1 SW=SW+8 Wait Vbl Until SW=240 'then reset player coordinates SBASE(0,3)=144 SBASE(0,4)=224 SBASE(3,3)=160 SBASE(3,4)=224 End If 'do the same process based on the driection selected and comments will 'resume after checks If SDIR=1 Get Cblock 22,0,32,16,208 SW=8 Repeat Put Cblock 22,SW,32 Bar SW-8,33 To SW-1,238 SW=SW+8 Wait Vbl Until SW=304 SBASE(0,3)=288 SBASE(0,4)=112 SBASE(3,3)=288 SBASE(3,4)=128 End If If SDIR=2 Get Cblock 22,16,16,288,16 SW=240 Repeat Put Cblock 22,16,SW Bar 17,SW+16 To 303,SW+24 SW=SW-8 Wait Vbl Until SW=24 SBASE(0,3)=144 SBASE(0,4)=32 SBASE(3,3)=160 SBASE(3,4)=32 End If If SDIR=3 Get Cblock 22,304,32,8,208 SW=296 Repeat Put Cblock 22,SW,32 Bar SW+17,33 To SW+24,238 SW=SW-8 Wait Vbl Until SW=0 SBASE(0,3)=16 SBASE(0,4)=112 SBASE(3,3)=16 SBASE(3,4)=128 End If End Proc Procedure PADSCORE[SCR] 'this routine measures the length of a variable and returns a text string 'carrying the value of that variable, with the length padded out to nine 'characters with leading zeros 'Parameters: 'SCR: Variable value to process 'turn our parameter into a string SCR$=Str$(SCR) 'remove any spaces SCR$=SCR$-" " 'work out the length of our string SCR_LEN=Len(SCR$) 'if it is less than 9, then find out how much less If SCR_LEN<9 : SCR_LEN=9-SCR_LEN : End If 'declare a new variable PAD$="" 'iterate a loop through 1 to the total of SCR_LEN and add string "0" 'into PAD$ For X=1 To SCR_LEN PAD$=PAD$+"0" Next X 'our new string is equal to the PAD$ of "0"'s plus the original string 'minus any spaces SCRSTR$=PAD$+SCR$ SCRSTR$=SCRSTR$-" " End Proc[SCRSTR$] Procedure LEVEL_COMPLETE 'this routine declares the level is complete then calculates player 'bonus points and adds them to the score 'switch off sprites and bobs and stop the music Set Font 1 : Ink 3,0 Sprite Off : Bob Off : Track Stop 'let's work out how many rooms the player has visited by checking the 'Z AXIS of LMAP array and incrementing a counter if the result of Z1 is >0 RC=0 For X=0 To 11 For Y=0 To 11 Add RC,LMAP(X,Y,1) Next Y Next X 'now some graphics on the screen Text 127,50,"LEVEL COMPLETE" 'and player columns if the player is active... If SBASE(0,2)=255 Paste Bob 64,64,17 Text 60,80,"BONUS" Paste Bob 16,96,68 Paste Bob 16,112,56 Paste Bob 16,132,78 End If 'same for player two in a differant location If SBASE(3,2)=255 Paste Bob 240,64,37 Text 236,80,"BONUS" Paste Bob 192,96,68 Paste Bob 192,112,56 Paste Bob 192,132,78 End If Wait 50 'now work out what bonuses are appropriate and display them onscreen with 'a little pause in between and comments resume after If SBASE(0,2)=255 P1CCSCR=P1CC*50 PADSCORE[P1CCSCR] T$="X"+Str$(P1CC)+"..."+Param$ Text 36,106,T$ End If If SBASE(3,2)=255 P2CCSCR=P2CC*50 PADSCORE[P2CCSCR] T$="X"+Str$(P2CC)+"..."+Param$ Text 212,106,T$ End If Wait 50 If SBASE(0,2)=255 P1KCSCR=P1KC*50 PADSCORE[P1KCSCR] T$="X"+Str$(P1KC)+"..."+Param$ Text 36,122,T$ End If If SBASE(3,2)=255 P2KCSCR=P2KC*50 PADSCORE[P2KCSCR] T$="X"+Str$(P2KC)+"..."+Param$ Text 212,112,T$ End If Wait 50 If SBASE(0,2)=255 P1RCSCR=RC*50 PADSCORE[P1RCSCR] T$="X"+Str$(RC)+"..."+Param$ Text 36,142,T$ End If If SBASE(3,2)=255 P2RCSCR=RC*50 PADSCORE[P2RCSCR] T$="X"+Str$(RC)+"..."+Param$ Text 212,142,T$ End If Wait 50 If SBASE(0,2)=255 P1TOSCR=P1CCSCR+P1KCSCR+P1RCSCR PADSCORE[P1TOSCR] T$="TOTAL"+"..."+Param$ Text 36,172,T$ End If If SBASE(3,2)=255 P2TOSCR=P2CCSCR+P2KCSCR+P2RCSCR PADSCORE[P2TOSCR] T$="TOTAL"+"..."+Param$ Text 212,172,T$ End If Wait 100 'then add the bonuses to the score If SBASE(0,2)=255 Add P1SC,P1TOSCR End If If SBASE(3,2)=255 Add P1SC,P1TOSCR End If 'reset our player counters P1KC=0 : P1CC=0 : P2KC=0 : P2CC=0 'initiate a new level, wave, draw the screen, start a new level INITLEVEL BANKTOMAP[LMAP(LEVX,LEVY,0)] INITWAVE BLITSCREEN[-1] LEVEL_START GMODE=1 End Proc Procedure GAME_OVER 'this routine handles a game over and high score name entry 'choose a font, ink colours, switch off objects, stop the music Set Font 1 : Ink 3,0 Sprite Off : Bob Off : Track Stop 'generate a text string of players score padded with leading zeros PADSCORE[P1SC] P1SC$=Param$ PADSCORE[P2SC] P2SC$=Param$ 'tell the players the game is over Text 138,50,"GAME OVER" 'now work out if either player has obtained a high score P1HS=-1 P2HS=-1 P1TE=0 P2TE=0 ST=8 'using this little loop that will compare the value of p1 score against 'all values in the HSCORE$ table in reverse order Repeat If P1SC>Val(HSCORE$(1,ST)) P1HS=ST End If Dec ST Until ST=-1 'and if the player has managed to achieve a high score If P1HS>-1 'this variable indicates the amount of characters the player needs to 'enter to finish the high score name P1TE=3 ST=8 'we use this little loop to move the HSCORE$ data down the list 'until we get to the position the player has achieved Repeat If ST>0 HSCORE$(0,ST)=HSCORE$(0,ST-1) HSCORE$(1,ST)=HSCORE$(1,ST-1) End If Dec ST Until ST=P1HS 'then we set that position to equal the players score HSCORE$(0,P1HS)="P 1" HSCORE$(1,P1HS)=P1SC$ End If 'we do the same routines for player two and comments will resume afterwards ST=8 Repeat If P2SC>Val(HSCORE$(1,ST)) P2HS=ST End If Dec ST Until ST=-1 If P2HS>-1 P2TE=3 ST=8 Repeat If ST>0 HSCORE$(0,ST)=HSCORE$(0,ST-1) HSCORE$(1,ST)=HSCORE$(1,ST-1) End If Dec ST Until ST=P2HS HSCORE$(0,P2HS)="P 2" HSCORE$(1,P2HS)=P2SC$ End If 'run this routine to generate a new high score table block and put it 'it on screen HSCRTAB Put Block 5,124,80 Colour 13,$100 'now we let the payer know if they got a high score or if not 'we tell them it's just their final score If NUM_PLAY>0 Paste Bob 64,64,17 Text 50,80,"HIGH SCORE" If P1HS=-1 : Text 46,80,"FINAL SCORE" : End If If P1HS>-1 : Box 68,94 To 76,102 : Text 70,100,"A" : End If Text 50,90,P1SC$ End If 'and same for player two If NUM_PLAY=2 Paste Bob 240,64,37 Text 226,80,"HIGH SCORE" If P2HS=-1 : Text 222,80,"FINAL SCORE" : End If If P2HS>-1 : Box 244,94 To 252,102 : Text 246,100,"A" : End If Text 226,90,P2SC$ End If 'now play the game over music and make sure it is looped as this sequence 'is not auto looped in the module Track Play 43 : Track Loop On 'this variables hold a numeric value of the letter currently displayed in 'the high score entry box P1PNT=0 P2PNT=0 'these empty strings will hold the letters the player enters P1NAM$="" P2NAM$="" 'this little loop will be bypassed if P1TE=0 and P2TE=0 'but if it is higher, it will read the joystick input of P1 and P2 'to cycle through letters using up and down. when the player presses 'firebutton, we will add the contents of TE$(P1PNT) to P1NAM$ to build 'a name string and decrease the number of characters the player needs 'to enter Repeat 'if there are still characters that need to be entered If P1TE>0 'if pressing up If Joy(1)=1 and P1PNT>0 'short pause and then decrease the value of P1PNT and redraw the box and 'which letter is currently selected Wait 10 Dec P1PNT Ink 0 : Bar 68,94 To 76,102 Ink 3,0 : Box 68,94 To 76,102 Text 70,100,TE$(P1PNT) End If 'the same routine for down If Joy(1)=2 and P1PNT<25 Wait 10 Inc P1PNT Ink 0 : Bar 68,94 To 76,102 Ink 3,0 : Box 68,94 To 76,102 Text 70,100,TE$(P1PNT) End If 'and if fire is pressed If Joy(1)=16 and P1TE>0 Wait 10 'build our string P1NAM$=P1NAM$+TE$(P1PNT)-" " Text 64,110,P1NAM$ 'decrease the number of characters to enter Dec P1TE End If End If 'do all the same for player two and comments resume after If P2TE>0 If Joy(0)=1 and P2PNT>0 Wait 10 Dec P2PNT Ink 0 : Bar 244,94 To 252,102 Ink 3,0 : Box 244,94 To 252,102 Text 246,100,TE$(P2PNT) End If If Joy(0)=2 and P2PNT<25 Wait 10 Inc P2PNT Ink 0 : Bar 244,94 To 252,102 Ink 3,0 : Box 244,94 To 252,102 Text 246,100,TE$(P2PNT) End If If Joy(0)=16 and P2TE>0 Wait 10 P2NAM$=P2NAM$+TE$(P2PNT)-" " Text 240,110,P2NAM$ Dec P2TE End If End If Wait Vbl Until P1TE=0 and P2TE=0 'now make changes to the HSCORE$ array if high scores were achieved If P1HS>-1 : HSCORE$(0,P1HS)=P1NAM$ : End If If P2HS>-1 : HSCORE$(0,P2HS)=P2NAM$ : End If 'redraw the highscore table, grab it and repaint it onscreen HSCRTAB Put Block 5,124,80 'set GameMODE back to 0 so we will pop back to title screen after 'this routine GMODE=0 'save our HSCORE$ array as a sequential file Open Out 1,"hsc0.dat" For Y=0 To 8 For X=0 To 1 Print #1,HSCORE$(X,Y) Next X Next Y Close 1 'have a short pause to make sure all is saved and then end routine Wait 200 End Proc Procedure RICONCOLOUR 'this routine generates a random number then sets the colour values of 'colour one and two based on the result. these are the colours used in 'the level wall tiles so we get changing screens of differant colour C=Rnd(6) If C=0 C1=$444 C2=$888 End If If C=1 C1=$400 C2=$800 End If If C=2 C1=$40 C2=$80 End If If C=3 C1=$6 C2=$A End If If C=4 C1=$440 C2=$880 End If If C=5 C1=$404 C2=$808 End If If C=6 C1=$88 C2=$CC End If Colour 1,C1 Colour 2,C2 End Proc Procedure QUIT 'a routine to quit the game. if we are sat at title in GameMODE 0, erase all 'memory banks and end the program 'if we currently playing, just set the GameMODE to 0 and we'll be launched 'back to the title screen If GMODE=0 Erase All End End If If GMODE=1 Then GMODE=0 End Proc