From 51867506159fef92c75f2b913386d0532c87becf Mon Sep 17 00:00:00 2001 From: Hourier <66951241+Hourier@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:18:09 +0900 Subject: [PATCH] =?utf8?q?[Refactor]=20PlayerType::arena=5Fnumber=20?= =?utf8?q?=E3=82=92ArenaEntryList=20=E3=81=AB=E7=B9=B0=E3=82=8A=E8=BE=BC?= =?utf8?q?=E3=82=93=E3=81=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/birth/game-play-initializer.cpp | 3 ++- src/cmd-building/cmd-building.cpp | 5 ++-- src/core/game-play.cpp | 6 ++--- src/floor/floor-generator.cpp | 5 ++-- src/io-dump/character-dump.cpp | 30 ++++++++++----------- src/io/write-diary.cpp | 11 +++++--- src/load/player-info-loader.cpp | 16 ++++++++--- src/market/arena-entry.cpp | 51 +++++++++++++++++++++++++++++++++++ src/market/arena-entry.h | 14 ++++++++-- src/market/arena.cpp | 34 ++++++++++++----------- src/monster-floor/monster-death.cpp | 14 +++++----- src/player/player-damage.cpp | 7 +++-- src/player/player-status.cpp | 5 ++-- src/save/player-writer.cpp | 7 +++-- src/system/angband-version.h | 2 +- src/system/player-type-definition.cpp | 3 +-- src/system/player-type-definition.h | 1 - 17 files changed, 148 insertions(+), 66 deletions(-) diff --git a/src/birth/game-play-initializer.cpp b/src/birth/game-play-initializer.cpp index 307ab87a6..27010c1cf 100644 --- a/src/birth/game-play-initializer.cpp +++ b/src/birth/game-play-initializer.cpp @@ -5,6 +5,7 @@ #include "game-option/cheat-options.h" #include "info-reader/fixed-map-parser.h" #include "inventory/inventory-slot-types.h" +#include "market/arena-entry.h" #include "market/arena.h" #include "pet/pet-util.h" #include "player-base/player-class.h" @@ -128,7 +129,7 @@ void player_wipe_without_name(PlayerType *player_ptr) player_ptr->wild_mode = false; player_ptr->max_plv = player_ptr->lev = 1; - player_ptr->arena_number = 0; + ArenaEntryList::get_instance().reset_entry(); w_ptr->set_arena(true); w_ptr->knows_daily_bounty = false; update_gambling_monsters(player_ptr); diff --git a/src/cmd-building/cmd-building.cpp b/src/cmd-building/cmd-building.cpp index 3a7a03cda..8a24f80fd 100644 --- a/src/cmd-building/cmd-building.cpp +++ b/src/cmd-building/cmd-building.cpp @@ -30,6 +30,7 @@ #include "io/input-key-requester.h" #include "main/music-definitions-table.h" #include "main/sound-of-music.h" +#include "market/arena-entry.h" #include "market/arena.h" #include "market/bounty.h" #include "market/building-actions-table.h" @@ -330,8 +331,8 @@ void do_cmd_building(PlayerType *player_ptr) bldg = &buildings[which]; reinit_wilderness = false; - - if ((which == 2) && (player_ptr->arena_number < 0)) { + const auto &entries = ArenaEntryList::get_instance(); + if ((which == 2) && entries.get_defeated_entry() && !entries.is_player_true_victor()) { msg_print(_("「敗者に用はない。」", "'There's no place here for a LOSER like you!'")); return; } diff --git a/src/core/game-play.cpp b/src/core/game-play.cpp index 331c7e52c..660091959 100644 --- a/src/core/game-play.cpp +++ b/src/core/game-play.cpp @@ -349,10 +349,10 @@ static void decide_arena_death(PlayerType *player_ptr) floor.inside_arena = false; auto &entries = ArenaEntryList::get_instance(); - if (player_ptr->arena_number > entries.get_max_entries()) { - player_ptr->arena_number++; + if (entries.is_player_true_victor()) { + entries.increment_entry(); } else { - player_ptr->arena_number = -1 - player_ptr->arena_number; + entries.set_defeated_entry(); } player_ptr->is_dead = false; diff --git a/src/floor/floor-generator.cpp b/src/floor/floor-generator.cpp index 49ed1ae95..88aba4174 100644 --- a/src/floor/floor-generator.cpp +++ b/src/floor/floor-generator.cpp @@ -138,12 +138,13 @@ static void generate_challenge_arena(PlayerType *player_ptr) build_arena(player_ptr, &y, &x); player_place(player_ptr, y, x); - if (place_specific_monster(player_ptr, 0, player_ptr->y + 5, player_ptr->x, arena_info[player_ptr->arena_number].r_idx, PM_NO_KAGE | PM_NO_PET)) { + auto &entries = ArenaEntryList::get_instance(); + if (place_specific_monster(player_ptr, 0, player_ptr->y + 5, player_ptr->x, arena_info[entries.get_current_entry()].r_idx, PM_NO_KAGE | PM_NO_PET)) { return; } w_ptr->set_arena(true); - player_ptr->arena_number++; + entries.increment_entry(); msg_print(_("相手は欠場した。あなたの不戦勝だ。", "The enemy is unable to appear. You won by default.")); } diff --git a/src/io-dump/character-dump.cpp b/src/io-dump/character-dump.cpp index 9d61a2632..5a0faa941 100644 --- a/src/io-dump/character-dump.cpp +++ b/src/io-dump/character-dump.cpp @@ -264,51 +264,49 @@ static void dump_aux_options(FILE *fff) * @brief 闘技場の情報をファイルにダンプする * @param player_ptr プレイヤーへの参照ポインタ * @param fff ファイルポインタ + * @details 旧バージョン (v1.5.0.1より前)では何回戦で敗北したか記録していないので、便宜的に1回戦で敗北したことにする. */ -static void dump_aux_arena(PlayerType *player_ptr, FILE *fff) +static void dump_aux_arena(FILE *fff) { if (lite_town || vanilla_town) { return; } const auto &entries = ArenaEntryList::get_instance(); - const auto arena_number = player_ptr->arena_number; - if (arena_number < 0) { - if (arena_number == ARENA_DEFEATED_OLD_VER) { - fprintf(fff, _("\n 闘技場: 敗北\n\n", "\n Arena: Defeated\n\n")); - return; - } - + const auto defeated_entry = entries.get_defeated_entry(); + if (defeated_entry && !entries.is_player_true_victor()) { + const auto defeated_fight = *defeated_entry + 1; //!< entryは配列番号なので対戦回数と1つずれる. constexpr auto fmt = _("\n 闘技場: %d回戦で%sの前に敗北\n", "\n Arena: Defeated by %s in the %d%s fight\n"); - const auto &arena = arena_info[-1 - arena_number]; + const auto &arena = arena_info[*defeated_entry]; const auto &arena_monrace = monraces_info[arena.r_idx]; #ifdef JP - fprintf(fff, fmt, -arena_number, arena_monrace.name.data()); + fprintf(fff, fmt, defeated_fight, arena_monrace.name.data()); #else - fprintf(fff, fmt, arena_monrace.name.data(), -arena_number, get_ordinal_number_suffix(-arena_number).data()); + fprintf(fff, fmt, arena_monrace.name.data(), defeated_fight, get_ordinal_number_suffix(*defeated_entry).data()); #endif fprintf(fff, "\n"); return; } const auto max_entries = entries.get_max_entries(); - if (arena_number > max_entries + 2) { + const auto current_entry = entries.get_current_entry(); + if (current_entry > max_entries + 2) { fprintf(fff, _("\n 闘技場: 真のチャンピオン\n", "\n Arena: True Champion\n")); fprintf(fff, "\n"); return; } - if (arena_number > max_entries - 1) { + if (current_entry > max_entries - 1) { fprintf(fff, _("\n 闘技場: チャンピオン\n", "\n Arena: Champion\n")); fprintf(fff, "\n"); return; } - const auto victory_count = arena_number > max_entries ? max_entries : arena_number; + const auto victory_count = current_entry > max_entries ? max_entries : current_entry; #ifdef JP fprintf(fff, "\n 闘技場: %2d勝\n", victory_count); #else - fprintf(fff, "\n Arena: %2d %s\n", victory_count, (arena_number > 1) ? "Victories" : "Victory"); + fprintf(fff, "\n Arena: %2d %s\n", victory_count, (current_entry > 1) ? "Victories" : "Victory"); #endif fprintf(fff, "\n"); } @@ -623,7 +621,7 @@ void make_character_dump(PlayerType *player_ptr, FILE *fff) dump_aux_options(fff); dump_aux_recall(fff); dump_aux_quest(player_ptr, fff); - dump_aux_arena(player_ptr, fff); + dump_aux_arena(fff); dump_aux_monsters(fff); dump_aux_virtues(player_ptr, fff); dump_aux_race_history(player_ptr, fff); diff --git a/src/io/write-diary.cpp b/src/io/write-diary.cpp index 09c3c3370..e6d1f2017 100644 --- a/src/io/write-diary.cpp +++ b/src/io/write-diary.cpp @@ -350,15 +350,18 @@ void exe_write_diary(const FloorType &floor, DiaryKind dk, int num, std::string_ break; } case DiaryKind::ARENA: { - if (num < 0) { - int n = -num; + const auto &entries = ArenaEntryList::get_instance(); + const auto defeated_entry = entries.get_defeated_entry(); + if (defeated_entry) { constexpr auto fmt = _(" %2d:%02d %20s 闘技場の%d%s回戦で、%sの前に敗れ去った。\n", " %2d:%02d %20s beaten by %s in the %d%s fight.\n"); - fprintf(fff, fmt, hour, min, note_level.data(), _(n, note.data()), _("", n), _(note.data(), get_ordinal_number_suffix(n).data())); + const auto num_defeated = *defeated_entry + 1; //!< entryは配列番号なので対戦回数と1つずれる. + fprintf(fff, fmt, hour, min, note_level.data(), _(num_defeated, note.data()), _("", num_defeated), _(note.data(), get_ordinal_number_suffix(num_defeated).data())); break; } constexpr auto fmt = _(" %2d:%02d %20s 闘技場の%d%s回戦(%s)に勝利した。\n", " %2d:%02d %20s won the %d%s fight (%s).\n"); - fprintf(fff, fmt, hour, min, note_level.data(), num, _("", get_ordinal_number_suffix(num).data()), note.data()); + const auto current_entry = entries.get_current_entry(); + fprintf(fff, fmt, hour, min, note_level.data(), current_entry, _("", get_ordinal_number_suffix(current_entry).data()), note.data()); if (num == ArenaEntryList::get_instance().get_max_entries()) { constexpr auto mes_champion = _(" 闘技場のすべての敵に勝利し、チャンピオンとなった。\n", " won all fights to become a Champion.\n"); diff --git a/src/load/player-info-loader.cpp b/src/load/player-info-loader.cpp index d066e89f9..f49e7c3e9 100644 --- a/src/load/player-info-loader.cpp +++ b/src/load/player-info-loader.cpp @@ -268,11 +268,21 @@ static void rd_arena(PlayerType *player_ptr) } player_ptr->town_num = rd_s16b(); - player_ptr->arena_number = rd_s16b(); + auto &entries = ArenaEntryList::get_instance(); + entries.load_current_entry(rd_s16b()); if (h_older_than(1, 5, 0, 1)) { - if (player_ptr->arena_number >= 99) { - player_ptr->arena_number = ARENA_DEFEATED_OLD_VER; + if (entries.get_current_entry() >= 99) { + entries.reset_entry(); + entries.set_defeated_entry(); } + } else if (loading_savefile_version < 23) { + const auto currrent_entry = entries.get_current_entry(); + if (currrent_entry < 0) { + entries.load_current_entry(-currrent_entry); + entries.set_defeated_entry(); + } + } else { + entries.load_defeated_entry(rd_s16b()); } rd_phase_out(player_ptr); diff --git a/src/market/arena-entry.cpp b/src/market/arena-entry.cpp index 93e1c0c6d..70aa2e63c 100644 --- a/src/market/arena-entry.cpp +++ b/src/market/arena-entry.cpp @@ -27,6 +27,57 @@ int ArenaEntryList::get_max_entries() const return std::ssize(arena_info) - 2; } +int ArenaEntryList::get_current_entry() const +{ + return this->current_entry; +} + +std::optional ArenaEntryList::get_defeated_entry() const +{ + return this->defeated_entry; +} + +bool ArenaEntryList::is_player_victor() const +{ + return this->current_entry == this->get_max_entries(); +} + +bool ArenaEntryList::is_player_true_victor() const +{ + return this->current_entry > this->get_max_entries(); +} + +void ArenaEntryList::increment_entry() +{ + this->current_entry++; +} + +void ArenaEntryList::reset_entry() +{ + this->current_entry = 0; + this->defeated_entry = std::nullopt; +} + +void ArenaEntryList::set_defeated_entry() +{ + this->defeated_entry = this->current_entry; +} + +void ArenaEntryList::load_current_entry(int entry) +{ + this->current_entry = entry; +} + +void ArenaEntryList::load_defeated_entry(int entry) +{ + if (entry < 0) { + this->defeated_entry = std::nullopt; + return; + } + + this->defeated_entry = entry; +} + /*! * @brief 闘技場のモンスターID及び報酬アイテムテーブル */ diff --git a/src/market/arena-entry.h b/src/market/arena-entry.h index a9c1285eb..7f00df59e 100644 --- a/src/market/arena-entry.h +++ b/src/market/arena-entry.h @@ -2,6 +2,7 @@ #include "system/baseitem-info.h" #include "system/h-type.h" +#include #include /*! @@ -30,13 +31,22 @@ public: static ArenaEntryList &get_instance(); int get_max_entries() const; + int get_current_entry() const; + std::optional get_defeated_entry() const; + bool is_player_victor() const; + bool is_player_true_victor() const; + void increment_entry(); + void reset_entry(); + void set_defeated_entry(); + void load_current_entry(int entry); + void load_defeated_entry(int entry); private: ArenaEntryList() = default; static ArenaEntryList instance; + int current_entry = 0; //!< 現在の対戦相手. + std::optional defeated_entry; //!< 負けた相手. 無敗ならnullopt. v1.5.0.1以前の敗北済セーブデータは0固定. }; extern const std::vector arena_info; - -constexpr auto ARENA_DEFEATED_OLD_VER = -MAX_SHORT; /* #include +#include namespace { enum class ArenaRecord { @@ -47,11 +48,11 @@ enum class ArenaRecord { * @param player_ptr プレイヤーへの参照ポインタ * @return まだ優勝していないか、挑戦者モンスターとの戦いではFALSE */ -static bool process_ostensible_arena_victory(PlayerType *player_ptr) +static std::optional process_ostensible_arena_victory() { auto &entries = ArenaEntryList::get_instance(); - if (player_ptr->arena_number != entries.get_max_entries()) { - return false; + if (!entries.is_player_victor()) { + return std::nullopt; } clear_bldg(5, 19); @@ -61,11 +62,10 @@ static bool process_ostensible_arena_victory(PlayerType *player_ptr) prt("", 10, 0); prt("", 11, 0); - player_ptr->au += 1000000L; msg_print(_("スペースキーで続行", "Press the space bar to continue")); msg_print(nullptr); - player_ptr->arena_number++; - return true; + entries.increment_entry(); + return 1000000; } /*! @@ -73,15 +73,15 @@ static bool process_ostensible_arena_victory(PlayerType *player_ptr) * @param player_ptr プレイヤーへの参照ポインタ * @return 最後に倒した対戦相手 (鳳凰以下は一律で鳳凰) */ -static ArenaRecord check_arena_record(PlayerType *player_ptr) +static ArenaRecord check_arena_record() { const auto &entries = ArenaEntryList::get_instance(); const auto max_entries = entries.get_max_entries(); - if (player_ptr->arena_number <= max_entries) { + if (entries.get_current_entry() <= max_entries) { return ArenaRecord::FENGFUANG; } - if (player_ptr->arena_number < max_entries + 2) { + if (entries.get_current_entry() < max_entries + 2) { return ArenaRecord::POWER_WYRM; } @@ -115,11 +115,13 @@ static bool check_battle_metal_babble(PlayerType *player_ptr) */ static bool go_to_arena(PlayerType *player_ptr) { - if (process_ostensible_arena_victory(player_ptr)) { + const auto prize_money = process_ostensible_arena_victory(); + if (prize_money) { + player_ptr->au += *prize_money; return false; } - const auto arena_record = check_arena_record(player_ptr); + const auto arena_record = check_arena_record(); if (arena_record == ArenaRecord::METAL_BABBLE) { msg_print(_("あなたはアリーナに入り、しばらくの間栄光にひたった。", "You enter the arena briefly and bask in your glory.")); msg_print(nullptr); @@ -147,20 +149,20 @@ static bool go_to_arena(PlayerType *player_ptr) static void see_arena_poster(PlayerType *player_ptr) { const auto &entries = ArenaEntryList::get_instance(); - const auto max_entries = entries.get_max_entries(); - if (player_ptr->arena_number == max_entries) { + if (entries.is_player_victor()) { msg_print(_("あなたは勝利者だ。 アリーナでのセレモニーに参加しなさい。", "You are victorious. Enter the arena for the ceremony.")); return; } - if (player_ptr->arena_number > max_entries) { + if (entries.is_player_true_victor()) { msg_print(_("あなたはすべての敵に勝利した。", "You have won against all foes.")); return; } - const auto &monrace = monraces_info[arena_info[player_ptr->arena_number].r_idx]; + const auto current_entry = entries.get_current_entry(); + const auto &monrace = MonraceList::get_instance().get_monrace(arena_info[current_entry].r_idx); msg_format(_("%s に挑戦するものはいないか?", "Do I hear any challenges against: %s"), monrace.name.data()); - LoreTracker::get_instance().set_trackee(arena_info[player_ptr->arena_number].r_idx); + LoreTracker::get_instance().set_trackee(monrace.idx); handle_stuff(player_ptr); } diff --git a/src/monster-floor/monster-death.cpp b/src/monster-floor/monster-death.cpp index f79932c6b..9bc388eff 100644 --- a/src/monster-floor/monster-death.cpp +++ b/src/monster-floor/monster-death.cpp @@ -82,14 +82,14 @@ static void on_defeat_arena_monster(PlayerType *player_ptr, MonsterDeath *md_ptr w_ptr->set_arena(true); auto &entries = ArenaEntryList::get_instance(); - const auto max_entries = entries.get_max_entries(); - if (player_ptr->arena_number > max_entries) { + const auto is_true_victor = entries.is_player_true_victor(); + if (is_true_victor) { msg_print(_("素晴らしい!君こそ真の勝利者だ。", "You are a Genuine Champion!")); } else { msg_print(_("勝利!チャンピオンへの道を進んでいる。", "Victorious! You're on your way to becoming Champion.")); } - const auto &arena = arena_info[player_ptr->arena_number]; + const auto &arena = arena_info[entries.get_current_entry()]; const auto tval = arena.key.tval(); if (tval > ItemKindType::NONE) { ItemEntity item(arena.key); @@ -97,17 +97,17 @@ static void on_defeat_arena_monster(PlayerType *player_ptr, MonsterDeath *md_ptr (void)drop_near(player_ptr, &item, -1, md_ptr->md_y, md_ptr->md_x); } - if (player_ptr->arena_number > max_entries) { - player_ptr->arena_number++; + if (is_true_victor) { + entries.increment_entry(); } - player_ptr->arena_number++; + entries.increment_entry(); if (!record_arena) { return; } const auto m_name = monster_desc(player_ptr, md_ptr->m_ptr, MD_WRONGDOER_NAME); - exe_write_diary(floor, DiaryKind::ARENA, player_ptr->arena_number, m_name); + exe_write_diary(floor, DiaryKind::ARENA, 0, m_name); } static void drop_corpse(PlayerType *player_ptr, MonsterDeath *md_ptr) diff --git a/src/player/player-damage.cpp b/src/player/player-damage.cpp index 7ef144405..de6ec9f25 100644 --- a/src/player/player-damage.cpp +++ b/src/player/player-damage.cpp @@ -376,11 +376,14 @@ int take_hit(PlayerType *player_ptr, int damage_type, int damage, std::string_vi } if (floor.inside_arena) { - const auto &m_name = monraces_info[arena_info[player_ptr->arena_number].r_idx].name; + auto &entries = ArenaEntryList::get_instance(); + entries.set_defeated_entry(); + const auto current_entry = entries.get_current_entry(); + const auto &m_name = monraces_info[arena_info[current_entry].r_idx].name; msg_format(_("あなたは%sの前に敗れ去った。", "You are beaten by %s."), m_name.data()); msg_print(nullptr); if (record_arena) { - exe_write_diary(floor, DiaryKind::ARENA, -1 - player_ptr->arena_number, m_name); + exe_write_diary(floor, DiaryKind::ARENA, 0, m_name); } } else { const auto q_idx = floor.get_quest_id(); diff --git a/src/player/player-status.cpp b/src/player/player-status.cpp index af51511be..74b4d45df 100644 --- a/src/player/player-status.cpp +++ b/src/player/player-status.cpp @@ -3088,7 +3088,8 @@ int16_t modify_stat_value(int value, int amount) long calc_score(PlayerType *player_ptr) { const auto &entries = ArenaEntryList::get_instance(); - const auto arena_win = std::min(player_ptr->arena_number, entries.get_max_entries()); + const auto current_entry = entries.get_current_entry(); + const auto arena_win = std::min(current_entry, entries.get_max_entries()); auto mult = 100; if (!preserve_mode) { mult += 10; @@ -3145,7 +3146,7 @@ long calc_score(PlayerType *player_ptr) point_l /= 100; uint32_t point = (point_h << 16) + (point_l); - if (player_ptr->arena_number >= 0) { + if (current_entry >= 0) { point += (arena_win * arena_win * (arena_win > 29 ? 1000 : 100)); } diff --git a/src/save/player-writer.cpp b/src/save/player-writer.cpp index 77460cede..fb92594f6 100644 --- a/src/save/player-writer.cpp +++ b/src/save/player-writer.cpp @@ -1,6 +1,7 @@ #include "save/player-writer.h" #include "cmd-building/cmd-building.h" #include "game-option/birth-options.h" +#include "market/arena-entry.h" #include "player-base/player-class.h" #include "player/player-skill.h" #include "save/info-writer.h" @@ -118,8 +119,10 @@ void wr_player(PlayerType *player_ptr) } wr_s16b(player_ptr->town_num); - - wr_s16b(player_ptr->arena_number); + const auto &entries = ArenaEntryList::get_instance(); + wr_s16b(static_cast(entries.get_current_entry())); + const auto defeated_entry = entries.get_defeated_entry(); + wr_s16b(static_cast(defeated_entry.value_or(-1))); wr_s16b(player_ptr->current_floor_ptr->inside_arena); wr_s16b(enum2i(player_ptr->current_floor_ptr->quest_number)); wr_s16b(AngbandSystem::get_instance().is_phase_out()); diff --git a/src/system/angband-version.h b/src/system/angband-version.h index 1dc49eb17..2be829613 100644 --- a/src/system/angband-version.h +++ b/src/system/angband-version.h @@ -29,7 +29,7 @@ constexpr std::string_view ROOT_VARIANT_NAME("Hengband"); /*! * @brief セーブファイルのバージョン(3.0.0から導入) */ -constexpr uint32_t SAVEFILE_VERSION = 22; +constexpr uint32_t SAVEFILE_VERSION = 23; /*! * @brief バージョンが開発版が安定版かを返す(廃止予定) diff --git a/src/system/player-type-definition.cpp b/src/system/player-type-definition.cpp index bc774c4b4..83e402a62 100644 --- a/src/system/player-type-definition.cpp +++ b/src/system/player-type-definition.cpp @@ -2,7 +2,6 @@ #include "floor/geometry.h" #include "market/arena-entry.h" #include "system/angband-exceptions.h" -#include "system/monster-race-info.h" // @todo 暫定、後で消す. #include "system/redrawing-flags-updater.h" #include "timed-effect/timed-effects.h" #include "world/world.h" @@ -25,7 +24,7 @@ PlayerType::PlayerType() bool PlayerType::is_true_winner() const { const auto &entries = ArenaEntryList::get_instance(); - return (w_ptr->total_winner > 0) && (this->arena_number > entries.get_max_entries() + 2); + return (w_ptr->total_winner > 0) && (entries.is_player_true_victor()); } std::shared_ptr PlayerType::effects() const diff --git a/src/system/player-type-definition.h b/src/system/player-type-definition.h index 0a7359d6c..fe4023f8b 100644 --- a/src/system/player-type-definition.h +++ b/src/system/player-type-definition.h @@ -64,7 +64,6 @@ public: PLAYER_LEVEL lev{}; /* Level */ int16_t town_num{}; /* Current town number */ - int16_t arena_number{}; /* monster number in on_defeat_arena_monster -KMW- */ POSITION wilderness_x{}; /* Coordinates in the wilderness */ POSITION wilderness_y{}; -- 2.11.0