/* * rtc_thread * DESCRIPTION: Thread that handles updating the screen * INPUTS: none * OUTPUTS: none * RETURN VALUE: none * SIDE EFFECTS: none */ static void *rtc_thread(void *arg) { int ticks = 0; int level; int ret; int open[NUM_DIRS]; int need_redraw = 0; int goto_next_level = 0; char str[40]; int need_fruit=0; /*variables to track the maze's condition*/ int start_time, time, newtime, minute,minute0,minute1,second,second0,second1,fruit,newfruit; unsigned long led_diaplay; /*build buffer for the status bar unsigned char buf[STATUS_BAR_SIZE]={[0 ... (STATUS_BAR_SIZE-1)]=level%5};*/ /*variables used as counter*/ int i, c, fnum; unsigned char old_val[BLOCK_X_DIM*BLOCK_Y_DIM]; unsigned char* player_mask; unsigned char* player_no_mask; unsigned char player_with_mask[BLOCK_X_DIM*BLOCK_Y_DIM]; unsigned char* floor = (unsigned char*)blocks[BLOCK_EMPTY]; char fruit_name[15]; // Loop over levels until a level is lost or quit. for (level = 1; (level <= MAX_LEVEL) && (quit_flag == 0); level++) { change_palette (level); /*record the start time of each level and initialize the time*/ start_time=total; time=0; /*build buffer for the status bar*/ unsigned char buf[STATUS_BAR_SIZE]={[0 ... (STATUS_BAR_SIZE-1)]=level%LEVEL_COLOR_PERIOD}; // Prepare for the level. If we fail, just let the player win. if (prepare_maze_level (level) != 0) break; goto_next_level = 0; // Start the player at (1,1) play_x = BLOCK_X_DIM; play_y = BLOCK_Y_DIM; // move_cnt tracks moves remaining between maze squares. // When not moving, it should be 0. move_cnt = 0; // Initialize last direction moved to up last_dir = DIR_UP; // Initialize the current direction of motion to stopped dir = DIR_STOP; next_dir = DIR_STOP; // Show maze around the player's original position (void)unveil_around_player (play_x, play_y); //This part is used to display the starting screen. //The part at the end is the same as this one.(detailed explanations are here ) //check whether the block has a fruit fnum = check_for_fruit((play_x) / BLOCK_X_DIM, (play_y) / BLOCK_Y_DIM); //if yes, update the block with the one without fruit, else just draw the regular block if (fnum != 0) { switch(fnum){ case APPLE: sprintf(fruit_name,"Apple!"); break; case GRAPE: sprintf(fruit_name,"Grapes!"); break; case PEACH: sprintf(fruit_name,"Peach!"); break; case STRAWBERY: sprintf(fruit_name,"Strawberry!"); break; case BANANA: sprintf(fruit_name,"Banana!"); break; case WATERMELON: sprintf(fruit_name,"Watermelon!"); break; case DEW: sprintf(fruit_name,"Dew!"); break; } need_fruit=TEXT_TIME; for(i = 0 ; i< BLOCK_X_DIM*BLOCK_Y_DIM; i++) old_val[i] = floor[i]; } else { save_floor(play_x,play_y,old_val); } //get the block image data and also the mask data player_mask=get_player_mask(last_dir); player_no_mask=get_player_block(last_dir); //determine whether the part of block should be drawn with the block color or be totally transparent for(c=0;c<BLOCK_X_DIM*BLOCK_Y_DIM;c++){ if (player_mask[c]) if(player_no_mask[c]==32){ player_with_mask[c]=time%PLAYER_COLOR_PERIOD+PLAYER_COLOR_OFFSET; } else player_with_mask[c]=player_no_mask[c]; else player_with_mask[c]=old_val[c]; } //draw the whole block to build buffer and update the screen draw_full_block (play_x, play_y, player_with_mask); show_screen(); if(need_fruit) show_text(play_x, play_y,fruit_name); //after updating the screen, put the floor image back to build buffer restore_floor(play_x,play_y,old_val); /*show status bar*/ // Lock the mutex pthread_mutex_lock(&mtx); fruit=fruit_num(); sprintf(str,"Level %d %d fruits 00:00",level,fruit_num()); // Unlock the mutex pthread_mutex_unlock(&mtx); //transfer the string to image and save in to buf text_to_graph(buf,str,level%LEVEL_COLOR_PERIOD,level%LEVEL_COLOR_PERIOD+LEVEL_COLOR_OFFSET); //draw the buf into video memory for (i = 0; i < 4; i++) { SET_WRITE_MASK (1 << (i + 8)); status_copy(buf + i * STATUS_BAR_ADDR); } // get first Periodic Interrupt ret = read(fd, &data, sizeof(unsigned long)); while ((quit_flag == 0) && (goto_next_level == 0)) { // Wait for Periodic Interrupt ret = read(fd, &data, sizeof(unsigned long)); // Update tick to keep track of time. If we missed some // interrupts we want to update the player multiple times so // that player velocity is smooth ticks = data >> 8; //everytime tick being update, update the status bar. // Lock the mutex pthread_mutex_lock(&mtx); newtime=(total-start_time)/32;//32 is the frequency newfruit=fruit_num(); //check if the status bar need to be updated. if((newtime!=time)||(newfruit!=fruit)){ if(need_fruit>0) need_fruit--; time=newtime; fruit=newfruit; //Calculate time. minute=time/60; second=time%60; //separate the minute and second into four number minute0=minute%10; minute1=minute/10; second0=second%10; second1=second/10; //only the decimal in middle need to be set so the lower 4 bits of the highest byte is 4. //the F in the lower 4 bits in the second byte means all of the led should be on. led_diaplay=0x040F0000; //add the number should be displayed by each LED to the led_display. led_diaplay=led_diaplay+second0+(second1<<SHIFT_SEC1)+(minute0<<SHIFT_MIN0)+(minute1<<SHIFT_MIN1); ioctl(tux_fd, TUX_SET_LED,led_diaplay); sprintf(str,"Level %d %d fruits %02d:%02d",level,fruit,minute,second); text_to_graph(buf,str,level%LEVEL_COLOR_PERIOD,level%LEVEL_COLOR_PERIOD+LEVEL_COLOR_OFFSET); for (i = 0; i < 4; i++) { SET_WRITE_MASK (1 << (i + 8)); status_copy(buf + i * STATUS_BAR_ADDR); } } // Unlock the mutex pthread_mutex_unlock(&mtx); total += ticks; // If the system is completely overwhelmed we better slow down: if (ticks > 8) ticks = 8; if (ticks > 1) { badcount++; } else { goodcount++; } while (ticks--) { // Lock the mutex pthread_mutex_lock(&mtx); // Check to see if a key has been pressed if (next_dir != dir) { // Check if new direction is backwards...if so, do immediately if ((dir == DIR_UP && next_dir == DIR_DOWN) || (dir == DIR_DOWN && next_dir == DIR_UP) || (dir == DIR_LEFT && next_dir == DIR_RIGHT) || (dir == DIR_RIGHT && next_dir == DIR_LEFT)) { if (move_cnt > 0) { if (dir == DIR_UP || dir == DIR_DOWN) move_cnt = BLOCK_Y_DIM - move_cnt; else move_cnt = BLOCK_X_DIM - move_cnt; } dir = next_dir; } } // New Maze Square! if (move_cnt == 0) { // The player has reached a new maze square; unveil nearby maze // squares and check whether the player has won the level. if (unveil_around_player (play_x, play_y)) { pthread_mutex_unlock(&mtx); goto_next_level = 1; break; } // Record directions open to motion. find_open_directions (play_x / BLOCK_X_DIM, play_y / BLOCK_Y_DIM, open); // Change dir to next_dir if next_dir is open if (open[next_dir]) { dir = next_dir; } // The direction may not be open to motion... // 1) ran into a wall // 2) initial direction and its opposite both face walls if (dir != DIR_STOP) { if (!open[dir]) { dir = DIR_STOP; } else if (dir == DIR_UP || dir == DIR_DOWN) { move_cnt = BLOCK_Y_DIM; } else { move_cnt = BLOCK_X_DIM; } } } // Unlock the mutex pthread_mutex_unlock(&mtx); if (dir != DIR_STOP) { // move in chosen direction last_dir = dir; move_cnt--; switch (dir) { case DIR_UP: move_up (&play_y); break; case DIR_RIGHT: move_right (&play_x); break; case DIR_DOWN: move_down (&play_y); break; case DIR_LEFT: move_left (&play_x); break; } //The same logic as the one at the beginning. //This part is used during the game to update the screen. fnum = check_for_fruit((play_x) / BLOCK_X_DIM, (play_y) / BLOCK_Y_DIM); if (fnum != 0) { switch(fnum){ case APPLE: sprintf(fruit_name,"Apple!"); break; case GRAPE: sprintf(fruit_name,"Grapes!"); break; case PEACH: sprintf(fruit_name,"Peach!"); break; case STRAWBERY: sprintf(fruit_name,"Strawberry!"); break; case BANANA: sprintf(fruit_name,"Banana!"); break; case WATERMELON: sprintf(fruit_name,"Watermelon!"); break; case DEW: sprintf(fruit_name,"Dew!"); break; } need_fruit=TEXT_TIME; for(i = 0 ; i< BLOCK_X_DIM*BLOCK_Y_DIM; i++) old_val[i] = floor[i]; } else { save_floor(play_x,play_y,old_val); } player_mask=get_player_mask(last_dir); player_no_mask=get_player_block(last_dir); for(c=0;c<BLOCK_X_DIM*BLOCK_Y_DIM;c++){ if (player_mask[c]) if(player_no_mask[c]==32){ player_with_mask[c]=time%PLAYER_COLOR_PERIOD+PLAYER_COLOR_OFFSET; } else player_with_mask[c]=player_no_mask[c]; else player_with_mask[c]=old_val[c]; } need_redraw = 1; } draw_full_block (play_x, play_y, player_with_mask); show_screen(); if(need_fruit) show_text(play_x, play_y,fruit_name); restore_floor(play_x,play_y,old_val); } need_redraw = 0; } } if (quit_flag == 0) winner = 1; return 0; }
/*! * @brief 現在フロアの書き込み / * Write the current dungeon (new method) * @return なし */ static bool wr_dungeon(void) { saved_floor_type *cur_sf_ptr; int i; /* Forget the lite */ forget_lite(); /* Forget the view */ forget_view(); /* Forget the view */ clear_mon_lite(); /* Update lite/view */ p_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE); /* Update monsters */ p_ptr->update |= (PU_MONSTERS | PU_DISTANCE | PU_FLOW); /*** Meta info ***/ /* Number of floor_id used from birth */ wr_s16b(max_floor_id); /* Current dungeon type */ wr_byte(dungeon_type); /*** No saved floor (On the surface etc.) ***/ if (!p_ptr->floor_id) { /* No array elements */ wr_byte(0); /* Write the current floor data */ wr_saved_floor(NULL); /* Success */ return TRUE; } /*** In the dungeon ***/ /* Number of array elements */ wr_byte(MAX_SAVED_FLOORS); /* Write the saved_floors array */ for (i = 0; i < MAX_SAVED_FLOORS; i++) { saved_floor_type *sf_ptr = &saved_floors[i]; wr_s16b(sf_ptr->floor_id); wr_byte(sf_ptr->savefile_id); wr_s16b(sf_ptr->dun_level); wr_s32b(sf_ptr->last_visit); wr_u32b(sf_ptr->visit_mark); wr_s16b(sf_ptr->upper_floor_id); wr_s16b(sf_ptr->lower_floor_id); } /* Extract pointer to current floor */ cur_sf_ptr = get_sf_ptr(p_ptr->floor_id); /* Save current floor to temporal file */ if (!save_floor(cur_sf_ptr, (SLF_SECOND))) return FALSE; /* Move data in temporal files to the savefile */ for (i = 0; i < MAX_SAVED_FLOORS; i++) { saved_floor_type *sf_ptr = &saved_floors[i]; /* Unused element */ if (!sf_ptr->floor_id) continue; /* Load temporal saved floor file */ if (load_floor(sf_ptr, (SLF_SECOND | SLF_NO_KILL))) { /* Mark success */ wr_byte(0); /* Write saved floor data to the save file */ wr_saved_floor(sf_ptr); } else { /* Mark failure */ wr_byte(1); } } /* Restore current floor */ if (!load_floor(cur_sf_ptr, (SLF_SECOND))) return FALSE; /* Success */ return TRUE; }
/*! * @brief 現在のフロアを離れるに伴って行なわれる保存処理 * / Maintain quest monsters, mark next floor_id at stairs, save current floor, and prepare to enter next floor. * @return なし */ void leave_floor(void) { cave_type *c_ptr = NULL; feature_type *f_ptr; saved_floor_type *sf_ptr; int quest_r_idx = 0; DUNGEON_IDX i; /* Preserve pets and prepare to take these to next floor */ preserve_pet(); /* Remove all mirrors without explosion */ remove_all_mirrors(FALSE); if (p_ptr->special_defense & NINJA_S_STEALTH) set_superstealth(FALSE); /* New floor is not yet prepared */ new_floor_id = 0; /* Temporary get a floor_id (for Arena) */ if (!p_ptr->floor_id && (change_floor_mode & CFM_SAVE_FLOORS) && !(change_floor_mode & CFM_NO_RETURN)) { /* Get temporal floor_id */ p_ptr->floor_id = get_new_floor_id(); } /* Search the quest monster index */ for (i = 0; i < max_q_idx; i++) { if ((quest[i].status == QUEST_STATUS_TAKEN) && ((quest[i].type == QUEST_TYPE_KILL_LEVEL) || (quest[i].type == QUEST_TYPE_RANDOM)) && (quest[i].level == dun_level) && (dungeon_type == quest[i].dungeon) && !(quest[i].flags & QUEST_FLAG_PRESET)) { quest_r_idx = quest[i].r_idx; } } /* Maintain quest monsters */ for (i = 1; i < m_max; i++) { monster_race *r_ptr; monster_type *m_ptr = &m_list[i]; /* Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Only maintain quest monsters */ if (quest_r_idx != m_ptr->r_idx) continue; /* Extract real monster race */ r_ptr = real_r_ptr(m_ptr); /* Ignore unique monsters */ if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NAZGUL)) continue; /* Delete non-unique quest monsters */ delete_monster_idx(i); } /* Check if there is a same item */ for (i = 0; i < INVEN_PACK; i++) { object_type *o_ptr = &inventory[i]; /* Skip dead objects */ if (!o_ptr->k_idx) continue; /* Delete old memorized location of the artifact */ if (object_is_fixed_artifact(o_ptr)) { a_info[o_ptr->name1].floor_id = 0; } } /* Extract current floor info or NULL */ sf_ptr = get_sf_ptr(p_ptr->floor_id); /* Choose random stairs */ if ((change_floor_mode & CFM_RAND_CONNECT) && p_ptr->floor_id) { locate_connected_stairs(sf_ptr); } /* Extract new dungeon level */ if (change_floor_mode & CFM_SAVE_FLOORS) { /* Extract stair position */ c_ptr = &cave[p_ptr->y][p_ptr->x]; f_ptr = &f_info[c_ptr->feat]; /* Get back to old saved floor? */ if (c_ptr->special && !have_flag(f_ptr->flags, FF_SPECIAL) && get_sf_ptr(c_ptr->special)) { /* Saved floor is exist. Use it. */ new_floor_id = c_ptr->special; } /* Mark shaft up/down */ if (have_flag(f_ptr->flags, FF_STAIRS) && have_flag(f_ptr->flags, FF_SHAFT)) { prepare_change_floor_mode(CFM_SHAFT); } } /* Climb up/down some sort of stairs */ if (change_floor_mode & (CFM_DOWN | CFM_UP)) { int move_num = 0; /* Extract level movement number */ if (change_floor_mode & CFM_DOWN) move_num = 1; else if (change_floor_mode & CFM_UP) move_num = -1; /* Shafts are deeper than normal stairs */ if (change_floor_mode & CFM_SHAFT) move_num += SGN(move_num); /* Get out from or Enter the dungeon */ if (change_floor_mode & CFM_DOWN) { if (!dun_level) move_num = d_info[dungeon_type].mindepth; } else if (change_floor_mode & CFM_UP) { if (dun_level + move_num < d_info[dungeon_type].mindepth) move_num = -dun_level; } dun_level += move_num; } /* Leaving the dungeon to town */ if (!dun_level && dungeon_type) { p_ptr->leaving_dungeon = TRUE; if (!vanilla_town && !lite_town) { p_ptr->wilderness_y = d_info[dungeon_type].dy; p_ptr->wilderness_x = d_info[dungeon_type].dx; } p_ptr->recall_dungeon = dungeon_type; dungeon_type = 0; /* Reach to the surface -- Clear all saved floors */ change_floor_mode &= ~CFM_SAVE_FLOORS; } /* Kill some old saved floors */ if (!(change_floor_mode & CFM_SAVE_FLOORS)) { /* Kill all saved floors */ for (i = 0; i < MAX_SAVED_FLOORS; i++) kill_saved_floor(&saved_floors[i]); /* Reset visit_mark count */ latest_visit_mark = 1; } else if (change_floor_mode & CFM_NO_RETURN) { /* Kill current floor */ kill_saved_floor(sf_ptr); } /* No current floor -- Left/Enter dungeon etc... */ if (!p_ptr->floor_id) { /* No longer need to save current floor */ return; } /* Mark next floor_id on the previous floor */ if (!new_floor_id) { /* Get new id */ new_floor_id = get_new_floor_id(); /* Connect from here */ if (c_ptr && !feat_uses_special(c_ptr->feat)) { c_ptr->special = new_floor_id; } } /* Fix connection -- level teleportation or trap door */ if (change_floor_mode & CFM_RAND_CONNECT) { if (change_floor_mode & CFM_UP) sf_ptr->upper_floor_id = new_floor_id; else if (change_floor_mode & CFM_DOWN) sf_ptr->lower_floor_id = new_floor_id; } /* If you can return, you need to save previous floor */ if ((change_floor_mode & CFM_SAVE_FLOORS) && !(change_floor_mode & CFM_NO_RETURN)) { /* Get out of the my way! */ get_out_monster(); /* Record the last visit turn of current floor */ sf_ptr->last_visit = turn; /* Forget the lite */ forget_lite(); /* Forget the view */ forget_view(); /* Forget the view */ clear_mon_lite(); /* Save current floor */ if (!save_floor(sf_ptr, 0)) { /* Save failed -- No return */ prepare_change_floor_mode(CFM_NO_RETURN); /* Kill current floor */ kill_saved_floor(get_sf_ptr(p_ptr->floor_id)); } } }