Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407

Dependencies:   Joystick N5110 SDFileSystem mbed

Revision:
8:b2faec20ed8f
Parent:
7:babc367a3333
Child:
9:cbb982b7e353
--- a/main.cpp	Mon May 02 16:28:07 2016 +0000
+++ b/main.cpp	Tue May 03 20:16:06 2016 +0000
@@ -1,3 +1,8 @@
+/**
+@file main.cpp
+@brief Implementation File
+*/
+
 /*
 Space Invaders - Avinash Patel 200860407
 
@@ -12,14 +17,11 @@
 #include "mbed.h"
 #include "main.h"
 
-int row_no = 5;
-int col_no = 14;
-
 int main()
 {
-    //Wait for 2 seconds to allow power to settle
+    ///Wait for 2 seconds to allow power to settle
     wait(1);
-    //Initalises the board and perhiperals
+    ///Initalises the board and perhiperals
     init_K64F();
     init_serial();
     init_shoot();
@@ -28,67 +30,166 @@
     lcd.init();
     lcd.clear();
 
-    //Configures the function pointer for the invaders normal missile
+    ///Configures the function pointer for the invaders normal missile
     move_invader_normal_missile_isr[0] = &move_invader_normal_missile_0_isr;
     move_invader_normal_missile_isr[1] = &move_invader_normal_missile_1_isr;
 
-    //Samples joystick every 0.05 second
+    ///Samples joystick every 0.05 second
     move_joystick.attach(&move_joystick_isr, 0.05);
 
-    
-
     while (true) {
-        if (game_state == menu) { //Menu screen
+        if (game_state == menu) { ///Menu screen
+            lcd.clear();
+            fsm_state = 0; ///Sets the fsm state to 0
+            MenuScreen();
+        } else if (game_state == paused) { ///Paused screen
+            ///Clears the screen
             lcd.clear();
-            fsm_state = 0; //Sets the fsm state to 0
-            while (game_state == menu) {
-                lcd.printString("Space Invaders", 0, 0);
-                lcd.printString("Menu", 28, 1);
-                lcd.drawLine(0, 15, 83, 15, 2);
-
-                lcd.printString("New Game", 5, 2);
-                lcd.printString("Load Game", 5, 3);
-                lcd.printString("High Scores", 5, 4);
-                lcd.printString("Settings", 5, 5);
+            fsm_state = 0; ///Ssets the fsm state to 0
+            PauseScreen();
+        } else if (game_state == game) { ///Game screen
+            AttachTickers();
+            Game();
+        } else if (game_state == save) {
+            ///Creates file pointer and attaches the file
+            FILE *fp;
+            fp = fopen("/sd/game_save.txt", "w");
 
-                //Draws the cursor
-                cursor_y_pos = ((fsm_state+2)*8)+3; //Adds 2 to the fsm state to get the bank, multiplies it by 8 to get the pixel no and offsets it by 3
-                lcd.drawRect(74, cursor_y_pos, 2, 2, 1);
-
-                if (g_move_joystick_flag) {
-                    g_move_joystick_flag = false;
-
-                    //Moves the cursor to match the selected option, only if the joystick isn't centred
-                    MoveCursor(fsm_main_menu);
+            if (fp == NULL) { ///If file can't be opened then error
+                lcd.clear();
+                lcd.printString("Error Opening", 1, 1);
+                wait(2.0);
+            } else {
+                ///Prints booleans to file
+                fprintf(fp, "%d\n", invaders_in_state2);
+                fprintf(fp, "%d,%d,%d,%d,%d,%d\n", invader_direction, cannon_missile_on_screen, ufo_on_screen, ufo_direction, ufo_bonus, is_muted);
+                ///Prints integers to file
+                fprintf(fp, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n", score, shot_count, number_of_lives, cannon_xpos, cannon_missile_x_pos, cannon_missile_y_pos, no_of_alive_invaders, down_count, ufo_x_pos);
+                ///Prints small invader info to file
+                for (int small = 0; small < 5; ++small) {
+                    fprintf(fp, "%d,%d,%d\n", small_invader[small].x_pos, small_invader[small].y_pos, small_invader[small].status);
+                }
+                ///Prints medium invader info to file
+                for (int medium = 0; medium < 5; ++medium) {
+                    fprintf(fp, "%d,%d,%d\n", medium_invader[medium].x_pos, medium_invader[medium].y_pos, medium_invader[medium].status);
+                }
+                ///Prints large invader info to file
+                for (int large = 0; large < 5; ++large) {
+                    fprintf(fp, "%d,%d,%d\n", large_invader[large].x_pos, large_invader[large].y_pos, large_invader[large].status);
                 }
-
-                if (g_shoot_pressed_flag) {
-                    g_shoot_pressed_flag = false;
-
-                    game_state = fsm_main_menu[fsm_state].output;
-
-                    //If the game state is equal to the game initalise it
-                    if (game_state == game) {
-                        InitaliseGame();
+                ///Stores invader missile data
+                for (int missile = 0; missile < 2; ++missile) {
+                    fprintf(fp, "%d,%d,%d\n", invader_normal_missile[missile].x_pos, invader_normal_missile[missile].y_pos, invader_normal_missile[missile].fired);
+                }
+                ///Stores barrier data
+                for (int barrier_no = 0; barrier_no < 3; ++barrier_no) {
+                    fprintf(fp, "%d,%d\n", barrier[barrier_no].x_pos, barrier[barrier_no].y_pos);
+                    ///Stores barrier before bitmaps
+                    for (int row = 0; row < 8; ++row) {
+                        for (int col = 0; col < 14; ++col) {
+                            if (col < 13) {
+                                fprintf(fp, "%d,", barrier[barrier_no].before_bitmap[row][col]);
+                            } else {
+                                fprintf(fp, "%d\n", barrier[barrier_no].before_bitmap[row][col]);
+                            }
+                        }
+                    }
+                    ///Stores barrier after bitmaps
+                    for (int row = 0; row < 8; ++row) {
+                        for (int col = 0; col < 14; ++col) {
+                            if (col < 13) {
+                                fprintf(fp, "%d,", barrier[barrier_no].after_bitmap[row][col]);
+                            } else {
+                                fprintf(fp, "%d\n", barrier[barrier_no].after_bitmap[row][col]);
+                            }
+                        }
                     }
                 }
 
-                if(joystick.get_button_flag()) {
-                    joystick.set_button_flag(0);
-                }
-
-                lcd.refresh();
-                sleep();
+                fclose(fp);
+                game_state = paused;
             }
-        } else if (game_state == paused) { //Paused screen
-            //Clears the screen
-            lcd.clear();
-            //Resets the fsm state to 0
-            fsm_state = 0;
-            PauseScreen();
-        } else if (game_state == game) { //Game screen
-            AttachTickers();
-            Game();
+        } else if (game_state == load) {
+            ///Creates file pointer and attaches the file
+            FILE *fp;
+            fp = fopen("/sd/game_save.txt", "r");
+            rewind(fp);
+
+            if (fp == NULL) { ///If file can't be opened then error
+                lcd.clear();
+                lcd.printString("Error Opening", 1, 1);
+                wait(2.0);
+
+                game_state = menu;
+            } else {
+                int test;
+                ///Prints booleans to file
+                fscanf(fp, "%d\n", &invaders_in_state2);
+                test = fscanf(fp, "%d,%d,%d,%d,%d,%d", &invader_direction, &cannon_missile_on_screen, &ufo_on_screen, &ufo_direction, &ufo_bonus, &is_muted);
+                
+                pc.printf("Bool: %d\n", test);
+                ///Prints integers to file
+                test = fscanf(fp, "%d,%d,%d,%d,%d,%d,%d,%d,%d", &score, &shot_count, &number_of_lives, &cannon_xpos, &cannon_missile_x_pos, &cannon_missile_y_pos, &no_of_alive_invaders, &down_count, &ufo_x_pos);
+                pc.printf("Int: %d\n", test);
+                ///Prints small invader info to file
+                for (int small = 0; small < 5; ++small) {
+                    test = fscanf(fp, "%d,%d,%d", &(small_invader[small].x_pos), &(small_invader[small].y_pos), &(small_invader[small].status));
+                    pc.printf("Small: %d\n", test);
+                }
+                ///Prints medium invader info to file
+                for (int medium = 0; medium < 5; ++medium) {
+                    test = fscanf(fp, "%d,%d,%d", &(medium_invader[medium].x_pos), &(medium_invader[medium].y_pos), &(medium_invader[medium].status));
+                    pc.printf("Medium: %d\n", test);
+                }
+                ///Prints large invader info to file
+                for (int large = 0; large < 5; ++large) {
+                    test = fscanf(fp, "%d,%d,%d", &(large_invader[large].x_pos), &(large_invader[large].y_pos), &(large_invader[large].status));
+                    pc.printf("Large: %d\n", test);
+                }
+                ///Stores invader missile data
+                for (int missile = 0; missile < 2; ++missile) {
+                    test = fscanf(fp, "%d,%d,%d", &(invader_normal_missile[missile].x_pos), &(invader_normal_missile[missile].y_pos), &(invader_normal_missile[missile].fired));
+                    pc.printf("Missile: %d\n", test);
+                }
+                ///Stores barrier data
+                for (int barrier_no = 0; barrier_no < 3; ++barrier_no) {
+                    test = fscanf(fp, "%d,%d", &(barrier[barrier_no].x_pos), &(barrier[barrier_no].y_pos));
+                    pc.printf("Barrier: %d\n", test);
+                    ///Stores barrier before bitmaps
+                    for (int row = 0; row < 8; ++row) {
+                        for (int col = 0; col < 14; ++col) {
+                            if (col < 13) {
+                                test = fscanf(fp, "%d,", &(barrier[barrier_no].before_bitmap[row][col]));
+                                pc.printf("Barrier Before: %d\n", test);
+                            } else {
+                                test = fscanf(fp, "%d", &(barrier[barrier_no].before_bitmap[row][col]));
+                                pc.printf("Barrier Before: %d\n", test);
+                            }
+                        }
+                    }
+                    ///Stores barrier after bitmaps
+                    for (int row = 0; row < 8; ++row) {
+                        for (int col = 0; col < 14; ++col) {
+                            if (col < 13) {
+                                test = fscanf(fp, "%d,", &(barrier[barrier_no].after_bitmap[row][col]));
+                                pc.printf("Barrier After: %d\n", test);
+                            } else {
+                                test = fscanf(fp, "%d", &(barrier[barrier_no].after_bitmap[row][col]));
+                                pc.printf("Barrier After: %d\n", test);
+                            }
+                        }
+                    }
+                }
+                
+
+                fclose(fp);
+                game_state = game;
+
+                g_update_screen_flag = true;
+                g_move_joystick_flag = true;
+                g_move_enemies_flag = true;
+                g_fire_buzzer_flag = true;
+            }           
         }
 
         sleep();
@@ -97,20 +198,20 @@
 
 void init_K64F()
 {
-    // on-board LEDs are active-low, so set pin high to turn them off.
+    /// on-board LEDs are active-low, so set pin high to turn them off.
     r_led = 1;
     g_led = 1;
     b_led = 1;
 
-    // since the on-board switches have external pull-ups, we should disable the internal pull-down
-    // resistors that are enabled by default using InterruptIn
+    /// since the on-board switches have external pull-ups, we should disable the internal pull-down
+    /// resistors that are enabled by default using InterruptIn
     sw2.mode(PullNone);
     sw3.mode(PullNone);
 }
 
 void error()
 {
-    while(1) {  // if error, hang while flashing error message
+    while(1) {  /// if error, hang while flashing error message
         r_led = 0;
         wait(0.2);
         r_led = 1;
@@ -120,15 +221,15 @@
 
 void init_serial()
 {
-    // set to highest baud - ensure terminal software matches
+    /// set to highest baud - ensure terminal software matches
     pc.baud(115200);
 }
 
-//Seeds the random number generator with noise from an analog in pin
+///Seeds the random number generator with noise from an analog in pin
 void init_rng()
 {
-    AnalogIn rng_seed(PTC10); //Creates a AnalogIn on a unused pin
-    srand(floor(10000*rng_seed.read())); //Sets the seed as 10000x the input of the analog in
+    AnalogIn rng_seed(PTC10); ///Creates a AnalogIn on a unused pin
+    srand(floor(10000*rng_seed.read())); ///Sets the seed as 10000x the input of the analog in
 }
 
 void init_shoot()
@@ -149,12 +250,12 @@
 
 void shoot_pressed_isr()
 {
-    //Only sets the shoot pressed flag 0.1s after the last press
+    ///Only sets the shoot pressed flag 0.1s after the last press
     if (!g_shoot_button_debounce_flag) {
         g_shoot_pressed_flag = true;
         g_shoot_button_debounce_flag = true;
 
-        //Attaches a timeout to clear the debounce flag 0.125 seconds after it was set
+        ///Attaches a timeout to clear the debounce flag 0.125 seconds after it was set
         shoot_button_debounce.attach(&shoot_button_debounce_isr, 0.125);
     }
 }
@@ -166,15 +267,15 @@
 
 void move_joystick_isr()
 {
-    //Always set the move flag in a game
+    ///Always set the move flag in a game
     if (game_state == game) {
         g_move_joystick_flag = true;
     } else if (!g_joystick_cursor_regulator_flag) {
-        //Only sets the flag if the regulator is not set
+        ///Only sets the flag if the regulator is not set
         g_move_joystick_flag = true;
         g_joystick_cursor_regulator_flag = true;
 
-        //Attachs a timeout to clear the regulator in 0.1s to prevent the cursor from behaving erratically
+        ///Attachs a timeout to clear the regulator in 0.1s to prevent the cursor from behaving erratically
         joystick_cursor_regulator.attach(&joystick_cursor_regulator_isr, 0.1);
     }
 }
@@ -204,11 +305,22 @@
     g_cannon_hit_flag = false;
 }
 
+void move_ufo_isr()
+{
+    g_move_ufo_flag = true;
+}
+
+void fire_buzzer_isr()
+{
+    g_fire_buzzer_flag = true;
+}
+
 void Game()
 {
-    //Stays within the loop while the selected state is game
+    ///Stays within the loop while the selected state is game
     while (game_state == game) {
-        //If the game is over detach all the tickers
+        pc.printf("Mute: %d\n", is_muted);
+        ///If the game is over detach all the tickers
         if (number_of_lives == 0) {
             DetachTickers();
 
@@ -217,26 +329,27 @@
             char buffer[14];
             sprintf(buffer, "Score: %d", score);
             lcd.printString(buffer, 1, 3);
-        } else if (no_of_alive_invaders == 0) { //If the player wins a round
-            //Resets the no of alive invaders
+        } else if (no_of_alive_invaders == 0) { ///If the player wins a round
+            ///Resets the no of alive invaders
             no_of_alive_invaders = 15;
-            //Detaches the enemy ticker while reinitalising invaders
+            down_count = 0;
+            ///Detaches the enemy ticker while reinitalising invaders
             move_enemies.detach();
-            //Reinitalises objects
+            ///Reinitalises objects
             InitSmallInvaders();
             InitMediumInvaders();
             InitLargeInvaders();
-            //Reattaches enemy ticker
+            ///Reattaches enemy ticker
             move_enemies.attach(&move_enemies_isr, 1);
         } else {
-            //Updates pixels on the screen
+            ///Updates pixels on the screen
             if (g_update_screen_flag) {
                 g_update_screen_flag = false;
 
                 UpdateScreen();
             }
 
-            //Controls cannon movement
+            ///Controls cannon movement
             if (g_move_joystick_flag) {
                 g_move_joystick_flag = false;
 
@@ -244,67 +357,116 @@
                 DrawBarriers();
             }
 
-            //Controls enemy movement
+            ///Controls enemy movement
             if (g_move_enemies_flag) {
                 g_move_enemies_flag = false;
 
-                //Increses the speed the invaders move
+                ///Increses the speed the invaders move
                 move_enemies.detach();
                 ticker_period = 0.1+(no_of_alive_invaders*0.06);
                 move_enemies.attach(&move_enemies_isr, ticker_period);
 
-                //Clears the old bitmaps
+                //Attach the buzzer timeout if mute is unselected
+                if (!is_muted) {
+                    fire_buzzer.attach(&fire_buzzer_isr, ticker_period/2.0f);
+                }
+
+                ///Clears the old bitmaps
                 ClearSmallInvaders();
                 ClearMediumInvaders();
                 ClearLargeInvaders();
 
                 MoveInvaderXPositions();
-                //Switches the bitmap state
+                ///Switches the bitmap state
                 invaders_in_state2 = !invaders_in_state2;
 
-                //Draws the invaders
+                ///Draws the invaders
                 DrawSmallInvaders();
                 DrawMediumInvaders();
                 DrawLargeInvaders();
 
-                //Attemots to fire the invaders missiles
+                ///Attempts to fire the invaders missiles
                 AttemptToFireInvaderNormalMissiles();
+
+                ///Attempts to spawn UFO
+                AttemptToSpawnUFO();
             }
 
-            //Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen
+            if (g_fire_buzzer_flag && !is_muted) {
+                g_fire_buzzer_flag = false;
+
+                if (play_sound) {
+                    buzzer.period(1/fsm_buzzer[buzzer_state].frequency);
+                    buzzer.write(0.5);
+                    play_sound = false;
+                } else {
+                    buzzer.write(0);
+                    buzzer_state = fsm_buzzer[buzzer_state].next_state;
+                    play_sound = true;
+                }
+            }
+
+            ///Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen
             if (g_shoot_pressed_flag) {
                 g_shoot_pressed_flag = false;
 
                 if (!cannon_missile_on_screen) {
                     FireCannonMissile();
+
+                    ///Counts fired missiles to see if the ufo bonus can be applied
+                    if (ufo_bonus && shot_count > 14) {
+                        shot_count = 0;
+                    } else if (shot_count > 22) {
+                        shot_count = 0;
+                    } else {
+                        ++shot_count;
+                    }
                 }
             }
 
-            //Move the cannon shot
+            ///Move the cannon shot
             if (g_move_cannon_missile_flag) {
                 g_move_cannon_missile_flag = false;
 
                 MoveCannonMissile();
             }
 
-            //Moves the invaders 1st normal missile
+            ///Moves the invaders 1st normal missile
             if (g_move_invader_normal_missile_flag[0]) {
                 g_move_invader_normal_missile_flag[0] = false;
 
                 MoveInvaderNormalMissile(0);
             }
 
-            //Moves the invaders 2nd normal missile
+            ///Moves the invaders 2nd normal missile
             if (g_move_invader_normal_missile_flag[1]) {
                 g_move_invader_normal_missile_flag[1] = false;
 
                 MoveInvaderNormalMissile(1);
             }
 
+            ///Moves the UFO
+            if (g_move_ufo_flag) {
+                g_move_ufo_flag = false;
+
+                ///Clears the UFO
+                ClearUFO();
+
+                ///Moves the UFO in the correct direction
+                if (ufo_direction == RIGHT) {
+                    ufo_x_pos += 2;
+                } else {
+                    ufo_x_pos -= 2;
+                }
+
+                ///Draws the UFO
+                DrawUFO();
+            }
+
             if (joystick.get_button_flag()) {
                 joystick.set_button_flag(0);
 
-                //Detach all game tickers
+                ///Detach all game tickers
                 DetachTickers();
                 game_state = paused;
             }
@@ -316,20 +478,29 @@
 
 void InitaliseGame()
 {
-    //Clears the screen buffer and runs init functions
+    ///Clears the screen buffer and runs init functions
     memset(screen_buffer, 0, sizeof(screen_buffer));
     no_of_alive_invaders = 15;
     score = 0;
     number_of_lives = 3;
+    down_count = 0;
+    cannon_xpos = 15;
+    ufo_bonus = false;
+    shot_count = 0;
     InitSmallInvaders();
     InitMediumInvaders();
     InitLargeInvaders();
     InitBarriers();
-    //Sets the flags so enemies pop up straight away
+    ///If the sound is set activate the buzzer flag
+    if (!is_muted) {
+        g_fire_buzzer_flag = true;
+    }
+    ///Sets the flags so enemies pop up straight away
     g_update_screen_flag = true;
     g_move_joystick_flag = true;
     g_move_enemies_flag = true;
-    //Forces the missiles to have the fired flags to flase
+    g_fire_buzzer_flag = true;
+    ///Forces the missiles to have the fired flags to flase
     cannon_missile_on_screen = false;
     invader_normal_missile[0].fired = false;
     invader_normal_missile[1].fired = false;
@@ -337,7 +508,7 @@
 
 void UpdateScreen()
 {
-    //Loops through the screen buffer and sets pixels on the LCD
+    ///Loops through the screen buffer and sets pixels on the LCD
     for (int col = 0; col < 84; ++col) {
         for (int row = 0; row < 48; ++row) {
             if (screen_buffer[col][row]) {
@@ -353,7 +524,7 @@
 
 void MoveCannon()
 {
-    //Clears the cannon
+    ///Clears the cannon
     for (int col = 0; col < 9; ++col) {
         for (int row = 0; row < 5; ++row) {
             if(cannon_bitmap[row][col]) {
@@ -362,7 +533,7 @@
         }
     }
 
-    //Changes the position of the cannon when the joystick is moved, capping at 0 and 75 so it always fits on the screen
+    ///Changes the position of the cannon when the joystick is moved, capping at 0 and 75 so it always fits on the screen
     if (joystick.GetXValue() < 0.25f) {
         cannon_xpos--;
         if (cannon_xpos < 0) {
@@ -375,7 +546,7 @@
         }
     }
 
-    //Redraws the cannon
+    ///Redraws the cannon
     for (int col = 0; col < 9; ++col) {
         for (int row = 0; row < 5; ++row) {
             if(cannon_bitmap[row][col]) {
@@ -385,17 +556,17 @@
     }
 }
 
-//Sets the position and status of the small invaders
+///Sets the position and status of the small invaders
 void InitSmallInvaders()
 {
     for (int i = 0; i < 5; ++i) {
-        small_invader[i].x_pos = 2 + (i*13); // Large invaders are 12 across so add 13 for a gap space
+        small_invader[i].x_pos = 2 + (i*13); /// Large invaders are 12 across so add 13 for a gap space
         small_invader[i].y_pos = 1;
         small_invader[i].status = alive;
     }
 }
 
-//Cycles through all the small invaders. If they're not already dead clear them
+///Cycles through all the small invaders. If they're not already dead clear them
 void ClearSmallInvaders()
 {
     for (int i = 0; i < 5; ++i) {
@@ -405,7 +576,7 @@
     }
 }
 
-//Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0
+///Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0
 void ClearSingleSmallInvader(int invader_no)
 {
     for (int col = 0; col < 8; ++col) {
@@ -425,7 +596,7 @@
     small_invader[invader_no].status = (small_invader[invader_no].status == dying) ? dead : alive;
 }
 
-//Cycles through all the small invaders. If they're alive set them in the screen buffer
+///Cycles through all the small invaders. If they're alive set them in the screen buffer
 void DrawSmallInvaders()
 {
     for (int i = 0; i < 5; ++i) {
@@ -435,7 +606,7 @@
     }
 }
 
-//Cycles through the the screen invader bitmap and sets the pixels in the buffer
+///Cycles through the the screen invader bitmap and sets the pixels in the buffer
 void DrawSingleSmallInvader(int invader_no)
 {
     for (int col = 0; col < 8; ++col) {
@@ -453,17 +624,17 @@
     }
 }
 
-//Sets the position and aliveness of the medium invaders
+///Sets the position and aliveness of the medium invaders
 void InitMediumInvaders()
 {
     for (int i = 0; i < 5; ++i) {
-        medium_invader[i].x_pos = 1 + (i*13); // Large invaders are 12 across so add 13 for a gap space
+        medium_invader[i].x_pos = 1 + (i*13); /// Large invaders are 12 across so add 13 for a gap space
         medium_invader[i].y_pos = 8;
         medium_invader[i].status = alive;
     }
 }
 
-//Cycles through all the medium invaders. If they're not already dead clear them
+///Cycles through all the medium invaders. If they're not already dead clear them
 void ClearMediumInvaders()
 {
     for (int i = 0; i < 5; ++i) {
@@ -473,7 +644,7 @@
     }
 }
 
-//Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0
+///Cycles through the the screen invader bitmap and sets the pixels in the buffer to 0
 void ClearSingleMediumInvader(int invader_no)
 {
     for (int col = 0; col < 10; ++col) {
@@ -493,7 +664,7 @@
     medium_invader[invader_no].status = (medium_invader[invader_no].status == dying) ? dead : alive;
 }
 
-//Cycles through all the medium invaders. If they're alive set them in the screen buffer
+///Cycles through all the medium invaders. If they're alive set them in the screen buffer
 void DrawMediumInvaders()
 {
     for (int i = 0; i < 5; ++i) {
@@ -503,7 +674,7 @@
     }
 }
 
-//Cycles through the the screen invader bitmap and sets the pixels in the buffer
+///Cycles through the the screen invader bitmap and sets the pixels in the buffer
 void DrawSingleMediumInvader(int invader_no)
 {
     for (int col = 0; col < 10; ++col) {
@@ -521,7 +692,7 @@
     }
 }
 
-//Sets the position and status of the large invaders
+///Sets the position and status of the large invaders
 void InitLargeInvaders()
 {
     for (int i = 0; i < 5; ++i) {
@@ -531,7 +702,7 @@
     }
 }
 
-//Cycles through all the large invaders. If they're not already dead clear them
+///Cycles through all the large invaders. If they're not already dead clear them
 void ClearLargeInvaders()
 {
     for (int i = 0; i < 5; ++i) {
@@ -541,7 +712,7 @@
     }
 }
 
-//Loops through the large invader bitmap, if the pixel in the bitmap is set to 1, set the pixel in the buffer to 0
+///Loops through the large invader bitmap, if the pixel in the bitmap is set to 1, set the pixel in the buffer to 0
 void ClearSingleLargeInvader(int invader_no)
 {
     for (int col = 0; col < 12; ++col) {
@@ -561,7 +732,7 @@
     large_invader[invader_no].status = (large_invader[invader_no].status == dying) ? dead : alive;
 }
 
-//Cycles through all the large invaders. If they're alive set them in the screen buffer
+///Cycles through all the large invaders. If they're alive set them in the screen buffer
 void DrawLargeInvaders()
 {
     for (int i = 0; i < 5; ++i) {
@@ -571,7 +742,7 @@
     }
 }
 
-//Cycles through the the screen invader bitmap and sets the pixels in the buffer
+///Cycles through the the screen invader bitmap and sets the pixels in the buffer
 void DrawSingleLargeInvader(int invader_no)
 {
     for (int col = 0; col < 12; ++col) {
@@ -589,13 +760,13 @@
     }
 }
 
-//Sets the position and loads the bitmap into the barrier objects
+///Sets the position and loads the bitmap into the barrier objects
 void InitBarriers()
 {
     for (int i = 0; i < 3; ++i) {
         barrier[i].x_pos = 10 + (i*25);
         barrier[i].y_pos = 33;
-        //Copies the bitmap into the structs
+        ///Copies the bitmap into the structs
         memcpy(barrier[i].before_bitmap, barrier_bitmap, sizeof(barrier_bitmap));
         memcpy(barrier[i].after_bitmap, barrier_bitmap, sizeof(barrier_bitmap));
     }
@@ -603,7 +774,7 @@
 
 void DrawBarriers()
 {
-    //Clears the barrier and redraws it with damage applied
+    ///Clears the barrier and redraws it with damage applied
     for (int i = 0; i < 3; ++i) {
         for (int col = 0; col < 14; ++col) {
             for (int row = 0; row < 8; ++row) {
@@ -615,27 +786,27 @@
                 }
             }
         }
-        //Copies the after array to the before array
+        ///Copies the after array to the before array
         memcpy(barrier[i].before_bitmap, barrier[i].after_bitmap, sizeof(barrier[i].after_bitmap));
     }
 }
 
 void MoveInvaderXPositions()
 {
-    //Moves the invader in the current direction
+    ///Moves the invader in the current direction
     if (invader_direction == RIGHT) {
-        //Checking the right limit
+        ///Checking the right limit
         int right_invader_limit = CalculateInvaderRightLimit();
         MoveInvadersRight(right_invader_limit);
     } else {
-        //Checks the left limit
+        ///Checks the left limit
         int left_invader_limit = CalculateInvaderLeftLimit();
         MoveInvadersLeft(left_invader_limit);
     }
 }
 
-//Checks the status off the invaders per column, starting from the left
-//If they're alive return the row number
+///Checks the status off the invaders per column, starting from the left
+///If they're alive return the row number
 int CalculateInvaderLeftLimit()
 {
     for (int i = 0; i < 5; ++i) {
@@ -644,12 +815,12 @@
         }
     }
 
-    //Sort gameover out stuff after
+    ///Sort gameover out stuff after
     return 4;
 }
 
-//Checks the status off the invaders per column, starting from the right
-//If they're alive return the row number
+///Checks the status off the invaders per column, starting from the right
+///If they're alive return the row number
 int CalculateInvaderRightLimit()
 {
     for (int i = 4; i >= 0; --i) {
@@ -658,59 +829,60 @@
         }
     }
 
-    //Sort gameover stuff
+    ///Sort gameover stuff
     return 0;
 }
 
 void MoveInvadersLeft(int limit)
 {
-    //Checks the first large invader to see if it can travel anymore
+    ///Checks the first large invader to see if it can travel anymore
     if (large_invader[limit].x_pos > 1) {
         for (int i = 0; i < 5; ++i) {
-            //Moves the invaders 2 to the left
+            ///Moves the invaders 2 to the left
             small_invader[i].x_pos -= 2;
             medium_invader[i].x_pos -= 2;
             large_invader[i].x_pos -= 2;
         }
     } else {
-        //Shifts the Invaders down and passes in the new direction
+        ///Shifts the Invaders down and passes in the new direction
         MoveInvaderYPositions(RIGHT);
     }
 }
 
 void MoveInvadersRight(int limit)
 {
-    //Checks the first large invader to see if it can travel anymore
+    ///Checks the first large invader to see if it can travel anymore
     if (large_invader[limit].x_pos < 71) {
-        //Moves the invaders 2 to the right
+        ///Moves the invaders 2 to the right
         for (int i = 0; i < 5; ++i) {
             small_invader[i].x_pos += 2;
             medium_invader[i].x_pos += 2;
             large_invader[i].x_pos += 2;
         }
     } else {
-        //Shifts the Invaders down and passes in the new direction
+        ///Shifts the Invaders down and passes in the new direction
         MoveInvaderYPositions(LEFT);
     }
 }
 
 void MoveInvaderYPositions(bool new_direction)
 {
-    //Finds the invaders lower limit
+    ///Finds the invaders lower limit
     Invader lowest_invader = CalculateInvaderYLimit();
 
-    //When moving down lowest_invader should not equal none
+    ///When moving down lowest_invader should not equal none
     if (lowest_invader == none) {
         error();
     }
 
-    //If an invader touches the bottom the game ends, otherwise the invaders descend
+    ///If an invader touches the bottom the game ends, otherwise the invaders descend
     if (small_invader[0].y_pos < 33 - (7*lowest_invader)) {
         for (int i = 0; i < 5; ++i) {
             small_invader[i].y_pos += 3;
             medium_invader[i].y_pos += 3;
             large_invader[i].y_pos += 3;
         }
+        ++down_count;
         invader_direction = new_direction;
     } else {
         number_of_lives = 0;
@@ -719,7 +891,7 @@
 
 Invader CalculateInvaderYLimit()
 {
-    //Checks to see which row of invaders are still alive to work out maximum y positions
+    ///Checks to see which row of invaders are still alive to work out maximum y positions
     if (large_invader[0].status == alive || large_invader[1].status == alive || large_invader[2].status == alive || large_invader[3].status == alive || large_invader[4].status == alive) {
         return large;
     } else if (medium_invader[0].status == alive || medium_invader[1].status == alive || medium_invader[2].status == alive || medium_invader[3].status == alive || medium_invader[4].status == alive) {
@@ -729,7 +901,7 @@
     }
 }
 
-//Queries the invaders on their status and returns the type of invader which is alive
+///Queries the invaders on their status and returns the type of invader which is alive
 Invader LowestInvaderInColumn(int column)
 {
     if (large_invader[column].status == alive) {
@@ -743,59 +915,38 @@
     }
 }
 
-/*
-void InitUFO()
-{
-
-}
-*/
-
-void DrawUFO()
-{
-    //Draws the UFO
-    int x_pos = 20;
-    int y_pos = 25;
-    for (int col = 0; col < col_no; ++col) {
-        for (int row = 0; row < row_no; ++row) {
-            if(ufo_bitmap[row][col]) {
-                screen_buffer[x_pos + col][y_pos + row] = ufo_pixel;
-            }
-        }
-    }
-}
-
 void FireCannonMissile()
 {
-    //Sets the cannon fired flag to true
+    ///Sets the cannon fired flag to true
     cannon_missile_on_screen = true;
 
-    //Offset cannon missile x position by 4 of the cannons x pos
+    ///Offset cannon missile x position by 4 of the cannons x pos
     cannon_missile_x_pos = cannon_xpos + 4;
-    //Will always have a starting y of 40
+    ///Will always have a starting y of 40
     cannon_missile_y_pos = 40;
-    //Attach the move cannon missile
+    ///Attach the move cannon missile
     move_cannon_missile.attach(&move_cannon_missile_isr, 0.05);
 }
 
 void MoveCannonMissile()
 {
-    //Checks bullet will not go beyond the bounds of the screen buffer
+    ///Checks bullet will not go beyond the bounds of the screen buffer
     if (cannon_missile_y_pos > -1) {
-        //Loops throught the shot bitmap and clears the pixels in the screen buffer
+        ///Loops throught the shot bitmap and clears the pixels in the screen buffer
         for (int row = 0; row < 4; ++row) {
-            //Clears the position where the bullet was
+            ///Clears the position where the bullet was
             screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel;
         }
 
-        //Increments the shot going up the screen
+        ///Increments the shot going up the screen
         --cannon_missile_y_pos;
 
-        //Checks to see if the shot will hit anything
+        ///Checks to see if the shot will hit anything
         CollisionDetectionCannonMissile();
     } else {
-        //Loops throught the shot bitmap and clears the pixels in the screen buffer
+        ///Loops throught the shot bitmap and clears the pixels in the screen buffer
         for (int row = 1; row < 4; ++row) {
-            //Clears the position where the bullet was
+            ///Clears the position where the bullet was
             screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] = empty_pixel;
         }
 
@@ -804,38 +955,48 @@
     }
 }
 
-//Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen buffer
+///Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen buffer
 void CollisionDetectionCannonMissile()
 {
     for (int row = 0; row < 4; ++row) {
         int object_no;
         int pixel_check = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row];
-        pc.printf("Pixel check: %d\n", pixel_check);
-        if (pixel_check >= first_small_invader_pixel && pixel_check < ufo_pixel) { //Collides with a small invader
-            //Find the object no of the small invader it hit, clears it and increments the score
+        if (pixel_check >= first_small_invader_pixel && pixel_check < ufo_pixel) { ///Collides with a small invader
+            ///Find the object no of the small invader it hit, clears it and increments the score
             object_no = CannonMissileHitInvader(first_small_invader_pixel, row, small_invader);
             ClearSingleSmallInvader(object_no);
             score += 40;
             break;
-        } else if (pixel_check >= first_medium_invader_pixel && pixel_check < first_small_invader_pixel) { //Collides with a medium invader
-            //Find the object no of the medium invader it hit, clears it and increments the score
+        } else if (pixel_check >= first_medium_invader_pixel && pixel_check < first_small_invader_pixel) { ///Collides with a medium invader
+            ///Find the object no of the medium invader it hit, clears it and increments the score
             object_no = CannonMissileHitInvader(first_medium_invader_pixel, row, medium_invader);
             ClearSingleMediumInvader(object_no);
             score += 20;
             break;
-        } else if (pixel_check >= first_large_invader_pixel && pixel_check < first_medium_invader_pixel) { //Collides with a large invader
-            //Find the object no of the large invader it hit, clears it and increments the score
+        } else if (pixel_check >= first_large_invader_pixel && pixel_check < first_medium_invader_pixel) { ///Collides with a large invader
+            ///Find the object no of the large invader it hit, clears it and increments the score
             object_no = CannonMissileHitInvader(first_large_invader_pixel, row, large_invader);
             ClearSingleLargeInvader(object_no);
             score += 10;
             break;
-        } else if (pixel_check >= first_barrier_pixel && pixel_check < (first_barrier_pixel + 3)) { //Collides with a barrier
-            //Adds the destruction done to the barrier to the bitmap and redraws the barriers
+        } else if (pixel_check >= first_barrier_pixel && pixel_check < (first_barrier_pixel + 3)) { ///Collides with a barrier
+            ///Adds the destruction done to the barrier to the bitmap and redraws the barriers
             CannonMissileHitBarrier(row);
             DrawBarriers();
             break;
-        } else if (pixel_check == ufo_pixel) { //Collides with a UFO
-            pc.printf("UFO Hit\n");
+        } else if (pixel_check == ufo_pixel) { ///Collides with a UFO
+            ///Clears the UFO, calculates score depending on the ufo bonus
+            ClearUFO();
+            ufo_on_screen = false;
+            move_ufo.detach();
+            if (ufo_bonus && shot_count == 15) { ///If the shot bonus is active and on the 15th shot, give 300 points
+                score += 300;
+            } else if (shot_count == 23) { ///If the shot bonus isn't active and on the 23rd shot, give 300 points and activate the bonus
+                ufo_bonus = true;
+                score += 300;
+            } else { ///Randomly assign score between 50, 100, 150 points
+                score += 50 * ((rand() % 3) + 1);
+            }
             cannon_missile_on_screen = false;
             move_cannon_missile.detach();
             break;
@@ -845,7 +1006,7 @@
     }
 }
 
-//Finds the invader number the missile hits, sets the hit invader to dying, decrements the no_of_alive_invaders and stops the shot from travalling up the screen
+///Finds the invader number the missile hits, sets the hit invader to dying, decrements the no_of_alive_invaders and stops the shot from travalling up the screen
 int CannonMissileHitInvader(int first_pixel, int row, struct Invaders (&invader)[5])
 {
     int invader_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_pixel;
@@ -857,18 +1018,18 @@
     return invader_no;
 }
 
-//Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
+///Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
 void CannonMissileHitBarrier(int row)
 {
     int barrier_no = screen_buffer[cannon_missile_x_pos][cannon_missile_y_pos + row] - first_barrier_pixel;
-    //Essentially inverse of barrier init
+    ///Essentially inverse of barrier init
     int relative_x_pos = cannon_missile_x_pos - 10 - (barrier_no*25) - 1;
-    int relative_y_pos = (cannon_missile_y_pos + row) - 33 - 1; //Don't know why it's -1 and not -2
-    //Loops through the damage bitmap and modifies the barrier's after bitmap
+    int relative_y_pos = (cannon_missile_y_pos + row) - 33 - 1; ///Don't know why it's -1 and not -2
+    ///Loops through the damage bitmap and modifies the barrier's after bitmap
     for (int col = 0; col < 3; ++col) {
         for (int row_bit = 0; row_bit < 3; ++row_bit) {
-            //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration
-            //Element by element multiplication of the 2 bitmaps to clear the required pixals
+            ///Makes sure bitmap index does not go out of bounds. If it does go to the next iteration
+            ///Element by element multiplication of the 2 bitmaps to clear the required pixals
             if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) {
                 barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_cannon_missile_damage_bitmap[row_bit][col];
             }
@@ -880,16 +1041,15 @@
 
 void AttemptToFireInvaderNormalMissiles()
 {
-    //Fires the normal missiles
-    //Loops through the 2 allowed missiles and if they're not on the screen, randomly fire
+    ///Fires the normal missiles
+    ///Loops through the 2 allowed missiles and if they're not on the screen, randomly fire
     for (int i = 0; i < 2; ++i) {
         if (!invader_normal_missile[i].fired) {
-            //If the random mumber is 1, fire a missile
-            //Higher chance when there are less invaders on the screen, up to a 1/3 chance
+            ///If the random mumber is 1, fire a missile
+            ///Higher chance when there are less invaders on the screen, up to a 1/3 chance
             if ((rand() % (no_of_alive_invaders + 2)) == 1) {
-//            if ((rand() % 5) == 1) {
                 int fired_column;
-                int loop_limit = 0; //Stops loop from never ending
+                int loop_limit = 0; ///Stops loop from never ending
                 Invader missile_source;
                 do {
                     fired_column = rand() % 5;
@@ -897,8 +1057,8 @@
                     ++loop_limit;
                 } while (missile_source == none && loop_limit < 10);
 
-                //Finds the centre point of the chosen invader and fires the missile
-                //If the loop limit is reached, the missile source will be none and the for loop will jump to the next iteration
+                ///Finds the centre point of the chosen invader and fires the missile
+                ///If the loop limit is reached, the missile source will be none and the for loop will jump to the next iteration
                 if (missile_source == none) {
                     continue;
                 } else if (missile_source == large) {
@@ -915,19 +1075,19 @@
 
 void FireNormalInvaderMissile(int missile_no, Invader source, const struct Invaders (&invader))
 {
-    //Finds the centre point of the chosen invader and fires the missile
-    //Enums are implicity converted to ints --> the middle x position of the invader found by offsetting the invader type by 3
+    ///Finds the centre point of the chosen invader and fires the missile
+    ///Enums are implicity converted to ints --> the middle x position of the invader found by offsetting the invader type by 3
     invader_normal_missile[missile_no].x_pos = invader.x_pos + (3 + source);
     invader_normal_missile[missile_no].y_pos = invader.y_pos + 6;
     invader_normal_missile[missile_no].fired = true;
 
-    //Uses a function pointer to attach the ticker
+    ///Uses a function pointer to attach the ticker
     move_invader_normal_missile[missile_no].attach(move_invader_normal_missile_isr[missile_no], 0.05);
 }
 
 void MoveInvaderNormalMissile(int missile_no)
 {
-    //Loops through the bitmap and clears the missile from the screen buffer
+    ///Loops through the bitmap and clears the missile from the screen buffer
     for (int col = 0; col < 3; ++col) {
         for (int row = 0; row < 4; ++row) {
             if (invader_normal_missile_bitmap[row][col]) {
@@ -936,25 +1096,25 @@
         }
     }
 
-    //Checks missile will not exceed screen buffer
+    ///Checks missile will not exceed screen buffer
     if (invader_normal_missile[missile_no].y_pos < 44) {
-        //Increments the position of the missile
+        ///Increments the position of the missile
         ++invader_normal_missile[missile_no].y_pos;
 
-        //Collision detection
+        ///Collision detection
         CollisionDetectionInvaderNormalMissile(missile_no);
 
     } else {
-        //Sets the missiles fired flag as false and detaches the tickers
+        ///Sets the missiles fired flag as false and detaches the tickers
         invader_normal_missile[missile_no].fired = false;
         move_invader_normal_missile[missile_no].detach();
     }
 }
 
-//Checks the bottom centre point for a collision. If it doesn't push the bitmap to the screen buffer
+///Checks the bottom centre point for a collision. If it doesn't push the bitmap to the screen buffer
 void CollisionDetectionInvaderNormalMissile(int missile_no)
 {
-    //Invader missile coordinates shifted to match centre bottom of bitmap
+    ///Invader missile coordinates shifted to match centre bottom of bitmap
     int relative_x_pos = invader_normal_missile[missile_no].x_pos + 1;
     int relative_y_pos = invader_normal_missile[missile_no].y_pos + 3;
     if (screen_buffer[relative_x_pos][relative_y_pos] == cannon_pixel) {
@@ -962,7 +1122,7 @@
         invader_normal_missile[missile_no].fired = false;
         move_invader_normal_missile[missile_no].detach();
     } else if (screen_buffer[relative_x_pos][relative_y_pos] >= first_barrier_pixel && screen_buffer[relative_x_pos][relative_y_pos] < (first_barrier_pixel + 3)) {
-        //Finds barrier number
+        ///Finds barrier number
         InvaderNormalMissileHitBarrier(invader_normal_missile[missile_no]);
         invader_normal_missile[missile_no].fired = false;
         move_invader_normal_missile[missile_no].detach();
@@ -979,12 +1139,12 @@
 
 void InvaderNormalMissileHitCannon()
 {
-    //Decrements the number of lives, pauses the game for 2 seconds
-    //Marks the cannon as hit
+    ///Decrements the number of lives, pauses the game for 2 seconds
+    ///Marks the cannon as hit
     g_cannon_hit_flag = true;
-    //Detaches all tickers
+    ///Detaches all tickers
     DetachTickers();
-    //Creates a Timeout object on the stack with a period of 2 seconds to pause the game for 2 seconds
+    ///Creates a Timeout object on the stack with a period of 2 seconds to pause the game for 2 seconds
     Timeout cannon_hit;
     cannon_hit.attach(&cannon_hit_isr, 2);
     while (g_cannon_hit_flag) {
@@ -994,17 +1154,17 @@
     --number_of_lives;
 }
 
-//Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
+///Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
 void InvaderNormalMissileHitBarrier(const struct InvaderNormalMissiles (&missile))
 {
     int barrier_no = screen_buffer[missile.x_pos + 1][missile.y_pos + 3] - first_barrier_pixel;
-    //Essentially inverse of barrier init
+    ///Essentially inverse of barrier init
     int relative_x_pos = (missile.x_pos + 1) - 10 - (barrier_no*25) - 1;
     int relative_y_pos = (missile.y_pos + 3) - 33;
-    //Loops through the damage bitmap and modifies the barrier's after bitmap
+    ///Loops through the damage bitmap and modifies the barrier's after bitmap
     for (int col = 0; col < 3; ++col) {
         for (int row_bit = 0; row_bit < 2; ++row_bit) {
-            //Makes sure bitmap index does not go out of bounds. If it does go to the next iteration
+            ///Makes sure bitmap index does not go out of bounds. If it does go to the next iteration
             if (relative_x_pos + col >= 0 && relative_x_pos + col < 14 && relative_y_pos + row_bit >= 0 && relative_y_pos + row_bit < 8) {
                 barrier[barrier_no].after_bitmap[relative_y_pos + row_bit][relative_x_pos + col] *= barrier_invader_normal_missile_damage_bitmap[row_bit][col];
             }
@@ -1012,12 +1172,13 @@
     }
 }
 
-//Detaches game related tickers
+///Detaches game related tickers
 void DetachTickers()
 {
     update_screen.detach();
     move_enemies.detach();
-    //Only detaches if missiles are on the screen
+
+    ///Only detaches if missiles are on the screen
     if (cannon_missile_on_screen) {
         move_cannon_missile.detach();
     }
@@ -1028,12 +1189,12 @@
     }
 }
 
-//Attaches game related tickers
+///Attaches game related tickers
 void AttachTickers()
 {
     update_screen.attach(&update_screen_isr, 0.05);
     move_enemies.attach(&move_enemies_isr, ticker_period);
-    //Only attaches if missiles were on the screen
+    ///Only attaches if missiles were on the screen
     if (cannon_missile_on_screen) {
         move_cannon_missile.attach(&move_cannon_missile_isr, 0.05);
     }
@@ -1046,28 +1207,28 @@
 
 void PauseScreen()
 {
-    //Prints the pause screen, score etc
+    ///Prints the pause screen, score etc
     PrintPauseScreen();
 
     while (game_state == paused) {
-        //Draws the cursor
-        cursor_y_pos = ((fsm_state+3)*8)+3; //Adds 3 to the fsm state to get the bank, multiplies it by 8 to get the pixel no and offsets it by 3
-        lcd.drawRect(74, cursor_y_pos, 2, 2, 1); //Draws the cursor
+        ///Draws the cursor
+        cursor_y_pos = ((fsm_state+3)*8)+3; ///Adds 3 to the fsm state to get the bank, multiplies it by 8 to get the pixel no and offsets it by 3
+        lcd.drawRect(74, cursor_y_pos, 2, 2, 1); ///Draws the cursor
 
         if (g_move_joystick_flag) {
             g_move_joystick_flag = false;
 
-            //Moves the cursor to match the selected option, only if the joystick isn't centred
+            ///Moves the cursor to match the selected option, only if the joystick isn't centred
             MoveCursor(fsm_paused);
         }
 
-        //If the button is pressed the selected option will appear on the screen
+        ///If the button is pressed the selected option will appear on the screen
         if (g_shoot_pressed_flag) {
             g_shoot_pressed_flag = false;
             game_state = fsm_paused[fsm_state].output;
         }
 
-        //Resets the joystick flag to false if pressed
+        ///Resets the joystick flag to false if pressed
         if (joystick.get_button_flag()) {
             joystick.set_button_flag(0);
         }
@@ -1080,17 +1241,17 @@
 
 void PrintPauseScreen()
 {
-    //Prints paused and a line underneath
+    ///Prints paused and a line underneath
     lcd.printString("Paused", 24, 0);
-    //Displays the current score
+    ///Displays the current score
     char buffer[14];
     sprintf(buffer, "Score: %d", score);
     lcd.printString(buffer, 0, 1);
-    //Displays the no of lives
+    ///Displays the no of lives
     sprintf(buffer, "Lives: %d", number_of_lives);
     lcd.printString(buffer, 0, 2);
     lcd.drawLine(0, 23, 83, 23, 2);
-    //Prints options on pause menu
+    ///Prints options on pause menu
     lcd.printString("Resume", 5, 3);
     lcd.printString("Save", 5, 4);
     lcd.printString("Quit", 5, 5);
@@ -1098,16 +1259,124 @@
 
 void MoveCursor(const struct FSMMenus *fsm)
 {
-    //If the joystick is is pushed down half way clear the cursor and set the next state
+    ///If the joystick is is pushed down half way clear the cursor and set the next state
     if (joystick.GetYValue() < 0.25f) {
-        //Clears the cursor
+        ///Clears the cursor
         lcd.drawRect(74, cursor_y_pos, 2, 2, 2);
-        //Sets the new state
+        ///Sets the new state
         fsm_state = fsm[fsm_state].next_state[0];
     } else if (joystick.GetYValue() > 0.75f) {
-        //Clears the cursor
+        ///Clears the cursor
         lcd.drawRect(74, cursor_y_pos, 2, 2, 2);
-        //Sets the new state
+        ///Sets the new state
         fsm_state = fsm[fsm_state].next_state[1];
     }
+}
+
+void MenuScreen()
+{
+    ///Print the menu text
+    PrintMenuScreen();
+
+    while (game_state == menu) {
+        ///Draws the cursor
+        cursor_y_pos = ((fsm_state+2)*8)+3; ///Adds 2 to the fsm state to get the bank, multiplies it by 8 to get the pixel no and offsets it by 3
+        lcd.drawRect(74, cursor_y_pos, 2, 2, 1);
+
+        if (g_move_joystick_flag) {
+            g_move_joystick_flag = false;
+
+            ///Moves the cursor to match the selected option, only if the joystick isn't centred
+            MoveCursor(fsm_main_menu);
+        }
+
+        ///If shoot is pressed go to the selected screen
+        if (g_shoot_pressed_flag) {
+            g_shoot_pressed_flag = false;
+
+            game_state = fsm_main_menu[fsm_state].output;
+
+            ///If the game state is equal to the game initalise it
+            if (game_state == game) {
+                InitaliseGame();
+            }
+        }
+
+        ///Do nothing when the joystick is pressed
+        if(joystick.get_button_flag()) {
+            joystick.set_button_flag(0);
+        }
+
+        lcd.refresh();
+        sleep();
+    }
+}
+
+void PrintMenuScreen()
+{
+    ///Prints Space invaders, then menu below, then a line underneath
+    lcd.printString("Space Invaders", 0, 0);
+    lcd.printString("Menu", 28, 1);
+    lcd.drawLine(0, 15, 83, 15, 2);
+
+    ///Prints menu options
+    lcd.printString("New Game", 5, 2);
+    lcd.printString("Load Game", 5, 3);
+    lcd.printString("High Scores", 5, 4);
+    lcd.printString("Settings", 5, 5);
+}
+
+void AttemptToSpawnUFO()
+{
+    ///1/8 chance of UFO spawning if it hasn't already
+    if (!ufo_on_screen && (rand() % 8 == 1) && down_count > 1 && no_of_alive_invaders > 3) {
+        ///Marks the UFO as on the screen and sets its position and direction
+        ufo_on_screen = true;
+        ufo_direction = (rand() % 2);
+        if (ufo_direction == RIGHT) {
+            ufo_x_pos = -14;
+        } else {
+            ufo_x_pos = 83;
+        }
+
+        ///Attachs the move UFO ticker
+        move_ufo.attach(&move_ufo_isr, 0.1);
+    }
+}
+
+void ClearUFO()
+{
+    ///Clears the UFO
+    for (int col = 0; col < 14; ++col) {
+        for (int row = 0; row < 5; ++row) {
+            ///Only clear the pixel in the buffer if it is within bounds
+            if (ufo_x_pos + col >= 0 && ufo_x_pos + col < 84) {
+                if (ufo_bitmap[row][col]) {
+                    screen_buffer[ufo_x_pos + col][ufo_y_pos + row] = empty_pixel;
+                }
+            }
+        }
+    }
+}
+
+void DrawUFO()
+{
+    ///Checks if the ufo can be within the screen bounds
+    ///If it is, push the ufo to the screen buffer
+    if (ufo_x_pos > -14 && ufo_x_pos < 84) {
+        for (int col = 0; col < 14; ++col) {
+            for (int row = 0; row < 5; ++row) {
+                ///Only clear the pixel in the buffer if it is within bounds
+                if (ufo_x_pos + col >= 0 && ufo_x_pos + col < 84) {
+                    if (ufo_bitmap[row][col]) {
+                        screen_buffer[ufo_x_pos + col][ufo_y_pos + row] = ufo_pixel;
+                    }
+                }
+            }
+        }
+    } else {
+        ///Otherwise mark it as not on the screen and detach the ticker
+        ufo_on_screen = false;
+        move_ufo.detach();
+    }
 }
\ No newline at end of file