diff --git a/VisualStudio/Hengband/Hengband.vcxproj b/VisualStudio/Hengband/Hengband.vcxproj
index c6269d9afc..1c1a8b16b0 100644
--- a/VisualStudio/Hengband/Hengband.vcxproj
+++ b/VisualStudio/Hengband/Hengband.vcxproj
@@ -433,7 +433,6 @@
-
@@ -518,6 +517,7 @@
+
@@ -1228,7 +1228,6 @@
-
@@ -1320,6 +1319,7 @@
+
diff --git a/VisualStudio/Hengband/Hengband.vcxproj.filters b/VisualStudio/Hengband/Hengband.vcxproj.filters
index e81e86fa9f..7155b7668a 100644
--- a/VisualStudio/Hengband/Hengband.vcxproj.filters
+++ b/VisualStudio/Hengband/Hengband.vcxproj.filters
@@ -1850,6 +1850,9 @@
player
+
+ player
+
monster-floor
@@ -2111,9 +2114,6 @@
main-win
-
- main-win
-
main
@@ -4640,6 +4640,9 @@
player
+
+ player
+
monster-floor
@@ -4913,9 +4916,6 @@
main-win
-
- main-win
-
main
diff --git a/src/Makefile.am b/src/Makefile.am
index f89a5dacff..0fbf17b6e5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -689,6 +689,7 @@ hengband_SOURCES = \
player/player-personality.cpp player/player-personality.h \
player/player-realm.cpp player/player-realm.h \
player/player-skill.cpp player/player-skill.h \
+ player/player-spell-status.cpp player/player-spell-status.h \
player/player-status.cpp player/player-status.h \
player/player-status-flags.cpp player/player-status-flags.h \
player/player-status-table.cpp player/player-status-table.h \
@@ -1052,7 +1053,6 @@ EXTRA_hengband_SOURCES = \
main-win/main-win-cfg-reader.cpp main-win/main-win-cfg-reader.h \
main-win/main-win-define.h \
main-win/main-win-exception.cpp main-win/main-win-exception.h \
- main-win/main-win-file-utils.cpp main-win/main-win-file-utils.h \
main-win/main-win-mci.cpp main-win/main-win-mci.h \
main-win/main-win-menuitem.h \
main-win/main-win-mmsystem.h \
diff --git a/src/birth/game-play-initializer.cpp b/src/birth/game-play-initializer.cpp
index 10bece68cf..c7427efd68 100644
--- a/src/birth/game-play-initializer.cpp
+++ b/src/birth/game-play-initializer.cpp
@@ -13,6 +13,7 @@
#include "player-info/race-info.h"
#include "player-info/race-types.h"
#include "player/digestion-processor.h"
+#include "player/player-spell-status.h"
#include "system/artifact-type-definition.h"
#include "system/baseitem-info.h"
#include "system/dungeon-info.h"
@@ -82,18 +83,10 @@ void player_wipe_without_name(PlayerType *player_ptr)
}
player_ptr->food = PY_FOOD_FULL - 1;
- if (PlayerClass(player_ptr).equals(PlayerClassType::SORCERER)) {
- player_ptr->spell_learned1 = player_ptr->spell_learned2 = 0xffffffffL;
- player_ptr->spell_worked1 = player_ptr->spell_worked2 = 0xffffffffL;
- } else {
- player_ptr->spell_learned1 = player_ptr->spell_learned2 = 0L;
- player_ptr->spell_worked1 = player_ptr->spell_worked2 = 0L;
- }
- player_ptr->spell_forgotten1 = player_ptr->spell_forgotten2 = 0L;
- for (int i = 0; i < 64; i++) {
- player_ptr->spell_order[i] = 99;
- }
+ PlayerSpellStatus pss(player_ptr);
+ pss.realm1().initialize();
+ pss.realm2().initialize();
player_ptr->learned_spells = 0;
player_ptr->add_spells = 0;
diff --git a/src/cmd-action/cmd-hissatsu.cpp b/src/cmd-action/cmd-hissatsu.cpp
index 3cbce4258f..a056ffb18f 100644
--- a/src/cmd-action/cmd-hissatsu.cpp
+++ b/src/cmd-action/cmd-hissatsu.cpp
@@ -31,6 +31,7 @@
#include "player-status/player-energy.h"
#include "player/attack-defense-types.h"
#include "player/player-realm.h"
+#include "player/player-spell-status.h"
#include "player/special-defense-types.h"
#include "spell/spells-execution.h"
#include "spell/technic-info-table.h"
@@ -105,6 +106,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
}
choice = always_show_list ? ESCAPE : 1;
+ const auto realm_status = PlayerSpellStatus(player_ptr).realm1();
while (!flag) {
if (choice == ESCAPE) {
choice = ' ';
@@ -133,7 +135,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
if (menu_line > 32) {
menu_line -= 32;
}
- } while (!(player_ptr->spell_learned1 & (1UL << (menu_line - 1))));
+ } while (!realm_status.is_learned(menu_line - 1));
break;
}
@@ -145,7 +147,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
if (menu_line > 32) {
menu_line -= 32;
}
- } while (!(player_ptr->spell_learned1 & (1UL << (menu_line - 1))));
+ } while (!realm_status.is_learned(menu_line - 1));
break;
}
@@ -165,7 +167,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
} else {
menu_line += 16;
}
- while (!(player_ptr->spell_learned1 & (1UL << (menu_line - 1)))) {
+ while (!realm_status.is_learned(menu_line - 1)) {
if (reverse) {
menu_line--;
if (menu_line < 2) {
@@ -213,15 +215,12 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
continue;
}
line++;
- if (!(player_ptr->spell_learned1 >> i)) {
- break;
- }
/* Access the spell */
if (spell.slevel > plev) {
continue;
}
- if (!(player_ptr->spell_learned1 & (1UL << i))) {
+ if (!realm_status.is_learned(i)) {
continue;
}
std::string psi_desc;
@@ -270,7 +269,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
}
/* Totally Illegal */
- if ((i < 0) || (i >= 32) || !(player_ptr->spell_learned1 & (1U << selections[i]))) {
+ if ((i < 0) || (i >= 32) || !realm_status.is_learned(selections[i])) {
bell();
continue;
}
@@ -318,7 +317,7 @@ void do_cmd_hissatsu(PlayerType *player_ptr)
msg_print(_("武器を持たないと必殺技は使えない!", "You need to wield a weapon!"));
return;
}
- if (!player_ptr->spell_learned1) {
+ if (PlayerSpellStatus(player_ptr).realm1().is_nothing_learned()) {
msg_print(_("何も技を知らない。", "You don't know any special attacks."));
return;
}
@@ -395,8 +394,9 @@ void do_cmd_gain_hissatsu(PlayerType *player_ptr)
const auto sval = *o_ptr->bi_key.sval();
auto gain = false;
+ auto realm_status = PlayerSpellStatus(player_ptr).realm1();
for (auto i = sval * 8; i < sval * 8 + 8; i++) {
- if (player_ptr->spell_learned1 & (1UL << i)) {
+ if (realm_status.is_learned(i)) {
continue;
}
@@ -404,19 +404,11 @@ void do_cmd_gain_hissatsu(PlayerType *player_ptr)
continue;
}
- player_ptr->spell_learned1 |= (1UL << i);
- player_ptr->spell_worked1 |= (1UL << i);
+ realm_status.set_learned(i);
+ realm_status.set_worked(i);
const auto &spell_name = PlayerRealm::get_spell_name(RealmType::HISSATSU, i);
msg_format(_("%sの技を覚えた。", "You have learned the special attack of %s."), spell_name.data());
- int j;
- for (j = 0; j < 64; j++) {
- /* Stop at the first empty space */
- if (player_ptr->spell_order[j] == 99) {
- break;
- }
- }
-
- player_ptr->spell_order[j] = i;
+ player_ptr->spell_order_learned.push_back(i);
gain = true;
}
diff --git a/src/cmd-action/cmd-spell.cpp b/src/cmd-action/cmd-spell.cpp
index d74f6404b0..48a8e4536c 100644
--- a/src/cmd-action/cmd-spell.cpp
+++ b/src/cmd-action/cmd-spell.cpp
@@ -41,6 +41,7 @@
#include "player/player-damage.h"
#include "player/player-realm.h"
#include "player/player-skill.h"
+#include "player/player-spell-status.h"
#include "player/player-status.h"
#include "player/special-defense-types.h"
#include "spell-kind/spells-random.h"
@@ -69,6 +70,7 @@
#include "view/display-messages.h"
#include "view/display-util.h"
#include
+#include
concptr KWD_DAM = _("損傷:", "dam ");
concptr KWD_RANGE = _("射程:", "rng ");
@@ -273,7 +275,9 @@ static bool spell_okay(PlayerType *player_ptr, int spell_id, bool learned, bool
/* Spell is forgotten */
PlayerRealm pr(player_ptr);
- if (pr.realm2().equals(use_realm) ? (player_ptr->spell_forgotten2 & (1UL << spell_id)) : (player_ptr->spell_forgotten1 & (1UL << spell_id))) {
+ PlayerSpellStatus pss(player_ptr);
+ const auto realm_status = pr.realm2().equals(use_realm) ? pss.realm2() : pss.realm1();
+ if (realm_status.is_forgotten(spell_id)) {
/* Never okay */
return false;
}
@@ -283,7 +287,7 @@ static bool spell_okay(PlayerType *player_ptr, int spell_id, bool learned, bool
}
/* Spell is learned */
- if (pr.realm2().equals(use_realm) ? (player_ptr->spell_learned2 & (1UL << spell_id)) : (player_ptr->spell_learned1 & (1UL << spell_id))) {
+ if (realm_status.is_learned(spell_id)) {
/* Always true */
return !study_pray;
}
@@ -682,23 +686,11 @@ void do_cmd_browse(PlayerType *player_ptr)
*/
static void change_realm2(PlayerType *player_ptr, PlayerRealm &pr, RealmType next_realm)
{
- int i, j = 0;
- for (i = 0; i < 64; i++) {
- player_ptr->spell_order[j] = player_ptr->spell_order[i];
- if (player_ptr->spell_order[i] < 32) {
- j++;
- }
- }
- for (; j < 64; j++) {
- player_ptr->spell_order[j] = 99;
- }
+ PlayerSpellStatus(player_ptr).realm2().initialize();
- for (i = 32; i < 64; i++) {
+ for (auto i = 32; i < 64; i++) {
player_ptr->spell_exp[i] = PlayerSkill::spell_exp_at(PlayerSkillRank::UNSKILLED);
}
- player_ptr->spell_learned2 = 0L;
- player_ptr->spell_worked2 = 0L;
- player_ptr->spell_forgotten2 = 0L;
constexpr auto fmt_realm = _("魔法の領域を%sから%sに変更した。", "changed magic realm from %s to %s.");
const auto mes = format(fmt_realm, pr.realm2().get_name().data(), PlayerRealm::get_name(next_realm).data());
@@ -724,7 +716,6 @@ static void change_realm2(PlayerType *player_ptr, PlayerRealm &pr, RealmType nex
void do_cmd_study(PlayerType *player_ptr)
{
auto increment = 0;
- auto learned = false;
/* Spells of realm2 will have an increment of +32 */
SPELL_IDX spell = -1;
@@ -837,21 +828,10 @@ void do_cmd_study(PlayerType *player_ptr)
}
/* Learn the spell */
- if (spell < 32) {
- if (player_ptr->spell_learned1 & (1UL << spell)) {
- learned = true;
- } else {
- player_ptr->spell_learned1 |= (1UL << spell);
- }
- } else {
- if (player_ptr->spell_learned2 & (1UL << (spell - 32))) {
- learned = true;
- } else {
- player_ptr->spell_learned2 |= (1UL << (spell - 32));
- }
- }
+ PlayerSpellStatus pss(player_ptr);
+ auto realm_status = increment ? pss.realm2() : pss.realm1();
- if (learned) {
+ if (realm_status.is_learned(spell % 32)) {
auto max_exp = PlayerSkill::spell_exp_at((spell < 32) ? PlayerSkillRank::MASTER : PlayerSkillRank::EXPERT);
const auto old_exp = player_ptr->spell_exp[spell];
const auto &realm = increment ? pr.realm2() : pr.realm1();
@@ -874,17 +854,10 @@ void do_cmd_study(PlayerType *player_ptr)
auto new_rank_str = PlayerSkill::skill_rank_str(new_rank);
msg_format(_("%sの熟練度が%sに上がった。", "Your proficiency of %s is now %s rank."), spell_name.data(), new_rank_str);
} else {
- /* Find the next open entry in "player_ptr->spell_order[]" */
- int i;
- for (i = 0; i < 64; i++) {
- /* Stop at the first empty space */
- if (player_ptr->spell_order[i] == 99) {
- break;
- }
- }
+ realm_status.set_learned(spell % 32);
/* Add the spell to the known list */
- player_ptr->spell_order[i++] = spell;
+ player_ptr->spell_order_learned.push_back(spell);
/* Mention the result */
const auto &realm = increment ? pr.realm2() : pr.realm1();
@@ -1162,15 +1135,13 @@ bool do_cmd_cast(PlayerType *player_ptr)
}
/* A spell was cast */
- if (!(increment ? (player_ptr->spell_worked2 & (1UL << spell_id)) : (player_ptr->spell_worked1 & (1UL << spell_id))) && !is_every_magic) {
+ PlayerSpellStatus pss(player_ptr);
+ auto realm_status = increment ? pss.realm2() : pss.realm1();
+ if (!realm_status.is_worked(spell_id) && !is_every_magic) {
int e = spell.sexp;
/* The spell worked */
- if (pr.realm1().equals(use_realm)) {
- player_ptr->spell_worked1 |= (1UL << spell_id);
- } else {
- player_ptr->spell_worked2 |= (1UL << spell_id);
- }
+ realm_status.set_worked(spell_id);
gain_exp(player_ptr, e * spell.slevel);
RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::ITEM_KNOWLEDGE);
diff --git a/src/load/inventory-loader.cpp b/src/load/inventory-loader.cpp
index e15b455eae..61d959300a 100644
--- a/src/load/inventory-loader.cpp
+++ b/src/load/inventory-loader.cpp
@@ -65,8 +65,10 @@ static errr rd_inventory(PlayerType *player_ptr)
errr load_inventory(PlayerType *player_ptr)
{
- for (int i = 0; i < 64; i++) {
- player_ptr->spell_order[i] = rd_byte();
+ for (auto i = 0; i < 64; i++) {
+ if (const auto spell_id = rd_byte(); spell_id < 64) {
+ player_ptr->spell_order_learned.push_back(spell_id);
+ }
}
if (!rd_inventory(player_ptr)) {
diff --git a/src/load/load-zangband.cpp b/src/load/load-zangband.cpp
index 39211e4e9c..e19bf901dc 100644
--- a/src/load/load-zangband.cpp
+++ b/src/load/load-zangband.cpp
@@ -15,6 +15,7 @@
#include "player/player-personality.h"
#include "player/player-realm.h"
#include "player/player-skill.h"
+#include "player/player-spell-status.h"
#include "realm/realm-types.h"
#include "spell/spells-status.h"
#include "system/building-type-definition.h"
@@ -233,9 +234,12 @@ void set_zangband_class(PlayerType *player_ptr)
void set_zangband_learnt_spells(PlayerType *player_ptr)
{
player_ptr->learned_spells = 0;
- for (int i = 0; i < 64; i++) {
- if ((i < 32) ? (player_ptr->spell_learned1 & (1UL << i)) : (player_ptr->spell_learned2 & (1UL << (i - 32)))) {
- player_ptr->learned_spells++;
+ PlayerSpellStatus pss(player_ptr);
+ for (const auto &realm_status : { pss.realm1(), pss.realm2() }) {
+ for (auto i = 0; i < 32; i++) {
+ if (realm_status.is_learned(i)) {
+ player_ptr->learned_spells++;
+ }
}
}
}
diff --git a/src/main-win.cpp b/src/main-win.cpp
index 5f152075ed..9e5460d6f5 100644
--- a/src/main-win.cpp
+++ b/src/main-win.cpp
@@ -103,7 +103,6 @@
#include "main-win/graphics-win.h"
#include "main-win/main-win-bg.h"
#include "main-win/main-win-exception.h"
-#include "main-win/main-win-file-utils.h"
#include "main-win/main-win-mci.h"
#include "main-win/main-win-menuitem.h"
#include "main-win/main-win-music.h"
@@ -1913,7 +1912,7 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
}
case IDM_OPTIONS_OPEN_MUSIC_DIR: {
const auto path = path_build(ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
- open_dir_in_explorer(path.string());
+ open_dir_in_explorer(path);
break;
}
case IDM_OPTIONS_SOUND: {
@@ -1936,7 +1935,7 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
}
case IDM_OPTIONS_OPEN_SOUND_DIR: {
const auto path = path_build(ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
- open_dir_in_explorer(path.string());
+ open_dir_in_explorer(path);
break;
}
case IDM_OPTIONS_NO_BG: {
@@ -2645,7 +2644,7 @@ static void init_stuff()
init_file_paths(path);
validate_dir(ANGBAND_DIR_APEX, false);
validate_dir(ANGBAND_DIR_BONE, false);
- if (!check_dir(ANGBAND_DIR_EDIT)) {
+ if (!is_directory(ANGBAND_DIR_EDIT)) {
validate_dir(ANGBAND_DIR_DATA, true);
} else {
validate_dir(ANGBAND_DIR_DATA, false);
diff --git a/src/main-win/main-win-cfg-reader.cpp b/src/main-win/main-win-cfg-reader.cpp
index f42162669e..7b562ced67 100644
--- a/src/main-win/main-win-cfg-reader.cpp
+++ b/src/main-win/main-win-cfg-reader.cpp
@@ -6,11 +6,11 @@
#include "main-win/main-win-cfg-reader.h"
#include "locale/japanese.h"
#include "main-win/main-win-define.h"
-#include "main-win/main-win-file-utils.h"
#include "main-win/main-win-tokenizer.h"
#include "main/sound-definitions-table.h"
#include "term/z-term.h"
#include "util/angband-files.h"
+#include
#include
// 1つの項目に設定可能な最大ファイル数
@@ -29,57 +29,44 @@ static cfg_key make_cfg_key(int type, int val)
return (type << 16) | (val & 0xffff);
}
-/*!
- * @brief マップのキーに対応する値を取得する
- * @param key1_type the "actions" value of "term_xtra()". see:z-term.h TERM_XTRA_xxxxx
- * @param key2_val the 2nd parameter of "term_xtra()"
- * @return キーに対応する値を返す。登録されていない場合はnullptrを返す。
- */
-static cfg_values *get_map_value(cfg_map *map, int key1_type, int key2_val)
-{
- cfg_values *value = nullptr;
- auto ite = map->find(make_cfg_key(key1_type, key2_val));
- if (ite != map->end()) {
- value = ite->second;
- }
- return value;
-}
-
/*!
* @brief 登録されている中からランダムに選択する
* @param type the "actions" value of "term_xtra()". see:z-term.h TERM_XTRA_xxxxx
* @param val the 2nd parameter of "term_xtra()"
- * @return キーに対応する値、複数のファイル名の中からからランダムに返す。登録されていない場合はnullptrを返す。
+ * @return キーに対応する値、複数のファイル名の中からからランダムに返す。登録されていない場合はstd::nulloptを返す。
*/
-concptr CfgData::get_rand(int key1_type, int key2_val)
+std::optional CfgData::get_rand(int key1_type, int key2_val) const
{
- cfg_values *filenames = get_map_value(this->map, key1_type, key2_val);
- if (!filenames) {
- return nullptr;
+ const auto it = this->map.find(make_cfg_key(key1_type, key2_val));
+ if (it == this->map.end()) {
+ return std::nullopt;
}
- return filenames->at(Rand_external(filenames->size()));
+ const auto &filenames = it->second;
+ return filenames.at(Rand_external(filenames.size()));
}
-bool CfgData::has_key(int key1_type, int key2_val)
+bool CfgData::has_key(int key1_type, int key2_val) const
{
- auto ite = map->find(make_cfg_key(key1_type, key2_val));
- return ite != map->end();
+ return this->map.contains(make_cfg_key(key1_type, key2_val));
}
-void CfgData::insert(int key1_type, int key2_val, cfg_values *value)
+void CfgData::insert(int key1_type, int key2_val, cfg_values &&value)
{
- this->map->insert(std::make_pair(make_cfg_key(key1_type, key2_val), value));
+ this->map.emplace(make_cfg_key(key1_type, key2_val), std::move(value));
}
/*!
* @param dir .cfgファイルのディレクトリ
* @param files .cfgファイル名。複数指定可能で、最初に見つかったファイルから読み取る。
*/
-CfgReader::CfgReader(std::filesystem::path dir, std::initializer_list files)
+CfgReader::CfgReader(const std::filesystem::path &dir, std::initializer_list files)
{
this->dir = dir;
- this->cfg_path = find_any_file(dir, files);
+ auto exists_in_dir = [dir](const char *filename) { return is_regular_file(path_build(dir, filename)); };
+ if (auto it = std::find_if(files.begin(), files.end(), exists_in_dir); it != files.end()) {
+ this->cfg_path = path_build(dir, *it);
+ }
}
/*!
@@ -87,51 +74,46 @@ CfgReader::CfgReader(std::filesystem::path dir, std::initializer_list f
* @param sections 読み取るデータの指定
* @return 読み込んだデータを登録したCfgDataを返す。
*/
-CfgData *CfgReader::read_sections(std::initializer_list sections)
+CfgData CfgReader::read_sections(std::initializer_list sections) const
{
- CfgData *result = new CfgData();
+ CfgData result;
- if (!check_file(this->cfg_path.data())) {
+ if (!is_regular_file(this->cfg_path)) {
return result;
}
- char key_buf[80];
- char buf[MAIN_WIN_MAX_PATH];
- char *tokens[SAMPLE_MAX];
+ const auto cfg_path_str = this->cfg_path.string();
for (auto §ion : sections) {
-
- bool has_data = false;
- int index = 0;
concptr read_key;
- while ((read_key = section.key_at(index, key_buf)) != nullptr) {
- GetPrivateProfileStringA(section.section_name, read_key, "", buf, MAIN_WIN_MAX_PATH, this->cfg_path.data());
- if (*buf != '\0') {
- cfg_values *filenames = new cfg_values();
+ char key_buf[80]{};
+ for (auto index = 0; (read_key = section.key_at(index, key_buf)) != nullptr; ++index) {
+ char buf[MAIN_WIN_MAX_PATH]{};
+ if (GetPrivateProfileStringA(section.section_name, read_key, "", buf, MAIN_WIN_MAX_PATH, cfg_path_str.data()) == 0) {
+ continue;
+ }
+
#ifdef JP
- // .cfg (UTF-8) to Shift-JIS
- guess_convert_to_system_encoding(buf, MAIN_WIN_MAX_PATH);
+ // .cfg (UTF-8) to Shift-JIS
+ guess_convert_to_system_encoding(buf, MAIN_WIN_MAX_PATH);
#endif
- const int num = tokenize_whitespace(buf, SAMPLE_MAX, tokens);
- for (auto j = 0; j < num; j++) {
- const auto path = path_build(dir, tokens[j]);
- if (check_file(path)) {
- filenames->push_back(string_make(tokens[j]));
- }
- }
- if (filenames->empty()) {
- delete filenames;
- } else {
- result->insert(section.action_type, index, filenames);
- has_data = true;
+ char *tokens[SAMPLE_MAX]{};
+ const int num = tokenize_whitespace(buf, SAMPLE_MAX, tokens);
+
+ cfg_values filenames;
+ for (const std::string_view token : std::span(tokens, num)) {
+ if (is_regular_file(path_build(this->dir, token))) {
+ filenames.emplace_back(token);
}
}
+ if (filenames.empty()) {
+ continue;
+ }
- index++;
- }
-
- if (section.has_data) {
- *(section.has_data) = has_data;
+ result.insert(section.action_type, index, std::move(filenames));
+ if (section.has_data) {
+ *(section.has_data) = true;
+ }
}
}
diff --git a/src/main-win/main-win-cfg-reader.h b/src/main-win/main-win-cfg-reader.h
index 5113299df1..1feb67a93f 100644
--- a/src/main-win/main-win-cfg-reader.h
+++ b/src/main-win/main-win-cfg-reader.h
@@ -4,12 +4,13 @@
#include
#include
#include
+#include
#include
#include
typedef uint cfg_key;
-using cfg_values = std::vector;
-using cfg_map = std::unordered_map;
+using cfg_values = std::vector;
+using cfg_map = std::unordered_map;
using key_name_func = concptr (*)(int, char *);
/*!
@@ -38,32 +39,26 @@ struct cfg_section {
class CfgData {
public:
- CfgData()
- {
- map = new cfg_map();
- }
- virtual ~CfgData()
- {
- delete map;
- }
- concptr get_rand(int key1_type, int key2_val);
- bool has_key(int key1_type, int key2_val);
- void insert(int key1_type, int key2_val, cfg_values *value);
+ CfgData() = default;
+
+ std::optional get_rand(int key1_type, int key2_val) const;
+ bool has_key(int key1_type, int key2_val) const;
+ void insert(int key1_type, int key2_val, cfg_values &&value);
protected:
- cfg_map *map;
+ cfg_map map{};
};
class CfgReader {
public:
- CfgReader(std::filesystem::path dir, std::initializer_list files);
- CfgData *read_sections(std::initializer_list sections);
- std::string get_cfg_path()
+ CfgReader(const std::filesystem::path &dir, std::initializer_list files);
+ CfgData read_sections(std::initializer_list sections) const;
+ const std::filesystem::path &get_cfg_path() const
{
return cfg_path;
}
protected:
std::filesystem::path dir;
- std::string cfg_path;
+ std::filesystem::path cfg_path;
};
diff --git a/src/main-win/main-win-file-utils.cpp b/src/main-win/main-win-file-utils.cpp
deleted file mode 100644
index a16ef94caa..0000000000
--- a/src/main-win/main-win-file-utils.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*!
- * @file main-win-file-utils.cpp
- * @brief Windows版固有実装(ファイル関連処理)
- */
-
-#include "main-win/main-win-file-utils.h"
-#include "main-win/main-win-define.h"
-#include "main-win/main-win-utils.h"
-#include "util/angband-files.h"
-
-#include
-
-/*
- * Check for existance of a file
- * @param s path of file
- * @retval true 指定ファイルが存在する(かつディレクトリではない)
- * @retval false 指定ファイルが存在しない、またはディレクトリである
- */
-bool check_file(const std::filesystem::path &s)
-{
- const auto &file = s.string();
- DWORD attrib = GetFileAttributesW(to_wchar(file.data()).wc_str());
- if (attrib == INVALID_FILE_NAME) {
- return false;
- }
- if (attrib & FILE_ATTRIBUTE_DIRECTORY) {
- return false;
- }
-
- return true;
-}
-
-/*
- * Check for existance of a directory
- * @param s path of directory
- * @retval true 指定ディレクトリが存在する
- * @retval false 指定ディレクトリが存在しない、またはディレクトリではない
- */
-bool check_dir(const std::filesystem::path &s)
-{
- const auto &dir = s.string();
- char path[MAIN_WIN_MAX_PATH];
- strcpy(path, dir.data());
- int i = strlen(path);
- if (i && (path[i - 1] == '\\')) {
- path[--i] = '\0';
- }
-
- DWORD attrib = GetFileAttributesW(to_wchar(path).wc_str());
- if (attrib == INVALID_FILE_NAME) {
- return false;
- }
- if (!(attrib & FILE_ATTRIBUTE_DIRECTORY)) {
- return false;
- }
-
- return true;
-}
-
-/*!
- * @brief 候補リストを順に確認し、存在するファイルのパスを返す。
- * @param dir ディレクトリ
- * @param files ファイル名のリスト
- * @return ファイルのパスを返す。候補リストのファイルすべて存在しない場合は空文字列を返す。
- */
-std::string find_any_file(const std::filesystem::path &dir, std::initializer_list files)
-{
- for (const auto *filename : files) {
- const auto path = path_build(dir, filename);
- if (check_file(path)) {
- return path.string();
- }
- }
-
- return "";
-}
diff --git a/src/main-win/main-win-file-utils.h b/src/main-win/main-win-file-utils.h
deleted file mode 100644
index ef286bd2f2..0000000000
--- a/src/main-win/main-win-file-utils.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-#include "system/h-type.h"
-#include
-#include
-#include
-
-bool check_file(const std::filesystem::path &s);
-bool check_dir(const std::filesystem::path &s);
-std::string find_any_file(const std::filesystem::path &dir, std::initializer_list files);
diff --git a/src/main-win/main-win-music.cpp b/src/main-win/main-win-music.cpp
index ed14f6996f..d54b27b2c4 100644
--- a/src/main-win/main-win-music.cpp
+++ b/src/main-win/main-win-music.cpp
@@ -7,7 +7,6 @@
#include "dungeon/quest.h"
#include "floor/floor-town.h"
#include "main-win/main-win-define.h"
-#include "main-win/main-win-file-utils.h"
#include "main-win/main-win-mci.h"
#include "main-win/main-win-mmsystem.h"
#include "main-win/main-win-tokenizer.h"
@@ -37,7 +36,7 @@ std::filesystem::path ANGBAND_DIR_XTRA_MUSIC;
/*
* "music.cfg" data
*/
-CfgData *music_cfg_data;
+std::optional music_cfg_data;
namespace main_win_music {
@@ -134,7 +133,7 @@ void load_music_prefs()
CfgReader reader(ANGBAND_DIR_XTRA_MUSIC, { "music_debug.cfg", "music.cfg" });
char device_type[256];
- GetPrivateProfileStringA("Device", "type", "MPEGVideo", device_type, _countof(device_type), reader.get_cfg_path().data());
+ GetPrivateProfileStringA("Device", "type", "MPEGVideo", device_type, _countof(device_type), reader.get_cfg_path().string().data());
mci_device_type = to_wchar(device_type).wc_str();
// clang-format off
@@ -184,12 +183,16 @@ errr play_music(int type, int val)
return 0;
} // now playing
+ if (!music_cfg_data) {
+ return 1;
+ }
+
auto filename = music_cfg_data->get_rand(type, val);
if (!filename) {
return 1;
} // no setting
- auto path_music = path_build(ANGBAND_DIR_XTRA_MUSIC, filename);
+ auto path_music = path_build(ANGBAND_DIR_XTRA_MUSIC, *filename);
if (current_music_type != TERM_XTRA_MUSIC_MUTE) {
if (current_music_path == path_music) {
return 0;
@@ -200,10 +203,9 @@ errr play_music(int type, int val)
current_music_id = val;
current_music_path = path_music;
- const auto &filename_music = path_music.string();
- to_wchar path(filename_music.data());
+ const auto path_music_str = path_music.wstring();
mci_open_parms.lpstrDeviceType = mci_device_type.data();
- mci_open_parms.lpstrElementName = path.wc_str();
+ mci_open_parms.lpstrElementName = path_music_str.data();
mciSendCommandW(mci_open_parms.wDeviceID, MCI_STOP, MCI_WAIT, 0);
mciSendCommandW(mci_open_parms.wDeviceID, MCI_CLOSE, MCI_WAIT, 0);
mciSendCommandW(mci_open_parms.wDeviceID, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT | MCI_NOTIFY, (DWORD)&mci_open_parms);
diff --git a/src/main-win/main-win-music.h b/src/main-win/main-win-music.h
index 6f2f81d3dc..9dc4f4ef4f 100644
--- a/src/main-win/main-win-music.h
+++ b/src/main-win/main-win-music.h
@@ -5,11 +5,12 @@
#include "system/h-type.h"
#include
#include
+#include
#include
extern bool use_pause_music_inactive;
extern std::filesystem::path ANGBAND_DIR_XTRA_MUSIC;
-extern CfgData *music_cfg_data;
+extern std::optional music_cfg_data;
namespace main_win_music {
void load_music_prefs();
diff --git a/src/main-win/main-win-sound.cpp b/src/main-win/main-win-sound.cpp
index b47e4f2471..159754d37a 100644
--- a/src/main-win/main-win-sound.cpp
+++ b/src/main-win/main-win-sound.cpp
@@ -8,7 +8,6 @@
#include "main-win/main-win-sound.h"
#include "main-win/main-win-cfg-reader.h"
#include "main-win/main-win-define.h"
-#include "main-win/main-win-file-utils.h"
#include "main-win/main-win-utils.h"
#include "main-win/wav-reader.h"
#include "main/sound-definitions-table.h"
@@ -25,7 +24,7 @@ std::filesystem::path ANGBAND_DIR_XTRA_SOUND;
/*
* "sound.cfg" data
*/
-CfgData *sound_cfg_data;
+std::optional sound_cfg_data;
/*!
* 効果音データ
@@ -92,18 +91,19 @@ std::queue sound_queue;
*/
static void modulate_amplitude(int bits_per_sample, BYTE *pcm_buf, size_t bufsize, int mult, int div)
{
- auto modulate = [mult, div](auto sample) {
+ auto modulate = [mult, div](auto sample, int standard = 0) {
using sample_t = decltype(sample);
constexpr auto min = std::numeric_limits::min();
constexpr auto max = std::numeric_limits::max();
- const auto modulated_sample = std::clamp(sample * mult / div, min, max);
+ const auto diff = sample - standard;
+ const auto modulated_sample = std::clamp(standard + diff * mult / div, min, max);
return static_cast(modulated_sample);
};
switch (bits_per_sample) {
case 8:
for (auto i = 0U; i < bufsize; ++i) {
- pcm_buf[i] = modulate(pcm_buf[i]);
+ pcm_buf[i] = modulate(pcm_buf[i], 128);
}
break;
@@ -182,14 +182,14 @@ static bool add_sound_queue(const WAVEFORMATEX *wf, BYTE *buf, DWORD bufsize, in
/*!
* 指定ファイルを再生する
*
- * @param buf ファイル名
+ * @param path ファイルパス
* @retval true 正常に処理された
* @retval false 処理エラー
*/
-static bool play_sound_impl(char *filename, int volume)
+static bool play_sound_impl(const std::filesystem::path &path, int volume)
{
wav_reader reader;
- if (!reader.open(filename)) {
+ if (!reader.open(path)) {
return false;
}
auto wf = reader.get_waveformat();
@@ -252,14 +252,17 @@ void finalize_sound(void)
*/
int play_sound(int val, int volume)
{
+ if (!sound_cfg_data) {
+ return 1;
+ }
+
auto filename = sound_cfg_data->get_rand(TERM_XTRA_SOUND, val);
if (!filename) {
return 1;
}
- auto path = path_build(ANGBAND_DIR_XTRA_SOUND, filename);
- auto filename_sound = path.string();
- if (play_sound_impl(filename_sound.data(), volume)) {
+ auto path = path_build(ANGBAND_DIR_XTRA_SOUND, *filename);
+ if (play_sound_impl(path, volume)) {
return 0;
}
diff --git a/src/main-win/main-win-sound.h b/src/main-win/main-win-sound.h
index 12ed6c0f4a..379c0e4ccf 100644
--- a/src/main-win/main-win-sound.h
+++ b/src/main-win/main-win-sound.h
@@ -3,9 +3,10 @@
#include "main-win/main-win-cfg-reader.h"
#include
#include
+#include
extern std::filesystem::path ANGBAND_DIR_XTRA_SOUND;
-extern CfgData *sound_cfg_data;
+extern std::optional sound_cfg_data;
void load_sound_prefs();
void finalize_sound();
diff --git a/src/main-win/main-win-utils.cpp b/src/main-win/main-win-utils.cpp
index 55402fed54..2721ba7e95 100644
--- a/src/main-win/main-win-utils.cpp
+++ b/src/main-win/main-win-utils.cpp
@@ -56,13 +56,13 @@ void save_screen_as_html(HWND hWnd)
/*!
* @brief 対象ファイルを選択した状態でエクスプローラーを開く
- * @param filename 対象ファイル
+ * @param path 対象ファイルのパス
*/
-void open_dir_in_explorer(std::string_view filename)
+void open_dir_in_explorer(const std::filesystem::path &path)
{
- std::stringstream ss;
- ss << "/select," << filename;
- ShellExecuteW(NULL, NULL, L"explorer.exe", to_wchar(ss.str().data()).wc_str(), NULL, SW_SHOWNORMAL);
+ std::wstringstream ss;
+ ss << L"/select," << path.wstring();
+ ShellExecuteW(NULL, NULL, L"explorer.exe", ss.str().data(), NULL, SW_SHOWNORMAL);
}
/*!
diff --git a/src/main-win/main-win-utils.h b/src/main-win/main-win-utils.h
index d8ad502358..ad3149062a 100644
--- a/src/main-win/main-win-utils.h
+++ b/src/main-win/main-win-utils.h
@@ -84,5 +84,5 @@ class to_multibyte {
bool is_already_running();
void save_screen_as_html(HWND hWnd);
-void open_dir_in_explorer(std::string_view filename);
+void open_dir_in_explorer(const std::filesystem::path &path);
std::optional get_open_filename(OPENFILENAMEW *ofn, const std::filesystem::path &path_dir, const std::filesystem::path &path_file, DWORD max_name_size);
diff --git a/src/main-win/wav-reader.cpp b/src/main-win/wav-reader.cpp
index 58c3eeef7c..421821e963 100644
--- a/src/main-win/wav-reader.cpp
+++ b/src/main-win/wav-reader.cpp
@@ -6,11 +6,11 @@
#include "main-win/wav-reader.h"
#include "main-win/main-win-utils.h"
-bool wav_reader::open(char *filename)
+bool wav_reader::open(const std::filesystem::path &path)
{
close();
- this->hmmio = ::mmioOpenW(to_wchar(filename).wc_str(), NULL, MMIO_READ);
+ this->hmmio = ::mmioOpenW(path.wstring().data(), NULL, MMIO_READ);
if (this->hmmio == NULL) {
return false;
}
diff --git a/src/main-win/wav-reader.h b/src/main-win/wav-reader.h
index 8534afd12a..94548a99cf 100644
--- a/src/main-win/wav-reader.h
+++ b/src/main-win/wav-reader.h
@@ -6,6 +6,7 @@
#include
+#include
#include
#include
@@ -29,11 +30,11 @@ class wav_reader {
/*!
* WAVファイルを開く
*
- * @param filename
+ * @param path ファイルパス
* @retval true 正常に処理された
* @retval false 処理エラー
*/
- bool open(char *filename);
+ bool open(const std::filesystem::path &path);
/*!
* PCMデータ取得
* @details 呼び出し元でdelete[]すること
diff --git a/src/player/player-spell-status.cpp b/src/player/player-spell-status.cpp
new file mode 100644
index 0000000000..4c38d3e33c
--- /dev/null
+++ b/src/player/player-spell-status.cpp
@@ -0,0 +1,94 @@
+#include "player/player-spell-status.h"
+#include "player-base/player-class.h"
+#include "system/player-type-definition.h"
+#include "util/bit-flags-calculator.h"
+
+namespace {
+
+void set_flag_bit(BIT_FLAGS &flags, int bit_pos, bool value)
+{
+ if (value) {
+ set_bits(flags, 1U << bit_pos);
+ } else {
+ reset_bits(flags, 1U << bit_pos);
+ }
+}
+
+}
+
+PlayerSpellStatus::PlayerSpellStatus(PlayerType *player_ptr)
+ : player_ptr(player_ptr)
+{
+}
+
+PlayerSpellStatus::Realm PlayerSpellStatus::realm1() const
+{
+ return Realm(this->player_ptr, true);
+}
+
+PlayerSpellStatus::Realm PlayerSpellStatus::realm2() const
+{
+ return Realm(this->player_ptr, false);
+}
+
+PlayerSpellStatus::Realm::Realm(PlayerType *player_ptr, bool is_realm1)
+ : player_ptr(player_ptr)
+ , is_realm1(is_realm1)
+{
+}
+
+void PlayerSpellStatus::Realm::initialize()
+{
+ auto &learned = this->is_realm1 ? this->player_ptr->spell_learned1 : this->player_ptr->spell_learned2;
+ auto &worked = this->is_realm1 ? this->player_ptr->spell_worked1 : this->player_ptr->spell_worked2;
+ auto &forgotten = this->is_realm1 ? this->player_ptr->spell_forgotten1 : this->player_ptr->spell_forgotten2;
+
+ const auto is_sorcerer = PlayerClass(player_ptr).equals(PlayerClassType::SORCERER);
+ learned = worked = is_sorcerer ? 0xffffffffU : 0;
+ forgotten = 0;
+
+ auto is_erase_spell_id = this->is_realm1 ? [](int spell_id) { return spell_id >= 32; } : [](int spell_id) { return spell_id < 32; };
+ std::erase_if(this->player_ptr->spell_order_learned, is_erase_spell_id);
+}
+
+bool PlayerSpellStatus::Realm::is_nothing_learned() const
+{
+ const auto learned = this->is_realm1 ? this->player_ptr->spell_learned1 : this->player_ptr->spell_learned2;
+ return learned == 0;
+}
+
+bool PlayerSpellStatus::Realm::is_learned(int spell_id) const
+{
+ const auto learned = this->is_realm1 ? this->player_ptr->spell_learned1 : this->player_ptr->spell_learned2;
+ return any_bits(learned, 1U << spell_id);
+}
+
+bool PlayerSpellStatus::Realm::is_worked(int spell_id) const
+{
+ const auto worked = this->is_realm1 ? this->player_ptr->spell_worked1 : this->player_ptr->spell_worked2;
+ return any_bits(worked, 1U << spell_id);
+}
+
+bool PlayerSpellStatus::Realm::is_forgotten(int spell_id) const
+{
+ const auto forgotten = this->is_realm1 ? this->player_ptr->spell_forgotten1 : this->player_ptr->spell_forgotten2;
+ return any_bits(forgotten, 1U << spell_id);
+}
+
+void PlayerSpellStatus::Realm::set_learned(int spell_id, bool value)
+{
+ auto &learned = this->is_realm1 ? this->player_ptr->spell_learned1 : this->player_ptr->spell_learned2;
+ set_flag_bit(learned, spell_id, value);
+}
+
+void PlayerSpellStatus::Realm::set_worked(int spell_id, bool value)
+{
+ auto &worked = this->is_realm1 ? this->player_ptr->spell_worked1 : this->player_ptr->spell_worked2;
+ set_flag_bit(worked, spell_id, value);
+}
+
+void PlayerSpellStatus::Realm::set_forgotten(int spell_id, bool value)
+{
+ auto &forgotten = this->is_realm1 ? this->player_ptr->spell_forgotten1 : this->player_ptr->spell_forgotten2;
+ set_flag_bit(forgotten, spell_id, value);
+}
diff --git a/src/player/player-spell-status.h b/src/player/player-spell-status.h
new file mode 100644
index 0000000000..2d759006bd
--- /dev/null
+++ b/src/player/player-spell-status.h
@@ -0,0 +1,32 @@
+#pragma once
+
+class PlayerType;
+
+class PlayerSpellStatus {
+public:
+ PlayerSpellStatus(PlayerType *player_ptr);
+
+ class Realm {
+ public:
+ Realm(PlayerType *player_ptr, bool is_realm1);
+
+ void initialize();
+ bool is_nothing_learned() const;
+ bool is_learned(int spell_id) const;
+ bool is_worked(int spell_id) const;
+ bool is_forgotten(int spell_id) const;
+ void set_learned(int spell_id, bool value = true);
+ void set_worked(int spell_id, bool value = true);
+ void set_forgotten(int spell_id, bool value = true);
+
+ private:
+ PlayerType *player_ptr;
+ bool is_realm1;
+ };
+
+ Realm realm1() const;
+ Realm realm2() const;
+
+private:
+ PlayerType *player_ptr;
+};
diff --git a/src/player/player-status.cpp b/src/player/player-status.cpp
index 97ee283342..6ecc6648b4 100644
--- a/src/player/player-status.cpp
+++ b/src/player/player-status.cpp
@@ -75,6 +75,7 @@
#include "player/player-personality.h"
#include "player/player-realm.h"
#include "player/player-skill.h"
+#include "player/player-spell-status.h"
#include "player/player-status-flags.h"
#include "player/player-status-table.h"
#include "player/player-view.h"
@@ -536,49 +537,38 @@ static void update_num_of_spells(PlayerType *player_ptr)
}
}
- int num_boukyaku = 0;
- for (int j = 0; j < 64; j++) {
- if ((j < 32) ? any_bits(player_ptr->spell_forgotten1, (1UL << j)) : any_bits(player_ptr->spell_forgotten2, (1UL << (j - 32)))) {
- num_boukyaku++;
- }
- }
+ PlayerSpellStatus pss(player_ptr);
- player_ptr->new_spells = num_allowed + player_ptr->add_spells + num_boukyaku - player_ptr->learned_spells;
- for (int i = 63; i >= 0; i--) {
- if (!player_ptr->spell_learned1 && !player_ptr->spell_learned2) {
- break;
+ auto num_forgotten = 0;
+ for (const auto &realm_status : { pss.realm1(), pss.realm2() }) {
+ for (auto spell_id = 0; spell_id < 32; spell_id++) {
+ if (realm_status.is_forgotten(spell_id)) {
+ num_forgotten++;
+ }
}
+ }
- int j = player_ptr->spell_order[i];
- if (j >= 99) {
- continue;
- }
+ player_ptr->new_spells = num_allowed + player_ptr->add_spells + num_forgotten - player_ptr->learned_spells;
- const auto &realm = (j < 32) ? pr.realm1() : pr.realm2();
- const auto &spell = realm.get_spell_info(j % 32);
+ for (auto it = player_ptr->spell_order_learned.crbegin(); it != player_ptr->spell_order_learned.crend(); ++it) {
+ const auto is_realm1 = *it < 32;
+ const auto spell_id = *it % 32;
+ const auto &realm = is_realm1 ? pr.realm1() : pr.realm2();
+ const auto &spell = realm.get_spell_info(spell_id);
if (spell.slevel <= player_ptr->lev) {
continue;
}
- bool is_spell_learned = (j < 32) ? any_bits(player_ptr->spell_learned1, (1UL << j)) : any_bits(player_ptr->spell_learned2, (1UL << (j - 32)));
- if (!is_spell_learned) {
+ auto realm_status = is_realm1 ? pss.realm1() : pss.realm2();
+ if (!realm_status.is_learned(spell_id)) {
continue;
}
- if (j < 32) {
- set_bits(player_ptr->spell_forgotten1, (1UL << j));
- } else {
- set_bits(player_ptr->spell_forgotten2, (1UL << (j - 32)));
- }
-
- if (j < 32) {
- reset_bits(player_ptr->spell_learned1, (1UL << j));
- } else {
- reset_bits(player_ptr->spell_learned2, (1UL << (j - 32)));
- }
+ realm_status.set_forgotten(spell_id);
+ realm_status.set_learned(spell_id, false);
- const auto &spell_name = realm.get_spell_name(j % 32);
+ const auto &spell_name = realm.get_spell_name(spell_id);
#ifdef JP
msg_format("%sの%sを忘れてしまった。", spell_name.data(), spell_category.data());
#else
@@ -588,38 +578,24 @@ static void update_num_of_spells(PlayerType *player_ptr)
}
/* Forget spells if we know too many spells */
- for (int i = 63; i >= 0; i--) {
+ for (auto it = player_ptr->spell_order_learned.crbegin(); it != player_ptr->spell_order_learned.crend(); ++it) {
if (player_ptr->new_spells >= 0) {
break;
}
- if (!player_ptr->spell_learned1 && !player_ptr->spell_learned2) {
- break;
- }
- int j = player_ptr->spell_order[i];
- if (j >= 99) {
- continue;
- }
+ const auto is_realm1 = *it < 32;
+ const auto spell_id = *it % 32;
- bool is_spell_learned = (j < 32) ? any_bits(player_ptr->spell_learned1, (1UL << j)) : any_bits(player_ptr->spell_learned2, (1UL << (j - 32)));
- if (!is_spell_learned) {
+ auto realm_status = is_realm1 ? pss.realm1() : pss.realm2();
+ if (!realm_status.is_learned(spell_id)) {
continue;
}
- if (j < 32) {
- set_bits(player_ptr->spell_forgotten1, (1UL << j));
- } else {
- set_bits(player_ptr->spell_forgotten2, (1UL << (j - 32)));
- }
-
- if (j < 32) {
- reset_bits(player_ptr->spell_learned1, (1UL << j));
- } else {
- reset_bits(player_ptr->spell_learned2, (1UL << (j - 32)));
- }
+ realm_status.set_forgotten(spell_id);
+ realm_status.set_learned(spell_id, false);
- const auto &realm = (j < 32) ? pr.realm1() : pr.realm2();
- const auto &spell_name = realm.get_spell_name(j % 32);
+ const auto &realm = is_realm1 ? pr.realm1() : pr.realm2();
+ const auto &spell_name = realm.get_spell_name(spell_id);
#ifdef JP
msg_format("%sの%sを忘れてしまった。", spell_name.data(), spell_category.data());
#else
@@ -629,44 +605,30 @@ static void update_num_of_spells(PlayerType *player_ptr)
}
/* Check for spells to remember */
- for (int i = 0; i < 64; i++) {
+ for (const auto j : player_ptr->spell_order_learned) {
if (player_ptr->new_spells <= 0) {
break;
}
- if (!player_ptr->spell_forgotten1 && !player_ptr->spell_forgotten2) {
- break;
- }
- int j = player_ptr->spell_order[i];
- if (j >= 99) {
- break;
- }
- const auto &realm = (j < 32) ? pr.realm1() : pr.realm2();
- const auto &spell = realm.get_spell_info(j % 32);
+ const auto is_realm1 = j < 32;
+ const auto spell_id = j % 32;
+
+ const auto &realm = is_realm1 ? pr.realm1() : pr.realm2();
+ const auto &spell = realm.get_spell_info(spell_id);
if (spell.slevel > player_ptr->lev) {
continue;
}
- bool is_spell_learned = (j < 32) ? any_bits(player_ptr->spell_forgotten1, (1UL << j)) : any_bits(player_ptr->spell_forgotten2, (1UL << (j - 32)));
- if (!is_spell_learned) {
+ auto realm_status = is_realm1 ? pss.realm1() : pss.realm2();
+ if (!realm_status.is_forgotten(spell_id)) {
continue;
}
- if (j < 32) {
- reset_bits(player_ptr->spell_forgotten1, (1UL << j));
- } else {
- reset_bits(player_ptr->spell_forgotten2, (1UL << (j - 32)));
- }
-
- if (j < 32) {
- set_bits(player_ptr->spell_learned1, (1UL << j));
-
- } else {
- set_bits(player_ptr->spell_learned2, (1UL << (j - 32)));
- }
+ realm_status.set_forgotten(spell_id, false);
+ realm_status.set_learned(spell_id);
- const auto &spell_name = realm.get_spell_name(j % 32);
+ const auto &spell_name = realm.get_spell_name(spell_id);
#ifdef JP
msg_format("%sの%sを思い出した。", spell_name.data(), spell_category.data());
#else
@@ -684,7 +646,7 @@ static void update_num_of_spells(PlayerType *player_ptr)
continue;
}
- if (any_bits(player_ptr->spell_learned1, (1UL << j))) {
+ if (pss.realm1().is_learned(j)) {
continue;
}
diff --git a/src/save/save.cpp b/src/save/save.cpp
index daafd8fdfa..7bd34493a8 100644
--- a/src/save/save.cpp
+++ b/src/save/save.cpp
@@ -193,8 +193,9 @@ static bool wr_savefile_new(PlayerType *player_ptr)
wr_u32b(player_ptr->spell_forgotten2);
wr_s16b(player_ptr->learned_spells);
wr_s16b(player_ptr->add_spells);
- for (int i = 0; i < 64; i++) {
- wr_byte((byte)player_ptr->spell_order[i]);
+ for (auto i = 0; i < 64; i++) {
+ const auto spell_id = (i < std::ssize(player_ptr->spell_order_learned)) ? player_ptr->spell_order_learned[i] : 255;
+ wr_byte(static_cast(spell_id));
}
for (int i = 0; i < INVEN_TOTAL; i++) {
diff --git a/src/spell/spell-info.cpp b/src/spell/spell-info.cpp
index 9b51ae3788..3b3d57f71a 100644
--- a/src/spell/spell-info.cpp
+++ b/src/spell/spell-info.cpp
@@ -4,6 +4,7 @@
#include "player-info/class-info.h"
#include "player/player-realm.h"
#include "player/player-skill.h"
+#include "player/player-spell-status.h"
#include "player/player-status-table.h"
#include "player/player-status.h"
#include "realm/realm-types.h"
@@ -303,6 +304,8 @@ void print_spells(PlayerType *player_ptr, SPELL_IDX target_spell_id, const SPELL
const auto info = exe_spell(player_ptr, use_realm, spell_id, SpellProcessType::INFO);
concptr comment = info->data();
byte line_attr = TERM_WHITE;
+ PlayerSpellStatus pss(player_ptr);
+ const auto realm_status = pr.realm1().equals(use_realm) ? pss.realm1() : pss.realm2();
if (pc.is_every_magic()) {
if (spell.slevel > player_ptr->max_plv) {
comment = _("未知", "unknown");
@@ -314,13 +317,13 @@ void print_spells(PlayerType *player_ptr, SPELL_IDX target_spell_id, const SPELL
} else if (!pr.realm1().equals(use_realm) && !pr.realm2().equals(use_realm)) {
comment = _("未知", "unknown");
line_attr = TERM_L_BLUE;
- } else if (pr.realm1().equals(use_realm) ? ((player_ptr->spell_forgotten1 & (1UL << spell_id))) : ((player_ptr->spell_forgotten2 & (1UL << spell_id)))) {
+ } else if (realm_status.is_forgotten(spell_id)) {
comment = _("忘却", "forgotten");
line_attr = TERM_YELLOW;
- } else if (!(pr.realm1().equals(use_realm) ? (player_ptr->spell_learned1 & (1UL << spell_id)) : (player_ptr->spell_learned2 & (1UL << spell_id)))) {
+ } else if (!realm_status.is_learned(spell_id)) {
comment = _("未知", "unknown");
line_attr = TERM_L_BLUE;
- } else if (!(pr.realm1().equals(use_realm) ? (player_ptr->spell_worked1 & (1UL << spell_id)) : (player_ptr->spell_worked2 & (1UL << spell_id)))) {
+ } else if (!realm_status.is_worked(spell_id)) {
comment = _("未経験", "untried");
line_attr = TERM_L_GREEN;
}
diff --git a/src/system/player-type-definition.h b/src/system/player-type-definition.h
index c30ef52400..62b962e2b9 100644
--- a/src/system/player-type-definition.h
+++ b/src/system/player-type-definition.h
@@ -173,7 +173,7 @@ class PlayerType {
BIT_FLAGS spell_worked2{}; /* bit mask of spells tried and worked */
BIT_FLAGS spell_forgotten1{}; /* bit mask of spells learned but forgotten */
BIT_FLAGS spell_forgotten2{}; /* bit mask of spells learned but forgotten */
- SPELL_IDX spell_order[64]{}; /* order spells learned/remembered/forgotten */
+ std::vector spell_order_learned{}; /* order spells learned */
SUB_EXP spell_exp[64]{}; /* Proficiency of spells */
std::map> weapon_exp{}; /* Proficiency of weapons */
diff --git a/src/util/angband-files.cpp b/src/util/angband-files.cpp
index 432150c937..5645319e78 100644
--- a/src/util/angband-files.cpp
+++ b/src/util/angband-files.cpp
@@ -2,6 +2,9 @@
#include "locale/japanese.h"
#include "system/angband-exceptions.h"
#include "util/string-processor.h"
+#ifdef WINDOWS
+#include "main-win/main-win-utils.h"
+#endif
#include
#include
@@ -169,7 +172,13 @@ std::filesystem::path path_build(const std::filesystem::path &path, std::string_
}
auto parsed_path = path_parse(path);
+#ifdef WINDOWS
+ // システムロケールがUTF-8の場合、appendによるUTF-16への変換時に
+ // Shift-JISをUTF-8とみなしてしまい変換に失敗するので、自前でUTF-16に変換してからappendする
+ const auto &path_ret = parsed_path.append(to_wchar(file.data()).wc_str());
+#else
const auto &path_ret = parsed_path.append(file);
+#endif
constexpr auto max_path_length = 1024;
const auto path_str = path_ret.string();
if (path_str.length() > max_path_length) {
diff --git a/src/window/display-sub-windows.cpp b/src/window/display-sub-windows.cpp
index 3c91c74961..810a5fed5e 100644
--- a/src/window/display-sub-windows.cpp
+++ b/src/window/display-sub-windows.cpp
@@ -22,6 +22,7 @@
#include "player-base/player-class.h"
#include "player-info/class-info.h"
#include "player/player-realm.h"
+#include "player/player-spell-status.h"
#include "player/player-status-flags.h"
#include "player/player-status-table.h"
#include "player/player-status.h"
@@ -824,22 +825,26 @@ static void display_spell_list(PlayerType *player_ptr)
y = (j < 3) ? 0 : (m[j - 3] + 2);
x = 27 * (j % 3);
int n = 0;
- for (int i = 0; i < 32; i++) {
+
+ PlayerSpellStatus pss(player_ptr);
+ const auto realm_status = (j < 1) ? pss.realm1() : pss.realm2();
+
+ for (auto spell_id = 0; spell_id < 32; spell_id++) {
byte a = TERM_WHITE;
const auto &realm = (j < 1) ? pr.realm1() : pr.realm2();
- const auto &spell = realm.get_spell_info(i);
- const auto &spell_name = realm.get_spell_name(i % 32);
+ const auto &spell = realm.get_spell_info(spell_id);
+ const auto &spell_name = realm.get_spell_name(spell_id);
auto name = spell_name.data();
if (spell.slevel >= 99) {
name = _("(判読不能)", "(illegible)");
a = TERM_L_DARK;
- } else if ((j < 1) ? ((player_ptr->spell_forgotten1 & (1UL << i))) : ((player_ptr->spell_forgotten2 & (1UL << (i % 32))))) {
+ } else if (realm_status.is_forgotten(spell_id)) {
a = TERM_ORANGE;
- } else if (!((j < 1) ? (player_ptr->spell_learned1 & (1UL << i)) : (player_ptr->spell_learned2 & (1UL << (i % 32))))) {
+ } else if (!realm_status.is_learned(spell_id)) {
a = TERM_RED;
- } else if (!((j < 1) ? (player_ptr->spell_worked1 & (1UL << i)) : (player_ptr->spell_worked2 & (1UL << (i % 32))))) {
+ } else if (!realm_status.is_worked(spell_id)) {
a = TERM_YELLOW;
}
diff --git a/src/wizard/wizard-special-process.cpp b/src/wizard/wizard-special-process.cpp
index 02d70d05db..1e72f19d0c 100644
--- a/src/wizard/wizard-special-process.cpp
+++ b/src/wizard/wizard-special-process.cpp
@@ -63,6 +63,7 @@
#include "player/patron.h"
#include "player/player-realm.h"
#include "player/player-skill.h"
+#include "player/player-spell-status.h"
#include "player/player-status-table.h"
#include "player/player-status.h"
#include "player/race-info-table.h"
@@ -684,6 +685,10 @@ void wiz_reset_class(PlayerType *player_ptr)
if (chosen_realms->first != RealmType::NONE) {
pr.set(chosen_realms->first, chosen_realms->second);
}
+ PlayerSpellStatus pss(player_ptr);
+ pss.realm1().initialize();
+ pss.realm2().initialize();
+ player_ptr->learned_spells = 0;
change_birth_flags();
handle_stuff(player_ptr);
}
@@ -704,6 +709,10 @@ void wiz_reset_realms(PlayerType *player_ptr)
if (chosen_realms->first != RealmType::NONE) {
pr.set(chosen_realms->first, chosen_realms->second);
}
+ PlayerSpellStatus pss(player_ptr);
+ pss.realm1().initialize();
+ pss.realm2().initialize();
+ player_ptr->learned_spells = 0;
change_birth_flags();
handle_stuff(player_ptr);
}