int main(void) { asteroids.lives = START_LIVES; asteroids.display = NULL; asteroids.timer = NULL; asteroids.event_queue = NULL; SHIP *ship; bool redraw = true; bool quit = false; bool key[7] = { false }; seed_rand(); atexit(shutdown); if(!init()) exit(EXIT_FAILURE); if((asteroids.high_score = get_config_value("high_score")) == NULL) asteroids.high_score = "0"; asteroids.level = level_create(0, 0); if(!(ship = ship_create())) exit(EXIT_FAILURE); al_flip_display(); al_start_timer(asteroids.timer); while(!quit) { ALLEGRO_EVENT ev; al_wait_for_event(asteroids.event_queue, &ev); if(ev.type == ALLEGRO_EVENT_TIMER) { /* start game */ if(asteroids.level->number == 0 && key[KEY_S]) { start(); continue; } /* are we out of asteroids to destroy? */ if(list_length(asteroids.level->asteroids) == 0) asteroids.level = level_next(asteroids.level); /* update objects */ ship = ship_update(ship, key, asteroids.timer); explosions_update(); asteroids.level = level_update(asteroids.level, ship, key, asteroids.timer); /* ship->asteroid collisions. */ check_ship_asteroid_collisions(ship, asteroids.level->asteroids); /* ship[missile] -> asteroid collisions. */ check_ship_missile_asteroid_collisions(asteroids.level, ship); /* ship[missile] -> saucer collisions. */ check_ship_missile_saucer_collisions(asteroids.level, ship); /* saucer[missile] -> ship collisions. */ check_saucer_missile_ship_collisions(asteroids.level, ship); /* saucer[missile] -> asteroid collisions. */ check_saucer_missile_asteroids_collisions(asteroids.level); /* saucer->asteroid collisions. */ check_saucer_asteroid_collisions(asteroids.level); redraw = true; } else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) { keydown(ev, key); quit = key[KEY_ESCAPE]; } else if(ev.type == ALLEGRO_EVENT_KEY_UP) { keyup(ev, key); ship->fire_debounce = key[KEY_SPACE]; ship->hyper_debounce = key[KEY_LCONTROL]; } if(redraw && al_is_event_queue_empty(asteroids.event_queue)) { redraw = false; al_clear_to_color(al_map_rgb(BLACK)); level_draw(asteroids.level); draw_lives(); draw_high_score(); animation_draw_list(asteroids.explosions); if(asteroids.level->number == 0) { draw_home(); al_flip_display(); continue; } if(asteroids.lives > 0) { ship_draw(ship, key[KEY_UP]); missile_draw_list(ship->missiles); } else { if(ship->explosion) ship_draw(ship, false); draw_gameover(); } al_flip_display(); } }; /* FIXME: cleanup */ if(asteroids.timer != NULL) al_destroy_timer(asteroids.timer); if(asteroids.event_queue != NULL) al_destroy_event_queue(asteroids.event_queue); if(asteroids.display != NULL) al_destroy_display(asteroids.display); LIST *head = list_first(asteroids.level->asteroids); while(head != NULL) { ASTEROID *rock = (ASTEROID *) head->data; asteroid_free(rock); head = head->next; } ship_free(ship); al_destroy_bitmap(asteroids.lives_sprite); ship_shutdown(); missile_shutdown(); asteroid_shutdown(); explosion_shutdown(); al_uninstall_keyboard(); exit(EXIT_SUCCESS); }
static void play_game(struct thread_data *data) { int status; input_t input; int did_user_quit = 0; /* 0 if game-over, otherwise if user quits */ while (1) { /* take user input */ input = fetch_user_input(); if (input == INPUT_INVALID) continue; pthread_mutex_lock(&data->lock); /* check if the game is still going on */ if (data->game_over) { pthread_mutex_unlock(&data->lock); break; } /* in case there's no "current block", don't do anything */ if (input != INPUT_PAUSE_QUIT && (data->block_dropped_ignore_input || !data->current)) { pthread_mutex_unlock(&data->lock); continue; } /* take appropriate action based on user input */ switch (input) { case INPUT_MOVE_LEFT: status = move_block(data->current, ACTION_MOVE_LEFT); if (status == SUCCESS) draw_game_board(data->current); break; case INPUT_MOVE_RIGHT: status = move_block(data->current, ACTION_MOVE_RIGHT); if (status == SUCCESS) draw_game_board(data->current); break; case INPUT_MOVE_DOWN: status = move_block(data->current, ACTION_MOVE_DOWN); if (status == SUCCESS) draw_game_board(data->current); break; case INPUT_MOVE_UP_DROP: status = move_block(data->current, ACTION_MOVE_UP_DROP); if (status == SUCCESS) { data->block_dropped_ignore_input = 1; draw_game_board(data->current); } break; case INPUT_ROTATE_LEFT: status = move_block(data->current, ACTION_ROTATE_LEFT); if (status == SUCCESS) draw_game_board(data->current); break; case INPUT_ROTATE_RIGHT: status = move_block(data->current, ACTION_ROTATE_RIGHT); if (status == SUCCESS) draw_game_board(data->current); break; case INPUT_PAUSE_QUIT: status = display_quit_dialog(); draw_game_board(data->current); if (status == FAILURE) { /* if the user chooses to quit */ data->game_over = 1; did_user_quit = 1; } break; case INPUT_TIMEOUT: /* nothing to do */ break; default: break; } pthread_mutex_unlock(&data->lock); } draw_gameover(did_user_quit); }