/* * move_left * DESCRIPTION: Move the player right one pixel (assumed to be a legal move) * INPUTS: xpos -- pointer to player's x position (pixel) in the maze * OUTPUTS: *xpos -- decreased by one from initial value * RETURN VALUE: none * SIDE EFFECTS: pans display by one pixel when appropriate */ static void move_left (int* xpos) { /* * Move player by one pixel and check whether display should be panned. * Panning is necessary when the player moves past the left pan border * while the leftmost pixels of the maze are not on-screen. */ if (--(*xpos) < game_info.map_x + BLOCK_X_DIM * PAN_BORDER && game_info.map_x > SHOW_MIN) { /* * Shift the logical view to the left by one pixel and draw the * new line. */ set_view_window (--game_info.map_x, game_info.map_y); (void)draw_vert_line (0); } }
/* * move_up * DESCRIPTION: Move the player up one pixel (assumed to be a legal move) * INPUTS: ypos -- pointer to player's y position (pixel) in the maze * OUTPUTS: *ypos -- reduced by one from initial value * RETURN VALUE: none * SIDE EFFECTS: pans display by one pixel when appropriate */ static void move_up (int* ypos) { /* * Move player by one pixel and check whether display should be panned. * Panning is necessary when the player moves past the upper pan border * while the top pixels of the maze are not on-screen. */ if (--(*ypos) < game_info.map_y + BLOCK_Y_DIM * PAN_BORDER && game_info.map_y > SHOW_MIN) { /* * Shift the logical view upwards by one pixel and draw the * new line. */ set_view_window (game_info.map_x, --game_info.map_y); (void)draw_horiz_line (0); } }
/* * move_photo_right * DESCRIPTION: Move background photo right one or more pixels. Amount of * motion depends on game_info.x_speed. Movement stops at * left edge of photo. * INPUTS: none * OUTPUTS: none * RETURN VALUE: none * SIDE EFFECTS: shifts view window */ static void move_photo_right () { int32_t delta; /* Number of pixels by which to move. */ int32_t idx; /* Index over columns to redraw. */ /* Calculate the number of pixels by which to move. */ delta = (game_info.x_speed > game_info.map_x ? game_info.map_x : game_info.x_speed); /* Shift the logical view to the left. */ game_info.map_x -= delta; set_view_window (game_info.map_x, game_info.map_y); /* Draw the newly exposed lines. */ for (idx = 0; delta > idx; idx++) { (void)draw_vert_line (idx); } }
/* * move_photo_down * DESCRIPTION: Move background photo down one or more pixels. Amount of * motion depends on game_info.y_speed. Movement stops at * upper edge of photo. * INPUTS: none * OUTPUTS: none * RETURN VALUE: none * SIDE EFFECTS: shifts view window */ static void move_photo_down () { int32_t delta; /* Number of pixels by which to move. */ int32_t idx; /* Index over rows to redraw. */ /* Calculate the number of pixels by which to move. */ delta = (game_info.y_speed > game_info.map_y ? game_info.map_y : game_info.y_speed); /* Shift the logical view upward. */ game_info.map_y -= delta; set_view_window (game_info.map_x, game_info.map_y); /* Draw the newly exposed lines. */ for (idx = 0; delta > idx; idx++) { (void)draw_horiz_line (idx); } }
/* * prepare_maze_level * DESCRIPTION: Prepare for a maze of a given level. Fills the game_info * structure, creates a maze, and initializes the display. * INPUTS: level -- level to be used for selecting parameter values * OUTPUTS: none * RETURN VALUE: 0 on success, -1 on failure * SIDE EFFECTS: writes entire game_info structure; changes maze; * initializes display */ static int prepare_maze_level (int level) { int i; /* loop index for drawing display */ /* * Record level in game_info; other calculations use offset from * level 1. */ game_info.number = level--; /* Set per-level parameter values. */ if ((game_info.maze_x_dim = MAZE_MIN_X_DIM + 2 * level) > MAZE_MAX_X_DIM) game_info.maze_x_dim = MAZE_MAX_X_DIM; if ((game_info.maze_y_dim = MAZE_MIN_Y_DIM + 2 * level) > MAZE_MAX_Y_DIM) game_info.maze_y_dim = MAZE_MAX_Y_DIM; if ((game_info.initial_fruit_count = 1 + level / 2) > 6) game_info.initial_fruit_count = 6; if ((game_info.time_to_first_fruit = 300 - 30 * level) < 120) game_info.time_to_first_fruit = 120; if ((game_info.time_between_fruits = 300 - 60 * level) < 60) game_info.time_between_fruits = 60; if ((game_info.tick_usec = 20000 - 1750 * level) < 5000) game_info.tick_usec = 5000; /* Initialize dynamic values. */ game_info.map_x = game_info.map_y = SHOW_MIN; /* Create a maze. */ if (make_maze (game_info.maze_x_dim, game_info.maze_y_dim, game_info.initial_fruit_count) != 0) return -1; /* Set logical view and draw initial screen. */ set_view_window (game_info.map_x, game_info.map_y); for (i = 0; i < SCROLL_Y_DIM; i++) (void)draw_horiz_line (i); /* Return success. */ return 0; }
/* * move_photo_up * DESCRIPTION: Move background photo up one or more pixels. Amount of * motion depends on game_info.y_speed. Movement stops at * lower edge of photo. * INPUTS: none * OUTPUTS: none * RETURN VALUE: none * SIDE EFFECTS: shifts view window */ static void move_photo_up () { int32_t delta; /* Number of pixels by which to move. */ int32_t idx; /* Index over rows to redraw. */ /* Calculate the number of pixels by which to move. */ delta = room_photo_height (game_info.where) - SCROLL_Y_DIM - game_info.map_y; delta = (game_info.y_speed > delta ? delta : game_info.y_speed); /* Shift the logical view upward. */ game_info.map_y += delta; set_view_window (game_info.map_x, game_info.map_y); /* Draw the newly exposed lines. */ for (idx = 1; delta >= idx; idx++) { (void)draw_horiz_line (SCROLL_Y_DIM - idx); } }
/* * move_photo_left * DESCRIPTION: Move background photo left one or more pixels. Amount of * motion depends on game_info.x_speed. Movement stops at * right edge of photo. * INPUTS: none * OUTPUTS: none * RETURN VALUE: none * SIDE EFFECTS: shifts view window */ static void move_photo_left () { int32_t delta; /* Number of pixels by which to move. */ int32_t idx; /* Index over columns to redraw. */ /* Calculate the number of pixels by which to move. */ delta = room_photo_width (game_info.where) - SCROLL_X_DIM - game_info.map_x; delta = (game_info.x_speed > delta ? delta : game_info.x_speed); /* Shift the logical view to the right. */ game_info.map_x += delta; set_view_window (game_info.map_x, game_info.map_y); /* Draw the newly exposed lines. */ for (idx = 1; delta >= idx; idx++) { (void)draw_vert_line (SCROLL_X_DIM - idx); } }
/* * move_down * DESCRIPTION: Move the player right one pixel (assumed to be a legal move) * INPUTS: ypos -- pointer to player's y position (pixel) in the maze * OUTPUTS: *ypos -- increased by one from initial value * RETURN VALUE: none * SIDE EFFECTS: pans display by one pixel when appropriate */ static void move_down (int* ypos) { /* * Move player by one pixel and check whether display should be panned. * Panning is necessary when the player moves past the right pan border * while the bottom pixels of the maze are not on-screen. */ if (++(*ypos) > game_info.map_y + SCROLL_Y_DIM - BLOCK_Y_DIM * (PAN_BORDER + 1) && game_info.map_y + SCROLL_Y_DIM < (2 * game_info.maze_y_dim + 1) * BLOCK_Y_DIM - SHOW_MIN) { /* * Shift the logical view downwards by one pixel and draw the * new line. */ set_view_window (game_info.map_x, ++game_info.map_y); (void)draw_horiz_line (SCROLL_Y_DIM - 1); } }
/* * move_right * DESCRIPTION: Move the player right one pixel (assumed to be a legal move) * INPUTS: xpos -- pointer to player's x position (pixel) in the maze * OUTPUTS: *xpos -- increased by one from initial value * RETURN VALUE: none * SIDE EFFECTS: pans display by one pixel when appropriate */ static void move_right (int* xpos) { /* * Move player by one pixel and check whether display should be panned. * Panning is necessary when the player moves past the right pan border * while the rightmost pixels of the maze are not on-screen. */ if (++(*xpos) > game_info.map_x + SCROLL_X_DIM - BLOCK_X_DIM * (PAN_BORDER + 1) && game_info.map_x + SCROLL_X_DIM < (2 * game_info.maze_x_dim + 1) * BLOCK_X_DIM - SHOW_MIN) { /* * Shift the logical view to the right by one pixel and draw the * new line. */ set_view_window (++game_info.map_x, game_info.map_y); (void)draw_vert_line (SCROLL_X_DIM - 1); } }
/* * game_loop * DESCRIPTION: Main event loop for the adventure game. * INPUTS: none * OUTPUTS: none * RETURN VALUE: GAME_QUIT if the player quits, or GAME_WON if they have won * SIDE EFFECTS: drives the display, etc. */ static game_condition_t game_loop () { /* * Variables used to carry information between event loop ticks; see * initialization below for explanations of purpose. */ struct timeval start_time, tick_time; struct timeval cur_time; /* current time (during tick) */ cmd_t cmd; /* command issued by input control */ int32_t enter_room; /* player has changed rooms */ /* Record the starting time--assume success. */ (void)gettimeofday (&start_time, NULL); /* Calculate the time at which the first event loop tick should occur. */ tick_time = start_time; if ((tick_time.tv_usec += TICK_USEC) > 1000000) { tick_time.tv_sec++; tick_time.tv_usec -= 1000000; } /* The player has just entered the first room. */ enter_room = 1; /* The main event loop. */ while (1) { /* * Update the screen, preparing the VGA palette and photo-drawing * routines and drawing a new room photo first if the player has * entered a new room, then showing the screen (and status bar, * once you have it working). */ if (enter_room) { /* Reset the view window to (0,0). */ game_info.map_x = game_info.map_y = 0; set_view_window (game_info.map_x, game_info.map_y); /* Discard any partially-typed command. */ reset_typed_command (); /* Adjust colors and photo drawing for the current room photo. */ prep_room (game_info.where); /* Draw the room (calls show. */ redraw_room (); /* Only draw once on entry. */ enter_room = 0; } show_screen (); //lock status_msg to prevent changes (void)pthread_mutex_lock (&msg_lock); room_t* curr_room = game_info.where; // This is the current room pointer // Now call fill_status_bar with all the possible strings as params fill_status_bar(room_name(curr_room), get_typed_command(), status_msg); (void)pthread_mutex_unlock (&msg_lock); //unlock // Calculate game time display_time_on_tux (cur_time.tv_sec - start_time.tv_sec); /* * Wait for tick. The tick defines the basic timing of our * event loop, and is the minimum amount of time between events. */ do { if (gettimeofday (&cur_time, NULL) != 0) { /* Panic! (should never happen) */ clear_mode_X (); shutdown_input (); perror ("gettimeofday"); exit (3); } } while (!time_is_after (&cur_time, &tick_time)); /* * Advance the tick time. If we missed one or more ticks completely, * i.e., if the current time is already after the time for the next * tick, just skip the extra ticks and advance the clock to the one * that we haven't missed. */ do { if ((tick_time.tv_usec += TICK_USEC) > 1000000) { tick_time.tv_sec++; tick_time.tv_usec -= 1000000; } } while (time_is_after (&cur_time, &tick_time)); /* * Handle asynchronous events. These events use real time rather * than tick counts for timing, although the real time is rounded * off to the nearest tick by definition. */ /* (none right now...) */ /* * Handle synchronous events--in this case, only player commands. * Note that typed commands that move objects may cause the room * to be redrawn. */ cmd = get_command (); switch (cmd) { case CMD_UP: move_photo_down (); break; case CMD_RIGHT: move_photo_left (); break; case CMD_DOWN: move_photo_up (); break; case CMD_LEFT: move_photo_right (); break; case CMD_MOVE_LEFT: enter_room = (TC_CHANGE_ROOM == try_to_move_left (&game_info.where)); break; case CMD_ENTER: enter_room = (TC_CHANGE_ROOM == try_to_enter (&game_info.where)); break; case CMD_MOVE_RIGHT: enter_room = (TC_CHANGE_ROOM == try_to_move_right (&game_info.where)); break; case CMD_TYPED: if (handle_typing ()) { enter_room = 1; } break; case CMD_QUIT: return GAME_QUIT; default: break; } // Repeat the same thing for the tux cmd = get_tux_command(); switch (cmd) { case CMD_UP: move_photo_down (); break; case CMD_RIGHT: move_photo_left (); break; case CMD_DOWN: move_photo_up (); break; case CMD_LEFT: move_photo_right (); break; case CMD_MOVE_LEFT: enter_room = (TC_CHANGE_ROOM == try_to_move_left (&game_info.where)); break; case CMD_ENTER: enter_room = (TC_CHANGE_ROOM == try_to_enter (&game_info.where)); break; case CMD_MOVE_RIGHT: enter_room = (TC_CHANGE_ROOM == try_to_move_right (&game_info.where)); break; case CMD_QUIT: return GAME_QUIT; default: break; } /* If player wins the game, their room becomes NULL. */ if (NULL == game_info.where) { return GAME_WON; } } /* end of the main event loop */ }