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

Dependencies:   Joystick N5110 SDFileSystem mbed

Revision:
9:cbb982b7e353
Parent:
8:b2faec20ed8f
Child:
11:eab3fb334bde
--- a/main.cpp	Tue May 03 20:16:06 2016 +0000
+++ b/main.cpp	Thu May 05 11:01:17 2016 +0000
@@ -30,6 +30,8 @@
     lcd.init();
     lcd.clear();
 
+    LoadHighScores();
+
     ///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;
@@ -37,6 +39,9 @@
     ///Samples joystick every 0.05 second
     move_joystick.attach(&move_joystick_isr, 0.05);
 
+    ///Splash Screen
+    SplashScreen();
+
     while (true) {
         if (game_state == menu) { ///Menu screen
             lcd.clear();
@@ -51,145 +56,19 @@
             AttachTickers();
             Game();
         } else if (game_state == save) {
-            ///Creates file pointer and attaches the file
-            FILE *fp;
-            fp = fopen("/sd/game_save.txt", "w");
-
-            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);
-                }
-                ///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]);
-                            }
-                        }
-                    }
-                }
-
-                fclose(fp);
-                game_state = paused;
-            }
+            SaveGameData();
         } 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;
-            }           
+            LoadGameData();
+        } else if (game_state == over) {
+            lcd.clear();
+            GameOverScreen();            
+        } else if (game_state == scores) {
+            lcd.clear();
+            ScoreScreen();               
+        } else if (game_state == settings) {
+            lcd.clear();
+            fsm_state = 0;
+            SettingsScreen();
         }
 
         sleep();
@@ -236,6 +115,7 @@
 {
     shoot_button.mode(PullUp);
     shoot_button.fall(&shoot_pressed_isr);
+    shoot_button.rise(&shoot_pressed_rise_isr);
 }
 
 void update_screen_isr()
@@ -254,9 +134,6 @@
     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
-        shoot_button_debounce.attach(&shoot_button_debounce_isr, 0.125);
     }
 }
 
@@ -315,20 +192,26 @@
     g_fire_buzzer_flag = true;
 }
 
+void lp_wait_isr()
+{
+    g_lp_wait_flag = false;
+}
+
+void shoot_pressed_rise_isr()
+{
+    ///Attaches a timeout to clear the debounce flag in 0.125 seconds
+    shoot_button_debounce.attach(&shoot_button_debounce_isr, 0.125);
+}
+
 void Game()
 {
     ///Stays within the loop while the selected state is game
     while (game_state == game) {
         pc.printf("Mute: %d\n", is_muted);
-        ///If the game is over detach all the tickers
+        ///If the game is over detach all the tickers and set game state to over
         if (number_of_lives == 0) {
             DetachTickers();
-
-            lcd.clear();
-            lcd.printString("Game Over.", 1, 2);
-            char buffer[14];
-            sprintf(buffer, "Score: %d", score);
-            lcd.printString(buffer, 1, 3);
+            game_state = over;
         } else if (no_of_alive_invaders == 0) { ///If the player wins a round
             ///Resets the no of alive invaders
             no_of_alive_invaders = 15;
@@ -395,15 +278,7 @@
             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;
-                }
+                PlayBuzzer();
             }
 
             ///Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen
@@ -466,8 +341,9 @@
             if (joystick.get_button_flag()) {
                 joystick.set_button_flag(0);
 
-                ///Detach all game tickers
+                ///Detach all game tickers and turn off PWM
                 DetachTickers();
+                buzzer.write(0.0);
                 game_state = paused;
             }
         }
@@ -484,7 +360,8 @@
     score = 0;
     number_of_lives = 3;
     down_count = 0;
-    cannon_xpos = 15;
+    cannon_xpos = 13;
+    ufo_on_screen = false;
     ufo_bonus = false;
     shot_count = 0;
     InitSmallInvaders();
@@ -992,8 +869,8 @@
             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;
+            ufo_bonus = true;
+            score += 300;
             } else { ///Randomly assign score between 50, 100, 150 points
                 score += 50 * ((rand() % 3) + 1);
             }
@@ -1118,7 +995,13 @@
     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) {
-        InvaderNormalMissileHitCannon();
+        ///Cannon has invunerability for 1s after getting hit
+        if (!g_cannon_hit_flag) {
+            g_cannon_hit_flag = true;
+            InvaderNormalMissileHitCannon();
+            ///Attaches a timeout to allow cannon to be hit again
+            cannon_hit.attach(&cannon_hit_isr, 1);
+        }
         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)) {
@@ -1140,18 +1023,11 @@
 void InvaderNormalMissileHitCannon()
 {
     ///Decrements the number of lives, pauses the game for 2 seconds
-    ///Marks the cannon as hit
-    g_cannon_hit_flag = true;
     ///Detaches all tickers
     DetachTickers();
-    ///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) {
-        sleep();
-    }
-    AttachTickers();
+    LPWait(2);
     --number_of_lives;
+    AttachTickers();   
 }
 
 ///Calculates where to start drawing the damage bitmap over the barrier bitmap and performs the operation
@@ -1178,10 +1054,13 @@
     update_screen.detach();
     move_enemies.detach();
 
-    ///Only detaches if missiles are on the screen
+    ///Only detaches if are on the screen
     if (cannon_missile_on_screen) {
         move_cannon_missile.detach();
     }
+    if (ufo_on_screen) {
+        move_ufo.detach();
+    }
     for (int i = 0; i < 2; ++i) {
         if (invader_normal_missile[i].fired) {
             move_invader_normal_missile[i].detach();
@@ -1198,6 +1077,9 @@
     if (cannon_missile_on_screen) {
         move_cannon_missile.attach(&move_cannon_missile_isr, 0.05);
     }
+    if (ufo_on_screen) {
+        move_ufo.attach(&move_ufo_isr, 0.1);
+    }
     for (int i = 0; i < 2; ++i) {
         if (invader_normal_missile[i].fired) {
             move_invader_normal_missile[i].attach(move_invader_normal_missile_isr[i], 0.05);
@@ -1225,16 +1107,18 @@
         ///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
+        ///Returns to the game state when the joystick is pressed
         if (joystick.get_button_flag()) {
             joystick.set_button_flag(0);
+
+            game_state = game;
         }
 
         lcd.refresh();
-
         sleep();
     }
 }
@@ -1379,4 +1263,427 @@
         ufo_on_screen = false;
         move_ufo.detach();
     }
+}
+
+bool high_scores_sorter(const struct HighScores (&lhs), const struct HighScores (&rhs))
+{
+    return lhs.score > rhs.score;
+}
+
+void ScoreScreen()
+{
+    lcd.printString("High Scores", 8, 0);
+    lcd.drawLine(0, 7, 83, 7, 2);
+
+    PrintHighScores();
+
+    lcd.printString("Back", 5, 5);
+    const int cursor_y_pos = 43;
+    lcd.drawRect(74, cursor_y_pos, 2, 2, 1);
+
+    lcd.refresh();
+
+    while (game_state == scores) {
+        if (joystick.get_button_flag()) {
+            joystick.set_button_flag(0);
+        }
+        if (g_shoot_pressed_flag) {
+            g_shoot_pressed_flag = false;
+
+            game_state = menu; // If the button is pressed go to the menu state
+        }
+
+        sleep();
+    }
+}
+
+void PrintHighScores()
+{
+    ///Loops throught the high scores and prints them to the screen
+    for (int i = 0; i < 3; ++i) {
+        ///Counts how many digits are in score
+        int temp_score = high_scores[i].score;
+        int no_of_digits = 0;
+        do {
+            temp_score /= 10;
+            ++no_of_digits;
+        } while (temp_score != 0);
+
+        ///Prints name to c-string
+        char buffer[14];
+        sprintf(buffer, "%s", high_scores[i].name);
+
+        ///Prints correct number of spaces to c-string
+        int no_of_spaces = 14 - no_of_digits;
+        for (int space = 3; space < no_of_spaces; ++space) {
+            sprintf(buffer, "%s%s", buffer, " ");
+        }
+
+        ///Prints score to c-string
+        sprintf(buffer, "%s%d", buffer, high_scores[i].score);
+        lcd.printString(buffer, 0, 2 + i);
+    }
+}
+
+void GameOverScreen()
+{
+    lcd.printString("Game Over", 18, 0);
+    char buffer[14];
+    sprintf(buffer, "Score: %d", score);
+    lcd.printString(buffer, 0, 1);
+    
+    ///Save score input
+    if (score > high_scores[2].score) {
+        lcd.printString("High Score!", 0, 2);
+        lcd.printChar('A', 27, 3);
+        lcd.printChar('A', 42, 3);
+        lcd.printChar('A', 57, 3);
+
+        int name[3] = {0, 0, 0};
+        GetNameForScore(name);        
+
+        SaveHighScore(name);
+    }
+
+    ///After high score is inputted or no high score has been reached
+    lcd.printString("Quit", 5, 5);
+    const int cursor_y_pos = 43;
+    lcd.drawRect(74, cursor_y_pos, 2, 2, 1);
+
+    while (game_state == over) {
+        if (joystick.get_button_flag()) {
+            joystick.set_button_flag(0);
+        }
+
+        if (g_shoot_pressed_flag) {
+            g_shoot_pressed_flag = false;
+
+            game_state = menu;
+        }
+
+        lcd.refresh();
+        sleep(); 
+    }
+}
+
+void GetNameForScore(int (&name)[3])
+{
+    int name_cursor_pos = 0; ///Cursor is at first letter
+
+    while (name_cursor_pos < 3) {
+        ///Prints the name cursor
+        lcd.drawRect(27+(15*name_cursor_pos), 32, 4, 2, 1);
+
+        if (g_shoot_pressed_flag) {
+            g_shoot_pressed_flag = false;
+
+            ///Clears the name cursor and moves it
+            lcd.drawRect(27+(15*name_cursor_pos), 32, 4, 2, 2);
+            ++name_cursor_pos;
+        }
+
+        if (g_move_joystick_flag) {
+            g_move_joystick_flag = false;
+
+            if (joystick.GetYValue() < 0.25f) {
+                ///Increments the name position, if it is over 25 set it to 0
+                if (++name[name_cursor_pos] > 25) {
+                    name[name_cursor_pos] = 0;
+                }
+            } else if (joystick.GetYValue() > 0.75f) {
+                ///Decrements the name position, if it is under 0 set it to 25
+                if (--name[name_cursor_pos] < 0) {
+                    name[name_cursor_pos] = 25;
+                }
+            }
+
+            lcd.printChar(name[name_cursor_pos] + 65, 27+(15*name_cursor_pos), 3); ///ASCII is offset by 65
+        }
+
+        lcd.refresh();
+        sleep(); 
+    }
+}
+
+void SaveHighScore(const int (&name)[3])
+{
+    ///Saves name and score to struct array, overwritting lowest score
+    for (int letter = 0; letter < 3; ++letter) {
+        high_scores[2].name[letter] = name[letter] + 65;
+    }
+    high_scores[2].score = score;
+
+    ///Sorts struct array
+    std::sort(high_scores, high_scores + 3, &high_scores_sorter);
+
+    ///Saves the score
+    std::ofstream high_score_data("/sd/high_scores.dat", std::ios::binary);
+    if (high_score_data.good()) { ///Checks to see if file opening was good
+        high_score_data.write((char *)(&high_scores), sizeof(high_scores));
+        ///Flushes the buffer and saves the file
+        high_score_data.close();
+        lcd.printString("Saved", 27, 4);
+    } else {
+        lcd.clear();
+        lcd.printString("Error", 1, 1);
+        lcd.printString("Opening", 1, 2);
+        lcd.printString("File.", 1, 3);
+        LPWait(2);
+    }
+}
+
+void SaveGameData()
+{
+    ///Creates the output file as a binary file
+    std::ofstream save_data("/sd/game_save.dat", std::ios::binary);
+    if (save_data.good()) { ///Checks to see if file opening was good
+        ///Prints booleans to file
+        save_data.write((char *)(&invaders_in_state2), sizeof(invaders_in_state2));
+        save_data.write((char *)(&invader_direction), sizeof(invader_direction));
+        save_data.write((char *)(&cannon_missile_on_screen), sizeof(cannon_missile_on_screen));
+        save_data.write((char *)(&ufo_on_screen), sizeof(ufo_on_screen));
+        save_data.write((char *)(&ufo_direction), sizeof(ufo_direction));
+        save_data.write((char *)(&ufo_bonus), sizeof(ufo_bonus));
+
+        ///Prints integers to file
+        save_data.write((char *)(&score), sizeof(score));
+        save_data.write((char *)(&shot_count), sizeof(shot_count));
+        save_data.write((char *)(&number_of_lives), sizeof(number_of_lives));
+        save_data.write((char *)(&cannon_xpos), sizeof(cannon_xpos));
+        save_data.write((char *)(&cannon_missile_x_pos), sizeof(cannon_missile_x_pos));
+        save_data.write((char *)(&cannon_missile_y_pos), sizeof(cannon_missile_y_pos));
+        save_data.write((char *)(&no_of_alive_invaders), sizeof(no_of_alive_invaders));
+        save_data.write((char *)(&down_count), sizeof(down_count));
+        save_data.write((char *)(&ufo_x_pos), sizeof(ufo_x_pos));
+
+        ///Prints invaders to file
+        save_data.write((char *)(&small_invader), sizeof(small_invader));
+        save_data.write((char *)(&medium_invader), sizeof(medium_invader));
+        save_data.write((char *)(&large_invader), sizeof(large_invader));
+
+        ///Prints invader missiles and barriers to file
+        save_data.write((char *)(&invader_normal_missile), sizeof(invader_normal_missile));
+        save_data.write((char *)(&barrier), sizeof(barrier));
+
+        ///Flushes the buffer and saves the file
+        save_data.close();
+    } else {
+        lcd.clear();
+        lcd.printString("Error", 1, 1);
+        lcd.printString("Opening", 1, 2);
+        lcd.printString("File.", 1, 3);
+        LPWait(2);
+    }
+
+    game_state = paused;
+}
+
+void LoadGameData()
+{
+    ///Creates the input binary file object
+    std::ifstream save_data("/sd/game_save.dat", std::ios::binary);
+    if (save_data.good()) { ///Checks to see if file opening was good
+        ///Gets booleans from file
+        save_data.read((char *)(&invaders_in_state2), sizeof(invaders_in_state2));
+        save_data.read((char *)(&invader_direction), sizeof(invader_direction));
+        save_data.read((char *)(&cannon_missile_on_screen), sizeof(cannon_missile_on_screen));
+        save_data.read((char *)(&ufo_on_screen), sizeof(ufo_on_screen));
+        save_data.read((char *)(&ufo_direction), sizeof(ufo_direction));
+        save_data.read((char *)(&ufo_bonus), sizeof(ufo_bonus));
+
+        ///Gets integers from file
+        save_data.read((char *)(&score), sizeof(score));
+        save_data.read((char *)(&shot_count), sizeof(shot_count));
+        save_data.read((char *)(&number_of_lives), sizeof(number_of_lives));
+        save_data.read((char *)(&cannon_xpos), sizeof(cannon_xpos));
+        save_data.read((char *)(&cannon_missile_x_pos), sizeof(cannon_missile_x_pos));
+        save_data.read((char *)(&cannon_missile_y_pos), sizeof(cannon_missile_y_pos));
+        save_data.read((char *)(&no_of_alive_invaders), sizeof(no_of_alive_invaders));
+        save_data.read((char *)(&down_count), sizeof(down_count));
+        save_data.read((char *)(&ufo_x_pos), sizeof(ufo_x_pos));
+
+        ///Gets invaders from file
+        save_data.read((char *)(&small_invader), sizeof(small_invader));
+        save_data.read((char *)(&medium_invader), sizeof(medium_invader));
+        save_data.read((char *)(&large_invader), sizeof(large_invader));
+
+        ///Gets invader missiles and barriers from file
+        save_data.read((char *)(&invader_normal_missile), sizeof(invader_normal_missile));
+        save_data.read((char *)(&barrier), sizeof(barrier));
+        
+        ///Closes the file
+        save_data.close();
+
+        ///Clears the screen buffer
+        memset(screen_buffer, 0, sizeof(screen_buffer));
+        ///Sets the game state flags
+        game_state = game;
+        g_update_screen_flag = true;
+        g_move_joystick_flag = true;
+        g_move_enemies_flag = true;
+        g_fire_buzzer_flag = true;
+    } else {
+        lcd.clear();
+        lcd.printString("Error", 1, 1);
+        lcd.printString("Opening", 1, 2);
+        lcd.printString("File.", 1, 3);
+        LPWait(2);
+        game_state = menu;
+    }           
+}
+
+void LoadHighScores()
+{
+    ///Clears high score data before loading file
+    memset(high_scores, 0, sizeof(high_scores));
+    ///Extracts high scores from file
+    std::ifstream high_score_data("/sd/high_scores.dat", std::ios::binary);
+    if (high_score_data.good()) {
+        high_score_data.read((char *)(&high_scores), sizeof(high_scores));
+    }
+    high_score_data.close();
+    ///If there are any empty names, fill them with AAA to prevent crashes using printString
+    for (int i = 0; i < 3; ++i) {
+        if (high_scores[i].name[0] < 'A') {
+            for (int letter = 0; letter < 3; ++letter) {
+                high_scores[i].name[letter] = 'A';
+            }
+        }
+    }
+
+}
+
+void SettingsScreen()
+{
+    PrintSettingsText();
+
+    while (game_state == settings) {
+        ///Prints options and cursor
+        PrintSettingsOptions();
+
+        ///Returns to menu if joystick button is pressed
+        if (joystick.get_button_flag()) {
+            joystick.set_button_flag(0);
+
+            game_state = menu;
+        }
+
+        ///Moves the cursor when the joystick moves
+        if (g_move_joystick_flag) {
+            g_move_joystick_flag = false;
+
+            MoveCursor(fsm_settings);
+        }
+
+        if (g_shoot_pressed_flag) {
+            g_shoot_pressed_flag = false;
+
+            EditOption();
+        }
+
+        lcd.refresh();
+        sleep();
+    }
+}
+
+void PrintSettingsText()
+{
+    ///Prints the options
+    lcd.printString("Settings", 17, 0);
+    lcd.drawLine(0, 7, 83, 7, 2);
+    lcd.printString("Light:", 0, 2);
+    lcd.printString("Mute: ", 0, 3);
+    lcd.printString("Delete Data", 0, 4);
+    lcd.printString("Back", 10, 5);
+}
+
+void PrintSettingsOptions()
+{
+    ///Prints the active options
+    char buffer[14] = {0};
+    sprintf(buffer, "%d%%", (int)(100*fsm_brightness[brightness_state].output));
+    pc.printf("%s\n", buffer);
+    lcd.printString(buffer, 42, 2);
+    if (is_muted) {
+        lcd.printString("On", 42, 3);
+    } else {
+        lcd.printString("Off", 42, 3);
+    }
+    ///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);
+}
+
+void EditOption()
+{
+    if (fsm_state == 0) { ///Change brightness
+        brightness_state = fsm_brightness[brightness_state].next_state;
+        lcd.setBrightness(fsm_brightness[brightness_state].output);
+        ///Clears displayed brightness
+        lcd.drawRect(42, 16, 24, 7, 2);
+    } else if (fsm_state == 1) { ///Mute game
+        is_muted = !is_muted;
+    } else if (fsm_state == 2) { ///Delete save data
+        DeleteGameData();
+        ///Sets FSM list back to 0 and resets the cursor
+        lcd.drawRect(74, cursor_y_pos, 2, 2, 2);
+        fsm_state = 0;
+    } else if (fsm_state == 3) {
+        game_state = menu;
+    }
+}
+
+void DeleteGameData()
+{
+    ///Delete game state data
+    std::ifstream save_data("/sd/game_save.dat", std::ios::binary);
+    if (save_data.good()) {
+        ///Close the file and remove it
+        save_data.close();
+        remove("/sd/game_save.dat");
+    }
+    ///Deletes high score data
+    std::ifstream high_scores_data("/sd/high_scores.dat", std::ios::binary);
+    if (high_scores_data.good()) {
+        ///Closes the file and remove it
+        high_scores_data.close();
+        remove("/sd/high_scores.dat");
+    }
+    ///Reloads high score list
+    LoadHighScores();
+}
+
+void LPWait(float t)
+{
+    ///Sets the wait flag
+    g_lp_wait_flag = true;
+    ///Attachs the timeout to fire at the users request then sleep
+    lp_wait.attach(&lp_wait_isr, t);
+    while (g_lp_wait_flag) {
+        sleep();
+    } 
+}
+
+void SplashScreen()
+{
+    ///Prints text and waits for 3 seconds
+    lcd.printString("Space Invaders", 0, 1);
+    lcd.printString("Avinash Patel", 3, 3);
+    lcd.printString("200860407", 15, 4);
+    LPWait(3);
+}
+
+void PlayBuzzer()
+{
+    if (play_sound) {
+        ///Sets the frequency and activates the buzzer
+        buzzer.period(1/fsm_buzzer[buzzer_state].frequency);
+        buzzer.write(0.5);
+        play_sound = false;
+    } else {
+        ///Deactivates the buzzer and sets the next frequency
+        buzzer.write(0);
+        buzzer_state = fsm_buzzer[buzzer_state].next_state;
+        play_sound = true;
+    }
 }
\ No newline at end of file