' Experimental software to reproduce the classic Space Invaders game ' For version 2.1 of the PROTON+ BASIC Compiler ' Written by Les Johnson 2003. ' ' This version uses the LCDWRITE and PLOT commands to produce the graphics ' Which allows smooth movements on a pixel by pixel basis ' ' Use an 8MHz crystal ' ' BUTTON CONNECTIONS ' LEFT Button connects to PORTB.0 ' RIGHT Button connects to PORTB.1 ' FIRE Button connects to PORTB.2 ' ' SOUND CHANNEL CONNECTIONS ' Each channel is output from PORTA.0,1,2 ' Channel 1. PORTA.0 is the INVADER noise ' Channel 2. PORTA.1 is the MISSILE noise ' Channel 3. PORTA.2 is the SAUCER noise ' Each pin should have a current limiting resistor in order to stop pin to pin shorts. ' ' 1uF ' 220 +| |- ' PORTA.0 --/\/\/\----| |--- To SPEAKER ' | | | ' 330 | ' PORTA.1 --/\/\/\--| ' | ' 330 | ' PORTA.2 --/\/\/\--| ' ' ' * Revision 1.0 10 September 2003 ' ' Ship moving smoothly and missile working correctly ' ' * Revision 1.1 10 September 2003 ' ' Invaders moving left to right and down (got a problem with alignment when moving down) ' Invaders become faster as they move down ' Invader erased when missile hits, and hit counter incremented ' Bases require five hits per section before they dissapear ' There are 9 sections, three in each base ' A new sheet of invaders is created when all of them are hit ' The new sheet is slightly faster than the previous one ' ' * Revision 1.2 11 September 2003 ' ' Invaders now move down the screen without alignment problems ' Started placing subroutines to enable the invaders to fire back at the ship ' Placed the base hit check as a subroutine so that the invader's missile can also ' be checked for a base hit. ' Invaders can now fire back, but cannot detect any hits yet. ' Both the ship's and the invader's missiles are slowed down but still need some work. ' ' * Revision 1.3 12 September 2003 ' ' Both the ship's and the invaders missiles have independant speed controls ' Invader's missile now detect whether it has hit a base, and alters the base accordingly ' Still a problem with the invader's missile hitting the base, sometimes destroys it with one blow ' Game now detects whether the invaders have reached the bottom of the screen. In which case, GAME OVER ' If the invaders reach the bases, then the bases are disabled ' Invaders now have animated characters ' Bases also have animated characters that destroy with every hit with a missile ' The ship now only moves one pixel at a time instead of two. This slow the ship to a reasonable speed ' The invaders speed up whenever one is hit, and also speed up by a factor of 3 when there are 4 or less invaders left ' Invaders also speed up whenever they move down the screen ' Added simple sound effects when invaders move. This will be altered later. ' ' * Revision 1.4 13 September 2003 ' ' Flying saucer now moves right to left at the top of the screen ' Missile to missile collisions are now detected ' ' * Revision 1.5 14 September 2003 ' ' Missiles are now implemented using the PLOT command for smooth movement ' As the invaders move down the screen their missile speed slows down slightly ' Game now detects a hit on the flying saucer at the top of the screen ' There is still a problem with the invaders and the ship hitting the bases ' The base counter is decremented too quickly, or destroyed with a single hit ' ' * Revision 1.6 18 September 2003 ' ' Added scoring for invaders and saucer ' Invaders score 20 points for top row, 10 points for middle row, and 5 points for bottom row ' Saucer scores 100 points if hit ' A small animation of the points scored is also included if the saucer or invaders are hit. ' Added simple sound effects for invaders, saucer and missile shot. ' ' * Revision 1.7 27 September 2003 ' ' Added second missile for space invaders, but still requires some work ' because the spread of missiles is uneven. ' ' * Revision 1.8 28 September 2003 ' ' Replaced sound using the SOUND command with interrupt driven sounds ' There are three independant sound channels from PORTA0,1,2 ' Each is capable of producing a different frequency, and channel one (INVADER channel) also has a duration. ' With the interrupt driven sound, I have had to increase the crystal to 8MHz. ' Each layer of invader now has a different invader sprite, each consisting of two characters. ' Created new user defined shape for saucer and ship. ' Saucer now scores 100+ points if hit. More points gained the closer to the right hand side of the screen. ' Added levels to the game. After level 10 the invaders start firing two missiles. ' ' * Revision 1.9 01 October 2003 ' ' Invader to Ship missile collision detection is now implemented ' Each time the ship is hit a life is decremented. ' After three lives the game is over. ' Added a splash screen when the game first starts ' ' * Revision 2 04 October 2003 ' ' Score increases by one if a missile hits a missile ' If there are only 1 or 2 invaders left on the screen their speed increases dramatically ' When all the ship's lives are lost, a large circular explosion occurs. ' 'See if thare are any improvements you can make, and report them on the Forum!(written by Les) ' ' ' ' ' ' '* Revision 2.1 18,01,04 by Mark Rodgers ' 'All the changes listed below were done for my own amusement and as an exersise in learning how some 'one else writes their code, and realising that I don't do it properly and will probably not change very 'much, but you never know!. ' 'The program is now far too fat for an 877 so I am using an 18F452 to run it. ' 'Modifications are as follows: '1,Changed initial "SPACE INVADER" screen so "PRESS FIRE TO START" flashes and redraws the splash screen. '2,Added a new screen "HALL OF FAME" with a border, the text toggles between "INVADER HALL OF FAME" and ' "PRESS FIRE TO START GAME" and displays the four highest scores. '3,Changed the "Scoring" screen with a border re-aligned text and toggling "Invader Scoring" and ' "PRESS FIRE To Play Game" text. '4,The game display has been changed to make it easier to see what your status is. When you achieve ' a score better than the lowest high score the points display is inverted to let you know you will ' be in the Hall of Fame! Also if you have a button connected to portb.3 then you can use it to ' PAUSE the game at any time during play, "Game Paused" is displayed on screen, when pressed again ' the game will continue. '5,When the saucer flys accross it prints a space in front of its path to make it easier to see. '6,When you lose all your lives there is now a new "Game Over" screen, it uses the "SPACE INVADER" ' splash screen as a background and has flashing "GAME OVER" and "NEW HIGH SCORE" text. '7,After the "Game Over" screen there is a new screen for entering your name in the "Hall of Fame". 'Your name is entered using the LEFT and RIGHT buttons to change the inverted letter(A to Z) 'and FIRE to select the letter and move to the next one. '8,When you have finished entering your name the display goes to the "HALL OF FAME" display and 'your name is printed in the list with the position highlighted by inversion of the score. '9,There is a bonus screen, if you get to the end of the 10th screen you will see a "Bonus Points" 'screen that shows you how many extra points you have earned, this is calculated by dividing the 'score by ten then multiplying by the number of lives, you are given another life and the bases 'are redrawn to give you a good chance of getting further in the game, now you might understand 'the PAUSE button inclusion!. ' 'I think that is all the changes. I hope you enjoy them and they add to this great game!. 'Notes: '1,I use my own development board based on the information in the help file so all my declares are 'for use with that hardware. '2,I have a 16 button keyboard connected to portb and use line XXX "low portb.7" to select the bottom 'row of keys as the LEFT, RIGHT, PAUSE and FIRE keys. You may need to comment out this line in 'your own system. '3,The SOUND DOES NOT WORK, as I have no idea about assembler and very little knowledge of registers 'I can not make the sound work on the 18F452 so could someone please do it!, I expect it is very 'simple and I look forward to being told so! '4,I have only run the program on an 18F452. '5,The writing of the code is not very efficient but I have tried to make it as logical and easy 'to see what I have done and why. I make no appoligies for my style and blame Sir Clive for 'it as the closest I have come to a programing course was "Sinclair User", a fine publication 'as I remember and an invaluable source for all users of BASIC.(down with the Oric!) '73 de Mark Rodgers G0EBB. 'Include "PROTON_G8.INT" ' Game created on the PROTON board '**************************************************************************************** Device 18F452 'better than an OC71 XTAL 8 '8 million wiggles per second 'hserial_baud 4800 lcd_type graphic 'you may need to change these lcd_dtport portd 'declares to suit your own Hardware lcd_enpin porte.0 ' lcd_cs1pin porte.1 ' lcd_cs2pin porte.2 ' lcd_rspin portc.2 ' lcd_rwpin portc.5 ' internal_font on ' bootloader=off ' 'sda_pin portc.4 'scl_pin portc.3 'slow_bus on'use if xtal=20mhz adcon1=7 'set ports to digita '**************************************************************************************** ' Set up some Variables ' Interrupt driven sound channel variables Dim NOTE_STATUS as Byte SYSTEM Dim INVADER_SOUND_ENABLE as NOTE_STATUS.0 Dim MISSILE_SOUND_ENABLE as NOTE_STATUS.1 Dim SAUCER_SOUND_ENABLE as NOTE_STATUS.2 Dim INTERNAL_INVADER_SOUND_ENABLE as NOTE_STATUS.4 Dim INTERRUPT_COUNTER1 as Byte SYSTEM Dim INVADER_SOUND_COUNTER as Byte SYSTEM Dim INVADER_FREQ as Byte SYSTEM Dim INVADER_SOUND_DURATION as Byte SYSTEM Dim INVADER_SOUND_DURATION_COUNTER as Byte SYSTEM Dim MISSILE_SOUND_COUNTER as Byte SYSTEM Dim MISSILE_FREQ as Byte SYSTEM Dim SAUCER_SOUND_COUNTER as Byte SYSTEM Dim SAUCER_FREQ as Byte SYSTEM ' Space invader variables Dim BASE_ENABLED[9] as Byte ' Whether or not the section of the BASE is enabled Dim BASE_HITS[9] as Byte ' Holds the amount of hits each part of the bases has had Dim INVADER_XPOS[18] as Byte' at 400 ' Array to hold the space invader's X position Dim INVADER_YPOS[18] as Byte' at 418 ' Array to hold the space invader's Y position Dim INVADER_ENABLED[18] as Byte' at 436 ' Array to hold the space invader' config. i.e. hit or active Dim SHIP_XPOS as Byte ' X position of BASE ship Dim MISSILE_YPOS as Byte ' Y position of Ship's MISSILE Dim MISSILE_XPOS as Byte ' X position of Ship's MISSILE Dim MISSILE_STATUS as Byte SYSTEM Dim MISSILE_FIRED as MISSILE_STATUS.0 ' TRUE if Ship's MISSILE in the air Dim MISSILE_HIT as MISSILE_STATUS.1 ' Set if Ship's missile has hit something Dim TIME_TO_MOVE_INVADERS as MISSILE_STATUS.7 ' Indicate time to move the invaders Dim BASE_HIT as MISSILE_STATUS.2 ' Indicates whether a BASE has been hit by a missile Dim TIME_TO_MOVE_SHIP_MISSILE as MISSILE_STATUS.3 ' Indicate time to move the ship's missile Dim TIME_TO_MOVE_BASE as Bit Dim SHIP_SPEED as Byte Dim INVADER_TICK as Byte ' Constant tick within program Dim INVADER_LOOP as Byte SYSTEM ' Scans the invader arrays Dim INVADER_MISSILE_TICK as Byte Dim SHIP_MISSILE_TICK as Byte Dim TEMP_LOOP as Byte Dim INVADERS_DIRECTION as Bit Dim INVADERS_ENABLED as Byte ' Count the INVADERS enabled Dim INVADER_SPEED as Byte ' The speed of the invaders Dim BASE_XPOS_TEST as Byte ' Used for detecting a missile hit on a BASE Dim SHIP_HIT as Bit ' TRUE if ship hit by missile Dim INVADER_MISSILE_YPOS as Byte ' Y position of Invader's MISSILE Dim INVADER_MISSILE_XPOS as Byte ' X position of Invader's MISSILE Dim TIME_TO_MOVE_INV_MISSILE as MISSILE_STATUS.4 ' Indicate time to move the invader's missile Dim INVADER_MISSILE_FIRED as MISSILE_STATUS.5 ' TRUE if Invader's MISSILE in the air Dim INVADER_MISSILE_HIT as MISSILE_STATUS.6 ' Set if Invader's missile has hit something Dim TIME_TO_MOVE_INVADERS_DOWN as Bit ' Signal that the invaders need to move down Dim INVADERS_REACHED_BOTTOM as Bit ' Set if the invaders reach the botton of the screen Dim INVADER_MISSILE_SPEED as Byte ' The speed of the invader's missile. This slows down as invader near the bottom of the screen Dim DEFAULT_INVADER_SPEED as Byte ' Saves the initial speed of the invaders Dim INVADER_CHARACTER as Bit ' Determines the character to use for the invader Dim INVADER_MISSILE2_TICK as Byte Dim INVADER_MISSILE2_YPOS as Byte ' Y position of Invader's second MISSILE Dim INVADER_MISSILE2_XPOS as Byte ' X position of Invader's second MISSILE Dim TIME_TO_MOVE_INV_MISSILE2 as Bit ' Indicate time to move the invader's second missile Dim INVADER_MISSILE2_FIRED as Bit ' TRUE if Invader's second MISSILE in the air Dim INVADER_MISSILE2_HIT as Bit ' Set if Invader's second missile has hit something Dim INVADER_MISSILE2_SPEED as Byte ' The speed of the invader's second missile. This slows down as invader near the bottom of the screen Dim SAUCER_XPOS as Byte Dim SAUCER_HIT as Bit Dim TIME_TO_MOVE_SAUCER as Bit Dim SAUCER_SPEED as Byte Dim SAUCER_ENABLED as Bit Dim SCORE as Dword ' Holds the games score Dim LEVEL as Word ' Game level Dim LIVES as Byte ' Amount of lives left for the base 'variables for modifications done by Mark Rodgers dim high_score1 as dword 'holds high_score number 1 dim high_score2 as dword 'holds high_score number 2 dim high_score3 as dword 'holds high_score number 3 dim high_score4 as dword 'holds high_score number 4 dim flash_count 'used as loop counter in flashing displays dim temp_dword as dword dim saucer_ypos dim position dim character_xposition dim character_yposition dim character_address dim character dim eeprom_address dim name dim name1 dim name2 dim name3 dim name4 dim name5 dim name6 dim name7 dim name8 dim name9 dim name10 dim name11 dim name12 dim name_position dim name_address dim extra_life dim bonus_points as dword dim length as word ' Define some constants and alias's Symbol L_BUTTON = PORTB.0 Symbol R_BUTTON = PORTB.1 Symbol FIRE_BUTTON = PORTB.3 symbol pause_button=portb.2 'Symbol SPEAKER = PORTB.3 Symbol SHIP_WIDTH = 9 ' The width of the ship in pixels. This does not include the two blanks Symbol INVADER_WIDTH = 10 ' The width of the invaders. minus the two outside blanks Symbol INVADER_RIGHT_LIMIT = 127 - INVADER_WIDTH ' The right most limit for the invaders before they need to move down Symbol SAUCER_WIDTH = 14 Symbol TRUE = 1 Symbol FALSE = 0 Symbol FORWARD = 1 Symbol BACKWARD = 0 Symbol T0IF INTCON.2 ' Timer0 Overflow Interrupt Flag Symbol GIE INTCON.7 ' Global Interrupt Enable ON_INTERRUPT Goto NOTE_INT '---------------------------------------------------------------------------- Input L_BUTTON Input R_BUTTON Input FIRE_BUTTON input pause_button Delayms 200 ' Wait for the PICmicro to stabilise PORTB_PULLUPS = ON 'this line allows the bottom 4 buttons of a 16 button keypad to be used as the L,R,pause,Fire low portb.7 Cls ' Clear the LCD Goto MAIN_PROGRAM_LOOP ' Jump over any subroutines '----[NOTE GENERATING INTERRUPT HANDLER]--------------------------------------------------- NOTE_INT: 'TMR0 = 200 Incf INVADER_SOUND_COUNTER,F Incf MISSILE_SOUND_COUNTER,F Incf SAUCER_SOUND_COUNTER,F Incf INTERRUPT_COUNTER1,F Btfss INTERRUPT_COUNTER1,6 ' If INTERRUPT_COUNT.6 = 1 Jump INVADER_SOUND_LOOP Clrf INTERRUPT_COUNTER1 ' INTERRUPT_COUNT = 0 Bcf INTERNAL_INVADER_SOUND_ENABLE ' INTERNAL_INVADER_SOUND_ENABLE = 0 Movfw INVADER_SOUND_DURATION_COUNTER ' If((INVADER_SOUND_DURATION_COUNTER <= INVADER_SOUND_DURATION) && (INVADER_SOUND_ENABLE == 1)) Subwf INVADER_SOUND_DURATION,W Btfss STATUS,C Jump FINISH_NOTE1 Btfss INVADER_SOUND_ENABLE Jump FINISH_NOTE1 Incf INVADER_SOUND_DURATION_COUNTER,F ' INVADER_SOUND_DURATION_COUNTER++ Bsf INTERNAL_INVADER_SOUND_ENABLE ' INTERNAL_INVADER_SOUND_ENABLE = 1 Jump INVADER_SOUND_LOOP ' Otherwise FINISH_NOTE1: BCF INVADER_SOUND_ENABLE ' INVADER_SOUND_ENABLE = 0 CLRF INVADER_SOUND_DURATION_COUNTER ' INVADER_SOUND_DURATION_COUNTER = 0 INVADER_SOUND_LOOP: Movfw INVADER_FREQ ' If INVADER_SOUND_COUNTER >= INVADER_FREQ Subwf INVADER_SOUND_COUNTER,W Btfss STATUS,C Jump MISSILE_SOUND_LOOP Clrw Btfsc INTERNAL_INVADER_SOUND_ENABLE Movlw 1 ' Set for tone generation on PORTA.0 Xorwf PORTA,F ' PORTA = PORTA ^ 1 Clrf INVADER_SOUND_COUNTER ' INVADER_SOUND_COUNTER = 0 MISSILE_SOUND_LOOP: Movfw MISSILE_FREQ ' If MISSILE_SOUND_COUNTER >= MISSILE_FREQ Subwf MISSILE_SOUND_COUNTER,W Btfss STATUS,C Jump SAUCER_SOUND_LOOP Clrw Btfsc MISSILE_SOUND_ENABLE Movlw 2 ' Set for tone generation on PORTA.1 Xorwf PORTA,F ' PORTA = PORTA ^ 2 Clrf MISSILE_SOUND_COUNTER ' MISSILE_SOUND_COUNTER = 0 SAUCER_SOUND_LOOP: Movfw SAUCER_FREQ ' If SAUCER_SOUND_COUNTER >= SAUCER_FREQ Subwf SAUCER_SOUND_COUNTER,W Btfss STATUS,C Jump EXIT_INTERRUPT Clrw Btfsc SAUCER_SOUND_ENABLE Movlw 4 ' Set for tone generation on PORTA.2 Xorwf PORTA,F ' PORTA = PORTA ^ 4 Clrf SAUCER_SOUND_COUNTER ' SAUCER_SOUND_COUNTER = 0 EXIT_INTERRUPT: T0IF = 0 Context Restore '---------------------------------------------------------------------------- ' Draw or clear the Invader's missile CLEAR_INVADER_MISSILE: UnPlot INVADER_MISSILE_YPOS, INVADER_MISSILE_XPOS UnPlot INVADER_MISSILE_YPOS, INVADER_MISSILE_XPOS + 1 UnPlot INVADER_MISSILE_YPOS + 1, INVADER_MISSILE_XPOS UnPlot INVADER_MISSILE_YPOS + 1, INVADER_MISSILE_XPOS + 1 UnPlot INVADER_MISSILE_YPOS + 2, INVADER_MISSILE_XPOS UnPlot INVADER_MISSILE_YPOS + 2, INVADER_MISSILE_XPOS + 1 Return DRAW_INVADER_MISSILE: UnPlot INVADER_MISSILE_YPOS, INVADER_MISSILE_XPOS UnPlot INVADER_MISSILE_YPOS, INVADER_MISSILE_XPOS + 1 Plot INVADER_MISSILE_YPOS + 1, INVADER_MISSILE_XPOS Plot INVADER_MISSILE_YPOS + 1, INVADER_MISSILE_XPOS + 1 Plot INVADER_MISSILE_YPOS + 2, INVADER_MISSILE_XPOS Plot INVADER_MISSILE_YPOS + 2, INVADER_MISSILE_XPOS + 1 Return '---------------------------------------------------------------------------- ' Draw or clear the second Invader's missile CLEAR_INVADER_MISSILE2: UnPlot INVADER_MISSILE2_YPOS, INVADER_MISSILE2_XPOS UnPlot INVADER_MISSILE2_YPOS, INVADER_MISSILE2_XPOS + 1 UnPlot INVADER_MISSILE2_YPOS + 1, INVADER_MISSILE2_XPOS UnPlot INVADER_MISSILE2_YPOS + 1, INVADER_MISSILE2_XPOS + 1 UnPlot INVADER_MISSILE2_YPOS + 2, INVADER_MISSILE2_XPOS UnPlot INVADER_MISSILE2_YPOS + 2, INVADER_MISSILE2_XPOS + 1 Return DRAW_INVADER_MISSILE2: UnPlot INVADER_MISSILE2_YPOS, INVADER_MISSILE2_XPOS UnPlot INVADER_MISSILE2_YPOS, INVADER_MISSILE2_XPOS + 1 Plot INVADER_MISSILE2_YPOS + 1, INVADER_MISSILE2_XPOS Plot INVADER_MISSILE2_YPOS + 1, INVADER_MISSILE2_XPOS + 1 Plot INVADER_MISSILE2_YPOS + 2, INVADER_MISSILE2_XPOS Plot INVADER_MISSILE2_YPOS + 2, INVADER_MISSILE2_XPOS + 1 Return '---------------------------------------------------------------------------- ' Re-Draw the bases UPDATE_BASES: Print at 6,2,2 + BASE_HITS#0,8 + BASE_HITS#1,14 + BASE_HITS#2,_ at 6,9,2 + BASE_HITS#3,8 + BASE_HITS#4,14 + BASE_HITS#5,_ at 6,15,2 + BASE_HITS#6,8 + BASE_HITS#7,14 + BASE_HITS#8 Return '---------------------------------------------------------------------------- ' Check if BASE hit by a missile ' Each base is built from three elements (characters) ' Returns with BASE_HIT set if a hit was detected CHECK_BASE_HIT: BASE_HIT = FALSE ' Default to no hit detected Select BASE_XPOS_TEST Case 12 to 17 ' Has the missile XPOS hit BASE 1, ELEMENT 0 If BASE_HITS#0 < 5 AND BASE_ENABLED#0 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#0 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#0 = FALSE ' Disable the base element Endif Case 18 to 23 ' Has the missile XPOS hit BASE 1, ELEMENT 1 If BASE_HITS#1 < 5 AND BASE_ENABLED#1 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#1 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#1 = FALSE ' Disable the base element Endif Case 24 to 29 ' Has the missile XPOS hit BASE 1, ELEMENT 2 If BASE_HITS#2 < 5 AND BASE_ENABLED#2 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#2 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#2 = FALSE ' Disable the base element Endif Case 54 to 59 ' Has the missile XPOS hit BASE 2, ELEMENT 3 If BASE_HITS#3 < 5 AND BASE_ENABLED#3 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#3 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#3 = FALSE ' Disable the base element Endif Case 60 to 65 ' Has the missile XPOS hit BASE 2, ELEMENT 4 If BASE_HITS#4 < 5 AND BASE_ENABLED#4 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#4 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#4 = FALSE ' Disable the base element Endif Case 66 to 71 ' Has the missile XPOS hit BASE 2, ELEMENT 5 If BASE_HITS#5 < 5 AND BASE_ENABLED#5 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#5 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#5 = FALSE ' Disable the base element Endif Case 90 to 95 ' Has the missile XPOS hit BASE 3, ELEMENT 6 If BASE_HITS#6 < 5 AND BASE_ENABLED#6 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#6 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#6 = FALSE ' Disable the base element Endif Case 96 to 101 ' Has the missile XPOS hit BASE 3, ELEMENT 7 If BASE_HITS#7 < 5 AND BASE_ENABLED#7 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#7 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#7 = FALSE ' Disable the base element Endif Case 102 to 107 ' Has the missile XPOS hit BASE 3, ELEMENT 8 If BASE_HITS#8 < 5 AND BASE_ENABLED#8 = TRUE Then ' Is the base element enabled, and has had less than 5 hits ? Inc BASE_HITS#8 ' Increment the amount of hits the base element has sustained BASE_HIT = TRUE ' Indicate a missile has hit a target Else BASE_ENABLED#8 = FALSE ' Disable the base element Endif End Select If BASE_HIT = TRUE Then Gosub UPDATE_BASES ' Update the base shapes if a hit was detected Return '---------------------------------------------------------------------------- ' Move the invader's missile ' The missile can only be fired if the flag INVADER_MISSILE_FIRED is false, ' otherwise there is already a missile in the air MOVE_INVADER_MISSILE: If INVADER_MISSILE_FIRED = TRUE Then ' Don't enter the routine if the invader's missile is already flying If TIME_TO_MOVE_INV_MISSILE = TRUE Then ' Is it time to move the invader's missile ? Gosub DRAW_INVADER_MISSILE Inc INVADER_MISSILE_YPOS Endif If INVADER_MISSILE_YPOS >= 63 OR INVADER_MISSILE_HIT = TRUE Then ' Has the invader's missile reached the bottom of the display or hit something ? INVADER_MISSILE_FIRED = FALSE ' Yes. So signal the invader's missile is finished Gosub CLEAR_INVADER_MISSILE ' Clear the invader's missile INVADER_MISSILE_HIT = FALSE Endif Endif Return '---------------------------------------------------------------------------- ' Move the invader's second missile ' The missile can only be fired if the flag INVADER_MISSILE2_FIRED is false, ' otherwise there is already a missile in the air MOVE_INVADER_MISSILE2: If INVADER_MISSILE2_FIRED = TRUE Then ' Don't enter the routine if the invader's missile is already flying If TIME_TO_MOVE_INV_MISSILE2 = TRUE Then ' Is it time to move the invader's missile ? Gosub DRAW_INVADER_MISSILE2 Inc INVADER_MISSILE2_YPOS Endif If INVADER_MISSILE2_YPOS >= 63 OR INVADER_MISSILE2_HIT = TRUE Then ' Has the invader's missile reached the bottom of the display or hit something ? INVADER_MISSILE2_FIRED = FALSE ' Yes. So signal the invader's missile is finished Gosub CLEAR_INVADER_MISSILE2 ' Clear the invader's missile INVADER_MISSILE2_HIT = FALSE Endif Endif Return '---------------------------------------------------------------------------- ' Fire an invader missile if possible ' The logic is: - ' Make sure a missile is not already in flight. ' Scan all the invaders... ' If the invader is enabled, then check if it is over the ship. ' If it is then enable a missile to be fired. FIRE_INVADER_MISSILE: If INVADER_MISSILE_FIRED = FALSE Then ' Is it OK to fire an invader missile ? INVADER_LOOP = 0 Repeat ' Create a loop for all the invaders If INVADER_ENABLED[INVADER_LOOP] = TRUE Then ' Is this invader enabled ? Select INVADER_XPOS[INVADER_LOOP] + 5 Case SHIP_XPOS to SHIP_XPOS + 8 ' Is the invader over the ship ? INVADER_MISSILE_FIRED = TRUE ' Signal that an invader's missile is in the air INVADER_MISSILE_XPOS = INVADER_XPOS[INVADER_LOOP] + 5 ' Move missile XPOS to the middle of the invader INVADER_MISSILE_YPOS = (INVADER_YPOS[INVADER_LOOP] * 8) + 8 ' Move missile YPOS to below the invader End Select Endif Inc INVADER_LOOP Until INVADER_LOOP > 17 ' Close the loop when all invaders have been scanned Endif Return '---------------------------------------------------------------------------- ' Fire an invader second missile if possible ' The logic is: - ' Make sure a missile is not already in flight. ' Scan all the invaders... ' If the invader is enabled, then check if it is over the ship. ' If it is then enable a missile to be fired. Dim RANDOM_VALUE as Byte FIRE_INVADER_MISSILE2: If INVADER_MISSILE2_FIRED = FALSE Then ' Is it OK to fire an invader second missile ? 'If INVADER_MISSILE_XPOS < SHIP_XPOS Then Select SHIP_XPOS Case > INVADER_MISSILE_XPOS + RANDOM_VALUE , < INVADER_MISSILE_XPOS - RANDOM_VALUE INVADER_LOOP = 0 Repeat ' Create a loop for all the invaders If INVADER_ENABLED[INVADER_LOOP] = TRUE Then ' Is this invader enabled ? Select INVADER_XPOS[INVADER_LOOP] + 5 Case SHIP_XPOS to SHIP_XPOS + 8 ' Is the invader over the ship ? INVADER_MISSILE2_FIRED = TRUE ' Signal that an invader's missile is in the air INVADER_MISSILE2_XPOS = INVADER_XPOS[INVADER_LOOP] + 5 ' Move missile XPOS to the middle of the invader INVADER_MISSILE2_YPOS = (INVADER_YPOS[INVADER_LOOP] * 8) + 8 ' Move missile YPOS to below the invader End Select Endif Inc INVADER_LOOP Until INVADER_LOOP > 17 ' Close the loop when all invaders have been scanned EndSelect Endif Return '---------------------------------------------------------------------------- ' Check if the invader's missile has hit something ' Returns with INVADER_MISSILE_HIT set if the invader's missile has hit something CHECK_FOR_INVADER_MISSILE_HIT: INVADER_MISSILE_HIT = FALSE ' Default to not hit If INVADER_MISSILE_FIRED = TRUE Then ' First make sure that a missile is actually launched ' Check if the invader's missile has hit a BASE If INVADER_MISSILE_YPOS >= 45 Then BASE_XPOS_TEST = INVADER_MISSILE_XPOS ' Transfer the invader's missile XPOS for testing Gosub CHECK_BASE_HIT ' Check if a base was hit If BASE_HIT = TRUE Then INVADER_MISSILE_HIT = TRUE ' Transfer the hit detector into the invader's missile detector Return ' Return from the subroutine prematurely Endif Endif ' Check if the invader's missile has hit the ship If INVADER_MISSILE_YPOS >= 56 Then Select INVADER_MISSILE_XPOS Case SHIP_XPOS - 1 To SHIP_XPOS + SHIP_WIDTH Gosub DRAW_SHIP INVADER_MISSILE_HIT = TRUE ' Indicate the invader's missile has hit something SHIP_HIT = TRUE ' Indicate that it is the ship that has been hit End Select Endif Endif Return '---------------------------------------------------------------------------- ' Check if the invader's second missile has hit something ' Returns with INVADER_MISSILE2_HIT set if the invader's missile has hit something CHECK_FOR_INVADER_MISSILE2_HIT: INVADER_MISSILE2_HIT = FALSE ' Default to not hit If INVADER_MISSILE2_FIRED = TRUE Then ' First make sure that a second missile is actually launched ' Check if the invader's second missile has hit a BASE If INVADER_MISSILE2_YPOS >= 45 Then BASE_XPOS_TEST = INVADER_MISSILE2_XPOS ' Transfer the invader's second missile XPOS for testing Gosub CHECK_BASE_HIT ' Check if a base was hit If BASE_HIT = TRUE Then INVADER_MISSILE2_HIT = TRUE ' Transfer the hit detector into the invader's second missile detector Return ' Return from the subroutine prematurely Endif Endif ' Check if the invader's missile has hit the ship If INVADER_MISSILE2_YPOS >= 56 Then Select INVADER_MISSILE2_XPOS Case SHIP_XPOS - 1 To SHIP_XPOS + SHIP_WIDTH Gosub DRAW_SHIP INVADER_MISSILE2_HIT = TRUE ' Indicate the invader's second missile has hit something SHIP_HIT = TRUE ' Indicate that it is the ship that has been hit End Select Endif Endif Return '---------------------------------------------------------------------------- ' Draw or clear the Ship's missile CLEAR_MISSILE: UnPlot MISSILE_YPOS, MISSILE_XPOS UnPlot MISSILE_YPOS, MISSILE_XPOS + 1 UnPlot MISSILE_YPOS + 1, MISSILE_XPOS UnPlot MISSILE_YPOS + 1, MISSILE_XPOS + 1 UnPlot MISSILE_YPOS + 2, MISSILE_XPOS UnPlot MISSILE_YPOS + 2, MISSILE_XPOS + 1 Return DRAW_MISSILE: Plot MISSILE_YPOS, MISSILE_XPOS Plot MISSILE_YPOS, MISSILE_XPOS + 1 Plot MISSILE_YPOS + 1, MISSILE_XPOS Plot MISSILE_YPOS + 1, MISSILE_XPOS + 1 UnPlot MISSILE_YPOS + 2, MISSILE_XPOS UnPlot MISSILE_YPOS + 2, MISSILE_XPOS + 1 Return '---------------------------------------------------------------------------- ' Draw the ship DRAW_SHIP: LCDWRITE 7,SHIP_XPOS,[$00,$E0,$F0,$F0,$F8,$FC,$F8,$F0,$F0,$E0,$00] Return '---------------------------------------------------------------------------- ' Check if the ship's missile has hit something ' Returns with MISSILE_HIT set if the ship's missile has hit something CHECK_FOR_MISSILE_HIT: MISSILE_HIT = FALSE ' Default to not hit SAUCER_HIT = FALSE ' Default to saucer not hit If MISSILE_FIRED = TRUE Then ' First make sure a missile is actually launched ' Check if the ship's missile has hit a BASE If MISSILE_YPOS = 53 Then BASE_XPOS_TEST = MISSILE_XPOS ' Transfer the ship's missile XPOS for testing Gosub CHECK_BASE_HIT ' Check if a base was hit If BASE_HIT = TRUE Then MISSILE_SOUND_ENABLE = 0 ' Disable the missile's sound MISSILE_HIT = TRUE ' Transfer the hit detector into the missile detector Return ' And return from the subroutine prematurely Endif Endif ' Check if the ship's missile has hit an invader's missile If MISSILE_XPOS = INVADER_MISSILE_XPOS Then If MISSILE_YPOS = INVADER_MISSILE_YPOS Then MISSILE_SOUND_ENABLE = 0 ' Disable the missile's sound MISSILE_HIT = TRUE ' Indicate the ship's missile has hit a target INVADER_MISSILE_HIT = TRUE ' Indicate the invader's missile has also been hit Inc SCORE ' Increment the score by one Return ' And return from the subroutine prematurely Endif ' Check if the ship's missile has hit the saucer If SAUCER_ENABLED = TRUE Then If MISSILE_YPOS < 7 Then Select MISSILE_XPOS Case SAUCER_XPOS To SAUCER_XPOS + SAUCER_WIDTH MISSILE_HIT = TRUE ' Indicate the ship's missile has hit a target SAUCER_HIT = TRUE SAUCER_SOUND_ENABLE = TRUE SAUCER_FREQ = 30 LCDWRITE 0,SAUCER_XPOS,[$8C,$C5,$6B,$36,$0C,$20,$68,$CC,$96,$33,$69,$CC,$86,$02] Delayms 10 LCDWRITE 0,SAUCER_XPOS,[$7F,$08,$08,$08,$7F,$00,$00,$41,$7F,$41,$00,$00,$01,$01,$7F,$01,$01] ' Display text HIT SAUCER_FREQ = 20 Delayms 5 SAUCER_FREQ = 10 Delayms 10 SCORE = SCORE + (100 + SAUCER_XPOS) ' Add 100 + xpos to the score for hitting the saucer SAUCER_SOUND_ENABLE = FALSE Return EndSelect Endif Endif ' Check if the ship's missile has hit an INVADER INVADER_LOOP = 0 Repeat If INVADER_ENABLED[INVADER_LOOP] = TRUE Then ' Only check if the invader is enabled If INVADER_YPOS[INVADER_LOOP] = MISSILE_YPOS / 8 Then Select MISSILE_XPOS Case INVADER_XPOS[INVADER_LOOP] to INVADER_XPOS[INVADER_LOOP] + INVADER_WIDTH INVADER_ENABLED[INVADER_LOOP] = FALSE MISSILE_HIT = TRUE ' Indicate the ship's missile has hit a target MISSILE_SOUND_ENABLE = 1 MISSILE_FREQ = 30 Select INVADER_LOOP ' Decide on the score depending on which invader is hit Case 0 to 5 ' Top layer of invaders score 20 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$42,$61,$51,$49,$46,$00,$3E,$51,$49,$45,$3E,$00] SCORE = SCORE + 20 Case 6 to 11 ' Middle layer of invaders score 10 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$00,$42,$7F,$40,$00,$00,$3E,$51,$49,$45,$3E,$00] SCORE = SCORE + 10 Case 12 to 17 ' Bottom layer of invaders score 5 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$3E,$51,$49,$45,$3E,$00, $27,$45,$45,$45,$39,$00] SCORE = SCORE + 5 EndSelect Delayms 10 MISSILE_FREQ = 20 Delayms 10 MISSILE_FREQ = 10 Delayms 20 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00] ' Erase the INVADER that was hit Dec INVADERS_ENABLED ' Decrement the hits counter If INVADERS_ENABLED = 1 Then ' Increase the speed substantially if only one invader left INVADER_SPEED = 5 Else if INVADERS_ENABLED = 2 Then INVADER_SPEED = 10 ' Increase the speed to fast if there are only two invaders left Else If INVADER_SPEED >= 3 Then ' Is the inveders speed greater than 3 ? If INVADERS_ENABLED <= 4 Then ' Are there 4 or less invaders left ? INVADER_SPEED = INVADER_SPEED - 3 ' Yes.. So increase their speed by a factor of three Else Dec INVADER_SPEED ' Otherwise.. Increase the speed of the remaining invaders Endif Endif Endif MISSILE_SOUND_ENABLE = 0 ' Disable the missile's sound Return ' And return from the subroutine prematurely Endselect Endif Endif Inc INVADER_LOOP Until INVADER_LOOP > 17 Endif Return '---------------------------------------------------------------------------- ' Move the ship's missile ' The missile can only be fired if the flag MISSILE_FIRED is false, ' otherwise there is already a missile in the air ' MOVE_MISSILE: If MISSILE_FIRED = TRUE Then ' Don't enter the routine if the ship's missile is already flying If TIME_TO_MOVE_SHIP_MISSILE = TRUE Then ' Is it time to move the ship's missile ? Gosub DRAW_MISSILE Dec MISSILE_YPOS MISSILE_FREQ = 63 - MISSILE_YPOS Endif If MISSILE_YPOS = 0 OR MISSILE_HIT = TRUE Then ' Has the missile reached the top of the display or hit something ? MISSILE_SOUND_ENABLE = 0 MISSILE_FIRED = FALSE ' Yes. So signal the missile is finished Gosub CLEAR_MISSILE ' Clear the missile MISSILE_YPOS = 63 - 9 ' Reset the missile to the bottom of the display Endif Endif Return '---------------------------------------------------------------------------- ' Move the ship right SHIP_RIGHT: If SHIP_XPOS > 117 Then Return Gosub DRAW_SHIP Inc SHIP_XPOS Return '---------------------------------------------------------------------------- ' Move the ship left SHIP_LEFT: If SHIP_XPOS = 0 Then Return Gosub DRAW_SHIP Dec SHIP_XPOS Return '---------------------------------------------------------------------------- ' Move the INVADERS down a line ' And check whether they have reached the bottom of the screen ' Flag INVADERS_REACHED_BOTTOM will be set if they have MOVE_INVADERS_DOWN: INVADERS_REACHED_BOTTOM = FALSE ' Default to the invaders not at bottom of the screen TEMP_LOOP = 18 Repeat Dec TEMP_LOOP If INVADER_ENABLED[TEMP_LOOP] = TRUE Then LCDWRITE INVADER_YPOS[TEMP_LOOP],INVADER_XPOS[TEMP_LOOP],[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00] INVADER_YPOS[TEMP_LOOP] = INVADER_YPOS[TEMP_LOOP] + 1 If INVADER_YPOS[TEMP_LOOP] = 6 Then ' Have the invaders hit the bases ? Str BASE_ENABLED = 0,0,0,0,0,0,0,0,0 ' Yes.. So disable them all Str BASE_HITS = 5,5,5,5,5,5,5,5,5 ' And move their hit counters to past their thresholds Endif If INVADER_YPOS[TEMP_LOOP] >= 7 Then INVADERS_REACHED_BOTTOM = TRUE ' Set a flag if the invaders have reached the bottom LCDWRITE INVADER_YPOS[TEMP_LOOP],INVADER_XPOS[TEMP_LOOP],[$00,$06,$0C,$9C,$EA,$36,$36,$EA,$9C,$0C,$06,$00] Endif Until TEMP_LOOP = 0 Inc INVADER_MISSILE_SPEED ' Slow down the invader's missile speed as they approach the bottom of the screen If INVADER_SPEED >= 3 Then Dec INVADER_SPEED ' Increase the speed of the invaders Return '---------------------------------------------------------------------------- ' Reset the invaders positions ' Each element of the arrays hold coordinates for the invaders ' Bit-0 of INVADER_ENABLED determines whether the invader is active or not (has been hit) ' Bit-1 of INVADER_ENABLED sets which graphic to use for the invader ' INVADER_XPOS holds the X position of the invader ' INVADER_YPOS holds the Y position of the invader RESET_INVADERS: INVADER_LOOP = 0 Repeat INVADER_ENABLED[INVADER_LOOP] = TRUE ' Set all invaders to active and image 1 Select INVADER_LOOP Case 0 to 5 INVADER_XPOS[INVADER_LOOP] = (INVADER_LOOP + 1) * 16 INVADER_YPOS[INVADER_LOOP] = 1 Case 6 to 11 INVADER_XPOS[INVADER_LOOP] = (INVADER_LOOP - 5) * 16 INVADER_YPOS[INVADER_LOOP] = 2 Case 12 to 17 INVADER_XPOS[INVADER_LOOP] = (INVADER_LOOP - 11) * 16 INVADER_YPOS[INVADER_LOOP] = 3 End Select Inc INVADER_LOOP Until INVADER_LOOP > 17 Return '---------------------------------------------------------------------------- ' Move the INVADERS MOVE_INVADERS: 'If TIME_TO_MOVE_INVADERS = TRUE Then TIME_TO_MOVE_INVADERS_DOWN = FALSE If INVADERS_DIRECTION = FORWARD Then ' Are the invaders to move forward (right) ? INVADER_LOOP = 0 ' Yes.. So reset the invader loop Repeat ' Create a loop for all the invaders If INVADER_ENABLED[INVADER_LOOP] = TRUE Then ' Is this invader enabled ? INVADER_XPOS[INVADER_LOOP] = INVADER_XPOS[INVADER_LOOP] + 1 ' Yes.. So increment its XPOS If INVADER_XPOS[INVADER_LOOP] >= INVADER_RIGHT_LIMIT Then ' Have we hit the right side of the screen ? INVADERS_DIRECTION = BACKWARD ' Yes.. So indicate that we need to go backwards SAUCER_ENABLED = TRUE TIME_TO_MOVE_INVADERS_DOWN = TRUE ' and signal that we need to move the invaders down Endif Endif Inc INVADER_LOOP Until INVADER_LOOP > 17 ' Close the loop after all the invader elements have been scanned Else ' Otherwise we go backwards (left) INVADER_LOOP = 0 ' Reset the invader loop Repeat ' Create a loop for all the invaders If INVADER_ENABLED[INVADER_LOOP] = TRUE Then ' Is this invader enabled ? INVADER_XPOS[INVADER_LOOP] = INVADER_XPOS[INVADER_LOOP] - 1 ' Yes.. So decrement its XPOS If INVADER_XPOS[INVADER_LOOP] <= 1 Then ' Have we hit the left side of the screen ? INVADERS_DIRECTION = FORWARD ' Yes.. So indicate that we need to go forwards TIME_TO_MOVE_INVADERS_DOWN = TRUE ' and signal that we need to move the invaders down Endif Endif Inc INVADER_LOOP Until INVADER_LOOP > 17 ' Close the loop after all the invader elements have been scanned Endif If TIME_TO_MOVE_INVADERS_DOWN = TRUE Then Gosub MOVE_INVADERS_DOWN ' Do we need to move the invaders down ? 'Endif ' Fall through to DRAW_THE_INVADERS '---------------------------------------------------------------------------- ' Draw the invaders ' Draws one of two invader shapes depending on the contents of BIT variable INVADER_CHARACTER ' Each row of invaders is a different character 'INVADER TOP ROW character 1 $00,$18,$4C,$2E,$5B,$2F,$2F,$5B,$2E,$4C,$18,$00 'INVADER TOP ROW character 2 $00,$08,$2C,$5E,$0B,$1F,$1F,$0B,$5E,$2C,$08,$00 'INVADER MIDDLE ROW character 1 $00,$38,$0D,$3E,$5A,$1E,$1E,$5A,$3E,$0D,$38,$00 'INVADER MIDDLE ROW character 2 $00,$06,$48,$7F,$1A,$1E,$1E,$1A,$7F,$48,$06,$00 'INVADER BOTTOM ROW character 1 $00,$4C,$6E,$3A,$1B,$2F,$2F,$1B,$3A,$6E,$4C,$00 'INVADER BOTTOM ROW character 2 $00,$0C,$0E,$3A,$4B,$1F,$1F,$4B,$3A,$0E,$0C,$00 DRAW_INVADERS: INVADER_LOOP = 0 Repeat If INVADER_ENABLED[INVADER_LOOP] = TRUE Then If INVADER_CHARACTER = 0 Then INVADER_SOUND_ENABLE = 0 INVADER_FREQ = 90 Select INVADER_LOOP ' Decide on the score depending on which invader is hit Case 0 to 5 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$00,$18,$4C,$2E,$5B,$2F,$2F,$5B,$2E,$4C,$18,$00] Case 6 to 11 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$00,$38,$0D,$3E,$5A,$1E,$1E,$5A,$3E,$0D,$38,$00] Case 12 to 17 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$00,$4C,$6E,$3A,$1B,$2F,$2F,$1B,$3A,$6E,$4C,$00] EndSelect INVADER_SOUND_ENABLE = 1 Else INVADER_SOUND_ENABLE = 0 INVADER_FREQ = 105 Select INVADER_LOOP ' Decide on the score depending on which invader is hit Case 0 to 5 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$00,$08,$2C,$5E,$0B,$1F,$1F,$0B,$5E,$2C,$08,$00] Case 6 to 11 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$00,$06,$48,$7F,$1A,$1E,$1E,$1A,$7F,$48,$06,$00] Case 12 to 17 LCDWRITE INVADER_YPOS[INVADER_LOOP],INVADER_XPOS[INVADER_LOOP],[$00,$0C,$0E,$3A,$4B,$1F,$1F,$4B,$3A,$0E,$0C,$00] EndSelect INVADER_SOUND_ENABLE = 1 Endif Endif Inc INVADER_LOOP Until INVADER_LOOP > 17 Return '---------------------------------------------------------------------------- ' Clear the saucer located at the top of the screen CLEAR_SAUCER: Lcdwrite 0,SAUCER_XPOS,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] Return '---------------------------------------------------------------------------- ' Draw the saucer located at the top of the screen DRAW_SAUCER: print at 0,(saucer_xpos/6)-1," "'clear some space in front of the saucer to make it easy to see Lcdwrite 0,SAUCER_XPOS,[$00,$04,$0E,$3A,$1B,$0F,$1B,$1B,$0F,$1B,$3A,$0E,$04,$00] Return '---------------------------------------------------------------------------- ' Move the saucer if it is not already flying MOVE_SAUCER: If SAUCER_ENABLED = TRUE Then ' Don't enter the routine if the saucer is already flying SAUCER_SOUND_ENABLE = 1 ' Enable the saucer's sound channel If TIME_TO_MOVE_SAUCER = TRUE Then ' Is it time to move the saucer ? Dec SAUCER_XPOS ' Move the saucer accross the screen if SAUCER_XPOS // 2 = 0 Then SAUCER_FREQ = 10 Else SAUCER_FREQ = 12 Endif Gosub DRAW_SAUCER ' Display the saucer Endif If SAUCER_XPOS = 0 OR SAUCER_HIT = TRUE Then ' Has the saucer reached the left of the display or been hit ? SAUCER_ENABLED = FALSE ' Yes. So signal the saucer is finished Gosub CLEAR_SAUCER ' Clear the saucer SAUCER_XPOS = 127 - SAUCER_WIDTH ' Reset the saucer to the right of the display gosub display_score 'Print at 0,0,Dec LEVEL, " ",Dec SCORE,at 0,20,LIVES ' And display the score because it was erased by the saucer Endif Else SAUCER_SOUND_ENABLE = 0 ' Disable the saucer's sound channel Endif Return '---------------------------------------------------------------------------- ' Determine whether a missile, ship, saucer or base should move ' governed by their individual speed controls GOVERN_SPEEDS: ' Advance the saucers's tick (governs its speed) Dec SAUCER_SPEED TIME_TO_MOVE_SAUCER = FALSE If SAUCER_SPEED = 0 Then TIME_TO_MOVE_SAUCER = TRUE SAUCER_SPEED = 3 Endif ' Advance the ship's tick (governs its speed) Dec SHIP_SPEED TIME_TO_MOVE_BASE = FALSE If SHIP_SPEED = 0 Then TIME_TO_MOVE_BASE = TRUE SHIP_SPEED = 3 Endif ' Advance the invader's missile tick (governs its speed) Inc INVADER_MISSILE_TICK TIME_TO_MOVE_INV_MISSILE = FALSE If INVADER_MISSILE_TICK >= INVADER_MISSILE_SPEED Then ' Set the speed for the invader's missile TIME_TO_MOVE_INV_MISSILE = TRUE INVADER_MISSILE_TICK = 0 Endif ' Advance the invader's second missile tick (governs its speed) Inc INVADER_MISSILE2_TICK TIME_TO_MOVE_INV_MISSILE2 = FALSE If INVADER_MISSILE2_TICK >= INVADER_MISSILE2_SPEED Then ' Set the speed for the invader's second missile TIME_TO_MOVE_INV_MISSILE2 = TRUE INVADER_MISSILE2_TICK = 0 Endif ' Advance the ship's missile tick (governs its speed) Dec SHIP_MISSILE_TICK TIME_TO_MOVE_SHIP_MISSILE = FALSE If SHIP_MISSILE_TICK = 0 Then ' Set the speed for the ship's missile TIME_TO_MOVE_SHIP_MISSILE = TRUE SHIP_MISSILE_TICK = 2 Endif Return '---------------------------------------------------------------------------- ' Display the spash screen ' The subroutine re-uses some of the variables ' TEMP_LOOP, LEVEL, and INVADER_LOOP DISPLAY_SPASH_SCREEN: Cls game_over_splash: temp_dword = 0 TEMP_LOOP = 0 Repeat INVADER_LOOP = 0 Repeat LEVEL = CREAD INVADER_SPLASH_SCREEN + temp_dword LcdWrite TEMP_LOOP,INVADER_LOOP,[LEVEL] Inc temp_dword Inc INVADER_LOOP Until INVADER_LOOP > 127 Inc TEMP_LOOP Until TEMP_LOOP > 7 Return '---------------------------------------------------------------------------- MAIN_PROGRAM_LOOP: 'Gosub DISPLAY_SPASH_SCREEN''LES I wonder if this should have been SPLASH? 'Delayms 1000 'Print at 4,1,"PRESS FIRE TO START" 'While FIRE_BUTTON = 1 : Wend 'While FIRE_BUTTON = 0 : Wend 'Delayms 50 flash_count=0 intro_screen: if flash_count=0 then gosub game_over_splash 'print "SPACE INVADER" screen if flash_count=128 then print at 4,1,"PRESS FIRE TO START" flash_count=flash_count+1 'increment "flash_count" delayms 8 'flash rate approx=delayms X 128 if fire_button=0 then delayms 300:flash_count=0:gosub name_list'print the high scoring screen goto intro_screen score_screen: 'Cls 'Print at 0,7,"Scoring" 'print at 1,0,"HIGH SCORE= ",dec eread 0 'print the high score on screen 'Lcdwrite 2,0,[$00,$04,$0E,$3A,$1B,$0F,$1B,$1B,$0F,$1B,$3A,$0E,$04,$00] 'Print at 2,2," = 100+ Points" 'LCDWRITE 3,0,[$00,$18,$4C,$2E,$5B,$2F,$2F,$5B,$2E,$4C,$18,$00] 'Print at 3,2," = 20 Points" 'LCDWRITE 4,0,[$00,$38,$0D,$3E,$5A,$1E,$1E,$5A,$3E,$0D,$38,$00] 'Print at 4,2," = 10 Points" 'LCDWRITE 5,0,[$00,$4C,$6E,$3A,$1B,$2F,$2F,$1B,$3A,$6E,$4C,$00] 'Print at 5,2," = 5 Points" 'Print at 7,1,"PRESS FIRE TO START" 'While FIRE_BUTTON = 1 : Wend 'While FIRE_BUTTON = 0 : Wend 'Delayms 50 cls gosub hall_of_fame 'print a lovely border flash_count=0 lcdwrite 3,20,[$00,$04,$0E,$3A,$1B,$0F,$1B,$1B,$0F,$1B,$3A,$0E,$04,$00] print at 3,6,"=100+ Points" lcdwrite 4,28,[$00,$18,$4C,$2E,$5B,$2F,$2F,$5B,$2E,$4C,$18,$00] print at 4,7,"=20 Points" lcdwrite 5,28,[$00,$38,$0D,$3E,$5A,$1E,$1E,$5A,$3E,$0D,$38,$00] print at 5,7,"=10 Points" lcdwrite 6,34,[$00,$4C,$6E,$3A,$1B,$2F,$2F,$1B,$3A,$6E,$4C,$00] print at 6,8,"=5 Points" score_flash: if flash_count=0 then print at 1,5," Invader ",at 2,5," Scoring " if flash_count=128 then print at 1,5," PRESS FIRE",at 2,5,"To Play Game" flash_count=flash_count+1 'increment "flash_count" delayms 14 'flash rate approx=delayms X 128 if fire_button=0 then delayms 300:flash_count=0:goto can_we_start_yet 'lets play the game goto score_flash '------------------------------------------------------------------------------------------------ can_we_start_yet: LEVEL = 0 ' Start at level 0 LIVES = "3" ' Set the initial lives counter to 3 SHIP_SPEED = 3 SCORE = 0 SHIP_XPOS = 64 SAUCER_SPEED = 7 ' Speed of the saucer INVADER_SPEED = 70 ' The initial speed of the invaders DEFAULT_INVADER_SPEED = INVADER_SPEED 'TEMP_LOOP = 0 'Repeat 'BASE_ENABLED[TEMP_LOOP] = TRUE 'BASE_HITS[TEMP_LOOP] = 0 'Inc TEMP_LOOP 'Until TEMP_LOOP > 8 gosub build_base 'print ships bases to hide behind Output PORTA ' Set all of PORTA to outputs (for sound channels) INTERRUPT_COUNTER1 = 0 NOTE_STATUS = 0 INVADER_SOUND_COUNTER = 0 MISSILE_SOUND_COUNTER = 0 SAUCER_SOUND_COUNTER = 0 INVADER_SOUND_DURATION_COUNTER = 0 'GIE = 0 ' Disable interrupts 'OPTION_REG = %00000000 ' TMR0 prescaler 1:1, PORTB pullups ON 'TMR0 = 0 ' Reset TMR0 'INTCON = %10100000 ' Enable TMR0 Interrupt INVADER_SOUND_ENABLE = 1 ' Enable the Invaders sound channel INVADER_SOUND_DURATION = 20 ' Set the note duration to 20 ' Main program loop starts here ' Jump to this location to implement a new sheet of invaders NEW_SHEET: Inc LEVEL gosub bonus_screen 'check to see if the bonus level has been reached Cls Gosub UPDATE_BASES ' Draw the bases (or what's left of them) SHIP_HIT = FALSE ' Default to no hit on the ship by a missile SAUCER_ENABLED = FALSE ' Disable the saucer SAUCER_XPOS = 127 - SAUCER_WIDTH ' Position saucer at top tight of the screen MISSILE_XPOS = 0 MISSILE_YPOS = 63 - 9 INVADER_MISSILE_XPOS = 0 INVADER_MISSILE_YPOS = 0 MISSILE_STATUS = 0 INVADER_MISSILE2_YPOS = 0 ' Y position of Invader's second MISSILE INVADER_MISSILE2_XPOS = 0 ' X position of Invader's second MISSILE TIME_TO_MOVE_INV_MISSILE2 = FALSE ' Indicate time to move the invader's second missile INVADER_MISSILE2_FIRED = FALSE ' TRUE if Invader's second MISSILE in the air INVADER_MISSILE2_HIT = FALSE ' Default to not hit anything TIME_TO_MOVE_BASE = FALSE Gosub CLEAR_INVADER_MISSILE Gosub CLEAR_MISSILE Gosub DRAW_SHIP ' Draw the initial ship Dec DEFAULT_INVADER_SPEED ' Speed up the invaders every new sheet INVADER_SPEED = DEFAULT_INVADER_SPEED ' Transfer the speed into the actual speed altering variable Clear INVADER_TICK Clear INVADER_MISSILE_TICK Clear INVADER_MISSILE2_TICK SHIP_MISSILE_TICK = 2 INVADERS_REACHED_BOTTOM = FALSE ' Default to the invaders not at the bottom of the screen INVADER_CHARACTER = 0 INVADER_MISSILE_SPEED = 5 ' Default speed of the invader's missile INVADER_MISSILE2_SPEED = 4 INVADERS_DIRECTION = FORWARD ' Default to the invaders moving right INVADERS_ENABLED = 18 ' All 18 invaders are enabled Gosub RESET_INVADERS ' Reset all the invaders positions Gosub DRAW_INVADERS ' Place all the invaders on the screen 'Print at 0,0,Dec LEVEL, " ",Dec SCORE,at 0,20,LIVES gosub display_score While 1 = 1 RANDOM_VALUE = RANDOM RANDOM_VALUE = RANDOM_VALUE & %00111000 Inc INVADER_TICK TIME_TO_MOVE_INVADERS = FALSE If INVADER_TICK > INVADER_SPEED Then INVADER_TICK = 0 'TIME_TO_MOVE_INVADERS = TRUE 'If TIME_TO_MOVE_INVADERS = TRUE Then Gosub MOVE_INVADERS Gosub MOVE_INVADERS INVADER_CHARACTER = ~INVADER_CHARACTER ' Use a new invader character If INVADERS_REACHED_BOTTOM = TRUE Then GAME_OVER Endif Gosub MOVE_SAUCER ' Move the flying saucer (if required) Gosub GOVERN_SPEEDS ' Check whether a piece should be moving If L_BUTTON = 0 Then Gosub SHIP_LEFT ' Move ship left if LEFT button pressed If R_BUTTON = 0 Then Gosub SHIP_RIGHT ' Move ship right if RIGHT button pressed if pause_button=0 then delayms 200:print at 4,4," Game Paused ":gosub pause_game 'pause the game If FIRE_BUTTON = 0 Then If MISSILE_FIRED = FALSE Then ' Has the FIRE button been pressed and the ship's missile not already flying ? SEED INVADER_SOUND_COUNTER MISSILE_FIRED = TRUE ' Yes.. So signal we need the ship's missile FIRED MISSILE_XPOS = SHIP_XPOS + 4 ' Place the ship's missile's xpos at the middle of the ship's shape MISSILE_SOUND_ENABLE = 1 ' Enable the missile's sound Endif Gosub MOVE_MISSILE ' Move the ship's missile if OK to do so Gosub CHECK_FOR_MISSILE_HIT ' Check if the ship's missile has hit anything If MISSILE_HIT = TRUE OR SAUCER_HIT = TRUE Then If BASE_HIT = FALSE Then 'Print at 0,19,Dec2 INVADERS_ENABLED," " ' Display the INVADER hits count 'Print at 0,0,Dec LEVEL, " ",Dec SCORE,at 0,20,LIVES gosub display_score Endif Endif If INVADER_CHARACTER = 1 Then Gosub FIRE_INVADER_MISSILE ' Fire an invader missile is possible Endif Gosub MOVE_INVADER_MISSILE ' Move the invader's missile (if fired) Gosub CHECK_FOR_INVADER_MISSILE_HIT ' Check if the invader's missile has hit anything If INVADERS_ENABLED = 0 Then ' Have all the invaders been destroyed ? INVADERS_ENABLED = 18 ' Yes.. So enable them all again If INVADER_SPEED >= 3 Then Dec INVADER_SPEED ' Increase the speed of the invaders Goto NEW_SHEET ' and start a new sheet Endif If LEVEL > 10 Then ' Add a second invader missile after level 10 If INVADER_CHARACTER = 0 then Gosub FIRE_INVADER_MISSILE2 ' Fire an invader missile is possible Endif Gosub MOVE_INVADER_MISSILE2 ' Move the invader's missile (if fired) Gosub CHECK_FOR_INVADER_MISSILE2_HIT ' Check if the invader's missile has hit anything Endif If SHIP_HIT = TRUE Then ' Has the ship been hit ? SHIP_HIT = FALSE SAUCER_SOUND_ENABLE = 1 ' Yes. So enable SAUCER sound channel MISSILE_SOUND_ENABLE = 1 ' Enable MISSILE sound channel MISSILE_FREQ = 70 ' Set MISSILE channel frequency to 70 SAUCER_FREQ = 90 ' Set SAUCER channel frequency to 90 LCDWRITE 7,SHIP_XPOS,[$10,$24,$AC,$F8,$F0,$E0,$F0,$F8,$AC,$24,$10] ' Draw first part of ship exploding Delayms 40 ' Leave the graphic on the screen for 40ms SAUCER_FREQ = 100 ' Increase the SAUCER channel's frequency MISSILE_FREQ = 120 ' Increase the MISSILE channel's frequency LCDWRITE 7,SHIP_XPOS,[$00,$20,$28,$F0,$A8,$C0,$E0,$F0,$28,$04,$00] ' Draw second part of ship exploding Delayms 40 ' Leave the graphic on the screen for 40ms SAUCER_FREQ = 150 ' Increase the SAUCER channel's frequency MISSILE_FREQ = 135 ' Increase the MISSILE channel's frequency LCDWRITE 7,SHIP_XPOS,[$00,$00,$30,$60,$80,$C0,$60,$30,$00,$00,$00] ' Draw third part of ship exploding Delayms 100 LCDWRITE 7,SHIP_XPOS,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00] ' Clear the ship graphic Delayms 100 ' Leave the graphic on the screen for 100ms LIVES = LIVES - 1 ' Decrement the lives counter MISSILE_SOUND_ENABLE = 0 ' Disable the MISSILE sound channel SAUCER_SOUND_ENABLE = 0 ' Disable the SAUCER sound channel If LIVES > "0" Then ' Do we have any lives left ? LCDWRITE 7,SHIP_XPOS,[$00,$E0,$F0,$F0,$F8,$FC,$F8,$F0,$F0,$E0,$00] ' Yes. So Re-draw the ship and carry on Print at 0,20,LIVES ' Update the Display for the amount of lives Else ' Otherwise, we don't have any lives left Goto GAME_OVER ' So game over Endif Endif Delayms 6 ' Main game speed setting Wend '-------------------------------------------------------------------- ' Explode the ship when the game is over GAME_OVER: 'Print at 0,0,Dec LEVEL, " ",Dec SCORE,at 0,20,LIVES gosub display_score SAUCER_SOUND_ENABLE = TRUE ' Enable SAUCER sound channel MISSILE_SOUND_ENABLE = TRUE ' Enable MISSILE sound channel MISSILE_FREQ = 70 ' Set MISSILE channel frequency to 70 SAUCER_FREQ = 90 ' Set SAUCER channel frequency to 90 TEMP_LOOP = 1 Repeat MISSILE_FREQ = MISSILE_FREQ - TEMP_LOOP SAUCER_FREQ = SAUCER_FREQ - TEMP_LOOP Delayms 10 + TEMP_LOOP Circle 1,SHIP_XPOS + 5,63,TEMP_LOOP If TEMP_LOOP > 10 Then Circle 0,SHIP_XPOS + 5,63,TEMP_LOOP - 10 Endif TEMP_LOOP = TEMP_LOOP + 2 Until TEMP_LOOP > 24 SAUCER_SOUND_ENABLE = FALSE ' Disable SAUCER sound channel MISSILE_SOUND_ENABLE = FALSE ' Disable MISSILE sound channel TEMP_LOOP = 1 Repeat Circle 0,SHIP_XPOS + 5,63,TEMP_LOOP TEMP_LOOP = TEMP_LOOP + 2 Until TEMP_LOOP > 24 Cls 'Print at 3,6,INVERSE 1,"GAME OVER", INVERSE 0 'Delayms 500 'Print at 4,1,"PRESS FIRE TO START" 'While FIRE_BUTTON = 1 : Wend 'Delayms 50 'While FIRE_BUTTON = 0 : Wend 'Delayms 50 'Goto MAIN_PROGRAM_LOOP '------------------------------------------------------------------------------------------------ '------------------------------------------------------------------------------------------------ check_high_score:'new game over and high score routine gosub display_spash_screen high_score1=eread 0'check previous high scores high_score2=eread 4 high_score3=eread 8 high_score4=eread 12 name1=eread 16 'name for high_score1 name2=eread 17 name3=eread 18 name4=eread 19 'name for high_score2 name5=eread 20 name6=eread 21 name7=eread 22 'name for high_score3 name8=eread 23 name9=eread 24 name10=eread 25 'name for high_score4 name11=eread 26 name12=eread 27 'this part of the routine checks the score for its position in the "HALL OF FAME" and if it is the same as 'the score, or higher, the appropriate position is noted and the name and score to be replaced is moved 'down one place to make way for the new one, the lowest score is erased. select score case >high_score1 ewrite 0,[score]:delayms 40:ewrite 4,[high_score1]:delayms 40:ewrite 19,[name1,name2,name3]:delayms 30:ewrite 8,_ [high_score2]:delayms 40:ewrite 22,[name4,name5,name6]:delayms 30:ewrite 12,[high_score3]:delayms 40:ewrite 25,_ [name7,name8,name9]:delayms 30:position=1 case >high_score2 to high_score1 ewrite 4,[score]:delayms 40:ewrite 8,[high_score2]:delayms 40:ewrite 22,[name4,name5,name6]:delayms 30:ewrite 12,_ [high_score3]:delayms 40:ewrite 25,[name7,name8,name9]:delayms 30:position=2 case >high_score3 to high_score2 ewrite 8,[score]:delayms 40:ewrite 12,[high_score3]:delayms 40:ewrite 25,[name7,name8,name9]:delayms 30:position=3 case >high_score4 to high_score3 ewrite 12,[score]:delayms 40:position=4 endselect '********************************* 'this part of routine is used if no new high score Print at 4,1,"PRESS FIRE TO START" if score,Fire= End" print at 5,10,"A","A" name_position=9 'initial position of character on screen(9to11) character=65 'initial character="A", 65 in ascii code 'multiple line instructions below save much code on single line with multiple maths! name_address=position-1 'make name_address(0to2) name_address=name_address*3 'make name_address step in threes(0,3,6,9) name_address=name_address+16 'begining address of name(16,19,22,25) select_name:'set the name in the hall of fame 'character=eread name_address 'get character from table selected by LEFT and RIGHT keys print at 5,name_position,inverse 1,character,inverse 0 'print the character to change inverted on screen if name_position=11 then goto exit_loop if r_button=0 then delayms 300:character=character+1 'test RIGHT key,if pressed display the next character if character>90 then character=65 'rollover maximum to minimum if l_button=0 then delayms 300:character=character-1 'test LEFT key,if pressed display the previous character if character<65 then character=90 'rollover minimum to maximum 'this line checks for the FIRE button press and writes the chosen character to eeprom using the position in the high score 'to set the address of the character, then selects the next character to display if fire_button=0 then delayms 300:ewrite name_address,_ [character]:delayms 10:name_address=name_address+1:name_position=name_position+1 goto select_name exit_loop:'if this loop is not here the display flashes while continually printing the last name character! if fire_button=0 then delayms 300:ewrite name_address,[character]:delayms 10:goto name_list goto exit_loop name_list:'print the 4 top scores on screen and inverse the position you have just attained!!! gosub hall_of_fame character_yposition=3 'initial position of character in "print_name" routine if position=1 then print inverse 1 print at 3,4,"1> ",dec7 high_score1:name_position=16:print inverse 0:gosub print_name if position=2 then print inverse 1 print at 4,4,"2> ",dec7 high_score2:name_position=19:print inverse 0:gosub print_name if position=3 then print inverse 1 print at 5,4,"3> ",dec7 high_score3:name_position=22:print inverse 0:gosub print_name if position=4 then print inverse 1 print at 6,4,"4> ",dec7 high_score4:name_position=25:print inverse 0:gosub print_name fire_button_loop: gosub hall_of_fame_flash if fire_button=1 then goto fire_button_loop 'if fire button is not pressed keep looping! if fire_button=0 then delayms 200:print inverse 0:goto score_screen 'restart the game '------------------------------------------------------------------------------------------------ '------------------------------------------------------------------------------------------------ no_high_score: print at 0,1,"G",at 1,1,"A",at 2,1,"M",at 3,1,"E",at 0,20,"O",at 1,20,"V",at 2,20,"E",at 3,20,"R" if flash_count=0 then print inverse 0 'flash "GAME OVER" if flash_count=128 then print inverse 1 flash_count=flash_count+1 'increment "flash_count" delayms 8 'flash rate approx=delayms X 128 if fire_button=1 then goto no_high_score 'if fire button is not pressed keep looping! if fire_button=0 then delayms 200:print inverse 0:goto score_screen 'restart the game! '------------------------------------------------------------------------------------------------ '------------------------------------------------------------------------------------------------ print_name: 'this routine uses the high_score position(1 to 4) to point to a stored value generated by the 'select_name routine(a value of 1 to 26). this value is then used to read from the eeprom the 'stored text character at the coresponding position(1="A"~26="Z") that were setup in the "edata" table. character_xposition=15 'initial print X-position of character for name=name_position to name_position+2 'use a loop to read three characters from the eeprom character=eread name 'get the text in the position pointed to by name(address) print at character_yposition,character_xposition,character 'print character at selected position character_xposition=character_xposition+1 'choose the next character print position next name 'untill loop has finished its three characters character_yposition=character_yposition+1 'move the character along to its next position return '------------------------------------------------------------------------------------------------ '------------------------------------------------------------------------------------------------ display_score: 'this routine prints the level,score and lives on screen,checks the value of high_score4 'and if it has been beaten DURING the game it inverts the score display just to let you know! high_score4=eread 12 'check previous lowest high_score(in position 4) 'print the level and score if score8 return '------------------------------------------------------------------------------------------------ '------------------------------------------------------------------------------------------------ 'initial settings for High Score and Names! in onboard eeprom edata 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 'set high scores to zero(address 0to15) edata "MARK RODGERS" 'initial letters for hall of fame(address 16to27) '------------------------------------------------------------------------------------------------ '------------------------------------------------------------------------------------------------ ' Font CDATA table for space invaders game FONT:- CData $00,$00,$00,$00,$00,$00 'Graphic Character 0 CData $FF,$FF,$FF,$FF,$FF,$FF 'Graphic Character 1 CData $E0,$F0,$F8,$FC,$FC,$FE ' Left side of base complete (Character 2) CData $C0,$B0,$B0,$70,$EC,$F8 ' Left side of base after hit 1 (Character 3) CData $C0,$A0,$B0,$70,$AC,$28 ' Left side of base after hit 2 (Character 4) CData $40,$A0,$B0,$70,$A0,$20 ' Left side of base after hit 3 (Character 5) CData $40,$80,$80,$40,$A0,$20 ' Left side of base after hit 4 (Character 6) CData $00,$00,$00,$00,$00,$00 ' Left side of base after hit 5 (Character 7) CData $FE,$FE,$FE,$FE,$FE,$FE ' Middle of base complete (Character 8) CData $FE,$DE,$EC,$F0,$F8,$FE ' Middle of base after hit 1 (Character 9) CData $F8,$DE,$E4,$F0,$D8,$9E ' Middle of base after hit 2 (Character 10) CData $B8,$DE,$A4,$B0,$48,$B4 ' Middle of base after hit 3 (Character 11) CData $34,$58,$A4,$B8,$48,$34 ' Middle of base after hit 4 (Character 12) CData $00,$00,$00,$00,$00,$00 ' Middle of base after hit 5 (Character 13) CData $FE,$FC,$FC,$F8,$F0,$E0 ' Right side of base complete (Character 14) CData $C0,$B0,$B0,$70,$EC,$F8 ' Right side of base after hit 1 (Character 15) CData $C0,$A0,$B0,$70,$AC,$28 ' Right side of base after hit 2 (Character 16) CData $40,$A0,$B0,$70,$A0,$20 ' Right side of base after hit 3 (Character 17) CData $40,$80,$80,$40,$A0,$20 ' Right side of base after hit 4 (Character 18) CData $00,$00,$00,$00,$00,$00 ' Right side of base after hit 5 (Character 19) CData $FF,$00,$00,$00,$00,$00 'Graphic character 20 CData $00,$00,$00,$00,$00,$FF 'Graphic character 21 CData $FF,$01,$01,$01,$01,$01 'Graphic character 22 CData $01,$01,$01,$01,$01,$FF 'Graphic character 23 CData $FF,$80,$80,$80,$80,$80 'Graphic character 24 CData $80,$80,$80,$80,$80,$FF 'Graphic character 25 CData $00,$00,$00,$00,$F0,$F0 'User defined character 26 CData $00,$00,$00,$00,$0F,$0F 'User defined character 27 CData $00,$00,$00,$00,$00,$00 'User defined character 28 CData $00,$00,$00,$00,$00,$00 'User defined character 29 CData $00,$00,$00,$00,$00,$00 'User defined character 30 CData $00,$00,$00,$00,$00,$00 'User defined character 31 CData $00,$00,$00,$00,$00,$00 '32 - - 20 CData $00,$00,$4F,$00,$00,$00 '33 - ! - 21 CData $00,$07,$00,$07,$00,$00 '34 - " - 22 CData $14,$7F,$14,$7F,$14,$00 '35 - # - 23 CData $24,$2A,$7F,$2A,$12,$00 '36 - $ - 24 CData $23,$13,$08,$64,$62,$00 '37 - % - 25 CData $36,$49,$55,$22,$50,$00 '38 - & - 26 CData $00,$05,$03,$00,$00,$00 '39 - ' - 27 CData $1C,$22,$41,$00,$00,$00 '40 - ( - 28 CData $00,$00,$41,$22,$1C,$00 '41 - ) - 29 CData $14,$08,$3E,$08,$14,$00 '42 - * - 2A CData $08,$08,$3E,$08,$08,$00 '43 - + - 2B CData $00,$50,$30,$00,$00,$00 '44 - , - 2C CData $08,$08,$08,$08,$08,$00 '45 - - - 2D CData $00,$60,$60,$00,$00,$00 '46 - . - 2E CData $20,$10,$08,$04,$02,$00 '47 - / - 2F CData $3E,$51,$49,$45,$3E,$00 '48 - 0 - 30 CData $00,$42,$7F,$40,$00,$00 '49 - 1 - 31 CData $42,$61,$51,$49,$46,$00 '50 - 2 - 32 CData $21,$41,$45,$4B,$31,$00 '51 - 3 - 33 CData $18,$14,$12,$7F,$10,$00 '52 - 4 - 34 CData $27,$45,$45,$45,$39,$00 '53 - 5 - 35 CData $3C,$4A,$49,$49,$30,$00 '54 - 6 - 36 CData $01,$71,$09,$05,$03,$00 '55 - 7 - 37 CData $36,$49,$49,$49,$36,$00 '56 - 8 - 38 CData $06,$49,$49,$49,$3E,$00 '57 - 9 - 39 CData $00,$36,$36,$00,$00,$00 '58 - : - 3A CData $00,$56,$36,$00,$00,$00 '59 - ; - 3B CData $08,$14,$22,$41,$00,$00 '60 - < - 3C CData $14,$14,$14,$14,$14,$00 '61 - = - 3D CData $00,$41,$22,$14,$08,$00 '62 - > - 3E CData $02,$01,$51,$09,$06,$00 '63 - ? - 3F CData $32,$49,$79,$41,$3E,$00 '64 - @ - 40 CData $7E,$11,$11,$11,$7E,$00 '65 - A - 41 CData $7F,$49,$49,$49,$36,$00 '66 - B - 42 CData $3E,$41,$41,$41,$22,$00 '67 - C - 43 CData $7F,$41,$41,$22,$1C,$00 '68 - D - 44 CData $7F,$49,$49,$49,$41,$00 '69 - E - 45 CData $7F,$09,$09,$09,$01,$00 '70 - F - 46 CData $3E,$41,$49,$49,$7A,$00 '71 - G - 47 CData $7F,$08,$08,$08,$7F,$00 '72 - H - 48 CData $00,$41,$7F,$41,$00,$00 '73 - I - 49 CData $20,$40,$41,$3F,$01,$00 '74 - J - 4A CData $7F,$08,$14,$22,$41,$00 '75 - K - 4B CData $7F,$40,$40,$40,$40,$00 '76 - L - 4C CData $7F,$02,$0C,$02,$7F,$00 '77 - M - 4D CData $7F,$04,$08,$10,$7F,$00 '78 - N - 4E CData $3E,$41,$41,$41,$3E,$00 '79 - O - 4F CData $7F,$09,$09,$09,$06,$00 '80 - P - 50 CData $3E,$41,$51,$21,$5E,$00 '81 - Q - 51 CData $7F,$09,$19,$29,$46,$00 '82 - R - 52 CData $46,$49,$49,$49,$31,$00 '83 - S - 53 CData $01,$01,$7F,$01,$01,$00 '84 - T - 54 CData $3F,$40,$40,$40,$3F,$00 '85 - U - 55 CData $1F,$20,$40,$20,$1F,$00 '86 - V - 56 CData $3F,$40,$38,$40,$3F,$00 '87 - W - 57 CData $63,$14,$08,$14,$63,$00 '88 - X - 58 CData $07,$08,$70,$08,$07,$00 '89 - Y - 59 CData $61,$51,$49,$45,$43,$00 '90 - Z - 5A CData $7F,$41,$41,$00,$00,$00 '91 - [ - 5B CData $02,$04,$08,$10,$20,$00 '92 - \ - 5C CData $00,$00,$41,$41,$7F,$00 '93 - ] - 5D CData $04,$02,$01,$02,$04,$00 '94 - ^ - 5E CData $40,$40,$40,$40,$40,$00 '95 - _ - 5F CData $00,$01,$02,$04,$00,$00 '96 - ` - 60 CData $20,$54,$54,$54,$78,$00 '97 - a - 61 CData $7F,$48,$44,$44,$38,$00 '98 - b - 62 CData $38,$44,$44,$44,$20,$00 '99 - c - 63 CData $38,$44,$44,$48,$7F,$00 '100 d - 64 CData $38,$54,$54,$54,$18,$00 '101 e - 65 CData $08,$7E,$09,$01,$02,$00 '102 f - 66 CData $0C,$52,$52,$52,$3E,$00 '103 g - 67 CData $7F,$08,$04,$04,$78,$00 '104 h - 68 CData $00,$44,$7D,$40,$00,$00 '105 i - 69 CData $00,$20,$40,$44,$3D,$00 '106 j - 6A CData $7F,$10,$28,$44,$00,$00 '107 k - 6B CData $00,$41,$7F,$40,$00,$00 '108 l - 6C CData $7C,$04,$18,$04,$78,$00 '109 m - 6D CData $7C,$08,$04,$04,$78,$00 '110 n - 6E CData $38,$44,$44,$44,$38,$00 '111 o - 6F CData $7C,$14,$14,$14,$08,$00 '112 p - 70 CData $08,$14,$14,$18,$7C,$00 '113 q - 71 CData $7C,$08,$04,$04,$08,$00 '114 r - 72 CData $48,$54,$54,$54,$20,$00 '115 s - 73 CData $04,$3F,$44,$40,$20,$00 '116 t - 74 CData $3C,$40,$40,$20,$7C,$00 '117 u - 75 CData $1C,$20,$40,$20,$1C,$00 '118 v - 76 CData $3C,$40,$30,$40,$3C,$00 '119 w - 77 CData $44,$28,$10,$28,$44,$00 '120 x - 78 CData $0C,$50,$50,$50,$3C,$00 '121 y - 79 CData $44,$64,$54,$4C,$44,$00 '122 z - 7A CData $08,$36,$41,$00,$00,$00 '123 { - 7B CData $00,$00,$7F,$00,$00,$00 '124 | - 7C CData $00,$00,$41,$36,$08,$00 '125 } - 7D CData $00,$08,$04,$08,$04,$00 '126 ~ - 7E '-------------------------------------------------------------------- INVADER_SPLASH_SCREEN: CDATA $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$70,$78,_ $7C,$7C,$7C,$7C,$7C,$FC,$F8,$F0,$E0,$C0,$C0,$7C,$7C,$7C,$7C,$7C,_ $7C,$7C,$7C,$7C,$7C,$7C,$F8,$F0,$E0,$C0,$00,$00,$80,$7C,$7C,$7C,_ $7C,$7C,$7C,$7C,$7C,$70,$80,$00,$00,$00,$80,$C0,$F0,$F8,$3E,$3E,_ $3E,$3E,$3E,$3E,$3E,$3E,$3E,$7C,$F8,$E0,$C0,$FE,$FE,$3E,$3E,$3E,_ $3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$20,$A0,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$60,$F0,$0C,$06,$06,$06,$06,$86,_ $86,$86,$06,$06,$06,$0C,$19,$F3,$C7,$3F,$FF,$02,$02,$02,$02,$02,_ $82,$82,$82,$82,$02,$06,$0C,$19,$33,$E7,$F8,$00,$FF,$02,$02,$02,_ $02,$02,$02,$02,$02,$06,$FF,$00,$00,$FE,$FF,$F3,$71,$08,$0C,$06,_ $02,$02,$82,$82,$82,$02,$02,$02,$07,$0F,$FF,$3F,$C0,$FC,$1E,$02,_ $02,$02,$03,$C3,$C3,$C3,$C3,$C3,$C3,$43,$73,$1F,$03,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$03,$3C,$E0,$80,$00,$00,$03,_ $1E,$61,$5E,$58,$58,$58,$58,$99,$BF,$40,$03,$FF,$C0,$00,$00,$00,_ $01,$FF,$83,$FF,$00,$00,$00,$00,$00,$FF,$07,$FE,$0F,$00,$00,$00,_ $F8,$7F,$E0,$00,$00,$00,$0F,$FC,$00,$FF,$01,$FF,$00,$00,$00,$00,_ $00,$FE,$1F,$0C,$0F,$08,$08,$08,$F8,$7E,$07,$FC,$1F,$03,$00,$00,_ $00,$00,$0F,$0F,$0D,$E8,$38,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$63,$E6,$2C,_ $28,$28,$68,$E8,$98,$F0,$00,$01,$01,$07,$FE,$83,$7F,$F0,$00,$00,_ $00,$01,$E1,$21,$60,$30,$30,$0C,$06,$01,$00,$FF,$00,$00,$00,$00,_ $8F,$8C,$8F,$00,$00,$00,$00,$3F,$F8,$3F,$FE,$07,$00,$00,$00,$80,_ $FF,$C1,$FE,$0E,$02,$02,$82,$FB,$1F,$E0,$FF,$03,$00,$00,$00,$F0,_ $BE,$83,$83,$E3,$82,$83,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_ $00,$00,$00,$00,$00,$C0,$40,$40,$5C,$7C,$7C,$FC,$FC,$F0,$40,$4C,_ $7C,$7C,$7C,$FC,$FC,$F8,$20,$00,$0C,$3C,$3C,$7C,$FC,$FC,$F3,$06,_ $0C,$18,$30,$71,$F1,$F1,$F1,$D0,$18,$0C,$3F,$3D,$3C,$FF,$FC,$F8,_ $18,$18,$DF,$1E,$3C,$3C,$3C,$3C,$3C,$3C,$3F,$F8,$08,$08,$08,$0E,_ $0F,$3C,$3F,$3F,$38,$38,$38,$38,$3F,$3E,$7D,$F3,$EC,$08,$F8,$F8,_ $78,$38,$38,$38,$3C,$3F,$3F,$3E,$3E,$3F,$38,$38,$38,$E8,$88,$F8,_ $78,$38,$38,$3C,$3F,$3E,$3E,$38,$30,$20,$40,$80,$C0,$F0,$F8,$FC,_ $FE,$7E,$3E,$1E,$1E,$1E,$1E,$1E,$1C,$10,$00,$40,$80,$00,$00,$00,_ $00,$06,$0E,$36,$C6,$82,$02,$06,$1C,$30,$C6,$8F,$3B,$E3,$82,$02,_ $06,$0C,$30,$6E,$FB,$C3,$03,$02,$02,$02,$1E,$73,$9F,$73,$C3,$83,_ $03,$07,$1C,$70,$C1,$07,$7F,$C3,$03,$03,$03,$03,$7F,$C0,$FF,$FF,_ $FF,$FF,$03,$03,$03,$03,$03,$03,$03,$07,$3E,$C3,$7F,$E0,$00,$00,_ $FF,$03,$03,$01,$E1,$E1,$21,$E1,$01,$01,$03,$06,$8F,$F8,$FF,$3F,_ $FC,$07,$01,$01,$01,$01,$E1,$E1,$A1,$A1,$A1,$21,$E1,$F1,$3F,$E3,_ $3C,$07,$01,$01,$01,$C1,$61,$E1,$61,$01,$01,$01,$01,$C7,$7F,$99,_ $70,$3C,$06,$02,$03,$C1,$31,$B1,$71,$31,$01,$01,$81,$C1,$76,$18,_ $00,$00,$00,$00,$00,$01,$06,$0C,$30,$40,$80,$01,$06,$0C,$31,$C6,_ $9C,$70,$C0,$00,$00,$01,$07,$00,$80,$00,$00,$00,$07,$1E,$F0,$83,_ $0E,$38,$E0,$80,$00,$07,$0C,$7F,$80,$00,$00,$00,$00,$FF,$07,$FF,_ $FF,$FF,$00,$00,$00,$00,$FF,$E0,$00,$00,$00,$07,$F8,$8F,$FC,$80,_ $FF,$00,$00,$00,$FF,$07,$00,$FF,$00,$00,$00,$80,$FF,$FF,$8F,$7E,_ $03,$00,$00,$00,$00,$E4,$A7,$A6,$A6,$26,$FE,$7E,$CF,$F9,$0F,$01,_ $00,$00,$C0,$C8,$CE,$09,$07,$01,$30,$F0,$68,$2C,$27,$39,$3E,$C3,_ $40,$40,$C8,$4E,$0B,$08,$0A,$9B,$F2,$03,$03,$03,$01,$00,$00,$00,_ $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$02,$0C,$30,$60,$C0,_ $C1,$C6,$5D,$F7,$CC,$30,$E0,$C0,$C0,$47,$5E,$6C,$30,$60,$40,$43,_ $5E,$74,$04,$05,$06,$18,$70,$40,$40,$40,$40,$40,$40,$47,$7E,$07,_ $01,$7F,$40,$40,$40,$40,$79,$09,$09,$70,$40,$40,$40,$4F,$74,$01,_ $7F,$40,$40,$40,$47,$44,$46,$41,$40,$20,$10,$0F,$01,$43,$7F,$40,_ $40,$40,$40,$40,$4F,$48,$48,$48,$78,$08,$70,$5E,$43,$40,$40,$60,_ $38,$47,$7B,$47,$41,$40,$70,$1C,$07,$03,$3E,$61,$41,$61,$69,$6F,_ $6D,$66,$61,$30,$10,$1C,$06,$03,$00,$00,$00,$00,$00,$00,$00,$00