Carter Montgomery / Mbed 2 deprecated 2035_Final_Project

Dependencies:   mbed wave_player 4DGL-uLCD-SE MMA8452

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 // Project includes
00002 #include "globals.h"
00003 #include "hardware.h"
00004 #include "map.h"
00005 #include "graphics.h"
00006 #include "speech.h"
00007 #include "startmenu.h"
00008 #include "pausemenu.h"
00009 #include "gameover.h"
00010 
00011 // Functions in this file
00012 int get_action (GameInputs inputs);
00013 int update_game (int action);
00014 void draw_game (int init);
00015 void init_main_map();
00016 void init_house_map();
00017 int main ();
00018 
00019 Player p1;
00020 int omni_en = 0;
00021 int in_house;
00022 int house_enabled = false;
00023 int door_open = false;
00024 int game_over = false;
00025 int switch_axis = 0;
00026 
00027 
00028 /*Functions to for player to interact with the map
00029 */
00030 
00031 void interact_npc(MapItem* object){
00032     if (p1.rock_pushed && p1.gems >= 3){
00033         p1.quest_complete = true;
00034     }
00035     NonPlayer* n = (NonPlayer*)object -> data;
00036     if(n -> quest_requested == false){
00037         speech("Find 3 red gems", "and move the rock", "in the backyard", "then I will give you gold!");
00038         n -> quest_requested = true;
00039     } else if (p1.quest_complete == false){ //should quest complete be in the player struct?
00040         speech("get it boi! What", "are u waitin for?", "You must finish ", "the quest!!!!");
00041     } else if (n -> has_key == true) {
00042         speech("Congrats!", "Thank you for", "completing the", "quest! Here's the key!");
00043         n -> has_key = false;
00044         p1.has_key = true;
00045     } else if(n -> has_key == false){
00046         speech("Congrats!", "Quest complete.", "", "");
00047     }
00048 }
00049 
00050 void player_hurt(){
00051     //lower health bar
00052         p1.health+=10;   
00053         for(int i = 0; i < 2; i++){ 
00054         speaker.period(1.0/150.0); // 500hz period
00055         speaker =0.25; //25% duty cycle - mid range volume
00056         wait(.02);
00057         speaker=0.0; // turn off audio
00058         wait(0.1);
00059         }
00060 }
00061 
00062 
00063 /**
00064  * Given the game inputs, determine what kind of update needs to happen.
00065  * Possbile return values are defined below.
00066  */
00067 #define NO_ACTION 0
00068 #define BUTTON1 1 //omni button
00069 #define BUTTON2 2 //toggle/action button
00070 #define BUTTON3 3 //scroll/select?
00071 #define MENU_BUTTON 4
00072 #define GO_LEFT 5
00073 #define GO_RIGHT 6
00074 #define GO_UP 7
00075 #define GO_DOWN 8
00076 int get_action(GameInputs inputs)
00077 {
00078     double y_axis;
00079     double x_axis; 
00080     if(switch_axis){
00081         y_axis = inputs.ax;
00082         x_axis = inputs.ay;
00083     }else{
00084         y_axis = inputs.ay;
00085         x_axis = inputs.ax;
00086     }
00087     if(!inputs.b1){
00088         return BUTTON1;
00089     }
00090     if(!inputs.b2){
00091         return BUTTON2;
00092     }
00093     if (!inputs.b3){
00094         return MENU_BUTTON;
00095     }
00096     if ((y_axis > 0.05 && y_axis < 0.9) && abs(x_axis) < .9){
00097         return GO_LEFT;    
00098     } else if ((y_axis < -0.05 && y_axis > -0.9) && abs(x_axis) < .9){
00099         return GO_RIGHT;
00100     }else if (x_axis > 0.05 && x_axis < 0.9){
00101         return GO_DOWN;
00102     }else if (x_axis < -0.05 && x_axis > -0.9){
00103         return GO_UP;
00104     }
00105     return NO_ACTION;
00106 }
00107 
00108 void update_npcs(){
00109     //Map* m = get_active_map();
00110     /*int h = map_height();
00111     int w = map_width();
00112     
00113     for(int i = 0; i < w; i++){
00114         for(int j = 0; j < h; j++){
00115             if (MapItem* object = get_here(i, j)){
00116                 if (object -> type == EXTRA){
00117                     Extra* d = (Extra*)object -> data;
00118                     d -> e = true;
00119                     add_extra(i+1, j);
00120                 }
00121             } 
00122         }
00123     }
00124     for(int i = 0; i < w; i++){
00125         for(int j = 0; j < h; j++){
00126             if (MapItem* object = get_here(i, j)){
00127                 if (object -> type == EXTRA){
00128                     Extra* d = (Extra*)object -> data;
00129                     if(d -> e == true) map_erase(i, j);
00130                 }
00131             } 
00132         }
00133     }*/
00134 }
00135 
00136 /**
00137  * Update the game state based on the user action. For example, if the user
00138  * requests GO_UP, then this function should determine if that is possible by
00139  * consulting the map, and update the Player position accordingly.
00140  * 
00141  * Return values are defined below. FULL_DRAW indicates that for this frame,
00142  * draw_game should not optimize drawing and should draw every tile, even if
00143  * the player has not moved.
00144  */
00145 #define NO_RESULT 0
00146 #define GAME_OVER 1
00147 #define FULL_DRAW 2
00148 #define NO_DRAW   3
00149 int update_game(int action)
00150 {
00151     // Save player previous location before updating
00152     p1.px = p1.x;
00153     p1.py = p1.y;
00154     
00155     // Do different things based on the each action.
00156     // You can define functions like "go_up()" that get called for each case.
00157     switch(action) //have a function called for each type of object. Pass a pointer to the object to the interact function
00158     {
00159         case GO_UP: 
00160             if (MapItem* object = get_north(p1.x, p1.y)){
00161                 //if (object -> type == NPC){
00162                     //interact_npc(object);
00163                   //  return NO_RESULT;
00164                  if (object -> type == LBUSH){
00165                     p1.y = p1.y - 1;
00166                     return NO_DRAW;
00167                 } else if(object -> type == SPIKE){
00168                     player_hurt(); 
00169                 } else if(object -> type == GEM){
00170                     //add to gem score
00171                     p1.gems++;    
00172                     if (p1.gems >= 3 && p1.quest_complete < 1){
00173                         p1.quest_complete += 0.5;
00174                     }
00175                     map_erase(p1.x, p1.y-1);
00176                 } else if (!omni_en && object -> walkable == false){
00177                     return NO_RESULT;
00178                 }
00179             }
00180             p1.y = p1.y - 1;
00181             return FULL_DRAW;
00182         case GO_LEFT:   
00183             if (MapItem* object = get_west(p1.x, p1.y)){
00184                 if (object -> type == ROCK){
00185                     add_rock(p1.x + 2, p1.y);
00186                     map_erase(p1.x+1, p1.y);
00187                     p1.x = p1.x + 1;
00188                     p1.rock_pushed = true;
00189                     return FULL_DRAW;
00190                     
00191                 }else if (object -> type == LBUSH){
00192                     p1.x = p1.x + 1;
00193                     return NO_DRAW; 
00194                 }else if(object -> type == SPIKE){
00195                     player_hurt();   
00196                 } else if(object -> type == GEM){
00197                     //lower health bar
00198                     p1.gems++;  
00199                     if (p1.gems >= 3 && p1.quest_complete < 1){
00200                         p1.quest_complete += 0.5;
00201                     }
00202                     map_erase(p1.x+1, p1.y);
00203                 }else if(object -> type == DOOR){
00204                     if (in_house){
00205                         set_active_map(0);
00206                         p1.x = 3;
00207                         p1.y = 7;
00208                         in_house = 0;
00209                     }else{
00210                         set_active_map(1);
00211                         p1.x = 6;
00212                         p1.y = 7; 
00213                         in_house = 1;
00214                     }
00215                } if (!omni_en && object -> walkable == false){
00216                      return NO_RESULT;
00217                 }
00218             }
00219             p1.x = p1.x + 1;
00220             return FULL_DRAW; 
00221         case GO_DOWN:   
00222             if (MapItem* object = get_south(p1.x, p1.y)){
00223                 if (object -> type == DOOR){
00224                     if (p1.has_key == true){
00225                         map_erase(p1.x, p1.y + 1);
00226                         p1.y = p1.y + 1;
00227                         door_open = true;
00228                         return FULL_DRAW;
00229                     }
00230                     return NO_RESULT;
00231                 }if (object -> type == LBUSH){
00232                     p1.y = p1.y + 1;
00233                     return NO_DRAW;
00234                 }else if(object -> type == SPIKE){
00235                     player_hurt(); 
00236                 } else if(object -> type == GEM){
00237                     //add to gem score
00238                     p1.gems++;   
00239                     if (p1.gems >= 3 && p1.quest_complete < 1){
00240                         p1.quest_complete += 0.5;
00241                     } 
00242                     map_erase(p1.x, p1.y+1);
00243                 }
00244                 if (!omni_en && object -> walkable == false){
00245                     return NO_RESULT;
00246                 }    
00247             }
00248             p1.y = p1.y + 1;
00249             return FULL_DRAW;
00250             
00251         case GO_RIGHT:  
00252             if (MapItem* object = get_east(p1.x, p1.y)){
00253                 if (object -> type == GOAL){
00254                     if(door_open == true){
00255                         game_over = true;
00256                         uLCD.locate(1,1);
00257                         uLCD.printf("Goal reached");
00258                         return NO_RESULT;
00259                     }
00260                     
00261                 }//else if(object -> type == GDOOR){
00262                     
00263                 //} //add a bit of a wait here to simulate going into the house
00264                 else if(object -> type == SPIKE){
00265                     player_hurt();
00266     
00267                 } if (object -> type == LBUSH){
00268                     p1.x = p1.x - 1;
00269                     return NO_DRAW;
00270                     }else if(object -> type == GEM){
00271                     //add to gem score
00272                     p1.gems++; 
00273                     if (p1.gems >= 3 && p1.quest_complete < 1){
00274                         p1.quest_complete += 0.5;
00275                     }   
00276                     map_erase(p1.x-1, p1.y);
00277                 }
00278                 if (!omni_en && object -> walkable == false){
00279                     return NO_RESULT;
00280                 }
00281             }
00282             p1.x = p1.x - 1;
00283             return FULL_DRAW;
00284            
00285         case BUTTON1: 
00286             omni_en = !omni_en;
00287             break;
00288         case BUTTON2: 
00289             MapItem* object1 = get_north(p1.x, p1.y); 
00290             MapItem* object2 = get_south(p1.x, p1.y); 
00291             MapItem* object3 = get_east(p1.x, p1.y); 
00292             MapItem* object4 = get_west(p1.x, p1.y);
00293             if(object1 ->type == NPC){ 
00294                 interact_npc(object1);
00295             } else if (object2->type ==NPC){
00296                 interact_npc(object2);
00297             }else if (object3->type ==NPC){
00298                 interact_npc(object3);
00299             } else if (object4->type ==NPC){
00300                 interact_npc(object4);
00301             } 
00302             else if (object1 ->type == GDOOR|| object2->type == GDOOR || object3 ->type == GDOOR|| object4 ->type  == GDOOR){ 
00303                 if (p1.has_key){
00304                     door_open = true;
00305                     map_erase(p1.x-1, p1.y);
00306                 } else{
00307                     speech("Door Locked.", "Must get key.", "Door Locked.", "Must get key.");
00308                 }
00309             }
00310             break;
00311         case MENU_BUTTON:
00312             PauseMenu pause_m(&p1);
00313             pause_m.display();
00314             switch_axis = pause_m.get_config();
00315             //switch_axis = ingamemenu(&p1);
00316             
00317         break;
00318         default: break;
00319     }
00320     return NO_RESULT;
00321 }
00322 
00323 
00324 
00325 /**
00326  * Entry point for frame drawing. This should be called once per iteration of
00327  * the game loop. This draws all tiles on the screen, followed by the status 
00328  * bars. Unless init is nonzero, this function will optimize drawing by only 
00329  * drawing tiles that have changed from the previous frame.
00330  */
00331 void draw_game(int init)
00332 {
00333    // int param1;
00334     //int param2; 
00335     // Draw game border first
00336     if(init) draw_border();
00337     
00338     // Iterate over all visible map tiles
00339     for (int i = -5; i <= 5; i++) // Iterate over columns of tiles
00340     {
00341         for (int j = -4; j <= 4; j++) // Iterate over one column of tiles
00342         {
00343             // Here, we have a given (i,j)
00344             
00345             // Compute the current map (x,y) of this tile
00346             int x = i + p1.x;
00347             int y = j + p1.y;
00348             
00349             // Compute the previous map (px, py) of this tile
00350             int px = i + p1.px;
00351             int py = j + p1.py;
00352                         
00353             // Compute u,v coordinates for drawing
00354             int u = (i+5)*11 + 3;
00355             int v = (j+4)*11 + 15;
00356             
00357             // Figure out what to draw
00358             DrawFunc draw = NULL;
00359             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)
00360             {
00361                 draw_player(u, v, p1.has_key);
00362             
00363                 continue;
00364             }
00365             else if (x >= 0 && y >= 0 && x < map_width() && y < map_height()) // Current (i,j) in the map
00366             {
00367                 MapItem* curr_item = get_here(x, y);
00368                 MapItem* prev_item = get_here(px, py);
00369                 if (init || curr_item != prev_item) // Only draw if they're different
00370                 {
00371                     if (curr_item) // There's something here! Draw it
00372                     {
00373                         //if (curr_item -> type == ROCK){
00374                             //set parameters
00375                           //  Rock* r = (Rock*) curr_item -> data;
00376                             //param1 = r -> x;
00377                             //param2 = r -> y;
00378                             //}
00379                         draw = curr_item->draw;
00380                     }
00381                     else // There used to be something, but now there isn't
00382                     {
00383                         if (in_house){
00384                             draw = draw_house_floor;
00385                         }else{
00386                         draw = draw_nothing;
00387                         }
00388                     }
00389                 }
00390             }
00391             else if (init) // If doing a full draw, but we're out of bounds, draw the walls.
00392             {
00393                 draw = draw_wall;
00394             }
00395 
00396             // Actually draw the tile
00397             //MapItem* curr_item = get_here(x, y);
00398             //MapItem* prev_item = get_here(px, py);
00399             if (draw){
00400                // if(curr_item){
00401                  //   if(curr_item -> type == ROCK){
00402                    // draw(param1, param2);
00403                     //}
00404                 //}
00405                 draw(u,v);
00406             }
00407         }
00408     }
00409 
00410     // Draw status bars    
00411     draw_upper_status(p1.health);
00412     draw_lower_status(p1.x, p1.y);
00413 }
00414 
00415 
00416 /**
00417  * Initialize the main world map. Add walls around the edges, interior chambers,
00418  * and plants in the background so you can see motion.
00419  */
00420 void init_main_map()
00421 {
00422     Map* map = set_active_map(0);
00423     // "Random" plants
00424     
00425     maps_init(50, 50, 5);
00426     for(int i = map_width() + 3; i < map_area(); i += 39)
00427     {
00428         add_plant(i % map_width(), i / map_width());
00429     }
00430     
00431     srand(time(NULL));
00432     for(int i = 0; i < 30; i++)
00433     {
00434         int x = rand()%((map_width()+1)-1) + 1;
00435         int y = rand()%((map_height()+1)-1) + 1;
00436         add_spike(x, y);
00437     }
00438     
00439     for(int i = 0; i < 30; i++)
00440     {
00441         int x = rand()%((map_width()+1)-1) + 1;
00442         int y = rand()%((map_height()+1)-1) + 1;
00443         add_gem(x, y, 1);
00444     }
00445     
00446     for(int i = 0; i < 15; i++)
00447     {
00448         int x = rand()%((map_width()+1)-1) + 1;
00449         int y = rand()%((map_height()+1)-1) + 1;
00450         add_gem(x, y, 2);
00451     }
00452     
00453     for(int i = 0; i < 9; i++)
00454     {
00455         int x = rand()%((map_width()+1)-1) + 1;
00456         int y = rand()%((map_height()+1)-1) + 1;
00457         add_gem(x, y, 3);
00458     }
00459     
00460     pc.printf("plants\r\n");
00461         
00462     p1.x = 41;
00463     p1.y = 10;
00464     pc.printf("Adding walls!\r\n");
00465     add_wall(0,              0,              HORIZONTAL, map_width());
00466     add_wall(0,              map_height()-1, HORIZONTAL, map_width());
00467     add_wall(0,              0,              VERTICAL,   map_height());
00468     add_wall(map_width()-1,  0,              VERTICAL,   map_height());
00469     add_rock(13, 2);
00470     add_redhouse(9, 1, 1);
00471     add_bush_rect(1, 19, 11, 38);
00472     add_bush_rect(20, 17, 23, 21);
00473     pc.printf("Walls done!\r\n");
00474 
00475     print_map();
00476 }
00477 
00478 void init_house_map()
00479 {
00480     
00481     Map* map = set_active_map(1); //one is a house map
00482     //in_house = 1;
00483     maps_init(10, 10, 5);
00484     add_wall(0,              0,              HORIZONTAL, map_width());
00485     add_wall(0,              map_height()-1, HORIZONTAL, map_width());
00486     add_wall(0,              0,              VERTICAL,   map_height());
00487     add_wall(map_width()-1,  0,              VERTICAL,   map_height());
00488     
00489     add_wall(1, 4, HORIZONTAL, 3);
00490     add_wall(4, 4, VERTICAL, 4);
00491     add_gdoor(4,8);
00492     
00493     add_npc(6, 2); //place NPC in the house
00494     add_door(8, 8);
00495     add_goal(1, 8);
00496 }
00497 
00498 /**
00499  * Program entry point! This is where it all begins.
00500  * This function orchestrates all the parts of the game. Most of your
00501  * implementation should be elsewhere - this holds the game loop, and should
00502  * read like a road map for the rest of the code.
00503  */
00504 int main()
00505 {
00506     
00507     StartMenu start_m = StartMenu();   
00508     int st = start_m.display();
00509     // First things first: initialize hardware
00510     ASSERT_P(hardware_init() == ERROR_NONE, "Hardware init failed!");
00511 
00512     // Initialize the maps
00513     
00514     init_house_map();
00515     init_main_map();
00516     
00517     
00518     // Initialize game state
00519     //set_active_map(0); //this doesn't need to be here twice
00520     p1.health = 0;
00521     p1.lives = 3;
00522     p1.x = p1.y = 5;
00523     p1.quest_complete = false;
00524 
00525     // Initial drawing
00526     draw_game(true);
00527 
00528     // Main game loop
00529     while(p1.lives)
00530     {
00531         // Timer to measure game update speed
00532         Timer t; t.start();
00533         
00534         // Actually do the game update:
00535         // 1. Read inputs  
00536             GameInputs in = read_inputs();
00537         // 2. Determine action (get_action) 
00538             int a = get_action(in);       
00539         // 3. Update game (update_game)
00540             int u = update_game(a);
00541             update_npcs();
00542         // 3b. Check for game over
00543         draw_game(u);
00544         if (p1.health >= 120){
00545             int result = gameover(--p1.lives);
00546             if (result){
00547                 init_main_map();
00548                 p1.health = 0;
00549                 //Player.lives--;
00550                 p1.x = p1.y = 5;
00551                 p1.quest_complete = false;
00552             }} 
00553         if (game_over == true){
00554             break;
00555         }
00556             
00557         //else if(house_enabled == true){
00558             
00559             //Player.x = Player.y = 5; //idk if this should be here...
00560         //}
00561         // 4. Draw frame (draw_game)
00562         
00563         
00564         
00565         // 5. Frame delay
00566         t.stop();
00567         int dt = t.read_ms();
00568         if (dt < 100) wait_ms(100 - dt);
00569     }
00570     draw_game_over();
00571 }