/*! * @brief ゲームプレイ中のフロア一時保存出力処理サブルーチン / Actually write a temporal saved floor file * @param sf_ptr 保存フロア参照ポインタ * @return なし */ static bool save_floor_aux(saved_floor_type *sf_ptr) { byte tmp8u; /* Compact the objects */ compact_objects(0); /* Compact the monsters */ compact_monsters(0); /*** Actually write the file ***/ /* Initial value of xor_byte */ tmp8u = (byte)randint0(256); xor_byte = 0; wr_byte(tmp8u); /* Reset the checksum */ v_stamp = 0L; x_stamp = 0L; /* Write the sign of this process */ wr_u32b(saved_floor_file_sign); /* Dump the dungeon floor */ wr_saved_floor(sf_ptr); /* Write the "value check-sum" */ wr_u32b(v_stamp); /* Write the "encoded checksum" */ wr_u32b(x_stamp); /* Error in save */ if (ferror(fff) || (fflush(fff) == EOF)) return FALSE; /* Successful save */ return TRUE; }
/* * Write the current dungeon */ void wr_dungeon(void) { int y, x; byte tmp8u; byte count; byte prev_char; if (p_ptr->is_dead) return; /*** Basic info ***/ /* Dungeon specific info follows */ wr_u16b(p_ptr->depth); wr_u16b(daycount); wr_u16b(p_ptr->py); wr_u16b(p_ptr->px); wr_u16b(cave->height); wr_u16b(cave->width); wr_u16b(0); wr_u16b(0); /*** Simple "Run-Length-Encoding" of cave ***/ /* Note that this will induce two wasted bytes */ count = 0; prev_char = 0; /* Dump the cave */ for (y = 0; y < DUNGEON_HGT; y++) { for (x = 0; x < DUNGEON_WID; x++) { /* Extract the important cave->info flags */ tmp8u = (cave->info[y][x] & (IMPORTANT_FLAGS)); /* If the run is broken, or too full, flush it */ if ((tmp8u != prev_char) || (count == MAX_UCHAR)) { wr_byte((byte)count); wr_byte((byte)prev_char); prev_char = tmp8u; count = 1; } /* Continue the run */ else { count++; } } } /* Flush the data (if any) */ if (count) { wr_byte((byte)count); wr_byte((byte)prev_char); } /** Now dump the cave->info2[][] stuff **/ /* Note that this will induce two wasted bytes */ count = 0; prev_char = 0; /* Dump the cave */ for (y = 0; y < DUNGEON_HGT; y++) { for (x = 0; x < DUNGEON_WID; x++) { /* Keep all the information from info2 */ tmp8u = cave->info2[y][x]; /* If the run is broken, or too full, flush it */ if ((tmp8u != prev_char) || (count == MAX_UCHAR)) { wr_byte((byte)count); wr_byte((byte)prev_char); prev_char = tmp8u; count = 1; } /* Continue the run */ else { count++; } } } /* Flush the data (if any) */ if (count) { wr_byte((byte)count); wr_byte((byte)prev_char); } /*** Simple "Run-Length-Encoding" of cave ***/ /* Note that this will induce two wasted bytes */ count = 0; prev_char = 0; /* Dump the cave */ for (y = 0; y < DUNGEON_HGT; y++) { for (x = 0; x < DUNGEON_WID; x++) { /* Extract a byte */ tmp8u = cave->feat[y][x]; /* If the run is broken, or too full, flush it */ if ((tmp8u != prev_char) || (count == MAX_UCHAR)) { wr_byte((byte)count); wr_byte((byte)prev_char); prev_char = tmp8u; count = 1; } /* Continue the run */ else { count++; } } } /* Flush the data (if any) */ if (count) { wr_byte((byte)count); wr_byte((byte)prev_char); } /*** Compact ***/ /* Compact the objects */ compact_objects(0); /* Compact the monsters */ compact_monsters(0); }
/** * Handle things that need updating once every 10 game turns */ void process_world(struct chunk *c) { int i, y, x; /* Compact the monster list if we're approaching the limit */ if (cave_monster_count(cave) + 32 > z_info->level_monster_max) compact_monsters(64); /* Too many holes in the monster list - compress */ if (cave_monster_count(cave) + 32 < cave_monster_max(cave)) compact_monsters(0); /*** Check the Time ***/ /* Play an ambient sound at regular intervals. */ if (!(turn % ((10L * z_info->day_length) / 4))) play_ambient_sound(); /*** Handle stores and sunshine ***/ if (!player->depth) { /* Daybreak/Nighfall in town */ if (!(turn % ((10L * z_info->day_length) / 2))) { bool dawn; /* Check for dawn */ dawn = (!(turn % (10L * z_info->day_length))); /* Day breaks */ if (dawn) msg("The sun has risen."); /* Night falls */ else msg("The sun has fallen."); /* Illuminate */ cave_illuminate(c, dawn); } } else { /* Update the stores once a day (while in the dungeon). The changes are not actually made until return to town, to avoid giving details away in the knowledge menu. */ if (!(turn % (10L * z_info->store_turns))) daycount++; } /* Check for creature generation */ if (one_in_(z_info->alloc_monster_chance)) (void)pick_and_place_distant_monster(cave, player, z_info->max_sight + 5, true, player->depth); /*** Damage over Time ***/ /* Take damage from poison */ if (player->timed[TMD_POISONED]) take_hit(player, 1, "poison"); /* Take damage from cuts */ if (player->timed[TMD_CUT]) { /* Mortal wound or Deep Gash */ if (player->timed[TMD_CUT] > TMD_CUT_SEVERE) i = 3; /* Severe cut */ else if (player->timed[TMD_CUT] > TMD_CUT_NASTY) i = 2; /* Other cuts */ else i = 1; /* Take damage */ take_hit(player, i, "a fatal wound"); } /*** Check the Food, and Regenerate ***/ /* Digest normally */ if (!(turn % 100)) { /* Basic digestion rate based on speed */ i = turn_energy(player->state.speed) * 2; /* Regeneration takes more food */ if (player_of_has(player, OF_REGEN)) i += 30; /* Slow digestion takes less food */ if (player_of_has(player, OF_SLOW_DIGEST)) i /= 5; /* Minimal digestion */ if (i < 1) i = 1; /* Digest some food */ player_set_food(player, player->food - i); } /* Getting Faint */ if (player->food < PY_FOOD_FAINT) { /* Faint occasionally */ if (!player->timed[TMD_PARALYZED] && one_in_(10)) { /* Message */ msg("You faint from the lack of food."); disturb(player, 1); /* Faint (bypass free action) */ (void)player_inc_timed(player, TMD_PARALYZED, 1 + randint0(5), true, false); } } /* Starve to death (slowly) */ if (player->food < PY_FOOD_STARVE) { /* Calculate damage */ i = (PY_FOOD_STARVE - player->food) / 10; /* Take damage */ take_hit(player, i, "starvation"); } /* Regenerate Hit Points if needed */ if (player->chp < player->mhp) player_regen_hp(player); /* Regenerate mana if needed */ if (player->csp < player->msp) player_regen_mana(player); /* Timeout various things */ decrease_timeouts(); /* Process light */ player_update_light(player); /*** Process Inventory ***/ /* Handle experience draining */ if (player_of_has(player, OF_DRAIN_EXP)) { if ((player->exp > 0) && one_in_(10)) { s32b d = damroll(10, 6) + (player->exp / 100) * z_info->life_drain_percent; player_exp_lose(player, d / 10, false); } equip_learn_flag(player, OF_DRAIN_EXP); } /* Recharge activatable objects and rods */ recharge_objects(); /* Notice things after time */ if (!(turn % 100)) equip_learn_after_time(player); /* Decrease trap timeouts */ for (y = 0; y < cave->height; y++) { for (x = 0; x < cave->width; x++) { struct trap *trap = cave->squares[y][x].trap; while (trap) { if (trap->timeout) { trap->timeout--; if (!trap->timeout) square_light_spot(cave, y, x); } trap = trap->next; } } } /*** Involuntary Movement ***/ /* Delayed Word-of-Recall */ if (player->word_recall) { /* Count down towards recall */ player->word_recall--; /* Activate the recall */ if (!player->word_recall) { /* Disturbing! */ disturb(player, 0); /* Determine the level */ if (player->depth) { msgt(MSG_TPLEVEL, "You feel yourself yanked upwards!"); dungeon_change_level(player, 0); } else { msgt(MSG_TPLEVEL, "You feel yourself yanked downwards!"); /* Force descent to a lower level if allowed */ if (OPT(player, birth_force_descend) && player->max_depth < z_info->max_depth - 1 && !is_quest(player->max_depth)) { player->max_depth = dungeon_get_next_level(player->max_depth, 1); } /* New depth - back to max depth or 1, whichever is deeper */ dungeon_change_level(player, player->max_depth < 1 ? 1: player->max_depth); } } } /* Delayed Deep Descent */ if (player->deep_descent) { /* Count down towards recall */ player->deep_descent--; /* Activate the recall */ if (player->deep_descent == 0) { int target_increment; int target_depth = player->max_depth; /* Calculate target depth */ target_increment = (4 / z_info->stair_skip) + 1; target_depth = dungeon_get_next_level(player->max_depth, target_increment); disturb(player, 0); /* Determine the level */ if (target_depth > player->depth) { msgt(MSG_TPLEVEL, "The floor opens beneath you!"); dungeon_change_level(player, target_depth); } else { /* Otherwise do something disastrous */ msgt(MSG_TPLEVEL, "You are thrown back in an explosion!"); effect_simple(EF_DESTRUCTION, "0", 0, 5, 0, NULL); } } } }
/** * Write the current dungeon */ void wr_dungeon(void) { int y, x; size_t i; byte tmp8u; byte count; byte prev_char; if (p_ptr->is_dead) return; /*** Basic info ***/ /* Dungeon specific info follows */ wr_u16b(p_ptr->stage); wr_u16b(p_ptr->last_stage); wr_u16b(p_ptr->py); wr_u16b(p_ptr->px); wr_u16b(DUNGEON_HGT); wr_u16b(DUNGEON_WID); wr_u16b(SQUARE_SIZE); wr_u16b(0); /*** Simple "Run-Length-Encoding" of cave ***/ /* Loop across bytes of cave_info */ for (i = 0; i < SQUARE_SIZE; i++) { /* Note that this will induce two wasted bytes */ count = 0; prev_char = 0; /* Dump the cave */ for (y = 0; y < DUNGEON_HGT; y++) { for (x = 0; x < DUNGEON_WID; x++) { /* Extract the important cave_info flags */ tmp8u = cave_info[y][x][i]; /* If the run is broken, or too full, flush it */ if ((tmp8u != prev_char) || (count == MAX_UCHAR)) { wr_byte((byte) count); wr_byte((byte) prev_char); prev_char = tmp8u; count = 1; } /* Continue the run */ else { count++; } } } /* Flush the data (if any) */ if (count) { wr_byte((byte) count); wr_byte((byte) prev_char); } } /*** Simple "Run-Length-Encoding" of cave ***/ /* Note that this will induce two wasted bytes */ count = 0; prev_char = 0; /* Dump the cave */ for (y = 0; y < DUNGEON_HGT; y++) { for (x = 0; x < DUNGEON_WID; x++) { /* Extract a byte */ tmp8u = cave_feat[y][x]; /* If the run is broken, or too full, flush it */ if ((tmp8u != prev_char) || (count == MAX_UCHAR)) { wr_byte((byte) count); wr_byte((byte) prev_char); prev_char = tmp8u; count = 1; } /* Continue the run */ else { count++; } } } /* Flush the data (if any) */ if (count) { wr_byte((byte) count); wr_byte((byte) prev_char); } /*** Compact ***/ /* Compact the objects */ compact_objects(0); /* Compact the monsters */ compact_monsters(0); }
/*! * @brief セーブデータの書き込み / * Actually write a save-file * @return 成功すればtrue */ static bool wr_savefile_new(void) { int i, j; u32b now; byte tmp8u; u16b tmp16u; /* Compact the objects */ compact_objects(0); /* Compact the monsters */ compact_monsters(0); /* Guess at the current time */ now = time((time_t *)0); /* Note the operating system */ sf_system = 0L; /* Note when the file was saved */ sf_when = now; /* Note the number of saves */ sf_saves++; /*** Actually write the file ***/ /* Dump the file header */ xor_byte = 0; wr_byte(FAKE_VER_MAJOR); xor_byte = 0; wr_byte(FAKE_VER_MINOR); xor_byte = 0; wr_byte(FAKE_VER_PATCH); xor_byte = 0; /* Initial value of xor_byte */ tmp8u = (byte)Rand_external(256); wr_byte(tmp8u); /* Reset the checksum */ v_stamp = 0L; x_stamp = 0L; /* Write the savefile version for Hengband 1.1.1 and later */ wr_byte(H_VER_EXTRA); wr_byte(H_VER_PATCH); wr_byte(H_VER_MINOR); wr_byte(H_VER_MAJOR); /* Operating system */ wr_u32b(sf_system); /* Time file last saved */ wr_u32b(sf_when); /* Number of past lives */ wr_u16b(sf_lives); /* Number of times saved */ wr_u16b(sf_saves); /* Space */ wr_u32b(0L); wr_u16b(0); wr_byte(0); #ifdef JP # ifdef EUC /* EUC kanji code */ wr_byte(2); # endif # ifdef SJIS /* SJIS kanji code */ wr_byte(3); # endif #else /* ASCII */ wr_byte(1); #endif /* Write the RNG state */ wr_randomizer(); /* Write the boolean "options" */ wr_options(); /* Dump the number of "messages" */ tmp16u = message_num(); if (compress_savefile && (tmp16u > 40)) tmp16u = 40; wr_u16b(tmp16u); /* Dump the messages (oldest first!) */ for (i = tmp16u - 1; i >= 0; i--) { wr_string(message_str((s16b)i)); } /* Dump the monster lore */ tmp16u = max_r_idx; wr_u16b(tmp16u); for (i = 0; i < tmp16u; i++) wr_lore(i); /* Dump the object memory */ tmp16u = max_k_idx; wr_u16b(tmp16u); for (i = 0; i < tmp16u; i++) wr_xtra(i); /* Dump the towns */ tmp16u = max_towns; wr_u16b(tmp16u); /* Dump the quests */ tmp16u = max_quests; wr_u16b(tmp16u); /* Dump the quests */ tmp8u = MAX_RANDOM_QUEST-MIN_RANDOM_QUEST; wr_byte(tmp8u); for (i = 0; i < max_quests; i++) { quest_type* const q_ptr = &quest[i]; /* Save status for every quest */ wr_s16b(q_ptr->status); /* And the dungeon level too */ /* (prevents problems with multi-level quests) */ wr_s16b(q_ptr->level); wr_byte(q_ptr->complev); wr_u32b(q_ptr->comptime); /* Save quest status if quest is running */ if (q_ptr->status == QUEST_STATUS_TAKEN || q_ptr->status == QUEST_STATUS_COMPLETED || !is_fixed_quest_idx(i)) { wr_s16b(q_ptr->cur_num); wr_s16b(q_ptr->max_num); wr_s16b(q_ptr->type); wr_s16b(q_ptr->r_idx); wr_s16b(q_ptr->k_idx); wr_byte(q_ptr->flags); wr_byte(q_ptr->dungeon); } } /* Dump the position in the wilderness */ wr_s32b(p_ptr->wilderness_x); wr_s32b(p_ptr->wilderness_y); wr_byte(p_ptr->wild_mode); wr_byte(ambush_flag); wr_s32b(max_wild_x); wr_s32b(max_wild_y); /* Dump the wilderness seeds */ for (i = 0; i < max_wild_x; i++) { for (j = 0; j < max_wild_y; j++) { wr_u32b(wilderness[j][i].seed); } } /* Hack -- Dump the artifacts */ tmp16u = max_a_idx; wr_u16b(tmp16u); for (i = 0; i < tmp16u; i++) { artifact_type *a_ptr = &a_info[i]; wr_byte(a_ptr->cur_num); wr_s16b(a_ptr->floor_id); } /* Write the "extra" information */ wr_extra(); /* Dump the "player hp" entries */ tmp16u = PY_MAX_LEVEL; wr_u16b(tmp16u); for (i = 0; i < tmp16u; i++) { wr_s16b(p_ptr->player_hp[i]); } /* Write spell data */ wr_u32b(p_ptr->spell_learned1); wr_u32b(p_ptr->spell_learned2); wr_u32b(p_ptr->spell_worked1); wr_u32b(p_ptr->spell_worked2); wr_u32b(p_ptr->spell_forgotten1); wr_u32b(p_ptr->spell_forgotten2); wr_s16b(p_ptr->learned_spells); wr_s16b(p_ptr->add_spells); /* Dump the ordered spells */ for (i = 0; i < 64; i++) { wr_byte(p_ptr->spell_order[i]); } /* Write the inventory */ for (i = 0; i < INVEN_TOTAL; i++) { object_type *o_ptr = &inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Dump index */ wr_u16b((u16b)i); /* Dump object */ wr_item(o_ptr); } /* Add a sentinel */ wr_u16b(0xFFFF); /* Note the towns */ tmp16u = max_towns; wr_u16b(tmp16u); /* Note the stores */ tmp16u = MAX_STORES; wr_u16b(tmp16u); /* Dump the stores of all towns */ for (i = 1; i < max_towns; i++) { for (j = 0; j < MAX_STORES; j++) { wr_store(&town[i].store[j]); } } /* Write the pet command settings */ wr_s16b(p_ptr->pet_follow_distance); wr_s16b(p_ptr->pet_extra_flags); /* Write screen dump for sending score */ if (screen_dump && (p_ptr->wait_report_score || !p_ptr->is_dead)) { wr_string(screen_dump); } else { wr_string(""); } /* Player is not dead, write the dungeon */ if (!p_ptr->is_dead) { /* Dump the dungeon */ if (!wr_dungeon()) return FALSE; /* Dump the ghost */ wr_ghost(); /* No scripts */ wr_s32b(0); } /* Write the "value check-sum" */ wr_u32b(v_stamp); /* Write the "encoded checksum" */ wr_u32b(x_stamp); /* Error in save */ if (ferror(fff) || (fflush(fff) == EOF)) return FALSE; /* Successful save */ return TRUE; }
/* * Write the current dungeon */ static void wr_dungeon(void) { int i, y, x; byte tmp8u; byte count; byte prev_char; /*** Basic info ***/ /* Dungeon specific info follows */ wr_s16b(p_ptr->depth); wr_s16b(p_ptr->py); wr_s16b(p_ptr->px); wr_byte(p_ptr->cur_map_hgt); wr_byte(p_ptr->cur_map_wid); /*** Simple "Run-Length-Encoding" of cave ***/ /* Note that this will induce two wasted bytes */ count = 0; prev_char = 0; /* Dump the cave */ for (y = 0; y < p_ptr->cur_map_hgt; y++) { for (x = 0; x < p_ptr->cur_map_wid; x++) { /* Extract the important cave_info flags */ tmp8u = (cave_info[y][x] & (IMPORTANT_FLAGS)); /* If the run is broken, or too full, flush it */ if ((tmp8u != prev_char) || (count == MAX_UCHAR)) { wr_byte((byte)count); wr_byte((byte)prev_char); prev_char = tmp8u; count = 1; } /* Continue the run */ else { count++; } } } /* Flush the data (if any) */ if (count) { wr_byte((byte)count); wr_byte((byte)prev_char); } /*** Simple "Run-Length-Encoding" of cave ***/ /* Note that this will induce two wasted bytes */ count = 0; prev_char = 0; /* Dump the cave */ for (y = 0; y < p_ptr->cur_map_hgt; y++) { for (x = 0; x < p_ptr->cur_map_wid; x++) { /* Extract a byte */ tmp8u = cave_feat[y][x]; /* If the run is broken, or too full, flush it */ if ((tmp8u != prev_char) || (count == MAX_UCHAR)) { wr_byte((byte)count); wr_byte((byte)prev_char); prev_char = tmp8u; count = 1; } /* Continue the run */ else { count++; } } } /* Flush the data (if any) */ if (count) { wr_byte((byte)count); wr_byte((byte)prev_char); } /*** Compact ***/ /* Compact the objects */ compact_objects(0); /* Compact the monsters */ compact_monsters(0); /*** Dump objects ***/ /* Total objects */ wr_u16b(o_max); /* Dump the objects */ for (i = 1; i < o_max; i++) { object_type *o_ptr = &o_list[i]; /* Dump it */ wr_item(o_ptr); } /*** Dump the monsters ***/ /* Total monsters */ wr_u16b(mon_max); /* Dump the monsters */ for (i = 1; i < mon_max; i++) { monster_type *m_ptr = &mon_list[i]; /* Dump it */ wr_monster(m_ptr); } // dump the wandering monster information for (i = FLOW_WANDERING_HEAD; i < MAX_FLOWS; i++) { wr_byte(flow_center_y[i]); wr_byte(flow_center_x[i]); wr_s16b(wandering_pause[i]); } }