2035 project 2
Dependencies: mbed wave_player 4DGL-uLCD-SE MMA8452
main.cpp
- Committer:
- ranroun3
- Date:
- 2021-12-01
- Revision:
- 23:06cbe894690d
- Parent:
- 22:397601b1cdb4
File content as of revision 23:06cbe894690d:
// Project includes #include "globals.h" #include "hardware.h" #include "map.h" #include "graphics.h" #include "speech.h" #include "speech_script.h" /* 95. Time Traveler - PCs travel to other points in time via (artificial portals, device, magic, naturally occurring portals, ship) Save the Future - the future is doomed. PCs must travel back in time to try and change history in a way that will save the future Temporal Explorer - PCs explore various points in time Temporal Heist - PCs steal objects just before it is destroyed or lost Time Cop - PCs work to defend the time line or repair the damage caused by others */ // 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_boss_map(); void init_finalboss_map(); bool playerHealthCheck(int health); void youWinScreen(); void youLoseScreen(); void decreaseLife(); void conditionals(); void increaseLife(); void increaseHealth(); 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 bool has_key; int questStatus; bool isOmniEnabled; void *currBoss; int health; int lives; int item1; int potion1; int potion2; // void *Player.item2; // You can add other properties for the player here } Player; GameInputs in; bool firstDraw; /** * Given the game inputs, determine what kind of update needs to happen. * Possbile return values are defined below. */ #define NO_ACTION 0 #define ACTION_BUTTON 1 #define MENU_BUTTON 2 #define GO_LEFT 3 #define GO_RIGHT 4 #define GO_UP 5 #define GO_DOWN 6 #define OMNI_BUTTON 7 #define ITEM_1 8 #define ITEM_2 9 #define ITEM_3 10 int get_action(GameInputs inputs) { if (!inputs.b1) { return ACTION_BUTTON; } else if (!inputs.b2) { return OMNI_BUTTON; } else if (!inputs.b3) { return ITEM_1; } else if (!inputs.b4) { return ITEM_2; } else if (!inputs.b5) { return ITEM_3; } else if (inputs.ax < -0.25) { return GO_UP; } else if (inputs.ax > 0.25) { return GO_DOWN; } else if (inputs.ay > 0.25) { return GO_RIGHT; } else if (inputs.ay < -0.25) { return GO_LEFT; } else { return NO_ACTION; } } void conditionals() { MapItem *current = get_here(Player.x, Player.y); if (current->type == HAMMER && !Player.item1) { //Item *currItem = (currItem *)current->data; Player.item1 =1; map_erase(Player.x, Player.y); } if(current->type == POTION && !Player.potion1) { Player.potion1 = 1; map_erase(Player.x, Player.y); } if(current->type == HEART && !Player.potion2) { Player.potion2 = 1; map_erase(Player.x, Player.y); } if(current->type == KEY) { Player.has_key = true; map_erase(Player.x, Player.y); } } /** * 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 MOVEMENT 3 int update_game(int action) { // Save player previous location before updating Player.px = Player.x; Player.py = Player.y; //preprocess objects above, left, right, and below current character; MapItem *above = get_north(Player.x, Player.y); MapItem *left = get_west(Player.x, Player.y); MapItem *right = get_east(Player.x, Player.y); MapItem *below = get_south(Player.x, Player.y); MapItem *current = get_here(Player.x, Player.y); conditionals(); // Do different things based on the each action. // You can define functions like "go_up()" that get called for each case. switch (action) { case GO_UP: { if (above->walkable || Player.isOmniEnabled) { Player.y--; return MOVEMENT; } break; } case GO_LEFT: { if (left->walkable || Player.isOmniEnabled) { Player.x--; return MOVEMENT; } break; case GO_DOWN: if (below->walkable || Player.isOmniEnabled) { Player.y++; return MOVEMENT; } break; } case GO_RIGHT: { if (right->walkable || Player.isOmniEnabled) { Player.x++; return MOVEMENT; } break; } case ACTION_BUTTON: { /******************************************* * PORTAL CODE * ********************************************/ if (current->type == STAIRS) { StairsData *currStairs = (StairsData *)current->data; pc.printf("%d", currStairs->tx); pc.printf("%d", currStairs->ty); pc.printf("%d",currStairs->tm); if (Player.questStatus>=1) { pc.printf("%d", currStairs->tx); pc.printf("%d", currStairs->ty); pc.printf("%d",currStairs->tm); stairs_speech(1); Player.x = currStairs->tx; Player.y = currStairs->ty; set_active_map(currStairs->tm); return FULL_DRAW; } //else if(Player.questStatus == 3) { // // } else if (Player.questStatus == 0) { stairs_speech(0); Player.health -= 10; // playerHealthCheck(); break; } return NO_RESULT; } /********************************************* NPC CODE *********************************************/ if ((above->type == NPC) || (below->type == NPC) || (left->type == NPC) || (right->type == NPC)) { newNPC *npc1 = NULL; //determine which one is the correct npc location if (above->type == NPC) { npc1 = (newNPC *)above->data; } else if (below->type == NPC) { npc1 = (newNPC *)below->data; } else if (left->type == NPC) { npc1 = (newNPC *)left->data; } else if (right->type == NPC) { npc1 = (newNPC *)right->data; } int currState = npc1->state; if (Player.questStatus == 3 && currState == 1) { currState = 2; } switch (currState) { case 0: { //starting the quest (step 1) npc_speech(0); npc1->state = 1; Player.questStatus = 1; break; } case 1: { //quest incomplete (after step 1, step 2 incomplete) npc_speech(1); break; } case 2: { //quest complete (step 3) npc_speech(2); add_key(npc1->x +2, npc1->y); //Player.has_key = true; npc1->state = 3; break; } case 3: { //after quest complete (step 3 onwards); npc_speech(3); break; } default: break; } } /********************************************* ENEMY CODE *********************************************/ if ((above->type == BOSS) || (below->type == BOSS) || (left->type == BOSS) || (right->type == BOSS)) { bossChar *boss1 = NULL; if (above->type == BOSS) { boss1 = (bossChar *)above->data; } else if (below->type == BOSS) { boss1 = (bossChar *)below->data; } else if (left->type == BOSS) { boss1 = (bossChar *)left->data; } else if (right->type == BOSS) { boss1 = (bossChar *)right->data; } Player.currBoss = boss1; int thisBossNum = boss1->numBoss; int currState = boss1->state; switch (currState) { case 0: { if(thisBossNum == 1) { if(Player.questStatus == 1) { boss_speech(0); } } if(thisBossNum == 2) { if(Player.questStatus == 2) { boss_speech(1); } else if(Player.questStatus == 1) { boss_speech(2); Player.health -= 10; // playerHealthCheck(); } } break; } case 1: { //player chooses correct spell break; } case 2: { //incorrect spell break; } default: break; } } /********************************************* SPELL CODE *********************************************/ if (current->type == SPELL) { bossChar *boss1 = (bossChar *)Player.currBoss; Spell *currSpell = (Spell *)current->data; if (boss1 == NULL) { spell_speech(0); Player.health -= 10; // playerHealthCheck(); return NO_ACTION; } int deadlySpell = boss1->correctSpell; int thisSpell = currSpell->spell_type; if(Player.questStatus == 1) { if (thisSpell == LAVA) { spell_speech(1); } else if (thisSpell == WATER) { spell_speech(2); } else if (thisSpell == TACO) { spell_speech(3); } if (deadlySpell == thisSpell) { spell_speech(9); boss1->state = 1; Player.questStatus = 2; int newX = boss1->x; int newY = boss1->y; map_erase(boss1->x, boss1->y); add_dead(newX, newY); spell_speech(10); Player.currBoss = NULL; add_stairs(8, 1, 8, 1, 2); add_stairs(1, 1, 5, 5, 0); add_hammer(boss1->x -1, boss1->y -1); add_healthPotion(6, 3); add_heart(6, 4); add_door(5, 2, 2, 3); return FULL_DRAW; } else if(thisSpell == WATER) { spell_speech(7); boss1->state = 2; } else if(thisSpell == LAVA) { spell_speech(11); Player.health -= 30; } } //defeated first boss, not second else if(Player.questStatus == 2 ) { pc.printf("%d, %d", deadlySpell, thisSpell); if(thisSpell == REDSP) { spell_speech(4); } else if(thisSpell == BLUESP) { spell_speech(5); } if (deadlySpell == thisSpell) { spell_speech(13); boss1->state = 1; Player.questStatus = 3; int newX = boss1->x; int newY = boss1->y; map_erase(boss1->x, boss1->y); add_dead(newX, newY); spell_speech(8); add_stairs(1,1,5,5,0); add_stairs(8,1, 8, 1, 1); //TODO drop item add_hammer(boss1->x -1, boss1->y -1); add_healthPotion(2, 4); add_heart(2, 5); add_door(1, 3, 2, 3); return FULL_DRAW; } else { spell_speech(12); Player.health -= 100; boss1->state = 2; } } } /********************************************* DOOR CODE *********************************************/ if ((above->type == DOOR) || (below->type == DOOR) || (left->type == DOOR) || (right->type == DOOR)) { Door *door1 = NULL; //determine which one is the correct npc location if (above->type == DOOR) { door1 = (Door *)above->data; } else if (below->type == DOOR) { door1 = (Door *)below->data; } else if (left->type == DOOR) { door1 = (Door *)left->data; } else if (right->type == DOOR) { door1 = (Door *)right->data; } if (Player.has_key) { char unlocked_door_0[] = "Congratulations!"; char unlocked_door_1[] = "Grab treasure!"; // pc.printf("Congratulations! You unlocked door!"); speech(unlocked_door_0, unlocked_door_1); draw_nothing(37, 118); Player.has_key = false; int startX = door1->startX; int startY = door1->startY; int endX = door1->endX; int endY = door1->endY; for (int i = startX; i <= endX; i++) { map_erase(i, startY); map_erase(i, endY); } for (int i = startY; i <= endY; i++) { map_erase(startX, i); map_erase(endX, i); } return FULL_DRAW; } if(get_active_map_int() == 0) { char door_locked_0[] = "Where's your key!"; char door_locked_1[] = "Try again!"; speech(door_locked_0, door_locked_1); } if((get_active_map_int() == 1) ||(get_active_map_int() == 2)) { char door_locked_0[] = "Use your hammer!"; char door_locked_1[] = "Try again!"; speech(door_locked_0, door_locked_1); } Player.health -= 10; } /********************************************* TREASURE CODE *********************************************/ if ((above->type == TREASURE) || (below->type == TREASURE) || (left->type == TREASURE) || (right->type == TREASURE)) { Treasure *t1 = NULL; //determine which one is the correct npc location if (above->type == TREASURE) { t1 = (Treasure *)above->data; } else if (below->type == TREASURE) { t1 = (Treasure *)below->data; } else if (left->type == TREASURE) { t1 = (Treasure *)left->data; } else if (right->type == TREASURE) { t1 = (Treasure *)right->data; } if(!(t1->isClaimed)) { map_erase(t1->x, t1->y); return GAME_OVER; } } return NO_ACTION; } // // case MENU_BUTTON: // break; case OMNI_BUTTON: { Player.isOmniEnabled = !Player.isOmniEnabled; return FULL_DRAW; } case ITEM_1: { if(Player.item1) { MapItem *above = get_north(Player.x, Player.y); MapItem *left = get_west(Player.x, Player.y); MapItem *right = get_east(Player.x, Player.y); MapItem *below = get_south(Player.x, Player.y); char using_hammer[] = "Using hammer!"; speech(using_hammer, NULL); if ((above->type == DOOR) || (below->type == DOOR) || (left->type == DOOR) || (right->type == DOOR)) { Door *door1 = NULL; //determine which one is the correct npc location if (above->type == DOOR) { door1 = (Door *)above->data; } else if (below->type == DOOR) { door1 = (Door *)below->data; } else if (left->type == DOOR) { door1 = (Door *)left->data; } else if (right->type == DOOR) { door1 = (Door *)right->data; } draw_nothing(1, 118); Player.item1 = 0; int startX = door1->startX; int startY = door1->startY; int endX = door1->endX; int endY = door1->endY; for (int i = startX; i <= endX; i++) { map_erase(i, startY); map_erase(i, endY); } for (int i = startY; i <= endY; i++) { map_erase(startX, i); map_erase(endX, i); } return FULL_DRAW; } else { char noWallNearby[] = "No wall nearby!"; speech(noWallNearby, NULL); draw_nothing(1, 118); Player.item1 = 0; } } else { char noItemHere[] = "No item here!"; speech(noItemHere, NULL); } } case ITEM_2: { if(Player.potion1) { char using_health1[] = "Using health"; char using_health2[] = "potion! +30!"; speech(using_health1, using_health2); increaseHealth(); return FULL_DRAW; } else { char noItemHere[] = "No item here!"; speech(noItemHere, NULL); break; } case ITEM_3: { if(Player.potion2) { char using1up_1[] = "Using 1-up Potion!"; char using1up_2[] = "Extra Life!"; speech(using1up_1, using1up_2); increaseLife(); return FULL_DRAW; } else { char noItemHere[] = "No item here!"; speech(noItemHere, NULL); break; } } } } return NO_RESULT; } void increaseLife() { Player.lives++; if(Player.lives>9) { Player.lives = 9; } draw_nothing(25, 118); Player.potion2 = 0; } void increaseHealth() { Player.health +=30; if(Player.health>99) { Player.health = 99; } draw_nothing(13, 118); Player.potion1 = 0; } /** * 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) { // 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 + Player.x; int y = j + Player.y; // Compute the previous map (px, py) of this tile int px = i + Player.px; int py = j + Player.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) { // Only draw the player on init draw_player(u, v, Player.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 draw = curr_item->draw; } else { // There used to be something, but now there isn't 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 if (draw) draw(u, v); } } // Draw status bars draw_upper_status(Player.x, Player.y, Player.health, Player.lives); draw_lower_status(Player.item1, Player.potion1, Player.potion2, Player.has_key, firstDraw); } /** * Initialize the main world map. Add walls around the edges, interior chambers, * and plants in the background so you can see motion. Note: using the similar * procedure you can init the secondary map(s). */ void init_main_map() { // "Random" plants Map* map = set_active_map(0); for(int i = map_width() + 3; i < map_area(); i += 39) { add_plant(i % map_width(), i / map_width()); } pc.printf("plants\r\n"); 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()); pc.printf("Walls done!\r\n"); //adding stairs objects //add_stairs(10, 1, 5, 5, 2); add_stairs(1, 1, 1, 1, 1); //add npc add_npc(1, 5); //add door // add_door(3, 10, HORIZONTAL, 4); // // add_door(3, 14, HORIZONTAL, 5); // add_door(3, 10, VERTICAL, 4); // add_door(7, 10, VERTICAL, 4); add_door(3, 10, 4, 4); //add treasure add_treasure(5, 12); //printing map print_map(); } void init_boss_map() { Map* map = set_active_map(1); 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()); pc.printf("Walls done!\r\n"); //adding stairs objects // add_stairs(1, 8, 3, 5, 0); //adding enemy add_boss(8,8, TACO, 1); //todo add spells add_spell(3, 3, WATER); add_spell(3, 5, LAVA); add_spell(3, 7, TACO); //printing map print_map(); } void init_finalboss_map() { Map* map = set_active_map(2); 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_boss(8,8, REDSP, 2); add_spell(5, 5, REDSP); add_spell(5, 7, BLUESP); print_map(); } bool playerHealthCheck(int health) { if(health <=0) { return true; } else { return false; } } void youWinScreen() { uLCD.background_color(0xFFFF00); uLCD.cls(); uLCD.locate(2,2); uLCD.printf("YOU WIN!!!!!!"); } void youLoseScreen() { uLCD.background_color(0xFF0000); uLCD.cls(); uLCD.locate(2,2); uLCD.printf("YOU LOSE"); uLCD.locate(2,5); uLCD.printf("Try Again!"); } void decreaseLife() { if(Player.lives >1){ maps_init(); init_main_map(); init_boss_map(); init_finalboss_map(); set_active_map(0); Player.x = Player.y = 5; Player.isOmniEnabled = false; Player.questStatus = 0; Player.currBoss = NULL; Player.has_key = false; Player.health = 99; Player.lives--; } } /** * 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() { // First things first: initialize hardware ASSERT_P(hardware_init() == ERROR_NONE, "Hardware init failed!"); // uLCD.filled_rectangle(64, 64, 74, 74, RED); //DELETE OR COMMENT THIS LINE /********************************************* START SCREEN *********************************************/ uLCD.background_color(0x008080); uLCD.textbackground_color(0x315e26); uLCD.color(0xFFFFFF); uLCD.cls(); uLCD.background_color(0x000000); uLCD.textbackground_color(0x000000); uLCD.locate(2, 11); uLCD.printf("Rony Stephan"); uLCD.locate(2, 13); uLCD.printf("Press START"); // uLCD.locate(2, 14); //// uLCD.text_bold(1); uLCD.text_width(2); uLCD.text_height(2); uLCD.locate(1, 1); uLCD.printf("Alien"); uLCD.locate(1, 2); uLCD.printf("Vs."); uLCD.locate(1, 3); uLCD.printf("Duck!"); //uLCD.locate(1, 5); // uLCD.printf("Press"); // uLCD.locate(1, 6); // uLCD.printf("START"); in = read_inputs(); int currAction = get_action(in); do { in = read_inputs(); currAction = get_action(in); } while(currAction != OMNI_BUTTON); uLCD.cls(); // Initialize the maps maps_init(); init_main_map(); init_boss_map(); init_finalboss_map(); // set_active_map(0); // Initialize game state set_active_map(0); Player.x = Player.y = 5; Player.isOmniEnabled = false; Player.questStatus = 0; Player.currBoss = NULL; Player.has_key = false; Player.health = 99; Player.lives = 1; Player.item1 = Player.potion1 = Player.potion2 = 0; firstDraw = true; // Initial drawing draw_game(true); firstDraw = false; // Main game loop int doesGameContinue = 1; while(doesGameContinue) { // Timer to measure game update speed Timer t; t.start(); in = read_inputs(); int currAction = get_action(in); int isgameOver= update_game(currAction); int isPlayerDead = playerHealthCheck(Player.health); if(isgameOver == 1) { doesGameContinue =0; youWinScreen(); break; } if(isPlayerDead == 1) { if(Player.lives == 1) { doesGameContinue = 0; youLoseScreen(); break; } else { decreaseLife(); } } //updateCounter() // Actually do the game update: // 1. Read inputs // 2. Determine action (get_action) // 3. Update game (update_game) // 3b. Check for game over // 4. Draw frame (draw_game) draw_game(currAction); // 5. Frame delay t.stop(); int dt = t.read_ms(); if (dt < 100) wait_ms(100 - dt); } }