Adventure game written for ECE2035 at the Georgia Institute of Technology
Dependencies: mbed wave_player 4DGL-uLCD-SE MMA8452
main.cpp
- Committer:
- trmontgomery
- Date:
- 2019-10-26
- Revision:
- 5:93a4c396c1af
- Parent:
- 4:cdc54191ff07
File content as of revision 5:93a4c396c1af:
// Project includes #include "globals.h" #include "hardware.h" #include "map.h" #include "graphics.h" #include "speech.h" #include "startmenu.h" #include "pausemenu.h" #include "gameover.h" // Functions in this file int get_action (GameInputs inputs); int update_game (int action); void draw_game (int init); void init_main_map(); void init_house_map(); int main (); Player p1; int omni_en = 0; int in_house; int house_enabled = false; int door_open = false; int game_over = false; 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 //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 #define GO_UP 7 #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; } if(!inputs.b2){ return BUTTON2; } if (!inputs.b3){ return MENU_BUTTON; } if ((y_axis > 0.05 && y_axis < 0.9) && abs(x_axis) < .9){ return GO_LEFT; } else if ((y_axis < -0.05 && y_axis > -0.9) && abs(x_axis) < .9){ return GO_RIGHT; }else if (x_axis > 0.05 && x_axis < 0.9){ return GO_DOWN; }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 * consulting the map, and update the Player position accordingly. * * Return values are defined below. FULL_DRAW indicates that for this frame, * draw_game should not optimize drawing and should draw every tile, even if * the player has not moved. */ #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 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(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; } map_erase(p1.x, p1.y-1); } else if (!omni_en && object -> walkable == false){ return NO_RESULT; } } p1.y = p1.y - 1; return FULL_DRAW; case GO_LEFT: if (MapItem* object = get_west(p1.x, p1.y)){ if (object -> type == ROCK){ 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 == LBUSH){ p1.x = p1.x + 1; return NO_DRAW; }else if(object -> type == SPIKE){ player_hurt(); } else if(object -> type == GEM){ //lower health bar 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; } } p1.x = p1.x + 1; return FULL_DRAW; case GO_DOWN: if (MapItem* object = get_south(p1.x, p1.y)){ if (object -> type == DOOR){ 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 (!omni_en && object -> walkable == false){ return NO_RESULT; } } p1.y = p1.y + 1; return FULL_DRAW; case GO_RIGHT: 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 == 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; } } p1.x = p1.x - 1; return FULL_DRAW; case BUTTON1: 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: PauseMenu pause_m(&p1); pause_m.display(); switch_axis = pause_m.get_config(); //switch_axis = ingamemenu(&p1); 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 * bars. Unless init is nonzero, this function will optimize drawing by only * drawing tiles that have changed from the previous frame. */ void draw_game(int init) { // int param1; //int param2; // Draw game border first if(init) draw_border(); // Iterate over all visible map tiles for (int i = -5; i <= 5; i++) // Iterate over columns of tiles { for (int j = -4; j <= 4; j++) // Iterate over one column of tiles { // Here, we have a given (i,j) // Compute the current map (x,y) of this tile int x = i + p1.x; int y = j + p1.y; // Compute the previous map (px, py) of this tile int px = i + p1.px; int py = j + p1.py; // Compute u,v coordinates for drawing int u = (i+5)*11 + 3; int v = (j+4)*11 + 15; // Figure out what to draw DrawFunc draw = NULL; 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, p1.has_key); continue; } else if (x >= 0 && y >= 0 && x < map_width() && y < map_height()) // Current (i,j) in the map { MapItem* curr_item = get_here(x, y); MapItem* prev_item = get_here(px, py); if (init || curr_item != prev_item) // Only draw if they're different { if (curr_item) // There's something here! Draw it { //if (curr_item -> type == ROCK){ //set parameters // Rock* r = (Rock*) curr_item -> data; //param1 = r -> x; //param2 = r -> y; //} draw = curr_item->draw; } else // There used to be something, but now there isn't { if (in_house){ draw = draw_house_floor; }else{ draw = draw_nothing; } } } } else if (init) // If doing a full draw, but we're out of bounds, draw the walls. { draw = draw_wall; } // Actually draw the tile //MapItem* curr_item = get_here(x, y); //MapItem* prev_item = get_here(px, py); if (draw){ // if(curr_item){ // if(curr_item -> type == ROCK){ // draw(param1, param2); //} //} draw(u,v); } } } // Draw status bars draw_upper_status(p1.health); draw_lower_status(p1.x, p1.y); } /** * Initialize the main world map. Add walls around the edges, interior chambers, * and plants in the background so you can see motion. */ void init_main_map() { Map* map = set_active_map(0); // "Random" plants maps_init(50, 50, 5); for(int i = map_width() + 3; i < map_area(); i += 39) { add_plant(i % map_width(), i / map_width()); } srand(time(NULL)); for(int i = 0; i < 30; i++) { int x = rand()%((map_width()+1)-1) + 1; int y = rand()%((map_height()+1)-1) + 1; 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_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(); } void init_house_map() { Map* map = set_active_map(1); //one is a house map //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_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); } /** * Program entry point! This is where it all begins. * This function orchestrates all the parts of the game. Most of your * implementation should be elsewhere - this holds the game loop, and should * read like a road map for the rest of the code. */ int main() { StartMenu start_m = StartMenu(); int st = 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 p1.health = 0; p1.lives = 3; p1.x = p1.y = 5; p1.quest_complete = false; // Initial drawing draw_game(true); // Main game loop while(p1.lives) { // Timer to measure game update speed Timer t; t.start(); // Actually do the game update: // 1. Read inputs GameInputs in = read_inputs(); // 2. Determine action (get_action) 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){ break; } //else if(house_enabled == true){ //Player.x = Player.y = 5; //idk if this should be here... //} // 4. Draw frame (draw_game) // 5. Frame delay t.stop(); int dt = t.read_ms(); if (dt < 100) wait_ms(100 - dt); } draw_game_over(); }