Adventure game written for ECE2035 at the Georgia Institute of Technology

Dependencies:   mbed wave_player 4DGL-uLCD-SE MMA8452

Revision:
4:cdc54191ff07
Parent:
3:289762133fd6
Child:
5:93a4c396c1af
--- a/main.cpp	Wed Apr 18 20:18:51 2018 +0000
+++ b/main.cpp	Tue May 22 19:13:03 2018 +0000
@@ -5,6 +5,8 @@
 #include "graphics.h"
 #include "speech.h"
 #include "startmenu.h"
+#include "ingamemenu.h"
+#include "gameover.h"
 
 // Functions in this file
 int get_action (GameInputs inputs);
@@ -14,30 +16,58 @@
 void init_house_map();
 int main ();
 
-/**
- * The main game state. Must include Player locations and previous locations for
- * drawing to work properly. Other items can be added as needed.
- */
-struct {
-    int x,y;    // Current locations
-    int px, py; // Previous locations
-    int has_key;
-    int quest_complete;
-} Player;
-
+Player p1;
+int omni_en = 0;
+int in_house;
 int house_enabled = false;
 int door_open = false;
 int game_over = false;
-int health = 0;
+int switch_axis = 0;
+
+
+/*Functions to for player to interact with the map
+*/
+
+void interact_npc(MapItem* object){
+    if (p1.rock_pushed && p1.gems >= 3){
+        p1.quest_complete = true;
+    }
+    NonPlayer* n = (NonPlayer*)object -> data;
+    if(n -> quest_requested == false){
+        speech("Find 3 red gems", "and move the rock", "in the backyard", "then I will give you gold!");
+        n -> quest_requested = true;
+    } else if (p1.quest_complete == false){ //should quest complete be in the player struct?
+        speech("get it boi! What", "are u waitin for?", "You must finish ", "the quest!!!!");
+    } else if (n -> has_key == true) {
+        speech("Congrats!", "Thank you for", "completing the", "quest! Here's the key!");
+        n -> has_key = false;
+        p1.has_key = true;
+    } else if(n -> has_key == false){
+        speech("Congrats!", "Quest complete.", "", "");
+    }
+}
+
+void player_hurt(){
+    //lower health bar
+        p1.health+=10;   
+        for(int i = 0; i < 2; i++){ 
+        speaker.period(1.0/150.0); // 500hz period
+        speaker =0.25; //25% duty cycle - mid range volume
+        wait(.02);
+        speaker=0.0; // turn off audio
+        wait(0.1);
+        }
+}
+
 
 /**
  * Given the game inputs, determine what kind of update needs to happen.
  * Possbile return values are defined below.
  */
 #define NO_ACTION 0
-#define BUTTON1 1
-#define BUTTON2 2
-#define BUTTON3 3
+#define BUTTON1 1 //omni button
+#define BUTTON2 2 //toggle/action button
+#define BUTTON3 3 //scroll/select?
 #define MENU_BUTTON 4
 #define GO_LEFT 5
 #define GO_RIGHT 6
@@ -45,6 +75,15 @@
 #define GO_DOWN 8
 int get_action(GameInputs inputs)
 {
+    double y_axis;
+    double x_axis; 
+    if(switch_axis){
+        y_axis = inputs.ax;
+        x_axis = inputs.ay;
+    }else{
+        y_axis = inputs.ay;
+        x_axis = inputs.ax;
+    }
     if(!inputs.b1){
         return BUTTON1;
     }
@@ -54,18 +93,46 @@
     if (!inputs.b3){
         return MENU_BUTTON;
     }
-    if ((inputs.ay > 0.05 && inputs.ay < 0.5) && abs(inputs.ax) < .5){
+    if ((y_axis > 0.05 && y_axis < 0.9) && abs(x_axis) < .9){
         return GO_LEFT;    
-    } else if ((inputs.ay < -0.05 && inputs.ay > -0.5) && abs(inputs.ax) < .5){
+    } else if ((y_axis < -0.05 && y_axis > -0.9) && abs(x_axis) < .9){
         return GO_RIGHT;
-    }else if (inputs.ax > 0.05 && inputs.ax < 0.5){
+    }else if (x_axis > 0.05 && x_axis < 0.9){
         return GO_DOWN;
-    }else if (inputs.ax < -0.05 && inputs.ax > -0.5){
+    }else if (x_axis < -0.05 && x_axis > -0.9){
         return GO_UP;
     }
     return NO_ACTION;
 }
 
+void update_npcs(){
+    //Map* m = get_active_map();
+    /*int h = map_height();
+    int w = map_width();
+    
+    for(int i = 0; i < w; i++){
+        for(int j = 0; j < h; j++){
+            if (MapItem* object = get_here(i, j)){
+                if (object -> type == EXTRA){
+                    Extra* d = (Extra*)object -> data;
+                    d -> e = true;
+                    add_extra(i+1, j);
+                }
+            } 
+        }
+    }
+    for(int i = 0; i < w; i++){
+        for(int j = 0; j < h; j++){
+            if (MapItem* object = get_here(i, j)){
+                if (object -> type == EXTRA){
+                    Extra* d = (Extra*)object -> data;
+                    if(d -> e == true) map_erase(i, j);
+                }
+            } 
+        }
+    }*/
+}
+
 /**
  * Update the game state based on the user action. For example, if the user
  * requests GO_UP, then this function should determine if that is possible by
@@ -78,117 +145,180 @@
 #define NO_RESULT 0
 #define GAME_OVER 1
 #define FULL_DRAW 2
+#define NO_DRAW   3
 int update_game(int action)
 {
     // Save player previous location before updating
-    Player.px = Player.x;
-    Player.py = Player.y;
+    p1.px = p1.x;
+    p1.py = p1.y;
     
     // Do different things based on the each action.
     // You can define functions like "go_up()" that get called for each case.
     switch(action) //have a function called for each type of object. Pass a pointer to the object to the interact function
     {
         case GO_UP: 
-            if (MapItem* object = get_north(Player.x, Player.y)){
-                if (object -> type == NPC){
-                     NonPlayer* n = (NonPlayer*)object -> data;
-                    if(n -> quest_requested == false){
-                        speech("Get dat money", "its dat way");
-                        n -> quest_requested = true;
-                    } else if (Player.quest_complete == false){ //should quest complete be in the player struct?
-                        speech("What are u waitin for?", "get it boi");
-                    } else if (n -> has_key == true) {
-                        speech("Congrats!", "Here's the keyyyy");
-                        n -> has_key = false;
-                        Player.has_key = true;
-                    } else if(n -> has_key == false){
-                        speech("Congrats!", "Quest complete.");
+            if (MapItem* object = get_north(p1.x, p1.y)){
+                //if (object -> type == NPC){
+                    //interact_npc(object);
+                  //  return NO_RESULT;
+                 if (object -> type == LBUSH){
+                    p1.y = p1.y - 1;
+                    return NO_DRAW;
+                } else if(object -> type == SPIKE){
+                    player_hurt(); 
+                } else if(object -> type == GEM){
+                    //add to gem score
+                    p1.gems++;    
+                    if (p1.gems >= 3 && p1.quest_complete < 1){
+                        p1.quest_complete += 0.5;
                     }
-               // else if (object -> type == DOOR){
-                 //   bool o = object -> data;
-                   // if (Player.has_key == true){
-                     //   o = true;
-                   // }
-                //}
-            
-                    return NO_RESULT;
-                }
-                else if (object -> walkable == false){
+                    map_erase(p1.x, p1.y-1);
+                } else if (!omni_en && object -> walkable == false){
                     return NO_RESULT;
                 }
             }
-            Player.y = Player.y - 1;
+            p1.y = p1.y - 1;
             return FULL_DRAW;
         case GO_LEFT:   
-            if (MapItem* object = get_west(Player.x, Player.y)){
+            if (MapItem* object = get_west(p1.x, p1.y)){
                 if (object -> type == ROCK){
-                    add_rock(Player.x + 2, Player.y);
-                    map_erase(Player.x+1, Player.y);
-                    Player.x = Player.x + 1;
-                    Player.quest_complete = true;
+                    add_rock(p1.x + 2, p1.y);
+                    map_erase(p1.x+1, p1.y);
+                    p1.x = p1.x + 1;
+                    p1.rock_pushed = true;
                     return FULL_DRAW;
                     
-                } else if(object -> type == SPIKE){
+                }else if (object -> type == LBUSH){
+                    p1.x = p1.x + 1;
+                    return NO_DRAW; 
+                }else if(object -> type == SPIKE){
+                    player_hurt();   
+                } else if(object -> type == GEM){
                     //lower health bar
-                    health++;
-                    return NO_RESULT;
-                    
-                }
-                if (object -> walkable == false){
+                    p1.gems++;  
+                    if (p1.gems >= 3 && p1.quest_complete < 1){
+                        p1.quest_complete += 0.5;
+                    }
+                    map_erase(p1.x+1, p1.y);
+                }else if(object -> type == DOOR){
+                    if (in_house){
+                        set_active_map(0);
+                        p1.x = 3;
+                        p1.y = 7;
+                        in_house = 0;
+                    }else{
+                        set_active_map(1);
+                        p1.x = 6;
+                        p1.y = 7; 
+                        in_house = 1;
+                    }
+               } if (!omni_en && object -> walkable == false){
                      return NO_RESULT;
                 }
             }
-            Player.x = Player.x + 1;
+            p1.x = p1.x + 1;
             return FULL_DRAW; 
         case GO_DOWN:   
-            if (MapItem* object = get_south(Player.x, Player.y)){
+            if (MapItem* object = get_south(p1.x, p1.y)){
                 if (object -> type == DOOR){
-                    if (Player.has_key == true){
-                        map_erase(Player.x, Player.y + 1);
-                        Player.y = Player.y + 1;
+                    if (p1.has_key == true){
+                        map_erase(p1.x, p1.y + 1);
+                        p1.y = p1.y + 1;
                         door_open = true;
                         return FULL_DRAW;
                     }
                     return NO_RESULT;
+                }if (object -> type == LBUSH){
+                    p1.y = p1.y + 1;
+                    return NO_DRAW;
+                }else if(object -> type == SPIKE){
+                    player_hurt(); 
+                } else if(object -> type == GEM){
+                    //add to gem score
+                    p1.gems++;   
+                    if (p1.gems >= 3 && p1.quest_complete < 1){
+                        p1.quest_complete += 0.5;
+                    } 
+                    map_erase(p1.x, p1.y+1);
                 }
-                if (object -> walkable == false){
+                if (!omni_en && object -> walkable == false){
                     return NO_RESULT;
                 }    
             }
-            Player.y = Player.y + 1;
+            p1.y = p1.y + 1;
             return FULL_DRAW;
             
         case GO_RIGHT:  
-            if (MapItem* object = get_east(Player.x, Player.y)){
+            if (MapItem* object = get_east(p1.x, p1.y)){
                 if (object -> type == GOAL){
                     if(door_open == true){
                         game_over = true;
+                        uLCD.locate(1,1);
+                        uLCD.printf("Goal reached");
                         return NO_RESULT;
                     }
                     
-                } else if(object -> type == DOOR){
-                    init_house_map();  //add a bit of a wait here to simulate going into the house
-                    }
-                if (object -> walkable == false){
+                }//else if(object -> type == GDOOR){
+                    
+                //} //add a bit of a wait here to simulate going into the house
+                else if(object -> type == SPIKE){
+                    player_hurt();
+    
+                } if (object -> type == LBUSH){
+                    p1.x = p1.x - 1;
+                    return NO_DRAW;
+                    }else if(object -> type == GEM){
+                    //add to gem score
+                    p1.gems++; 
+                    if (p1.gems >= 3 && p1.quest_complete < 1){
+                        p1.quest_complete += 0.5;
+                    }   
+                    map_erase(p1.x-1, p1.y);
+                }
+                if (!omni_en && object -> walkable == false){
                     return NO_RESULT;
                 }
             }
-            Player.x = Player.x - 1;
+            p1.x = p1.x - 1;
             return FULL_DRAW;
            
         case BUTTON1: 
-            omni();
+            omni_en = !omni_en;
             break;
         case BUTTON2: 
+            MapItem* object1 = get_north(p1.x, p1.y); 
+            MapItem* object2 = get_south(p1.x, p1.y); 
+            MapItem* object3 = get_east(p1.x, p1.y); 
+            MapItem* object4 = get_west(p1.x, p1.y);
+            if(object1 ->type == NPC){ 
+                interact_npc(object1);
+            } else if (object2->type ==NPC){
+                interact_npc(object2);
+            }else if (object3->type ==NPC){
+                interact_npc(object3);
+            } else if (object4->type ==NPC){
+                interact_npc(object4);
+            } 
+            else if (object1 ->type == GDOOR|| object2->type == GDOOR || object3 ->type == GDOOR|| object4 ->type  == GDOOR){ 
+                if (p1.has_key){
+                    door_open = true;
+                    map_erase(p1.x-1, p1.y);
+                } else{
+                    speech("Door Locked.", "Must get key.", "Door Locked.", "Must get key.");
+                }
+            }
             break;
         case MENU_BUTTON:
+            switch_axis = ingamemenu(&p1);
             
         break;
-        default:        break;
+        default: break;
     }
     return NO_RESULT;
 }
 
+
+
 /**
  * Entry point for frame drawing. This should be called once per iteration of
  * the game loop. This draws all tiles on the screen, followed by the status 
@@ -210,12 +340,12 @@
             // Here, we have a given (i,j)
             
             // Compute the current map (x,y) of this tile
-            int x = i + Player.x;
-            int y = j + Player.y;
+            int x = i + p1.x;
+            int y = j + p1.y;
             
             // Compute the previous map (px, py) of this tile
-            int px = i + Player.px;
-            int py = j + Player.py;
+            int px = i + p1.px;
+            int py = j + p1.py;
                         
             // Compute u,v coordinates for drawing
             int u = (i+5)*11 + 3;
@@ -223,9 +353,9 @@
             
             // Figure out what to draw
             DrawFunc draw = NULL;
-            if (init && i == 0 && j == 0) // Only draw the player on init (this is when the loop hits the center of the screen)
+            if (init && i == 0 && j == 0 && init != NO_DRAW) // Only draw the player on init (this is when the loop hits the center of the screen)
             {
-                draw_player(u, v, Player.has_key);
+                draw_player(u, v, p1.has_key);
             
                 continue;
             }
@@ -247,10 +377,11 @@
                     }
                     else // There used to be something, but now there isn't
                     {
-                        if (house_enabled){
+                        if (in_house){
                             draw = draw_house_floor;
+                        }else{
+                        draw = draw_nothing;
                         }
-                        draw = draw_nothing;
                     }
                 }
             }
@@ -274,8 +405,8 @@
     }
 
     // Draw status bars    
-    draw_upper_status(health);
-    draw_lower_status(Player.x, Player.y);
+    draw_upper_status(p1.health);
+    draw_lower_status(p1.x, p1.y);
 }
 
 
@@ -285,6 +416,7 @@
  */
 void init_main_map()
 {
+    Map* map = set_active_map(0);
     // "Random" plants
     
     maps_init(50, 50, 5);
@@ -301,18 +433,40 @@
         add_spike(x, y);
     }
     
+    for(int i = 0; i < 30; i++)
+    {
+        int x = rand()%((map_width()+1)-1) + 1;
+        int y = rand()%((map_height()+1)-1) + 1;
+        add_gem(x, y, 1);
+    }
+    
+    for(int i = 0; i < 15; i++)
+    {
+        int x = rand()%((map_width()+1)-1) + 1;
+        int y = rand()%((map_height()+1)-1) + 1;
+        add_gem(x, y, 2);
+    }
+    
+    for(int i = 0; i < 9; i++)
+    {
+        int x = rand()%((map_width()+1)-1) + 1;
+        int y = rand()%((map_height()+1)-1) + 1;
+        add_gem(x, y, 3);
+    }
+    
     pc.printf("plants\r\n");
         
+    p1.x = 41;
+    p1.y = 10;
     pc.printf("Adding walls!\r\n");
     add_wall(0,              0,              HORIZONTAL, map_width());
     add_wall(0,              map_height()-1, HORIZONTAL, map_width());
     add_wall(0,              0,              VERTICAL,   map_height());
     add_wall(map_width()-1,  0,              VERTICAL,   map_height());
-    add_wall(20, 20, HORIZONTAL, 15);
-    add_npc(13, 13);
-    add_rock(6, 42);
-    add_door(7, 48);
-    add_goal(43, 5);
+    add_rock(13, 2);
+    add_redhouse(9, 1, 1);
+    add_bush_rect(1, 19, 11, 38);
+    add_bush_rect(20, 17, 23, 21);
     pc.printf("Walls done!\r\n");
 
     print_map();
@@ -322,15 +476,20 @@
 {
     
     Map* map = set_active_map(1); //one is a house map
-    maps_init(20, 20, 5);
-    Player.x = Player.y = 5;
-    
+    //in_house = 1;
+    maps_init(10, 10, 5);
     add_wall(0,              0,              HORIZONTAL, map_width());
     add_wall(0,              map_height()-1, HORIZONTAL, map_width());
     add_wall(0,              0,              VERTICAL,   map_height());
     add_wall(map_width()-1,  0,              VERTICAL,   map_height());
- 
-    add_npc(5, 15); //place NPC in the house
+    
+    add_wall(1, 4, HORIZONTAL, 3);
+    add_wall(4, 4, VERTICAL, 4);
+    add_gdoor(4,8);
+    
+    add_npc(6, 2); //place NPC in the house
+    add_door(8, 8);
+    add_goal(1, 8);
 }
 
 /**
@@ -341,26 +500,29 @@
  */
 int main()
 {
-    Map* map = set_active_map(0);
-    int start = menu();
+    Menu start_m = Menu(3);   
+    int start = start_m.display();
     // First things first: initialize hardware
     ASSERT_P(hardware_init() == ERROR_NONE, "Hardware init failed!");
 
     // Initialize the maps
     
+    init_house_map();
     init_main_map();
     
     
     // Initialize game state
     //set_active_map(0); //this doesn't need to be here twice
-    Player.x = Player.y = 5;
-    Player.quest_complete = false;
+    p1.health = 0;
+    p1.lives = 3;
+    p1.x = p1.y = 5;
+    p1.quest_complete = false;
 
     // Initial drawing
     draw_game(true);
 
     // Main game loop
-    while(1)
+    while(p1.lives)
     {
         // Timer to measure game update speed
         Timer t; t.start();
@@ -372,15 +534,28 @@
             int a = get_action(in);       
         // 3. Update game (update_game)
             int u = update_game(a);
+            update_npcs();
         // 3b. Check for game over
+        draw_game(u);
+        if (p1.health >= 120){
+            int result = gameover(--p1.lives);
+            if (result){
+                init_main_map();
+                p1.health = 0;
+                //Player.lives--;
+                p1.x = p1.y = 5;
+                p1.quest_complete = false;
+            }} 
         if (game_over == true){
-            draw_game_over();
-        }//else if(house_enabled == true){
+            break;
+        }
+            
+        //else if(house_enabled == true){
             
             //Player.x = Player.y = 5; //idk if this should be here...
         //}
         // 4. Draw frame (draw_game)
-        draw_game(u);
+        
         
         
         // 5. Frame delay
@@ -388,4 +563,5 @@
         int dt = t.read_ms();
         if (dt < 100) wait_ms(100 - dt);
     }
+    draw_game_over();
 }