Adventure game written for ECE2035 at the Georgia Institute of Technology
Dependencies: mbed wave_player 4DGL-uLCD-SE MMA8452
Diff: main.cpp
- 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(); }