ES_Event RunGameplay(ES_Event ThisEvent) { ES_Event returnVal; returnVal.EventType = ES_NO_EVENT; // Initialize nextState as current state GameplayState_t nextState = currentState; switch (currentState) { case INIT: if (ThisEvent.EventType == ES_INIT) { resetGameplay(); nextState = ARMED; startArmedUX(); } break; case ARMED: if (ThisEvent.EventType == START_BUTTON_UP) { printf("Game Started\r\n"); // start timers ES_Timer_InitTimer(GAME_TIMER, GAME_TIME); ES_Timer_InitTimer(INACTION_TIMER, INACTION_TIME); // send GAME_STARTED event to TimeOfDaySM ES_Event Event2Post; Event2Post.EventType = GAME_STARTED; // ES_PostAll(Event2Post); // post to TimeOfDay PostTimeOfDay(Event2Post); PostEventPrinter(Event2Post); stopArmedUX(); startMixingUX(); nextChemUX(); nextState = MIXING; } break; case MIXING: switch (ThisEvent.EventType) { case CHEM_BUTTON_DOWN: if (QueryStir() == STIRRING && numChems < TOTAL_AMMO * CHEMS_PER_AMMO) { if (thisChem == ThisEvent.EventParam) { numChems++; printf("Correct button press. numChems: %u\r\n", numChems); addChemUX(); if (numChems % CHEMS_PER_AMMO == 0) { numAmmo++; addChemLightUX(); } if (numChems == TOTAL_AMMO * CHEMS_PER_AMMO) { stopMixingUX(); startSprayingUX(); nextState = SHOOTING; printf("Mixing complete"); } else { nextChemUX(); printf("Next chem UX"); } } else { // if pressed the wrong chemical button if (numChems > CHEMS_PER_AMMO) numChems -= CHEMS_PER_AMMO; else numChems = 0; if (numAmmo > 0) numAmmo--; // play the sound for wrong chemical added and decrement a light if necessary wrongChemAddedUX(); } } break; case CHEM_BUTTON_UP: ES_Timer_InitTimer(INACTION_TIMER, INACTION_TIME); break; case ES_TIMEOUT: if (ThisEvent.EventParam == INACTION_TIMER || ThisEvent.EventParam == GAME_TIMER) { // send GAME_ENDED event to TimeOfDaySM ES_Event Event2Post; Event2Post.EventType = GAME_ENDED; // ES_PostAll(Event2Post); // only post to TimeOfDay PostTimeOfDay(Event2Post); PostEventPrinter(Event2Post); stopMixingUX(); startFailUX(); nextState = FAIL; ES_Timer_InitTimer(GAME_STATE_TIMER,FAIL_DISPLAY_TIME); } break; } break; case SHOOTING: switch (ThisEvent.EventType) { ES_Event Event2Post; case FIRE_READY: ES_Timer_InitTimer(INACTION_TIMER, INACTION_TIME); fireReadyUX(); break; case FIRE_ON: ES_Timer_InitTimer(INACTION_TIMER, INACTION_TIME); // UX: Flash indicator light & turn on IR emitter fireOnUX(); break; case FIRE_OFF: ES_Timer_InitTimer(INACTION_TIMER, INACTION_TIME); // UX: Turn off IR emitter & indicator light fireOffUX(); break; case CITY_SAVED: // UX: Turn that city’s LED blue citySavedUX(ThisEvent.EventParam); break; case ALL_CITIES_SAVED: ES_Timer_InitTimer(GAME_STATE_TIMER,WIN_DISPLAY_TIME); // send GAME_ENDED event to TimeOfDaySM Event2Post.EventType = GAME_ENDED; // ES_PostAll(Event2Post); // only post to TimeOfDay PostTimeOfDay(Event2Post); PostEventPrinter(Event2Post); startWinUX(); nextState = WIN; break; case USED_ONE_AMMO: numAmmo--; usedOneAmmoUX(); if (numAmmo>0) { printf("numAmmo: %u\r\n", numAmmo); // FOR DEBUGGING } else { // send GAME_ENDED event to TimeOfDaySM ES_Event Event2Post; Event2Post.EventType = GAME_ENDED; // ES_PostAll(Event2Post); // only post to TimeOfDay PostTimeOfDay(Event2Post); PostEventPrinter(Event2Post); stopSprayingUX(); startFailUX(); nextState = FAIL; ES_Timer_InitTimer(GAME_STATE_TIMER, FAIL_DISPLAY_TIME); } break; case ES_TIMEOUT: if (ThisEvent.EventParam == INACTION_TIMER || ThisEvent.EventParam == GAME_TIMER) { // send GAME_ENDED event to TimeOfDaySM ES_Event Event2Post; Event2Post.EventType = GAME_ENDED; // ES_PostAll(Event2Post); // only post to TimeOfDay PostTimeOfDay(Event2Post); PostEventPrinter(Event2Post); stopSprayingUX(); startFailUX(); nextState = FAIL; ES_Timer_InitTimer(GAME_STATE_TIMER, FAIL_DISPLAY_TIME); } break; } break; case FAIL: if ((ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == GAME_STATE_TIMER) || ThisEvent.EventType == START_BUTTON_UP) { // send GAME_ENDED event to TimeOfDaySM ES_Event Event2Post; Event2Post.EventType = GAME_ENDED; // ES_PostAll(Event2Post); // only post to TimeOfDay PostTimeOfDay(Event2Post); PostEventPrinter(Event2Post); // reset software & hardware resetGameplay(); nextState = ARMED; startArmedUX(); } break; case WIN: if ((ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == GAME_STATE_TIMER) || ThisEvent.EventType == START_BUTTON_UP) { // send GAME_ENDED event to TimeOfDaySM ES_Event Event2Post; Event2Post.EventType = GAME_ENDED; // ES_PostAll(Event2Post); // only post to TimeOfDay PostTimeOfDay(Event2Post); PostEventPrinter(Event2Post); // reset software & hardware & next state is ARMED resetGameplay(); nextState = ARMED; startArmedUX(); } break; } // set currentState to nextState currentState = nextState; return returnVal; }
int main(void) { // seed pseudorandom number generator srand48(time(NULL)); // instantiate window GWindow window = newGWindow(WIDTH, HEIGHT); // instantiate bricks initBricks(window); // instantiate ball, centered in middle of window GOval ball = initBall(window); // instantiate paddle, centered at bottom of window GRect paddle = initPaddle(window); // instantiate scoreboard, centered in middle of window, just above ball GLabel label = initScoreboard(window); // number of lives initially int lives = LIVES; // number of bricks initially int bricks = ROWS * COLS; // number of points initially int points = 0; // default ball direction is down Velocity *velocity = (Velocity *) malloc(sizeof(Velocity)); velocity->horizontalVelocity = 0.0; velocity->verticalVelocity = 2.0; char *paddleDirection = malloc(sizeof(char) * 10); Paddle *bat = (Paddle *) malloc(sizeof(Paddle)); bat->paddle = paddle; bat->direction = paddleDirection; bat->x = getX(paddle); bat->y = getY(paddle); // show the scoreboard updateScoreboard(window, label, points); // keep playing until game over while (lives > 0 && bricks > 0) { checkForEvent(bat); GObject object = detectCollision(window, ball); if (object != NULL) { if (object == bat->paddle) { ballHitsPaddle(bat, velocity, ball); } else if (strcmp(getType(object), "GRect") == 0) { ballHitsBrick(velocity, &window, &object, &label, &points, &bricks); } } else { if (hasBallHitTheSides(&ball, &window)) { invertHorizontalDirection(velocity); } else if (hasBallHitTheTop(&ball, &window)) { invertVerticalDirection(velocity); } else if (hasBallHitTheBottom(&ball, &window)) { resetGameplay(velocity, &ball, bat, &lives); } } move(ball, velocity->horizontalVelocity, velocity->verticalVelocity); pause(10); } showGameOverMessage(window, label); // wait for click before exiting waitForClick(); // game over closeGWindow(window); return 0; }