OSDN Git Service

Merge branch 'macos-develop' into macos-3-0-0 macos-3-0-0 vmacos3.0.1-beta6
authorEric Branlund <ebranlund@fastmail.com>
Mon, 22 Jan 2024 18:12:56 +0000 (11:12 -0700)
committerEric Branlund <ebranlund@fastmail.com>
Mon, 22 Jan 2024 18:12:56 +0000 (11:12 -0700)
1905 files changed:
.editorconfig
.github/scripts/check-bom.sh
.github/scripts/check-format.sh
.github/workflows/build-test-with-msvc.yml [new file with mode: 0644]
.github/workflows/build-with-autotools.yml
.github/workflows/create-cache-for-ccache.yml
.github/workflows/create-release.yml [new file with mode: 0644]
.github/workflows/publish-spoiler-page.yml
.github/workflows/pull-request-status-check.yml
.github/workflows/release.yaml [new file with mode: 0644]
.github/workflows/test-linux-build.yaml
.github/workflows/test-mac-build.yaml
Build-Windows-Release-Package.ps1
Hengband/.gitattributes [new file with mode: 0644]
Hengband/Hengband/Hengband.vcxproj
Hengband/Hengband/Hengband.vcxproj.filters
Hengband/Hengband/curl/include/curl/curl.h
Hengband/Hengband/curl/include/curl/curlver.h
Hengband/Hengband/curl/include/curl/easy.h
Hengband/Hengband/curl/include/curl/header.h [new file with mode: 0644]
Hengband/Hengband/curl/include/curl/mprintf.h
Hengband/Hengband/curl/include/curl/multi.h
Hengband/Hengband/curl/include/curl/options.h
Hengband/Hengband/curl/include/curl/stdcheaders.h
Hengband/Hengband/curl/include/curl/system.h
Hengband/Hengband/curl/include/curl/typecheck-gcc.h
Hengband/Hengband/curl/include/curl/urlapi.h
Hengband/Hengband/curl/include/curl/websockets.h [new file with mode: 0644]
Hengband/Hengband/curl/lib/libcurl_a.lib [new file with mode: 0755]
Hengband/Hengband/curl/lib/libcurl_a_debug.lib [new file with mode: 0755]
Hengband/Hengband/curl/x86 Debug/libcurl_a_debug.lib [deleted file]
Hengband/Hengband/curl/x86 Release/libcurl_a.lib [deleted file]
Hengband/Hengband/packages.config
Makefile.am
THIRD-PARTY-NOTICES.txt [new file with mode: 0644]
configure.ac
doxygen/Hengband.doxyfile
hengband.spec
lib/edit/ArtifactDefinitions.txt
lib/edit/BaseitemDefinitions.txt
lib/edit/EgoDefinitions.txt
lib/edit/MonsterRaceDefinitions.txt
lib/edit/QuestDefinitionList.txt
lib/edit/quests/013_NodeOfArcane.txt [new file with mode: 0644]
lib/edit/quests/034_DumpWitness.txt
lib/edit/quests/Makefile.am
lib/edit/towns/05_Zul.txt
lib/file/Makefile.am
lib/file/books/Makefile.am [new file with mode: 0644]
lib/file/books/book-000_en.txt [new file with mode: 0644]
lib/file/books/book-000_jp.txt [moved from lib/file/book-0_jp.txt with 100% similarity]
lib/file/books/book-001_en.txt [new file with mode: 0644]
lib/file/books/book-001_jp.txt [new file with mode: 0644]
lib/file/books/book-002_en.txt [new file with mode: 0644]
lib/file/books/book-002_jp.txt [new file with mode: 0644]
lib/file/books/book-003_en.txt [new file with mode: 0644]
lib/file/books/book-003_jp.txt [new file with mode: 0644]
lib/file/books/book-004_en.txt [new file with mode: 0644]
lib/file/books/book-004_jp.txt [new file with mode: 0644]
lib/file/books/book-005_en.txt [new file with mode: 0644]
lib/file/books/book-005_jp.txt [new file with mode: 0644]
lib/file/books/book-006_en.txt [new file with mode: 0644]
lib/file/books/book-006_jp.txt [new file with mode: 0644]
lib/file/books/book-007_en.txt [new file with mode: 0644]
lib/file/books/book-007_jp.txt [new file with mode: 0644]
readme-eng.md
src/Makefile.am
src/action/action-limited.cpp
src/action/action-limited.h
src/action/activation-execution.cpp
src/action/activation-execution.h
src/action/movement-execution.cpp
src/action/movement-execution.h
src/action/mutation-execution.cpp
src/action/mutation-execution.h
src/action/open-close-execution.cpp
src/action/open-close-execution.h
src/action/open-util.cpp
src/action/open-util.h
src/action/racial-execution.cpp
src/action/racial-execution.h
src/action/run-execution.cpp
src/action/run-execution.h
src/action/travel-execution.cpp
src/action/travel-execution.h
src/action/tunnel-execution.cpp
src/action/tunnel-execution.h
src/action/weapon-shield.cpp
src/action/weapon-shield.h
src/ang_jp.rc
src/artifact/artifact-info.cpp [deleted file]
src/artifact/artifact-info.h [deleted file]
src/artifact/fixed-art-generator.cpp
src/artifact/fixed-art-generator.h
src/artifact/fixed-art-types.h
src/artifact/random-art-activation.cpp
src/artifact/random-art-activation.h
src/artifact/random-art-bias-types.h
src/artifact/random-art-characteristics.cpp
src/artifact/random-art-characteristics.h
src/artifact/random-art-effects.h
src/artifact/random-art-generator.cpp
src/artifact/random-art-generator.h
src/artifact/random-art-misc.cpp
src/artifact/random-art-misc.h
src/artifact/random-art-pval-investor.cpp
src/artifact/random-art-pval-investor.h
src/artifact/random-art-resistance.cpp
src/artifact/random-art-resistance.h
src/artifact/random-art-slay.cpp
src/artifact/random-art-slay.h
src/autopick/autopick-command-menu.cpp
src/autopick/autopick-command-menu.h
src/autopick/autopick-commands-table.h
src/autopick/autopick-describer.cpp
src/autopick/autopick-describer.h
src/autopick/autopick-destroyer.cpp
src/autopick/autopick-destroyer.h
src/autopick/autopick-dirty-flags.h
src/autopick/autopick-drawer.cpp
src/autopick/autopick-drawer.h
src/autopick/autopick-editor-command.cpp
src/autopick/autopick-editor-command.h
src/autopick/autopick-editor-util.cpp
src/autopick/autopick-editor-util.h
src/autopick/autopick-entry.cpp
src/autopick/autopick-entry.h
src/autopick/autopick-finder.cpp
src/autopick/autopick-finder.h
src/autopick/autopick-flags-table.h
src/autopick/autopick-initializer.cpp
src/autopick/autopick-initializer.h
src/autopick/autopick-inserter-killer.cpp
src/autopick/autopick-inserter-killer.h
src/autopick/autopick-key-flag-process.h
src/autopick/autopick-keys-table.h
src/autopick/autopick-matcher.cpp
src/autopick/autopick-matcher.h
src/autopick/autopick-menu-data-table.cpp
src/autopick/autopick-menu-data-table.h
src/autopick/autopick-methods-table.h
src/autopick/autopick-pref-processor.cpp
src/autopick/autopick-pref-processor.h
src/autopick/autopick-reader-writer.cpp
src/autopick/autopick-reader-writer.h
src/autopick/autopick-registry.cpp
src/autopick/autopick-registry.h
src/autopick/autopick-util.cpp
src/autopick/autopick-util.h
src/autopick/autopick.cpp
src/autopick/autopick.h
src/avatar/avatar-changer.cpp
src/avatar/avatar-changer.h
src/avatar/avatar.cpp
src/avatar/avatar.h
src/birth/auto-roller.cpp
src/birth/auto-roller.h
src/birth/birth-body-spec.cpp
src/birth/birth-body-spec.h
src/birth/birth-explanations-table.cpp
src/birth/birth-explanations-table.h
src/birth/birth-select-class.cpp
src/birth/birth-select-class.h
src/birth/birth-select-personality.cpp
src/birth/birth-select-personality.h
src/birth/birth-select-race.cpp
src/birth/birth-select-race.h
src/birth/birth-select-realm.cpp
src/birth/birth-select-realm.h
src/birth/birth-stat.cpp
src/birth/birth-stat.h
src/birth/birth-util.cpp
src/birth/birth-util.h
src/birth/birth-wizard.cpp
src/birth/birth-wizard.h
src/birth/character-builder.cpp
src/birth/character-builder.h
src/birth/game-play-initializer.cpp
src/birth/game-play-initializer.h
src/birth/history-editor.cpp
src/birth/history-editor.h
src/birth/history-generator.cpp
src/birth/history-generator.h
src/birth/history.cpp
src/birth/history.h
src/birth/initial-equipments-table.cpp
src/birth/initial-equipments-table.h
src/birth/inventory-initializer.cpp
src/birth/inventory-initializer.h
src/birth/quick-start.cpp
src/birth/quick-start.h
src/blue-magic/blue-magic-ball-bolt.cpp
src/blue-magic/blue-magic-ball-bolt.h
src/blue-magic/blue-magic-breath.cpp
src/blue-magic/blue-magic-breath.h
src/blue-magic/blue-magic-caster.cpp
src/blue-magic/blue-magic-caster.h
src/blue-magic/blue-magic-checker.cpp
src/blue-magic/blue-magic-checker.h
src/blue-magic/blue-magic-spirit-curse.cpp
src/blue-magic/blue-magic-spirit-curse.h
src/blue-magic/blue-magic-status.cpp
src/blue-magic/blue-magic-status.h
src/blue-magic/blue-magic-summon.cpp
src/blue-magic/blue-magic-summon.h
src/blue-magic/blue-magic-util.cpp
src/blue-magic/blue-magic-util.h
src/blue-magic/learnt-info.cpp
src/blue-magic/learnt-info.h
src/blue-magic/learnt-power-getter.cpp
src/blue-magic/learnt-power-getter.h
src/cmd-action/cmd-attack.cpp
src/cmd-action/cmd-attack.h
src/cmd-action/cmd-hissatsu.cpp
src/cmd-action/cmd-hissatsu.h
src/cmd-action/cmd-mane.cpp
src/cmd-action/cmd-mane.h
src/cmd-action/cmd-mind.cpp
src/cmd-action/cmd-mind.h
src/cmd-action/cmd-move.cpp
src/cmd-action/cmd-move.h
src/cmd-action/cmd-open-close.cpp
src/cmd-action/cmd-open-close.h
src/cmd-action/cmd-others.cpp
src/cmd-action/cmd-others.h
src/cmd-action/cmd-pet.cpp
src/cmd-action/cmd-pet.h
src/cmd-action/cmd-racial.cpp
src/cmd-action/cmd-racial.h
src/cmd-action/cmd-shoot.cpp
src/cmd-action/cmd-shoot.h
src/cmd-action/cmd-spell.cpp
src/cmd-action/cmd-spell.h
src/cmd-action/cmd-travel.cpp
src/cmd-action/cmd-travel.h
src/cmd-action/cmd-tunnel.cpp
src/cmd-action/cmd-tunnel.h
src/cmd-building/cmd-building.cpp
src/cmd-building/cmd-building.h
src/cmd-building/cmd-inn.cpp
src/cmd-building/cmd-inn.h
src/cmd-io/cmd-autopick.cpp
src/cmd-io/cmd-autopick.h
src/cmd-io/cmd-diary.cpp
src/cmd-io/cmd-diary.h
src/cmd-io/cmd-dump.cpp
src/cmd-io/cmd-dump.h
src/cmd-io/cmd-floor.cpp
src/cmd-io/cmd-floor.h
src/cmd-io/cmd-gameoption.cpp
src/cmd-io/cmd-gameoption.h
src/cmd-io/cmd-help.cpp
src/cmd-io/cmd-help.h
src/cmd-io/cmd-knowledge.cpp
src/cmd-io/cmd-knowledge.h
src/cmd-io/cmd-lore.cpp
src/cmd-io/cmd-lore.h
src/cmd-io/cmd-macro.cpp
src/cmd-io/cmd-macro.h
src/cmd-io/cmd-menu-content-table.cpp
src/cmd-io/cmd-menu-content-table.h
src/cmd-io/cmd-process-screen.cpp
src/cmd-io/cmd-process-screen.h
src/cmd-io/cmd-save.cpp
src/cmd-io/cmd-save.h
src/cmd-io/diary-subtitle-table.cpp
src/cmd-io/diary-subtitle-table.h
src/cmd-io/feeling-table.cpp
src/cmd-io/feeling-table.h
src/cmd-io/macro-util.cpp
src/cmd-io/macro-util.h
src/cmd-item/cmd-destroy.cpp
src/cmd-item/cmd-destroy.h
src/cmd-item/cmd-eat.cpp
src/cmd-item/cmd-eat.h
src/cmd-item/cmd-equipment.cpp
src/cmd-item/cmd-equipment.h
src/cmd-item/cmd-item.cpp
src/cmd-item/cmd-item.h
src/cmd-item/cmd-magiceat.cpp
src/cmd-item/cmd-magiceat.h
src/cmd-item/cmd-quaff.cpp
src/cmd-item/cmd-quaff.h
src/cmd-item/cmd-read.cpp
src/cmd-item/cmd-read.h
src/cmd-item/cmd-refill.cpp
src/cmd-item/cmd-refill.h
src/cmd-item/cmd-throw.cpp
src/cmd-item/cmd-throw.h
src/cmd-item/cmd-usestaff.cpp
src/cmd-item/cmd-usestaff.h
src/cmd-item/cmd-zaprod.cpp
src/cmd-item/cmd-zaprod.h
src/cmd-item/cmd-zapwand.cpp
src/cmd-item/cmd-zapwand.h
src/cmd-visual/cmd-draw.cpp
src/cmd-visual/cmd-draw.h
src/cmd-visual/cmd-map.cpp
src/cmd-visual/cmd-map.h
src/cmd-visual/cmd-visuals.cpp
src/cmd-visual/cmd-visuals.h
src/cocoa/Angband-Cocoa.xml
src/cocoa/AngbandAudio.mm
src/cocoa/SoundAndMusic.mm
src/cocoa/en.lproj/Credits.html [new file with mode: 0644]
src/cocoa/ja.lproj/Credits.html [new file with mode: 0644]
src/combat/attack-accuracy.cpp
src/combat/attack-accuracy.h
src/combat/attack-criticality.cpp
src/combat/attack-criticality.h
src/combat/attack-power-table.cpp
src/combat/attack-power-table.h
src/combat/aura-counterattack.cpp
src/combat/aura-counterattack.h
src/combat/combat-options-type.h
src/combat/hallucination-attacks-table.cpp
src/combat/hallucination-attacks-table.h
src/combat/martial-arts-table.cpp
src/combat/martial-arts-table.h
src/combat/shoot.cpp
src/combat/shoot.h
src/combat/slaying.cpp
src/combat/slaying.h
src/core/asking-player.cpp
src/core/asking-player.h
src/core/disturbance.cpp
src/core/disturbance.h
src/core/game-closer.cpp
src/core/game-closer.h
src/core/game-play.cpp
src/core/game-play.h
src/core/magic-effects-timeout-reducer.cpp
src/core/magic-effects-timeout-reducer.h
src/core/object-compressor.cpp
src/core/object-compressor.h
src/core/player-processor.cpp
src/core/player-processor.h
src/core/player-redraw-types.h [deleted file]
src/core/player-update-types.h [deleted file]
src/core/score-util.cpp
src/core/score-util.h
src/core/scores.cpp
src/core/scores.h
src/core/show-file.cpp
src/core/show-file.h
src/core/special-internal-keys.h
src/core/speed-table.cpp
src/core/speed-table.h
src/core/stuff-handler.cpp
src/core/stuff-handler.h
src/core/turn-compensator.cpp
src/core/turn-compensator.h
src/core/visuals-reseter.cpp
src/core/visuals-reseter.h
src/core/window-redrawer.cpp
src/core/window-redrawer.h
src/dungeon/dungeon-flag-mask.h
src/dungeon/dungeon-flag-types.h
src/dungeon/dungeon-processor.cpp
src/dungeon/dungeon-processor.h
src/dungeon/quest-completion-checker.cpp
src/dungeon/quest-completion-checker.h
src/dungeon/quest-monster-placer.cpp
src/dungeon/quest-monster-placer.h
src/dungeon/quest.cpp
src/dungeon/quest.h
src/effect/attribute-types.h
src/effect/effect-characteristics.h
src/effect/effect-feature.cpp
src/effect/effect-feature.h
src/effect/effect-item.cpp
src/effect/effect-item.h
src/effect/effect-monster-charm.cpp
src/effect/effect-monster-charm.h
src/effect/effect-monster-curse.cpp
src/effect/effect-monster-curse.h
src/effect/effect-monster-evil.cpp
src/effect/effect-monster-evil.h
src/effect/effect-monster-lite-dark.cpp
src/effect/effect-monster-lite-dark.h
src/effect/effect-monster-oldies.cpp
src/effect/effect-monster-oldies.h
src/effect/effect-monster-psi.cpp
src/effect/effect-monster-psi.h
src/effect/effect-monster-resist-hurt.cpp
src/effect/effect-monster-resist-hurt.h
src/effect/effect-monster-spirit.cpp
src/effect/effect-monster-spirit.h
src/effect/effect-monster-switcher.cpp
src/effect/effect-monster-switcher.h
src/effect/effect-monster-util.cpp
src/effect/effect-monster-util.h
src/effect/effect-monster.cpp
src/effect/effect-monster.h
src/effect/effect-player-curse.cpp
src/effect/effect-player-curse.h
src/effect/effect-player-oldies.cpp
src/effect/effect-player-oldies.h
src/effect/effect-player-resist-hurt.cpp
src/effect/effect-player-resist-hurt.h
src/effect/effect-player-spirit.cpp
src/effect/effect-player-spirit.h
src/effect/effect-player-switcher.cpp
src/effect/effect-player-switcher.h
src/effect/effect-player.cpp
src/effect/effect-player.h
src/effect/effect-processor.cpp
src/effect/effect-processor.h
src/effect/spells-effect-util.cpp
src/effect/spells-effect-util.h
src/external-lib/include-json.h [new file with mode: 0644]
src/external-lib/json.hpp [new file with mode: 0644]
src/flavor/flag-inscriptions-table.cpp
src/flavor/flag-inscriptions-table.h
src/flavor/flavor-describer.cpp
src/flavor/flavor-describer.h
src/flavor/flavor-util.cpp
src/flavor/flavor-util.h
src/flavor/named-item-describer.cpp
src/flavor/named-item-describer.h
src/flavor/object-flavor-types.h
src/flavor/object-flavor.cpp
src/flavor/object-flavor.h
src/flavor/tval-description-switcher.cpp
src/flavor/tval-description-switcher.h
src/floor/cave-generator.cpp
src/floor/cave-generator.h
src/floor/cave.cpp
src/floor/cave.h
src/floor/dungeon-tunnel-util.cpp
src/floor/dungeon-tunnel-util.h
src/floor/fixed-map-generator.cpp
src/floor/fixed-map-generator.h
src/floor/floor-allocation-types.h
src/floor/floor-base-definitions.h
src/floor/floor-changer.cpp
src/floor/floor-changer.h
src/floor/floor-events.cpp
src/floor/floor-events.h
src/floor/floor-generator-util.h
src/floor/floor-generator.cpp
src/floor/floor-generator.h
src/floor/floor-leaver.cpp
src/floor/floor-leaver.h
src/floor/floor-mode-changer.cpp
src/floor/floor-mode-changer.h
src/floor/floor-object.cpp
src/floor/floor-object.h
src/floor/floor-save-util.cpp
src/floor/floor-save-util.h
src/floor/floor-save.cpp
src/floor/floor-save.h
src/floor/floor-streams.cpp
src/floor/floor-streams.h
src/floor/floor-town.cpp
src/floor/floor-town.h
src/floor/floor-util.cpp
src/floor/floor-util.h
src/floor/geometry.cpp
src/floor/geometry.h
src/floor/line-of-sight.cpp
src/floor/line-of-sight.h
src/floor/object-allocator.cpp
src/floor/object-allocator.h
src/floor/object-scanner.cpp
src/floor/object-scanner.h
src/floor/pattern-walk.cpp
src/floor/pattern-walk.h
src/floor/tunnel-generator.cpp
src/floor/tunnel-generator.h
src/floor/wild.cpp
src/floor/wild.h
src/game-option/auto-destruction-options.cpp
src/game-option/auto-destruction-options.h
src/game-option/birth-options.cpp
src/game-option/birth-options.h
src/game-option/cheat-options.cpp
src/game-option/cheat-options.h
src/game-option/cheat-types.h
src/game-option/disturbance-options.cpp
src/game-option/disturbance-options.h
src/game-option/game-play-options.cpp
src/game-option/game-play-options.h
src/game-option/input-options.cpp
src/game-option/input-options.h
src/game-option/keymap-directory-getter.cpp
src/game-option/keymap-directory-getter.h
src/game-option/map-screen-options.cpp
src/game-option/map-screen-options.h
src/game-option/option-flags.cpp
src/game-option/option-flags.h
src/game-option/option-types-table.cpp
src/game-option/option-types-table.h
src/game-option/play-record-options.cpp
src/game-option/play-record-options.h
src/game-option/runtime-arguments.cpp
src/game-option/runtime-arguments.h
src/game-option/special-options.cpp
src/game-option/special-options.h
src/game-option/text-display-options.cpp
src/game-option/text-display-options.h
src/grid/door.cpp
src/grid/door.h
src/grid/feature-action-flags.cpp
src/grid/feature-action-flags.h
src/grid/feature-flag-types.h
src/grid/feature-generator.cpp
src/grid/feature-generator.h
src/grid/feature.cpp
src/grid/feature.h
src/grid/grid.cpp
src/grid/grid.h
src/grid/lighting-colors-table.cpp
src/grid/lighting-colors-table.h
src/grid/object-placer.cpp
src/grid/object-placer.h
src/grid/stair.cpp
src/grid/stair.h
src/grid/trap.cpp
src/grid/trap.h
src/hpmp/hp-mp-processor.cpp
src/hpmp/hp-mp-processor.h
src/hpmp/hp-mp-regenerator.cpp
src/hpmp/hp-mp-regenerator.h
src/info-reader/artifact-reader.cpp
src/info-reader/artifact-reader.h
src/info-reader/baseitem-reader.cpp
src/info-reader/baseitem-reader.h
src/info-reader/baseitem-tokens-table.cpp
src/info-reader/baseitem-tokens-table.h
src/info-reader/dungeon-info-tokens-table.cpp
src/info-reader/dungeon-info-tokens-table.h
src/info-reader/dungeon-reader.cpp
src/info-reader/dungeon-reader.h
src/info-reader/ego-reader.cpp
src/info-reader/ego-reader.h
src/info-reader/feature-info-tokens-table.cpp
src/info-reader/feature-info-tokens-table.h
src/info-reader/feature-reader.cpp
src/info-reader/feature-reader.h
src/info-reader/fixed-map-parser.cpp
src/info-reader/fixed-map-parser.h
src/info-reader/general-parser.cpp
src/info-reader/general-parser.h
src/info-reader/info-reader-util.cpp
src/info-reader/info-reader-util.h
src/info-reader/magic-reader.cpp
src/info-reader/magic-reader.h
src/info-reader/parse-error-types.h
src/info-reader/race-info-tokens-table.cpp
src/info-reader/race-info-tokens-table.h
src/info-reader/race-reader.cpp
src/info-reader/race-reader.h
src/info-reader/random-grid-effect-types.h
src/info-reader/skill-reader.cpp
src/info-reader/skill-reader.h
src/info-reader/vault-reader.cpp
src/info-reader/vault-reader.h
src/inventory/floor-item-getter.cpp
src/inventory/floor-item-getter.h
src/inventory/inventory-curse.cpp
src/inventory/inventory-curse.h
src/inventory/inventory-damage.cpp
src/inventory/inventory-damage.h
src/inventory/inventory-describer.cpp
src/inventory/inventory-describer.h
src/inventory/inventory-object.cpp
src/inventory/inventory-object.h
src/inventory/inventory-slot-types.h
src/inventory/inventory-util.cpp
src/inventory/inventory-util.h
src/inventory/item-getter.cpp
src/inventory/item-getter.h
src/inventory/item-selection-util.cpp
src/inventory/item-selection-util.h
src/inventory/pack-overflow.cpp
src/inventory/pack-overflow.h
src/inventory/player-inventory.cpp
src/inventory/player-inventory.h
src/inventory/recharge-processor.cpp
src/inventory/recharge-processor.h
src/io-dump/character-dump.cpp
src/io-dump/character-dump.h
src/io-dump/dump-remover.cpp
src/io-dump/dump-remover.h
src/io-dump/dump-util.cpp
src/io-dump/dump-util.h
src/io-dump/player-status-dump.cpp
src/io-dump/player-status-dump.h
src/io-dump/random-art-info-dumper.cpp
src/io-dump/random-art-info-dumper.h
src/io-dump/special-class-dump.cpp
src/io-dump/special-class-dump.h
src/io/command-repeater.cpp
src/io/command-repeater.h
src/io/cursor.cpp
src/io/cursor.h
src/io/exit-panic.cpp
src/io/exit-panic.h
src/io/files-util.cpp
src/io/files-util.h
src/io/gf-descriptions.cpp
src/io/gf-descriptions.h
src/io/inet.cpp [deleted file]
src/io/inet.h [deleted file]
src/io/input-key-acceptor.cpp
src/io/input-key-acceptor.h
src/io/input-key-processor.cpp
src/io/input-key-processor.h
src/io/input-key-requester.cpp
src/io/input-key-requester.h
src/io/interpret-pref-file.cpp
src/io/interpret-pref-file.h
src/io/mutations-dump.cpp
src/io/mutations-dump.h
src/io/pref-file-expressor.cpp
src/io/pref-file-expressor.h
src/io/read-pref-file.cpp
src/io/read-pref-file.h
src/io/record-play-movie.cpp
src/io/record-play-movie.h
src/io/report.cpp
src/io/report.h
src/io/screen-util.cpp
src/io/screen-util.h
src/io/signal-handlers.cpp
src/io/signal-handlers.h
src/io/tokenizer.cpp
src/io/tokenizer.h
src/io/uid-checker.cpp
src/io/uid-checker.h
src/io/write-diary.cpp
src/io/write-diary.h
src/item-info/flavor-initializer.cpp
src/item-info/flavor-initializer.h
src/knowledge/knowledge-autopick.cpp
src/knowledge/knowledge-autopick.h
src/knowledge/knowledge-experiences.cpp
src/knowledge/knowledge-experiences.h
src/knowledge/knowledge-features.cpp
src/knowledge/knowledge-features.h
src/knowledge/knowledge-inventory.cpp
src/knowledge/knowledge-inventory.h
src/knowledge/knowledge-items.cpp
src/knowledge/knowledge-items.h
src/knowledge/knowledge-monsters.cpp
src/knowledge/knowledge-monsters.h
src/knowledge/knowledge-mutations.cpp
src/knowledge/knowledge-mutations.h
src/knowledge/knowledge-quests.cpp
src/knowledge/knowledge-quests.h
src/knowledge/knowledge-self.cpp
src/knowledge/knowledge-self.h
src/knowledge/knowledge-uniques.cpp
src/knowledge/knowledge-uniques.h
src/knowledge/lighting-level-table.cpp
src/knowledge/lighting-level-table.h
src/knowledge/monster-group-table.cpp
src/knowledge/monster-group-table.h
src/knowledge/object-group-table.cpp
src/knowledge/object-group-table.h
src/load/angband-version-comparer.cpp
src/load/angband-version-comparer.h
src/load/birth-loader.cpp
src/load/birth-loader.h
src/load/dummy-loader.cpp
src/load/dummy-loader.h
src/load/dungeon-loader.cpp
src/load/dungeon-loader.h
src/load/extra-loader.cpp
src/load/extra-loader.h
src/load/floor-loader.cpp
src/load/floor-loader.h
src/load/info-loader.cpp
src/load/info-loader.h
src/load/inventory-loader.cpp
src/load/inventory-loader.h
src/load/item/item-loader-base.cpp
src/load/item/item-loader-base.h
src/load/item/item-loader-factory.cpp
src/load/item/item-loader-factory.h
src/load/item/item-loader-version-types.h
src/load/load-util.cpp
src/load/load-util.h
src/load/load-zangband.cpp
src/load/load-zangband.h
src/load/load.cpp
src/load/load.h
src/load/lore-loader.cpp
src/load/lore-loader.h
src/load/monster/monster-loader-base.h
src/load/monster/monster-loader-factory.cpp
src/load/monster/monster-loader-factory.h
src/load/monster/monster-loader-version-types.h
src/load/old-feature-types.h
src/load/old/item-flag-types-savefile50.h
src/load/old/item-loader-savefile50.cpp
src/load/old/item-loader-savefile50.h
src/load/old/load-v1-5-0.cpp
src/load/old/load-v1-5-0.h
src/load/old/load-v1-7-0.cpp
src/load/old/load-v1-7-0.h
src/load/old/monster-flag-types-savefile50.h
src/load/old/monster-loader-savefile50.cpp
src/load/old/monster-loader-savefile50.h
src/load/option-loader.cpp
src/load/option-loader.h
src/load/player-attack-loader.cpp
src/load/player-attack-loader.h
src/load/player-class-specific-data-loader.cpp
src/load/player-class-specific-data-loader.h
src/load/player-info-loader.cpp
src/load/player-info-loader.h
src/load/quest-loader.cpp
src/load/quest-loader.h
src/load/savedata-old-flag-types.h
src/load/store-loader.cpp
src/load/store-loader.h
src/load/world-loader.cpp
src/load/world-loader.h
src/locale/english.cpp
src/locale/english.h
src/locale/japanese.cpp
src/locale/japanese.h
src/locale/language-switcher.h
src/locale/utf-8.cpp
src/locale/utf-8.h
src/lore/combat-types-setter.cpp
src/lore/combat-types-setter.h
src/lore/lore-calculator.cpp
src/lore/lore-calculator.h
src/lore/lore-store.cpp
src/lore/lore-store.h
src/lore/lore-util.cpp
src/lore/lore-util.h
src/lore/magic-types-setter.cpp
src/lore/magic-types-setter.h
src/lore/monster-lore.cpp
src/lore/monster-lore.h
src/maid-x11.cpp
src/main-cap.cpp
src/main-cocoa.mm
src/main-gcu.cpp
src/main-unix/unix-user-ids.cpp [new file with mode: 0644]
src/main-unix/unix-user-ids.h [new file with mode: 0644]
src/main-unix/x11-gamma-builder.cpp [moved from src/main/x11-gamma-builder.cpp with 99% similarity]
src/main-unix/x11-gamma-builder.h [moved from src/main/x11-gamma-builder.h with 92% similarity]
src/main-unix/x11-type-string.cpp [moved from src/main/x11-type-string.cpp with 95% similarity]
src/main-unix/x11-type-string.h [moved from src/main/x11-type-string.h with 90% similarity]
src/main-win.cpp
src/main-win/commandline-win.cpp
src/main-win/commandline-win.h
src/main-win/graphics-win.cpp
src/main-win/graphics-win.h
src/main-win/main-win-bg.cpp
src/main-win/main-win-bg.h
src/main-win/main-win-cfg-reader.cpp
src/main-win/main-win-cfg-reader.h
src/main-win/main-win-define.h
src/main-win/main-win-exception.cpp [new file with mode: 0644]
src/main-win/main-win-exception.h [new file with mode: 0644]
src/main-win/main-win-file-utils.cpp
src/main-win/main-win-file-utils.h
src/main-win/main-win-mci.cpp
src/main-win/main-win-mci.h
src/main-win/main-win-menuitem.h
src/main-win/main-win-mmsystem.h
src/main-win/main-win-music.cpp
src/main-win/main-win-music.h
src/main-win/main-win-sound.cpp
src/main-win/main-win-sound.h
src/main-win/main-win-term.cpp
src/main-win/main-win-term.h
src/main-win/main-win-tokenizer.cpp
src/main-win/main-win-tokenizer.h
src/main-win/main-win-utils.cpp
src/main-win/main-win-utils.h
src/main-win/wav-reader.cpp
src/main-win/wav-reader.h
src/main-x11.cpp
src/main.cpp
src/main/angband-headers.cpp
src/main/angband-headers.h
src/main/angband-initializer.cpp
src/main/angband-initializer.h
src/main/game-data-initializer.cpp
src/main/game-data-initializer.h
src/main/info-initializer.cpp
src/main/info-initializer.h
src/main/init-error-messages-table.cpp
src/main/init-error-messages-table.h
src/main/music-definitions-table.cpp
src/main/music-definitions-table.h
src/main/scene-table-floor.cpp
src/main/scene-table-floor.h
src/main/scene-table-monster.cpp
src/main/scene-table-monster.h
src/main/scene-table.cpp
src/main/scene-table.h
src/main/sound-definitions-table.cpp
src/main/sound-definitions-table.h
src/main/sound-of-music.cpp
src/main/sound-of-music.h
src/market/arena-info-table.cpp
src/market/arena-info-table.h
src/market/arena.cpp
src/market/arena.h
src/market/bounty-prize-table.cpp
src/market/bounty-prize-table.h
src/market/bounty-type-definition.h
src/market/bounty.cpp
src/market/bounty.h
src/market/building-actions-table.h
src/market/building-craft-armor.cpp
src/market/building-craft-armor.h
src/market/building-craft-fix.cpp
src/market/building-craft-fix.h
src/market/building-craft-weapon.cpp
src/market/building-craft-weapon.h
src/market/building-enchanter.cpp
src/market/building-enchanter.h
src/market/building-initializer.cpp
src/market/building-initializer.h
src/market/building-monster.cpp
src/market/building-monster.h
src/market/building-quest.cpp
src/market/building-quest.h
src/market/building-recharger.cpp
src/market/building-recharger.h
src/market/building-service.cpp
src/market/building-service.h
src/market/building-util.cpp
src/market/building-util.h
src/market/play-gamble.cpp
src/market/play-gamble.h
src/market/poker.cpp
src/market/poker.h
src/melee/melee-postprocess.cpp
src/melee/melee-postprocess.h
src/melee/melee-spell-flags-checker.cpp
src/melee/melee-spell-flags-checker.h
src/melee/melee-spell-util.cpp
src/melee/melee-spell-util.h
src/melee/melee-spell.cpp
src/melee/melee-spell.h
src/melee/melee-switcher.cpp
src/melee/melee-switcher.h
src/melee/melee-util.cpp
src/melee/melee-util.h
src/melee/monster-attack-monster.cpp
src/melee/monster-attack-monster.h
src/mind/drs-types.h
src/mind/mind-archer.cpp
src/mind/mind-archer.h
src/mind/mind-berserker.cpp
src/mind/mind-berserker.h
src/mind/mind-blue-mage.cpp
src/mind/mind-blue-mage.h
src/mind/mind-cavalry.cpp
src/mind/mind-cavalry.h
src/mind/mind-chaos-warrior.cpp
src/mind/mind-chaos-warrior.h
src/mind/mind-elementalist.cpp
src/mind/mind-elementalist.h
src/mind/mind-explanations-table.cpp
src/mind/mind-explanations-table.h
src/mind/mind-force-trainer.cpp
src/mind/mind-force-trainer.h
src/mind/mind-hobbit.cpp
src/mind/mind-hobbit.h
src/mind/mind-info.cpp
src/mind/mind-info.h
src/mind/mind-mage.cpp
src/mind/mind-mage.h
src/mind/mind-magic-eater.cpp
src/mind/mind-magic-eater.h
src/mind/mind-magic-resistance.cpp
src/mind/mind-magic-resistance.h
src/mind/mind-mindcrafter.cpp
src/mind/mind-mindcrafter.h
src/mind/mind-mirror-master.cpp
src/mind/mind-mirror-master.h
src/mind/mind-monk.cpp
src/mind/mind-monk.h
src/mind/mind-ninja.cpp
src/mind/mind-ninja.h
src/mind/mind-numbers.h
src/mind/mind-power-getter.cpp
src/mind/mind-power-getter.h
src/mind/mind-priest.cpp
src/mind/mind-priest.h
src/mind/mind-samurai.cpp
src/mind/mind-samurai.h
src/mind/mind-sniper.cpp
src/mind/mind-sniper.h
src/mind/mind-types.h
src/mind/mind-warrior-mage.cpp
src/mind/mind-warrior-mage.h
src/mind/mind-warrior.cpp
src/mind/mind-warrior.h
src/mind/mind-weaponsmith.cpp
src/mind/mind-weaponsmith.h
src/mind/monk-attack.cpp
src/mind/monk-attack.h
src/mind/snipe-types.h
src/mind/stances-table.cpp
src/mind/stances-table.h
src/monster-attack/insults-moans.cpp
src/monster-attack/insults-moans.h
src/monster-attack/monster-attack-describer.cpp
src/monster-attack/monster-attack-describer.h
src/monster-attack/monster-attack-effect.h
src/monster-attack/monster-attack-lose.cpp
src/monster-attack/monster-attack-lose.h
src/monster-attack/monster-attack-player.cpp
src/monster-attack/monster-attack-player.h
src/monster-attack/monster-attack-processor.cpp
src/monster-attack/monster-attack-processor.h
src/monster-attack/monster-attack-status.cpp
src/monster-attack/monster-attack-status.h
src/monster-attack/monster-attack-switcher.cpp
src/monster-attack/monster-attack-switcher.h
src/monster-attack/monster-attack-table.cpp
src/monster-attack/monster-attack-table.h
src/monster-attack/monster-eating.cpp
src/monster-attack/monster-eating.h
src/monster-floor/monster-death-util.cpp
src/monster-floor/monster-death-util.h
src/monster-floor/monster-death.cpp
src/monster-floor/monster-death.h
src/monster-floor/monster-direction.cpp
src/monster-floor/monster-direction.h
src/monster-floor/monster-dist-offsets.cpp
src/monster-floor/monster-dist-offsets.h
src/monster-floor/monster-generator.cpp
src/monster-floor/monster-generator.h
src/monster-floor/monster-lite-util.cpp
src/monster-floor/monster-lite-util.h
src/monster-floor/monster-lite.cpp
src/monster-floor/monster-lite.h
src/monster-floor/monster-move.cpp
src/monster-floor/monster-move.h
src/monster-floor/monster-object.cpp
src/monster-floor/monster-object.h
src/monster-floor/monster-remover.cpp
src/monster-floor/monster-remover.h
src/monster-floor/monster-runaway.cpp
src/monster-floor/monster-runaway.h
src/monster-floor/monster-safety-hiding.cpp
src/monster-floor/monster-safety-hiding.h
src/monster-floor/monster-summon.cpp
src/monster-floor/monster-summon.h
src/monster-floor/monster-sweep-grid.cpp
src/monster-floor/monster-sweep-grid.h
src/monster-floor/one-monster-placer.cpp
src/monster-floor/one-monster-placer.h
src/monster-floor/place-monster-types.h
src/monster-floor/quantum-effect.cpp
src/monster-floor/quantum-effect.h
src/monster-floor/special-death-switcher.cpp
src/monster-floor/special-death-switcher.h
src/monster-race/monster-aura-types.h
src/monster-race/monster-kind-mask.cpp
src/monster-race/monster-kind-mask.h
src/monster-race/monster-race-hook.cpp
src/monster-race/monster-race-hook.h
src/monster-race/monster-race.cpp
src/monster-race/monster-race.h
src/monster-race/race-ability-flags.h
src/monster-race/race-ability-mask.cpp
src/monster-race/race-ability-mask.h
src/monster-race/race-behavior-flags.h
src/monster-race/race-brightness-flags.h
src/monster-race/race-brightness-mask.cpp
src/monster-race/race-brightness-mask.h
src/monster-race/race-drop-flags.h
src/monster-race/race-feature-flags.h
src/monster-race/race-feature-mask.cpp
src/monster-race/race-feature-mask.h
src/monster-race/race-flags-resistance.h
src/monster-race/race-flags1.h
src/monster-race/race-flags2.h
src/monster-race/race-flags3.h
src/monster-race/race-flags7.h
src/monster-race/race-flags8.h
src/monster-race/race-indice-types.h
src/monster-race/race-kind-flags.h
src/monster-race/race-population-flags.h
src/monster-race/race-resistance-mask.cpp
src/monster-race/race-resistance-mask.h
src/monster-race/race-sex-const.cpp [new file with mode: 0644]
src/monster-race/race-sex-const.h [new file with mode: 0644]
src/monster-race/race-speak-flags.h
src/monster-race/race-visual-flags.h
src/monster-race/race-wilderness-flags.h
src/monster/horror-descriptions.cpp
src/monster/horror-descriptions.h
src/monster/monster-compaction.cpp
src/monster/monster-compaction.h
src/monster/monster-damage.cpp
src/monster/monster-damage.h
src/monster/monster-describer.cpp
src/monster/monster-describer.h
src/monster/monster-description-types.h
src/monster/monster-flag-types.h
src/monster/monster-info.cpp
src/monster/monster-info.h
src/monster/monster-list.cpp
src/monster/monster-list.h
src/monster/monster-pain-describer.cpp
src/monster/monster-pain-describer.h
src/monster/monster-processor-util.cpp
src/monster/monster-processor-util.h
src/monster/monster-processor.cpp
src/monster/monster-processor.h
src/monster/monster-status-setter.cpp
src/monster/monster-status-setter.h
src/monster/monster-status.cpp
src/monster/monster-status.h
src/monster/monster-timed-effect-types.h
src/monster/monster-update.cpp
src/monster/monster-update.h
src/monster/monster-util.cpp
src/monster/monster-util.h
src/monster/smart-learn-types.h
src/mspell/assign-monster-spell.cpp
src/mspell/assign-monster-spell.h
src/mspell/element-resistance-checker.cpp
src/mspell/element-resistance-checker.h
src/mspell/high-resistance-checker.cpp
src/mspell/high-resistance-checker.h
src/mspell/improper-mspell-remover.cpp
src/mspell/improper-mspell-remover.h
src/mspell/monster-power-table.cpp
src/mspell/monster-power-table.h
src/mspell/mspell-attack-util.cpp
src/mspell/mspell-attack-util.h
src/mspell/mspell-attack.cpp
src/mspell/mspell-attack.h
src/mspell/mspell-attack/abstract-mspell.cpp
src/mspell/mspell-attack/abstract-mspell.h
src/mspell/mspell-attack/mspell-ball.cpp
src/mspell/mspell-attack/mspell-ball.h
src/mspell/mspell-attack/mspell-bolt.cpp
src/mspell/mspell-attack/mspell-bolt.h
src/mspell/mspell-attack/mspell-breath.cpp
src/mspell/mspell-attack/mspell-breath.h
src/mspell/mspell-attack/mspell-curse.cpp
src/mspell/mspell-attack/mspell-curse.h
src/mspell/mspell-attack/mspell-particularity.cpp
src/mspell/mspell-attack/mspell-particularity.h
src/mspell/mspell-checker.cpp
src/mspell/mspell-checker.h
src/mspell/mspell-damage-calculator.cpp
src/mspell/mspell-damage-calculator.h
src/mspell/mspell-data.cpp
src/mspell/mspell-data.h
src/mspell/mspell-dispel.cpp
src/mspell/mspell-dispel.h
src/mspell/mspell-floor.cpp
src/mspell/mspell-floor.h
src/mspell/mspell-judgement.cpp
src/mspell/mspell-judgement.h
src/mspell/mspell-learn-checker.cpp
src/mspell/mspell-learn-checker.h
src/mspell/mspell-lite.cpp
src/mspell/mspell-lite.h
src/mspell/mspell-result.h
src/mspell/mspell-selector.cpp
src/mspell/mspell-selector.h
src/mspell/mspell-special.cpp
src/mspell/mspell-special.h
src/mspell/mspell-status.cpp
src/mspell/mspell-status.h
src/mspell/mspell-summon.cpp
src/mspell/mspell-summon.h
src/mspell/mspell-util.cpp
src/mspell/mspell-util.h
src/mspell/smart-mspell-util.cpp
src/mspell/smart-mspell-util.h
src/mspell/specified-summon.cpp
src/mspell/specified-summon.h
src/mspell/summon-checker.cpp
src/mspell/summon-checker.h
src/mutation/gain-mutation-switcher.cpp
src/mutation/gain-mutation-switcher.h
src/mutation/lose-mutation-switcher.cpp
src/mutation/lose-mutation-switcher.h
src/mutation/mutation-calculator.cpp
src/mutation/mutation-calculator.h
src/mutation/mutation-flag-types.h
src/mutation/mutation-investor-remover.cpp
src/mutation/mutation-investor-remover.h
src/mutation/mutation-processor.cpp
src/mutation/mutation-processor.h
src/mutation/mutation-techniques.cpp
src/mutation/mutation-techniques.h
src/mutation/mutation-util.cpp
src/mutation/mutation-util.h
src/net/curl-easy-session.cpp [new file with mode: 0644]
src/net/curl-easy-session.h [new file with mode: 0644]
src/net/curl-slist.cpp [new file with mode: 0644]
src/net/curl-slist.h [new file with mode: 0644]
src/net/http-client.cpp [new file with mode: 0644]
src/net/http-client.h [new file with mode: 0644]
src/net/report-error.cpp [new file with mode: 0644]
src/net/report-error.h [new file with mode: 0644]
src/object-activation/activation-bolt-ball.cpp
src/object-activation/activation-bolt-ball.h
src/object-activation/activation-breath.cpp
src/object-activation/activation-breath.h
src/object-activation/activation-charm.cpp
src/object-activation/activation-charm.h
src/object-activation/activation-genocide.cpp
src/object-activation/activation-genocide.h
src/object-activation/activation-others.cpp
src/object-activation/activation-others.h
src/object-activation/activation-resistance.cpp
src/object-activation/activation-resistance.h
src/object-activation/activation-switcher.cpp
src/object-activation/activation-switcher.h
src/object-activation/activation-teleport.cpp
src/object-activation/activation-teleport.h
src/object-activation/activation-util.cpp
src/object-activation/activation-util.h
src/object-enchant/activation-info-table.cpp
src/object-enchant/activation-info-table.h
src/object-enchant/dragon-breaths-table.cpp
src/object-enchant/dragon-breaths-table.h
src/object-enchant/enchanter-base.h
src/object-enchant/enchanter-factory.cpp
src/object-enchant/enchanter-factory.h
src/object-enchant/item-apply-magic.h
src/object-enchant/item-feeling.h
src/object-enchant/item-magic-applier.cpp
src/object-enchant/item-magic-applier.h
src/object-enchant/object-boost.cpp
src/object-enchant/object-boost.h
src/object-enchant/object-curse.cpp
src/object-enchant/object-curse.h
src/object-enchant/object-ego.cpp
src/object-enchant/object-ego.h
src/object-enchant/old-ego-extra-values.h
src/object-enchant/others/apply-magic-amulet.cpp
src/object-enchant/others/apply-magic-amulet.h
src/object-enchant/others/apply-magic-lite.cpp
src/object-enchant/others/apply-magic-lite.h
src/object-enchant/others/apply-magic-others.cpp
src/object-enchant/others/apply-magic-others.h
src/object-enchant/others/apply-magic-ring.cpp
src/object-enchant/others/apply-magic-ring.h
src/object-enchant/protector/abstract-protector-enchanter.cpp
src/object-enchant/protector/abstract-protector-enchanter.h
src/object-enchant/protector/apply-magic-armor.cpp
src/object-enchant/protector/apply-magic-armor.h
src/object-enchant/protector/apply-magic-boots.cpp
src/object-enchant/protector/apply-magic-boots.h
src/object-enchant/protector/apply-magic-cloak.cpp
src/object-enchant/protector/apply-magic-cloak.h
src/object-enchant/protector/apply-magic-crown.cpp
src/object-enchant/protector/apply-magic-crown.h
src/object-enchant/protector/apply-magic-dragon-armor.cpp
src/object-enchant/protector/apply-magic-dragon-armor.h
src/object-enchant/protector/apply-magic-gloves.cpp
src/object-enchant/protector/apply-magic-gloves.h
src/object-enchant/protector/apply-magic-hard-armor.cpp
src/object-enchant/protector/apply-magic-hard-armor.h
src/object-enchant/protector/apply-magic-helm.cpp
src/object-enchant/protector/apply-magic-helm.h
src/object-enchant/protector/apply-magic-shield.cpp
src/object-enchant/protector/apply-magic-shield.h
src/object-enchant/protector/apply-magic-soft-armor.cpp
src/object-enchant/protector/apply-magic-soft-armor.h
src/object-enchant/special-object-flags.h
src/object-enchant/tr-flags.h
src/object-enchant/tr-types.h
src/object-enchant/trc-types.h
src/object-enchant/trg-types.h
src/object-enchant/vorpal-weapon.cpp
src/object-enchant/vorpal-weapon.h
src/object-enchant/weapon/abstract-weapon-enchanter.cpp
src/object-enchant/weapon/abstract-weapon-enchanter.h
src/object-enchant/weapon/apply-magic-arrow.cpp
src/object-enchant/weapon/apply-magic-arrow.h
src/object-enchant/weapon/apply-magic-bow.cpp
src/object-enchant/weapon/apply-magic-bow.h
src/object-enchant/weapon/apply-magic-digging.cpp
src/object-enchant/weapon/apply-magic-digging.h
src/object-enchant/weapon/apply-magic-hafted.cpp
src/object-enchant/weapon/apply-magic-hafted.h
src/object-enchant/weapon/apply-magic-polearm.cpp
src/object-enchant/weapon/apply-magic-polearm.h
src/object-enchant/weapon/apply-magic-sword.cpp
src/object-enchant/weapon/apply-magic-sword.h
src/object-enchant/weapon/melee-weapon-enchanter.cpp
src/object-enchant/weapon/melee-weapon-enchanter.h
src/object-hook/hook-armor.cpp
src/object-hook/hook-armor.h
src/object-hook/hook-expendable.cpp
src/object-hook/hook-expendable.h
src/object-hook/hook-magic.cpp
src/object-hook/hook-magic.h
src/object-hook/hook-perception.cpp
src/object-hook/hook-perception.h
src/object-hook/hook-quest.cpp
src/object-hook/hook-quest.h
src/object-hook/hook-weapon.cpp
src/object-hook/hook-weapon.h
src/object-use/item-use-checker.cpp
src/object-use/item-use-checker.h
src/object-use/quaff/quaff-effects.cpp
src/object-use/quaff/quaff-effects.h
src/object-use/quaff/quaff-execution.cpp
src/object-use/quaff/quaff-execution.h
src/object-use/read/gbh-shirt-read-executor.cpp
src/object-use/read/gbh-shirt-read-executor.h
src/object-use/read/parchment-read-executor.cpp
src/object-use/read/parchment-read-executor.h
src/object-use/read/read-execution.cpp
src/object-use/read/read-execution.h
src/object-use/read/read-executor-base.h
src/object-use/read/read-executor-factory.cpp
src/object-use/read/read-executor-factory.h
src/object-use/read/ring-power-read-executor.cpp
src/object-use/read/ring-power-read-executor.h
src/object-use/read/scroll-read-executor.cpp
src/object-use/read/scroll-read-executor.h
src/object-use/throw-execution.cpp
src/object-use/throw-execution.h
src/object-use/use-execution.cpp
src/object-use/use-execution.h
src/object-use/zaprod-execution.cpp
src/object-use/zaprod-execution.h
src/object-use/zapwand-execution.cpp
src/object-use/zapwand-execution.h
src/object/item-tester-hooker.cpp
src/object/item-tester-hooker.h
src/object/item-use-flags.h
src/object/lite-processor.cpp
src/object/lite-processor.h
src/object/object-broken.cpp
src/object/object-broken.h
src/object/object-flags.cpp [deleted file]
src/object/object-flags.h [deleted file]
src/object/object-index-list.cpp
src/object/object-index-list.h
src/object/object-info.cpp
src/object/object-info.h
src/object/object-kind-hook.cpp
src/object/object-kind-hook.h
src/object/object-mark-types.h
src/object/object-stack.cpp
src/object/object-stack.h
src/object/object-value-calc.cpp
src/object/object-value-calc.h
src/object/object-value.cpp
src/object/object-value.h
src/object/tval-types.h
src/object/warning.cpp
src/object/warning.h
src/perception/identification.cpp
src/perception/identification.h
src/perception/object-perception.cpp
src/perception/object-perception.h
src/perception/simple-perception.cpp
src/perception/simple-perception.h
src/pet/pet-fall-off.cpp
src/pet/pet-fall-off.h
src/pet/pet-util.cpp
src/pet/pet-util.h
src/player-ability/player-ability-types.h
src/player-ability/player-charisma.cpp
src/player-ability/player-charisma.h
src/player-ability/player-constitution.cpp
src/player-ability/player-constitution.h
src/player-ability/player-dexterity.cpp
src/player-ability/player-dexterity.h
src/player-ability/player-intelligence.cpp
src/player-ability/player-intelligence.h
src/player-ability/player-strength.cpp
src/player-ability/player-strength.h
src/player-ability/player-wisdom.cpp
src/player-ability/player-wisdom.h
src/player-attack/attack-chaos-effect.cpp
src/player-attack/attack-chaos-effect.h
src/player-attack/blood-sucking-processor.cpp
src/player-attack/blood-sucking-processor.h
src/player-attack/player-attack-util.h [deleted file]
src/player-attack/player-attack.cpp
src/player-attack/player-attack.h
src/player-base/player-class.cpp
src/player-base/player-class.h
src/player-base/player-race.cpp
src/player-base/player-race.h
src/player-info/alignment.cpp
src/player-info/alignment.h
src/player-info/bard-data-type.h
src/player-info/base-status-info.cpp
src/player-info/base-status-info.h
src/player-info/bluemage-data-type.h
src/player-info/body-improvement-info.cpp
src/player-info/body-improvement-info.h
src/player-info/class-ability-info.cpp
src/player-info/class-ability-info.h
src/player-info/class-info.cpp
src/player-info/class-info.h
src/player-info/class-specific-data.h
src/player-info/class-types.h
src/player-info/equipment-info.cpp
src/player-info/equipment-info.h
src/player-info/force-trainer-data-type.h
src/player-info/magic-eater-data-type.cpp
src/player-info/magic-eater-data-type.h
src/player-info/mane-data-type.h
src/player-info/mimic-info-table.cpp
src/player-info/mimic-info-table.h
src/player-info/monk-data-type.h
src/player-info/mutation-info.cpp
src/player-info/mutation-info.h
src/player-info/ninja-data-type.h
src/player-info/race-ability-info.cpp
src/player-info/race-ability-info.h
src/player-info/race-info.cpp
src/player-info/race-info.h
src/player-info/race-types.h
src/player-info/resistance-info.cpp
src/player-info/resistance-info.h
src/player-info/samurai-data-type.h
src/player-info/self-info-util.cpp
src/player-info/self-info-util.h
src/player-info/self-info.cpp
src/player-info/self-info.h
src/player-info/smith-data-type.h
src/player-info/sniper-data-type.h
src/player-info/spell-hex-data-type.h
src/player-info/weapon-effect-info.cpp
src/player-info/weapon-effect-info.h
src/player-status/player-basic-statistics.cpp
src/player-status/player-basic-statistics.h
src/player-status/player-energy.cpp
src/player-status/player-energy.h
src/player-status/player-hand-types.h
src/player-status/player-infravision.cpp
src/player-status/player-infravision.h
src/player-status/player-speed.cpp
src/player-status/player-speed.h
src/player-status/player-status-base.cpp
src/player-status/player-status-base.h
src/player-status/player-stealth.cpp
src/player-status/player-stealth.h
src/player/attack-defense-types.h
src/player/digestion-processor.cpp
src/player/digestion-processor.h
src/player/eldritch-horror.cpp
src/player/eldritch-horror.h
src/player/patron.cpp
src/player/patron.h
src/player/permanent-resistances.cpp
src/player/permanent-resistances.h
src/player/player-damage.cpp
src/player/player-damage.h
src/player/player-move.cpp
src/player/player-move.h
src/player/player-personality-types.h
src/player/player-personality.cpp
src/player/player-personality.h
src/player/player-realm.cpp
src/player/player-realm.h
src/player/player-sex.cpp
src/player/player-sex.h
src/player/player-skill.cpp
src/player/player-skill.h
src/player/player-status-flags.cpp
src/player/player-status-flags.h
src/player/player-status-resist.cpp
src/player/player-status-resist.h
src/player/player-status-table.cpp
src/player/player-status-table.h
src/player/player-status.cpp
src/player/player-status.h
src/player/player-view.cpp
src/player/player-view.h
src/player/process-death.cpp
src/player/process-death.h
src/player/process-name.cpp
src/player/process-name.h
src/player/race-info-table.cpp
src/player/race-info-table.h
src/player/race-resistances.cpp
src/player/race-resistances.h
src/player/special-defense-types.h
src/player/temporary-resistances.cpp
src/player/temporary-resistances.h
src/racial/class-racial-switcher.cpp
src/racial/class-racial-switcher.h
src/racial/mutation-racial-selector.cpp
src/racial/mutation-racial-selector.h
src/racial/race-racial-command-setter.cpp
src/racial/race-racial-command-setter.h
src/racial/racial-android.cpp
src/racial/racial-android.h
src/racial/racial-balrog.cpp
src/racial/racial-balrog.h
src/racial/racial-draconian.cpp
src/racial/racial-draconian.h
src/racial/racial-kutar.cpp
src/racial/racial-kutar.h
src/racial/racial-switcher.cpp
src/racial/racial-switcher.h
src/racial/racial-util.cpp
src/racial/racial-util.h
src/racial/racial-vampire.cpp
src/racial/racial-vampire.h
src/realm/realm-arcane.cpp
src/realm/realm-arcane.h
src/realm/realm-chaos.cpp
src/realm/realm-chaos.h
src/realm/realm-craft.cpp
src/realm/realm-craft.h
src/realm/realm-crusade.cpp
src/realm/realm-crusade.h
src/realm/realm-death.cpp
src/realm/realm-death.h
src/realm/realm-demon.cpp
src/realm/realm-demon.h
src/realm/realm-hex-numbers.h
src/realm/realm-hex.cpp
src/realm/realm-hex.h
src/realm/realm-hissatsu.cpp
src/realm/realm-hissatsu.h
src/realm/realm-life.cpp
src/realm/realm-life.h
src/realm/realm-names-table.cpp
src/realm/realm-names-table.h
src/realm/realm-nature.cpp
src/realm/realm-nature.h
src/realm/realm-song-numbers.h
src/realm/realm-song.cpp
src/realm/realm-song.h
src/realm/realm-sorcery.cpp
src/realm/realm-sorcery.h
src/realm/realm-trump.cpp
src/realm/realm-trump.h
src/realm/realm-types.h
src/room/cave-filler.cpp
src/room/cave-filler.h
src/room/door-definition.cpp
src/room/door-definition.h
src/room/lake-types.h
src/room/room-generator.cpp
src/room/room-generator.h
src/room/room-info-table.cpp
src/room/room-info-table.h
src/room/room-types.h
src/room/rooms-builder.cpp
src/room/rooms-builder.h
src/room/rooms-city.cpp
src/room/rooms-city.h
src/room/rooms-fractal.cpp
src/room/rooms-fractal.h
src/room/rooms-maze-vault.cpp
src/room/rooms-maze-vault.h
src/room/rooms-normal.cpp
src/room/rooms-normal.h
src/room/rooms-pit-nest.cpp
src/room/rooms-pit-nest.h
src/room/rooms-special.cpp
src/room/rooms-special.h
src/room/rooms-trap.cpp
src/room/rooms-trap.h
src/room/rooms-vault.cpp
src/room/rooms-vault.h
src/room/space-finder.cpp
src/room/space-finder.h
src/room/treasure-deployment.cpp
src/room/treasure-deployment.h
src/room/vault-builder.cpp
src/room/vault-builder.h
src/save/floor-writer.cpp
src/save/floor-writer.h
src/save/info-writer.cpp
src/save/info-writer.h
src/save/item-writer.cpp
src/save/item-writer.h
src/save/monster-writer.cpp
src/save/monster-writer.h
src/save/player-class-specific-data-writer.cpp
src/save/player-class-specific-data-writer.h
src/save/player-writer.cpp
src/save/player-writer.h
src/save/save-util.cpp
src/save/save-util.h
src/save/save.cpp
src/save/save.h
src/smith/object-smith.cpp
src/smith/object-smith.h
src/smith/smith-info.cpp
src/smith/smith-info.h
src/smith/smith-tables.cpp
src/smith/smith-tables.h
src/smith/smith-types.h
src/specific-object/blade-turner.cpp
src/specific-object/blade-turner.h
src/specific-object/bloody-moon.cpp
src/specific-object/bloody-moon.h
src/specific-object/chest.cpp
src/specific-object/chest.h
src/specific-object/death-crimson.cpp
src/specific-object/death-crimson.h
src/specific-object/death-scythe.cpp
src/specific-object/death-scythe.h
src/specific-object/monster-ball.cpp
src/specific-object/monster-ball.h
src/specific-object/muramasa.cpp
src/specific-object/muramasa.h
src/specific-object/ring-of-power.cpp
src/specific-object/ring-of-power.h
src/specific-object/stone-of-lore.cpp
src/specific-object/stone-of-lore.h
src/specific-object/toragoroshi.cpp
src/specific-object/toragoroshi.h
src/specific-object/torch.cpp
src/specific-object/torch.h
src/spell-class/spells-mirror-master.cpp
src/spell-class/spells-mirror-master.h
src/spell-kind/blood-curse.cpp
src/spell-kind/blood-curse.h
src/spell-kind/earthquake.cpp
src/spell-kind/earthquake.h
src/spell-kind/magic-item-recharger.cpp
src/spell-kind/magic-item-recharger.h
src/spell-kind/spells-beam.cpp
src/spell-kind/spells-beam.h
src/spell-kind/spells-charm.cpp
src/spell-kind/spells-charm.h
src/spell-kind/spells-curse-removal.cpp
src/spell-kind/spells-curse-removal.h
src/spell-kind/spells-detection.cpp
src/spell-kind/spells-detection.h
src/spell-kind/spells-enchant.cpp
src/spell-kind/spells-enchant.h
src/spell-kind/spells-equipment.cpp
src/spell-kind/spells-equipment.h
src/spell-kind/spells-fetcher.cpp
src/spell-kind/spells-fetcher.h
src/spell-kind/spells-floor.cpp
src/spell-kind/spells-floor.h
src/spell-kind/spells-genocide.cpp
src/spell-kind/spells-genocide.h
src/spell-kind/spells-grid.cpp
src/spell-kind/spells-grid.h
src/spell-kind/spells-launcher.cpp
src/spell-kind/spells-launcher.h
src/spell-kind/spells-lite.cpp
src/spell-kind/spells-lite.h
src/spell-kind/spells-neighbor.cpp
src/spell-kind/spells-neighbor.h
src/spell-kind/spells-perception.cpp
src/spell-kind/spells-perception.h
src/spell-kind/spells-pet.cpp
src/spell-kind/spells-pet.h
src/spell-kind/spells-polymorph.cpp
src/spell-kind/spells-polymorph.h
src/spell-kind/spells-random.cpp
src/spell-kind/spells-random.h
src/spell-kind/spells-sight.cpp
src/spell-kind/spells-sight.h
src/spell-kind/spells-specific-bolt.cpp
src/spell-kind/spells-specific-bolt.h
src/spell-kind/spells-teleport.cpp
src/spell-kind/spells-teleport.h
src/spell-kind/spells-world.cpp
src/spell-kind/spells-world.h
src/spell-realm/spells-arcane.cpp
src/spell-realm/spells-arcane.h
src/spell-realm/spells-chaos.cpp
src/spell-realm/spells-chaos.h
src/spell-realm/spells-craft.cpp
src/spell-realm/spells-craft.h
src/spell-realm/spells-crusade.cpp
src/spell-realm/spells-crusade.h
src/spell-realm/spells-demon.cpp
src/spell-realm/spells-demon.h
src/spell-realm/spells-hex.cpp
src/spell-realm/spells-hex.h
src/spell-realm/spells-nature.cpp
src/spell-realm/spells-nature.h
src/spell-realm/spells-song.cpp
src/spell-realm/spells-song.h
src/spell-realm/spells-sorcery.cpp
src/spell-realm/spells-sorcery.h
src/spell-realm/spells-trump.cpp
src/spell-realm/spells-trump.h
src/spell/range-calc.cpp
src/spell/range-calc.h
src/spell/spell-info.cpp
src/spell/spell-info.h
src/spell/spells-describer.cpp
src/spell/spells-describer.h
src/spell/spells-diceroll.cpp
src/spell/spells-diceroll.h
src/spell/spells-execution.cpp
src/spell/spells-execution.h
src/spell/spells-object.cpp
src/spell/spells-object.h
src/spell/spells-staff-only.cpp
src/spell/spells-staff-only.h
src/spell/spells-status.cpp
src/spell/spells-status.h
src/spell/spells-summon.cpp
src/spell/spells-summon.h
src/spell/spells-util.h
src/spell/summon-types.h
src/spell/technic-info-table.cpp
src/spell/technic-info-table.h
src/status/action-setter.cpp
src/status/action-setter.h
src/status/bad-status-setter.cpp
src/status/bad-status-setter.h
src/status/base-status.cpp
src/status/base-status.h
src/status/body-improvement.cpp
src/status/body-improvement.h
src/status/buff-setter.cpp
src/status/buff-setter.h
src/status/element-resistance.cpp
src/status/element-resistance.h
src/status/experience.cpp
src/status/experience.h
src/status/shape-changer.cpp
src/status/shape-changer.h
src/status/sight-setter.cpp
src/status/sight-setter.h
src/status/temporary-resistance.cpp
src/status/temporary-resistance.h
src/stdafx.cpp
src/stdafx.h
src/store/articles-on-sale.cpp
src/store/articles-on-sale.h
src/store/black-market.cpp
src/store/black-market.h
src/store/cmd-store.cpp
src/store/cmd-store.h
src/store/gold-magnification-table.cpp
src/store/gold-magnification-table.h
src/store/home.cpp
src/store/home.h
src/store/museum.cpp
src/store/museum.h
src/store/pricing.cpp
src/store/pricing.h
src/store/purchase-order.cpp
src/store/purchase-order.h
src/store/rumor.cpp
src/store/rumor.h
src/store/say-comments.cpp
src/store/say-comments.h
src/store/sell-order.cpp
src/store/sell-order.h
src/store/service-checker.cpp
src/store/service-checker.h
src/store/store-key-processor.cpp
src/store/store-key-processor.h
src/store/store-owner-comments.cpp
src/store/store-owner-comments.h
src/store/store-owners.cpp
src/store/store-owners.h
src/store/store-util.cpp
src/store/store-util.h
src/store/store.cpp
src/store/store.h
src/sv-definition/sv-amulet-types.h
src/sv-definition/sv-armor-types.h
src/sv-definition/sv-bow-types.h
src/sv-definition/sv-digging-types.h
src/sv-definition/sv-food-types.h
src/sv-definition/sv-lite-types.h
src/sv-definition/sv-other-types.h
src/sv-definition/sv-potion-types.h
src/sv-definition/sv-protector-types.h
src/sv-definition/sv-ring-types.h
src/sv-definition/sv-rod-types.h
src/sv-definition/sv-scroll-types.h
src/sv-definition/sv-staff-types.h
src/sv-definition/sv-wand-types.h
src/sv-definition/sv-weapon-types.h
src/system/alloc-entries.cpp
src/system/alloc-entries.h
src/system/angband-exceptions.h
src/system/angband-system.cpp [new file with mode: 0644]
src/system/angband-system.h [new file with mode: 0644]
src/system/angband-version.cpp
src/system/angband-version.h
src/system/angband.h
src/system/artifact-type-definition.cpp
src/system/artifact-type-definition.h
src/system/baseitem-info.cpp
src/system/baseitem-info.h
src/system/building-type-definition.cpp
src/system/building-type-definition.h
src/system/dungeon-data-definition.h
src/system/dungeon-info.cpp
src/system/dungeon-info.h
src/system/floor-type-definition.cpp
src/system/floor-type-definition.h
src/system/game-option-types.h
src/system/gamevalue.h
src/system/grafmode.cpp
src/system/grid-type-definition.cpp
src/system/grid-type-definition.h
src/system/h-basic.h
src/system/h-config.h
src/system/h-system.h
src/system/h-type.h
src/system/item-entity.cpp
src/system/item-entity.h
src/system/monster-entity.cpp
src/system/monster-entity.h
src/system/monster-race-info.cpp
src/system/monster-race-info.h
src/system/player-type-definition.cpp
src/system/player-type-definition.h
src/system/redrawing-flags-updater.cpp
src/system/redrawing-flags-updater.h
src/system/system-variables.cpp
src/system/system-variables.h
src/system/terrain-type-definition.cpp
src/system/terrain-type-definition.h
src/target/grid-selector.cpp
src/target/grid-selector.h
src/target/projection-path-calculator.cpp
src/target/projection-path-calculator.h
src/target/target-checker.cpp
src/target/target-checker.h
src/target/target-describer.cpp
src/target/target-describer.h
src/target/target-getter.cpp
src/target/target-getter.h
src/target/target-preparation.cpp
src/target/target-preparation.h
src/target/target-setter.cpp
src/target/target-setter.h
src/target/target-types.h
src/term/gameterm.cpp
src/term/gameterm.h
src/term/screen-processor.cpp
src/term/screen-processor.h
src/term/term-color-types.h
src/term/z-form.cpp
src/term/z-form.h
src/term/z-rand.cpp
src/term/z-rand.h
src/term/z-term.cpp
src/term/z-term.h
src/term/z-util.cpp
src/term/z-util.h
src/term/z-virt.cpp
src/term/z-virt.h
src/test/test-sha256.cpp [new file with mode: 0644]
src/timed-effect/player-acceleration.cpp
src/timed-effect/player-acceleration.h
src/timed-effect/player-blindness.cpp
src/timed-effect/player-blindness.h
src/timed-effect/player-confusion.cpp
src/timed-effect/player-confusion.h
src/timed-effect/player-cut.cpp
src/timed-effect/player-cut.h
src/timed-effect/player-deceleration.cpp
src/timed-effect/player-deceleration.h
src/timed-effect/player-fear.cpp
src/timed-effect/player-fear.h
src/timed-effect/player-hallucination.cpp
src/timed-effect/player-hallucination.h
src/timed-effect/player-paralysis.cpp
src/timed-effect/player-paralysis.h
src/timed-effect/player-poison.cpp
src/timed-effect/player-poison.h
src/timed-effect/player-stun.cpp
src/timed-effect/player-stun.h
src/timed-effect/timed-effects.cpp
src/timed-effect/timed-effects.h
src/util/angband-files.cpp
src/util/angband-files.h
src/util/bit-flags-calculator.h
src/util/buffer-shaper.cpp
src/util/buffer-shaper.h
src/util/candidate-selector.cpp [new file with mode: 0644]
src/util/candidate-selector.h [new file with mode: 0644]
src/util/enum-converter.h
src/util/enum-range.h
src/util/finalizer.h [new file with mode: 0644]
src/util/flag-group.h
src/util/int-char-converter.h
src/util/object-sort.cpp
src/util/object-sort.h
src/util/point-2d.h
src/util/probability-table.h
src/util/quarks.cpp [deleted file]
src/util/quarks.h [deleted file]
src/util/rng-xoshiro.cpp
src/util/rng-xoshiro.h
src/util/sha256.cpp [new file with mode: 0644]
src/util/sha256.h [new file with mode: 0644]
src/util/sort.cpp
src/util/sort.h
src/util/string-processor.cpp
src/util/string-processor.h
src/view/display-birth.cpp
src/view/display-birth.h
src/view/display-characteristic.cpp
src/view/display-characteristic.h
src/view/display-fruit.cpp
src/view/display-fruit.h
src/view/display-inventory.cpp
src/view/display-inventory.h
src/view/display-lore-attacks.cpp
src/view/display-lore-attacks.h
src/view/display-lore-drops.cpp
src/view/display-lore-drops.h
src/view/display-lore-magics.cpp
src/view/display-lore-magics.h
src/view/display-lore-status.cpp
src/view/display-lore-status.h
src/view/display-lore.cpp
src/view/display-lore.h
src/view/display-map.cpp
src/view/display-map.h
src/view/display-messages.cpp
src/view/display-messages.h
src/view/display-monster-status.cpp
src/view/display-monster-status.h
src/view/display-player-middle.cpp
src/view/display-player-middle.h
src/view/display-player-misc-info.cpp
src/view/display-player-misc-info.h
src/view/display-player-stat-info.cpp
src/view/display-player-stat-info.h
src/view/display-player.cpp
src/view/display-player.h
src/view/display-scores.cpp
src/view/display-scores.h
src/view/display-self-info.cpp
src/view/display-self-info.h
src/view/display-store.cpp
src/view/display-store.h
src/view/display-util.cpp
src/view/display-util.h
src/view/object-describer.cpp
src/view/object-describer.h
src/view/status-bars-table.cpp
src/view/status-bars-table.h
src/view/status-first-page.cpp
src/view/status-first-page.h
src/window/display-sub-windows.cpp
src/window/display-sub-windows.h
src/window/main-window-equipments.cpp
src/window/main-window-equipments.h
src/window/main-window-left-frame.cpp
src/window/main-window-left-frame.h
src/window/main-window-row-column.cpp
src/window/main-window-row-column.h
src/window/main-window-stat-poster.cpp
src/window/main-window-stat-poster.h
src/window/main-window-util.cpp
src/window/main-window-util.h
src/wizard/artifact-analyzer.cpp
src/wizard/artifact-analyzer.h
src/wizard/artifact-bias-table.cpp
src/wizard/artifact-bias-table.h
src/wizard/cmd-wizard.cpp
src/wizard/cmd-wizard.h
src/wizard/fixed-artifacts-spoiler.cpp
src/wizard/fixed-artifacts-spoiler.h
src/wizard/items-spoiler.cpp
src/wizard/items-spoiler.h
src/wizard/monster-info-spoiler.cpp
src/wizard/monster-info-spoiler.h
src/wizard/spoiler-table.cpp
src/wizard/spoiler-table.h
src/wizard/spoiler-util.cpp
src/wizard/spoiler-util.h
src/wizard/tval-descriptions-table.cpp
src/wizard/tval-descriptions-table.h
src/wizard/wizard-game-modifier.cpp
src/wizard/wizard-game-modifier.h
src/wizard/wizard-item-modifier.cpp
src/wizard/wizard-item-modifier.h
src/wizard/wizard-messages.cpp
src/wizard/wizard-messages.h
src/wizard/wizard-player-modifier.cpp
src/wizard/wizard-player-modifier.h
src/wizard/wizard-special-process.cpp
src/wizard/wizard-special-process.h
src/wizard/wizard-spells.cpp
src/wizard/wizard-spells.h
src/wizard/wizard-spoiler.cpp
src/wizard/wizard-spoiler.h
src/world/world-movement-processor.cpp
src/world/world-movement-processor.h
src/world/world-object.cpp
src/world/world-object.h
src/world/world-turn-processor.cpp
src/world/world-turn-processor.h
src/world/world.cpp
src/world/world.h

index 3170fbd..7091a54 100644 (file)
@@ -3,6 +3,3 @@ root = true
 [*]
 insert_final_newline = true
 charset = utf-8
-
-[*.{c,cpp,h}]
-charset = utf-8-bom
index 2322f16..e1875ee 100644 (file)
@@ -6,8 +6,8 @@ STATUS=0
 
 for file in $SRC_FILES; do
     file $file | grep "BOM" >/dev/null
-    if [ $? != 0 ]; then
-        echo "$file: BOM does not exists."
+    if [ $? == 0 ]; then
+        echo "$file: BOM exists."
         STATUS=1
     fi
 done
index 53ed8d5..753a983 100644 (file)
@@ -1,22 +1,5 @@
 #!/bin/sh
 
-# InsertBraces オプションに対応するため、clang-format-15 をインストールする
-# そのため LLVM が用意している APT リポジトリを追加する
-# 将来的に GitHub Actions の Ubuntu runner が 22.04 になれば Ubuntu の APT リポジトリからインストールできるかもしれない
-wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key 2>/dev/null | sudo apt-key add - >/dev/null 2>&1
-
-cat <<EOF | sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null
-deb http://apt.llvm.org/focal/ llvm-toolchain-focal main
-deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main
-# 14
-deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main
-deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main
-# 15
-deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main
-deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main
-
-EOF
-
 sudo apt-get update >/dev/null
 sudo apt-get install clang-format-15 >/dev/null
 
diff --git a/.github/workflows/build-test-with-msvc.yml b/.github/workflows/build-test-with-msvc.yml
new file mode 100644 (file)
index 0000000..8934464
--- /dev/null
@@ -0,0 +1,28 @@
+name: Build test with MSVC
+on:
+  workflow_call:
+
+  # 手動トリガーを許可
+  workflow_dispatch:
+
+jobs:
+  build:
+    runs-on: windows-2022
+
+    steps:
+      - name: Checkout Repository
+        uses: nschloe/action-cached-lfs-checkout@v1
+
+      - name: Setup MSBuild
+        uses: microsoft/setup-msbuild@v1
+
+      - name: Setup NuGet
+        uses: NuGet/setup-nuget@v1
+
+      - name: Restore Nuget Packages
+        run: |
+          NuGet restore .\Hengband\Hengband.sln
+
+      - name: Run build test
+        run: |
+          MSBuild -warnAsError .\Hengband\Hengband.sln /t:Rebuild /p:Configuration=Debug
index 0ae3a5a..43d2798 100644 (file)
@@ -12,6 +12,9 @@ on:
       configure-opts:
         type: string
         required: false
+      distcheck:
+        type: boolean
+        required: false
       use-ccache:
         type: boolean
         required: false
@@ -24,8 +27,17 @@ jobs:
         with:
           submodules: true
 
+      - id: calculate-cache-key
+        name: Calculate cache key for ccache
+        run: |
+          key=$(echo "${{ inputs.cxx }} ${{ inputs.cxx-flags }} ${{ inputs.configure-opts }}" | sha256sum | cut -d' ' -f1)
+          echo "key=$key" >> $GITHUB_OUTPUT
+
       - if: ${{ inputs.use-ccache }}
         uses: hendrikmuhs/ccache-action@v1.2
+        with:
+          key: ${{ steps.calculate-cache-key.outputs.key }}
+          max-size: "200M"
 
       - name: Configuring ccache to use precompiled headers
         if: ${{ inputs.use-ccache }}
@@ -52,5 +64,10 @@ jobs:
           CXX: ${{ inputs.cxx }}
           CXXFLAGS: ${{ inputs.cxx-flags }}
 
+      - name: Build with distcheck
+        if: ${{ inputs.distcheck }}
+        run: make DISTCHECK_CONFIGURE_FLAGS="CXX=\"${{ inputs.cxx }}\" CXXFLAGS=\"${{ inputs.cxx-flags }}\" ${{ inputs.configure-opts }}" -j$(nproc) distcheck >/dev/null
+
       - name: Build
+        if: ${{ !inputs.distcheck }}
         run: make -j$(nproc) >/dev/null
index 2084cc3..3c446a7 100644 (file)
@@ -14,13 +14,12 @@ jobs:
     uses: ./.github/workflows/build-with-autotools.yml
     with:
       cxx: clang++-14
-      cxx-flags: "-pipe -O3 -Werror -Wall -Wextra -Wno-unused-const-variable -Wno-invalid-source-encoding"
+      cxx-flags: "-pipe -O3 -Werror -Wall -Wextra -Wno-unused-const-variable -Wno-invalid-source-encoding -stdlib=libc++"
       configure-opts: "--disable-pch"
       use-ccache: true
 
   gcc_japanese:
     name: Japanese version with gcc
-    needs: clang_without_pch_japanese
     uses: ./.github/workflows/build-with-autotools.yml
     with:
       cxx: g++-11
@@ -29,10 +28,10 @@ jobs:
 
   gcc_english:
     name: English version with gcc
-    needs: gcc_japanese
     uses: ./.github/workflows/build-with-autotools.yml
     with:
       cxx: g++-11
       cxx-flags: "-pipe -O3 -Werror -Wall -Wextra"
       configure-opts: "--disable-japanese"
+      distcheck: true
       use-ccache: true
diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml
new file mode 100644 (file)
index 0000000..37e090b
--- /dev/null
@@ -0,0 +1,48 @@
+name: Create Release
+
+on:
+  push:
+    branches:
+      - master
+  # 手動トリガーを許可
+  workflow_dispatch:
+
+
+jobs:
+  publish-release-page:
+    name: Publish Release Page
+    runs-on: windows-2022
+    steps:
+      - name: Checkout Repository
+        uses: nschloe/action-cached-lfs-checkout@v1
+        with:
+          submodules: true
+
+      - name: Extract version from configure.ac
+        id: get_version
+        run: |
+          $version = Select-String -Path configure.ac -Pattern 'AC_INIT\(hengband, (.+?)\)' | ForEach-Object { $_.Matches.Groups[1].Value }
+          echo "version=$version" >> $Env:GITHUB_OUTPUT
+
+      - name: Setup MSBuild
+        uses: microsoft/setup-msbuild@v1
+
+      - name: Setup NuGet
+        uses: NuGet/setup-nuget@v1
+
+      - name: Restore Nuget Packages
+        run: |
+          NuGet restore .\Hengband\Hengband.sln
+
+      - name: Build Windows Release Package
+        run: |
+          .\Build-Windows-Release-Package.ps1 -Version ${{ steps.get_version.outputs.version }}
+
+      - name: Release
+        uses: softprops/action-gh-release@v1
+        with:
+          files: Hengband-*.zip
+          name: ${{ steps.get_version.outputs.version }}
+          tag_name: ${{ steps.get_version.outputs.version }}
+          generate_release_notes: true
+          draft: true
index cf3ea30..8651698 100644 (file)
@@ -25,7 +25,7 @@ jobs:
         run: ./bootstrap
 
       - name: Configuration for Japanese version
-        run: ./configure --disable-worldscore
+        run: ./configure --disable-net
         env:
           CFLAGS: "-pipe"
 
index 805157f..af80567 100644 (file)
@@ -24,17 +24,15 @@ jobs:
 
   build_test_clang_without_pch:
     name: Build Japanese version with clang (without using pre-compiled headers)
-    needs: [check_bom, check_format]
     uses: ./.github/workflows/build-with-autotools.yml
     with:
       cxx: clang++-14
-      cxx-flags: "-pipe -O3 -Werror -Wall -Wextra -Wno-unused-const-variable -Wno-invalid-source-encoding"
+      cxx-flags: "-pipe -O3 -Werror -Wall -Wextra -Wno-unused-const-variable -Wno-invalid-source-encoding -stdlib=libc++"
       configure-opts: "--disable-pch"
       use-ccache: true
 
   build_test_japanese:
     name: Build Japanese version with gcc
-    needs: build_test_clang_without_pch
     uses: ./.github/workflows/build-with-autotools.yml
     with:
       cxx: g++-11
@@ -43,10 +41,14 @@ jobs:
 
   build_test_english:
     name: Build English version with gcc
-    needs: build_test_japanese
     uses: ./.github/workflows/build-with-autotools.yml
     with:
       cxx: g++-11
       cxx-flags: "-pipe -O3 -Werror -Wall -Wextra"
       configure-opts: "--disable-japanese"
+      distcheck: true
       use-ccache: true
+
+  build_test_with_msvc:
+    name: Build test with MSVC
+    uses: ./.github/workflows/build-test-with-msvc.yml
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
new file mode 100644 (file)
index 0000000..5075236
--- /dev/null
@@ -0,0 +1,455 @@
+name: create-github-release
+
+on:
+  push:
+    branches: [ macos-develop ]
+
+env:
+    # If set and is not empty or all whitespace, this should be the list of
+    # architectures to build into a universal binary.  If not set, empty, or
+    # all whitespace, the default architecture for the combination of runner
+    # and hardware will be used.
+    UNIVERSAL_ARCHS: x86_64 arm64
+    # If set and is not empty or all whitespace, sets the name of the SDK to
+    # use.  Otherwise the default SDK for the runner will be used.  Want an
+    # SDK that can build all the architectures in UNIVERSAL_ARCHS.  For valid
+    # values of the sdk name, look at the xcrun man page.
+    #SDK_OVERRIDE: macosx11.3
+    # Used as the name when uploading or downloading the artifact for passing
+    # configuration data from the Setup job to those dependent on it.
+    CONFIG_ARTIFACT: release-config
+    # Used as the path for the file with the configuration data passed from
+    # the Setup job to those dependent on it.
+    CONFIG_ARTIFACT_PATH: release-config.txt
+    # Used as the name when uploading or downloading the artifact for passing
+    # the name of the source archive.
+    SRC_ARTIFACT: release-src
+    # Used as the path for the file with the name of the source archive in it.
+    SRC_ARTIFACT_PATH: release-src.txt
+    # Used as the name when uploading or downloading the artifact holding
+    # the source archive.
+    SRC_ARCHIVE_ARTIFACT: release-src-archive
+    # Used as the name when uploading or downloading the artifact for passing
+    # the name of the Mac archive for the English version.
+    MAC_ENGLISH_ARTIFACT: release-mac-en
+    # Used as the path for the file with the name of the Mac archive for the
+    # English version in it.
+    MAC_ENGLISH_ARTIFACT_PATH: release-mac-en.txt
+    # Used as the name when uploading or downloading the artifact holding
+    # the Mac archive for the English version.
+    MAC_ENGLISH_ARCHIVE_ARTIFACT: release-mac-en-archive
+    # Used as the name when uploading or downloading the artifact for passing
+    # the name of the Mac archive for the English version.
+    MAC_JAPANESE_ARTIFACT: release-mac-ja
+    # Used as the path for the file with the name of the Mac archive for the
+    # English version in it.
+    MAC_JAPANESE_ARTIFACT_PATH: release-mac-ja.txt
+    # Used as the name when uploading or downloading the artifact holding
+    # the Mac archive for the English version.
+    MAC_JAPANESE_ARCHIVE_ARTIFACT: release-mac-ja-archive
+
+jobs:
+  setup:
+    name: Setup
+    runs-on: ubuntu-latest
+    steps:
+      # Need commit history and tags to get the version so use 0 for
+      # fetch-depth.  Don't need the submodule(s) here.
+      - name: Clone Project
+        uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
+
+      - name: Extract Names from configure.ac
+        id: get_names
+        run: |
+          name=`sed -E -n -e 's/^[[:blank:]]*AC_INIT\([[:blank:]]*\\[?//p' configure.ac | tail -1 | cut -d ']' -f 1 | cut -d ',' -f 1`
+          echo "name=$name" >> $GITHUB_OUTPUT
+          cap=`echo $name | sed -E -e 's/^a/A/' -e 's/^b/B/' -e 's/^c/C/' -e 's/^d/D/' -e 's/^e/E/' -e 's/^f/F/' -e 's/^g/G/' -e 's/^h/H/' -e 's/^i/I/' -e 's/^j/J/' -e 's/^k/K/' -e 's/^l/L/' -e 's/^m/M/' -e 's/^n/N/' -e 's/^o/O/' -e 's/^p/P/' -e 's/^q/Q/' -e 's/^r/R/' -e 's/^s/S/' -e 's/^t/T/' -e 's/^u/U/' -e 's/^v/V/' -e 's/^w/W/' -e 's/^x/X/' -e 's/^y/Y/' -e 's/^z/Z/'`
+          echo "cap=$cap" >> $GITHUB_OUTPUT
+
+      - name: Set Release Version
+        id: get_release_vars
+        run: |
+          verfile=src/system/angband-version.h
+          major=`sed -E -n -e 's/^[[:blank:]]*#define[[:blank:]]+H_VER_MAJOR[[:blank:]]+//p' "$verfile" | cut -d ' ' -f 1 | cut -f 1 | cut -d '/' -f 1`
+          minor=`sed -E -n -e 's/^[[:blank:]]*#define[[:blank:]]+H_VER_MINOR[[:blank:]]+//p' "$verfile" | cut -d ' ' -f 1 | cut -f 1 | cut -d '/' -f 1`
+          patch=`sed -E -n -e 's/^[[:blank:]]*#define[[:blank:]]+H_VER_PATCH[[:blank:]]+//p' "$verfile" | cut -d ' ' -f 1 | cut -f 1 | cut -d '/' -f 1`
+          extra=`sed -E -n -e 's/^[[:blank:]]*#define[[:blank:]]+H_VER_EXTRA[[:blank:]]+//p' "$verfile" | cut -d ' ' -f 1 | cut -f 1 | cut -d '/' -f 1`
+          version="$major"."$minor"."$patch"
+          tag=vauto"$version"
+          if test x$extra != x0 ; then
+            version="${version}-Alpha${extra}"
+            tag="${tag}-alpha${extra}"
+          fi
+          head=`git rev-parse --verify --short HEAD`
+          version="${version}-${head}"
+          tag="${tag}-${head}"
+          if git diff-index --quiet HEAD ; then
+            true
+          else
+            version="$version"-dirty
+            tag="$tag"-dirty
+          fi
+          echo "version=$version" >> $GITHUB_OUTPUT
+          echo "tag=$tag" >> $GITHUB_OUTPUT
+          prerelease=true
+          echo "prerelease=$prerelease" >> $GITHUB_OUTPUT
+          # Mark anything that isn't a prerelease as a draft.
+          draft=true
+          if test x$prerelease = xtrue ; then
+              draft=false
+          fi
+          echo "draft=$draft" >> $GITHUB_OUTPUT
+
+      # The quoting here may be too simple-minded:  what if there are single
+      # quotes in the steps.*.outputs.* stuff.
+      - name: Create Artifact with Configuration Details
+        run: |
+          echo name= '${{ steps.get_names.outputs.name }}' > $CONFIG_ARTIFACT_PATH
+          echo cap= '${{ steps.get_names.outputs.cap }}' >> $CONFIG_ARTIFACT_PATH
+          echo version= '${{ steps.get_release_vars.outputs.version }}' >> $CONFIG_ARTIFACT_PATH
+          echo tag= '${{ steps.get_release_vars.outputs.tag }}' >> $CONFIG_ARTIFACT_PATH
+          echo prerelease= '${{ steps.get_release_vars.outputs.prerelease }}' >> $CONFIG_ARTIFACT_PATH
+          echo draft= '${{ steps.get_release_vars.outputs.draft }}' >> $CONFIG_ARTIFACT_PATH
+
+      - name: Upload Artifact for Use by Dependent Steps
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.CONFIG_ARTIFACT }}
+          path: ${{ env.CONFIG_ARTIFACT_PATH }}
+          retention-days: 1
+
+  source:
+    needs: setup
+    name: Source Archive
+    runs-on: ubuntu-latest
+    steps:
+      - name: Download Artifact with Configuration Information
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.CONFIG_ARTIFACT }}
+
+      - name: Extract Configuration Information and Store in Step Outputs
+        id: store_config
+        run: |
+          name=`sed -E -n -e 's/name= //p' $CONFIG_ARTIFACT_PATH`
+          echo "name=$name" >> $GITHUB_OUTPUT
+          version=`sed -E -n -e 's/version= //p' $CONFIG_ARTIFACT_PATH`
+          echo "version=$version" >> $GITHUB_OUTPUT
+
+      - name: Install Build Dependencies
+        run: |
+          sudo apt-get update
+          sudo apt-get install automake autoconf make tar gzip
+
+      - name: Clone Project
+        uses: actions/checkout@v3
+        with:
+          submodules: true
+
+      - name: Create Source Archive
+        id: create_source_archive
+        run: |
+          out="${{ steps.store_config.outputs.name }}"-"${{ steps.store_config.outputs.version }}"
+          echo "archive_file=${out}.tar.gz" >> $GITHUB_OUTPUT
+          ./bootstrap
+          ./configure --disable-japanese --disable-net
+          make distdir
+          mv "${{ steps.store_config.outputs.name }}"-* "$out"
+          tar -cBf - "$out" | gzip -c - >"$out".tar.gz
+
+      - name: Create Artifact with Source Archive Path
+        run: |
+          echo archive_path= '${{ steps.create_source_archive.outputs.archive_file }}' > $SRC_ARTIFACT_PATH
+
+      - name: Upload Artifact with Source Archive Path
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.SRC_ARTIFACT }}
+          path: ${{ env.SRC_ARTIFACT_PATH }}
+          retention-days: 1
+
+      - name: Upload Source Archive as Artifact
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.SRC_ARCHIVE_ARTIFACT }}
+          path: ${{ steps.create_source_archive.outputs.archive_file }}
+          retention-days: 1
+
+  mac_en:
+    needs: [setup]
+    name: Mac English
+    runs-on: macos-latest
+    steps:
+      - name: Download Artifact with Configuration Information
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.CONFIG_ARTIFACT }}
+
+      - name: Extract Configuration Information and Store in Step Outputs
+        id: store_config
+        run: |
+          name=`sed -E -n -e 's/name= //p' $CONFIG_ARTIFACT_PATH`
+          echo "name=$name" >> $GITHUB_OUTPUT
+          cap=`sed -E -n -e 's/cap= //p' $CONFIG_ARTIFACT_PATH`
+          echo "cap=$cap" >> $GITHUB_OUTPUT
+          version=`sed -E -n -e 's/version= //p' $CONFIG_ARTIFACT_PATH`
+          echo "version=$version" >> $GITHUB_OUTPUT
+
+      - name: Clone Project
+        uses: actions/checkout@v3
+        with:
+          submodules: true
+
+      # Requires automake and autoconf; install those via homebrew (available
+      # by default).
+      - name: Install Build Dependencies
+        run: |
+          brew install m4
+          brew install autoconf
+          brew install automake
+
+      - name: Create Mac English Archive
+        id: create_mac_en_archive
+        run: |
+          if test -n `echo "${{ env.SDK_OVERRIDE }}" | tr -d ' \t\r\n'` ; then
+            SDKROOT=`echo "${{ env.SDK_OVERRIDE }}" | tr -d ' \t\r\n'`
+            export SDKROOT
+          fi
+          ./bootstrap
+          CFLAGS=""
+          CXXFLAGS=""
+          OBJCXXFLAGS=""
+          LDFLAGS=""
+          DEPENDENCY_TRACKING=""
+          if test -n `echo "${{ env.UNIVERSAL_ARCHS }}" | tr -d ' \t\r\n'` ; then
+            DEPENDENCY_TRACKING="--disable-dependency-tracking --disable-pch"
+            # Include what configure normally infers for the compiler flags.
+            # Without -O2, the generated executables take painfully long to
+            # read the data files.
+            CFLAGS="$CFLAGS -g -O2"
+            CXXFLAGS="$CXXFLAGS -g -O2"
+            OBJCXXFLAGS="$OBJCXXFLAGS -g -O2"
+            for arch in ${{ env.UNIVERSAL_ARCHS }} ; do
+              option="-arch $arch"
+              CFLAGS="$CFLAGS $option"
+              CXXFLAGS="$CXXFLAGS $option"
+              OBJCXXFLAGS="$OBJCXXFLAGS $option"
+              LDFLAGS="$LDFLAGS $option"
+            done
+            echo "Performing a univeral build:"
+            echo "  CFLAGS = $CFLAGS"
+            echo "  CXXFLAGS = $CXXFLAGS"
+            echo "  OBJCXXFLAGS = $OBJCXXFLAGS"
+            echo "  LDFLAGS = $LDFLAGS"
+          fi
+          env CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" \
+            OBJCXXFLAGS="$OBJCXXFLAGS" LDFLAGS="$LDFLAGS" \
+            ./configure --enable-cocoa --disable-japanese $DEPENDENCY_TRACKING
+          make install
+          mkdir disttemp
+          mv "${{ steps.store_config.outputs.name }}".app disttemp
+          hdiutil create -quiet -volname "${{ steps.store_config.outputs.cap }}-${{ steps.store_config.outputs.version }}-English" -srcfolder disttemp disttemp.dmg
+          archive_prefix="${{ steps.store_config.outputs.cap }}-${{ steps.store_config.outputs.version }}-English"
+          echo "archive_file=${archive_prefix}.dmg" >> $GITHUB_OUTPUT
+          hdiutil convert disttemp.dmg -quiet -format UDZO -imagekey zlib-level=6 -o "${archive_prefix}.dmg"
+
+      - name: Create Artifact with Mac English Archive Path
+        run: |
+          echo archive_path= '${{ steps.create_mac_en_archive.outputs.archive_file }}' > $MAC_ENGLISH_ARTIFACT_PATH
+
+      - name: Upload Artifact with Mac English Archive Path
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.MAC_ENGLISH_ARTIFACT }}
+          path: ${{ env.MAC_ENGLISH_ARTIFACT_PATH }}
+          retention-days: 1
+
+      - name: Upload Mac English Archive as Artifact
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.MAC_ENGLISH_ARCHIVE_ARTIFACT }}
+          path: ${{ steps.create_mac_en_archive.outputs.archive_file }}
+          retention-days: 1
+
+  mac_ja:
+    needs: [setup]
+    name: Mac Japanese
+    runs-on: macos-latest
+    steps:
+      - name: Download Artifact with Configuration Information
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.CONFIG_ARTIFACT }}
+
+      - name: Extract Configuration Information and Store in Step Outputs
+        id: store_config
+        run: |
+          name=`sed -E -n -e 's/name= //p' $CONFIG_ARTIFACT_PATH`
+          echo "name=$name" >> $GITHUB_OUTPUT
+          cap=`sed -E -n -e 's/cap= //p' $CONFIG_ARTIFACT_PATH`
+          echo "cap=$cap" >> $GITHUB_OUTPUT
+          version=`sed -E -n -e 's/version= //p' $CONFIG_ARTIFACT_PATH`
+          echo "version=$version" >> $GITHUB_OUTPUT
+
+      - name: Clone Project
+        uses: actions/checkout@v3
+        with:
+          submodules: true
+
+      # Requires automake, autoconf, and nkf; install those via homebrew
+      # (available by default).
+      - name: Install Build Dependencies
+        run: |
+          brew install m4
+          brew install autoconf
+          brew install automake
+          brew install nkf
+
+      - name: Create Mac Japanese Archive
+        id: create_mac_ja_archive
+        run: |
+          if test -n `echo "${{ env.SDK_OVERRIDE }}" | tr -d ' \t\r\n'` ; then
+            SDKROOT=`echo "${{ env.SDK_OVERRIDE }}" | tr -d ' \t\r\n'`
+            export SDKROOT
+          fi
+          ./bootstrap
+          CFLAGS=""
+          CXXFLAGS=""
+          OBJCXXFLAGS=""
+          LDFLAGS=""
+          DEPENDENCY_TRACKING=""
+          if test -n `echo "${{ env.UNIVERSAL_ARCHS }}" | tr -d ' \t\r\n'` ; then
+            DEPENDENCY_TRACKING="--disable-dependency-tracking --disable-pch"
+            # Include what configure normally infers for the compiler flags.
+            # Without -O2, the generated executables take painfully long to
+            # read the data files.
+            CFLAGS="$CFLAGS -g -O2"
+            CXXFLAGS="$CXXFLAGS -g -O2"
+            OBJCXXFLAGS="$OBJCXXFLAGS -g -O2"
+            for arch in ${{ env.UNIVERSAL_ARCHS }} ; do
+              option="-arch $arch"
+              CFLAGS="$CFLAGS $option"
+              CXXFLAGS="$CXXFLAGS $option"
+              OBJCXXFLAGS="$OBJCXXFLAGS $option"
+              LDFLAGS="$LDFLAGS $option"
+            done
+            echo "Performing a univeral build:"
+            echo "  CFLAGS = $CFLAGS"
+            echo "  CXXFLAGS = $CXXFLAGS"
+            echo "  OBJCXXFLAGS = $OBJCXXFLAGS"
+            echo "  LDFLAGS = $LDFLAGS"
+          fi
+          env CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" \
+            OBJCXXFLAGS="$OBJCXXFLAGS" LDFLAGS="$LDFLAGS" \
+            ./configure --enable-cocoa $DEPENDENCY_TRACKING
+          make install
+          mkdir disttemp
+          mv "${{ steps.store_config.outputs.name }}".app disttemp
+          hdiutil create -quiet -volname "${{ steps.store_config.outputs.cap }}-${{ steps.store_config.outputs.version}}-Japanese" -srcfolder disttemp disttemp.dmg
+          archive_prefix="${{ steps.store_config.outputs.cap }}-${{ steps.store_config.outputs.version }}-Japanese"
+          echo "archive_file=${archive_prefix}.dmg" >> $GITHUB_OUTPUT
+          hdiutil convert disttemp.dmg -quiet -format UDZO -imagekey zlib-level=6 -o "${archive_prefix}.dmg"
+
+      - name: Create Artifact with Mac Japanese Archive Path
+        run: |
+          echo archive_path= '${{ steps.create_mac_ja_archive.outputs.archive_file }}' > $MAC_JAPANESE_ARTIFACT_PATH
+
+      - name: Upload Artifact with Mac Japanese Archive Path
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.MAC_JAPANESE_ARTIFACT }}
+          path: ${{ env.MAC_JAPANESE_ARTIFACT_PATH }}
+          retention-days: 1
+
+      - name: Upload Mac Japanese Archive as Artifact
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ env.MAC_JAPANESE_ARCHIVE_ARTIFACT }}
+          path: ${{ steps.create_mac_ja_archive.outputs.archive_file }}
+          retention-days: 1
+
+  release:
+    needs: [ setup, source, mac_en, mac_ja ]
+    name: Create GitHub Release
+    runs-on: ubuntu-latest
+    steps:
+      - name: Download Artifact with Configuration Information
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.CONFIG_ARTIFACT }}
+
+      - name: Extract Configuration Information and Store in Step Outputs
+        id: store_config
+        run: |
+          version=`sed -E -n -e 's/version= //p' $CONFIG_ARTIFACT_PATH`
+          echo "version=$version" >> $GITHUB_OUTPUT
+          tag=`sed -E -n -e 's/tag= //p' $CONFIG_ARTIFACT_PATH`
+          echo "tag=$tag" >> $GITHUB_OUTPUT
+          prerelease=`sed -E -n -e 's/prerelease= //p' $CONFIG_ARTIFACT_PATH`
+          echo "prerelease=$prerelease" >> $GITHUB_OUTPUT
+          draft=`sed -E -n -e 's/draft= //p' $CONFIG_ARTIFACT_PATH`
+          echo "draft=$draft" >> $GITHUB_OUTPUT
+
+      - name: Download Artifact with Source Archive Path
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.SRC_ARTIFACT }}
+
+      - name: Extract Source Archive Path and Store in Step Outputs
+        id: store_src
+        run: |
+          archive_path=`sed -E -n -e 's/archive_path= //p' $SRC_ARTIFACT_PATH`
+          echo "archive_path=$archive_path" >> $GITHUB_OUTPUT
+
+      - name: Download Artifact with Source Archive
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.SRC_ARCHIVE_ARTIFACT }}
+
+      - name: Download Artifact with Mac English Archive Path
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.MAC_ENGLISH_ARTIFACT }}
+
+      - name: Extract Mac English Archive Path and Store in Step Outputs
+        id: store_mac_en
+        run: |
+          archive_path=`sed -E -n -e 's/archive_path= //p' $MAC_ENGLISH_ARTIFACT_PATH`
+          echo "archive_path=$archive_path" >> $GITHUB_OUTPUT
+
+      - name: Download Artifact with Mac English Archive
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.MAC_ENGLISH_ARCHIVE_ARTIFACT }}
+
+      - name: Download Artifact with Mac Japanese Archive Path
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.MAC_JAPANESE_ARTIFACT }}
+
+      - name: Extract Mac Japanese Archive Path and Store in Step Outputs
+        id: store_mac_ja
+        run: |
+          archive_path=`sed -E -n -e 's/archive_path= //p' $MAC_JAPANESE_ARTIFACT_PATH`
+          echo "archive_path=$archive_path" >> $GITHUB_OUTPUT
+
+      - name: Download Artifact with Mac Japanese Archive
+        uses: actions/download-artifact@v3
+        with:
+          name: ${{ env.MAC_JAPANESE_ARCHIVE_ARTIFACT }}
+
+      - name: Populate Release
+        uses: softprops/action-gh-release@v1
+        with:
+          tag_name: "${{ steps.store_config.outputs.tag }}"
+          name: ${{ steps.store_config.outputs.version }}
+          target_commitish: ${{ github.sha }}
+          draft: ${{ steps.store_config.outputs.draft }}
+          prerelease: ${{ steps.store_config.outputs.prerelease }}
+          files: |
+            ${{ steps.store_src.outputs.archive_path }}
+            ${{ steps.store_mac_en.outputs.archive_path }}
+            ${{ steps.store_mac_ja.outputs.archive_path }}
+          token: ${{ secrets.GITHUB_TOKEN }}
index 503cec7..d91fa4b 100644 (file)
@@ -14,8 +14,8 @@ jobs:
     runs-on: ubuntu-latest
     env:
       # This will be passed to all invocations of configure for this test.
-      # Could drop --disable-worldscore if libcurl is installed.
-      DEFAULT_CONFIGURE_OPTIONS: --disable-japanese --disable-worldscore
+      # Could drop --disable-net if libcurl is installed.
+      DEFAULT_CONFIGURE_OPTIONS: --disable-japanese --disable-net
 
     steps:
       - name: Clone Project
@@ -25,7 +25,9 @@ jobs:
 
       # Requires automake and autoconf; install those via apt-get.
       - name: Install Build Dependencies
-        run: sudo apt-get install autoconf automake
+        run: |
+          sudo apt-get update
+          sudo apt-get install autoconf automake
 
       - name: Build
         run: |
@@ -51,7 +53,7 @@ jobs:
     runs-on: ubuntu-latest
     env:
       # This will be passed to all invocations of configure for this test.
-      DEFAULT_CONFIGURE_OPTIONS: --disable-worldscore --disable-pch
+      DEFAULT_CONFIGURE_OPTIONS: --disable-pch
 
     steps:
       - name: Clone Project
@@ -59,11 +61,13 @@ jobs:
         with:
           submodules: true
 
-      # Requires automake, autoconf, and, unless building the
-      # 1.6.2 version, nkf; install those via apt-get.
-      # macos-latest).
+      # Requires automake, autoconf, and, unless building the 1.6.2 version,
+      # nkf.  Hengband 3.0.0 now requires libcurl if not configured with
+      # --disable-net.  Install those via apt-get.
       - name: Install Build Dependencies
-        run: sudo apt-get install automake autoconf nkf
+        run: |
+          sudo apt-get update
+          sudo apt-get install automake autoconf nkf libcurl4-openssl-dev
 
       - name: Build
         run: |
index 81290b4..54c444d 100644 (file)
@@ -35,12 +35,11 @@ jobs:
           submodules: true
 
       # Requires automake and autoconf; install those via homebrew (available
-      # by default).  Use autoconf 2.69 since autoconf 2.71 does not work well
-      # with the version of m4 (GNU M4 1.4.6) include with macOS 11 and 12.
+      # by default).
       - name: Install Build Dependencies
         run: |
           brew install m4
-          brew install autoconf@2.69
+          brew install autoconf
           brew install automake
 
       - name: Build
@@ -49,7 +48,6 @@ jobs:
             SDKROOT=`echo "${{ env.SDK_OVERRIDE }}" | tr -d ' \t\r\n'`
             export SDKROOT
           fi
-          PATH=/usr/local/opt/autoconf@2.69/bin:"$PATH"
           ./bootstrap
           CFLAGS=""
           CXXFLAGS=""
@@ -92,7 +90,6 @@ jobs:
       # of the source tree works.
       - name: Distcheck
         run: |
-          PATH=/usr/local/opt/autoconf@2.69/bin:"$PATH"
           ./bootstrap
           ./configure ${{ env.DEFAULT_CONFIGURE_OPTIONS }}
           make DISTCHECK_CONFIGURE_FLAGS="${{ env.DEFAULT_CONFIGURE_OPTIONS }}" \
@@ -115,12 +112,11 @@ jobs:
           submodules: true
 
       # Requires automake, autoconf, and, unless building the 1.6.2 version,
-      # nkf; install those via homebrew (available by default).  For the same
-      # reason as above, use autoconf 2.69.
+      # nkf; install those via homebrew (available by default).
       - name: Install Build Dependencies
         run: |
           brew install m4
-          brew install autoconf@2.69
+          brew install autoconf
           brew install automake
           brew install nkf
 
@@ -130,7 +126,6 @@ jobs:
             SDKROOT=`echo "${{ env.SDK_OVERRIDE }}" | tr -d ' \t\r\n'`
             export SDKROOT
           fi
-          PATH=/usr/local/opt/autoconf@2.69/bin:"$PATH"
           ./bootstrap
           CFLAGS=""
           CXXFLAGS=""
index e6e38fc..c5428ed 100644 (file)
@@ -25,7 +25,7 @@ function BuildPackage ($package_name, $package_unique_files, $build_conf) {
     New-Item $hengbandDir -ItemType Directory
 
     # 必要なファイルをコピーして、その中で不要になりえるものを削除
-    Copy-Item -Verbose -Path .\Hengband.exe, .\readme_angband -Destination $hengbandDir
+    Copy-Item -Verbose -Path .\Hengband.exe, .\readme_angband, .\THIRD-PARTY-NOTICES.txt -Destination $hengbandDir
     Copy-Item -Verbose -Path $package_unique_files -Destination $hengbandDir
     Copy-Item -Verbose -Recurse -Path .\lib -Destination $hengbandDir -Exclude Makefile.am, *.raw, .gitattributes
     Copy-Item -Verbose -Path .\lib\apex\h_scores.raw -Destination $hengbandDir\lib\apex
diff --git a/Hengband/.gitattributes b/Hengband/.gitattributes
new file mode 100644 (file)
index 0000000..5c4bd94
--- /dev/null
@@ -0,0 +1 @@
+*.lib filter=lfs diff=lfs merge=lfs -text
index 1a429d8..8f5b363 100644 (file)
@@ -1,10 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>\r
 <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <Import Project="..\packages\Microsoft.CodeAnalysis.FxCopAnalyzers.3.0.0\build\Microsoft.CodeAnalysis.FxCopAnalyzers.props" Condition="Exists('..\packages\Microsoft.CodeAnalysis.FxCopAnalyzers.3.0.0\build\Microsoft.CodeAnalysis.FxCopAnalyzers.props')" />\r
-  <Import Project="..\packages\Microsoft.NetFramework.Analyzers.3.0.0\build\Microsoft.NetFramework.Analyzers.props" Condition="Exists('..\packages\Microsoft.NetFramework.Analyzers.3.0.0\build\Microsoft.NetFramework.Analyzers.props')" />\r
-  <Import Project="..\packages\Microsoft.NetCore.Analyzers.3.0.0\build\Microsoft.NetCore.Analyzers.props" Condition="Exists('..\packages\Microsoft.NetCore.Analyzers.3.0.0\build\Microsoft.NetCore.Analyzers.props')" />\r
-  <Import Project="..\packages\Microsoft.CodeQuality.Analyzers.3.0.0\build\Microsoft.CodeQuality.Analyzers.props" Condition="Exists('..\packages\Microsoft.CodeQuality.Analyzers.3.0.0\build\Microsoft.CodeQuality.Analyzers.props')" />\r
-  <Import Project="..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.3.0.0\build\Microsoft.CodeAnalysis.VersionCheckAnalyzer.props" Condition="Exists('..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.3.0.0\build\Microsoft.CodeAnalysis.VersionCheckAnalyzer.props')" />\r
+  <Import Project="..\packages\Microsoft.CodeAnalysis.NetAnalyzers.7.0.4\build\Microsoft.CodeAnalysis.NetAnalyzers.props" Condition="Exists('..\packages\Microsoft.CodeAnalysis.NetAnalyzers.7.0.4\build\Microsoft.CodeAnalysis.NetAnalyzers.props')" />\r
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
     <ConfigurationType>StaticLibrary</ConfigurationType>\r
     <UseDebugLibraries>true</UseDebugLibraries>\r
       <ExceptionHandling>SyncCThrow</ExceptionHandling>\r
       <PrecompiledHeader>Use</PrecompiledHeader>\r
       <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>\r
+      <AdditionalOptions>/source-charset:utf-8 /execution-charset:shift-jis %(AdditionalOptions)</AdditionalOptions>\r
     </ClCompile>\r
     <Link>\r
       <GenerateDebugInformation>true</GenerateDebugInformation>\r
       <TargetMachine>MachineX86</TargetMachine>\r
-      <AdditionalDependencies>winmm.lib;gdiplus.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\x86 Debug\libcurl_a_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+      <AdditionalDependencies>winmm.lib;gdiplus.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\lib\libcurl_a_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
       <ShowProgress>LinkVerbose</ShowProgress>\r
       <SubSystem>Windows</SubSystem>\r
     </Link>\r
       <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
       <AdditionalIncludeDirectories>..\..\src;curl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <ExceptionHandling>SyncCThrow</ExceptionHandling>\r
-      <LanguageStandard>stdcpplatest</LanguageStandard>\r
+      <LanguageStandard>stdcpp20</LanguageStandard>\r
       <PrecompiledHeader>Use</PrecompiledHeader>\r
       <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>\r
+      <AdditionalOptions>/source-charset:utf-8 %(AdditionalOptions)</AdditionalOptions>\r
     </ClCompile>\r
     <Link>\r
       <GenerateDebugInformation>true</GenerateDebugInformation>\r
       <TargetMachine>MachineX86</TargetMachine>\r
       <ShowProgress>LinkVerbose</ShowProgress>\r
-      <AdditionalDependencies>winmm.lib;gdiplus.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\x86 Debug\libcurl_a_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+      <AdditionalDependencies>winmm.lib;gdiplus.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\lib\libcurl_a_debug.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
       <SubSystem>Windows</SubSystem>\r
     </Link>\r
   </ItemDefinitionGroup>\r
       <FunctionLevelLinking>true</FunctionLevelLinking>\r
       <CompileAs>CompileAsCpp</CompileAs>\r
       <ExceptionHandling>SyncCThrow</ExceptionHandling>\r
-      <LanguageStandard>stdcpplatest</LanguageStandard>\r
+      <LanguageStandard>stdcpp20</LanguageStandard>\r
       <PrecompiledHeader>Use</PrecompiledHeader>\r
       <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>\r
+      <AdditionalOptions>/source-charset:utf-8 /execution-charset:shift-jis %(AdditionalOptions)</AdditionalOptions>\r
     </ClCompile>\r
     <Link>\r
       <TargetMachine>MachineX86</TargetMachine>\r
-      <AdditionalDependencies>winmm.lib;gdiplus.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\x86 Release\libcurl_a.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+      <AdditionalDependencies>winmm.lib;gdiplus.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\lib\libcurl_a.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
       <LinkTimeCodeGeneration>UseFastLinkTimeCodeGeneration</LinkTimeCodeGeneration>\r
       <GenerateDebugInformation>false</GenerateDebugInformation>\r
       <OptimizeReferences>true</OptimizeReferences>\r
       <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
       <AdditionalIncludeDirectories>..\..\src;curl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <ExceptionHandling>SyncCThrow</ExceptionHandling>\r
-      <LanguageStandard>stdcpplatest</LanguageStandard>\r
+      <LanguageStandard>stdcpp20</LanguageStandard>\r
       <CompileAs>CompileAsCpp</CompileAs>\r
       <PrecompiledHeader>Use</PrecompiledHeader>\r
       <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>\r
+      <AdditionalOptions>/source-charset:utf-8 %(AdditionalOptions)</AdditionalOptions>\r
     </ClCompile>\r
     <Link>\r
-      <AdditionalDependencies>winmm.lib;gdiplus.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\x86 Release\libcurl_a.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+      <AdditionalDependencies>winmm.lib;gdiplus.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\lib\libcurl_a.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
       <GenerateDebugInformation>true</GenerateDebugInformation>\r
       <OptimizeReferences>true</OptimizeReferences>\r
       <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
     <ClCompile Include="..\..\src\action\travel-execution.cpp" />\r
     <ClCompile Include="..\..\src\action\tunnel-execution.cpp" />\r
     <ClCompile Include="..\..\src\action\weapon-shield.cpp" />\r
-    <ClCompile Include="..\..\src\artifact\artifact-info.cpp" />\r
     <ClCompile Include="..\..\src\artifact\fixed-art-generator.cpp" />\r
     <ClCompile Include="..\..\src\artifact\random-art-activation.cpp" />\r
     <ClCompile Include="..\..\src\artifact\random-art-characteristics.cpp" />\r
     <ClCompile Include="..\..\src\load\item\item-loader-factory.cpp" />\r
     <ClCompile Include="..\..\src\load\monster\monster-loader-factory.cpp" />\r
     <ClCompile Include="..\..\src\load\player-class-specific-data-loader.cpp" />\r
+    <ClCompile Include="..\..\src\main-win\main-win-exception.cpp" />\r
     <ClCompile Include="..\..\src\monster-race\race-brightness-mask.cpp" />\r
     <ClCompile Include="..\..\src\monster-race\race-feature-mask.cpp" />\r
+    <ClCompile Include="..\..\src\monster-race\race-sex-const.cpp" />\r
     <ClCompile Include="..\..\src\monster\monster-pain-describer.cpp" />\r
+    <ClCompile Include="..\..\src\net\curl-easy-session.cpp" />\r
+    <ClCompile Include="..\..\src\net\curl-slist.cpp" />\r
+    <ClCompile Include="..\..\src\net\http-client.cpp" />\r
+    <ClCompile Include="..\..\src\net\report-error.cpp" />\r
     <ClCompile Include="..\..\src\object-enchant\enchanter-factory.cpp" />\r
     <ClCompile Include="..\..\src\mspell\mspell-attack\abstract-mspell.cpp" />\r
     <ClCompile Include="..\..\src\mspell\mspell-data.cpp" />\r
     <ClCompile Include="..\..\src\save\player-class-specific-data-writer.cpp" />\r
     <ClCompile Include="..\..\src\specific-object\stone-of-lore.cpp" />\r
     <ClCompile Include="..\..\src\spell-class\spells-mirror-master.cpp" />\r
+    <ClCompile Include="..\..\src\system\angband-system.cpp" />\r
     <ClCompile Include="..\..\src\system\redrawing-flags-updater.cpp" />\r
     <ClCompile Include="..\..\src\system\floor-type-definition.cpp" />\r
     <ClCompile Include="..\..\src\system\grid-type-definition.cpp" />\r
     <ClCompile Include="..\..\src\timed-effect\player-poison.cpp" />\r
     <ClCompile Include="..\..\src\timed-effect\player-stun.cpp" />\r
     <ClCompile Include="..\..\src\timed-effect\timed-effects.cpp" />\r
+    <ClCompile Include="..\..\src\util\candidate-selector.cpp" />\r
     <ClCompile Include="..\..\src\util\rng-xoshiro.cpp" />\r
+    <ClCompile Include="..\..\src\util\sha256.cpp" />\r
     <ClCompile Include="..\..\src\view\display-inventory.cpp" />\r
     <ClCompile Include="..\..\src\view\display-map.cpp" />\r
     <ClCompile Include="..\..\src\view\display-self-info.cpp" />\r
     <ClCompile Include="..\..\src\system\alloc-entries.cpp" />\r
     <ClCompile Include="..\..\src\term\screen-processor.cpp" />\r
     <ClCompile Include="..\..\src\util\buffer-shaper.cpp" />\r
-    <ClCompile Include="..\..\src\util\quarks.cpp" />\r
     <ClCompile Include="..\..\src\lore\combat-types-setter.cpp" />\r
     <ClCompile Include="..\..\src\lore\magic-types-setter.cpp" />\r
     <ClCompile Include="..\..\src\lore\lore-calculator.cpp" />\r
     <ClCompile Include="..\..\src\mspell\summon-checker.cpp" />\r
     <ClCompile Include="..\..\src\object-enchant\activation-info-table.cpp" />\r
     <ClCompile Include="..\..\src\object-enchant\dragon-breaths-table.cpp" />\r
-    <ClCompile Include="..\..\src\object\object-flags.cpp" />\r
     <ClCompile Include="..\..\src\perception\identification.cpp" />\r
     <ClCompile Include="..\..\src\player-attack\attack-chaos-effect.cpp" />\r
     <ClCompile Include="..\..\src\combat\attack-criticality.cpp" />\r
     <ClInclude Include="..\..\src\action\open-close-execution.h" />\r
     <ClInclude Include="..\..\src\action\open-util.h" />\r
     <ClInclude Include="..\..\src\action\run-execution.h" />\r
+    <ClInclude Include="..\..\src\external-lib\include-json.h" />\r
+    <ClInclude Include="..\..\src\external-lib\json.hpp" />\r
     <ClInclude Include="..\..\src\item-info\flavor-initializer.h" />\r
     <ClInclude Include="..\..\src\load\item\item-loader-version-types.h" />\r
     <ClInclude Include="..\..\src\load\item\item-loader-base.h" />\r
     <ClInclude Include="..\..\src\load\old\monster-flag-types-savefile50.h" />\r
     <ClInclude Include="..\..\src\load\player-class-specific-data-loader.h" />\r
     <ClInclude Include="..\..\src\load\savedata-old-flag-types.h" />\r
+    <ClInclude Include="..\..\src\main-win\main-win-exception.h" />\r
     <ClInclude Include="..\..\src\market\bounty-type-definition.h" />\r
     <ClInclude Include="..\..\src\monster-race\monster-aura-types.h" />\r
     <ClInclude Include="..\..\src\monster-race\monster-kind-mask.h" />\r
     <ClInclude Include="..\..\src\mspell\mspell-attack\abstract-mspell.h" />\r
     <ClInclude Include="..\..\src\mspell\mspell-data.h" />\r
     <ClInclude Include="..\..\src\mspell\mspell-result.h" />\r
+    <ClInclude Include="..\..\src\net\curl-easy-session.h" />\r
+    <ClInclude Include="..\..\src\net\curl-slist.h" />\r
+    <ClInclude Include="..\..\src\net\http-client.h" />\r
+    <ClInclude Include="..\..\src\net\report-error.h" />\r
     <ClInclude Include="..\..\src\object-enchant\enchanter-factory.h" />\r
     <ClInclude Include="..\..\src\object-enchant\protector\apply-magic-soft-armor.h" />\r
     <ClInclude Include="..\..\src\object-enchant\others\apply-magic-lite.h" />\r
     <ClInclude Include="..\..\src\action\weapon-shield.h" />\r
     <ClInclude Include="..\..\src\artifact\fixed-art-types.h" />\r
     <ClInclude Include="..\..\src\artifact\random-art-effects.h" />\r
-    <ClInclude Include="..\..\src\artifact\artifact-info.h" />\r
     <ClInclude Include="..\..\src\artifact\fixed-art-generator.h" />\r
     <ClInclude Include="..\..\src\artifact\random-art-activation.h" />\r
     <ClInclude Include="..\..\src\artifact\random-art-generator.h" />\r
     <ClInclude Include="..\..\src\core\asking-player.h" />\r
     <ClInclude Include="..\..\src\core\disturbance.h" />\r
     <ClInclude Include="..\..\src\core\object-compressor.h" />\r
-    <ClInclude Include="..\..\src\core\player-redraw-types.h" />\r
     <ClInclude Include="..\..\src\core\visuals-reseter.h" />\r
     <ClInclude Include="..\..\src\core\window-redrawer.h" />\r
     <ClInclude Include="..\..\src\dungeon\dungeon-flag-types.h" />\r
     <ClInclude Include="..\..\src\object-hook\hook-weapon.h" />\r
     <ClInclude Include="..\..\src\object-use\quaff\quaff-execution.h" />\r
     <ClInclude Include="..\..\src\player\attack-defense-types.h" />\r
-    <ClInclude Include="..\..\src\core\player-update-types.h" />\r
     <ClInclude Include="..\..\src\load\angband-version-comparer.h" />\r
     <ClInclude Include="..\..\src\load\birth-loader.h" />\r
     <ClInclude Include="..\..\src\load\dummy-loader.h" />\r
     <ClInclude Include="..\..\src\store\service-checker.h" />\r
     <ClInclude Include="..\..\src\system\alloc-entries.h" />\r
     <ClInclude Include="..\..\src\system\angband-exceptions.h" />\r
+    <ClInclude Include="..\..\src\system\angband-system.h" />\r
     <ClInclude Include="..\..\src\system\redrawing-flags-updater.h" />\r
     <ClInclude Include="..\..\src\system\dungeon-data-definition.h" />\r
     <ClInclude Include="..\..\src\system\floor-type-definition.h" />\r
     <ClInclude Include="..\..\src\timed-effect\timed-effects.h" />\r
     <ClInclude Include="..\..\src\util\bit-flags-calculator.h" />\r
     <ClInclude Include="..\..\src\util\buffer-shaper.h" />\r
+    <ClInclude Include="..\..\src\util\candidate-selector.h" />\r
     <ClInclude Include="..\..\src\util\enum-converter.h" />\r
     <ClInclude Include="..\..\src\util\enum-range.h" />\r
+    <ClInclude Include="..\..\src\util\finalizer.h" />\r
     <ClInclude Include="..\..\src\util\flag-group.h" />\r
     <ClInclude Include="..\..\src\util\int-char-converter.h" />\r
     <ClInclude Include="..\..\src\util\point-2d.h" />\r
-    <ClInclude Include="..\..\src\util\quarks.h" />\r
     <ClInclude Include="..\..\src\lore\combat-types-setter.h" />\r
     <ClInclude Include="..\..\src\lore\magic-types-setter.h" />\r
     <ClInclude Include="..\..\src\lore\lore-calculator.h" />\r
     <ClInclude Include="..\..\src\object-enchant\dragon-breaths-table.h" />\r
     <ClInclude Include="..\..\src\artifact\random-art-bias-types.h" />\r
     <ClInclude Include="..\..\src\object-enchant\trg-types.h" />\r
-    <ClInclude Include="..\..\src\object\object-flags.h" />\r
     <ClInclude Include="..\..\src\perception\identification.h" />\r
     <ClInclude Include="..\..\src\player-attack\attack-chaos-effect.h" />\r
     <ClInclude Include="..\..\src\combat\attack-criticality.h" />\r
     <ClInclude Include="..\..\src\monster-attack\monster-attack-table.h" />\r
     <ClInclude Include="..\..\src\combat\attack-accuracy.h" />\r
     <ClInclude Include="..\..\src\monster-attack\monster-eating.h" />\r
-    <ClInclude Include="..\..\src\player-attack\player-attack-util.h" />\r
     <ClInclude Include="..\..\src\player-attack\player-attack.h" />\r
     <ClInclude Include="..\..\src\combat\slaying.h" />\r
     <ClInclude Include="..\..\src\object-enchant\vorpal-weapon.h" />\r
     <ClCompile Include="..\..\src\player\player-move.cpp" />\r
     <ClCompile Include="..\..\src\io\files-util.cpp" />\r
     <ClCompile Include="..\..\src\grid\grid.cpp" />\r
-    <ClCompile Include="..\..\src\io\inet.cpp" />\r
     <ClCompile Include="..\..\src\locale\japanese.cpp" />\r
     <ClCompile Include="..\..\src\load\load.cpp" />\r
     <ClCompile Include="..\..\src\main-win.cpp" />\r
     <ClInclude Include="..\..\src\util\angband-files.h" />\r
     <ClInclude Include="..\..\src\util\object-sort.h" />\r
     <ClInclude Include="..\..\src\util\rng-xoshiro.h" />\r
+    <ClInclude Include="..\..\src\util\sha256.h" />\r
     <ClInclude Include="..\..\src\util\string-processor.h" />\r
     <ClInclude Include="..\..\src\view\display-birth.h" />\r
     <ClInclude Include="..\..\src\view\display-inventory.h" />\r
     <ClInclude Include="..\..\src\wizard\tval-descriptions-table.h" />\r
     <ClInclude Include="..\..\src\load\quest-loader.h" />\r
     <ClInclude Include="..\..\src\view\display-store.h" />\r
+    <ClInclude Include="..\..\src\monster-race\race-sex-const.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\..\src\system\angband.h" />\r
     <ClInclude Include="..\..\src\system\h-system.h" />\r
     <ClInclude Include="..\..\src\system\h-type.h" />\r
     <ClInclude Include="..\..\src\birth\history.h" />\r
-    <ClInclude Include="..\..\src\io\inet.h" />\r
     <ClInclude Include="..\..\src\main\angband-initializer.h" />\r
     <ClInclude Include="..\..\src\load\load.h" />\r
     <ClInclude Include="..\..\src\cmd-action\cmd-mind.h" />\r
     <None Include="packages.config" />\r
   </ItemGroup>\r
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+    <Import Project="..\packages\Microsoft.CodeAnalysis.NetAnalyzers.7.0.4\build\Microsoft.CodeAnalysis.NetAnalyzers.targets" Condition="Exists('..\packages\Microsoft.CodeAnalysis.NetAnalyzers.7.0.4\build\Microsoft.CodeAnalysis.NetAnalyzers.targets')" />\r
+  </ImportGroup>\r
   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">\r
     <PropertyGroup>\r
       <ErrorText>このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。</ErrorText>\r
     </PropertyGroup>\r
-    <Error Condition="!Exists('..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.3.0.0\build\Microsoft.CodeAnalysis.VersionCheckAnalyzer.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeAnalysis.VersionCheckAnalyzer.3.0.0\build\Microsoft.CodeAnalysis.VersionCheckAnalyzer.props'))" />\r
-    <Error Condition="!Exists('..\packages\Microsoft.CodeQuality.Analyzers.3.0.0\build\Microsoft.CodeQuality.Analyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeQuality.Analyzers.3.0.0\build\Microsoft.CodeQuality.Analyzers.props'))" />\r
-    <Error Condition="!Exists('..\packages\Microsoft.NetCore.Analyzers.3.0.0\build\Microsoft.NetCore.Analyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.NetCore.Analyzers.3.0.0\build\Microsoft.NetCore.Analyzers.props'))" />\r
-    <Error Condition="!Exists('..\packages\Microsoft.NetFramework.Analyzers.3.0.0\build\Microsoft.NetFramework.Analyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.NetFramework.Analyzers.3.0.0\build\Microsoft.NetFramework.Analyzers.props'))" />\r
-    <Error Condition="!Exists('..\packages\Microsoft.CodeAnalysis.FxCopAnalyzers.3.0.0\build\Microsoft.CodeAnalysis.FxCopAnalyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeAnalysis.FxCopAnalyzers.3.0.0\build\Microsoft.CodeAnalysis.FxCopAnalyzers.props'))" />\r
+    <Error Condition="!Exists('..\packages\Microsoft.CodeAnalysis.NetAnalyzers.7.0.4\build\Microsoft.CodeAnalysis.NetAnalyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeAnalysis.NetAnalyzers.7.0.4\build\Microsoft.CodeAnalysis.NetAnalyzers.props'))" />\r
+    <Error Condition="!Exists('..\packages\Microsoft.CodeAnalysis.NetAnalyzers.7.0.4\build\Microsoft.CodeAnalysis.NetAnalyzers.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeAnalysis.NetAnalyzers.7.0.4\build\Microsoft.CodeAnalysis.NetAnalyzers.targets'))" />\r
   </Target>\r
 </Project>
\ No newline at end of file
index e32eaef..fb42be2 100644 (file)
     <ClCompile Include="..\..\src\object\warning.cpp">\r
       <Filter>object</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\src\io\inet.cpp">\r
-      <Filter>io</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="..\..\src\dungeon\quest.cpp">\r
       <Filter>dungeon</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\src\core\visuals-reseter.cpp">\r
       <Filter>core</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\src\object\object-flags.cpp">\r
-      <Filter>object</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="..\..\src\object\object-info.cpp">\r
       <Filter>object</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\src\io\input-key-acceptor.cpp">\r
       <Filter>io</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\src\util\quarks.cpp">\r
-      <Filter>util</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="..\..\src\view\display-messages.cpp">\r
       <Filter>view</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\src\artifact\fixed-art-generator.cpp">\r
       <Filter>artifact</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\src\artifact\artifact-info.cpp">\r
-      <Filter>artifact</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="..\..\src\system\artifact-type-definition.cpp">\r
       <Filter>system</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\src\system\redrawing-flags-updater.cpp">\r
       <Filter>system</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\..\src\net\curl-easy-session.cpp">\r
+      <Filter>net</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\net\curl-slist.cpp">\r
+      <Filter>net</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\net\http-client.cpp">\r
+      <Filter>net</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\util\sha256.cpp">\r
+      <Filter>util</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\net\report-error.cpp">\r
+      <Filter>net</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\main-win\main-win-exception.cpp">\r
+      <Filter>main-win</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\util\candidate-selector.cpp">\r
+      <Filter>util</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\system\angband-system.cpp">\r
+      <Filter>system</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\src\monster-race\race-sex-const.cpp">\r
+      <Filter>monster-race</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\..\src\combat\shoot.h">\r
     <ClInclude Include="..\..\src\object\warning.h">\r
       <Filter>object</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\src\io\inet.h">\r
-      <Filter>io</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\src\dungeon\quest.h">\r
       <Filter>dungeon</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\src\player-attack\player-attack.h">\r
       <Filter>player-attack</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\src\player-attack\player-attack-util.h">\r
-      <Filter>player-attack</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\src\monster-attack\insults-moans.h">\r
       <Filter>monster-attack</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\src\object-enchant\trg-types.h">\r
       <Filter>object-enchant</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\src\object\object-flags.h">\r
-      <Filter>object</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\src\object\object-info.h">\r
       <Filter>object</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\src\io\input-key-acceptor.h">\r
       <Filter>io</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\src\util\quarks.h">\r
-      <Filter>util</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\src\view\display-messages.h">\r
       <Filter>view</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\src\load\quest-loader.h">\r
       <Filter>load</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\src\core\player-update-types.h">\r
-      <Filter>core</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\src\core\player-redraw-types.h">\r
-      <Filter>core</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\src\flavor\object-flavor-types.h">\r
       <Filter>flavor</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\src\artifact\fixed-art-generator.h">\r
       <Filter>artifact</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\src\artifact\artifact-info.h">\r
-      <Filter>artifact</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="..\..\src\system\artifact-type-definition.h">\r
       <Filter>system</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\src\system\redrawing-flags-updater.h">\r
       <Filter>system</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\src\net\http-client.h">\r
+      <Filter>net</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\net\curl-easy-session.h">\r
+      <Filter>net</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\net\curl-slist.h">\r
+      <Filter>net</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\util\finalizer.h">\r
+      <Filter>util</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\util\sha256.h">\r
+      <Filter>util</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\external-lib\json.hpp">\r
+      <Filter>external-lib</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\external-lib\include-json.h">\r
+      <Filter>external-lib</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\net\report-error.h">\r
+      <Filter>net</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\main-win\main-win-exception.h">\r
+      <Filter>main-win</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\util\candidate-selector.h">\r
+      <Filter>util</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\system\angband-system.h">\r
+      <Filter>system</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\src\monster-race\race-sex-const.h">\r
+      <Filter>monster-race</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <None Include="..\..\src\wall.bmp" />\r
     <Filter Include="item-info">\r
       <UniqueIdentifier>{3aefd2e8-8dd8-41dd-bc6b-7dadd75dfd6b}</UniqueIdentifier>\r
     </Filter>\r
+    <Filter Include="net">\r
+      <UniqueIdentifier>{6f311bdc-4407-49b7-96ab-bc2ed187b61c}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="external-lib">\r
+      <UniqueIdentifier>{7a77d993-afa0-4750-97c6-d52b440fafa9}</UniqueIdentifier>\r
+    </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ResourceCompile Include="..\..\src\angband.rc" />\r
index a73418d..9443524 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 
 /*
  * If you have libcurl problems, all docs and details are found here:
  *   https://curl.se/libcurl/
- *
- * curl-library mailing list subscription and unsubscription web interface:
- *   https://cool.haxx.se/mailman/listinfo/curl-library/
  */
 
 #ifdef CURL_NO_OLDIES
 #define CURL_STRICTER
 #endif
 
+/* Compile-time deprecation macros. */
+#if defined(__GNUC__) &&                                                \
+  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) &&  \
+  !defined(__INTEL_COMPILER) &&                                         \
+  !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
+#define CURL_DEPRECATED(version, message)                       \
+  __attribute__((deprecated("since " # version ". " message)))
+#define CURL_IGNORE_DEPRECATION(statements) \
+      _Pragma("GCC diagnostic push") \
+      _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
+      statements \
+      _Pragma("GCC diagnostic pop")
+#else
+#define CURL_DEPRECATED(version, message)
+#define CURL_IGNORE_DEPRECATION(statements)     statements
+#endif
+
 #include "curlver.h"         /* libcurl version defines   */
 #include "system.h"          /* determine things run-time */
 
@@ -49,8 +65,8 @@
 #include <stdio.h>
 #include <limits.h>
 
-#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
-/* Needed for __FreeBSD_version symbol definition */
+#if (defined(__FreeBSD__) && (__FreeBSD__ >= 2)) || defined(__MidnightBSD__)
+/* Needed for __FreeBSD_version or __MidnightBSD_version symbol definition */
 #include <osreldate.h>
 #endif
 
 #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
     defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
-    defined(__CYGWIN__) || defined(AMIGA) || \
-   (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
+    defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
+   (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
+   (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
+    defined(__sun__) || defined(__serenity__)
 #include <sys/select.h>
 #endif
 
 #include <sys/socket.h>
 #endif
 
-#if !defined(CURL_WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
+#if !defined(CURL_WIN32)
 #include <sys/time.h>
 #endif
 
-#ifdef __BEOS__
-#include <support/SupportDefs.h>
-#endif
-
 /* Compatibility for non-Clang compilers */
 #ifndef __has_declspec_attribute
 #  define __has_declspec_attribute(x) 0
@@ -148,19 +162,21 @@ typedef enum {
   CURLSSLBACKEND_NSS = 3,
   CURLSSLBACKEND_OBSOLETE4 = 4,  /* Was QSOSSL. */
   CURLSSLBACKEND_GSKIT = 5,
-  CURLSSLBACKEND_POLARSSL = 6,
+  CURLSSLBACKEND_POLARSSL               CURL_DEPRECATED(7.69.0, "") = 6,
   CURLSSLBACKEND_WOLFSSL = 7,
   CURLSSLBACKEND_SCHANNEL = 8,
   CURLSSLBACKEND_SECURETRANSPORT = 9,
-  CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */
+  CURLSSLBACKEND_AXTLS                  CURL_DEPRECATED(7.61.0, "") = 10,
   CURLSSLBACKEND_MBEDTLS = 11,
-  CURLSSLBACKEND_MESALINK = 12,
-  CURLSSLBACKEND_BEARSSL = 13
+  CURLSSLBACKEND_MESALINK               CURL_DEPRECATED(7.82.0, "") = 12,
+  CURLSSLBACKEND_BEARSSL = 13,
+  CURLSSLBACKEND_RUSTLS = 14
 } curl_sslbackend;
 
 /* aliases for library clones and renames */
-#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL
+#define CURLSSLBACKEND_AWSLC CURLSSLBACKEND_OPENSSL
 #define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL
+#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL
 
 /* deprecated names: */
 #define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL
@@ -234,7 +250,7 @@ typedef int (*curl_xferinfo_callback)(void *clientp,
 
 #ifndef CURL_MAX_READ_SIZE
   /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */
-#define CURL_MAX_READ_SIZE 524288
+#define CURL_MAX_READ_SIZE (10*1024*1024)
 #endif
 
 #ifndef CURL_MAX_WRITE_SIZE
@@ -258,6 +274,10 @@ typedef int (*curl_xferinfo_callback)(void *clientp,
    will signal libcurl to pause receiving on the current transfer. */
 #define CURL_WRITEFUNC_PAUSE 0x10000001
 
+/* This is a magic return code for the write callback that, when returned,
+   will signal an error from the callback. */
+#define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
+
 typedef size_t (*curl_write_callback)(char *buffer,
                                       size_t size,
                                       size_t nitems,
@@ -312,7 +332,8 @@ struct curl_fileinfo {
 
   unsigned int flags;
 
-  /* used internally */
+  /* These are libcurl private struct fields. Previously used by libcurl, so
+     they must never be interfered with. */
   char *b_data;
   size_t b_size;
   size_t b_used;
@@ -370,7 +391,7 @@ typedef int (*curl_seek_callback)(void *instream,
 #define CURL_READFUNC_PAUSE 0x10000001
 
 /* Return code for when the trailing headers' callback has terminated
-   without any errors*/
+   without any errors */
 #define CURL_TRAILERFUNC_OK 0
 /* Return code for when was an error in the trailing header's list and we
   want to abort the request */
@@ -452,7 +473,7 @@ typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
 #define CURL_DID_MEMORY_FUNC_TYPEDEFS
 #endif
 
-/* the kind of data that is passed to information_callback*/
+/* the kind of data that is passed to information_callback */
 typedef enum {
   CURLINFO_TEXT = 0,
   CURLINFO_HEADER_IN,    /* 1 */
@@ -471,6 +492,20 @@ typedef int (*curl_debug_callback)
         size_t size,       /* size of the data pointed to */
         void *userptr);    /* whatever the user please */
 
+/* This is the CURLOPT_PREREQFUNCTION callback prototype. */
+typedef int (*curl_prereq_callback)(void *clientp,
+                                    char *conn_primary_ip,
+                                    char *conn_local_ip,
+                                    int conn_primary_port,
+                                    int conn_local_port);
+
+/* Return code for when the pre-request callback has terminated without
+   any errors */
+#define CURL_PREREQFUNC_OK 0
+/* Return code for when the pre-request callback wants to abort the
+   request */
+#define CURL_PREREQFUNC_ABORT 1
+
 /* All possible error codes from all sorts of curl functions. Future versions
    may return other values, stay prepared.
 
@@ -515,10 +550,6 @@ typedef enum {
   CURLE_UPLOAD_FAILED,           /* 25 - failed upload "command" */
   CURLE_READ_ERROR,              /* 26 - couldn't open/read from file */
   CURLE_OUT_OF_MEMORY,           /* 27 */
-  /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
-           instead of a memory allocation error if CURL_DOES_CONVERSIONS
-           is defined
-  */
   CURLE_OPERATION_TIMEDOUT,      /* 28 - the timeout time was reached */
   CURLE_OBSOLETE29,              /* 29 - NOT USED */
   CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
@@ -540,7 +571,7 @@ typedef enum {
   CURLE_OBSOLETE46,              /* 46 - NOT USED */
   CURLE_TOO_MANY_REDIRECTS,      /* 47 - catch endless re-direct loops */
   CURLE_UNKNOWN_OPTION,          /* 48 - User specified an unknown option */
-  CURLE_TELNET_OPTION_SYNTAX,    /* 49 - Malformed telnet option */
+  CURLE_SETOPT_OPTION_SYNTAX,    /* 49 - Malformed setopt option */
   CURLE_OBSOLETE50,              /* 50 - NOT USED */
   CURLE_OBSOLETE51,              /* 51 - NOT USED */
   CURLE_GOT_NOTHING,             /* 52 - when this is a specific error */
@@ -555,7 +586,7 @@ typedef enum {
   CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
                                      wasn't verified fine */
   CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized/bad encoding */
-  CURLE_LDAP_INVALID_URL,        /* 62 - Invalid LDAP URL */
+  CURLE_OBSOLETE62,              /* 62 - NOT IN USE since 7.82.0 */
   CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
   CURLE_USE_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
   CURLE_SEND_FAIL_REWIND,        /* 65 - Sending the data requires a rewind
@@ -570,12 +601,8 @@ typedef enum {
   CURLE_TFTP_UNKNOWNID,          /* 72 - Unknown transfer ID */
   CURLE_REMOTE_FILE_EXISTS,      /* 73 - File already exists */
   CURLE_TFTP_NOSUCHUSER,         /* 74 - No such user */
-  CURLE_CONV_FAILED,             /* 75 - conversion failed */
-  CURLE_CONV_REQD,               /* 76 - caller must register conversion
-                                    callbacks using curl_easy_setopt options
-                                    CURLOPT_CONV_FROM_NETWORK_FUNCTION,
-                                    CURLOPT_CONV_TO_NETWORK_FUNCTION, and
-                                    CURLOPT_CONV_FROM_UTF8_FUNCTION */
+  CURLE_OBSOLETE75,              /* 75 - NOT IN USE since 7.82.0 */
+  CURLE_OBSOLETE76,              /* 76 - NOT IN USE since 7.82.0 */
   CURLE_SSL_CACERT_BADFILE,      /* 77 - could not load CACERT file, missing
                                     or wrong format */
   CURLE_REMOTE_FILE_NOT_FOUND,   /* 78 - remote file not found */
@@ -611,6 +638,8 @@ typedef enum {
   CURLE_HTTP3,                   /* 95 - An HTTP/3 layer problem */
   CURLE_QUIC_CONNECT_ERROR,      /* 96 - QUIC connection error */
   CURLE_PROXY,                   /* 97 - proxy handshake error */
+  CURLE_SSL_CLIENTCERT,          /* 98 - client-side certificate required */
+  CURLE_UNRECOVERABLE_POLL,      /* 99 - poll/select returned fatal error */
   CURL_LAST /* never use! */
 } CURLcode;
 
@@ -634,6 +663,9 @@ typedef enum {
 /* The following were added in 7.21.5, April 2011 */
 #define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
 
+/* Added for 7.78.0 */
+#define CURLE_TELNET_OPTION_SYNTAX CURLE_SETOPT_OPTION_SYNTAX
+
 /* The following were added in 7.17.1 */
 /* These are scheduled to disappear by 2009 */
 #define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION
@@ -665,13 +697,14 @@ typedef enum {
 /* The following were added earlier */
 
 #define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT
-
 #define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
 #define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
 #define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED
-
 #define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
 #define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+#define CURLE_LDAP_INVALID_URL CURLE_OBSOLETE62
+#define CURLE_CONV_REQD CURLE_OBSOLETE76
+#define CURLE_CONV_FAILED CURLE_OBSOLETE75
 
 /* This was the error code 50 in 7.7.3 and a few earlier versions, this
    is no longer used by libcurl but is instead #defined here only to not
@@ -688,7 +721,7 @@ typedef enum {
 #define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
 #define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
 
-#endif /*!CURL_NO_OLDIES*/
+#endif /* !CURL_NO_OLDIES */
 
 /*
  * Proxy error codes. Returned in CURLINFO_PROXY_ERROR if CURLE_PROXY was
@@ -747,7 +780,8 @@ typedef enum {
                            CONNECT HTTP/1.1 */
   CURLPROXY_HTTP_1_0 = 1,   /* added in 7.19.4, force to use CONNECT
                                HTTP/1.0  */
-  CURLPROXY_HTTPS = 2, /* added in 7.52.0 */
+  CURLPROXY_HTTPS = 2,  /* HTTPS but stick to HTTP/1 added in 7.52.0 */
+  CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.1.0 */
   CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
                            in 7.10 */
   CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
@@ -787,6 +821,7 @@ typedef enum {
 #define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
 #define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
 #define CURLAUTH_BEARER       (((unsigned long)1)<<6)
+#define CURLAUTH_AWS_SIGV4    (((unsigned long)1)<<7)
 #define CURLAUTH_ONLY         (((unsigned long)1)<<31)
 #define CURLAUTH_ANY          (~CURLAUTH_DIGEST_IE)
 #define CURLAUTH_ANYSAFE      (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
@@ -829,10 +864,10 @@ enum curl_khstat {
   CURLKHSTAT_FINE_ADD_TO_FILE,
   CURLKHSTAT_FINE,
   CURLKHSTAT_REJECT, /* reject the connection, return an error */
-  CURLKHSTAT_DEFER,  /* do not accept it, but we can't answer right now so
-                        this causes a CURLE_DEFER error but otherwise the
+  CURLKHSTAT_DEFER,  /* do not accept it, but we can't answer right now.
+                        Causes a CURLE_PEER_FAILED_VERIFICATION error but the
                         connection will be left intact etc */
-  CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key*/
+  CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */
   CURLKHSTAT_LAST    /* not for use, only a marker for last-in-list */
 };
 
@@ -849,7 +884,18 @@ typedef int
                           const struct curl_khkey *knownkey, /* known */
                           const struct curl_khkey *foundkey, /* found */
                           enum curl_khmatch, /* libcurl's view on the keys */
-                          void *clientp); /* custom pointer passed from app */
+                          void *clientp); /* custom pointer passed with */
+                                          /* CURLOPT_SSH_KEYDATA */
+
+typedef int
+  (*curl_sshhostkeycallback) (void *clientp,/* custom pointer passed */
+                                            /* with CURLOPT_SSH_HOSTKEYDATA */
+                          int keytype, /* CURLKHTYPE */
+                          const char *key, /* hostkey to check */
+                          size_t keylen); /* length of the key */
+                          /* return CURLE_OK to accept */
+                          /* or something else to refuse */
+
 
 /* parameter for the CURLOPT_USE_SSL option */
 typedef enum {
@@ -886,6 +932,10 @@ typedef enum {
    operating system. Currently implemented under MS-Windows. */
 #define CURLSSLOPT_NATIVE_CA (1<<4)
 
+/* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use
+   a client certificate for authentication. (Schannel) */
+#define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5)
+
 /* The default connection attempt delay in milliseconds for happy eyeballs.
    CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
    this value, keep them in sync. */
@@ -906,7 +956,7 @@ typedef enum {
 #define CURLFTPSSL_ALL CURLUSESSL_ALL
 #define CURLFTPSSL_LAST CURLUSESSL_LAST
 #define curl_ftpssl curl_usessl
-#endif /*!CURL_NO_OLDIES*/
+#endif /* !CURL_NO_OLDIES */
 
 /* parameter for the CURLOPT_FTP_SSL_CCC option */
 typedef enum {
@@ -985,7 +1035,8 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
 #define CURLHSTS_ENABLE       (long)(1<<0)
 #define CURLHSTS_READONLYFILE (long)(1<<1)
 
-/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
+/* The CURLPROTO_ defines below are for the **deprecated** CURLOPT_*PROTOCOLS
+   options. Do not use. */
 #define CURLPROTO_HTTP   (1<<0)
 #define CURLPROTO_HTTPS  (1<<1)
 #define CURLPROTO_FTP    (1<<2)
@@ -1015,6 +1066,7 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
 #define CURLPROTO_SMB    (1<<26)
 #define CURLPROTO_SMBS   (1<<27)
 #define CURLPROTO_MQTT   (1<<28)
+#define CURLPROTO_GOPHERS (1<<29)
 #define CURLPROTO_ALL    (~0) /* enable everything */
 
 /* long may be 32 or 64 bits, but we should never depend on anything else
@@ -1030,6 +1082,7 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
 
 
 #define CURLOPT(na,t,nu) na = t + nu
+#define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu
 
 /* CURLOPT aliases that make no run-time difference */
 
@@ -1091,7 +1144,7 @@ typedef enum {
   /* Time-out the read operation after this amount of seconds */
   CURLOPT(CURLOPT_TIMEOUT, CURLOPTTYPE_LONG, 13),
 
-  /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
+  /* If CURLOPT_READDATA is used, this can be used to inform libcurl about
    * how large the file being sent really is. That allows better error
    * checking and better verifies that the upload was successful. -1 means
    * unknown size.
@@ -1143,7 +1196,8 @@ typedef enum {
   CURLOPT(CURLOPT_HTTPHEADER, CURLOPTTYPE_SLISTPOINT, 23),
 
   /* This points to a linked list of post entries, struct curl_httppost */
-  CURLOPT(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24),
+  CURLOPTDEPRECATED(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24,
+                    7.56.0, "Use CURLOPT_MIMEPOST"),
 
   /* name of the file keeping your private SSL-certificate */
   CURLOPT(CURLOPT_SSLCERT, CURLOPTTYPE_STRINGPOINT, 25),
@@ -1233,7 +1287,8 @@ typedef enum {
   CURLOPT(CURLOPT_TRANSFERTEXT, CURLOPTTYPE_LONG, 53),
 
   /* HTTP PUT */
-  CURLOPT(CURLOPT_PUT, CURLOPTTYPE_LONG, 54),
+  CURLOPTDEPRECATED(CURLOPT_PUT, CURLOPTTYPE_LONG, 54,
+                    7.12.1, "Use CURLOPT_UPLOAD"),
 
   /* 55 = OBSOLETE */
 
@@ -1241,7 +1296,8 @@ typedef enum {
    * Function that will be called instead of the internal progress display
    * function. This function should be defined as the curl_progress_callback
    * prototype defines. */
-  CURLOPT(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56),
+  CURLOPTDEPRECATED(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56,
+                    7.32.0, "Use CURLOPT_XFERINFOFUNCTION"),
 
   /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
      callbacks */
@@ -1258,7 +1314,7 @@ typedef enum {
   /* size of the POST input data, if strlen() is not good to use */
   CURLOPT(CURLOPT_POSTFIELDSIZE, CURLOPTTYPE_LONG, 60),
 
-  /* tunnel non-http operations through a HTTP proxy */
+  /* tunnel non-http operations through an HTTP proxy */
   CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61),
 
   /* Set the interface string to use as outgoing network interface */
@@ -1309,10 +1365,12 @@ typedef enum {
 
   /* Set to a file name that contains random data for libcurl to use to
      seed the random engine when doing SSL connects. */
-  CURLOPT(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76),
+  CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76,
+                    7.84.0, "Serves no purpose anymore"),
 
   /* Set to the Entropy Gathering Daemon socket pathname */
-  CURLOPT(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77),
+  CURLOPTDEPRECATED(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77,
+                    7.84.0, "Serves no purpose anymore"),
 
   /* Time-out connect operations after this amount of seconds, if connects are
      OK within this time, then fine... This only aborts the connect phase. */
@@ -1367,7 +1425,8 @@ typedef enum {
 
   /* Non-zero value means to use the global dns cache */
   /* DEPRECATED, do not use! */
-  CURLOPT(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91),
+  CURLOPTDEPRECATED(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91,
+                    7.11.1, "Use CURLOPT_SHARE"),
 
   /* DNS cache timeout */
   CURLOPT(CURLOPT_DNS_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 92),
@@ -1450,16 +1509,15 @@ typedef enum {
      Note that setting multiple bits may cause extra network round-trips. */
   CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111),
 
-  /* FTP option that changes the timeout, in seconds, associated with
-     getting a response.  This is different from transfer timeout time and
-     essentially places a demand on the FTP server to acknowledge commands
-     in a timely manner. */
-  CURLOPT(CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112),
-#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
+  /* Option that changes the timeout, in seconds, associated with getting a
+     response.  This is different from transfer timeout time and essentially
+     places a demand on the server to acknowledge commands in a timely
+     manner. For FTP, SMTP, IMAP and POP3. */
+  CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112),
 
   /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
-     tell libcurl to resolve names to those IP versions only. This only has
-     affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
+     tell libcurl to use those IP versions only. This only has effect on
+     systems with support for more than one, i.e IPv4 _and_ IPv6. */
   CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),
 
   /* Set this option to limit the size of a file that will be downloaded from
@@ -1523,8 +1581,10 @@ typedef enum {
   */
   CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_VALUES, 129),
 
-  CURLOPT(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130),
-  CURLOPT(CURLOPT_IOCTLDATA, CURLOPTTYPE_CBPOINT, 131),
+  CURLOPTDEPRECATED(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130,
+                    7.18.0, "Use CURLOPT_SEEKFUNCTION"),
+  CURLOPTDEPRECATED(CURLOPT_IOCTLDATA, CURLOPTTYPE_CBPOINT, 131,
+                    7.18.0, "Use CURLOPT_SEEKDATA"),
 
   /* 132 OBSOLETE. Gone in 7.16.0 */
   /* 133 OBSOLETE. Gone in 7.16.0 */
@@ -1563,16 +1623,22 @@ typedef enum {
 
   /* Function that will be called to convert from the
      network encoding (instead of using the iconv calls in libcurl) */
-  CURLOPT(CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 142),
+  CURLOPTDEPRECATED(CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+                    CURLOPTTYPE_FUNCTIONPOINT, 142,
+                    7.82.0, "Serves no purpose anymore"),
 
   /* Function that will be called to convert to the
      network encoding (instead of using the iconv calls in libcurl) */
-  CURLOPT(CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 143),
+  CURLOPTDEPRECATED(CURLOPT_CONV_TO_NETWORK_FUNCTION,
+                    CURLOPTTYPE_FUNCTIONPOINT, 143,
+                    7.82.0, "Serves no purpose anymore"),
 
   /* Function that will be called to convert from UTF8
      (instead of using the iconv calls in libcurl)
      Note that this is used only for SSL certificate processing */
-  CURLOPT(CURLOPT_CONV_FROM_UTF8_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 144),
+  CURLOPTDEPRECATED(CURLOPT_CONV_FROM_UTF8_FUNCTION,
+                    CURLOPTTYPE_FUNCTIONPOINT, 144,
+                    7.82.0, "Serves no purpose anymore"),
 
   /* if the connection proceeds too quickly then need to slow it down */
   /* limit-rate: maximum number of bytes per second to send or receive */
@@ -1614,7 +1680,7 @@ typedef enum {
   CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159),
   CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160),
 
-  /* Set the behaviour of POST when redirecting. Values must be set to one
+  /* Set the behavior of POST when redirecting. Values must be set to one
      of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
   CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_VALUES, 161),
 
@@ -1673,7 +1739,9 @@ typedef enum {
 
   /* Socks Service */
   /* DEPRECATED, do not use! */
-  CURLOPT(CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOPTTYPE_STRINGPOINT, 179),
+  CURLOPTDEPRECATED(CURLOPT_SOCKS5_GSSAPI_SERVICE,
+                    CURLOPTTYPE_STRINGPOINT, 179,
+                    7.49.0, "Use CURLOPT_PROXY_SERVICE_NAME"),
 
   /* Socks Service */
   CURLOPT(CURLOPT_SOCKS5_GSSAPI_NEC, CURLOPTTYPE_LONG, 180),
@@ -1682,12 +1750,14 @@ typedef enum {
      transfer, which thus helps the app which takes URLs from users or other
      external inputs and want to restrict what protocol(s) to deal
      with. Defaults to CURLPROTO_ALL. */
-  CURLOPT(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181),
+  CURLOPTDEPRECATED(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181,
+                    7.85.0, "Use CURLOPT_PROTOCOLS_STR"),
 
   /* set the bitmask for the protocols that libcurl is allowed to follow to,
      as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
      to be set in both bitmasks to be allowed to get redirected to. */
-  CURLOPT(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182),
+  CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182,
+                    7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"),
 
   /* set the SSH knownhost file name to use */
   CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183),
@@ -1832,12 +1902,13 @@ typedef enum {
   CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224),
 
   /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */
-  CURLOPT(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225),
+  CURLOPTDEPRECATED(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225,
+                    7.86.0, "Has no function"),
 
   /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */
   CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226),
 
-  /* Time to wait for a response to a HTTP request containing an
+  /* Time to wait for a response to an HTTP request containing an
    * Expect: 100-continue header before sending the data anyway. */
   CURLOPT(CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOPTTYPE_LONG, 227),
 
@@ -2034,10 +2105,11 @@ typedef enum {
   /* alt-svc cache file name to possibly read from/write to */
   CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),
 
-  /* maximum age of a connection to consider it for reuse (in seconds) */
+  /* maximum age (idle time) of a connection to consider it for reuse
+   * (in seconds) */
   CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),
 
-  /* SASL authorisation identity */
+  /* SASL authorization identity */
   CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289),
 
   /* allow RCPT TO command to fail for some recipients */
@@ -2073,6 +2145,68 @@ typedef enum {
   CURLOPT(CURLOPT_HSTSWRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 303),
   CURLOPT(CURLOPT_HSTSWRITEDATA, CURLOPTTYPE_CBPOINT, 304),
 
+  /* Parameters for V4 signature */
+  CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305),
+
+  /* Same as CURLOPT_SSL_VERIFYPEER but for DoH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 306),
+
+  /* Same as CURLOPT_SSL_VERIFYHOST but for DoH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 307),
+
+  /* Same as CURLOPT_SSL_VERIFYSTATUS but for DoH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308),
+
+  /* The CA certificates as "blob" used to validate the peer certificate
+     this option is used only if SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_CAINFO_BLOB, CURLOPTTYPE_BLOB, 309),
+
+  /* The CA certificates as "blob" used to validate the proxy certificate
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
+
+  /* used by scp/sftp to verify the host's public key */
+  CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPTTYPE_STRINGPOINT, 311),
+
+  /* Function that will be called immediately before the initial request
+     is made on a connection (after any protocol negotiation step).  */
+  CURLOPT(CURLOPT_PREREQFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 312),
+
+  /* Data passed to the CURLOPT_PREREQFUNCTION callback */
+  CURLOPT(CURLOPT_PREREQDATA, CURLOPTTYPE_CBPOINT, 313),
+
+  /* maximum age (since creation) of a connection to consider it for reuse
+   * (in seconds) */
+  CURLOPT(CURLOPT_MAXLIFETIME_CONN, CURLOPTTYPE_LONG, 314),
+
+  /* Set MIME option flags. */
+  CURLOPT(CURLOPT_MIME_OPTIONS, CURLOPTTYPE_LONG, 315),
+
+  /* set the SSH host key callback, must point to a curl_sshkeycallback
+     function */
+  CURLOPT(CURLOPT_SSH_HOSTKEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 316),
+
+  /* set the SSH host key callback custom pointer */
+  CURLOPT(CURLOPT_SSH_HOSTKEYDATA, CURLOPTTYPE_CBPOINT, 317),
+
+  /* specify which protocols that are allowed to be used for the transfer,
+     which thus helps the app which takes URLs from users or other external
+     inputs and want to restrict what protocol(s) to deal with. Defaults to
+     all built-in protocols. */
+  CURLOPT(CURLOPT_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 318),
+
+  /* specify which protocols that libcurl is allowed to follow directs to */
+  CURLOPT(CURLOPT_REDIR_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 319),
+
+  /* websockets options */
+  CURLOPT(CURLOPT_WS_OPTIONS, CURLOPTTYPE_LONG, 320),
+
+  /* CA cache timeout */
+  CURLOPT(CURLOPT_CA_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 321),
+
+  /* Can leak things, gonna exit() soon */
+  CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -2098,6 +2232,9 @@ typedef enum {
 #define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD
 #define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL
 
+/* */
+#define CURLOPT_FTP_RESPONSE_TIMEOUT CURLOPT_SERVER_RESPONSE_TIMEOUT
+
 #else
 /* This is set if CURL_NO_OLDIES is defined at compile-time */
 #undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
@@ -2107,12 +2244,12 @@ typedef enum {
   /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
      name resolves addresses using more than one IP protocol version, this
      option might be handy to force libcurl to use a specific IP version. */
-#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
+#define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP
                                      versions that your system allows */
-#define CURL_IPRESOLVE_V4       1 /* resolve to IPv4 addresses */
-#define CURL_IPRESOLVE_V6       2 /* resolve to IPv6 addresses */
+#define CURL_IPRESOLVE_V4       1 /* uses only IPv4 addresses/connections */
+#define CURL_IPRESOLVE_V6       2 /* uses only IPv6 addresses/connections */
 
-  /* three convenient "aliases" that follow the name scheme better */
+  /* Convenient "aliases" */
 #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
 
   /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
@@ -2126,8 +2263,13 @@ enum {
   CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
   CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE,  /* please use HTTP 2 without HTTP/1.1
                                            Upgrade */
-  CURL_HTTP_VERSION_3 = 30, /* Makes use of explicit HTTP/3 without fallback.
-                               Use CURLOPT_ALTSVC to enable HTTP/3 upgrade */
+  CURL_HTTP_VERSION_3 = 30, /* Use HTTP/3, fallback to HTTP/2 or HTTP/1 if
+                               needed. For HTTPS only. For HTTP, this option
+                               makes libcurl return error. */
+  CURL_HTTP_VERSION_3ONLY = 31, /* Use HTTP/3 without fallback. For HTTPS
+                                   only. For HTTP, this makes libcurl
+                                   return error. */
+
   CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
 };
 
@@ -2232,6 +2374,9 @@ CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n);
 typedef struct curl_mime      curl_mime;      /* Mime context. */
 typedef struct curl_mimepart  curl_mimepart;  /* Mime part context. */
 
+/* CURLMIMEOPT_ defines are for the CURLOPT_MIME_OPTIONS option. */
+#define CURLMIMEOPT_FORMESCAPE  (1<<0) /* Use backslash-escaping for forms. */
+
 /*
  * NAME curl_mime_init()
  *
@@ -2354,30 +2499,32 @@ CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part,
                                        int take_ownership);
 
 typedef enum {
-  CURLFORM_NOTHING,        /********* the first one is unused ************/
-  CURLFORM_COPYNAME,
-  CURLFORM_PTRNAME,
-  CURLFORM_NAMELENGTH,
-  CURLFORM_COPYCONTENTS,
-  CURLFORM_PTRCONTENTS,
-  CURLFORM_CONTENTSLENGTH,
-  CURLFORM_FILECONTENT,
-  CURLFORM_ARRAY,
+  /********* the first one is unused ************/
+  CURLFORM_NOTHING         CURL_DEPRECATED(7.56.0, ""),
+  CURLFORM_COPYNAME        CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"),
+  CURLFORM_PTRNAME         CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"),
+  CURLFORM_NAMELENGTH      CURL_DEPRECATED(7.56.0, ""),
+  CURLFORM_COPYCONTENTS    CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+  CURLFORM_PTRCONTENTS     CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+  CURLFORM_CONTENTSLENGTH  CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+  CURLFORM_FILECONTENT     CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"),
+  CURLFORM_ARRAY           CURL_DEPRECATED(7.56.0, ""),
   CURLFORM_OBSOLETE,
-  CURLFORM_FILE,
+  CURLFORM_FILE            CURL_DEPRECATED(7.56.0, "Use curl_mime_filedata()"),
 
-  CURLFORM_BUFFER,
-  CURLFORM_BUFFERPTR,
-  CURLFORM_BUFFERLENGTH,
+  CURLFORM_BUFFER          CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"),
+  CURLFORM_BUFFERPTR       CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
+  CURLFORM_BUFFERLENGTH    CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
 
-  CURLFORM_CONTENTTYPE,
-  CURLFORM_CONTENTHEADER,
-  CURLFORM_FILENAME,
+  CURLFORM_CONTENTTYPE     CURL_DEPRECATED(7.56.0, "Use curl_mime_type()"),
+  CURLFORM_CONTENTHEADER   CURL_DEPRECATED(7.56.0, "Use curl_mime_headers()"),
+  CURLFORM_FILENAME        CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"),
   CURLFORM_END,
   CURLFORM_OBSOLETE2,
 
-  CURLFORM_STREAM,
-  CURLFORM_CONTENTLEN, /* added in 7.46.0, provide a curl_off_t length */
+  CURLFORM_STREAM          CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"),
+  CURLFORM_CONTENTLEN  /* added in 7.46.0, provide a curl_off_t length */
+                           CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"),
 
   CURLFORM_LASTENTRY /* the last unused */
 } CURLformoption;
@@ -2405,15 +2552,16 @@ struct curl_forms {
  *
  ***************************************************************************/
 typedef enum {
-  CURL_FORMADD_OK, /* first, no error */
+  CURL_FORMADD_OK             CURL_DEPRECATED(7.56.0, ""), /* 1st, no error */
 
-  CURL_FORMADD_MEMORY,
-  CURL_FORMADD_OPTION_TWICE,
-  CURL_FORMADD_NULL,
-  CURL_FORMADD_UNKNOWN_OPTION,
-  CURL_FORMADD_INCOMPLETE,
-  CURL_FORMADD_ILLEGAL_ARRAY,
-  CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
+  CURL_FORMADD_MEMORY         CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_OPTION_TWICE   CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_NULL           CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_UNKNOWN_OPTION CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_INCOMPLETE     CURL_DEPRECATED(7.56.0, ""),
+  CURL_FORMADD_ILLEGAL_ARRAY  CURL_DEPRECATED(7.56.0, ""),
+  /* libcurl was built with form api disabled */
+  CURL_FORMADD_DISABLED       CURL_DEPRECATED(7.56.0, ""),
 
   CURL_FORMADD_LAST /* last */
 } CURLFORMcode;
@@ -2427,9 +2575,10 @@ typedef enum {
  * adds one part that together construct a full post. Then use
  * CURLOPT_HTTPPOST to send it off to libcurl.
  */
-CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
-                                      struct curl_httppost **last_post,
-                                      ...);
+CURL_EXTERN CURLFORMcode CURL_DEPRECATED(7.56.0, "Use curl_mime_init()")
+curl_formadd(struct curl_httppost **httppost,
+             struct curl_httppost **last_post,
+             ...);
 
 /*
  * callback function for curl_formget()
@@ -2452,8 +2601,9 @@ typedef size_t (*curl_formget_callback)(void *arg, const char *buf,
  * the curl_formget_callback function.
  * Returns 0 on success.
  */
-CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
-                             curl_formget_callback append);
+CURL_EXTERN int CURL_DEPRECATED(7.56.0, "")
+curl_formget(struct curl_httppost *form, void *arg,
+             curl_formget_callback append);
 /*
  * NAME curl_formfree()
  *
@@ -2461,7 +2611,8 @@ CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
  *
  * Free a multipart formpost previously built with curl_formadd().
  */
-CURL_EXTERN void curl_formfree(struct curl_httppost *form);
+CURL_EXTERN void CURL_DEPRECATED(7.56.0, "Use curl_mime_free()")
+curl_formfree(struct curl_httppost *form);
 
 /*
  * NAME curl_getenv()
@@ -2537,8 +2688,10 @@ CURL_EXTERN void curl_free(void *p);
  *
  * curl_global_init() should be invoked exactly once for each application that
  * uses libcurl and before any call of other libcurl functions.
- *
- * This function is not thread-safe!
+
+ * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the
+ * curl_version_info_data.features flag (fetch by curl_version_info()).
+
  */
 CURL_EXTERN CURLcode curl_global_init(long flags);
 
@@ -2628,8 +2781,8 @@ CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
  * Appends a string to a linked list. If no list exists, it will be created
  * first. Returns the new list, after appending.
  */
-CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
-                                                 const char *);
+CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *list,
+                                                 const char *data);
 
 /*
  * NAME curl_slist_free_all()
@@ -2638,7 +2791,7 @@ CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
  *
  * free a previously built curl_slist.
  */
-CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
+CURL_EXTERN void curl_slist_free_all(struct curl_slist *list);
 
 /*
  * NAME curl_getdate()
@@ -2686,22 +2839,35 @@ typedef enum {
   CURLINFO_NAMELOOKUP_TIME  = CURLINFO_DOUBLE + 4,
   CURLINFO_CONNECT_TIME     = CURLINFO_DOUBLE + 5,
   CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
-  CURLINFO_SIZE_UPLOAD      = CURLINFO_DOUBLE + 7,
+  CURLINFO_SIZE_UPLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_UPLOAD_T")
+                            = CURLINFO_DOUBLE + 7,
   CURLINFO_SIZE_UPLOAD_T    = CURLINFO_OFF_T  + 7,
-  CURLINFO_SIZE_DOWNLOAD    = CURLINFO_DOUBLE + 8,
+  CURLINFO_SIZE_DOWNLOAD
+                       CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_DOWNLOAD_T")
+                            = CURLINFO_DOUBLE + 8,
   CURLINFO_SIZE_DOWNLOAD_T  = CURLINFO_OFF_T  + 8,
-  CURLINFO_SPEED_DOWNLOAD   = CURLINFO_DOUBLE + 9,
+  CURLINFO_SPEED_DOWNLOAD
+                       CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_DOWNLOAD_T")
+                            = CURLINFO_DOUBLE + 9,
   CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T  + 9,
-  CURLINFO_SPEED_UPLOAD     = CURLINFO_DOUBLE + 10,
+  CURLINFO_SPEED_UPLOAD
+                       CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_UPLOAD_T")
+                            = CURLINFO_DOUBLE + 10,
   CURLINFO_SPEED_UPLOAD_T   = CURLINFO_OFF_T  + 10,
   CURLINFO_HEADER_SIZE      = CURLINFO_LONG   + 11,
   CURLINFO_REQUEST_SIZE     = CURLINFO_LONG   + 12,
   CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG   + 13,
   CURLINFO_FILETIME         = CURLINFO_LONG   + 14,
   CURLINFO_FILETIME_T       = CURLINFO_OFF_T  + 14,
-  CURLINFO_CONTENT_LENGTH_DOWNLOAD   = CURLINFO_DOUBLE + 15,
+  CURLINFO_CONTENT_LENGTH_DOWNLOAD
+                       CURL_DEPRECATED(7.55.0,
+                                      "Use CURLINFO_CONTENT_LENGTH_DOWNLOAD_T")
+                            = CURLINFO_DOUBLE + 15,
   CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T  + 15,
-  CURLINFO_CONTENT_LENGTH_UPLOAD     = CURLINFO_DOUBLE + 16,
+  CURLINFO_CONTENT_LENGTH_UPLOAD
+                       CURL_DEPRECATED(7.55.0,
+                                       "Use CURLINFO_CONTENT_LENGTH_UPLOAD_T")
+                            = CURLINFO_DOUBLE + 16,
   CURLINFO_CONTENT_LENGTH_UPLOAD_T   = CURLINFO_OFF_T  + 16,
   CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
   CURLINFO_CONTENT_TYPE     = CURLINFO_STRING + 18,
@@ -2715,7 +2881,8 @@ typedef enum {
   CURLINFO_NUM_CONNECTS     = CURLINFO_LONG   + 26,
   CURLINFO_SSL_ENGINES      = CURLINFO_SLIST  + 27,
   CURLINFO_COOKIELIST       = CURLINFO_SLIST  + 28,
-  CURLINFO_LASTSOCKET       = CURLINFO_LONG   + 29,
+  CURLINFO_LASTSOCKET  CURL_DEPRECATED(7.45.0, "Use CURLINFO_ACTIVESOCKET")
+                            = CURLINFO_LONG   + 29,
   CURLINFO_FTP_ENTRY_PATH   = CURLINFO_STRING + 30,
   CURLINFO_REDIRECT_URL     = CURLINFO_STRING + 31,
   CURLINFO_PRIMARY_IP       = CURLINFO_STRING + 32,
@@ -2729,12 +2896,14 @@ typedef enum {
   CURLINFO_PRIMARY_PORT     = CURLINFO_LONG   + 40,
   CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
   CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
-  CURLINFO_TLS_SESSION      = CURLINFO_PTR    + 43,
+  CURLINFO_TLS_SESSION CURL_DEPRECATED(7.48.0, "Use CURLINFO_TLS_SSL_PTR")
+                            = CURLINFO_PTR    + 43,
   CURLINFO_ACTIVESOCKET     = CURLINFO_SOCKET + 44,
   CURLINFO_TLS_SSL_PTR      = CURLINFO_PTR    + 45,
   CURLINFO_HTTP_VERSION     = CURLINFO_LONG   + 46,
   CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47,
-  CURLINFO_PROTOCOL         = CURLINFO_LONG   + 48,
+  CURLINFO_PROTOCOL    CURL_DEPRECATED(7.85.0, "Use CURLINFO_SCHEME")
+                            = CURLINFO_LONG   + 48,
   CURLINFO_SCHEME           = CURLINFO_STRING + 49,
   CURLINFO_TOTAL_TIME_T     = CURLINFO_OFF_T + 50,
   CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51,
@@ -2746,8 +2915,10 @@ typedef enum {
   CURLINFO_RETRY_AFTER      = CURLINFO_OFF_T + 57,
   CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58,
   CURLINFO_PROXY_ERROR      = CURLINFO_LONG + 59,
-
-  CURLINFO_LASTONE          = 59
+  CURLINFO_REFERER          = CURLINFO_STRING + 60,
+  CURLINFO_CAINFO           = CURLINFO_STRING + 61,
+  CURLINFO_CAPATH           = CURLINFO_STRING + 62,
+  CURLINFO_LASTONE          = 62
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -2766,7 +2937,7 @@ typedef enum {
   CURLCLOSEPOLICY_LAST /* last, never use this */
 } curl_closepolicy;
 
-#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */
+#define CURL_GLOBAL_SSL (1<<0) /* no purpose since 7.57.0 */
 #define CURL_GLOBAL_WIN32 (1<<1)
 #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
 #define CURL_GLOBAL_NOTHING 0
@@ -2791,6 +2962,7 @@ typedef enum {
   CURL_LOCK_DATA_SSL_SESSION,
   CURL_LOCK_DATA_CONNECT,
   CURL_LOCK_DATA_PSL,
+  CURL_LOCK_DATA_HSTS,
   CURL_LOCK_DATA_LAST
 } curl_lock_data;
 
@@ -2833,8 +3005,9 @@ typedef enum {
 } CURLSHoption;
 
 CURL_EXTERN CURLSH *curl_share_init(void);
-CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
-CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *);
+CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *share, CURLSHoption option,
+                                         ...);
+CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *share);
 
 /****************************************************************************
  * Structures for querying information about the curl library at runtime.
@@ -2849,6 +3022,9 @@ typedef enum {
   CURLVERSION_SIXTH,
   CURLVERSION_SEVENTH,
   CURLVERSION_EIGHTH,
+  CURLVERSION_NINTH,
+  CURLVERSION_TENTH,
+  CURLVERSION_ELEVENTH,
   CURLVERSION_LAST /* never actually use this */
 } CURLversion;
 
@@ -2857,7 +3033,7 @@ typedef enum {
    meant to be a built-in version number for what kind of struct the caller
    expects. If the struct ever changes, we redefine the NOW to another enum
    from above. */
-#define CURLVERSION_NOW CURLVERSION_EIGHTH
+#define CURLVERSION_NOW CURLVERSION_ELEVENTH
 
 struct curl_version_info_data {
   CURLversion age;          /* age of the returned struct */
@@ -2908,6 +3084,15 @@ struct curl_version_info_data {
                                   (MAJOR << 24) | (MINOR << 12) | PATCH */
   const char *zstd_version; /* human readable string. */
 
+  /* These fields were added in CURLVERSION_NINTH */
+  const char *hyper_version; /* human readable string. */
+
+  /* These fields were added in CURLVERSION_TENTH */
+  const char *gsasl_version; /* human readable string. */
+
+  /* These fields were added in CURLVERSION_ELEVENTH */
+  /* feature_names is terminated by an entry with a NULL feature name */
+  const char * const *feature_names;
 };
 typedef struct curl_version_info_data curl_version_info_data;
 
@@ -2945,6 +3130,8 @@ typedef struct curl_version_info_data curl_version_info_data;
 #define CURL_VERSION_ZSTD         (1<<26) /* zstd features are present */
 #define CURL_VERSION_UNICODE      (1<<27) /* Unicode support on Windows */
 #define CURL_VERSION_HSTS         (1<<28) /* HSTS is supported */
+#define CURL_VERSION_GSASL        (1<<29) /* libgsasl is supported */
+#define CURL_VERSION_THREADSAFE   (1<<30) /* libcurl API is thread-safe */
 
  /*
  * NAME curl_version_info()
@@ -2999,7 +3186,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #define CURLPAUSE_CONT      (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
 
 #ifdef  __cplusplus
-}
+} /* end of extern "C" */
 #endif
 
 /* unfortunately, the easy.h and multi.h include files need options and info
@@ -3008,6 +3195,8 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #include "multi.h"
 #include "urlapi.h"
 #include "options.h"
+#include "header.h"
+#include "websockets.h"
 
 /* the typechecker doesn't work in C++ (yet) */
 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
@@ -3024,6 +3213,6 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
 #define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
 #endif /* __STDC__ >= 1 */
-#endif /* gcc >= 4.3 && !__cplusplus */
+#endif /* gcc >= 4.3 && !__cplusplus && !CURL_DISABLE_TYPECHECK */
 
 #endif /* CURLINC_CURL_H */
index 0acb5a8..fe3d7e1 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 
 /* This header file contains nothing but libcurl version info, generated by
    a script at release-time. This was made its own header file in 7.11.2 */
 
 /* This is the global package copyright */
-#define LIBCURL_COPYRIGHT "1996 - 2020 Daniel Stenberg, <daniel@haxx.se>."
+#define LIBCURL_COPYRIGHT "Daniel Stenberg, <daniel@haxx.se>."
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.74.0"
+#define LIBCURL_VERSION "8.1.2-DEV"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
-#define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 74
-#define LIBCURL_VERSION_PATCH 0
+#define LIBCURL_VERSION_MAJOR 8
+#define LIBCURL_VERSION_MINOR 1
+#define LIBCURL_VERSION_PATCH 2
 
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -57,7 +59,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x074a00
+#define LIBCURL_VERSION_NUM 0x080102
 
 /*
  * This is the date and time when the full source package was created. The
@@ -68,7 +70,7 @@
  *
  * "2007-11-23"
  */
-#define LIBCURL_TIMESTAMP "2020-12-09"
+#define LIBCURL_TIMESTAMP "[unreleased]"
 
 #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
 #define CURL_AT_LEAST_VERSION(x,y,z) \
index 2dbfb26..1285101 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -20,6 +20,8 @@
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 #ifdef  __cplusplus
 extern "C" {
@@ -46,13 +48,13 @@ CURL_EXTERN void curl_easy_cleanup(CURL *curl);
  *
  * DESCRIPTION
  *
- * Request internal information from the curl session with this function.  The
- * third argument MUST be a pointer to a long, a pointer to a char * or a
- * pointer to a double (as the documentation describes elsewhere).  The data
- * pointed to will be filled in accordingly and can be relied upon only if the
- * function returns CURLE_OK.  This function is intended to get used *AFTER* a
- * performed transfer, all results from this function are undefined until the
- * transfer is completed.
+ * Request internal information from the curl session with this function.
+ * The third argument MUST be pointing to the specific type of the used option
+ * which is documented in each man page of the option. The data pointed to
+ * will be filled in accordingly and can be relied upon only if the function
+ * returns CURLE_OK. This function is intended to get used *AFTER* a performed
+ * transfer, all results from this function are undefined until the transfer
+ * is completed.
  */
 CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
 
@@ -117,7 +119,7 @@ CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
 CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl);
 
 #ifdef  __cplusplus
-}
+} /* end of extern "C" */
 #endif
 
 #endif
diff --git a/Hengband/Hengband/curl/include/curl/header.h b/Hengband/Hengband/curl/include/curl/header.h
new file mode 100644 (file)
index 0000000..8df11e1
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef CURLINC_HEADER_H
+#define CURLINC_HEADER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct curl_header {
+  char *name;    /* this might not use the same case */
+  char *value;
+  size_t amount; /* number of headers using this name  */
+  size_t index;  /* ... of this instance, 0 or higher */
+  unsigned int origin; /* see bits below */
+  void *anchor; /* handle privately used by libcurl */
+};
+
+/* 'origin' bits */
+#define CURLH_HEADER    (1<<0) /* plain server header */
+#define CURLH_TRAILER   (1<<1) /* trailers */
+#define CURLH_CONNECT   (1<<2) /* CONNECT headers */
+#define CURLH_1XX       (1<<3) /* 1xx headers */
+#define CURLH_PSEUDO    (1<<4) /* pseudo headers */
+
+typedef enum {
+  CURLHE_OK,
+  CURLHE_BADINDEX,      /* header exists but not with this index */
+  CURLHE_MISSING,       /* no such header exists */
+  CURLHE_NOHEADERS,     /* no headers at all exist (yet) */
+  CURLHE_NOREQUEST,     /* no request with this number was used */
+  CURLHE_OUT_OF_MEMORY, /* out of memory while processing */
+  CURLHE_BAD_ARGUMENT,  /* a function argument was not okay */
+  CURLHE_NOT_BUILT_IN   /* if API was disabled in the build */
+} CURLHcode;
+
+CURL_EXTERN CURLHcode curl_easy_header(CURL *easy,
+                                       const char *name,
+                                       size_t index,
+                                       unsigned int origin,
+                                       int request,
+                                       struct curl_header **hout);
+
+CURL_EXTERN struct curl_header *curl_easy_nextheader(CURL *easy,
+                                                     unsigned int origin,
+                                                     int request,
+                                                     struct curl_header *prev);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* CURLINC_HEADER_H */
index 3549552..e652a65 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -20,6 +20,8 @@
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 
 #include <stdarg.h>
@@ -44,7 +46,7 @@ CURL_EXTERN char *curl_maprintf(const char *format, ...);
 CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
 
 #ifdef  __cplusplus
-}
+} /* end of extern "C" */
 #endif
 
 #endif /* CURLINC_MPRINTF_H */
index 37f9829..30a3d93 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -20,6 +20,8 @@
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 /*
   This is an "external" header file. Don't give away any internals here!
@@ -73,7 +75,9 @@ typedef enum {
   CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
                                callback */
   CURLM_WAKEUP_FAILURE,  /* wakeup is unavailable or failed */
-  CURLM_BAD_FUNCTION_ARGUMENT,  /* function called with a bad parameter */
+  CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */
+  CURLM_ABORTED_BY_CALLBACK,
+  CURLM_UNRECOVERABLE_POLL,
   CURLM_LAST
 } CURLMcode;
 
@@ -120,7 +124,7 @@ struct curl_waitfd {
 /*
  * Name:    curl_multi_init()
  *
- * Desc:    inititalize multi-style curl usage
+ * Desc:    initialize multi-style curl usage
  *
  * Returns: a new CURLM handle to use in all 'curl_multi' functions.
  */
@@ -314,16 +318,16 @@ typedef int (*curl_multi_timer_callback)(CURLM *multi,    /* multi handle */
                                          void *userp);    /* private callback
                                                              pointer */
 
-CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
-                                        int *running_handles);
+CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()")
+curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles);
 
 CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle,
                                                curl_socket_t s,
                                                int ev_bitmask,
                                                int *running_handles);
 
-CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
-                                            int *running_handles);
+CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()")
+curl_multi_socket_all(CURLM *multi_handle, int *running_handles);
 
 #ifndef CURL_ALLOW_OLD_MULTI_SOCKET
 /* This macro below was added in 7.16.3 to push users who recompile to use
index 14373b5..1ed76a9 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -20,6 +20,8 @@
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 
 #ifdef  __cplusplus
@@ -31,7 +33,7 @@ typedef enum {
   CURLOT_VALUES,  /*      (a defined set or bitmask) */
   CURLOT_OFF_T,   /* curl_off_t (a range of values) */
   CURLOT_OBJECT,  /* pointer (void *) */
-  CURLOT_STRING,  /*         (char * to zero terminated buffer) */
+  CURLOT_STRING,  /*         (char * to null-terminated buffer) */
   CURLOT_SLIST,   /*         (struct curl_slist *) */
   CURLOT_CBPTR,   /*         (void * passed as-is to a callback) */
   CURLOT_BLOB,    /* blob (struct curl_blob *) */
@@ -57,7 +59,7 @@ CURL_EXTERN const struct curl_easyoption *
 curl_easy_option_by_name(const char *name);
 
 CURL_EXTERN const struct curl_easyoption *
-curl_easy_option_by_id (CURLoption id);
+curl_easy_option_by_id(CURLoption id);
 
 CURL_EXTERN const struct curl_easyoption *
 curl_easy_option_next(const struct curl_easyoption *prev);
index 60596c7..7451aa3 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -20,6 +20,8 @@
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 
 #include <sys/types.h>
index faf8fcf..def7739 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -20,6 +20,8 @@
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 
 /*
 #  define CURL_SUFFIX_CURL_OFF_TU    UL
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
-#elif defined(__WATCOMC__)
-#  if defined(__386__)
-#    define CURL_TYPEOF_CURL_OFF_T     __int64
-#    define CURL_FORMAT_CURL_OFF_T     "I64d"
-#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
-#    define CURL_SUFFIX_CURL_OFF_T     i64
-#    define CURL_SUFFIX_CURL_OFF_TU    ui64
-#  else
-#    define CURL_TYPEOF_CURL_OFF_T     long
-#    define CURL_FORMAT_CURL_OFF_T     "ld"
-#    define CURL_FORMAT_CURL_OFF_TU    "lu"
-#    define CURL_SUFFIX_CURL_OFF_T     L
-#    define CURL_SUFFIX_CURL_OFF_TU    UL
-#  endif
-#  define CURL_TYPEOF_CURL_SOCKLEN_T int
-
 #elif defined(__POCC__)
 #  if (__POCC__ < 280)
 #    define CURL_TYPEOF_CURL_OFF_T     long
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 #elif defined(__LCC__)
-#  if defined(__e2k__) /* MCST eLbrus C Compiler */
+#  if defined(__MCST__) /* MCST eLbrus Compiler Collection */
 #    define CURL_TYPEOF_CURL_OFF_T     long
 #    define CURL_FORMAT_CURL_OFF_T     "ld"
 #    define CURL_FORMAT_CURL_OFF_TU    "lu"
 #  endif
 #  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
 
-#elif defined(__MWERKS__)
+#elif defined(macintosh)
+#  include <ConditionalMacros.h>
+#  if TYPE_LONGLONG
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+
+#elif defined(__TANDEM)
+# if ! defined(__LP64)
+   /* Required for 32-bit NonStop builds only. */
 #  define CURL_TYPEOF_CURL_OFF_T     long long
 #  define CURL_FORMAT_CURL_OFF_T     "lld"
 #  define CURL_FORMAT_CURL_OFF_TU    "llu"
 #  define CURL_SUFFIX_CURL_OFF_T     LL
 #  define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
+# endif
 
 #elif defined(_WIN32_WCE)
 #  define CURL_TYPEOF_CURL_OFF_T     __int64
 #  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
 
 #elif defined(__OS400__)
-#  if defined(__ILEC400__)
-#    define CURL_TYPEOF_CURL_OFF_T     long long
-#    define CURL_FORMAT_CURL_OFF_T     "lld"
-#    define CURL_FORMAT_CURL_OFF_TU    "llu"
-#    define CURL_SUFFIX_CURL_OFF_T     LL
-#    define CURL_SUFFIX_CURL_OFF_TU    ULL
-#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
-#    define CURL_PULL_SYS_TYPES_H      1
-#    define CURL_PULL_SYS_SOCKET_H     1
-#  endif
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
 
 #elif defined(__MVS__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
index 6d84150..bc8d7a7 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -20,6 +20,8 @@
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 
 /* wraps curl_easy_setopt() with typechecking */
  */
 #define curl_easy_setopt(handle, option, value)                         \
   __extension__({                                                       \
-      __typeof__(option) _curl_opt = option;                            \
+      CURLoption _curl_opt = (option);                                  \
       if(__builtin_constant_p(_curl_opt)) {                             \
-        if(curlcheck_long_option(_curl_opt))                            \
-          if(!curlcheck_long(value))                                    \
-            _curl_easy_setopt_err_long();                               \
-        if(curlcheck_off_t_option(_curl_opt))                           \
-          if(!curlcheck_off_t(value))                                   \
-            _curl_easy_setopt_err_curl_off_t();                         \
-        if(curlcheck_string_option(_curl_opt))                          \
-          if(!curlcheck_string(value))                                  \
-            _curl_easy_setopt_err_string();                             \
-        if(curlcheck_write_cb_option(_curl_opt))                        \
-          if(!curlcheck_write_cb(value))                                \
-            _curl_easy_setopt_err_write_callback();                     \
-        if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION)              \
-          if(!curlcheck_resolver_start_callback(value))                 \
-            _curl_easy_setopt_err_resolver_start_callback();            \
-        if((_curl_opt) == CURLOPT_READFUNCTION)                         \
-          if(!curlcheck_read_cb(value))                                 \
-            _curl_easy_setopt_err_read_cb();                            \
-        if((_curl_opt) == CURLOPT_IOCTLFUNCTION)                        \
-          if(!curlcheck_ioctl_cb(value))                                \
-            _curl_easy_setopt_err_ioctl_cb();                           \
-        if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION)                      \
-          if(!curlcheck_sockopt_cb(value))                              \
-            _curl_easy_setopt_err_sockopt_cb();                         \
-        if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION)                   \
-          if(!curlcheck_opensocket_cb(value))                           \
-            _curl_easy_setopt_err_opensocket_cb();                      \
-        if((_curl_opt) == CURLOPT_PROGRESSFUNCTION)                     \
-          if(!curlcheck_progress_cb(value))                             \
-            _curl_easy_setopt_err_progress_cb();                        \
-        if((_curl_opt) == CURLOPT_DEBUGFUNCTION)                        \
-          if(!curlcheck_debug_cb(value))                                \
-            _curl_easy_setopt_err_debug_cb();                           \
-        if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION)                     \
-          if(!curlcheck_ssl_ctx_cb(value))                              \
-            _curl_easy_setopt_err_ssl_ctx_cb();                         \
-        if(curlcheck_conv_cb_option(_curl_opt))                         \
-          if(!curlcheck_conv_cb(value))                                 \
-            _curl_easy_setopt_err_conv_cb();                            \
-        if((_curl_opt) == CURLOPT_SEEKFUNCTION)                         \
-          if(!curlcheck_seek_cb(value))                                 \
-            _curl_easy_setopt_err_seek_cb();                            \
-        if(curlcheck_cb_data_option(_curl_opt))                         \
-          if(!curlcheck_cb_data(value))                                 \
-            _curl_easy_setopt_err_cb_data();                            \
-        if((_curl_opt) == CURLOPT_ERRORBUFFER)                          \
-          if(!curlcheck_error_buffer(value))                            \
-            _curl_easy_setopt_err_error_buffer();                       \
-        if((_curl_opt) == CURLOPT_STDERR)                               \
-          if(!curlcheck_FILE(value))                                    \
-            _curl_easy_setopt_err_FILE();                               \
-        if(curlcheck_postfields_option(_curl_opt))                      \
-          if(!curlcheck_postfields(value))                              \
-            _curl_easy_setopt_err_postfields();                         \
-        if((_curl_opt) == CURLOPT_HTTPPOST)                             \
-          if(!curlcheck_arr((value), struct curl_httppost))             \
-            _curl_easy_setopt_err_curl_httpost();                       \
-        if((_curl_opt) == CURLOPT_MIMEPOST)                             \
-          if(!curlcheck_ptr((value), curl_mime))                        \
-            _curl_easy_setopt_err_curl_mimepost();                      \
-        if(curlcheck_slist_option(_curl_opt))                           \
-          if(!curlcheck_arr((value), struct curl_slist))                \
-            _curl_easy_setopt_err_curl_slist();                         \
-        if((_curl_opt) == CURLOPT_SHARE)                                \
-          if(!curlcheck_ptr((value), CURLSH))                           \
-            _curl_easy_setopt_err_CURLSH();                             \
+        CURL_IGNORE_DEPRECATION(                                        \
+          if(curlcheck_long_option(_curl_opt))                          \
+            if(!curlcheck_long(value))                                  \
+              _curl_easy_setopt_err_long();                             \
+          if(curlcheck_off_t_option(_curl_opt))                         \
+            if(!curlcheck_off_t(value))                                 \
+              _curl_easy_setopt_err_curl_off_t();                       \
+          if(curlcheck_string_option(_curl_opt))                        \
+            if(!curlcheck_string(value))                                \
+              _curl_easy_setopt_err_string();                           \
+          if(curlcheck_write_cb_option(_curl_opt))                      \
+            if(!curlcheck_write_cb(value))                              \
+              _curl_easy_setopt_err_write_callback();                   \
+          if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION)            \
+            if(!curlcheck_resolver_start_callback(value))               \
+              _curl_easy_setopt_err_resolver_start_callback();          \
+          if((_curl_opt) == CURLOPT_READFUNCTION)                       \
+            if(!curlcheck_read_cb(value))                               \
+              _curl_easy_setopt_err_read_cb();                          \
+          if((_curl_opt) == CURLOPT_IOCTLFUNCTION)                      \
+            if(!curlcheck_ioctl_cb(value))                              \
+              _curl_easy_setopt_err_ioctl_cb();                         \
+          if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION)                    \
+            if(!curlcheck_sockopt_cb(value))                            \
+              _curl_easy_setopt_err_sockopt_cb();                       \
+          if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION)                 \
+            if(!curlcheck_opensocket_cb(value))                         \
+              _curl_easy_setopt_err_opensocket_cb();                    \
+          if((_curl_opt) == CURLOPT_PROGRESSFUNCTION)                   \
+            if(!curlcheck_progress_cb(value))                           \
+              _curl_easy_setopt_err_progress_cb();                      \
+          if((_curl_opt) == CURLOPT_DEBUGFUNCTION)                      \
+            if(!curlcheck_debug_cb(value))                              \
+              _curl_easy_setopt_err_debug_cb();                         \
+          if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION)                   \
+            if(!curlcheck_ssl_ctx_cb(value))                            \
+              _curl_easy_setopt_err_ssl_ctx_cb();                       \
+          if(curlcheck_conv_cb_option(_curl_opt))                       \
+            if(!curlcheck_conv_cb(value))                               \
+              _curl_easy_setopt_err_conv_cb();                          \
+          if((_curl_opt) == CURLOPT_SEEKFUNCTION)                       \
+            if(!curlcheck_seek_cb(value))                               \
+              _curl_easy_setopt_err_seek_cb();                          \
+          if(curlcheck_cb_data_option(_curl_opt))                       \
+            if(!curlcheck_cb_data(value))                               \
+              _curl_easy_setopt_err_cb_data();                          \
+          if((_curl_opt) == CURLOPT_ERRORBUFFER)                        \
+            if(!curlcheck_error_buffer(value))                          \
+              _curl_easy_setopt_err_error_buffer();                     \
+          if((_curl_opt) == CURLOPT_STDERR)                             \
+            if(!curlcheck_FILE(value))                                  \
+              _curl_easy_setopt_err_FILE();                             \
+          if(curlcheck_postfields_option(_curl_opt))                    \
+            if(!curlcheck_postfields(value))                            \
+              _curl_easy_setopt_err_postfields();                       \
+          if((_curl_opt) == CURLOPT_HTTPPOST)                           \
+            if(!curlcheck_arr((value), struct curl_httppost))           \
+              _curl_easy_setopt_err_curl_httpost();                     \
+          if((_curl_opt) == CURLOPT_MIMEPOST)                           \
+            if(!curlcheck_ptr((value), curl_mime))                      \
+              _curl_easy_setopt_err_curl_mimepost();                    \
+          if(curlcheck_slist_option(_curl_opt))                         \
+            if(!curlcheck_arr((value), struct curl_slist))              \
+              _curl_easy_setopt_err_curl_slist();                       \
+          if((_curl_opt) == CURLOPT_SHARE)                              \
+            if(!curlcheck_ptr((value), CURLSH))                         \
+              _curl_easy_setopt_err_CURLSH();                           \
+        )                                                               \
       }                                                                 \
       curl_easy_setopt(handle, _curl_opt, value);                       \
     })
 
 /* wraps curl_easy_getinfo() with typechecking */
 #define curl_easy_getinfo(handle, info, arg)                            \
-  __extension__({                                                      \
-      __typeof__(info) _curl_info = info;                               \
+  __extension__({                                                       \
+      CURLINFO _curl_info = (info);                                     \
       if(__builtin_constant_p(_curl_info)) {                            \
-        if(curlcheck_string_info(_curl_info))                           \
-          if(!curlcheck_arr((arg), char *))                             \
-            _curl_easy_getinfo_err_string();                            \
-        if(curlcheck_long_info(_curl_info))                             \
-          if(!curlcheck_arr((arg), long))                               \
-            _curl_easy_getinfo_err_long();                              \
-        if(curlcheck_double_info(_curl_info))                           \
-          if(!curlcheck_arr((arg), double))                             \
-            _curl_easy_getinfo_err_double();                            \
-        if(curlcheck_slist_info(_curl_info))                            \
-          if(!curlcheck_arr((arg), struct curl_slist *))                \
-            _curl_easy_getinfo_err_curl_slist();                        \
-        if(curlcheck_tlssessioninfo_info(_curl_info))                   \
-          if(!curlcheck_arr((arg), struct curl_tlssessioninfo *))       \
-            _curl_easy_getinfo_err_curl_tlssesssioninfo();              \
-        if(curlcheck_certinfo_info(_curl_info))                         \
-          if(!curlcheck_arr((arg), struct curl_certinfo *))             \
-            _curl_easy_getinfo_err_curl_certinfo();                     \
-        if(curlcheck_socket_info(_curl_info))                           \
-          if(!curlcheck_arr((arg), curl_socket_t))                      \
-            _curl_easy_getinfo_err_curl_socket();                       \
-        if(curlcheck_off_t_info(_curl_info))                            \
-          if(!curlcheck_arr((arg), curl_off_t))                         \
-            _curl_easy_getinfo_err_curl_off_t();                        \
+        CURL_IGNORE_DEPRECATION(                                        \
+          if(curlcheck_string_info(_curl_info))                         \
+            if(!curlcheck_arr((arg), char *))                           \
+              _curl_easy_getinfo_err_string();                          \
+          if(curlcheck_long_info(_curl_info))                           \
+            if(!curlcheck_arr((arg), long))                             \
+              _curl_easy_getinfo_err_long();                            \
+          if(curlcheck_double_info(_curl_info))                         \
+            if(!curlcheck_arr((arg), double))                           \
+              _curl_easy_getinfo_err_double();                          \
+          if(curlcheck_slist_info(_curl_info))                          \
+            if(!curlcheck_arr((arg), struct curl_slist *))              \
+              _curl_easy_getinfo_err_curl_slist();                      \
+          if(curlcheck_tlssessioninfo_info(_curl_info))                 \
+            if(!curlcheck_arr((arg), struct curl_tlssessioninfo *))     \
+              _curl_easy_getinfo_err_curl_tlssesssioninfo();            \
+          if(curlcheck_certinfo_info(_curl_info))                       \
+            if(!curlcheck_arr((arg), struct curl_certinfo *))           \
+              _curl_easy_getinfo_err_curl_certinfo();                   \
+          if(curlcheck_socket_info(_curl_info))                         \
+            if(!curlcheck_arr((arg), curl_socket_t))                    \
+              _curl_easy_getinfo_err_curl_socket();                     \
+          if(curlcheck_off_t_info(_curl_info))                          \
+            if(!curlcheck_arr((arg), curl_off_t))                       \
+              _curl_easy_getinfo_err_curl_off_t();                      \
+        )                                                               \
       }                                                                 \
       curl_easy_getinfo(handle, _curl_info, arg);                       \
     })
@@ -270,9 +276,9 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_DNS_SERVERS ||                                         \
    (option) == CURLOPT_DOH_URL ||                                             \
    (option) == CURLOPT_EGDSOCKET ||                                           \
-   (option) == CURLOPT_FTPPORT ||                                             \
    (option) == CURLOPT_FTP_ACCOUNT ||                                         \
    (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
+   (option) == CURLOPT_FTPPORT ||                                             \
    (option) == CURLOPT_HSTS ||                                                \
    (option) == CURLOPT_INTERFACE ||                                           \
    (option) == CURLOPT_ISSUERCERT ||                                          \
@@ -286,10 +292,8 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_PASSWORD ||                                            \
    (option) == CURLOPT_PINNEDPUBLICKEY ||                                     \
    (option) == CURLOPT_PRE_PROXY ||                                           \
+   (option) == CURLOPT_PROTOCOLS_STR ||                                       \
    (option) == CURLOPT_PROXY ||                                               \
-   (option) == CURLOPT_PROXYPASSWORD ||                                       \
-   (option) == CURLOPT_PROXYUSERNAME ||                                       \
-   (option) == CURLOPT_PROXYUSERPWD ||                                        \
    (option) == CURLOPT_PROXY_CAINFO ||                                        \
    (option) == CURLOPT_PROXY_CAPATH ||                                        \
    (option) == CURLOPT_PROXY_CRLFILE ||                                       \
@@ -297,17 +301,21 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_PROXY_KEYPASSWD ||                                     \
    (option) == CURLOPT_PROXY_PINNEDPUBLICKEY ||                               \
    (option) == CURLOPT_PROXY_SERVICE_NAME ||                                  \
+   (option) == CURLOPT_PROXY_SSL_CIPHER_LIST ||                               \
    (option) == CURLOPT_PROXY_SSLCERT ||                                       \
    (option) == CURLOPT_PROXY_SSLCERTTYPE ||                                   \
    (option) == CURLOPT_PROXY_SSLKEY ||                                        \
    (option) == CURLOPT_PROXY_SSLKEYTYPE ||                                    \
-   (option) == CURLOPT_PROXY_SSL_CIPHER_LIST ||                               \
    (option) == CURLOPT_PROXY_TLS13_CIPHERS ||                                 \
    (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD ||                              \
    (option) == CURLOPT_PROXY_TLSAUTH_TYPE ||                                  \
    (option) == CURLOPT_PROXY_TLSAUTH_USERNAME ||                              \
+   (option) == CURLOPT_PROXYPASSWORD ||                                       \
+   (option) == CURLOPT_PROXYUSERNAME ||                                       \
+   (option) == CURLOPT_PROXYUSERPWD ||                                        \
    (option) == CURLOPT_RANDOM_FILE ||                                         \
    (option) == CURLOPT_RANGE ||                                               \
+   (option) == CURLOPT_REDIR_PROTOCOLS_STR ||                                 \
    (option) == CURLOPT_REFERER ||                                             \
    (option) == CURLOPT_REQUEST_TARGET ||                                      \
    (option) == CURLOPT_RTSP_SESSION_ID ||                                     \
@@ -317,6 +325,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_SERVICE_NAME ||                                        \
    (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
    (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 ||                          \
    (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
    (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
    (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
@@ -334,6 +343,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_URL ||                                                 \
    (option) == CURLOPT_USERAGENT ||                                           \
    (option) == CURLOPT_USERNAME ||                                            \
+   (option) == CURLOPT_AWS_SIGV4 ||                                           \
    (option) == CURLOPT_USERPWD ||                                             \
    (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
    (option) == CURLOPT_SSL_EC_CURVES ||                                       \
@@ -362,6 +372,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_INTERLEAVEDATA ||                                      \
    (option) == CURLOPT_IOCTLDATA ||                                           \
    (option) == CURLOPT_OPENSOCKETDATA ||                                      \
+   (option) == CURLOPT_PREREQDATA ||                                          \
    (option) == CURLOPT_PROGRESSDATA ||                                        \
    (option) == CURLOPT_READDATA ||                                            \
    (option) == CURLOPT_SEEKDATA ||                                            \
@@ -371,6 +382,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_WRITEDATA ||                                           \
    (option) == CURLOPT_RESOLVER_START_DATA ||                                 \
    (option) == CURLOPT_TRAILERDATA ||                                         \
+   (option) == CURLOPT_SSH_HOSTKEYDATA ||                                     \
    0)
 
 /* evaluates to true if option takes a POST data argument (void* or char*) */
@@ -428,7 +440,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
   (CURLINFO_OFF_T < (info))
 
 
-/* typecheck helpers -- check whether given expression has requested type*/
+/* typecheck helpers -- check whether given expression has requested type */
 
 /* For pointers, you can use the curlcheck_ptr/curlcheck_arr macros,
  * otherwise define a new macro. Search for __builtin_types_compatible_p
@@ -666,11 +678,11 @@ typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
 /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
  * this will of course break if we're included before OpenSSL headers...
  */
-typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *);
-typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *);
-typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *);
-typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX,
-                                           const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *,
+                                            const void *);
 #else
 typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
 typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;
index 7343cb6..b3504b6 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -20,6 +20,8 @@
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * SPDX-License-Identifier: curl
+ *
  ***************************************************************************/
 
 #include "curl.h"
@@ -47,7 +49,21 @@ typedef enum {
   CURLUE_NO_HOST,             /* 14 */
   CURLUE_NO_PORT,             /* 15 */
   CURLUE_NO_QUERY,            /* 16 */
-  CURLUE_NO_FRAGMENT          /* 17 */
+  CURLUE_NO_FRAGMENT,         /* 17 */
+  CURLUE_NO_ZONEID,           /* 18 */
+  CURLUE_BAD_FILE_URL,        /* 19 */
+  CURLUE_BAD_FRAGMENT,        /* 20 */
+  CURLUE_BAD_HOSTNAME,        /* 21 */
+  CURLUE_BAD_IPV6,            /* 22 */
+  CURLUE_BAD_LOGIN,           /* 23 */
+  CURLUE_BAD_PASSWORD,        /* 24 */
+  CURLUE_BAD_PATH,            /* 25 */
+  CURLUE_BAD_QUERY,           /* 26 */
+  CURLUE_BAD_SCHEME,          /* 27 */
+  CURLUE_BAD_SLASHES,         /* 28 */
+  CURLUE_BAD_USER,            /* 29 */
+  CURLUE_LACKS_IDN,           /* 30 */
+  CURLUE_LAST
 } CURLUcode;
 
 typedef enum {
@@ -79,6 +95,8 @@ typedef enum {
 #define CURLU_GUESS_SCHEME (1<<9)       /* legacy curl-style guessing */
 #define CURLU_NO_AUTHORITY (1<<10)      /* Allow empty authority when the
                                            scheme is unknown. */
+#define CURLU_ALLOW_SPACE (1<<11)       /* Allow spaces in the URL */
+#define CURLU_PUNYCODE (1<<12)          /* get the host name in pynycode */
 
 typedef struct Curl_URL CURLU;
 
@@ -99,14 +117,14 @@ CURL_EXTERN void curl_url_cleanup(CURLU *handle);
  * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new
  * handle must also be freed with curl_url_cleanup().
  */
-CURL_EXTERN CURLU *curl_url_dup(CURLU *in);
+CURL_EXTERN CURLU *curl_url_dup(const CURLU *in);
 
 /*
  * curl_url_get() extracts a specific part of the URL from a CURLU
  * handle. Returns error code. The returned pointer MUST be freed with
  * curl_free() afterwards.
  */
-CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
+CURL_EXTERN CURLUcode curl_url_get(const CURLU *handle, CURLUPart what,
                                    char **part, unsigned int flags);
 
 /*
@@ -117,6 +135,12 @@ CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
 CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
                                    const char *part, unsigned int flags);
 
+/*
+ * curl_url_strerror() turns a CURLUcode value into the equivalent human
+ * readable error string.  This is useful for printing meaningful error
+ * messages.
+ */
+CURL_EXTERN const char *curl_url_strerror(CURLUcode);
 
 #ifdef __cplusplus
 } /* end of extern "C" */
diff --git a/Hengband/Hengband/curl/include/curl/websockets.h b/Hengband/Hengband/curl/include/curl/websockets.h
new file mode 100644 (file)
index 0000000..fd6a916
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef CURLINC_WEBSOCKETS_H
+#define CURLINC_WEBSOCKETS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct curl_ws_frame {
+  int age;              /* zero */
+  int flags;            /* See the CURLWS_* defines */
+  curl_off_t offset;    /* the offset of this data into the frame */
+  curl_off_t bytesleft; /* number of pending bytes left of the payload */
+  size_t len;           /* size of the current data chunk */
+};
+
+/* flag bits */
+#define CURLWS_TEXT       (1<<0)
+#define CURLWS_BINARY     (1<<1)
+#define CURLWS_CONT       (1<<2)
+#define CURLWS_CLOSE      (1<<3)
+#define CURLWS_PING       (1<<4)
+#define CURLWS_OFFSET     (1<<5)
+
+/*
+ * NAME curl_ws_recv()
+ *
+ * DESCRIPTION
+ *
+ * Receives data from the websocket connection. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
+                                  size_t *recv,
+                                  struct curl_ws_frame **metap);
+
+/* sendflags for curl_ws_send() */
+#define CURLWS_PONG       (1<<6)
+
+/*
+ * NAME curl_easy_send()
+ *
+ * DESCRIPTION
+ *
+ * Sends data over the websocket connection. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
+                                  size_t buflen, size_t *sent,
+                                  curl_off_t framesize,
+                                  unsigned int sendflags);
+
+/* bits for the CURLOPT_WS_OPTIONS bitmask: */
+#define CURLWS_RAW_MODE (1<<0)
+
+CURL_EXTERN struct curl_ws_frame *curl_ws_meta(CURL *curl);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* CURLINC_WEBSOCKETS_H */
diff --git a/Hengband/Hengband/curl/lib/libcurl_a.lib b/Hengband/Hengband/curl/lib/libcurl_a.lib
new file mode 100755 (executable)
index 0000000..2feee2f
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:dc9bc9f66a7d6b4ce69c4ce0622c5036ee1fccba817d9ccd6f5354231a0d5f9e
+size 1822790
diff --git a/Hengband/Hengband/curl/lib/libcurl_a_debug.lib b/Hengband/Hengband/curl/lib/libcurl_a_debug.lib
new file mode 100755 (executable)
index 0000000..e199bbf
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8a5e2c366e9dad9a4712693b360a34e003de034723b3ec16010c894bf6a64fdf
+size 11150452
diff --git a/Hengband/Hengband/curl/x86 Debug/libcurl_a_debug.lib b/Hengband/Hengband/curl/x86 Debug/libcurl_a_debug.lib
deleted file mode 100644 (file)
index d08a7c4..0000000
Binary files a/Hengband/Hengband/curl/x86 Debug/libcurl_a_debug.lib and /dev/null differ
diff --git a/Hengband/Hengband/curl/x86 Release/libcurl_a.lib b/Hengband/Hengband/curl/x86 Release/libcurl_a.lib
deleted file mode 100644 (file)
index 4e1e246..0000000
Binary files a/Hengband/Hengband/curl/x86 Release/libcurl_a.lib and /dev/null differ
index 6659b9c..f8c2465 100644 (file)
@@ -1,8 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="Microsoft.CodeAnalysis.FxCopAnalyzers" version="3.0.0" targetFramework="native" developmentDependency="true" />
-  <package id="Microsoft.CodeAnalysis.VersionCheckAnalyzer" version="3.0.0" targetFramework="native" developmentDependency="true" />
-  <package id="Microsoft.CodeQuality.Analyzers" version="3.0.0" targetFramework="native" developmentDependency="true" />
-  <package id="Microsoft.NetCore.Analyzers" version="3.0.0" targetFramework="native" developmentDependency="true" />
-  <package id="Microsoft.NetFramework.Analyzers" version="3.0.0" targetFramework="native" developmentDependency="true" />
+  <package id="Microsoft.CodeAnalysis.NetAnalyzers" version="7.0.4" targetFramework="native" developmentDependency="true" />
 </packages>
\ No newline at end of file
index e869665..da64189 100644 (file)
@@ -7,6 +7,7 @@ visual_studio_files = \
        Hengband/Hengband/curl/include/curl/curl.h \
        Hengband/Hengband/curl/include/curl/curlver.h \
        Hengband/Hengband/curl/include/curl/easy.h \
+       Hengband/Hengband/curl/include/curl/header.h \
        Hengband/Hengband/curl/include/curl/mprintf.h \
        Hengband/Hengband/curl/include/curl/multi.h \
        Hengband/Hengband/curl/include/curl/options.h \
@@ -14,6 +15,9 @@ visual_studio_files = \
        Hengband/Hengband/curl/include/curl/system.h \
        Hengband/Hengband/curl/include/curl/typecheck-gcc.h \
        Hengband/Hengband/curl/include/curl/urlapi.h \
+       Hengband/Hengband/curl/include/curl/websockets.h \
+       Hengband/Hengband/curl/lib/libcurl_a.lib \
+       Hengband/Hengband/curl/lib/libcurl_a_debug.lib \
        Hengband/Hengband/Hengband.vcxproj \
        Hengband/Hengband/Hengband.vcxproj.filters \
        Hengband/Hengband/packages.config
@@ -25,12 +29,8 @@ EXTRA_DIST = \
        readme.md \
        readme_angband \
        readme-eng.md \
+       THIRD-PARTY-NOTICES.txt \
        hengband.spec \
        $(visual_studio_files)
 
 SUBDIRS = src lib
-
-# Handle some paths in Hengband/Hengband that have spaces in them and would
-# be mishandled by make/automake.
-dist-hook:
-       (cd $(srcdir)/Hengband/Hengband/curl && tar -cf - "x86 Debug" "x86 Release" ) | (cd $(distdir)/Hengband/Hengband/curl && tar -xf -)
diff --git a/THIRD-PARTY-NOTICES.txt b/THIRD-PARTY-NOTICES.txt
new file mode 100644 (file)
index 0000000..ebbcdc2
--- /dev/null
@@ -0,0 +1,63 @@
+THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
+Do Not Translate or Localize
+
+hengband incorporates third party material from the projects listed below.
+
+
+
+---------------------------------------------------------
+
+curl 8.1.2 - The curl license
+https://curl.se/
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (C) Daniel Stenberg, <daniel@haxx.se>, and many
+contributors, see the THANKS file.
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright
+notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization of the copyright holder.
+
+---------------------------------------------------------
+
+JSON for Modern C++ 3.11.2 - MIT
+https://github.com/nlohmann/json
+
+MIT License
+
+Copyright (c) 2013-2022 Niels Lohmann
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+---------------------------------------------------------
index f9cb7d6..56fdac2 100644 (file)
@@ -1,5 +1,5 @@
-,dnl Process this file with autoconf to produce a configure script.
-AC_INIT(hengband, 3.0.0.0)
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(hengband, 3.0.1.6-Beta)
 
 AC_CONFIG_MACRO_DIRS([m4])
 AC_CONFIG_HEADERS(src/autoconf.h)
@@ -59,10 +59,14 @@ AC_ARG_ENABLE(fontset,
 [  --disable-fontset       disable fontset support], use_fontset=no, use_fontset=yes)
 AC_ARG_ENABLE([xft],
        AS_HELP_STRING([--enable-xft], [Enable xft support]))
+AC_ARG_ENABLE(net,
+[  --disable-net           disable networking support], use_net=no)
 AC_ARG_ENABLE(worldscore,
 [  --disable-worldscore    disable worldscore support], worldscore=no)
-AC_ARG_ENABLE(chuukei,
-[  --enable-chuukei        enable internet chuukei support], AC_DEFINE(CHUUKEI, 1, [Chuukei mode]))
+AC_ARG_ENABLE([pch],
+[  --disable-pch           disable use of precompiled headers],
+enable_pch=no, enable_pch=yes)
+AM_CONDITIONAL([PCH], [test x$enable_pch = xyes])
 AC_ARG_ENABLE([cocoa],
 [  --enable-cocoa          enable a Cocoa user interface (OS X only)],
 [AC_DEFINE([MACH_O_COCOA], [1], [Use a Cocoa interface (OS X only)])], [])
@@ -80,10 +84,6 @@ if test x"$enable_cocoa" = xyes ; then
   AC_DEFINE(SAFE_DIRECTORY, 1, [Mark var directory with version string])
   AC_DEFINE(VERSION_STRING, "3.0.0", [Version string to use for var directory])
 fi
-AC_ARG_ENABLE([pch],
-[  --disable-pch           disable use of precompiled headers],
-enable_pch=no, enable_pch=yes)
-AM_CONDITIONAL([PCH], [test x$enable_pch = xyes])
 
 dnl Checks for libraries.
 dnl Replace `main' with a function in -lncurses:
@@ -102,13 +102,18 @@ fi
 
 AC_CHECK_LIB(iconv, iconv_open)
 
+if test "$use_net" = no; then
+  AC_DEFINE(DISABLE_NET, 1, [Disable networking support])
+  worldscore=no;
+else
+  PKG_CHECK_MODULES(libcurl, [libcurl], , [AC_CHECK_LIB([curl], [curl_global_init], [libcurl_LIBS=-lcurl], [AC_MSG_ERROR([Could not find libcurl for networking support])])])
+fi
+
 dnl The world score server is currently only available in Japanese.
 if test "$use_japanese" = no; then
   worldscore=no
 fi
 if test "$worldscore" != no; then
-  PKG_CHECK_MODULES([libcurl], [libcurl], [true], [
-    AC_SEARCH_LIBS([curl_global_init], [curl curl-gnutls curl-nss], [true], [AC_MSG_ERROR([libcurl is necessary for posting scores])])])
   AC_DEFINE(WORLD_SCORE, 1, [Allow the game to send scores to the score server])
 fi
 
@@ -179,7 +184,13 @@ AC_PROG_GCC_TRADITIONAL
 AC_FUNC_MEMCMP
 AC_FUNC_STRFTIME
 AC_FUNC_VPRINTF
-AC_CHECK_FUNCS(gethostname mkdir select socket strtol vsnprintf mkstemp usleep)
-
-AC_CONFIG_FILES(Makefile src/Makefile lib/Makefile lib/apex/Makefile lib/bone/Makefile lib/data/Makefile lib/edit/Makefile lib/edit/quests/Makefile lib/edit/towns/Makefile lib/file/Makefile lib/help/Makefile lib/info/Makefile lib/pref/Makefile lib/save/Makefile lib/script/Makefile lib/user/Makefile lib/xtra/Makefile lib/xtra/graf/Makefile lib/xtra/music/Makefile lib/xtra/sound/Makefile)
+AC_CHECK_FUNCS(gethostname mkdir select socket strtol mkstemp usleep)
+
+AC_CONFIG_FILES(Makefile src/Makefile lib/Makefile lib/apex/Makefile \
+       lib/bone/Makefile lib/data/Makefile \
+       lib/edit/Makefile lib/edit/quests/Makefile lib/edit/towns/Makefile \
+       lib/file/Makefile lib/file/books/Makefile lib/help/Makefile \
+       lib/info/Makefile lib/pref/Makefile lib/save/Makefile \
+       lib/script/Makefile lib/user/Makefile lib/xtra/Makefile \
+       lib/xtra/graf/Makefile lib/xtra/music/Makefile lib/xtra/sound/Makefile)
 AC_OUTPUT()
index 0d2d490..374b63f 100644 (file)
@@ -38,7 +38,7 @@ PROJECT_NAME           = Hengband
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 3.0.0Alpha81
+PROJECT_NUMBER         = 3.0.1.6-Beta
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
index 6126fbf..afbc7fc 100644 (file)
@@ -1,6 +1,5 @@
-%define version 3.0.0Alpha78
+%define version 3.0.1.5
 %define release 1
-%global debug_package %{nil}
 
 Summary: hengband %{version}
 Name: hengband
@@ -10,8 +9,8 @@ License: unknown
 Group: Amusements/Games
 Url: https://hengband.github.io
 Source: hengband-%{version}.tar.gz
-Requires: ncurses-libs libstdc++ libcurl
-BuildRequires: autoconf automake gcc-c++ ncurses-devel libcurl-devel nkf
+Requires: ncurses-libs libstdc++ libcurl libX11
+BuildRequires: autoconf automake gcc-c++ ncurses-devel libcurl-devel nkf libX11-devel
 
 %description
 Hengband is a variant of ZAngband.
@@ -32,7 +31,7 @@ https://hengband.github.io
 詳しくは /usr/share/doc/hengband/readme.md を参照。
 
 %prep
-rm -rf $RPM_BUILD_ROOT
+rm -rf %{buildroot}
 
 %setup -n %{name}-%{version}
 ./bootstrap
@@ -42,18 +41,18 @@ rm -rf $RPM_BUILD_ROOT
 %make_build
 
 %install
-mkdir -p $RPM_BUILD_ROOT/%{_bindir}
-mkdir -p $RPM_BUILD_ROOT/%{_datadir}/games/hengband
-%makeinstall
-cp -R lib/ -p $RPM_BUILD_ROOT/%{_datadir}/games/hengband/
-find $RPM_BUILD_ROOT/%{_datadir}/games/hengband/ -type f -name "Makefile*" -exec rm {} \;
-find $RPM_BUILD_ROOT/%{_datadir}/games/hengband/ -type f -name "delete.me*" -exec rm {} \;
-find $RPM_BUILD_ROOT/%{_datadir}/games/hengband/ -name ".git*" -exec rm -rf {} \;
-rm -rf $RPM_BUILD_ROOT/%{_datadir}/games/hengband/lib/xtra/{sound,music}
-touch $RPM_BUILD_ROOT/%{_datadir}/games/hengband/lib/apex/scores.raw
+mkdir -p %{buildroot}/%{_bindir}
+mkdir -p %{buildroot}/%{_datadir}/games/hengband
+%make_install bindir=%{_bindir}
+cp -R lib/ -p %{buildroot}/%{_datadir}/games/hengband/
+find %{buildroot}/%{_datadir}/games/hengband/ -type f -name "Makefile*" -exec rm {} \;
+find %{buildroot}/%{_datadir}/games/hengband/ -type f -name "delete.me*" -exec rm {} \;
+find %{buildroot}/%{_datadir}/games/hengband/ -name ".git*" -exec rm -rf {} \;
+rm -rf %{buildroot}/%{_datadir}/games/hengband/lib/xtra/{sound,music}
+touch %{buildroot}/%{_datadir}/games/hengband/lib/apex/scores.raw
 
 %clean
-rm -rf $RPM_BUILD_ROOT
+rm -rf %{buildroot}
 
 %preun
 if [ -e %{_datadir}/games/hengband/lib/data/f_info_j.raw ]
@@ -71,6 +70,7 @@ exit 0
 %attr(775,root,games) %dir %{_datadir}/games/hengband/lib/data
 %dir %{_datadir}/games/hengband/lib/edit
 %dir %{_datadir}/games/hengband/lib/file
+%dir %{_datadir}/games/hengband/lib/file/books
 %dir %{_datadir}/games/hengband/lib/help
 %dir %{_datadir}/games/hengband/lib/info
 %dir %{_datadir}/games/hengband/lib/pref
@@ -86,6 +86,7 @@ exit 0
 %{_datadir}/games/hengband/lib/edit/quests/*.txt
 %{_datadir}/games/hengband/lib/edit/towns/*.txt
 %{_datadir}/games/hengband/lib/file/*.txt
+%{_datadir}/games/hengband/lib/file/books/*.txt
 %{_datadir}/games/hengband/lib/help/*.hlp
 %{_datadir}/games/hengband/lib/help/*.txt
 %{_datadir}/games/hengband/lib/pref/*.prf
@@ -94,6 +95,63 @@ exit 0
 %license lib/help/jlicense.txt
 
 %changelog
+* Tue Jan 09 2024 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.1.5(Beta)
+
+* Wed Dec 27 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.1.4(Beta)
+
+* Mon Dec 11 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.1.3(Beta)
+
+* Mon Nov 27 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.1.2(Beta)
+
+* Fri Nov 17 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.1.1(Beta)
+
+* Mon Oct 30 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.1.0(Beta)
+
+* Sun Oct 22 2023 Shiro Hara <white@vx-xv.com>
+- Fix the graphic mode is not available on X11
+
+* Wed Oct 18 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0.91(Alpha)
+
+* Mon Oct 16 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0.90(Alpha)
+
+* Tue Aug 8 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0.89(Alpha)
+
+* Mon Jul 24 2023 Shiro Hara <white@vx-xv.com>
+- Enable X11
+
+* Sun Jul 23 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0.88(Alpha)
+
+* Sun Jul 09 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0.87(Alpha)
+
+* Mon Jun 26 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0.86(Alpha)
+
+* Wed Jun 14 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0.85(Alpha)
+
+* Mon May 29 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0Alpha release 84
+
+* Wed May 17 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0Alpha release 83
+- Replace RPM_BUILD_ROOT to builddir macro
+
+* Sat May 06 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0Alpha release 82
+
+* Thu May 04 2023 Shiro Hara <white@vx-xv.com>
+- hengband RPM 3.0.0Alpha release 81
 
 * Mon Feb 20 2023 Shiro Hara <white@vx-xv.com>
 - hengband RPM 3.0.0Alpha release 78
@@ -129,4 +187,3 @@ exit 0
 
 * Sun Jun 16 2002 Takahiro MIZUNO <tow@plum.freemail.ne.jp> 
 - hengband RPM 1.0.0 release 1
-
index fa37515..422daef 100644 (file)
@@ -4422,7 +4422,7 @@ I:23:4:1
 W:4:10:12:12000
 P:0:2d4:4:6:0
 F:STR | HIDE_TYPE
-F:BRAND_ACID | RES_ACID | ACTIVATE | SHOW_MODS | LITE | THROW | XTRA_H_RES
+F:BRAND_ACID | RES_ACID | ACTIVATE | SHOW_MODS | THROW | XTRA_H_RES
 U:ACID_BALL_AND_RESISTANCE
 D:$An acidic dagger finely balanced for deadly throws.
 D:「黒の牙」を意味する名を持つこの暗澹とした短剣は、
@@ -4499,7 +4499,7 @@ E:'Alalarang'
 I:23:20:-2
 W:30:1:50:3500
 P:0:8d4:-10:-10:-15
-F:DEX | HIDE_TYPE | BLOWS | HEAVY_SPELL | AGGRAVATE | IM_COLD
+F:DEX | HIDE_TYPE | BLOWS | HARD_SPELL | AGGRAVATE | IM_COLD
 F:SHOW_MODS | SPEED | CURSED | HEAVY_CURSE | TY_CURSE
 F:RANDOM_CURSE0 | RANDOM_CURSE2 | WARNING
 D:$Ala, ala, ala.
index 9618752..82786aa 100644 (file)
@@ -6452,3 +6452,62 @@ F:INT | WIS | SUST_INT | SUST_WIS
 F:RES_CHAOS | RES_CONF | RES_NEXUS | HOLD_EXP
 D:$It protects you from the power of chaos.
 D:それは混沌の力からあなたを守る。
+
+N:675:モルデンカイネン著『洞察の魔法大全』第1巻
+E:Mordekainen's Magical Compendium of Deep Thought Vol 1.
+G:?:o
+I:69:1:0
+W:0:5:1
+A:0/255
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:676:モルデンカイネン著『洞察の魔法大全』第2巻
+E:Mordekainen's Magical Compendium of Deep Thought Vol 2.
+G:?:o
+I:69:2:0
+W:0:5:1
+A:0/255
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:677:モルデンカイネン著『洞察の魔法大全』第3巻
+E:Mordekainen's Magical Compendium of Deep Thought Vol 3.
+G:?:o
+I:69:3:0
+W:0:5:1
+A:0/255
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:678:アーティファクトの伝承 第1巻 武器編
+E:Artifact Lore, Vol. I "Ancient Weapons"
+G:?:o
+I:69:4:0
+W:0:5:1
+A:0/255
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:679:アーティファクトの伝承 第2巻 防具編
+E:Artifact Lore, Vol. II, "Ancient Armor"
+G:?:o
+I:69:5:0
+W:0:5:1
+A:0/255
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:680:アーティファクトの伝承 第3巻 アクセサリ編
+E:Artifact Lore, Vol. III, "Ancient Magical Tools"
+G:?:o
+I:69:6:0
+W:0:5:1
+A:0/255
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+
+N:681:宝の地図
+E:Treasure map
+G:?:o
+I:69:7:0
+W:0:5:1
+A:0/255
+F:IGNORE_ACID | IGNORE_ELEC | IGNORE_FIRE | IGNORE_COLD
+D:$It's a cheap piece of paper.
+D:$  You should wonder if the hidden location of Gungnir is written.
+D:安っぽい紙切れだ。グングニルの隠し場所でも書いてあるのだろうか。
index 12907e4..3e9ad29 100644 (file)
@@ -1532,7 +1532,7 @@ E:and Stupidity
 X:27:0
 W:30:0:0:0
 C:0:0:0:3
-F:INT | CURSED | HEAVY_CURSE | HEAVY_SPELL
+F:INT | CURSED | HEAVY_CURSE | HARD_SPELL
 
 N:216:反感の
 E:and Aggravate
index 2ff3876..9fd07aa 100644 (file)
 # N: serial number : monster name
 # G: symbol : color
 # I: speed : hit points : vision : armor class : alertness
-# W: depth : rarity : 0 : exp : next_exp : next_mon
+# W: depth : rarity : exp : next_exp : next_mon
 # B: attack method : attack effect : damage
 # S: spell frequency |
 # S: spell type | spell type | etc
 # from 0 (ever vigilant for intruders) to 255 (prefers to ignore
 # intruders).
 
-# 'W' is for more information - level, rarity, and experience for
-# killing. The third slot is unused.
+# 'W' is for more information - level, rarity, experience for
+# killing, required experience to evolve, and evolution target.
 
 # 'B' is for blows - method of attack, effect of attack, and damage
 # from attack. There may be up to four of these lines; effect and
@@ -209,7 +209,8 @@ I:110:1d4:4:1:40
 W:0:2:0:10:14
 B:BEG:FLAVOR
 B:TOUCH:EAT_GOLD
-F:MALE | EVIL | WILD_TOWN | WILD_ONLY
+X:MALE
+F:EVIL | WILD_TOWN | WILD_ONLY
 F:RAND_25 | FRIENDS | HUMAN |
 F:TAKE_ITEM | OPEN_DOOR | DROP_CORPSE | DROP_SKELETON
 D:$He looks squalid and thoroughly revolting.
@@ -277,7 +278,8 @@ I:110:3d3:10:1:255
 W:0:1:0:100:83
 B:HIT:HURT:1d6
 B:HIT:HURT:1d6
-F:MALE | WILD_ONLY | WILD_WOOD | HUMAN |
+X:MALE
+F:WILD_ONLY | WILD_WOOD | HUMAN |
 F:RAND_25 | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_GOLD | DROP_60 |
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR
@@ -306,7 +308,8 @@ W:0:3:0:0:0
 B:MOAN:FLAVOR
 B:MOAN:FLAVOR
 B:HIT:HURT:1d5
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE | FRIENDLY
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE | FRIENDLY
 F:FORCE_MAXHP | WILD_TOWN | WILD_ONLY | ONLY_ITEM | DROP_90 | DROP_GREAT
 F:OPEN_DOOR | BASH_DOOR | HAS_LITE_1 | NO_CONF | NO_SLEEP
 D:$Before you appears a broad thick-set hobbit with a round red face. 
@@ -329,7 +332,8 @@ G:t:W
 I:110:1d2:6:1:0
 W:0:1:0:0:0
 B:DROOL:FLAVOR
-F:MALE | DROP_CORPSE | DROP_SKELETON | WILD_TOWN | WILD_ONLY
+X:MALE
+F:DROP_CORPSE | DROP_SKELETON | WILD_TOWN | WILD_ONLY
 F:RAND_25 | HUMAN |
 F:TAKE_ITEM
 D:$He tends to blubber a lot.
@@ -343,7 +347,8 @@ G:t:g
 I:110:1d2:6:1:0
 W:0:1:0:0:0
 B:DROOL:FLAVOR
-F:MALE | DROP_SKELETON | DROP_CORPSE | WILD_TOWN | WILD_ONLY
+X:MALE
+F:DROP_SKELETON | DROP_CORPSE | WILD_TOWN | WILD_ONLY
 F:RAND_25 | HUMAN |
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR
 D:$Ugly doesn't begin to describe him.
@@ -356,7 +361,8 @@ G:t:G
 I:120:4d4:6:1:0
 W:0:1:0:0:0
 B:DROOL:FLAVOR
-F:MALE | DROP_CORPSE | DROP_SKELETON | WILD_TOWN | WILD_ONLY
+X:MALE
+F:DROP_CORPSE | DROP_SKELETON | WILD_TOWN | WILD_ONLY
 F:RAND_25 | HUMAN |
 F:TAKE_ITEM
 D:$Drooling and comical, but then, what do you expect?
@@ -369,7 +375,8 @@ G:t:U
 I:110:1d4:10:1:40
 W:0:1:0:10:14
 B:BEG:FLAVOR
-F:MALE | DROP_SKELETON | DROP_CORPSE | HUMAN |
+X:MALE
+F:DROP_SKELETON | DROP_CORPSE | HUMAN |
 F:RAND_25 | WILD_TOWN | WILD_ONLY
 F:TAKE_ITEM | OPEN_DOOR
 D:$You just can't help feeling sorry for him.
@@ -390,7 +397,8 @@ I:110:1d1:10:1:50
 W:0:1:0:0:0
 B:BEG:FLAVOR
 B:TOUCH:DISEASE
-F:MALE | DROP_CORPSE | DROP_SKELETON | HUMAN |
+X:MALE
+F:DROP_CORPSE | DROP_SKELETON | HUMAN |
 F:RAND_25 | WILD_TOWN | WILD_ONLY
 F:TAKE_ITEM | OPEN_DOOR
 D:$You feel it isn't safe to touch him.
@@ -404,7 +412,8 @@ I:110:2d8:10:8:99
 W:0:1:0:10:44
 B:HIT:HURT:1d6
 B:TOUCH:EAT_ITEM
-F:MALE | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:DROP_CORPSE | DROP_SKELETON
 F:DROP_60 | WILD_TOWN | HUMAN |
 F:WILD_SWAMP | WILD_WOOD | WILD_GRASS | WILD_MOUNTAIN | WILD_ONLY
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
@@ -419,7 +428,8 @@ G:t:y
 I:110:2d3:10:1:0
 W:0:1:0:0:0
 B:BEG:FLAVOR
-F:MALE | HAS_LITE_1
+X:MALE
+F:HAS_LITE_1
 F:RAND_50 | DROP_SKELETON | DROP_CORPSE | HUMAN |
 F:ONLY_GOLD | DROP_60 | WILD_TOWN | WILD_ONLY
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR
@@ -433,7 +443,8 @@ G:t:o
 I:110:3d3:10:1:255
 W:0:1:0:0:0
 B:HIT:HURT:1d5
-F:MALE | HAS_LITE_1 |
+X:MALE
+F:HAS_LITE_1 |
 F:RAND_50 | HUMAN |
 F:ONLY_GOLD | DROP_60 | DROP_SKELETON | DROP_CORPSE
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_TOWN | WILD_ONLY
@@ -449,7 +460,8 @@ G:t:R
 I:110:5d8:10:20:250
 W:0:1:0:8:43
 B:HIT:HURT:1d10
-F:MALE | DROP_SKELETON | DROP_CORPSE | HAS_LITE_1 | HUMAN |
+X:MALE
+F:DROP_SKELETON | DROP_CORPSE | HAS_LITE_1 | HUMAN |
 F:RAND_50 | DROP_90 | WILD_GRASS | WILD_TOWN | WILD_WOOD | WILD_ONLY
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | 
 F:EVIL
@@ -466,7 +478,8 @@ G:t:r
 I:110:7d8:10:30:250
 W:0:1:0:8:43
 B:HIT:HURT:2d6
-F:MALE | DROP_SKELETON | DROP_CORPSE | HAS_LITE_1 | HUMAN |
+X:MALE
+F:DROP_SKELETON | DROP_CORPSE | HAS_LITE_1 | HUMAN |
 F:RAND_50 | DROP_90 | WILD_TOWN | WILD_ONLY
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR
 D:$He doesn't take to strangers kindly.
@@ -478,7 +491,8 @@ G:f:s
 I:111:20d20:50:15:4
 W:0:255:0:0:0
 B:HIT:HURT:1d3
-F:UNIQUE | MALE | ANIMAL | SPEAK_ALL
+X:MALE
+F:UNIQUE | ANIMAL | SPEAK_ALL
 F:FORCE_MAXHP | DROP_CORPSE | WILD_TOWN | WILD_ONLY
 F:DROP_90 | DROP_GOOD | HUMAN |
 F:OPEN_DOOR | BASH_DOOR | HAS_LITE_1 |
@@ -820,7 +834,8 @@ W:2:1:8:70:216
 B:SLASH:HURT:1d8
 B:SLASH:HURT:1d8
 B:SLASH:HURT:1d7
-F:MALE | HAS_LITE_1 |
+X:MALE
+F:HAS_LITE_1 |
 F:DROP_60 | WILD_ALL | DROP_SKELETON | DROP_CORPSE | HUMAN |
 F:OPEN_DOOR | BASH_DOOR
 D:$He looks inexperienced but tough.
@@ -835,7 +850,8 @@ W:2:1:8:50:150
 B:HIT:HURT:1d5
 B:HIT:HURT:1d5
 B:TOUCH:EAT_GOLD
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:DROP_60 | DROP_SKELETON | DROP_CORPSE
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | WILD_ALL |
 F:EVIL
@@ -849,7 +865,8 @@ G:p:B
 I:110:7d4:20:10:10
 W:2:1:9:100:225
 B:HIT:HURT:1d9
-F:MALE | HAS_LITE_1 | HUMAN |
+X:MALE
+F:HAS_LITE_1 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | GOOD | WILD_ALL | DROP_SKELETON | DROP_CORPSE
 F:DROP_60
 F:OPEN_DOOR | BASH_DOOR
@@ -865,7 +882,8 @@ G:p:R
 I:110:6d4:20:6:5
 W:2:1:9:100:240
 B:HIT:HURT:1d8
-F:MALE | HAS_LITE_1 | HUMAN |
+X:MALE
+F:HAS_LITE_1 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | WILD_ALL | DROP_SKELETON | DROP_CORPSE
 F:DROP_60
 F:OPEN_DOOR | BASH_DOOR
@@ -937,7 +955,8 @@ W:2:1:7:30:157
 B:CLAW:HURT:1d2
 B:CLAW:HURT:1d2
 B:BITE:HURT:1d3
-F:FEMALE | CAN_FLY | WILD_MOUNTAIN 
+X:FEMALE
+F:CAN_FLY | WILD_MOUNTAIN 
 F:RAND_50 | DROP_CORPSE
 F:ANIMAL | EVIL
 D:$A flying, screeching bird with a woman's face.
@@ -1113,7 +1132,8 @@ G:h:u
 I:130:20d20:20:12:5
 W:3:2:18:0:0
 B:TOUCH:EAT_GOLD
-F:UNIQUE | MALE | EVIL | CAN_SWIM | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | EVIL | CAN_SWIM | DROP_SKELETON | DROP_CORPSE
 F:FORCE_MAXHP | SPEAK_ALL | SMART | 
 F:RAND_50 | RAND_25 | WILD_ALL
 F:ONLY_ITEM | DROP_90 | DROP_GREAT
@@ -1244,7 +1264,7 @@ G:n:D
 I:110:6d8:16:40:120
 W:3:1:22:40:94
 B:CRUSH:HURT:2d6
-F:FEMALE | 
+X:FEMALE
 F:RAND_25 | DROP_60 | DROP_CORPSE
 F:BASH_DOOR | CAN_SWIM
 F:EVIL
@@ -1291,7 +1311,8 @@ I:110:3d5:16:8:10
 W:3:1:5:5000:539
 B:HIT:HURT:1d7
 B:TOUCH:EAT_GOLD
-F:MALE | HAS_LITE_1 |
+X:MALE
+F:HAS_LITE_1 |
 F:DROP_60 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL
@@ -1413,7 +1434,8 @@ W:4:1:18:500:1039
 B:SHOOT:HURT:2d7
 B:HIT:HURT:1d7
 B:HIT:HURT:1d7
-F:MALE | HAS_LITE_1 | HUMAN |
+X:MALE
+F:HAS_LITE_1 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | DROP_SKELETON | DROP_CORPSE
 F:DROP_60
 F:OPEN_DOOR | BASH_DOOR | WILD_WOOD |
@@ -1472,7 +1494,7 @@ G:o:G
 I:110:5d5:20:32:30
 W:4:1:15:30:118
 B:HIT:HURT:1d9
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | RAND_50 | DROP_SKELETON | DROP_CORPSE |
 F:OPEN_DOOR | BASH_DOOR | WILD_WOOD | RES_DARK |
 F:EVIL | ORC | HURT_LITE
@@ -1559,7 +1581,8 @@ G:p:R
 I:110:6d4:20:6:10
 W:5:2:7:100:240
 B:HIT:HURT:1d8
-F:MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | 
 F:FRIENDS | DROP_60 | WILD_ALL | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR |
@@ -1576,7 +1599,7 @@ I:110:9d8:18:40:120
 W:5:1:30:40:130
 B:CRUSH:HURT:2d6
 B:SPIT:ACID:2d8
-F:FEMALE | 
+X:FEMALE
 F:RAND_25 | TAKE_ITEM | DROP_60 | DROP_CORPSE
 F:BASH_DOOR | CAN_SWIM | WILD_SHORE |
 F:EVIL | IM_ACID
@@ -1618,7 +1641,8 @@ I:110:6d8:20:16:5
 W:4:1:20:500:1038
 B:HIT:HURT:2d4
 B:HIT:HURT:2d4
-F:MALE | GOOD | HAS_LITE_1 | HUMAN |
+X:MALE
+F:GOOD | HAS_LITE_1 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | 
 F:DROP_60 | WILD_ALL | DROP_SKELETON | DROP_CORPSE |
 F:OPEN_DOOR | BASH_DOOR
@@ -1791,7 +1815,8 @@ G:p:B
 I:110:7d4:20:10:5
 W:6:2:7:100:225
 B:HIT:HURT:1d9
-F:MALE | GOOD | HAS_LITE_2 | HUMAN |
+X:MALE
+F:GOOD | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | WILD_ALL | DROP_SKELETON | DROP_CORPSE |
 F:FRIENDS | DROP_60 |
 F:OPEN_DOOR | BASH_DOOR
@@ -1809,7 +1834,8 @@ W:6:2:6:70:216
 B:SLASH:HURT:1d8
 B:SLASH:HURT:1d8
 B:SLASH:HURT:1d7
-F:MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:HAS_LITE_2 | HUMAN |
 F:FRIENDS | DROP_60 | WILD_ALL |
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 D:$He looks inexperienced but tough.
@@ -1823,7 +1849,7 @@ I:110:8d4:20:12:5
 W:6:1:6:0:0
 B:HIT:HURT:1d8
 B:TOUCH:EAT_GOLD
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | 
 F:HURT_LITE | RES_DARK | RES_DISE | DROP_SKELETON | DROP_CORPSE
@@ -1901,7 +1927,8 @@ W:6:2:20:140:219
 B:SHOOT:HURT:2d5
 B:HIT:HURT:1d5
 B:HIT:HURT:1d5
-F:MALE | HAS_LITE_1 | HUMAN |
+X:MALE
+F:HAS_LITE_1 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | WILD_ALL | DROP_SKELETON | DROP_CORPSE
 F:ONLY_GOLD | DROP_1D2
 F:OPEN_DOOR | BASH_DOOR
@@ -1931,7 +1958,7 @@ G:o:G
 I:110:8d8:20:32:30
 W:6:1:15:0:0
 B:HIT:HURT:1d9
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | WILD_ALL | DROP_SKELETON | DROP_CORPSE |
 F:OPEN_DOOR | BASH_DOOR | 
 F:EVIL | ORC | HURT_LITE | RES_DARK
@@ -1991,7 +2018,7 @@ I:110:7d10:20:16:20
 W:7:2:25:700:348
 B:HIT:HURT:1d8
 B:HIT:HURT:1d8
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | 
 F:DROP_90 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
@@ -2057,7 +2084,7 @@ G:o:U
 I:110:11d9:20:32:30
 W:7:1:20:0:0
 B:HIT:HURT:1d9
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE |
 F:OPEN_DOOR | BASH_DOOR | 
 F:EVIL | ORC | HURT_LITE | RES_DARK
@@ -2113,7 +2140,8 @@ I:110:11d8:20:40:120
 W:7:2:40:200:265
 B:CRUSH:HURT:2d6
 B:BITE:LOSE_STR:1d5
-F:FEMALE | CAN_SWIM | WILD_SHORE |
+X:FEMALE
+F:CAN_SWIM | WILD_SHORE |
 F:RAND_25 | DROP_60 | 
 F:TAKE_ITEM | BASH_DOOR | DROP_CORPSE
 F:EVIL
@@ -2188,7 +2216,8 @@ B:HIT:HURT:1d10
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
-F:UNIQUE | MALE | SPEAK_ALL
+X:MALE
+F:UNIQUE | SPEAK_ALL
 F:FORCE_MAXHP | 
 F:ESCORT | ESCORTS | DROP_SKELETON | DROP_CORPSE
 F:DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
@@ -2226,7 +2255,8 @@ W:8:2:150:0:0
 B:HIT:HURT:1d6
 B:HIT:HURT:1d6
 B:TOUCH:EAT_GOLD
-F:UNIQUE | MALE | EVIL | SPEAK_ALL | HAS_LITE_2
+X:MALE
+F:UNIQUE | EVIL | SPEAK_ALL | HAS_LITE_2
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN | ONLY_ITEM | DROP_1D2 | DROP_GREAT
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_CORPSE | RES_TELE
 S:1_IN_5 | 
@@ -2254,7 +2284,8 @@ B:SHOOT:HURT:3d6
 B:HIT:HURT:2d6
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_ITEM
-F:UNIQUE | MALE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | HUMAN
+X:MALE
+F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | HUMAN
 F:ONLY_ITEM | DROP_1D2 | DROP_GREAT | WILD_WOOD
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | EVIL | DROP_SKELETON | DROP_CORPSE
 S:1_IN_5 | SHOOT | HEAL | TRAPS
@@ -2293,7 +2324,8 @@ B:HIT:HURT:2d6
 B:HIT:HURT:2d6
 B:HIT:HURT:1d9
 B:HIT:HURT:1d9
-F:UNIQUE | MALE | FORCE_MAXHP | ESCORT | DROP_1D2 | DROP_GOOD
+X:MALE
+F:UNIQUE | FORCE_MAXHP | ESCORT | DROP_1D2 | DROP_GOOD
 F:OPEN_DOOR | BASH_DOOR | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:EVIL | ORC | RES_DARK
 D:$A captain of a regiment of weaker orcs, Lagduf keeps his troop in order
@@ -2329,7 +2361,8 @@ W:8:1:18:500:1039
 B:SHOOT:HURT:2d7
 B:HIT:HURT:1d7
 B:HIT:HURT:1d7
-F:MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR |
 S:1_IN_9 | 
@@ -2401,7 +2434,8 @@ I:110:6d8:20:16:5
 W:8:2:20:500:1038
 B:HIT:HURT:2d4
 B:HIT:HURT:2d4
-F:MALE | GOOD | WILD_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:GOOD | WILD_ALL | DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | HAS_LITE_2 | HUMAN |
 F:FRIENDS | DROP_60 | 
 F:OPEN_DOOR | BASH_DOOR
@@ -2430,7 +2464,7 @@ G:o:s
 I:110:13d9:20:32:30
 W:8:1:25:0:0
 B:HIT:HURT:1d11
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | ORC | HURT_LITE | RES_DARK
@@ -2445,7 +2479,8 @@ I:110:8d8:20:24:10
 W:8:2:26:100:199
 B:HIT:HURT:2d6
 B:TOUCH:EAT_GOLD
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:DROP_1D2 | WILD_ALL |
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL
@@ -2545,7 +2580,8 @@ W:9:1:19:0:0
 B:CLAW:HURT:1d3
 B:CLAW:HURT:1d3
 B:BITE:HURT:1d3
-F:FEMALE | CAN_FLY | WILD_MOUNTAIN | DROP_CORPSE
+X:FEMALE
+F:CAN_FLY | WILD_MOUNTAIN | DROP_CORPSE
 F:RAND_25 | 
 F:ANIMAL | EVIL
 D:$A woman's face on the body of a vicious black bird.
@@ -2559,8 +2595,9 @@ I:110:11d9:15:25:20
 W:9:1:20:0:0
 B:HIT:HURT:1d5
 B:HIT:HURT:1d5
+X:MALE
 F:EVIL | FRIENDS | DROP_60 | DROP_90 | DROP_SKELETON | DROP_CORPSE
-F:OPEN_DOOR | MALE | WILD_WASTE | WILD_SWAMP
+F:OPEN_DOOR | WILD_WASTE | WILD_SWAMP
 D:$A mutated rat-creature from the great waste, it is vaguely
 D:$ humanoid in appearance and walks on its hind legs. This race
 D:$ serves chaos fervently and is greatly feared by others.
@@ -2617,7 +2654,7 @@ I:110:9d8:20:15:20
 W:9:1:30:0:0
 B:HIT:HURT:1d7
 B:HIT:HURT:1d7
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | DROP_90 | WILD_WOOD | WILD_SWAMP | WILD_MOUNTAIN |
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE | RES_DARK |
 F:EVIL | ORC | HURT_LITE
@@ -2744,7 +2781,8 @@ B:HIT:HURT:1d13
 B:HIT:HURT:1d13
 B:HIT:HURT:1d13
 B:HIT:HURT:1d13
-F:UNIQUE | MALE | EVIL | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | EVIL | HAS_LITE_2 | HUMAN |
 F:FORCE_MAXHP | SPEAK_ALL | WILD_ALL | DROP_SKELETON | DROP_CORPSE
 F:DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
 D:$A nasty piece of work, Brodda picks on defenseless women and children.
@@ -2901,7 +2939,7 @@ I:120:7d10:20:16:20
 W:10:1:50:700:375
 B:HIT:HURT:1d6
 B:HIT:HURT:1d6
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | 
 F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR
@@ -2933,7 +2971,8 @@ B:HIT:HURT:1d9
 B:HIT:HURT:1d8
 B:INSULT:FLAVOR
 B:INSULT:FLAVOR
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | ESCORTS | HAS_LITE_2 | DROP_90 | DROP_GOOD
 F:SMART | OPEN_DOOR | BASH_DOOR | ANIMAL | EVIL | IM_ACID
@@ -2982,7 +3021,7 @@ I:110:10d11:20:16:20
 W:10:1:50:700:348
 B:HIT:HURT:1d8
 B:HIT:HURT:1d8
-F:MALE | 
+X:MALE
 F:DROP_1D2 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | HURT_LITE | RES_DARK
@@ -3001,9 +3040,9 @@ I:110:9d10:20:20:20
 W:10:1:30:0:0
 B:CLAW:HURT:1d6
 B:CLAW:HURT:1d6
+X:MALE
 F:FRIENDS | WILD_WASTE | DROP_SKELETON
 F:OPEN_DOOR | BASH_DOOR | HURT_LITE | EVIL | DROP_60 | DROP_90
-F:MALE
 D:$"Rough-skinned, large-eyed, large-eared, with a horrible, 
 D:$distorted resemblance to the koala bear facially, though 
 D:$his body had an appearance of emaciation."
@@ -3059,7 +3098,8 @@ B:HIT:HURT:1d12
 B:HIT:HURT:1d10
 B:HIT:HURT:1d12
 B:HIT:HURT:1d10
-F:UNIQUE | MALE | SPEAK_ALL | FORCE_MAXHP | ESCORT | WILD_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL | FORCE_MAXHP | ESCORT | WILD_ALL |
 F:DROP_1D2 | DROP_GOOD | DROP_SKELETON | DROP_CORPSE |
 F:OPEN_DOOR | BASH_DOOR | EVIL | ORC | IM_POIS | RES_DARK
 D:$He is a cunning and devious orc. 
@@ -3251,7 +3291,8 @@ I:110:9d8:20:32:10
 W:10:3:35:500:376
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_ITEM
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:DROP_1D2 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | 
 F:EVIL | DROP_SKELETON
@@ -3267,8 +3308,9 @@ W:10:2:45:0:0
 B:CLAW:HURT:1d11
 B:CLAW:HURT:1d11
 B:BITE:HURT:1d4
+X:MALE
 F:BASH_DOOR | UNIQUE | FORCE_MAXHP | NO_CONF | NO_SLEEP
-F:ANIMAL | MALE | SPEAK_ALL | DROP_CORPSE
+F:ANIMAL | SPEAK_ALL | DROP_CORPSE
 D:$Fast-moving, with a taste for tuna sandwiches.
 D:素早く動く。ツナサンドが大好き。
 
@@ -3280,8 +3322,9 @@ I:110:9d8:12:12:16
 W:10:2:35:0:0
 B:HIT:HURT:1d7
 B:HIT:HURT:1d7
+X:MALE
 F:BASH_DOOR | OPEN_DOOR | FRIENDS | DROP_60 | IM_POIS | NO_SLEEP | NO_CONF
-F:MALE | DROP_SKELETON
+F:DROP_SKELETON
 D:$"There was something unusual about their appearance... For one thing, 
 D:$all had uniformly bloodshot eyes. Very, very bloodshot eyes. With them, 
 D:$though, the condition seemed normal. For another, all had an extra joint 
@@ -3539,7 +3582,8 @@ B:HIT:HURT:1d12
 B:HIT:HURT:1d12
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
-F:UNIQUE | MALE | QUESTOR | FORCE_MAXHP | WILD_ALL
+X:MALE
+F:UNIQUE | QUESTOR | FORCE_MAXHP | WILD_ALL
 F:ESCORT | DROP_SKELETON | DROP_CORPSE
 F:DROP_2D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR | SPEAK_ALL
 F:EVIL | ORC | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | RES_DARK
@@ -3554,7 +3598,8 @@ I:110:12d8:20:34:20
 W:12:1:40:400:372
 B:SLASH:HURT:3d6
 B:SLASH:HURT:3d6
-F:MALE | HUMAN | WILD_ALL | HAS_LITE_2 |
+X:MALE
+F:HUMAN | WILD_ALL | HAS_LITE_2 |
 F:DROP_1D2 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR
 D:$A warrior of considerable skill.
@@ -3568,7 +3613,8 @@ I:110:10d8:20:15:20
 W:9:1:36:0:0
 B:HIT:HURT:1d7
 B:HIT:HURT:1d7
-F:MALE | WILD_SWAMP | WILD_WASTE |
+X:MALE
+F:WILD_SWAMP | WILD_WASTE |
 F:PREVENT_SUDDEN_MAGIC | DROP_90 | HAS_LITE_2 |
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | 
@@ -3605,7 +3651,8 @@ W:12:1:40:0:0
 B:SHOOT:HURT:4d6
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
-F:MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:HAS_LITE_2 | HUMAN |
 F:DROP_1D2 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 S:1_IN_8
@@ -3707,7 +3754,8 @@ I:110:12d8:20:22:40
 W:12:1:36:800:445
 B:HIT:HURT:2d3
 B:HIT:HURT:2d3
-F:MALE | GOOD | HAS_LITE_2 |
+X:MALE
+F:GOOD | HAS_LITE_2 |
 F:PREVENT_SUDDEN_MAGIC | HUMAN |
 F:DROP_1D2 | 
 F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
@@ -3725,7 +3773,7 @@ I:115:7d10:20:30:30
 W:12:1:50:600:400
 B:HIT:HURT:1d9
 B:HIT:HURT:1d10
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | 
 F:ONLY_ITEM | DROP_1D2 | 
 F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
@@ -3902,7 +3950,8 @@ W:13:3:200:0:0
 B:HIT:HURT:1d9
 B:HIT:HURT:1d9
 B:HIT:HURT:1d8
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | ESCORTS | HAS_LITE_2 | DROP_90 | DROP_1D2 | DROP_GOOD
 F:SMART | OPEN_DOOR | BASH_DOOR | SPEAK_ALL | DROP_CORPSE
@@ -3952,7 +4001,8 @@ G:p:v
 I:110:12d8:20:10:10
 W:13:2:50:500:449
 B:HIT:HURT:2d2
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:PREVENT_SUDDEN_MAGIC | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
 F:SMART | OPEN_DOOR | BASH_DOOR
 F:EVIL
@@ -3974,7 +4024,8 @@ I:110:12d12:20:10:10
 W:13:2:50:700:370
 B:HIT:HURT:2d4
 B:HIT:HURT:2d4
-F:MALE | WILD_WOOD | HAS_LITE_2 | HUMAN |
+X:MALE
+F:WILD_WOOD | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
 F:SMART | OPEN_DOOR | BASH_DOOR
 S:1_IN_3 | 
@@ -4022,7 +4073,8 @@ W:13:2:45:0:0
 B:SHOOT:HURT:2d7
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
-F:MALE | WILD_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:WILD_ALL | DROP_SKELETON | DROP_CORPSE
 F:FRIENDS | DROP_60
 F:OPEN_DOOR | BASH_DOOR | 
 F:EVIL | ORC | HURT_LITE | RES_DARK
@@ -4132,7 +4184,7 @@ I:111:8d8:20:32:30
 W:14:1:15:0:0
 B:HIT:HURT:1d8
 B:EXPLODE:HURT:20d2
-F:MALE | 
+X:MALE
 F:WILD_ALL | 
 F:OPEN_DOOR | BASH_DOOR | 
 F:EVIL | ORC | HURT_LITE | RES_DARK
@@ -4199,9 +4251,10 @@ I:110:16d10:20:45:50
 W:14:1:60:400:321
 B:HIT:HURT:3d6
 B:HIT:HURT:3d6
+X:MALE
 F:DROP_60 | WILD_MOUNTAIN | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR
-F:EVIL | GIANT | MALE
+F:EVIL | GIANT |
 D:$A ten foot tall humanoid with powerful muscles.
 D:それは背の高さが 3 メートルもある、非常に屈強な人間型のモンスターだ。
 
@@ -4247,7 +4300,8 @@ I:120:2d5:8:6:6
 W:14:2:23:2000:700
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_FOOD
-F:MULTIPLY | DROP_60 | ONLY_GOLD | RAND_50 | OPEN_DOOR | MALE | GOOD 
+X:MALE
+F:MULTIPLY | DROP_60 | ONLY_GOLD | RAND_50 | OPEN_DOOR | GOOD 
 F:HAS_LITE_1 |
 S:1_IN_6
 S:BLINK
@@ -4277,7 +4331,8 @@ B:HIT:HURT:3d4
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:FORCE_MAXHP | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:ESCORT | DROP_1D2 | DROP_GOOD
 F:OPEN_DOOR | BASH_DOOR | EVIL | ORC | IM_COLD | IM_POIS | RES_DARK
@@ -4324,7 +4379,7 @@ B:GAZE:PARALYZE
 B:GAZE:TERRIFY
 B:GAZE:CONFUSE
 F:NEVER_MOVE | DROP_60 | EVIL | DEMON | DROP_CORPSE
-F:IM_POIS | IM_COLD |IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP
+F:IM_POIS | IM_COLD | IM_FIRE | NO_FEAR | NO_CONF | NO_SLEEP
 S:1_IN_6
 S:BO_ACID | S_MONSTER | SCARE | DRAIN_MANA
 D:$A creature like a giant purple Buddha with lots of teeth.
@@ -4347,7 +4402,8 @@ I:110:16d10:20:40:20
 W:15:3:50:0:0
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
-F:MALE | WILD_ALL |
+X:MALE
+F:WILD_ALL |
 F:FRIENDS | DROP_60 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | ORC | RES_DARK
@@ -4364,7 +4420,7 @@ I:110:22d11:60:65:60
 W:15:2:90:1000:436
 B:STING:HURT:1d10
 B:BITE:HURT:1d10
-F:FEMALE | 
+X:FEMALE
 F:RAND_25 | DROP_60 | DROP_1D2 | IM_POIS | IM_COLD | RES_WATE |
 F:OPEN_DOOR | BASH_DOOR | EMPTY_MIND | CAN_SWIM | DROP_CORPSE |
 F:EVIL
@@ -4435,7 +4491,7 @@ W:15:2:80:800:436
 B:CRUSH:HURT:2d8
 B:BITE:HURT:1d8
 B:BITE:HURT:1d8
-F:FEMALE | 
+X:FEMALE
 F:RAND_25 | DROP_60 | DROP_1D2 | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
 F:EVIL
@@ -4590,9 +4646,10 @@ I:110:17d10:20:50:50
 W:15:1:75:0:0
 B:HIT:COLD:3d6
 B:HIT:HURT:2d8
+X:MALE
 F:DROP_60 | WILD_WASTE | WILD_MOUNTAIN |
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
-F:EVIL | GIANT | MALE | AURA_COLD
+F:EVIL | GIANT | AURA_COLD
 F:IM_COLD
 D:$A twelve foot tall giant covered in furs.
 D:大きさが 3 メートルもある毛皮で覆われた巨人だ。
@@ -4636,7 +4693,8 @@ G:h:R
 I:110:7d8:20:20:20
 W:15:2:40:0:0
 B:HIT:HURT:1d5
-F:MALE | HAS_LITE_1 |
+X:MALE
+F:HAS_LITE_1 |
 F:PREVENT_SUDDEN_MAGIC | FRIENDS | DROP_60 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON
 F:EVIL
@@ -4709,7 +4767,8 @@ B:SHOOT:HURT:3d6
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
-F:MALE | WILD_ALL |
+X:MALE
+F:WILD_ALL |
 F:DROP_90 | 
 F:OPEN_DOOR | BASH_DOOR | ESCORT | DROP_SKELETON | DROP_CORPSE
 F:EVIL | ORC | RES_DARK | SPEAK_ALL
@@ -4764,9 +4823,10 @@ I:110:20d8:20:60:50
 W:16:2:54:2000:893
 B:HIT:FIRE:3d7
 B:HIT:FIRE:3d7
+X:MALE
 F:DROP_60 | SELF_LITE_1 |
 F:OPEN_DOOR | BASH_DOOR | WILD_VOLCANO |
-F:EVIL | GIANT | MALE | AURA_FIRE | DROP_SKELETON | DROP_CORPSE
+F:EVIL | GIANT | AURA_FIRE | DROP_SKELETON | DROP_CORPSE
 F:IM_FIRE
 D:$A glowing fourteen foot tall giant.  Flames drip from its red skin.
 D:背の高さが 4 メートル以上もある輝く巨人だ。
@@ -4793,7 +4853,8 @@ I:110:16d10:20:40:20
 W:16:3:55:800:332
 B:HIT:HURT:4d4
 B:HIT:HURT:4d4
-F:MALE | CAN_SWIM | IM_ACID | HAS_LITE_1 |
+X:MALE
+F:CAN_SWIM | IM_ACID | HAS_LITE_1 |
 F:FRIENDS | DROP_60 | WILD_SHORE |
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE
 F:EVIL 
@@ -4810,8 +4871,9 @@ B:HIT:HURT:3d5
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
+X:MALE
 F:UNIQUE | FORCE_MAXHP | EVIL | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
-F:MALE | HUMAN | DROP_90 | DROP_GOOD
+F:HUMAN | DROP_90 | DROP_GOOD
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR
 D:$A short and swarthy Easterling.
 D:背が低くて浅黒い肌をした東夷だ。
@@ -4838,8 +4900,9 @@ W:16:3:50:0:0
 B:HIT:SUPERHURT:4d4
 B:HIT:SUPERHURT:4d4
 B:HIT:SUPERHURT:4d4
+X:MALE
 F:HUMAN |
-F:MALE | NO_FEAR | NO_STUN | BASH_DOOR | OPEN_DOOR | DROP_1D2 | HAS_LITE_1 |
+F:NO_FEAR | NO_STUN | BASH_DOOR | OPEN_DOOR | DROP_1D2 | HAS_LITE_1 |
 F:WILD_WASTE | DROP_SKELETON | DROP_CORPSE
 D:$A warrior in a battle-frenzy; he'll stop only when he drops.
 D:戦闘狂乱状態の戦士だ。彼が止まるのは倒れた時のみだろう。
@@ -4912,7 +4975,7 @@ W:17:1:70:500:401
 B:HIT:HURT:1d4
 B:HIT:HURT:1d4
 B:BITE:HURT:1d6
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | WILD_WOOD | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | REGENERATE |
 F:EVIL | TROLL | HURT_LITE
@@ -5173,7 +5236,7 @@ W:18:1:68:0:0
 B:SHOOT:HURT:3d5
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
-F:MALE | 
+X:MALE
 F:FORCE_MAXHP | FRIENDS | DROP_60 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | ORC | IM_POIS | RES_DARK
@@ -5194,7 +5257,8 @@ B:HIT:HURT:3d8
 B:HIT:HURT:3d8
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:FORCE_MAXHP | 
 F:ESCORT | DROP_SKELETON | DROP_CORPSE
 F:DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
@@ -5213,7 +5277,8 @@ B:HIT:HURT:3d8
 B:HIT:HURT:3d8
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:FORCE_MAXHP | 
 F:ESCORT | DROP_SKELETON | DROP_CORPSE
 F:DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
@@ -5285,7 +5350,8 @@ I:120:12d8:20:50:30
 W:18:2:75:0:0
 B:CLAW:CONFUSE:3d5
 B:CLAW:CONFUSE:3d5
-F:FORCE_MAXHP | DROP_60 | FEMALE |
+X:FEMALE
+F:FORCE_MAXHP | DROP_60 |
 F:OPEN_DOOR | BASH_DOOR | IM_COLD | NO_CONF | NO_SLEEP |
 F:EVIL | DEMON | IM_POIS | IM_FIRE
 S:1_IN_8
@@ -5321,9 +5387,10 @@ I:110:24d8:20:75:50
 W:18:1:90:20000:709
 B:HIT:HURT:3d8
 B:HIT:HURT:3d8
+X:MALE
 F:DROP_60 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
-F:EVIL | GIANT | MALE | WILD_MOUNTAIN
+F:EVIL | GIANT | WILD_MOUNTAIN
 D:$It is eighteen feet tall and looking at you.
 D:それは背丈が 5 メートル以上もあって、冒険者を見下ろしている。
 
@@ -5469,7 +5536,8 @@ B:HIT:HURT:3d6
 B:HIT:HURT:3d6
 B:HIT:HURT:3d6
 B:HIT:HURT:3d6
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:FORCE_MAXHP | 
 F:ESCORT | DROP_SKELETON | DROP_CORPSE
 F:DROP_2D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
@@ -5507,7 +5575,8 @@ W:20:3:150:0:0
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:WAIL:TERRIFY
-F:MALE | CAN_SWIM | IM_ACID | IM_POIS | WILD_SHORE |
+X:MALE
+F:CAN_SWIM | IM_ACID | IM_POIS | WILD_SHORE |
 F:DROP_60 | DROP_1D2 | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | 
 F:EVIL | FORCE_MAXHP
@@ -5792,7 +5861,7 @@ I:120:18d15:20:40:30
 W:20:2:500:0:0
 B:HIT:HURT:3d8
 B:HIT:HURT:3d5
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | 
 F:ONLY_ITEM | DROP_2D2 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | 
@@ -5810,9 +5879,10 @@ I:110:24d10:20:60:50
 W:20:1:125:1500:487
 B:HIT:ELEC:3d8
 B:HIT:ELEC:3d8
+X:MALE
 F:DROP_90 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
-F:EVIL | GIANT | IM_ELEC | MALE
+F:EVIL | GIANT | IM_ELEC |
 D:$It is a twenty foot tall giant wreathed in clouds.
 D:それは背丈が 6 メートル以上もある巨人で、雲が周りに渦巻いている。
 
@@ -5826,7 +5896,8 @@ B:HIT:HURT:3d5
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ESCORT
 F:DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
@@ -5938,7 +6009,8 @@ B:HIT:HURT:3d8
 B:HIT:HURT:3d8
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ESCORT
 F:DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
@@ -6076,7 +6148,8 @@ I:115:15d10:20:40:20
 W:22:3:75:0:0
 B:BITE:POISON:5d5
 B:BITE:POISON:5d5
-F:MALE | CAN_SWIM | IM_POIS | IM_ACID | HAS_LITE_2 |
+X:MALE
+F:CAN_SWIM | IM_POIS | IM_ACID | HAS_LITE_2 |
 F:DROP_60 | DROP_1D2 | FRIENDS | DROP_CORPSE |
 F:OPEN_DOOR | BASH_DOOR
 F:EVIL | 
@@ -6174,7 +6247,8 @@ B:KICK:SUPERHURT:4d2
 B:HIT:SUPERHURT:4d1
 B:KICK:SUPERHURT:4d5
 B:HIT:SUPERHURT:4d1
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON
 F:DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_ELEC | HAS_LITE_2
 F:IM_FIRE | IM_COLD | IM_POIS | NO_FEAR | NO_CONF | NO_SLEEP
 S:1_IN_6 | BO_ELEC
@@ -6205,7 +6279,8 @@ I:110:15d11:20:40:40
 W:23:1:60:2500:532
 B:SLASH:HURT:3d5
 B:SLASH:SUPERHURT:3d5
-F:MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:HAS_LITE_2 | HUMAN |
 F:DROP_1D2 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL
@@ -6221,7 +6296,8 @@ W:23:5:1111:0:0
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ESCORT | ESCORTS
 F:DROP_2D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
@@ -6257,7 +6333,7 @@ I:120:7d10:20:16:20
 W:23:1:75:20000:657
 B:HIT:HURT:1d6
 B:HIT:HURT:1d6
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC
 F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | FRIENDS
@@ -6280,7 +6356,8 @@ W:23:2:110:2500:516
 B:HIT:HURT:2d8
 B:HIT:HURT:2d8
 B:HIT:EAT_GOLD:4d4
-F:MALE | DROP_SKELETON | DROP_CORPSE | HUMAN |
+X:MALE
+F:DROP_SKELETON | DROP_CORPSE | HUMAN |
 F:DROP_2D2
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | 
 F:EVIL
@@ -6340,7 +6417,8 @@ B:HIT:HURT:4d6
 B:HIT:HURT:4d6
 B:HIT:HURT:4d6
 B:HIT:HURT:4d6
-F:UNIQUE | MALE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:DROP_90 | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
 F:EVIL | IM_FIRE | IM_ELEC | NO_CONF | NO_SLEEP
@@ -6381,7 +6459,8 @@ B:HIT:HURT:3d6
 B:HIT:HURT:3d6
 B:HIT:UN_BONUS
 B:TOUCH:EAT_GOLD
-F:UNIQUE | MALE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
 F:DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR | EVIL
 F:IM_FIRE | IM_COLD | NO_CONF | NO_SLEEP | RES_DARK | RES_DISE | RES_TELE
@@ -6403,7 +6482,8 @@ B:HIT:HURT:3d7
 B:HIT:HURT:3d7
 B:HIT:HURT:3d7
 B:HIT:UN_BONUS
-F:UNIQUE | MALE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR | EVIL |
 F:IM_FIRE | IM_COLD | RES_DARK | RES_DISE | NO_CONF | NO_SLEEP | RES_TELE
@@ -6556,7 +6636,8 @@ B:HIT:HURT:4d6
 B:HIT:HURT:4d6
 B:HIT:HURT:4d6
 B:HIT:HURT:4d6
-F:UNIQUE | MALE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HAS_LITE_1 | HUMAN |
 F:DROP_90 | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
 F:EVIL | IM_FIRE | IM_ELEC | NO_CONF | NO_SLEEP
@@ -6593,7 +6674,7 @@ W:24:2:60:600:477
 B:WAIL:TERRIFY
 B:TOUCH:EXP_20
 B:TOUCH:DR_MANA:2d6
-F:FEMALE | 
+X:FEMALE
 F:RAND_50 | DROP_1D2 | 
 F:INVISIBLE | COLD_BLOOD | TAKE_ITEM | PASS_WALL | CAN_FLY |
 F:EVIL | UNDEAD | IM_COLD | IM_POIS | RES_NETH | NO_CONF | NO_SLEEP
@@ -6712,7 +6793,7 @@ W:25:3:500:0:0
 B:HIT:HURT:1d7
 B:HIT:HURT:1d7
 B:HIT:HURT:3d8
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | 
 F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR
@@ -6732,7 +6813,7 @@ W:25:1:85:800:424
 B:HIT:HURT:1d6
 B:HIT:HURT:1d6
 B:BITE:HURT:3d4
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | REGENERATE |
 F:EVIL | TROLL | HURT_LITE | HURT_ROCK
@@ -6766,7 +6847,7 @@ W:25:1:100:0:0
 B:HIT:HURT:1d8
 B:HIT:HURT:1d8
 B:BITE:HURT:3d4
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_90 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | REGENERATE |
 F:EVIL | TROLL | HURT_LITE | NO_CONF | NO_SLEEP
@@ -6868,7 +6949,8 @@ B:GAZE:TERRIFY
 B:HIT:DISEASE:6d6
 B:CLAW:LOSE_CON:2d6
 B:CLAW:LOSE_CON:2d6
-F:UNIQUE | MALE | SPEAK_ALL | UNDEAD | EVIL | ESCORTS | ESCORT
+X:MALE
+F:UNIQUE | SPEAK_ALL | UNDEAD | EVIL | ESCORTS | ESCORT
 F:FORCE_MAXHP | COLD_BLOOD | IM_POIS | IM_COLD | RES_NETH | NO_FEAR
 F:DROP_90 | DROP_GOOD | OPEN_DOOR | BASH_DOOR | RES_TELE
 S:1_IN_5 | TRAPS | CAUSE_3 | DARKNESS | S_UNDEAD | SCARE | SLOW
@@ -6938,7 +7020,8 @@ W:26:4:500:0:0
 B:HIT:HURT:4d6
 B:HIT:HURT:4d6
 B:HIT:HURT:4d6
-F:UNIQUE | MALE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:FORCE_MAXHP | WILD_ALL | HAS_LITE_2 | HUMAN |
 F:DROP_90 | DROP_GOOD | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | EVIL
 D:$A short and swarthy Easterling.
@@ -6953,7 +7036,8 @@ I:110:20d8:14:54:20
 W:26:3:100:0:0
 B:HIT:HURT:1d9
 B:HIT:HURT:1d9
-F:FRIENDS | MALE | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:FRIENDS | DROP_SKELETON | DROP_CORPSE
 F:BASH_DOOR | OPEN_DOOR | HAS_LITE_2 | HUMAN |
 S:1_IN_8
 S:BLIND | CONF | TPORT
@@ -7059,7 +7143,8 @@ B:HIT:UN_BONUS:3d12
 B:HIT:UN_BONUS:3d12
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_GOLD
-F:UNIQUE | MALE | SPEAK_ALL
+X:MALE
+F:UNIQUE | SPEAK_ALL
 F:FORCE_MAXHP | PREVENT_SUDDEN_MAGIC | DROP_SKELETON | DROP_CORPSE
 F:DROP_2D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR | INVISIBLE
 F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
@@ -7280,7 +7365,8 @@ W:27:2:1500:0:0
 B:HIT:SUPERHURT:5d6
 B:HIT:SUPERHURT:5d6
 B:HIT:SUPERHURT:5d6
-F:UNIQUE | FORCE_MAXHP | MALE | SPEAK_ALL | WILD_SWAMP | WILD_SHORE
+X:MALE
+F:UNIQUE | FORCE_MAXHP | SPEAK_ALL | WILD_SWAMP | WILD_SHORE
 F:ESCORT | HAS_LITE_2 |
 F:DROP_2D2 | DROP_GOOD | DROP_CORPSE | OPEN_DOOR | BASH_DOOR | CAN_SWIM
 F:EVIL | GIANT | IM_POIS
@@ -7378,7 +7464,7 @@ B:CRUSH:HURT:2d8
 B:BITE:HURT:1d10
 B:BITE:HURT:1d10
 B:TOUCH:DR_MANA:1d10
-F:FEMALE | 
+X:FEMALE
 F:PREVENT_SUDDEN_MAGIC | CAN_FLY |
 F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_CORPSE
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | 
@@ -7476,8 +7562,9 @@ B:SHOW:LOSE_INT
 B:SHOW:LOSE_WIS
 B:CHARGE:EAT_GOLD
 B:CHARGE:EAT_GOLD
+X:MALE
 F:DROP_1D2 | DROP_90 | DROP_GREAT | ONLY_ITEM
-F:EVIL | MALE | SPEAK_ALL | SMART | RES_TELE | CAN_SWIM | DROP_CORPSE
+F:EVIL | SPEAK_ALL | SMART | RES_TELE | CAN_SWIM | DROP_CORPSE
 F:ANIMAL | IM_POIS | NO_CONF | NO_SLEEP | FORCE_MAXHP | UNIQUE | PREVENT_SUDDEN_MAGIC
 F:RES_CHAO
 S:1_IN_3
@@ -7496,7 +7583,8 @@ W:28:1:240:1800:497
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:PREVENT_SUDDEN_MAGIC | DROP_1D2 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL
@@ -7550,7 +7638,8 @@ I:120:25d10:100:50:10
 W:28:3:250:6000:637
 B:HIT:CONFUSE:5d5
 B:HIT:TERRIFY:5d5
-F:MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | SMART
 F:EVIL
@@ -7616,7 +7705,8 @@ W:28:1:150:2500:571
 B:HIT:HURT:2d5
 B:HIT:HURT:2d5
 B:TOUCH:DR_MANA:2d6
-F:MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | 
 F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON | DROP_CORPSE
 F:SMART | OPEN_DOOR | BASH_DOOR
@@ -7735,7 +7825,7 @@ B:HIT:HURT:1d5
 B:HIT:HURT:1d5
 B:HIT:HURT:1d5
 B:BITE:COLD:3d6
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | WILD_WASTE | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | REGENERATE |
 F:EVIL | TROLL | IM_COLD | HURT_LITE
@@ -8251,7 +8341,8 @@ B:BITE:HURT:2d10
 B:STING:POISON:2d5
 B:STING:LOSE_STR:1d4
 B:STING:POISON:2d5
-F:UNIQUE | FEMALE | 
+X:FEMALE
+F:UNIQUE | 
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | ESCORTS | DROP_CORPSE
 F:DROP_1D2 | DROP_2D2 | DROP_GOOD | SMART | BASH_DOOR | 
@@ -8336,7 +8427,8 @@ W:32:2:300:0:0
 B:HIT:POISON:3d4
 B:HIT:LOSE_STR:3d4
 B:HIT:LOSE_STR:3d4
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:DROP_1D2 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE |
 F:EVIL | NO_CONF | NO_SLEEP
@@ -8370,9 +8462,10 @@ W:35:1:1500:0:0
 B:HIT:ELEC:3d8
 B:HIT:ELEC:3d8
 B:HIT:ELEC:3d8
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_1D2 | WILD_MOUNTAIN |
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | AURA_ELEC | DROP_SKELETON | DROP_CORPSE
-F:EVIL | GIANT | IM_COLD | IM_ELEC | MALE | SELF_LITE_1
+F:EVIL | GIANT | IM_COLD | IM_ELEC | SELF_LITE_1
 S:1_IN_8 | 
 S:BLINK | TELE_TO | CONF | SCARE | BO_ELEC | BA_ELEC
 D:$It is a twenty-five foot tall giant wreathed in lighting.
@@ -8461,7 +8554,7 @@ B:CLAW:HURT:1d5
 B:CLAW:HURT:1d5
 B:CLAW:HURT:1d5
 B:BITE:HURT:2d6
-F:MALE | 
+X:MALE
 F:FRIENDS | 
 F:ONLY_ITEM | DROP_90 | DROP_SKELETON | DROP_CORPSE |
 F:OPEN_DOOR | BASH_DOOR | REGENERATE |
@@ -8478,7 +8571,8 @@ B:KICK:SUPERHURT:7d1
 B:HIT:SUPERHURT:7d1
 B:KICK:SUPERHURT:7d4
 B:HIT:SUPERHURT:7d1
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON
 F:DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_FIRE | IM_POIS
 F:NO_FEAR | NO_CONF | NO_SLEEP | HAS_LITE_1 | HAS_LITE_2
 S:1_IN_7 | HEAL
@@ -8494,7 +8588,8 @@ W:33:3:2000:0:0
 B:HIT:SUPERHURT:5d5
 B:BITE:HURT:2d10
 B:BITE:HURT:2d3
-F:UNIQUE | MALE | FORCE_MAXHP | ESCORT
+X:MALE
+F:UNIQUE | FORCE_MAXHP | ESCORT
 F:DROP_1D2 | DROP_GOOD | WILD_WOOD | REGENERATE
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK
@@ -8512,7 +8607,8 @@ W:33:3:2000:0:0
 B:HIT:SUPERHURT:5d5
 B:BITE:HURT:2d10
 B:BITE:HURT:2d3
-F:UNIQUE | MALE | FORCE_MAXHP | ESCORT
+X:MALE
+F:UNIQUE | FORCE_MAXHP | ESCORT
 F:DROP_1D2 | DROP_GOOD | WILD_WOOD | REGENERATE
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK
@@ -8530,7 +8626,8 @@ W:33:3:2000:0:0
 B:HIT:SUPERHURT:5d5
 B:BITE:HURT:2d10
 B:BITE:HURT:2d3
-F:UNIQUE | MALE | FORCE_MAXHP | ESCORT
+X:MALE
+F:UNIQUE | FORCE_MAXHP | ESCORT
 F:DROP_1D2 | DROP_GOOD | WILD_WOOD | REGENERATE
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | TROLL | IM_COLD | IM_POIS | HURT_LITE | HURT_ROCK
@@ -8549,7 +8646,7 @@ B:HIT:HURT:3d5
 B:HIT:HURT:1d8
 B:HIT:HURT:1d8
 B:HIT:HURT:1d8
-F:MALE | 
+X:MALE
 F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | REGENERATE |
 F:EVIL | TROLL | IM_POIS | HURT_LITE
@@ -8566,7 +8663,8 @@ W:33:2:450:5000:597
 B:HIT:HURT:2d6
 B:HIT:HURT:1d6
 B:HIT:HURT:1d6
-F:MALE | HUMAN | OPEN_DOOR | BASH_DOOR | TAKE_ITEM | DROP_1D2 | ONLY_ITEM |
+X:MALE
+F:HUMAN | OPEN_DOOR | BASH_DOOR | TAKE_ITEM | DROP_1D2 | ONLY_ITEM |
 F:EVIL | IM_POIS | IM_COLD | NO_CONF | NO_SLEEP | DROP_SKELETON | DROP_CORPSE
 S:1_IN_4
 S:HOLD | SCARE | BLIND | CAUSE_3 | TRAPS | DARKNESS | FORGET | HASTE
@@ -8583,7 +8681,8 @@ B:HIT:HURT:10d2
 B:KICK:HURT:10d2
 B:PUNCH:HURT:10d2
 B:KICK:HURT:10d2
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | EVIL | HAS_LITE_1 |
 F:ONLY_ITEM | DROP_1D2 | ATTR_ANY | DROP_SKELETON | DROP_CORPSE
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR |
@@ -8724,7 +8823,8 @@ B:SLASH:HURT:9d1
 B:SLASH:HURT:6d5
 B:SLASH:HURT:25d1
 B:SLASH:HURT:30d1
-F:UNIQUE | MALE | SPEAK_ALL | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | HUMAN |
 F:FORCE_MAXHP | WILD_ALL | DROP_CORPSE
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
 F:OPEN_DOOR | BASH_DOOR | 
@@ -8747,7 +8847,8 @@ W:33:7:2000:0:0
 B:HIT:HURT:5d5
 B:BITE:HURT:2d10
 B:HIT:EAT_GOLD:2d2
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:FORCE_MAXHP | WILD_ALL | DROP_CORPSE
 F:ESCORT
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | 
@@ -8809,7 +8910,8 @@ B:HIT:HURT:1d9
 B:HIT:HURT:1d9
 B:HIT:HURT:2d2
 B:HIT:HURT:2d2
-F:MALE | WILD_SHORE | WILD_SWAMP | REGENERATE |
+X:MALE
+F:WILD_SHORE | WILD_SWAMP | REGENERATE |
 F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:FRIENDS | DROP_60 | 
 F:OPEN_DOOR | BASH_DOOR | CAN_SWIM |
@@ -8949,7 +9051,8 @@ B:HIT:HURT:2d8
 B:HIT:HURT:3d4
 B:HIT:EAT_GOLD:4d4
 B:HIT:EAT_ITEM:4d5
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:DROP_90 | DROP_2D2 | DROP_SKELETON | DROP_CORPSE
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR
 F:EVIL
@@ -8966,7 +9069,8 @@ B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
-F:UNIQUE | MALE | SPEAK_ALL | HAS_LITE_1 | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | HAS_LITE_1 | HUMAN |
 F:FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | 
@@ -9200,8 +9304,9 @@ E:Malicious leprechaun
 G:h:v
 I:120:4d5:8:13:8
 W:35:4:85:500:700
+X:MALE
 F:MULTIPLY | INVISIBLE | RAND_25 | TAKE_ITEM | COLD_BLOOD |
-F:HURT_LITE | EVIL | OPEN_DOOR | MALE | HAS_LITE_1 |
+F:HURT_LITE | EVIL | OPEN_DOOR | HAS_LITE_1 |
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_ITEM
 S:1_IN_6
@@ -9261,7 +9366,7 @@ B:SLASH:POISON:3d4
 B:SLASH:LOSE_STR:3d4
 B:SLASH:LOSE_STR:3d4
 B:SLASH:POISON:3d4
-F:MALE | 
+X:MALE
 F:DROP_1D2 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | HUMAN | NO_CONF | NO_SLEEP
@@ -9412,8 +9517,9 @@ W:35:1:330:0:0
 B:SHOOT:HURT:6d6
 B:HIT:HURT:2d6
 B:HIT:HURT:2d6
+X:MALE
 F:FORCE_MAXHP | OPEN_DOOR | FRIENDS | DROP_90 |
-F:SMART | EVIL | IM_POIS | IM_COLD | MALE | DROP_SKELETON | DROP_CORPSE
+F:SMART | EVIL | IM_POIS | IM_COLD | DROP_SKELETON | DROP_CORPSE
 S:1_IN_3
 S:SHOOT
 D:$A rebel halfling who has rejected the halfling tradition of archery.
@@ -9518,7 +9624,7 @@ B:HIT:HURT:1d10
 B:HIT:HURT:1d10
 B:HIT:HURT:3d2
 B:HIT:HURT:3d2
-F:MALE | 
+X:MALE
 F:FORCE_MAXHP | AQUATIC |
 F:FRIENDS | DROP_60 | WILD_OCEAN | REGENERATE |
 F:OPEN_DOOR | BASH_DOOR | RES_WATE
@@ -9639,7 +9745,8 @@ B:HIT:HURT:6d6
 B:BITE:HURT:2d10
 B:BITE:HURT:2d3
 B:SPIT:ACID:3d8
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:FORCE_MAXHP | 
 F:ESCORT | 
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | DROP_CORPSE | REGENERATE |
@@ -9902,7 +10009,7 @@ W:36:2:315:0:0
 B:HIT:POISON:3d4
 B:HIT:POISON:3d4
 B:HIT:LOSE_CON:3d4
-F:MALE | 
+X:MALE
 F:DROP_1D2 | FRIENDS | INVISIBLE | DROP_SKELETON | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | HURT_LITE |
 F:EVIL | RES_DARK | NO_CONF | NO_SLEEP
@@ -10047,7 +10154,8 @@ I:110:28d13:20:50:10
 W:36:2:666:6000:638
 B:HIT:HURT:2d6
 B:HIT:HURT:2d6
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_1D2 | DROP_SKELETON
 F:SMART | OPEN_DOOR | BASH_DOOR | 
@@ -10099,7 +10207,8 @@ B:HIT:HURT:6d6
 B:HIT:HURT:6d6
 B:HIT:HURT:3d8
 B:HIT:HURT:3d8
-F:UNIQUE | MALE | SPEAK_ALL | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | 
 F:OPEN_DOOR | BASH_DOOR | 
@@ -10264,7 +10373,8 @@ B:BITE:HURT:2d12
 B:BITE:HURT:2d12
 B:BITE:HURT:2d8
 B:BITE:HURT:2d8
-F:UNIQUE | FEMALE | GOOD | DROP_CORPSE
+X:FEMALE
+F:UNIQUE | GOOD | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | ESCORTS | CAN_FLY |
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | 
@@ -10544,11 +10654,12 @@ W:38:3:3250:0:0
 B:CLAW:POISON:8d4
 B:CLAW:POISON:8d4
 B:BITE:HURT:8d8
+X:MALE
 F:ESCORT
 F:DROP_60 | DROP_90 | DROP_1D2 | DROP_GOOD | ONLY_ITEM | DROP_CORPSE
 F:CAN_SWIM | BASH_DOOR | ELDRITCH_HORROR | RES_TELE | SPEAK_ALL |
 F:EVIL | DEMON | IM_FIRE | IM_COLD | IM_POIS | RES_WATE |
-F:UNIQUE | MALE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
+F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:NO_CONF | NO_SLEEP |
 S:1_IN_7 | 
 S:S_KIN | S_DEMON | BO_WATE | BA_WATE | BO_ACID | BA_ACID 
@@ -10574,11 +10685,12 @@ W:38:3:3250:0:0
 B:CLAW:POISON:8d4
 B:CLAW:POISON:8d4
 B:BITE:HURT:8d8
+X:FEMALE
 F:ESCORT
 F:DROP_60 | DROP_90 | DROP_1D2 | DROP_GOOD | ONLY_ITEM | DROP_CORPSE
 F:CAN_SWIM | BASH_DOOR | ELDRITCH_HORROR | RES_TELE | SPEAK_ALL |
 F:EVIL | DEMON | IM_FIRE | IM_COLD | IM_POIS | RES_WATE |
-F:UNIQUE | FEMALE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
+F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:NO_CONF | NO_SLEEP |
 S:1_IN_7 | 
 S:S_HYDRA | S_DEMON | DARKNESS | BA_WATE | BO_ACID | BA_ACID 
@@ -10602,7 +10714,8 @@ B:HIT:HURT:6d6
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:EXP_20
-F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | RES_NETH | MALE | HUMAN |
+X:MALE
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | RES_NETH | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | 
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | 
 F:EVIL | IM_COLD | HAS_LITE_1 |
@@ -10625,7 +10738,8 @@ B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:UN_POWER:5d5
 B:HIT:UN_BONUS:5d5
-F:UNIQUE | MALE | SPEAK_ALL | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | 
 F:SMART | OPEN_DOOR | TAKE_ITEM | BASH_DOOR | 
@@ -10786,9 +10900,10 @@ B:HIT:FIRE:6d6
 B:HIT:FIRE:6d6
 B:HIT:FIRE:6d6
 B:HIT:FIRE:6d6
+X:MALE
 F:UNIQUE | SELF_LITE_2 |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RAND_25 |
-F:EMPTY_MIND | SPEAK_ALL | MALE | AURA_FIRE |
+F:EMPTY_MIND | SPEAK_ALL | AURA_FIRE |
 F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
 F:EVIL | IM_FIRE | NONLIVING |
 F:IM_POIS | NO_CONF | NO_SLEEP
@@ -10864,7 +10979,8 @@ W:38:3:3000:20000:1244
 B:CLAW:HURT:10d2
 B:CLAW:HURT:10d2
 B:CLAW:HURT:20d1
-F:IM_POIS | OPEN_DOOR | BASH_DOOR | MALE | RES_PLAS | NONLIVING |
+X:MALE
+F:IM_POIS | OPEN_DOOR | BASH_DOOR | RES_PLAS | NONLIVING |
 F:IM_FIRE | NO_CONF | NO_SLEEP | EVIL | DEMON | FORCE_MAXHP | RES_TELE
 S:1_IN_3 | BO_PLAS
 D:$A minor demon lord with a goat's head, tough to kill.
@@ -10997,7 +11113,8 @@ B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
-F:UNIQUE | FEMALE | DROP_1D2 | DROP_2D2 | ONLY_ITEM | DROP_GOOD | HUMAN |
+X:FEMALE
+F:UNIQUE | DROP_1D2 | DROP_2D2 | ONLY_ITEM | DROP_GOOD | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RAND_25 | DROP_CORPSE |
 F:SPEAK_ALL | CAN_SWIM | WILD_OCEAN |
 F:KILL_ITEM | KILL_BODY | BASH_DOOR | POWERFUL |
@@ -11037,7 +11154,8 @@ B:BITE:HURT:2d12
 B:BITE:HURT:3d12
 B:BUTT:HURT:2d12
 B:BUTT:HURT:3d12
-F:UNIQUE | MALE | ATTR_MULTI | SPEAK_ALL | ATTR_ANY |
+X:MALE
+F:UNIQUE | ATTR_MULTI | SPEAK_ALL | ATTR_ANY |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_CORPSE | SELF_LITE_2 |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | RES_NEXU | RES_SOUN |
 F:OPEN_DOOR | BASH_DOOR | POWERFUL | CAN_FLY |
@@ -11275,7 +11393,8 @@ I:125:25d100:20:70:10
 W:47:2:7500:0:0
 B:HIT:HURT:12d9
 B:HIT:HURT:12d9
-F:MALE | REGENERATE | UNIQUE | SPEAK_ALL
+X:MALE
+F:REGENERATE | UNIQUE | SPEAK_ALL
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_CORPSE
 F:ONLY_ITEM | DROP_90 | DROP_2D2 | DROP_GREAT
 F:SMART | OPEN_DOOR | BASH_DOOR
@@ -11389,10 +11508,11 @@ B:HIT:CONFUSE:6d6
 B:HIT:CONFUSE:6d6
 B:HIT:CONFUSE:6d6
 B:HIT:CONFUSE:6d6
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:DROP_2D2 | DROP_4D2 | DROP_SKELETON | DROP_CORPSE
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
-F:EVIL | GIANT | MALE
+F:EVIL | GIANT |
 S:1_IN_5 | HEAL | TELE_TO | SCARE | S_MONSTERS
 D:$It is a humanoid figure thirty feet tall that gives off an aura of power 
 D:$and hate.
@@ -11428,7 +11548,7 @@ W:40:4:2100:0:0
 B:HIT:HURT:2d6
 B:HIT:HURT:2d6
 B:HIT:HURT:2d8
-F:FEMALE |
+X:FEMALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | HUMAN |
 F:OPEN_DOOR | BASH_DOOR | 
@@ -11450,7 +11570,8 @@ W:40:2:1800:8000:689
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
 B:HIT:HURT:3d5
-F:MALE | HAS_LITE_2 |
+X:MALE
+F:HAS_LITE_2 |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_90 | DROP_2D2 | HUMAN |
 F:SMART | OPEN_DOOR | BASH_DOOR | 
@@ -11480,7 +11601,8 @@ W:40:2:2150:20000:1026
 B:HIT:HURT:2d8
 B:HIT:HURT:2d8
 B:HIT:HURT:2d8
-F:MALE | HAS_LITE_2 |
+X:MALE
+F:HAS_LITE_2 |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_90 | DROP_4D2 | HUMAN |
 F:SMART | OPEN_DOOR | BASH_DOOR | 
@@ -11555,7 +11677,8 @@ B:GAZE:EXP_80
 B:GAZE:PARALYZE
 B:HIT:HURT:8d6
 B:HIT:HURT:8d6
-F:UNIQUE | FEMALE | SPEAK_ALL | DROP_CORPSE
+X:FEMALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | CAN_SWIM |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | 
 F:SMART | OPEN_DOOR | BASH_DOOR | SELF_LITE_2 |
@@ -11653,7 +11776,7 @@ W:40:4:1900:0:0
 B:CLAW:HURT:2d6
 B:CLAW:HURT:2d6
 B:CLAW:HURT:2d8
-F:FEMALE | 
+X:FEMALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_2D2 | DROP_SKELETON
 F:OPEN_DOOR | BASH_DOOR | 
@@ -11811,7 +11934,8 @@ B:HIT:FIRE:5d5
 B:HIT:FIRE:5d5
 B:GAZE:EXP_80
 B:WAIL:TERRIFY
-F:UNIQUE | MALE | SPEAK_ALL | SELF_LITE_1 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | SELF_LITE_1 |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | POWERFUL |
 F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
@@ -11876,7 +12000,8 @@ B:HIT:POISON:5d5
 B:HIT:DISEASE:5d5
 B:TOUCH:LOSE_ALL
 B:TOUCH:EXP_80
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
@@ -11900,7 +12025,7 @@ W:41:2:3000:30000:886
 B:HIT:HURT:2d8
 B:HIT:HURT:2d8
 B:HIT:HURT:2d8
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_90 | DROP_4D2 | 
 F:SMART | OPEN_DOOR | BASH_DOOR | 
@@ -11987,7 +12112,8 @@ B:HIT:HURT:8d6
 B:HIT:HURT:8d6
 B:HIT:UN_BONUS:6d8
 B:HIT:UN_BONUS:6d8
-F:UNIQUE | MALE | SPEAK_ALL | AMBERITE | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | AMBERITE | DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HAS_LITE_2 | HUMAN |
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | 
 F:SMART | OPEN_DOOR | BASH_DOOR |
@@ -12234,7 +12360,8 @@ B:HIT:HURT:5d10
 B:HIT:HURT:5d10
 B:HIT:EAT_ITEM:2d10
 B:HIT:EAT_ITEM:2d10
-F:UNIQUE | MALE | FORCE_MAXHP | HUMAN | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | FORCE_MAXHP | HUMAN | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:REGENERATE | NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR | RES_TELE
 F:ONLY_ITEM | DROP_1D2 | DROP_GREAT
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | SMART | POWERFUL |
@@ -12253,7 +12380,8 @@ W:43:2:3000:0:0
 B:HIT:EXP_20:8d2
 B:HIT:LOSE_STR:8d2
 B:HIT:LOSE_CON:8d2
-F:MALE | ATTR_MULTI | UNDEAD | EVIL |
+X:MALE
+F:ATTR_MULTI | UNDEAD | EVIL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | CAN_FLY |
 F:IM_FIRE | IM_COLD | IM_ACID | IM_ELEC | IM_POIS | RES_NETH |
 F:ONLY_ITEM | DROP_90 | DROP_4D2 | 
@@ -12309,7 +12437,8 @@ B:GAZE:TERRIFY
 B:GAZE:EXP_40
 B:GAZE:DR_MANA:4d8
 B:GAZE:HURT:2d20
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | 
 F:INVISIBLE | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
@@ -12455,7 +12584,8 @@ B:HIT:SUPERHURT:6d6
 B:HIT:SUPERHURT:6d6
 B:HIT:SUPERHURT:6d6
 B:HIT:SHATTER:10d10
-F:UNIQUE | MALE | SPEAK_ALL | 
+X:MALE
+F:UNIQUE | SPEAK_ALL | 
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:EMPTY_MIND | COLD_BLOOD | KILL_WALL | 
 F:KILL_ITEM | KILL_BODY | PASS_WALL | POWERFUL | 
@@ -12478,8 +12608,9 @@ W:44:6:85:0:0
 B:TOUCH:EXP_40:1d10
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_ITEM
+X:MALE
 F:MULTIPLY | INVISIBLE | RAND_25 | TAKE_ITEM | COLD_BLOOD | SMART |
-F:HURT_LITE | EVIL | OPEN_DOOR | MALE | UNDEAD | RES_NETH | HAS_LITE_1 |
+F:HURT_LITE | EVIL | OPEN_DOOR | UNDEAD | RES_NETH | HAS_LITE_1 |
 S:1_IN_6
 S:BLINK | TPORT | TELE_TO | CAUSE_3 | ANIM_DEAD
 D:$Nasty undead little creatures.  They are chanting the name of the 
@@ -12575,11 +12706,12 @@ B:HIT:COLD:12d12
 B:HIT:COLD:12d12
 B:HIT:COLD:12d12
 B:HIT:COLD:12d12
+X:MALE
 F:ESCORT | UNIQUE | IM_COLD | AURA_COLD | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
-F:EVIL | GIANT | MALE 
+F:EVIL | GIANT | 
 S:1_IN_3 | 
 S:HEAL | TELE_TO | 
 S:S_KIN | BR_COLD 
@@ -12673,7 +12805,8 @@ B:CLAW:POISON:10d5
 B:CLAW:POISON:10d5
 B:CLAW:EXP_40:10d1
 B:GAZE:TERRIFY
-F:UNIQUE | MALE | SPEAK_ALL | 
+X:MALE
+F:UNIQUE | SPEAK_ALL | 
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | 
 F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
@@ -12695,7 +12828,8 @@ B:HIT:HURT:4d6
 B:HIT:CONFUSE:1d4
 B:HIT:HURT:4d6
 B:HIT:CONFUSE:1d4
-F:UNIQUE | FEMALE | AURA_ELEC | SPEAK_ALL |
+X:FEMALE
+F:UNIQUE | AURA_ELEC | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SELF_LITE_1 |
 F:RAND_25 | CAN_FLY | NONLIVING |
 F:EMPTY_MIND | COLD_BLOOD | 
@@ -12738,7 +12872,8 @@ W:44:2:5000:0:0
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
 B:HIT:HURT:3d5
-F:MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_90 | DROP_4D2 | 
 F:SMART | OPEN_DOOR | BASH_DOOR | 
@@ -12815,7 +12950,8 @@ B:CLAW:HURT:4d10
 B:CLAW:HURT:4d10
 B:CLAW:HURT:4d10
 B:BITE:HURT:6d14
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_CORPSE
 F:BASH_DOOR | POWERFUL | MOVE_BODY | CAN_FLY |
@@ -12836,10 +12972,11 @@ I:120:25d25:20:70:20
 W:45:2:500:0:0
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
+X:MALE
 F:IM_POIS | IM_FIRE | IM_ELEC | IM_ACID | IM_COLD |
 F:NO_SLEEP | NO_FEAR | HUMAN |
 F:FRIENDS |
-F:MALE | OPEN_DOOR | BASH_DOOR
+F:OPEN_DOOR | BASH_DOOR
 D:$Fierce, barbaric warriors, armed with great spiked clubs, and surrounded 
 D:$in an aura of scarlet. Whenever one of them is slain, another appears 
 D:$out of nowhere to take his place.
@@ -12919,7 +13056,7 @@ B:HIT:TERRIFY:10d6
 B:HIT:TERRIFY:10d6
 B:HIT:EXP_80:8d6
 B:HIT:EXP_80:8d6
-F:MALE | 
+X:MALE
 F:FORCE_MAXHP | NAZGUL |
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | RES_TELE | RES_DARK |
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | RES_NETH | SMART |
@@ -12944,7 +13081,8 @@ B:CLAW:HURT:4d10
 B:CLAW:HURT:4d10
 B:CLAW:HURT:4d10
 B:BITE:HURT:6d14
-F:UNIQUE | MALE | REFLECTING | CAN_FLY | DROP_CORPSE
+X:MALE
+F:UNIQUE | REFLECTING | CAN_FLY | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | SELF_LITE_2 |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:BASH_DOOR | POWERFUL | MOVE_BODY | 
@@ -12988,12 +13126,13 @@ I:120:77d10:20:144:20
 W:45:2:1200:10000:1037
 B:HIT:HURT:3d12
 B:HIT:HURT:3d12
+X:MALE
 F:IM_POIS | IM_FIRE | IM_ELEC | IM_ACID | IM_COLD | GOOD | HUMAN | HAS_LITE_2 |
 F:RES_LITE | RES_DARK | RES_NETH | RES_SHAR | RES_SOUN |
 F:RES_CHAO | RES_NEXU | RES_DISE | RES_TIME | RES_TELE |
 F:DROP_SKELETON | DROP_CORPSE | NO_SLEEP | NO_CONF | NO_FEAR | NO_STUN |
 F:DROP_1D2 | DROP_90 | DROP_60 | FRIENDS | REFLECTING |
-F:MALE | OPEN_DOOR | BASH_DOOR | FORCE_MAXHP
+F:OPEN_DOOR | BASH_DOOR | FORCE_MAXHP
 S:1_IN_12
 S:HEAL 
 D:$Fighting for a good cause, and they consider you an agent of the devil.
@@ -13006,8 +13145,9 @@ G:h:D
 I:123:6d6:8:13:8
 W:46:6:80:0:0
 B:EXPLODE:HURT:20d3
+X:MALE
 F:MULTIPLY | RAND_25 | TAKE_ITEM | SMART |
-F:EVIL | OPEN_DOOR | MALE | NO_FEAR | HAS_LITE_1 |
+F:EVIL | OPEN_DOOR | NO_FEAR | HAS_LITE_1 |
 S:1_IN_6
 S:BLINK | TPORT | TELE_TO
 D:$These leprechauns are not afraid to die for their cause. They are 
@@ -13045,10 +13185,11 @@ B:HIT:CONFUSE:9d9
 B:HIT:CONFUSE:9d9
 B:HIT:CONFUSE:9d9
 B:HIT:CONFUSE:9d9
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
-F:EVIL | GIANT | MALE
+F:EVIL | GIANT |
 S:1_IN_5 | HEAL | TELE_TO | S_MONSTERS
 D:$It is a forty foot tall humanoid that shakes the ground as it walks.  The
 D:$ power radiating from its frame shakes your courage.  Your defiance stokes
@@ -13207,10 +13348,11 @@ B:CRUSH:HURT:10d11
 B:CRUSH:HURT:10d11
 B:CRUSH:HURT:10d11
 B:CRUSH:HURT:10d11
+X:MALE
 F:DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | FRIENDLY | HURT_FIRE |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
-F:GOOD | GIANT | MALE | RIDING
+F:GOOD | GIANT | RIDING
 D:$A treeherd; a sentient, moving tree. Its wrath is fearsome!
 D:木飼いの、意識を持った動く木だ。怒ると非常に恐い。
 
@@ -13223,10 +13365,11 @@ B:CRUSH:SHATTER:10d11
 B:CRUSH:SHATTER:10d11
 B:CRUSH:SHATTER:10d11
 B:CRUSH:SHATTER:10d11
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HURT_ROCK |
 F:ONLY_GOLD | DROP_4D2 | MOVE_BODY | KILL_WALL |
 F:SMART | KILL_ITEM | BASH_DOOR |
-F:EVIL | GIANT | MALE
+F:EVIL | GIANT |
 D:$A rock giant, a being made of living stone.
 D:生きている石で出来た、岩の巨人だ。
 
@@ -13240,7 +13383,8 @@ B:CLAW:HURT:1d10
 B:CLAW:HURT:1d10
 B:BITE:HURT:3d14
 B:BITE:HURT:4d14
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | CAN_FLY | DROP_CORPSE
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:BASH_DOOR | POWERFUL | MOVE_BODY | SELF_LITE_2 |
@@ -13289,7 +13433,8 @@ B:CLAW:HURT:4d10
 B:CLAW:HURT:4d10
 B:BITE:FIRE:14d6
 B:BITE:POISON:14d6
-F:UNIQUE | MALE |
+X:MALE
+F:UNIQUE | |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | DROP_CORPSE |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | DROP_90 | DROP_60 |
 F:BASH_DOOR | POWERFUL | MOVE_BODY | RIDING | SELF_LITE_2 |
@@ -13312,11 +13457,12 @@ B:CRUSH:HURT:12d13
 B:CRUSH:HURT:12d13
 B:CRUSH:HURT:12d13
 B:CRUSH:HURT:12d13
+X:MALE
 F:UNIQUE | DROP_CORPSE | SPEAK_ALL | HURT_FIRE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
-F:GOOD | GIANT | FRIENDLY | MALE
+F:GOOD | GIANT | FRIENDLY |
 D:$The oldest of all ents, a respected and feared ancient creature.
 D:ヴァラを除いてアルダにおいて最初に目覚めたのは彼である。
 D:エントの最長老で、尊敬し畏怖されている古えの存在だ。
@@ -13368,7 +13514,8 @@ B:CLAW:HURT:7d12
 B:CLAW:HURT:7d12
 B:BITE:HURT:8d14
 B:BITE:HURT:8d14
-F:UNIQUE | MALE | CAN_SWIM | DROP_CORPSE
+X:MALE
+F:UNIQUE | CAN_SWIM | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SELF_LITE_2 |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:BASH_DOOR | POWERFUL | MOVE_BODY | SPEAK_ALL |
@@ -13679,7 +13826,8 @@ W:51:4:18000:0:0
 B:HIT:SHATTER:20d12
 B:HIT:SHATTER:20d12
 B:BITE:POISON:6d14
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD | 
 F:DROP_90 | REGENERATE | KILL_WALL | RES_TELE |
@@ -13704,7 +13852,8 @@ B:BUTT:HURT:12d13
 B:BUTT:HURT:12d13
 B:HIT:HURT:10d10
 B:HIT:HURT:10d10
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD | 
 F:BASH_DOOR | DROP_CORPSE
@@ -13727,7 +13876,8 @@ B:HIT:HURT:10d5
 B:HIT:HURT:10d5
 B:HIT:HURT:10d5
 B:HIT:EXP_80
-F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | IM_FIRE | IM_COLD | IM_POIS | MALE | HUMAN |
+X:MALE
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | IM_FIRE | IM_COLD | IM_POIS | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | RES_NETH | RES_NEXU | RES_PLAS |
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | EVIL
 S:1_IN_5 |
@@ -13747,7 +13897,8 @@ B:CHARGE:EAT_GOLD:5d5
 B:CHARGE:EAT_ITEM:5d5
 B:SPIT:BLIND:10d5
 B:DROOL:DISEASE:8d5
-F:UNIQUE | MALE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | 
@@ -13768,7 +13919,8 @@ B:HIT:LOSE_CHR:5d5
 B:TOUCH:LOSE_ALL:10d1
 B:TOUCH:LOSE_ALL:10d1
 B:CHARGE:EAT_GOLD
-F:UNIQUE | MALE | SPEAK_ALL | REFLECTING | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | REFLECTING | DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | HAS_LITE_1
 F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GREAT
 F:NO_STUN | NO_SLEEP | NO_CONF | IM_ELEC | IM_FIRE | IM_POIS | IM_COLD
@@ -13839,7 +13991,8 @@ B:CRUSH:HURT:12d12
 B:CRUSH:HURT:12d12
 B:GAZE:LOSE_WIS:5d10
 B:GAZE:TERRIFY:5d10
-F:UNIQUE | MALE | SPEAK_ALL | ATTR_MULTI | ATTR_ANY |
+X:MALE
+F:UNIQUE | SPEAK_ALL | ATTR_MULTI | ATTR_ANY |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | ELDRITCH_HORROR |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
@@ -13899,7 +14052,8 @@ B:KICK:HURT:20d2
 B:KICK:HURT:10d2
 B:HIT:POISON:20d1
 B:HIT:LOSE_ALL:15d1
-F:MALE | EVIL | HUMAN |
+X:MALE
+F:EVIL | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON |
 F:ONLY_ITEM | DROP_4D2 | ATTR_MULTI | SHAPECHANGER | ATTR_ANY |
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | SMART | HAS_LITE_2 | RES_CHAO |
@@ -13923,7 +14077,8 @@ B:HIT:HURT:10d10
 B:HIT:HURT:5d5
 B:TOUCH:EXP_40
 B:TOUCH:EXP_40
-F:UNIQUE | MALE | SPEAK_ALL | 
+X:MALE
+F:UNIQUE | SPEAK_ALL | 
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
@@ -14358,7 +14513,8 @@ B:BITE:DR_MANA:8d8
 B:BITE:EXP_VAMP:8d8
 B:HIT:CONFUSE:6d6
 B:HIT:CONFUSE:6d6
-F:UNIQUE | FEMALE | 
+X:FEMALE
+F:UNIQUE | 
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | SPEAK_ALL | CAN_FLY |
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | RES_NETH | RES_DARK |
@@ -14546,7 +14702,8 @@ B:HIT:HURT:10d10
 B:HIT:HURT:8d6
 B:HIT:HURT:8d6
 B:HIT:HURT:8d6
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE |
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | FRIENDLY |
 F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD |
 F:OPEN_DOOR | BASH_DOOR | 
@@ -14579,7 +14736,8 @@ B:HIT:CONFUSE:4d8
 B:HIT:TERRIFY:5d6
 B:HIT:PARALYZE:5d6
 B:HIT:BLIND:4d8
-F:UNIQUE | MALE | AMBERITE | DROP_CORPSE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | AMBERITE | DROP_CORPSE | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SHAPECHANGER | SPEAK_ALL |
 F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD | CAN_FLY | RES_CHAO |
 F:OPEN_DOOR | BASH_DOOR | ATTR_MULTI | RES_DISE | ATTR_ANY | RES_TELE
@@ -14625,7 +14783,8 @@ B:HIT:FIRE:8d12
 B:HIT:FIRE:8d12
 B:HIT:FIRE:10d10
 B:HIT:FIRE:10d10
-F:UNIQUE | MALE | SPEAK_ALL | NO_FEAR | GOOD | AURA_FIRE | REFLECTING |
+X:MALE
+F:UNIQUE | SPEAK_ALL | NO_FEAR | GOOD | AURA_FIRE | REFLECTING |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | CAN_FLY |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | 
@@ -14635,7 +14794,7 @@ S:1_IN_2 |
 S:TELE_TO | BLIND | 
 S:BO_MANA | BA_FIRE |
 S:BR_FIRE | BR_MANA | INVULNER | BO_PLAS | BR_PLAS |
-S:S_ANGEL | PSY_SPEAR | HEAL | BA_LITE
+S:S_ANGEL | PSY_SPEAR | HEAL | BA_LITE | BO_LITE
 D:$A creature of godly appearance, you dare not challenge Uriel's supremacy.  
 D:$Those who stood against him before are but a memory, cremated by his 
 D:$mastery of elemental fire.
@@ -14656,7 +14815,8 @@ B:TOUCH:EXP_VAMP:5d12
 B:TOUCH:EXP_VAMP:5d12
 B:HIT:BLIND:10d10
 B:HIT:HURT:10d10
-F:UNIQUE | MALE | SPEAK_ALL | RES_NETH | NO_FEAR | GOOD |
+X:MALE
+F:UNIQUE | SPEAK_ALL | RES_NETH | NO_FEAR | GOOD |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | REFLECTING | AURA_COLD |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GREAT | CAN_FLY |
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | 
@@ -14666,7 +14826,7 @@ S:1_IN_2 |
 S:TELE_TO | BLIND | 
 S:BO_MANA | BA_NETH |
 S:BR_NETH | PSY_SPEAR | S_MONSTERS | HEAL |
-S:S_ANGEL | BR_MANA | BR_COLD | S_DRAGON | INVULNER | BA_LITE
+S:S_ANGEL | BR_MANA | BR_COLD | S_DRAGON | INVULNER | BA_LITE | BO_LITE
 D:$Azriel commands awesome power, his visage holy enough to shrivel your 
 D:$soul.  You shriek with disbelief as his mastery of death draws you to your 
 D:$grave.  It is truly beyond all but the mightiest of warriors to stand 
@@ -14686,7 +14846,8 @@ B:CLAW:HURT:5d12
 B:CLAW:HURT:6d12
 B:CLAW:HURT:8d12
 B:BITE:HURT:10d14
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | CAN_FLY |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | 
@@ -14778,7 +14939,8 @@ B:HIT:UN_BONUS:10d8
 B:HIT:FIRE:4d6
 B:HIT:HURT:15d10
 B:HIT:HURT:15d10
-F:UNIQUE | MALE | FORCE_MAXHP | SPEAK_ALL | NO_FEAR | GOOD |
+X:MALE
+F:UNIQUE | FORCE_MAXHP | SPEAK_ALL | NO_FEAR | GOOD |
 F:PREVENT_SUDDEN_MAGIC | SMART | AURA_ELEC | REFLECTING | RES_TELE |
 F:ESCORT | CAN_FLY | POWERFUL | SELF_LITE_1 | SELF_LITE_2 | ANGEL
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GREAT |
@@ -14788,7 +14950,7 @@ F:NO_CONF | NO_SLEEP |
 S:1_IN_2 |
 S:TELE_TO | BLIND | BO_MANA | S_ANGEL | S_KIN | INVULNER | DISPEL | PSY_SPEAR
 S:BR_MANA | BR_LITE | BR_ELEC | BA_MANA | HAND_DOOM | S_HI_DRAGON |
-S:BRAIN_SMASH | S_MONSTERS | HEAL | BR_DISE | BA_LITE
+S:BRAIN_SMASH | S_MONSTERS | HEAL | BR_DISE | BA_LITE | BO_LITE
 V:133
 D:$Commanding a legion of angels, Raphael will destroy you for your sins.  He 
 D:$will crush you like the pitiful insignificant being he sees you to be.  
@@ -14808,7 +14970,8 @@ W:61:2:22000:0:0
 B:HIT:EXP_VAMP:6d6
 B:HIT:EXP_VAMP:8d8
 B:HIT:EXP_VAMP:10d10
-F:UNIQUE | MALE | SPEAK_ALL | HAS_LITE_2 | HUMAN
+X:MALE
+F:UNIQUE | SPEAK_ALL | HAS_LITE_2 | HUMAN
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | DROP_CORPSE
 F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GREAT
 F:OPEN_DOOR | BASH_DOOR | RES_NEXU | RES_NETH | RES_CHAO | EVIL
@@ -14832,7 +14995,8 @@ B:HIT:UN_BONUS:6d8
 B:HIT:UN_BONUS:6d8
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
-F:UNIQUE | MALE | DROP_CORPSE | ATTR_MULTI | SPEAK_ALL |
+X:MALE
+F:UNIQUE | DROP_CORPSE | ATTR_MULTI | SPEAK_ALL |
 F:FRIENDLY | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | REFLECTING | RES_TELE
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
@@ -14863,7 +15027,8 @@ B:HIT:UN_BONUS:6d8
 B:HIT:UN_BONUS:6d8
 B:HIT:TERRIFY:5d5
 B:HIT:TERRIFY:5d5
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE | FRIENDLY | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE | FRIENDLY | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | REFLECTING | RES_TELE |
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
 F:SMART | OPEN_DOOR | BASH_DOOR | 
@@ -14897,7 +15062,8 @@ B:HIT:UN_BONUS:6d8
 B:HIT:UN_BONUS:6d8
 B:HIT:CONFUSE:5d5
 B:HIT:UN_POWER:5d5
-F:UNIQUE | MALE | ATTR_MULTI | SPEAK_ALL | AMBERITE | ATTR_ANY | RES_TELE
+X:MALE
+F:UNIQUE | ATTR_MULTI | SPEAK_ALL | AMBERITE | ATTR_ANY | RES_TELE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE | HAS_LITE_2 |
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | HUMAN |
 F:SMART | OPEN_DOOR | BASH_DOOR | 
@@ -15010,7 +15176,8 @@ B:HIT:CONFUSE:12d12
 B:TOUCH:LOSE_DEX:2d12
 B:HIT:BLIND:10d5
 B:HIT:PARALYZE:15d1
-F:UNIQUE | FEMALE | SPEAK_ALL |
+X:FEMALE
+F:UNIQUE | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | ESCORTS | EVIL |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | 
@@ -15087,7 +15254,8 @@ B:BITE:EXP_VAMP:8d8
 B:BITE:EXP_VAMP:8d8
 B:HIT:CONFUSE:8d8
 B:HIT:CONFUSE:8d8
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | SPEAK_ALL | CAN_FLY |
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | RES_NETH | RES_DARK |
@@ -15259,7 +15427,8 @@ B:TOUCH:LOSE_ALL:2d25
 B:GAZE:PARALYZE:1d20
 B:GAZE:TERRIFY:1d20
 B:GAZE:BLIND:1d20
-F:UNIQUE | MALE | SPEAK_ALL | ATTR_MULTI | 
+X:MALE
+F:UNIQUE | SPEAK_ALL | ATTR_MULTI | 
 F:RES_DISE | RES_NEXU | RES_CHAO | RES_INER | CAN_FLY |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | EVIL | SMART | DROP_CORPSE
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
@@ -15343,7 +15512,8 @@ W:67:1:35000:0:0
 B:HIT:HURT:8d15
 B:HIT:HURT:8d15
 B:TOUCH:EAT_ITEM
-F:UNIQUE | MALE | SPEAK_ALL | AMBERITE | RES_TELE | DROP_CORPSE | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | AMBERITE | RES_TELE | DROP_CORPSE | HAS_LITE_2 |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP | DROP_SKELETON | HUMAN |
 F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
 F:EVIL | IM_FIRE | IM_ELEC | SMART | REGENERATE | OPEN_DOOR | BASH_DOOR |
@@ -15402,7 +15572,8 @@ B:HIT:POISON:8d15
 B:HIT:POISON:8d15
 B:TOUCH:LOSE_CHR
 B:TOUCH:LOSE_CON
-F:UNIQUE | FEMALE | SPEAK_ALL | AMBERITE | ONLY_ITEM | RES_CHAO | RES_TELE |
+X:FEMALE
+F:UNIQUE | SPEAK_ALL | AMBERITE | ONLY_ITEM | RES_CHAO | RES_TELE |
 F:DROP_CORPSE | DROP_SKELETON | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP |
 F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 |
@@ -15428,7 +15599,8 @@ B:HIT:HURT:10d10
 B:HIT:HURT:10d10
 B:HIT:LOSE_STR:4d6
 B:HIT:LOSE_STR:4d6
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | CAN_FLY | HAS_DARK_2 |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:INVISIBLE | COLD_BLOOD | PASS_WALL | 
@@ -15481,7 +15653,8 @@ B:SHOOT:HURT:10d15
 B:HIT:HURT:9d15
 B:HIT:HURT:9d15
 B:HIT:LOSE_CON:1d30
-F:UNIQUE | MALE | SPEAK_ALL | AMBERITE | RES_TELE | DROP_SKELETON | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | AMBERITE | RES_TELE | DROP_SKELETON | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP | DROP_CORPSE
 F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
 F:HAS_LITE_2 |
@@ -15515,8 +15688,9 @@ B:CLAW:HURT:6d12
 B:CLAW:HURT:8d12
 B:CLAW:HURT:8d12
 B:BITE:HURT:10d14
+X:FEMALE
 F:ATTR_MULTI | 
-F:UNIQUE | FEMALE | CAN_FLY | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
+F:UNIQUE | CAN_FLY | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
 F:ESCORT | RIDING | AURA_FIRE | AURA_COLD | AURA_ELEC
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT
 F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY
@@ -15636,7 +15810,8 @@ B:HIT:HURT:9d15
 B:HIT:HURT:9d15
 B:INSULT:EAT_ITEM:1d3
 B:INSULT:EAT_GOLD:1d3
-F:UNIQUE | MALE | SPEAK_ALL | AMBERITE | RES_TELE | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | AMBERITE | RES_TELE | HAS_LITE_2 |
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP | HUMAN |
 F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
@@ -15744,7 +15919,8 @@ B:TOUCH:EXP_80
 B:TOUCH:UN_POWER
 B:TOUCH:LOSE_DEX:2d12
 B:TOUCH:LOSE_DEX:2d12
-F:UNIQUE | MALE | DROP_SKELETON | SPEAK_ALL | RES_TELE
+X:MALE
+F:UNIQUE | DROP_SKELETON | SPEAK_ALL | RES_TELE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | POWERFUL |
 F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | 
@@ -15771,7 +15947,8 @@ B:GAZE:EXP_40:2d6
 B:GAZE:UN_POWER:2d6
 B:GAZE:LOSE_INT:2d6
 B:GAZE:DR_MANA:7d10
-F:UNIQUE | MALE | SPEAK_ALL | RES_TELE
+X:MALE
+F:UNIQUE | SPEAK_ALL | RES_TELE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | CAN_FLY |
 F:SMART | BASH_DOOR | 
 F:EVIL | IM_POIS | 
@@ -15839,7 +16016,8 @@ I:130:66d101:100:150:20
 W:74:1:36500:0:0
 B:HIT:SHATTER:15d15
 B:HIT:SHATTER:15d15
-F:UNIQUE | MALE | SPEAK_ALL | AMBERITE | RES_TELE | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | AMBERITE | RES_TELE | HAS_LITE_2 |
 F:DROP_SKELETON | DROP_CORPSE | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP | KILL_WALL |
 F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
@@ -15878,7 +16056,8 @@ B:BITE:POISON:3d9
 B:BITE:POISON:3d9
 B:STING:POISON:2d5
 B:STING:POISON:2d5
-F:UNIQUE | FEMALE | 
+X:FEMALE
+F:UNIQUE | 
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_CORPSE | SELF_DARK_1 | SELF_DARK_2 |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | 
 F:SMART | BASH_DOOR | 
@@ -16038,7 +16217,8 @@ W:76:1:35500:0:0
 B:HIT:HURT:10d15
 B:HIT:HURT:10d15
 B:HIT:EAT_ITEM:10d15
-F:UNIQUE | MALE | SPEAK_ALL | SMART | AMBERITE | RES_TELE | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | SMART | AMBERITE | RES_TELE | HAS_LITE_2 |
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP | HUMAN |
 F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
@@ -16083,7 +16263,8 @@ B:CLAW:POISON:8d10
 B:CLAW:POISON:8d10
 B:CRUSH:HURT:8d15
 B:BITE:HURT:100d1
-F:UNIQUE | MALE | SPEAK_ALL | SMART | RES_TELE | ANIMAL |
+X:MALE
+F:UNIQUE | SPEAK_ALL | SMART | RES_TELE | ANIMAL |
 F:ESCORT | ESCORTS | CAN_SWIM | ELDRITCH_HORROR |
 F:OPEN_DOOR | BASH_DOOR |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP |
@@ -16166,7 +16347,8 @@ B:TOUCH:LOSE_ALL:50d1
 B:TOUCH:EXP_VAMP:50d1
 B:TOUCH:UN_BONUS:50d1
 B:TOUCH:DR_MANA:50d1
-F:UNIQUE | FEMALE | SPEAK_ALL | POWERFUL | RES_TELE |
+X:FEMALE
+F:UNIQUE | SPEAK_ALL | POWERFUL | RES_TELE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | 
 F:ONLY_ITEM | DROP_1D2 | DROP_GREAT
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | CAN_FLY |
@@ -16196,7 +16378,8 @@ B:HIT:UN_BONUS:6d8
 B:HIT:UN_BONUS:6d8
 B:TOUCH:UN_POWER
 B:TOUCH:UN_POWER
-F:UNIQUE | MALE | DROP_CORPSE | DROP_SKELETON | HUMAN |
+X:MALE
+F:UNIQUE | DROP_CORPSE | DROP_SKELETON | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | HAS_LITE_2 |
 F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD | 
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | 
@@ -16223,7 +16406,8 @@ B:HIT:UN_BONUS:6d8
 B:HIT:UN_POWER:6d8
 B:TOUCH:BLIND
 B:TOUCH:CONFUSE
-F:UNIQUE | MALE | SPEAK_ALL | POWERFUL | RES_TELE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | POWERFUL | RES_TELE | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | DROP_CORPSE | DROP_SKELETON 
 F:ONLY_ITEM | DROP_1D2 | DROP_GREAT
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | 
@@ -16257,12 +16441,13 @@ W:78:1:35500:0:0
 B:HIT:HURT:10d15
 B:HIT:HURT:10d15
 B:HIT:LOSE_CON:10d15
-F:UNIQUE | MALE | SPEAK_ALL | SMART | AMBERITE | RES_TELE | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | SMART | AMBERITE | RES_TELE | HAS_LITE_2 |
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP | HUMAN |
 F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
 F:POWERFUL |
-F:EVIL |IM_COLD | IM_POIS | IM_ACID | IM_ELEC | REGENERATE
+F:EVIL | IM_COLD | IM_POIS | IM_ACID | IM_ELEC | REGENERATE
 R:1094:5d6
 S:1_IN_4 |
 S:SCARE | CONF | TPORT | TELE_TO | S_MONSTER | DRAIN_MANA |
@@ -16384,7 +16569,8 @@ B:HIT:HURT:15d15
 B:HIT:HURT:15d15
 B:HIT:HURT:15d15
 B:HIT:HURT:15d15
-F:UNIQUE | MALE | SPEAK_ALL | SMART | AMBERITE | RES_TELE | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | SMART | AMBERITE | RES_TELE | HAS_LITE_2 |
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP | HUMAN |
 F:DROP_4D2 | DROP_1D2 | DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM |
@@ -16420,7 +16606,8 @@ B:HIT:HURT:10d10
 B:HIT:HURT:10d10
 B:HIT:EXP_80:5d10
 B:TOUCH:DR_MANA:6d10
-F:UNIQUE | MALE | SPEAK_ALL | RES_TELE
+X:MALE
+F:UNIQUE | SPEAK_ALL | RES_TELE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | 
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GREAT | 
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
@@ -16490,7 +16677,8 @@ B:HIT:ELEC:12d12
 B:HIT:ELEC:12d12
 B:HIT:ELEC:12d12
 B:HIT:ELEC:12d12
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | CAN_FLY |
 F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GREAT | 
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | 
@@ -16571,7 +16759,8 @@ B:GAZE:EXP_80
 B:GAZE:EXP_80
 B:TOUCH:POISON:3d5
 B:TOUCH:POISON:3d5
-F:UNIQUE | MALE | SPEAK_ALL | DROP_SKELETON | RES_TELE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_SKELETON | RES_TELE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT |
 F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | 
@@ -16600,7 +16789,8 @@ B:GAZE:EXP_VAMP:1d15
 B:GAZE:TERRIFY:1d15
 B:TOUCH:FIRE:4d5
 B:TOUCH:UN_POWER:4d5
-F:MALE | UNIQUE | SPEAK_ALL | CAN_FLY |
+X:MALE
+F:UNIQUE | SPEAK_ALL | CAN_FLY |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT |
 F:IM_FIRE | RES_PLAS | RES_NETH | AURA_FIRE |
@@ -16683,8 +16873,9 @@ B:HIT:COLD:5d10
 B:HIT:SUPERHURT:5d10
 B:HIT:COLD:5d10
 B:HIT:SUPERHURT:5d10
+X:MALE
 F:UNIQUE | SPEAK_ALL |
-F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RES_TELE | RES_NETH | RES_WATE | MALE |
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RES_TELE | RES_NETH | RES_WATE | |
 F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GREAT | EVIL | ESCORT | GIANT |
 F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | TAKE_ITEM | RES_DISE |
 F:IM_COLD | NO_CONF | NO_SLEEP | IM_POIS | HURT_FIRE |
@@ -16709,7 +16900,8 @@ B:HIT:BLIND:6d11
 B:HIT:UN_BONUS:6d11
 B:HIT:UN_POWER:6d11
 B:TOUCH:DR_MANA:6d11
-F:UNIQUE | DROP_CORPSE | MALE |
+X:MALE
+F:UNIQUE | DROP_CORPSE | |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RES_TELE | RES_NETH | RES_PLAS |
 F:ONLY_ITEM | DROP_4D2 | DROP_3D2 | DROP_GREAT | EVIL | AURA_FIRE |
 F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | TAKE_ITEM | SPEAK_ALL |
@@ -16782,8 +16974,9 @@ B:HIT:FIRE:6d11
 B:HIT:SUPERHURT:6d11
 B:HIT:FIRE:6d11
 B:HIT:SUPERHURT:6d11
+X:MALE
 F:UNIQUE | SELF_LITE_2 |
-F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RES_TELE | RES_NETH | RES_PLAS | MALE |
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RES_TELE | RES_NETH | RES_PLAS | |
 F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GREAT | EVIL | AURA_FIRE | DEMON |
 F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | TAKE_ITEM | SPEAK_ALL |
 F:IM_FIRE | NO_CONF | NO_SLEEP | IM_POIS | HURT_COLD | GIANT |
@@ -16835,7 +17028,8 @@ B:HIT:FIRE:8d12
 B:HIT:FIRE:8d12
 B:CRUSH:SUPERHURT:8d12
 B:TOUCH:UN_POWER
-F:UNIQUE | MALE | SELF_LITE_1 | SELF_LITE_2 | AURA_FIRE |
+X:MALE
+F:UNIQUE | SELF_LITE_1 | SELF_LITE_2 | AURA_FIRE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | ESCORTS | CAN_FLY |
 F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GREAT | 
@@ -16864,7 +17058,8 @@ B:CLAW:HURT:29d9
 B:CLAW:HURT:29d9
 B:BITE:POISON:24d6
 B:BITE:POISON:24d6
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | ESCORTS | DROP_CORPSE 
 F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GREAT | 
@@ -16965,7 +17160,8 @@ B:HIT:UN_BONUS:6d8
 B:HIT:UN_BONUS:6d8
 B:HIT:HURT:5d10
 B:HIT:DR_MANA:10d10
-F:UNIQUE | MALE | DROP_SKELETON | SPEAK_ALL | RES_TELE
+X:MALE
+F:UNIQUE | DROP_SKELETON | SPEAK_ALL | RES_TELE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | 
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT | 
@@ -17096,7 +17292,8 @@ B:CRUSH:LOSE_WIS:20d5
 B:CRUSH:LOSE_INT:20d5
 B:BITE:LOSE_STR:10d2
 B:BITE:LOSE_CON:10d2
-F:UNIQUE | SPEAK_ALL | FEMALE | ELDRITCH_HORROR | AURA_ELEC | RES_TELE
+X:FEMALE
+F:UNIQUE | SPEAK_ALL | ELDRITCH_HORROR | AURA_ELEC | RES_TELE
 F:ATTR_MULTI | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | PASS_WALL | ATTR_ANY | 
 F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GREAT | NONLIVING | CAN_FLY |
 F:SMART | OPEN_DOOR | BASH_DOOR | REGENERATE | DEMON | AURA_COLD 
@@ -17128,7 +17325,8 @@ I:130:75d99:100:100:20
 W:92:3:96000:0:0
 B:HIT:HURT:2d66
 B:HIT:HURT:2d66
-F:UNIQUE | SPEAK_ALL | MALE |
+X:MALE
+F:UNIQUE | SPEAK_ALL | |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | PASS_WALL |
 F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GREAT |
 F:SMART | OPEN_DOOR | BASH_DOOR | REGENERATE | CAN_FLY |
@@ -17156,7 +17354,8 @@ B:CLAW:HURT:30d10
 B:CLAW:HURT:30d10
 B:BITE:POISON:28d12
 B:BITE:POISON:28d12
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE | FORCE_MAXHP | RAND_25 | 
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE | FORCE_MAXHP | RAND_25 | 
 F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GREAT | AURA_FIRE |
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | KILL_BODY | 
 F:ANIMAL | EVIL | IM_FIRE | IM_POIS | 
@@ -17184,9 +17383,10 @@ B:CRUSH:LOSE_CON:30d4
 B:CRUSH:LOSE_STR:30d4
 B:GAZE:LOSE_INT:1d50
 B:GAZE:LOSE_WIS:1d50
+X:MALE
 F:UNIQUE | SPEAK_ALL | ELDRITCH_HORROR | RES_TELE | NONLIVING |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | PASS_WALL | DEMON | RES_NEXU | RES_CHAO |
-F:SHAPECHANGER | ATTR_MULTI | ATTR_ANY | MALE | AURA_ELEC |
+F:SHAPECHANGER | ATTR_MULTI | ATTR_ANY | AURA_ELEC |
 F:ONLY_ITEM | DROP_4D2 | DROP_3D2 | DROP_GREAT |
 F:SMART | OPEN_DOOR | BASH_DOOR | REGENERATE | AURA_COLD |
 F:EVIL | IM_ACID | IM_POIS | IM_FIRE | NO_CONF | NO_SLEEP | POWERFUL |
@@ -17337,7 +17537,8 @@ B:HIT:FIRE:30d12
 B:HIT:SUPERHURT:30d10
 B:HIT:FIRE:30d12
 B:HIT:SUPERHURT:30d10
-F:UNIQUE | MALE | SPEAK_ALL | CAN_FLY | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
+X:MALE
+F:UNIQUE | SPEAK_ALL | CAN_FLY | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
 F:ESCORT | ESCORTS | KILL_WALL | AURA_FIRE | NONLIVING
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT
 F:OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY
@@ -17409,7 +17610,8 @@ B:HIT:UN_BONUS:10d12
 B:HIT:UN_BONUS:10d12
 B:TOUCH:UN_POWER
 B:TOUCH:UN_POWER
-F:UNIQUE | MALE | SPEAK_ALL | REFLECTING | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | REFLECTING | HAS_LITE_2 |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT |
 F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY | REGENERATE | 
@@ -17442,7 +17644,8 @@ B:KICK:DR_MANA:10d10
 B:KICK:UN_POWER:13d13
 B:BUTT:UN_BONUS:12d12
 B:BITE:TIME:11d11
-F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | FEMALE
+X:FEMALE
+F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:REFLECTING | AURA_COLD | AURA_ELEC |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 | 
 F:DROP_GREAT | RES_LITE | RES_NETH | RES_WATE | RES_PLAS |
@@ -17489,7 +17692,8 @@ B:HIT:UN_BONUS:12d12
 B:HIT:UN_POWER:12d12
 B:HIT:BLIND:10d3
 B:TOUCH:DR_MANA:10d8
-F:UNIQUE | QUESTOR | MALE | SPEAK_ALL | DROP_CORPSE | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | QUESTOR | SPEAK_ALL | DROP_CORPSE | HAS_LITE_2 |
 F:ATTR_MULTI | AMBERITE | RES_TELE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | FORCE_DEPTH | HUMAN |
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT |
@@ -17544,7 +17748,8 @@ B:HIT:SHATTER:20d10
 B:HIT:SHATTER:20d10
 B:HIT:LOSE_ALL:10d12
 B:TOUCH:UN_POWER
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | FORCE_DEPTH | SELF_DARK_1 | SELF_DARK_2
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 
 F:DROP_GREAT | SMART | KILL_WALL | MOVE_BODY | AURA_COLD
@@ -17788,7 +17993,8 @@ B:KICK:SUPERHURT:6d1
 B:HIT:EXP_10:6d2
 B:KICK:SUPERHURT:6d4
 B:HIT:EXP_10:6d2
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON | DROP_60 | DROP_1D2
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON | DROP_60 | DROP_1D2
 F:OPEN_DOOR | BASH_DOOR | IM_COLD | HAS_LITE_2
 F:IM_POIS | RES_NETH | NO_FEAR | NO_CONF | NO_SLEEP
 S:1_IN_9 | BO_NETH
@@ -17848,7 +18054,8 @@ B:KICK:HURT:7d10
 B:HIT:UN_POWER:7d8
 B:KICK:HURT:7d10
 B:HIT:UN_POWER:7d8
-F:UNIQUE | MALE | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | HAS_LITE_2 | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_CORPSE | SPEAK_ALL |
 F:ONLY_ITEM | DROP_1D2 | DROP_3D2 | DROP_GREAT |
 F:OPEN_DOOR | POWERFUL | MOVE_BODY | CAN_SWIM |
@@ -17950,7 +18157,8 @@ B:CLAW:EXP_VAMP:10d10
 B:CLAW:EXP_VAMP:10d10
 B:SPIT:BLIND:10d10
 B:HIT:LOSE_CON:10d10
-F:UNIQUE | MALE |
+X:MALE
+F:UNIQUE | |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | SPEAK_ALL | CAN_FLY | AURA_COLD |
 F:ONLY_ITEM | DROP_1D2 | DROP_GREAT |
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | REGENERATE | 
@@ -17991,7 +18199,8 @@ B:HIT:TIME:5d8
 B:HIT:TIME:5d8
 B:HIT:TIME:5d8
 B:KICK:UN_BONUS:8d10
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_4D2 | DROP_GREAT | HUMAN |
 F:REFLECTING | SMART | REGENERATE | PASS_WALL | CAN_FLY |
 F:EVIL | IM_ACID | IM_COLD | IM_POIS | IM_FIRE | IM_ELEC | NO_CONF | 
@@ -18018,7 +18227,8 @@ B:HIT:HURT:14d14
 B:HIT:HURT:14d14
 B:HIT:HURT:14d14
 B:HIT:HURT:14d14
-F:UNIQUE | MALE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | FRIENDLY |
+X:MALE
+F:UNIQUE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | FRIENDLY |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_GOOD | HUMAN |
 F:REFLECTING | SMART | REGENERATE | OPEN_DOOR |
 F:GOOD | IM_COLD | IM_FIRE | IM_ELEC | NO_CONF | NO_STUN |
@@ -18042,7 +18252,8 @@ B:HIT:BLIND:8d8
 B:HIT:CONFUSE:8d8
 B:TOUCH:UN_POWER
 B:TOUCH:UN_POWER
-F:UNIQUE | FEMALE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL |
+X:FEMALE
+F:UNIQUE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_GOOD | HUMAN |
 F:REFLECTING | SMART | REGENERATE | OPEN_DOOR |
 F:EVIL | IM_COLD | IM_FIRE | IM_ELEC | NO_CONF | NO_STUN |
@@ -18068,7 +18279,7 @@ B:CRUSH:SHATTER:22d15
 B:CRUSH:SHATTER:22d15
 B:BITE:LOSE_ALL:15d12
 B:TOUCH:UN_POWER
-F:SPEAK_ALL | UNDEAD | UNIQUE2 |
+F:SPEAK_ALL | UNDEAD | ONLY_ONE | NO_INSTANTLY_DEATH |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | FORCE_DEPTH |
 F:REFLECTING | AURA_FIRE | AURA_ELEC | AURA_COLD |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_4D2 | 
@@ -18123,7 +18334,7 @@ B:TOUCH:EXP_VAMP:1d16
 B:TOUCH:DR_MANA:3d10
 B:TOUCH:LOSE_DEX:8d8
 B:TOUCH:LOSE_INT:8d8
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
 F:ONLY_ITEM | DROP_90 | DROP_4D2 | 
 F:SMART | INVISIBLE | COLD_BLOOD | UNDEAD |
@@ -18217,7 +18428,8 @@ B:HIT:HURT:8d6
 B:HIT:HURT:8d6
 B:HIT:UN_BONUS:6d8
 B:HIT:UN_BONUS:6d8
-F:UNIQUE | DROP_CORPSE | MALE | 
+X:MALE
+F:UNIQUE | DROP_CORPSE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | UNDEAD 
 F:SMART | OPEN_DOOR | BASH_DOOR | HAS_LITE_2 |
@@ -18306,7 +18518,8 @@ B:HIT:HURT:2d4
 B:HIT:HURT:2d4
 B:HIT:HURT:2d4
 B:HIT:HURT:2d4
-F:MALE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_1D2 | SMART
+X:MALE
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_1D2 | SMART
 F:DROP_CORPSE | DROP_SKELETON | CAN_SWIM
 S:1_IN_5 |
 S:ROCKET
@@ -18354,7 +18567,8 @@ W:25:1:90:800:424
 B:HIT:FIRE:1d6
 B:HIT:FIRE:1d6
 B:BITE:FIRE:3d4
-F:MALE | FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE | SELF_LITE_1 |
+X:MALE
+F:FRIENDS | DROP_60 | DROP_SKELETON | DROP_CORPSE | SELF_LITE_1 |
 F:OPEN_DOOR | BASH_DOOR | EVIL | TROLL | HURT_LITE | REGENERATE |
 F:HURT_COLD | IM_FIRE | WILD_VOLCANO
 D:$Fire trolls are believed to have been created by an
@@ -18372,7 +18586,8 @@ B:SHOOT:HURT:7d6
 B:HIT:HURT:1d9
 B:HIT:HURT:1d9
 B:HIT:HURT:4d8
-F:MALE | ONLY_ITEM | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR |
+X:MALE
+F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR |
 F:NO_SLEEP | FRIENDLY | GOOD | 
 S:1_IN_3 |
 S:HEAL | BLINK | TPORT | BA_FIRE | SHOOT | BA_COLD
@@ -18386,7 +18601,8 @@ I:110:40d10:12:60:10
 W:25:2:350:0:0
 B:SLASH:HURT:4d6
 B:SLASH:HURT:4d6
-F:MALE | ONLY_ITEM | DROP_90 | DROP_CORPSE | DROP_SKELETON | GOOD | HUMAN |
+X:MALE
+F:ONLY_ITEM | DROP_90 | DROP_CORPSE | DROP_SKELETON | GOOD | HUMAN |
 F:OPEN_DOOR | BASH_DOOR | NO_FEAR | HAS_LITE_1 |
 D:$A warrior clad in ornate but effective armour, holding katana so sharp it
 D:$ can cut your throat and you won't notice till you nod.
@@ -18510,7 +18726,8 @@ B:CRAWL:POISON:3d4
 B:CRAWL:EAT_FOOD:3d4
 B:TOUCH:ACID:3d5
 B:HIT:HURT:3d5
-F:UNIQUE | FEMALE | FORCE_MAXHP | SPEAK_ALL | SMART | ESCORT | ESCORTS | 
+X:FEMALE
+F:UNIQUE | FORCE_MAXHP | SPEAK_ALL | SMART | ESCORT | ESCORTS | 
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_CORPSE |
 F:WEIRD_MIND | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
 F:EVIL | IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | IM_POIS
@@ -18585,7 +18802,8 @@ W:5:3:90:0:0
 B:HIT:HURT:2d6
 B:TOUCH:EAT_ITEM
 B:TOUCH:EAT_GOLD
-F:UNIQUE | MALE | HAS_LITE_1 |
+X:MALE
+F:UNIQUE | HAS_LITE_1 |
 F:FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON |
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | 
 F:OPEN_DOOR | BASH_DOOR | 
@@ -18598,12 +18816,13 @@ N:915:初級修験者
 E:Elementary mystic
 G:p:o
 I:115:35d10:30:50:5
-W:33:3:600:5000:916
+W:33:3:700:5000:916
 B:KICK:HURT:9d2
 B:KICK:HURT:9d2
 B:KICK:HURT:9d2
 B:KICK:HURT:9d2
-F:MALE | GOOD | DROP_CORPSE | DROP_SKELETON |
+X:MALE
+F:GOOD | DROP_CORPSE | DROP_SKELETON |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | 
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | 
@@ -18618,12 +18837,13 @@ E:Medium mystic
 G:p:o
 G:p:o
 I:120:35d15:30:50:5
-W:38:3:500:10000:917
+W:38:3:900:10000:917
 B:KICK:HURT:10d2
 B:KICK:HURT:10d2
 B:KICK:HURT:10d2
 B:KICK:HURT:10d2
-F:MALE | GOOD | DROP_CORPSE | DROP_SKELETON |
+X:MALE
+F:GOOD | DROP_CORPSE | DROP_SKELETON |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | 
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | 
@@ -18645,7 +18865,8 @@ B:KICK:HURT:15d2
 B:KICK:HURT:15d2
 B:HIT:POISON:20d1
 B:HIT:PARALYZE:15d1
-F:MALE | GOOD | DROP_CORPSE | DROP_SKELETON |
+X:MALE
+F:GOOD | DROP_CORPSE | DROP_SKELETON |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | 
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR | 
@@ -18683,7 +18904,8 @@ B:CRUSH:HURT:2d8
 B:CRUSH:HURT:2d8
 B:BITE:POISON:2d8
 B:BITE:HURT:1d8
-F:FEMALE | AQUATIC | RES_WATE |
+X:FEMALE
+F:AQUATIC | RES_WATE |
 F:ONLY_ITEM | DROP_90 | DROP_2D2 |
 F:EVIL | NO_CONF | NO_SLEEP | SMART
 S:1_IN_7 |
@@ -18701,7 +18923,8 @@ B:HIT:LOSE_CON:5d10
 B:HIT:LOSE_CON:5d10
 B:CRUSH:HURT:12d12
 B:TOUCH:UN_POWER:3d5
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | CAN_FLY |
 F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | 
@@ -18759,7 +18982,8 @@ W:27:2:300:0:0
 B:TOUCH:COLD:3d5
 B:TOUCH:COLD:3d5
 B:TOUCH:COLD:3d5
-F:FEMALE | IM_COLD | DROP_1D2 | NONLIVING | AURA_COLD |
+X:FEMALE
+F:IM_COLD | DROP_1D2 | NONLIVING | AURA_COLD |
 S:1_IN_5
 S:BR_COLD | BO_COLD | BA_COLD
 D:$This female figure stirs the memory of a tale of two woodcutters sheltering
@@ -18822,7 +19046,8 @@ W:31:4:2500:0:0
 B:HIT:HURT:3d7
 B:HIT:HURT:3d7
 B:HIT:HURT:3d7
-F:UNIQUE | MALE | DROP_SKELETON | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
+X:MALE
+F:UNIQUE | DROP_SKELETON | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
 F:HAS_LITE_2 | HUMAN | DROP_2D2 | ONLY_ITEM | DROP_GOOD | OPEN_DOOR
 F:GOOD | FRIENDLY | CAN_SWIM | CAN_FLY | NO_CONF | NO_SLEEP | TAKE_ITEM
 S:1_IN_4 | BA_FIRE | HASTE | HOLD | CONF | BLIND | INVULNER
@@ -18840,7 +19065,8 @@ B:CLAW:POISON:2d5
 B:CLAW:POISON:2d5
 B:BITE:FIRE:3d4
 B:CRUSH:HURT:8d8
-F:UNIQUE | MALE | DROP_SKELETON | DROP_CORPSE |
+X:MALE
+F:UNIQUE | DROP_SKELETON | DROP_CORPSE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:DROP_1D2 | DROP_2D2 | ONLY_ITEM | DROP_GOOD |
 F:BASH_DOOR | EVIL | CAN_SWIM | CAN_FLY | KILL_ITEM |
@@ -18871,9 +19097,9 @@ F:EVIL | ANIMAL | GOOD | AURA_COLD | NONLIVING | HURT_ROCK |
 F:IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | IM_POIS | HUMAN | ANGEL
 F:RES_LITE | RES_DARK | RES_NETH | RES_WATE | RES_PLAS | RES_SHAR | RES_SOUN |
 F:RES_CHAO | RES_NEXU | RES_DISE | RES_WALL | RES_INER | RES_TIME | RES_GRAV |
-F:RES_VOID | RES_ABYSS | 
+F:RES_VOID | RES_ABYSS | RES_METEOR |
 F:RES_TELE | NO_FEAR | NO_STUN | NO_CONF | NO_SLEEP |
-F:CAN_SWIM | CAN_FLY | UNIQUE2 | WILD_SHORE |
+F:CAN_SWIM | CAN_FLY |  ONLY_ONE | NO_INSTANTLY_DEATH | | WILD_SHORE |
 F:WILD_OCEAN | WILD_WASTE | WILD_WOOD | WILD_VOLCANO | WILD_MOUNTAIN |
 F:WILD_GRASS | WILD_ALL | SELF_LITE_1 | SELF_LITE_2 |
 S:1_IN_3 |
@@ -18882,14 +19108,15 @@ S:BR_ELEC | BR_FIRE | BR_COLD | BR_POIS | BR_NETH | BR_LITE | BR_DARK | BR_CONF
 S:BR_SOUN | BR_CHAO | BR_DISE | BR_NEXU | BR_TIME | BR_INER | BR_GRAV | BR_SHAR |
 S:BR_PLAS | BR_FORC | BR_MANA | BA_NUKE | BR_NUKE | BA_CHAO | BR_DISI | BA_ACID |
 S:BA_ELEC | BA_FIRE | BA_COLD | BA_POIS | BA_NETH | BA_WATE | BA_MANA | BA_DARK |
-S:BA_ABYSS | BA_VOID | BR_ABYSS | BR_VOID | BO_ABYSS | BO_VOID
+S:BA_ABYSS | BA_VOID | BR_ABYSS | BR_VOID | BO_ABYSS | BO_VOID | BA_METEOR | BO_METEOR |
+S:BO_LITE |
 S:DRAIN_MANA | MIND_BLAST| BRAIN_SMASH | CAUSE_1 | CAUSE_2 | CAUSE_3 | CAUSE_4 |
 S:BO_ACID | BO_ELEC | BO_FIRE | BO_COLD | BO_NETH | BO_WATE | BO_MANA |
 S:BO_PLAS | BO_ICEE | MISSILE | BLIND | CONF | SLOW | HOLD | HASTE | HAND_DOOM |
 S:HEAL | INVULNER | BLINK | TPORT | WORLD | TELE_TO | TELE_AWAY | TELE_LEVEL |
 S:PSY_SPEAR | DARKNESS | TRAPS | FORGET | ANIM_DEAD | S_KIN | S_CYBER | S_MONSTER |
 S:S_MONSTERS | S_ANT | S_SPIDER | S_HOUND | S_HYDRA | S_DEMON | S_UNDEAD |
-S:S_DRAGON | S_HI_UNDEAD | S_AMBERITES | S_UNIQUE | BA_LITE
+S:S_DRAGON | S_HI_UNDEAD | S_AMBERITES | S_UNIQUE | BA_LITE | S_DEAD_UNIQUE
 V:133
 D:$You don't know what it is.
 D:それは何が何だか分からない。
@@ -18903,8 +19130,9 @@ B:HIT:HURT:14d14
 B:HIT:HURT:14d14
 B:HIT:HURT:14d14
 B:HIT:HURT:14d14
+X:MALE
 F:DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
-F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | MALE | HUMAN |
+F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | HUMAN |
 F:REFLECTING | SMART | REGENERATE | OPEN_DOOR |
 F:IM_COLD | IM_FIRE | IM_ELEC | NO_CONF | NO_STUN |
 F:NO_SLEEP | RES_TELE | RES_NETH | CAN_FLY | POWERFUL |
@@ -18925,7 +19153,8 @@ B:HIT:BLIND:8d8
 B:HIT:CONFUSE:8d8
 B:TOUCH:UN_BONUS:6d6
 B:TOUCH:UN_BONUS:6d6
-F:UNIQUE | MALE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
+X:MALE
+F:UNIQUE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_3D2 | DROP_GOOD | CAN_SWIM |
 F:GOOD | EVIL | REFLECTING | SMART | REGENERATE | OPEN_DOOR | SPEAK_ALL |
 F:IM_COLD | IM_FIRE | IM_ELEC | IM_ACID | IM_POIS | NO_CONF | NO_STUN |
@@ -18948,7 +19177,8 @@ B:HIT:BLIND:10d13
 B:HIT:CONFUSE:10d13
 B:HIT:HURT:13d13
 B:HIT:HURT:13d13
-F:UNIQUE | MALE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
+X:MALE
+F:UNIQUE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_3D2 | DROP_4D2 | DROP_GOOD |
 F:REFLECTING | SMART | REGENERATE | OPEN_DOOR | SPEAK_ALL |
 F:EVIL | IM_COLD | IM_FIRE | IM_ELEC | NO_CONF | NO_STUN |
@@ -18973,7 +19203,8 @@ B:HIT:BLIND:8d8
 B:HIT:CONFUSE:8d8
 B:TOUCH:DR_MANA:4d10
 B:TOUCH:UN_POWER
-F:UNIQUE | MALE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
+X:MALE
+F:UNIQUE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | SPEAK_ALL |
 F:REFLECTING | SMART | REGENERATE | OPEN_DOOR |
 F:EVIL | IM_COLD | IM_FIRE | IM_ELEC | NO_CONF | NO_STUN |
@@ -18996,7 +19227,8 @@ B:HIT:HURT:13d13
 B:HIT:HURT:13d13
 B:HIT:HURT:13d13
 B:HIT:HURT:13d13
-F:UNIQUE | MALE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
+X:MALE
+F:UNIQUE | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | SPEAK_ALL |
 F:REFLECTING | SMART | REGENERATE | OPEN_DOOR |
 F:EVIL | IM_COLD | IM_FIRE | IM_ELEC | NO_CONF | NO_STUN |
@@ -19040,7 +19272,8 @@ B:PUNCH:HURT:15d15
 B:PUNCH:HURT:15d15
 B:PUNCH:TERRIFY:30d1
 B:KICK:SUPERHURT:15d15
-F:UNIQUE | MALE | SPEAK_ALL | SMART | REFLECTING | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | SMART | REFLECTING | HAS_LITE_2 |
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP |
 F:DROP_2D2 | DROP_1D2 | DROP_GOOD | ONLY_ITEM | CAN_SWIM |
@@ -19061,7 +19294,8 @@ B:PUNCH:HURT:10d10
 B:PUNCH:HURT:10d10
 B:KICK:SHATTER:16d10
 B:KICK:SHATTER:16d10
-F:UNIQUE | MALE | DROP_CORPSE | 
+X:MALE
+F:UNIQUE | DROP_CORPSE | 
 F:NONLIVING | NO_FEAR | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC |
 F:KILL_BODY | IM_FIRE | IM_POIS |
 F:NO_STUN | REGENERATE | NO_CONF | NO_SLEEP | CAN_SWIM |
@@ -19081,7 +19315,8 @@ W:28:1:240:6000:699
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:PREVENT_SUDDEN_MAGIC | DROP_1D2 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:GOOD
@@ -19100,7 +19335,8 @@ B:HIT:HURT:10d10
 B:HIT:HURT:5d5
 B:TOUCH:EXP_80
 B:WAIL:TERRIFY
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | 
 F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD | 
 F:COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
@@ -19189,7 +19425,7 @@ F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | RES_LITE |
 F:NO_CONF | NO_SLEEP | NO_FEAR | CAN_FLY | ANGEL
 S:1_IN_3 | 
 S:TELE_TO | BLIND | SCARE | CAUSE_4 | BO_MANA | PSY_SPEAR | INVULNER
-S:S_ANGEL | S_DRAGON | BA_LITE | HEAL | DISPEL
+S:S_ANGEL | S_DRAGON | BA_LITE | HEAL | DISPEL | BO_LITE
 D:$Never a more heavenly being have you seen.  The very holiness of its 
 D:$presence makes you deeply respect it.  Few creatures can match the powers 
 D:$of a Solar; fewer still live to tell the tale after attacking one.
@@ -19253,7 +19489,8 @@ W:25:3:500:0:0
 B:HIT:HURT:5d10
 B:HIT:HURT:5d10
 B:CRUSH:SUPERHURT:30d2
-F:UNIQUE | DROP_CORPSE | FORCE_MAXHP | SPEAK_ALL | HUMAN | MALE |
+X:MALE
+F:UNIQUE | DROP_CORPSE | FORCE_MAXHP | SPEAK_ALL | HUMAN | |
 F:EVIL | ONLY_ITEM | DROP_1D2 | DROP_60 | DROP_GOOD |
 F:NO_SLEEP | NO_CONF | BASH_DOOR
 
@@ -19266,7 +19503,8 @@ B:HIT:POISON:3d6
 B:HIT:POISON:3d6
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_ITEM
-F:UNIQUE | DROP_CORPSE | FORCE_MAXHP | SPEAK_ALL | HUMAN | MALE |
+X:MALE
+F:UNIQUE | DROP_CORPSE | FORCE_MAXHP | SPEAK_ALL | HUMAN | |
 F:EVIL | ONLY_ITEM | DROP_2D2 | DROP_GOOD |
 F:NO_SLEEP | NO_CONF | OPEN_DOOR | MOVE_BODY |
 V:75
@@ -19282,7 +19520,8 @@ B:HIT:SUPERHURT:12d12
 B:HIT:SUPERHURT:12d12
 B:HIT:UN_BONUS:10d4
 B:TOUCH:UN_POWER
-F:UNIQUE | FORCE_MAXHP | EVIL | GOOD | PREVENT_SUDDEN_MAGIC | SPEAK_ALL | MALE |
+X:MALE
+F:UNIQUE | FORCE_MAXHP | EVIL | GOOD | PREVENT_SUDDEN_MAGIC | SPEAK_ALL | |
 F:ONLY_ITEM | DROP_3D2 | DROP_2D2 | DROP_GOOD | HAS_LITE_2 |
 F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS |
 F:RES_WATE | RES_NETH | RES_DISE | HUMAN |
@@ -19493,7 +19732,8 @@ B:PUNCH:HURT:4d12
 B:PUNCH:HURT:5d12
 B:PUNCH:BLIND:20d1
 B:KICK:HURT:8d8
-F:UNIQUE | MALE | SPEAK_ALL | REFLECTING | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | REFLECTING | HAS_LITE_2 | HUMAN |
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | MOVE_BODY | TAKE_ITEM |
 F:DROP_1D2 | DROP_90 | DROP_GOOD | ONLY_ITEM | CAN_SWIM |
@@ -19543,7 +19783,8 @@ W:31:4:2500:0:0
 B:HIT:HURT:3d7
 B:HIT:HURT:3d7
 B:HIT:HURT:3d7
-F:UNIQUE | MALE | DROP_SKELETON | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
+X:MALE
+F:UNIQUE | DROP_SKELETON | DROP_CORPSE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP
 F:HAS_LITE_2 | HUMAN | DROP_2D2 | ONLY_ITEM | DROP_GOOD | OPEN_DOOR
 F:GOOD | FRIENDLY | CAN_SWIM | CAN_FLY | NO_CONF | NO_SLEEP | TAKE_ITEM
 S:1_IN_4 | BA_ELEC | HASTE | HOLD | CONF | BLIND | INVULNER
@@ -19559,7 +19800,8 @@ B:SHOW:CONFUSE
 B:SHOW:CONFUSE
 B:HIT:HURT:4d5
 B:CRUSH:HURT:20d2
-F:UNIQUE | MALE | DROP_SKELETON | DROP_CORPSE | HUMAN |
+X:MALE
+F:UNIQUE | DROP_SKELETON | DROP_CORPSE | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HAS_LITE_2 |
 F:DROP_2D2 | ONLY_GOLD |
 F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM | MOVE_BODY | RES_SOUN
@@ -19680,7 +19922,8 @@ B:HIT:HURT:8d15
 B:HIT:HURT:8d15
 B:HIT:SUPERHURT:8d15
 B:HIT:SUPERHURT:8d15
-F:UNIQUE | MALE | FORCE_MAXHP | DROP_60 | DROP_GOOD | HUMAN |
+X:MALE
+F:UNIQUE | FORCE_MAXHP | DROP_60 | DROP_GOOD | HUMAN |
 F:DROP_1D2 | OPEN_DOOR | BASH_DOOR | SMART | POWERFUL | IM_FIRE |
 F:TAKE_ITEM | SPEAK_ALL | EVIL | NO_FEAR | NO_CONF | NO_SLEEP | 
 F:CAN_SWIM | DROP_CORPSE | AURA_FIRE | HAS_LITE_2 |
@@ -19697,7 +19940,8 @@ B:HIT:HURT:8d8
 B:HIT:HURT:8d8
 B:HIT:SUPERHURT:8d8
 B:HIT:SUPERHURT:8d8
-F:UNIQUE | MALE | FORCE_MAXHP | DROP_60 | DROP_GOOD | EVIL | HUMAN |
+X:MALE
+F:UNIQUE | FORCE_MAXHP | DROP_60 | DROP_GOOD | EVIL | HUMAN |
 F:DROP_1D2 | OPEN_DOOR | BASH_DOOR | SMART | POWERFUL | IM_FIRE |
 F:TAKE_ITEM | SPEAK_ALL | NO_FEAR | NO_CONF | NO_SLEEP | 
 F:CAN_SWIM | DROP_CORPSE | AURA_FIRE | HAS_LITE_2 |
@@ -19734,7 +19978,8 @@ B:GAZE:PARALYZE
 B:HIT:HURT:5d12
 B:HIT:HURT:5d12
 B:HIT:HURT:5d12
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | MOVE_BODY | DROP_CORPSE
 F:ONLY_ITEM | DROP_3D2 | DROP_GOOD |
 F:SMART | OPEN_DOOR | BASH_DOOR |
@@ -19755,7 +20000,8 @@ B:HIT:LOSE_WIS:4d11
 B:HIT:LOSE_INT:4d11
 B:HIT:SHATTER:10d10
 B:HIT:SUPERHURT:10d10
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GOOD |
 F:SMART | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY |
@@ -19778,8 +20024,9 @@ B:HIT:HURT:4d12
 B:HIT:HURT:4d12
 B:HIT:HURT:4d12
 B:HIT:HURT:4d12
+X:MALE
 F:HUMAN |
-F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | UNIQUE | SPEAK_ALL | HAS_LITE_2 | MALE |
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | UNIQUE | SPEAK_ALL | HAS_LITE_2 | |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | DROP_SKELETON | DROP_CORPSE
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | MOVE_BODY
 S:1_IN_10 |
@@ -19800,7 +20047,8 @@ B:HIT:HURT:10d11
 B:HIT:HURT:10d11
 B:HIT:HURT:10d11
 B:HIT:HURT:10d11
-F:UNIQUE | MALE | SPEAK_ALL | FORCE_MAXHP | ESCORT | 
+X:MALE
+F:UNIQUE | SPEAK_ALL | FORCE_MAXHP | ESCORT | 
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | DROP_CORPSE |
 F:OPEN_DOOR | BASH_DOOR | CAN_SWIM | AURA_ELEC |
 F:EVIL | GIANT | IM_POIS | IM_FIRE | IM_ELEC
@@ -19914,7 +20162,8 @@ I:110:12d16:20:32:40
 W:17:3:60:0:0
 B:HIT:HURT:2d5
 B:HIT:HURT:2d5
-F:MALE | EVIL | PREVENT_SUDDEN_MAGIC | DROP_1D2 | ANIMAL |
+X:MALE
+F:EVIL | PREVENT_SUDDEN_MAGIC | DROP_1D2 | ANIMAL |
 F:SMART | OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 S:1_IN_3 |
 S:SCARE | CAUSE_2 | S_MONSTER
@@ -20028,7 +20277,8 @@ B:CLAW:HURT:7d10
 B:CLAW:HURT:7d10
 B:BITE:POISON:5d10
 B:BITE:POISON:5d10
-F:UNIQUE | MALE | SPEAK_ALL | DROP_CORPSE | WILD_WOOD |
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE | WILD_WOOD |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RAND_25 | GOOD | FRIENDLY | 
 F:SMART | OPEN_DOOR | BASH_DOOR | MOVE_BODY | RIDING |
 F:ANIMAL | IM_FIRE | IM_POIS | NO_CONF | NO_SLEEP
@@ -20079,8 +20329,9 @@ W:22:6:120:0:0
 B:CLAW:HURT:2d6
 B:BITE:HURT:2d6
 B:WAIL:TERRIFY
+X:FEMALE
 F:ESCORTS | FORCE_MAXHP | IM_COLD | IM_ACID | ANIMAL |
-F:SMART | ESCORT | FEMALE | 
+F:SMART | ESCORT | 
 F:OPEN_DOOR | BASH_DOOR | 
 F:NO_FEAR
 S:1_IN_5 | 
@@ -20099,7 +20350,8 @@ B:HIT:HURT:3d5
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
 B:HIT:HURT:3d5
-F:UNIQUE | MALE | MOVE_BODY | SMART | DROP_CORPSE | DROP_SKELETON |
+X:MALE
+F:UNIQUE | MOVE_BODY | SMART | DROP_CORPSE | DROP_SKELETON |
 F:FORCE_MAXHP | PREVENT_SUDDEN_MAGIC | SPEAK_ALL |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | 
 F:OPEN_DOOR | BASH_DOOR | 
@@ -20164,8 +20416,9 @@ B:CLAW:HURT:6d12
 B:CLAW:HURT:8d12
 B:CLAW:HURT:8d12
 B:BITE:HURT:10d14
+X:MALE
 F:ATTR_MULTI | SPEAK_ALL | SELF_LITE_2 |
-F:UNIQUE | MALE | CAN_FLY | DROP_CORPSE
+F:UNIQUE | CAN_FLY | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ESCORT | 
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_4D2 | DROP_GREAT | 
@@ -20194,8 +20447,9 @@ I:115:40d15:20:80:0
 W:30:255:500:0:0
 B:HIT:SUPERHURT:4d8
 B:HIT:SUPERHURT:4d8
-F:MALE | DROP_CORPSE | DROP_SKELETON | FORCE_MAXHP | HAS_LITE_2 | HUMAN |
-F:OPEN_DOOR | BASH_DOOR | NO_FEAR | UNIQUE2
+X:MALE
+F:DROP_CORPSE | DROP_SKELETON | FORCE_MAXHP | HAS_LITE_2 | HUMAN |
+F:OPEN_DOOR | BASH_DOOR | NO_FEAR | ONLY_ONE | NO_INSTANTLY_DEATH
 D:$He is always traveling together with
 D:$ Mitsukuni of the Yellow Gate, Grand Duke of Mito.
 D:ご老公を助けて旅から旅へ。とんだ爺に仕えたもんだ。
@@ -20207,8 +20461,9 @@ I:115:40d15:20:80:0
 W:30:255:500:0:0
 B:HIT:SUPERHURT:4d8
 B:HIT:SUPERHURT:4d8
-F:MALE | DROP_CORPSE | DROP_SKELETON | FORCE_MAXHP | HAS_LITE_2 | HUMAN |
-F:OPEN_DOOR | BASH_DOOR | NO_FEAR | UNIQUE2
+X:MALE
+F:DROP_CORPSE | DROP_SKELETON | FORCE_MAXHP | HAS_LITE_2 | HUMAN |
+F:OPEN_DOOR | BASH_DOOR | NO_FEAR | ONLY_ONE | NO_INSTANTLY_DEATH
 D:$He is always traveling together with
 D:$ Mitsukuni of the Yellow Gate, Grand Duke of Mito.
 D:ご老公を助けて旅から旅へ。とんだ爺に仕えたもんだ。
@@ -20222,7 +20477,8 @@ B:TOUCH:EAT_FOOD:1d1
 B:TOUCH:EAT_FOOD:1d1
 B:TOUCH:EAT_FOOD:1d1
 B:TOUCH:EAT_FOOD:1d1
-F:UNIQUE | MALE | CAN_SWIM | CAN_FLY |
+X:MALE
+F:UNIQUE | CAN_SWIM | CAN_FLY |
 F:RAND_50 | RAND_25 |
 F:FORCE_MAXHP | SPEAK_ALL |
 F:ONLY_ITEM | DROP_90 | DROP_GOOD |
@@ -20241,7 +20497,8 @@ W:35:3:1800:0:0
 B:HIT:HURT:4d5
 B:HIT:HURT:4d5
 B:HIT:HURT:4d5
-F:UNIQUE | MALE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE | HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HAS_LITE_1 |
 F:DROP_1D2 | ONLY_ITEM | DROP_GOOD |
 F:OPEN_DOOR | GOOD | CAN_SWIM |
@@ -20266,7 +20523,8 @@ B:HIT:UN_BONUS:6d6
 B:HIT:UN_BONUS:6d6
 B:HIT:HURT:4d5
 B:HIT:HURT:4d5
-F:UNIQUE | MALE | SPEAK_ALL | HAS_LITE_2 |
+X:MALE
+F:UNIQUE | SPEAK_ALL | HAS_LITE_2 |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | DROP_CORPSE | DROP_SKELETON 
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_GOOD | HUMAN |
 F:OPEN_DOOR | BASH_DOOR | 
@@ -20291,7 +20549,8 @@ W:40:3:500:0:0
 B:SHOOT:HURT:9d6
 B:HIT:HURT:10d8
 B:HIT:HURT:10d8
-F:MALE | FRIENDS | OPEN_DOOR | BASH_DOOR |
+X:MALE
+F:FRIENDS | OPEN_DOOR | BASH_DOOR |
 F:ONLY_ITEM | DROP_1D2 | GOOD | DROP_SKELETON | DROP_CORPSE | SMART |
 F:IM_ACID | IM_COLD | RES_WATE | RES_NETH |
 S:1_IN_2 |
@@ -20319,7 +20578,8 @@ W:36:2:700:2250:1179
 B:HIT:HURT:2d5
 B:HIT:HURT:2d5
 B:HIT:HURT:2d4
-F:HUMAN | MALE | EVIL | DROP_CORPSE | DROP_SKELETON | HAS_LITE_2
+X:MALE
+F:HUMAN | EVIL | DROP_CORPSE | DROP_SKELETON | HAS_LITE_2
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | ONLY_ITEM | DROP_1D2
 F:SMART | OPEN_DOOR | BASH_DOOR
 S:1_IN_4 | TPORT | HOLD | S_DEMON
@@ -20335,7 +20595,8 @@ B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:BITE:EXP_40:2d4
 B:WAIL:TERRIFY
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | 
 F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
@@ -20358,7 +20619,7 @@ W:50:100:1:0:0
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_ITEM
 F:FORCE_MAXHP | PREVENT_SUDDEN_MAGIC |
-F:CAN_FLY | UNIQUE2 | ANGEL
+F:CAN_FLY | ONLY_ONE | NO_INSTANTLY_DEATH | ANGEL
 F:TAKE_ITEM | OPEN_DOOR |
 F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS | NO_CONF | NO_SLEEP
 S:1_IN_3 | 
@@ -20374,7 +20635,7 @@ I:130:30d10:30:50:255
 W:30:30:1:10000:1010
 B:TOUCH:EAT_GOLD
 F:FORCE_MAXHP | PREVENT_SUDDEN_MAGIC |
-F:CAN_FLY | UNIQUE2 | ANGEL
+F:CAN_FLY | ONLY_ONE | NO_INSTANTLY_DEATH | ANGEL
 F:TAKE_ITEM | OPEN_DOOR |
 F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS | NO_CONF | NO_SLEEP
 S:1_IN_3 | 
@@ -20409,7 +20670,8 @@ I:150:90d10:70:150:4
 W:38:4:4000:0:0
 B:HIT:HURT:8d4
 B:KICK:HURT:8d4
-F:MALE | FORCE_MAXHP | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:FORCE_MAXHP | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR | HAS_LITE_2 | HUMAN |
 F:RES_TELE | RAND_50 | ESCORT | IM_FIRE |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | UNIQUE |
@@ -20430,7 +20692,8 @@ B:KICK:HURT:18d2
 B:KICK:HURT:18d2
 B:KICK:HURT:30d1
 B:CRUSH:FIRE:8d8
-F:MALE | FORCE_MAXHP | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
+X:MALE
+F:FORCE_MAXHP | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
 F:NO_CONF | NO_SLEEP | HUMAN |
 F:RES_TELE |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | UNIQUE |
@@ -20489,7 +20752,8 @@ W:69:2:30000:0:0
 B:PUNCH:HURT:16d16
 B:PUNCH:HURT:16d16
 B:PUNCH:SUPERHURT:16d16
-F:UNIQUE | MALE | SPEAK_ALL | SMART | REFLECTING | HAS_LITE_2 | HUMAN
+X:MALE
+F:UNIQUE | SPEAK_ALL | SMART | REFLECTING | HAS_LITE_2 | HUMAN
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP
 F:DROP_2D2 | DROP_1D2 | DROP_GOOD | ONLY_ITEM | CAN_SWIM
@@ -20551,7 +20815,8 @@ B:HIT:HURT:5d6
 B:HIT:HURT:5d6
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_ITEM
-F:UNIQUE | DROP_CORPSE | FORCE_MAXHP | HUMAN | FEMALE |
+X:FEMALE
+F:UNIQUE | DROP_CORPSE | FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_GREAT | FRIENDLY | CAN_SWIM
 F:NO_SLEEP | NO_CONF | OPEN_DOOR | MOVE_BODY
 S:1_IN_4 |
@@ -20575,7 +20840,8 @@ I:125:25d100:30:125:15
 W:50:3:13500:0:0
 B:PUNCH:HURT:10d8
 B:HIT:SHATTER:10d10
-F:UNIQUE | MALE | SPEAK_ALL | RES_TELE
+X:MALE
+F:UNIQUE | SPEAK_ALL | RES_TELE
 F:DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | KILL_WALL | HUMAN |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
@@ -20610,7 +20876,8 @@ B:HIT:EAT_ITEM:5d5
 B:HIT:EAT_ITEM:5d5
 B:HIT:EAT_GOLD:5d5
 B:HIT:EAT_GOLD:5d5
-F:MALE | DROP_2D2 | HUMAN |
+X:MALE
+F:DROP_2D2 | HUMAN |
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
 F:EVIL |
 S:1_IN_2 |
@@ -20630,7 +20897,8 @@ B:WAIL:LOSE_ALL
 B:TOUCH:UN_POWER
 B:HIT:EXP_80:8d12
 B:HIT:EXP_80:8d12
-F:UNIQUE | MALE | SMART |
+X:MALE
+F:UNIQUE | SMART |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:ONLY_GOLD | DROP_3D2 | DROP_4D2 |
 F:COLD_BLOOD | PASS_WALL | OPEN_DOOR | BASH_DOOR | MOVE_BODY |
@@ -20654,7 +20922,8 @@ B:HIT:HURT:6d8
 B:HIT:HURT:6d8
 B:HIT:HURT:6d8
 B:TOUCH:DR_MANA:6d8
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP |
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD |
 F:SMART | OPEN_DOOR | BASH_DOOR | TAKE_ITEM |
@@ -20679,7 +20948,8 @@ B:CLAW:HURT:3d6
 B:CLAW:HURT:3d6
 B:BITE:HURT:3d10
 B:BITE:HURT:3d10
-F:MALE | ESCORT
+X:MALE
+F:ESCORT
 F:BASH_DOOR | FORCE_MAXHP | UNIQUE | DROP_CORPSE
 F:ANIMAL | EVIL | WILD_WOOD | WILD_MOUNTAIN | NO_SLEEP | NO_FEAR
 D:$He is king of the mad bears.  He has built his stronghold at Hutago
@@ -20722,7 +20992,8 @@ B:HIT:HURT:1d15
 B:HIT:HURT:1d15
 B:HIT:HURT:1d15
 B:HIT:HURT:1d15
-F:UNIQUE | MALE | EVIL | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | EVIL | HAS_LITE_2 | HUMAN |
 F:FORCE_MAXHP | SPEAK_ALL | WILD_ALL | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | ESCORT |
 F:OPEN_DOOR | BASH_DOOR
@@ -20764,7 +21035,8 @@ I:120:24d100:30:100:5
 W:51:3:16000:0:0
 B:INSULT:FLAVOR
 B:INSULT:FLAVOR
-F:UNIQUE | FEMALE | SPEAK_ALL | DROP_CORPSE
+X:FEMALE
+F:UNIQUE | SPEAK_ALL | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | CAN_SWIM | ELDRITCH_HORROR | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | DROP_GOOD | 
 F:SMART | OPEN_DOOR | BASH_DOOR | SELF_LITE_2 |
@@ -20832,8 +21104,9 @@ E:Trap master
 G:p:b
 I:125:30d10:20:70:0
 W:28:5:240:0:0
+X:MALE
 F:NEVER_BLOW |
-F:MALE | HUMAN | DROP_SKELETON | DROP_CORPSE |
+F:HUMAN | DROP_SKELETON | DROP_CORPSE |
 F:DROP_1D2 | OPEN_DOOR | BASH_DOOR | EVIL |
 S:1_IN_2 |
 S:TRAPS | BLINK
@@ -20849,7 +21122,8 @@ B:HIT:HURT:10d5
 B:HIT:HURT:10d5
 B:HIT:HURT:10d5
 B:HIT:HURT:10d5
-F:MALE | FORCE_MAXHP | HUMAN |
+X:MALE
+F:FORCE_MAXHP | HUMAN |
 F:ONLY_ITEM | DROP_90 | DROP_2D2 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | SMART |
 F:GOOD | NO_SLEEP | NO_FEAR | HAS_LITE_1 |
@@ -20873,7 +21147,8 @@ I:110:15d11:20:40:40
 W:20:1:55:800:938
 B:HIT:HURT:4d5
 B:HIT:HURT:4d5
-F:MALE | GOOD | HUMAN |
+X:MALE
+F:GOOD | HUMAN |
 F:DROP_1D2 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | 
 S:1_IN_4 | 
@@ -20890,7 +21165,8 @@ W:20:1:55:0:0
 B:SHOOT:HURT:5d6
 B:HIT:HURT:5d4
 B:HIT:HURT:5d4
-F:MALE | HUMAN |
+X:MALE
+F:HUMAN |
 F:DROP_1D2 | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR 
 S:1_IN_4 | 
@@ -21015,7 +21291,8 @@ B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
-F:UNIQUE | MALE | HUMAN |
+X:MALE
+F:UNIQUE | HUMAN |
 F:FORCE_MAXHP | HAS_LITE_1 | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | 
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | 
@@ -21032,7 +21309,8 @@ B:KICK:SUPERHURT:8d1
 B:HIT:SUPERHURT:8d1
 B:KICK:SUPERHURT:8d4
 B:HIT:SUPERHURT:8d1
-F:MALE | DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_ELEC | HAS_LITE_2 |
+X:MALE
+F:DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_ELEC | HAS_LITE_2 |
 F:IM_FIRE | IM_COLD | IM_POIS | IM_ACID | NO_FEAR | NO_CONF | NO_SLEEP | 
 F:HUMAN | DROP_CORPSE | DROP_SKELETON
 S:1_IN_9 | HASTE
@@ -21082,7 +21360,8 @@ B:HIT:SHATTER:13d13
 B:HIT:CONFUSE:13d13
 B:HIT:SHATTER:13d13
 B:HIT:CONFUSE:13d13
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | 
 F:ONLY_ITEM | DROP_GOOD | DROP_4D2 | KILL_BODY | KILL_WALL |
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | DROP_CORPSE | 
@@ -21102,7 +21381,8 @@ B:HIT:CONFUSE:12d12
 B:HIT:CONFUSE:12d12
 B:HIT:CONFUSE:12d12
 B:HIT:CONFUSE:12d12
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | MOVE_BODY | 
 F:ONLY_ITEM | DROP_4D2 | DROP_3D2 | DROP_GREAT | 
 F:SMART | TAKE_ITEM | BASH_DOOR | HAS_LITE_2 |
@@ -21140,7 +21420,8 @@ G:p:y
 I:110:6d8:20:10:5
 W:4:1:18:600:1055
 B:HIT:HURT:1d9
-F:DROP_60 | WILD_ALL | HUMAN | MALE |
+X:MALE
+F:DROP_60 | WILD_ALL | HUMAN | |
 F:OPEN_DOOR | DROP_SKELETON | DROP_CORPSE | 
 F:HAS_LITE_1 | NO_CONF | NO_SLEEP
 S:1_IN_12 |
@@ -21154,7 +21435,8 @@ G:p:y
 I:110:6d8:20:10:5
 W:8:1:18:600:1055
 B:HIT:HURT:1d6
-F:DROP_60 | WILD_ALL | FRIENDS | HUMAN | MALE |
+X:MALE
+F:DROP_60 | WILD_ALL | FRIENDS | HUMAN | |
 F:OPEN_DOOR | DROP_SKELETON | DROP_CORPSE | 
 F:HAS_LITE_1 | NO_CONF | NO_SLEEP
 S:1_IN_12 |
@@ -21169,7 +21451,7 @@ I:110:12d11:20:30:20
 W:22:2:50:5000:1056
 B:HIT:HURT:3d4
 B:HIT:HURT:3d4
-F:MALE | 
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | DROP_90 | WILD_ALL | HUMAN |
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE | 
 F:EVIL | HAS_LITE_2
@@ -21187,7 +21469,8 @@ W:40:2:2000:0:0
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
 B:HIT:HURT:5d5
-F:MALE | ONLY_ITEM | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_4D2 |
+X:MALE
+F:ONLY_ITEM | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_4D2 |
 F:SMART | BASH_DOOR | TAKE_ITEM | MOVE_BODY | HUMAN |
 F:EVIL | IM_FIRE | IM_ELEC | IM_POIS |
 F:NO_CONF | NO_SLEEP | NO_STUN | NO_FEAR
@@ -21245,7 +21528,8 @@ G:y:w
 I:109:10d20:50:15:4
 W:0:255:0:0:0
 B:HIT:EAT_GOLD:1d3
-F:UNIQUE | MALE | SPEAK_ALL | UNDEAD |
+X:MALE
+F:UNIQUE | SPEAK_ALL | UNDEAD |
 F:FORCE_MAXHP | DROP_CORPSE | WILD_TOWN | WILD_ONLY |
 F:OPEN_DOOR | BASH_DOOR | 
 F:RES_NETH | NO_CONF | NO_SLEEP
@@ -21260,7 +21544,8 @@ G:T:G
 I:109:35d20:50:15:4
 W:0:255:0:0:0
 B:HIT:HURT:1d3
-F:UNIQUE | MALE | GIANT | SPEAK_ALL | HUMAN |
+X:MALE
+F:UNIQUE | GIANT | SPEAK_ALL | HUMAN |
 F:FORCE_MAXHP | DROP_CORPSE | WILD_TOWN | WILD_ONLY
 F:OPEN_DOOR | BASH_DOOR | HAS_LITE_1 |
 F:NO_CONF | NO_SLEEP
@@ -21276,7 +21561,8 @@ B:SHOW:LOSE_INT
 B:SHOW:LOSE_WIS
 B:CHARGE:EAT_GOLD
 B:CHARGE:EAT_GOLD
-F:EVIL | MALE | SPEAK_ALL | SMART | RES_TELE | CAN_SWIM | DROP_CORPSE |
+X:MALE
+F:EVIL | SPEAK_ALL | SMART | RES_TELE | CAN_SWIM | DROP_CORPSE |
 F:ANIMAL | IM_POIS | NO_CONF | NO_SLEEP | FORCE_MAXHP | UNIQUE | PREVENT_SUDDEN_MAGIC |
 F:RES_CHAO
 S:1_IN_3
@@ -21294,7 +21580,8 @@ B:HIT:HURT:9d1
 B:HIT:HURT:6d5
 B:HIT:HURT:25d1
 B:HIT:HURT:30d1
-F:UNIQUE | MALE | WEIRD_MIND | SPEAK_ALL |
+X:MALE
+F:UNIQUE | WEIRD_MIND | SPEAK_ALL |
 F:FORCE_MAXHP | WILD_ALL | DROP_CORPSE
 F:OPEN_DOOR | BASH_DOOR | 
 F:TROLL | IM_COLD | IM_POIS
@@ -21312,7 +21599,8 @@ B:STING:HURT:1d5
 B:STING:HURT:1d5
 B:BITE:HURT:1d5
 B:BITE:LOSE_CHR:1d5
-F:UNIQUE | MALE | SPEAK_ALL | HUMAN |
+X:MALE
+F:UNIQUE | SPEAK_ALL | HUMAN |
 F:RAND_50 | RAND_25 | FORCE_MAXHP | 
 F:DROP_CORPSE | CAN_FLY | WEIRD_MIND |
 F:ANIMAL |
@@ -21412,7 +21700,8 @@ B:SHOOT:HURT:16d6
 B:SLASH:EXP_VAMP:6d8
 B:SLASH:EXP_VAMP:6d8
 B:TOUCH:EAT_ITEM
-F:UNIQUE | MALE | CAN_FLY | RAND_25 | RAND_50
+X:MALE
+F:UNIQUE | CAN_FLY | RAND_25 | RAND_50
 F:FORCE_MAXHP | SPEAK_ALL | SMART | REGENERATE |
 F:NO_CONF | NO_STUN |
 F:IM_ACID | IM_ELEC | IM_FIRE | IM_POIS | IM_COLD |
@@ -21439,7 +21728,8 @@ W:55:7:15000:0:0
 B:HIT:SHATTER:12d12
 B:HIT:SHATTER:12d12
 B:HIT:SHATTER:12d12
-F:UNIQUE | MALE | SPEAK_ALL
+X:MALE
+F:UNIQUE | SPEAK_ALL
 F:DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | 
 F:FORCE_MAXHP | HUMAN | EVIL | GOOD | KILL_BODY |
@@ -21491,7 +21781,8 @@ B:HIT:HURT:1d12
 B:HIT:HURT:1d12
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:FORCE_MAXHP | WILD_ALL |
 F:ESCORT | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD
@@ -21510,7 +21801,8 @@ B:HIT:HURT:1d15
 B:HIT:HURT:1d15
 B:HIT:HURT:1d15
 B:HIT:HURT:1d15
-F:UNIQUE | MALE | EVIL | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | EVIL | HAS_LITE_2 | HUMAN |
 F:FORCE_MAXHP | SPEAK_ALL | WILD_ALL | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | 
 F:OPEN_DOOR | BASH_DOOR
@@ -21525,7 +21817,8 @@ W:14:2:150:0:0
 B:HIT:HURT:1d12
 B:HIT:HURT:1d12
 B:HIT:FIRE:1d15
-F:UNIQUE | FEMALE | EVIL | HAS_LITE_2 | HUMAN | IM_FIRE |
+X:FEMALE
+F:UNIQUE | EVIL | HAS_LITE_2 | HUMAN | IM_FIRE |
 F:FORCE_MAXHP | SPEAK_ALL | WILD_ALL | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR |
 S:1_IN_9
@@ -21544,7 +21837,8 @@ B:HIT:HURT:1d10
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
-F:UNIQUE | MALE | EVIL | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | EVIL | HAS_LITE_2 | HUMAN |
 F:FORCE_MAXHP | SPEAK_ALL | WILD_ALL | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
 S:1_IN_5 |
@@ -21561,7 +21855,8 @@ W:11:2:150:0:0
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
-F:UNIQUE | MALE | EVIL | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | EVIL | HAS_LITE_2 | HUMAN |
 F:FORCE_MAXHP | SPEAK_ALL | WILD_ALL | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
 S:1_IN_5 |
@@ -21579,7 +21874,8 @@ B:HIT:HURT:1d13
 B:HIT:HURT:1d13
 B:HIT:HURT:1d15
 B:HIT:HURT:1d15
-F:UNIQUE | MALE | EVIL | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | EVIL | HAS_LITE_2 | HUMAN |
 F:FORCE_MAXHP | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR
 S:1_IN_6 |
@@ -21595,7 +21891,8 @@ I:110:35d10:20:60:20
 W:17:2:250:0:0
 B:HIT:HURT:2d20
 B:HIT:HURT:2d20
-F:UNIQUE | MALE | EVIL | HAS_LITE_2 | HUMAN |
+X:MALE
+F:UNIQUE | EVIL | HAS_LITE_2 | HUMAN |
 F:FORCE_MAXHP | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | OPEN_DOOR | BASH_DOOR |
 F:IM_ACID | IM_ELEC | IM_POIS | HURT_FIRE |
@@ -21613,7 +21910,8 @@ B:KICK:CONFUSE:9d9
 B:KICK:CONFUSE:9d9
 B:BUTT:HURT:8d8
 B:BITE:UN_BONUS:7d7
-F:UNIQUE | FEMALE | GOOD | EVIL | NONLIVING | RIDING |
+X:FEMALE
+F:UNIQUE | GOOD | EVIL | NONLIVING | RIDING |
 F:FORCE_MAXHP | OPEN_DOOR | BASH_DOOR | INVISIBLE |
 F:ONLY_ITEM | DROP_GREAT | DROP_2D2 |
 F:SMART | REGENERATE |
@@ -21680,7 +21978,8 @@ B:SHOOT:HURT:5d6
 B:HIT:HURT:1d6
 B:HIT:HURT:1d6
 B:HIT:HURT:1d6
-F:UNIQUE | MALE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | HUMAN |
+X:MALE
+F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_GREAT | WILD_WOOD |
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | EVIL | DROP_SKELETON | DROP_CORPSE
 S:1_IN_4
@@ -21719,7 +22018,8 @@ G:B:v
 I:111:20d20:50:15:4
 W:0:4:0:0:0
 B:HIT:HURT:1d3
-F:ATTR_MULTI | UNIQUE | MALE | ANIMAL | SPEAK_ALL | FRIENDLY
+X:MALE
+F:ATTR_MULTI | UNIQUE | ANIMAL | SPEAK_ALL | FRIENDLY
 F:FORCE_MAXHP | DROP_CORPSE | WILD_TOWN | WILD_ONLY
 F:ONLY_ITEM | DROP_90 | DROP_GOOD | HUMAN | STUPID | EMPTY_MIND
 F:OPEN_DOOR | BASH_DOOR | HAS_LITE_1 |
@@ -21840,7 +22140,8 @@ W:9:3:100:0:0
 B:SHOOT:HURT:1d12
 B:HIT:HURT:1d10
 B:HIT:HURT:1d10
-F:UNIQUE | MALE | SPEAK_ALL |
+X:MALE
+F:UNIQUE | SPEAK_ALL |
 F:FORCE_MAXHP |
 F:ESCORT | ESCORTS | DROP_SKELETON | DROP_CORPSE |
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD | 
@@ -21880,7 +22181,8 @@ B:HIT:HURT:8d6
 B:HIT:HURT:10d5
 B:HIT:HURT:10d5
 B:HIT:HURT:12d10
-F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | RES_CHAO | MALE | HUMAN |
+X:MALE
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | RES_CHAO | HUMAN |
 F:ONLY_ITEM | DROP_1D2 | DROP_2D2 | NO_FEAR | NO_CONF
 F:OPEN_DOOR | BASH_DOOR | 
 F:IM_FIRE | IM_POIS | HAS_LITE_1 |
@@ -21898,7 +22200,8 @@ I:108:80d12:10:110:20
 W:34:4:2000:0:0
 B:HIT:HURT:15d8
 B:HIT:HURT:10d10
-F:IM_POIS | OPEN_DOOR | BASH_DOOR | MALE | FORCE_MAXHP
+X:MALE
+F:IM_POIS | OPEN_DOOR | BASH_DOOR | FORCE_MAXHP
 F:NO_CONF | NO_SLEEP | EVIL | DEMON | HUMAN
 S:1_IN_2 |
 S:BO_FIRE | BA_FIRE
@@ -21930,9 +22233,10 @@ I:115:50d10:25:80:10
 W:54:3:3200:0:0
 B:SHOOT:HURT:20d10
 B:HIT:HURT:2d10
+X:MALE
 F:BASH_DOOR | OPEN_DOOR | FRIENDS | DROP_90 |
 F:IM_FIRE | IM_POIS | NO_SLEEP | NO_CONF
-F:MALE | DROP_CORPSE | DROP_SKELETON
+F:DROP_CORPSE | DROP_SKELETON
 S:1_IN_3 |
 S:SHOOT
 D:$Firearms were not used in Amber since gunpowder does not work there:
@@ -21957,7 +22261,8 @@ B:SHOOT:HURT:2d10
 B:HIT:HURT:2d4
 B:HIT:HURT:2d4
 B:HIT:HURT:2d4
-F:UNIQUE | MALE | 
+X:MALE
+F:UNIQUE |
 F:FORCE_MAXHP | 
 F:ESCORT | ONLY_ITEM | DROP_1D2 | DROP_GOOD | 
 F:OPEN_DOOR | BASH_DOOR | SPEAK_ALL | DROP_SKELETON | DROP_CORPSE
@@ -21983,7 +22288,8 @@ B:SLASH:BLIND:10d10
 B:SLASH:SUPERHURT:17d4
 B:SLASH:SUPERHURT:14d4
 B:SLASH:SUPERHURT:13d4
-F:UNIQUE | MALE | WEIRD_MIND | HUMAN | SPEAK_ALL
+X:MALE
+F:UNIQUE | WEIRD_MIND | HUMAN | SPEAK_ALL
 F:FORCE_MAXHP | WILD_ALL | DROP_CORPSE | KILL_BODY
 F:ONLY_ITEM | DROP_2D2 | DROP_GOOD |
 F:OPEN_DOOR | BASH_DOOR | NO_CONF | NO_FEAR
@@ -22084,8 +22390,9 @@ B:HIT:SUPERHURT:5d4
 B:HIT:SUPERHURT:5d4
 B:HIT:SUPERHURT:5d4
 B:BITE:POISON:9d3
+X:MALE
 F:EVIL | DROP_1D2 | DROP_SKELETON | DROP_CORPSE | PREVENT_SUDDEN_MAGIC
-F:OPEN_DOOR | MALE | WILD_WASTE | WILD_SWAMP | NO_FEAR
+F:OPEN_DOOR | WILD_WASTE | WILD_SWAMP | NO_FEAR
 D:$Walking on two legs, this creature looks like a Skaven, of sorts, but it's
 D:$ larger and more terrible than a Skaven.
 D:それはスケイヴンの亜種と思われるが、より大きくおぞましい二足歩行の怪物だ。
@@ -22144,7 +22451,8 @@ B:PUNCH:HURT:4d12
 B:PUNCH:HURT:4d12
 B:PUNCH:HURT:6d10
 B:KICK:HURT:6d10
-F:UNIQUE | MALE | SPEAK_ALL | GOOD | EVIL | REFLECTING |
+X:MALE
+F:UNIQUE | SPEAK_ALL | GOOD | EVIL | REFLECTING |
 F:FORCE_MAXHP | CAN_FLY | HUMAN |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL | MOVE_BODY | 
@@ -22177,8 +22485,9 @@ B:SLASH:HURT:6d6
 B:SLASH:HURT:6d6
 B:SLASH:HURT:6d6
 B:SLASH:HURT:6d6
+X:FEMALE
 F:FORCE_MAXHP | SMART | NO_FEAR | GOOD | CAN_FLY |
-F:ONLY_ITEM | DROP_2D2 | FEMALE | RES_LITE
+F:ONLY_ITEM | DROP_2D2 | RES_LITE
 F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | 
 F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | 
 F:NO_SLEEP | SELF_LITE_1 | ANGEL
@@ -22213,7 +22522,8 @@ B:PUNCH:HURT:3d3
 B:CLAW:HURT:2d4
 B:SLASH:HURT:2d6
 B:BITE:HURT:1d6
-F:UNIQUE | MALE | DROP_CORPSE | HAS_LITE_1 |
+X:MALE
+F:UNIQUE | DROP_CORPSE | HAS_LITE_1 |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN | DEMON | 
 F:IM_FIRE | IM_ELEC
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD |
@@ -22398,7 +22708,7 @@ W:35:2:600:0:0
 B:SHOOT:HURT:8d4
 B:HIT:HURT:8d4
 B:HIT:FIRE:8d4
-F:MALE | 
+X:MALE
 F:FORCE_MAXHP | FRIENDS | DROP_60 | 
 F:OPEN_DOOR | BASH_DOOR | DROP_SKELETON | DROP_CORPSE
 F:EVIL | ORC | IM_POIS | RES_DARK | IM_FIRE | RES_CHAO
@@ -22420,9 +22730,10 @@ B:SHOOT:HURT:10d10
 B:SLASH:HURT:8d4
 B:KICK:HURT:4d5
 B:SLASH:ELEC:14d4
+X:MALE
 F:UNIQUE | BASH_DOOR | OPEN_DOOR | ESCORT | DROP_90 |
 F:NO_SLEEP | NO_CONF | FORCE_MAXHP | DROP_4D2 | DROP_GOOD |
-F:MALE | DROP_CORPSE | DROP_SKELETON | SPEAK_ALL | HUMAN
+F:DROP_CORPSE | DROP_SKELETON | SPEAK_ALL | HUMAN
 S:1_IN_5 | S_KIN | SHOOT | BO_ELEC
 D:$The leader of this family, worried about the death of his homeland
 D:$ after the death of Isshin Ashina,
@@ -22442,7 +22753,8 @@ B:SLASH:SUPERHURT:15d2
 B:HIT:SUPERHURT:15d2
 B:CRAWL:SUPERHURT:15d2
 B:STING:SUPERHURT:15d2
-F:UNIQUE | FORCE_MAXHP | GOOD | FEMALE | ANGEL
+X:FEMALE
+F:UNIQUE | FORCE_MAXHP | GOOD | ANGEL
 F:IM_FIRE | RES_LITE | RES_GRAV | CAN_FLY
 F:BASH_DOOR | NO_SLEEP | NO_CONF | NO_FEAR
 F:DROP_GREAT | ONLY_ITEM | DROP_1D2
@@ -22649,10 +22961,11 @@ B:SLASH:LOSE_STR:5d5
 B:SLASH:LOSE_WIS:5d5
 B:SLASH:LOSE_DEX:5d5
 B:SLASH:LOSE_ALL:6d8
+X:MALE
 F:UNIQUE | FORCE_MAXHP | ONLY_ITEM | DROP_GREAT | DROP_2D2
 F:DROP_CORPSE | DROP_SKELETON
 F:REGENERATE | ELDRITCH_HORROR | OPEN_DOOR | BASH_DOOR | MOVE_BODY
-F:HUMAN | MALE | SELF_DARK_2 | SMART | POWERFUL
+F:HUMAN | SELF_DARK_2 | SMART | POWERFUL
 F:IM_FIRE | IM_COLD | IM_ELEC | IM_ACID | IM_POIS
 F:NO_FEAR | NO_CONF | NO_SLEEP
 S:1_IN_2 | BA_NETH | BA_WATE | BA_DARK | BA_NUKE | BA_CHAO
@@ -22674,7 +22987,8 @@ I:110:11d11:20:10:25
 W:12:1:48:0:0
 B:BITE:HURT:6d3
 B:BITE:HURT:6d3
-F:MALE | WILD_SWAMP | WILD_WASTE
+X:MALE
+F:WILD_SWAMP | WILD_WASTE
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON
 F:ANIMAL | EVIL | DROP_60 | FRIENDS
 D:$Skaven warriors carelessly wield the power of chaos and slaughter any prey
@@ -22702,7 +23016,8 @@ I:115:20d16:25:35:10
 W:16:2:220:0:0
 B:BITE:HURT:7d3
 B:CRUSH:HURT:7d3
-F:ANIMAL | EVIL | ESCORT | ESCORTS | MALE | UNIQUE | FORCE_MAXHP
+X:MALE
+F:ANIMAL | EVIL | ESCORT | ESCORTS | UNIQUE | FORCE_MAXHP
 F:DROP_GOOD | DROP_60 | DROP_90 | ONLY_ITEM | DROP_CORPSE | DROP_SKELETON
 S:1_IN_8 | CAUSE_2 | MISSILE | SCARE | S_KIN
 D:$It is the head of weasel who works with wisdom.
@@ -22723,7 +23038,8 @@ B:TOUCH:LOSE_ALL:8d7
 B:TOUCH:UN_BONUS:8d7
 B:TOUCH:UN_POWER:8d7
 B:TOUCH:TIME:8d7
-F:QUANTUM | UNIQUE | FEMALE | ATTR_CLEAR | FORCE_MAXHP | RAND_25
+X:FEMALE
+F:QUANTUM | UNIQUE | ATTR_CLEAR | FORCE_MAXHP | RAND_25
 F:ONLY_ITEM | DROP_GREAT | DROP_2D2 | DROP_4D2
 F:DROP_CORPSE | DROP_SKELETON
 F:PREVENT_SUDDEN_MAGIC
@@ -22940,7 +23256,8 @@ G:t:U
 I:109:7d5:5:15:100
 W:3:1:30:0:0
 B:WAIL:HURT:2d5
-F:UNIQUE | FORCE_MAXHP | HUMAN | MALE | EVIL | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:UNIQUE | FORCE_MAXHP | HUMAN | EVIL | DROP_CORPSE | DROP_SKELETON
 F:DROP_90 | ONLY_ITEM | DROP_GOOD
 S:1_IN_12 | BA_FIRE
 D:$This young boy has become a serial arsonist as a way of avoiding his own,
@@ -23174,7 +23491,8 @@ W:14:1:300:0:0
 B:SLASH:HURT:2d13
 B:HIT:HURT:2d15
 B:TOUCH:TERRIFY
-F:UNIQUE | FORCE_MAXHP | HUMAN | MALE | EVIL
+X:MALE
+F:UNIQUE | FORCE_MAXHP | HUMAN | EVIL
 F:DROP_60 | DROP_90 | ONLY_ITEM | DROP_GOOD | SPEAK_DEATH
 S:1_IN_6 | S_KIN
 D:$A man without pride who hunts ogres just for money.
@@ -23187,7 +23505,8 @@ E:Member of Demon Slayer Corps
 G:p:U
 I:110:5d25:10:30:100
 W:11:2:200:0:0
-F:NAZGUL | FORCE_MAXHP | HUMAN | MALE | UNDEAD
+X:MALE
+F:NAZGUL | FORCE_MAXHP | HUMAN | UNDEAD
 F:DROP_60
 B:SHOOT:HURT:6d7
 B:SLASH:HURT:2d10
@@ -23203,7 +23522,8 @@ I:110:15d15:20:30:25
 W:11:1:200:0:0
 B:CLAW:HURT:4d6
 B:BITE:HURT:4d6
-F:UNIQUE | FORCE_MAXHP | MALE | GOOD | ANIMAL
+X:MALE
+F:UNIQUE | FORCE_MAXHP | GOOD | ANIMAL
 F:DROP_60 | DROP_90 | DROP_GOOD | RES_SOUN | NO_STUN
 D:$He is the youngest of three brothers and swings a club.
 D:三兄弟の末っ子で、棍棒を振り回している。
@@ -23215,7 +23535,8 @@ I:110:15d16:20:35:25
 W:12:1:250:0:0
 B:PUNCH:HURT:4d6
 B:KICK:HURT:4d6
-F:UNIQUE | FORCE_MAXHP | MALE | GOOD | ANIMAL
+X:MALE
+F:UNIQUE | FORCE_MAXHP | GOOD | ANIMAL
 F:DROP_60 | DROP_90 | DROP_GOOD | RES_SOUN | NO_STUN
 D:$He is the second son of three brothers and is good at karate.
 D:三兄弟の次男で、空手が得意だ。
@@ -23228,7 +23549,8 @@ W:15:1:320:0:0
 B:SHOOT:HURT:8d7
 B:STING:HURT:5d6
 B:STING:HURT:5d6
-F:UNIQUE | FORCE_MAXHP | MALE | GOOD | ANIMAL
+X:MALE
+F:UNIQUE | FORCE_MAXHP | GOOD | ANIMAL
 F:DROP_90 | DROP_1D2 | DROP_GOOD | RES_SOUN | NO_STUN
 S:1_IN_6 | SHOOT
 D:$He is the eldest son of the three brothers,
@@ -23244,10 +23566,11 @@ B:CRUSH:SUPERHURT:12d15
 B:CRUSH:SUPERHURT:12d15
 B:CRUSH:SUPERHURT:12d15
 B:BITE:POISON:12d15
+X:FEMALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_4D2 | DROP_3D2 | DROP_GREAT | MOVE_BODY
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR | POWERFUL
-F:EVIL | FEMALE | UNIQUE | RES_LITE | RES_TIME | RES_DARK | RES_NETH
+F:EVIL | UNIQUE | RES_LITE | RES_TIME | RES_DARK | RES_NETH
 F:IM_COLD | IM_POIS | IM_ACID | IM_ELEC | IM_FIRE | RES_TELE
 S:1_IN_5 | 
 S:S_MONSTERS | SCARE | BA_DARK | BA_NETH | BR_POIS
@@ -23279,7 +23602,8 @@ B:PUNCH:HURT:12d12
 B:PUNCH:HURT:12d12
 B:CRUSH:SHATTER:16d11
 B:CRUSH:SHATTER:16d11
-F:UNIQUE | FEMALE | RES_TELE | CAN_FLY
+X:FEMALE
+F:UNIQUE | RES_TELE | CAN_FLY
 F:DROP_SKELETON | DROP_CORPSE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | KILL_WALL | DEMON | HUMAN
 F:ONLY_ITEM | DROP_4D2 | DROP_3D2 | DROP_GREAT | MOVE_BODY
@@ -23302,7 +23626,8 @@ B:KICK:SUPERHURT:5d2
 B:HIT:SUPERHURT:5d1
 B:KICK:SUPERHURT:5d5
 B:HIT:SUPERHURT:5d1
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON
 F:DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_ELEC | HAS_LITE_2
 F:IM_FIRE | IM_COLD | IM_POIS | NO_FEAR | NO_CONF | NO_SLEEP
 S:1_IN_6 | BO_ELEC
@@ -23318,7 +23643,8 @@ B:KICK:SUPERHURT:8d1
 B:HIT:SUPERHURT:8d1
 B:KICK:SUPERHURT:8d4
 B:HIT:SUPERHURT:8d1
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON
 F:DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_FIRE | IM_POIS
 F:NO_FEAR | NO_CONF | NO_SLEEP | HAS_LITE_1 | HAS_LITE_2
 S:1_IN_7 | HEAL
@@ -23334,7 +23660,8 @@ B:KICK:SUPERHURT:9d1
 B:HIT:SUPERHURT:9d1
 B:KICK:SUPERHURT:9d4
 B:HIT:SUPERHURT:9d1
-F:MALE | DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_ELEC | HAS_LITE_2 |
+X:MALE
+F:DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_ELEC | HAS_LITE_2 |
 F:IM_FIRE | IM_COLD | IM_POIS | IM_ACID | NO_FEAR | NO_CONF | NO_SLEEP | 
 F:HUMAN | DROP_CORPSE | DROP_SKELETON
 S:1_IN_9 | HASTE
@@ -23350,7 +23677,8 @@ B:KICK:SUPERHURT:7d1
 B:HIT:EXP_10:7d2
 B:KICK:SUPERHURT:7d4
 B:HIT:EXP_10:7d2
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON | DROP_60 | DROP_1D2
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON | DROP_60 | DROP_1D2
 F:OPEN_DOOR | BASH_DOOR | IM_COLD | HAS_LITE_2
 F:IM_POIS | RES_NETH | NO_FEAR | NO_CONF | NO_SLEEP
 S:1_IN_8 | BO_NETH
@@ -23387,7 +23715,8 @@ B:KICK:HURT:18d2
 B:KICK:HURT:18d2
 B:HIT:POISON:18d1
 B:HIT:PARALYZE:18d1
-F:HUMAN | MALE | GOOD | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | GOOD | DROP_CORPSE | DROP_SKELETON
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | ONLY_ITEM | DROP_4D2
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR
 F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP
@@ -23407,7 +23736,8 @@ B:KICK:HURT:20d2
 B:KICK:HURT:20d2
 B:HIT:POISON:20d1
 B:HIT:PARALYZE:20d1
-F:HUMAN | MALE | GOOD | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | GOOD | DROP_CORPSE | DROP_SKELETON
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | ONLY_ITEM | DROP_GOOD | DROP_4D2
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR
 F:IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS | NO_CONF | NO_SLEEP
@@ -23426,7 +23756,8 @@ W:41:2:700:0:0
 B:HIT:HURT:2d6
 B:HIT:HURT:2d6
 B:HIT:HURT:2d5
-F:HUMAN | MALE | EVIL | DROP_CORPSE | DROP_SKELETON | HAS_LITE_2
+X:MALE
+F:HUMAN | EVIL | DROP_CORPSE | DROP_SKELETON | HAS_LITE_2
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | ONLY_ITEM | DROP_1D2
 F:SMART | OPEN_DOOR | BASH_DOOR
 S:1_IN_2 | TPORT | HOLD | S_DEMON
@@ -23547,8 +23878,9 @@ B:GAZE:EXP_40:5d5
 B:GAZE:LOSE_INT:5d6
 B:GAZE:UN_POWER:5d6
 B:GAZE:DR_MANA:5d10
+X:FEMALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | RES_TELE | CAN_FLY |
-F:BASH_DOOR | FEMALE | SMART | DROP_CORPSE |
+F:BASH_DOOR | SMART | DROP_CORPSE |
 F:EVIL | IM_POIS | NO_CONF | NO_SLEEP
 S:1_IN_2 | 
 S:BLIND | CONF | SCARE | DRAIN_MANA | MIND_BLAST | FORGET | 
@@ -23586,10 +23918,11 @@ B:HIT:CONFUSE:12d12
 B:HIT:CONFUSE:12d12
 B:HIT:CONFUSE:12d12
 B:HIT:CONFUSE:12d12
+X:MALE
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | DROP_SKELETON | DROP_CORPSE
 F:ONLY_ITEM | DROP_4D2 | DROP_GOOD | MOVE_BODY |
 F:SMART | TAKE_ITEM | OPEN_DOOR | BASH_DOOR |
-F:EVIL | GIANT | MALE
+F:EVIL | GIANT |
 S:1_IN_5 | HEAL | TELE_TO | S_MONSTERS
 D:$This giant is rampaging with a physical structure that
 D:$ can reach ceiling of the cave.
@@ -23978,8 +24311,9 @@ B:SHOOT:HURT:8d8
 B:SLASH:HURT:8d8
 B:SLASH:HURT:9d7
 B:HIT:HURT:10d2
+X:FEMALE
 F:UNIQUE | FORCE_MAXHP | DROP_CORPSE | DROP_SKELETON | EVIL | BASH_DOOR
-F:HUMAN | FEMALE | ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD | NO_SLEEP
+F:HUMAN | ONLY_ITEM | DROP_90 | DROP_1D2 | DROP_GOOD | NO_SLEEP
 F:IM_FIRE | IM_COLD | IM_ELEC
 S:1_IN_8 | SHOOT | HEAL | CAUSE_3
 D:$There are good dragons in this world.
@@ -24099,7 +24433,8 @@ B:SLASH:UN_BONUS:13d11
 B:HIT:UN_POWER:13d11
 B:SLASH:EXP_VAMP:13d11
 B:HIT:SUPERHURT:10d11
-F:UNIQUE | FORCE_MAXHP | HUMAN | MALE | EVIL | DROP_SKELETON
+X:MALE
+F:UNIQUE | FORCE_MAXHP | HUMAN | EVIL | DROP_SKELETON
 F:POWERFUL | SMART | IM_FIRE | IM_COLD | IM_ELEC | RES_CHAO
 F:NO_SLEEP | NO_CONF | BASH_DOOR | KILL_BODY | PASS_WALL
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GREAT
@@ -24121,7 +24456,8 @@ B:CRUSH:LOSE_INT:10d11
 B:CRUSH:LOSE_WIS:10d11
 B:SLASH:EXP_VAMP:10d11
 B:SLASH:EXP_VAMP:10d11
-F:UNIQUE | FORCE_MAXHP | UNDEAD | EVIL | DEMON | MALE
+X:MALE
+F:UNIQUE | FORCE_MAXHP | UNDEAD | EVIL | DEMON |
 F:DROP_CORPSE | DROP_SKELETON | BASH_DOOR | KILL_BODY
 F:HURT_LITE | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS
 F:RES_NETH | RES_DARK | RES_SHAR | NO_SLEEP | NO_CONF
@@ -24252,7 +24588,8 @@ B:HIT:EXP_VAMP:6d9
 B:CLAW:DISEASE:6d9
 B:BITE:HURT:9d9
 B:INSULT:LOSE_CHR:6d9
-F:UNIQUE | FORCE_MAXHP | EVIL | UNDEAD | MALE | DROP_SKELETON
+X:MALE
+F:UNIQUE | FORCE_MAXHP | EVIL | UNDEAD | DROP_SKELETON
 F:IM_COLD | IM_POIS | RES_DARK | RES_NETH
 F:HURT_LITE | NO_SLEEP | NO_CONF | DROP_3D2 | DROP_GOOD
 S:1_IN_6 | HOLD | CONF | S_KIN | MIND_BLAST | S_UNDEAD
@@ -24543,7 +24880,8 @@ I:120:25d12:15:40:20
 W:18:3:350:0:0
 B:CRUSH:HURT:1d13
 B:SLASH:FIRE:4d11
-F:UNIQUE | FORCE_MAXHP | HUMAN | MALE | GOOD | NO_FEAR | SPEAK_ALL
+X:MALE
+F:UNIQUE | FORCE_MAXHP | HUMAN | GOOD | NO_FEAR | SPEAK_ALL
 F:ONLY_ITEM | DROP_4D2
 S:1_IN_7 | HASTE
 D:$Hey, girlfriend came to me...
@@ -24615,7 +24953,8 @@ W:43:3:6000:0:0
 B:CLAW:HURT:11d2
 B:CLAW:HURT:11d2
 B:CLAW:HURT:22d1
-F:IM_POIS | OPEN_DOOR | BASH_DOOR | MALE | RES_PLAS | NONLIVING |
+X:MALE
+F:IM_POIS | OPEN_DOOR | BASH_DOOR | RES_PLAS | NONLIVING |
 F:IM_FIRE | NO_CONF | NO_SLEEP | EVIL | DEMON | FORCE_MAXHP | RES_TELE
 S:1_IN_2 | BO_PLAS
 D:$A major demon lord with a goat's head, tough to kill.
@@ -24678,7 +25017,8 @@ B:INSULT:SUPERHURT:9d9
 B:INSULT:SUPERHURT:9d9
 B:INSULT:SUPERHURT:9d9
 B:INSULT:SUPERHURT:9d9
-F:UNIQUE | FORCE_MAXHP | HUMAN | MALE | UNDEAD | HAS_LITE_1
+X:MALE
+F:UNIQUE | FORCE_MAXHP | HUMAN | UNDEAD | HAS_LITE_1
 F:KILL_BODY | BASH_DOOR | SPEAK_ALL
 F:IM_ACID | RES_NETH | RES_NEXU | RES_CHAO
 S:1_IN_5 | BA_ACID |  BA_ELEC | BA_POIS | BA_CHAO | BA_NETH
@@ -24699,7 +25039,8 @@ W:85:1:82000:0:0
 B:BITE:HURT:15d15
 B:BITE:HURT:15d15
 B:BITE:POISON:15d15
-F:UNIQUE | MALE | RES_TELE |
+X:MALE
+F:UNIQUE | RES_TELE |
 F:BASH_DOOR | DROP_CORPSE | DROP_SKELETON | ANIMAL
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | NO_CONF | NO_SLEEP
 F:DROP_4D2 | DROP_3D2 | DROP_GREAT | ONLY_ITEM |
@@ -24788,7 +25129,8 @@ B:STING:PARALYZE:3d10
 B:STING:PARALYZE:3d10
 B:CRUSH:SUPERHURT:3d12
 S:1_IN_4 | SHRIEK | S_KIN | BR_ACID
-F:UNIQUE | FEMALE | ANIMAL | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC | CAN_FLY | RAND_25
+X:FEMALE
+F:UNIQUE | ANIMAL | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC | CAN_FLY | RAND_25
 F:ONLY_ITEM | DROP_60 | DROP_1D2 | DROP_GOOD | DROP_CORPSE |
 F:BASH_DOOR | IM_ACID | IM_ELEC | HURT_FIRE | WEIRD_MIND | NO_FEAR
 R:1252:5d5
@@ -24918,7 +25260,8 @@ B:CRUSH:SHATTER:16d10
 B:CRUSH:SHATTER:16d10
 S:1_IN_3 |
 S:SHRIEK | BA_FIRE | PSY_SPEAR | S_KIN
-F:UNIQUE | MALE | DROP_CORPSE | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC
+X:MALE
+F:UNIQUE | DROP_CORPSE | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC
 F:NONLIVING | SPEAK_ALL | POWERFUL
 F:ONLY_ITEM | DROP_1D2 | DROP_3D2 | DROP_GREAT
 F:IM_ACID | IM_ELEC | IM_FIRE | IM_COLD | IM_POIS | RES_LITE | RES_DARK
@@ -24962,7 +25305,8 @@ W:49:3:6000:0:0
 B:SLASH:HURT:8d8
 B:SLASH:HURT:8d8
 B:SLASH:HURT:45d1
-F:MALE | PREVENT_SUDDEN_MAGIC | ANIMAL
+X:MALE
+F:PREVENT_SUDDEN_MAGIC | ANIMAL
 F:REGENERATE | OPEN_DOOR | MOVE_BODY | TAKE_ITEM | DROP_CORPSE 
 F:IM_ACID | IM_ELEC | IM_COLD | IM_FIRE | IM_POIS
 S:1_IN_4 | HASTE | HEAL | CAUSE_2
@@ -25145,7 +25489,8 @@ I:120:80d20:20:50:80
 W:35:3:500:0:0
 B:SHOW:CONFUSE:4d5
 B:SHOW:BLIND:4d5
-F:FEMALE | AQUATIC | CAN_FLY | CAN_SWIM | WILD_SHORE | NEVER_MOVE
+X:FEMALE
+F:AQUATIC | CAN_FLY | CAN_SWIM | WILD_SHORE | NEVER_MOVE
 F:ONLY_ITEM | DROP_GOOD | DROP_1D2 | PREVENT_SUDDEN_MAGIC
 F:IM_COLD | IM_POIS | RES_WATE | RES_TELE | NO_STUN
 S:1_IN_2 | SHRIEK | TELE_TO
@@ -25194,7 +25539,8 @@ I:115:3d11:15:30:80
 W:12:3:20:0:0
 B:STING:POISON:5d1
 B:WAIL:LOSE_INT
-F:FEMALE | QUANTUM | PREVENT_SUDDEN_MAGIC | FRIENDS | DROP_90 | TAKE_ITEM
+X:FEMALE
+F:QUANTUM | PREVENT_SUDDEN_MAGIC | FRIENDS | DROP_90 | TAKE_ITEM
 F:HURT_FIRE | CAN_FLY | FRIENDLY | HAS_LITE_1 | IM_POIS | RES_LITE
 S:1_IN_4 | MISSILE
 D:$A few old photographs are the only proof that this fairy once existed.
@@ -25230,7 +25576,8 @@ B:CLAW:HURT:9d11
 B:CLAW:ELEC:12d12
 B:PUNCH:HURT:9d11
 B:PUNCH:ELEC:12d12
-F:UNIQUE | FORCE_MAXHP | FEMALE | EVIL | ANIMAL | POWERFUL
+X:FEMALE
+F:UNIQUE | FORCE_MAXHP | EVIL | ANIMAL | POWERFUL
 F:DROP_CORPSE | DROP_GOOD | DROP_4D2 | ONLY_ITEM | KILL_BODY
 F:BASH_DOOR | NO_CONF | NO_FEAR | NO_SLEEP | IM_ELEC
 S:1_IN_4 | BO_ELEC | BA_ELEC | BR_ELEC | BLINK | HOLD | CAUSE_3
@@ -25252,7 +25599,8 @@ B:BITE:EXP_VAMP:5d3
 B:BITE:EXP_VAMP:7d3
 B:BITE:EXP_VAMP:9d3
 B:BITE:EXP_VAMP:11d3
-F:UNIQUE | FORCE_MAXHP | MALE | DEMON | EVIL | FRIENDLY
+X:MALE
+F:UNIQUE | FORCE_MAXHP | DEMON | EVIL | FRIENDLY
 F:RES_DARK | RES_CHAO | RES_TIME
 F:OPEN_DOOR | NO_CONF | NO_FEAR | NO_SLEEP | DROP_GOOD | DROP_90
 S:1_IN_4 | BA_DARK | CAUSE_3 | SCARE | FORGET
@@ -25274,7 +25622,8 @@ B:KICK:FIRE:15d5
 B:HIT:FIRE:15d5
 B:KICK:CONFUSE:5d4
 B:HIT:CONFUSE:5d2
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON
 F:DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR
 F:IM_FIRE | RES_CHAO | NO_FEAR | NO_CONF | NO_SLEEP
 S:1_IN_9 | BO_FIRE | BA_FIRE | BA_CHAO | TELE_AWAY | MISSILE | CONF
@@ -25290,7 +25639,8 @@ B:KICK:FIRE:15d8
 B:HIT:FIRE:15d8
 B:KICK:CONFUSE:5d5
 B:HIT:CONFUSE:5d3
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON
 F:DROP_90 | DROP_1D2 | OPEN_DOOR | BASH_DOOR
 F:IM_FIRE | RES_CHAO | NO_FEAR | NO_CONF | NO_SLEEP
 S:1_IN_6 | BO_FIRE | BA_FIRE | BA_CHAO | TELE_AWAY | MISSILE | CONF
@@ -25350,7 +25700,8 @@ B:HIT:HURT:2d6
 B:HIT:HURT:2d6
 B:TOUCH:EAT_GOLD
 B:TOUCH:EAT_ITEM
-F:UNIQUE | MALE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | HUMAN
+X:MALE
+F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SPEAK_ALL | HUMAN
 F:DROP_GREAT | DROP_1D2 | WILD_TOWN
 F:TAKE_ITEM | OPEN_DOOR | BASH_DOOR | EVIL | DROP_SKELETON | DROP_CORPSE
 S:1_IN_5 | TRAPS
@@ -25392,7 +25743,8 @@ B:HIT:BLIND:6d8
 B:HIT:UN_BONUS:6d8
 B:HIT:LOSE_STR:6d8
 B:CLAW:EAT_ITEM:2d12
-F:UNIQUE | MALE | DROP_CORPSE | DROP_SKELETON | HUMAN
+X:MALE
+F:UNIQUE | DROP_CORPSE | DROP_SKELETON | HUMAN
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | HAS_LITE_2
 F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM
 F:EVIL | IM_FIRE | IM_POIS | REGENERATE | CAN_FLY
@@ -25428,7 +25780,8 @@ B:HIT:BLIND:6d8
 B:HIT:UN_BONUS:6d8
 B:HIT:LOSE_STR:6d8
 B:CLAW:EAT_ITEM:2d12
-F:UNIQUE | MALE | DROP_CORPSE | DROP_SKELETON | HUMAN
+X:MALE
+F:UNIQUE | DROP_CORPSE | DROP_SKELETON | HUMAN
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | HAS_LITE_2
 F:OPEN_DOOR | BASH_DOOR | TAKE_ITEM
 F:EVIL | IM_FIRE | IM_POIS | REGENERATE | CAN_FLY
@@ -25466,7 +25819,8 @@ B:HIT:UN_BONUS:6d8
 B:HIT:UN_BONUS:6d8
 B:TOUCH:UN_POWER
 B:TOUCH:UN_POWER
-F:UNIQUE | MALE | DROP_CORPSE | DROP_SKELETON | HUMAN
+X:MALE
+F:UNIQUE | DROP_CORPSE | DROP_SKELETON | HUMAN
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | HAS_LITE_2
 F:ONLY_ITEM | DROP_1D2 | DROP_4D2 | DROP_GOOD
 F:INVISIBLE | OPEN_DOOR | BASH_DOOR
@@ -25531,7 +25885,7 @@ W:10:2:45:0:0
 B:BITE:HURT:1d10
 B:BITE:HURT:10d1
 F:BASH_DOOR | UNIQUE | FORCE_MAXHP | NO_CONF | NO_SLEEP
-F:DRAGON |CAN_FLY | SPEAK_ALL | DROP_CORPSE
+F:DRAGON | CAN_FLY | SPEAK_ALL | DROP_CORPSE
 D:$"Give me that MAGI!" -BabyWyrm
 D:新しき神々の時代、この翼竜もまた古き神々の遺産の力で神になろうとした。
 D:あなたの持つ伝説のアイテムに目をつけている……
@@ -25542,7 +25896,8 @@ G:p:v
 I:130:10d100:20:100:10
 W:65:5:5555:0:0
 B:HIT:SUPERHURT:10d10
-F:UNIQUE | MALE |
+X:MALE
+F:UNIQUE | |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | SPEAK_ALL
 F:OPEN_DOOR | FRIENDLY
 S:1_IN_8 | INVULNER
@@ -25557,7 +25912,8 @@ I:130:50d100:20:100:10
 W:66:255:55555:0:0
 B:SPIT:BLIND:10d10
 B:HIT:SUPERHURT:100d2
-F:UNIQUE | MALE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | SPEAK_ALL
+X:MALE
+F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | SPEAK_ALL
 F:ONLY_ITEM | DROP_1D2 | DROP_GOOD | DROP_GREAT
 F:OPEN_DOOR | BASH_DOOR | KILL_BODY | EVIL | NO_CONF | REFLECTING
 S:1_IN_3 | INVULNER | WORLD | TELE_TO
@@ -25581,7 +25937,8 @@ B:HIT:UN_BONUS:8d8
 B:HIT:UN_BONUS:8d8
 B:HIT:DISEASE:10d10
 B:HIT:DISEASE:10d10
-F:UNIQUE | MALE
+X:MALE
+F:UNIQUE |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART | SPEAK_ALL | ESCORTS | HUMAN
 F:OPEN_DOOR | BASH_DOOR | MOVE_BODY | EVIL | IM_POIS | NO_CONF | NO_SLEEP
 S:1_IN_2 | S_KIN
@@ -25711,7 +26068,8 @@ G:h:u
 I:110:1d1:10:0:25
 W:2:1:35:0:0
 B:HIT:HURT:2d4
-F:UNIQUE | FORCE_MAXHP | DROP_CORPSE | MALE | DEMON
+X:MALE
+F:UNIQUE | FORCE_MAXHP | DROP_CORPSE | DEMON
 F:DROP_3D2 | ONLY_GOLD | SPEAK_ALL | EVIL | DROP_SKELETON
 D:$He is the weakest man among the big four,
 D:$ and is a mess of the demons.
@@ -25726,7 +26084,8 @@ B:SLASH:TIME:100d1
 B:SLASH:TIME:100d1
 B:SLASH:EAT_ITEM:5d5
 B:SLASH:EAT_ITEM:5d5
-F:UNIQUE | FORCE_MAXHP | GOOD | HUMAN | MALE | UNDEAD | COLD_BLOOD
+X:MALE
+F:UNIQUE | FORCE_MAXHP | GOOD | HUMAN | UNDEAD | COLD_BLOOD
 F:BASH_DOOR | CAN_SWIM | CAN_FLY | FRIENDLY | SPEAK_ALL | DROP_CORPSE
 F:IM_ACID | IM_ELEC | IM_FIRE | IM_POIS | RES_DARK | RES_NETH | RES_WATE
 F:RES_PLAS | RES_SHAR | RES_SOUN | RES_CHAO | RES_DISE | RES_NEXU | RES_WALL
@@ -25852,7 +26211,8 @@ B:SPIT:HURT:7d9
 B:HIT:HURT:7d9
 B:CLAW:HURT:7d9
 B:BITE:HURT:7d9
-F:UNIQUE | FORCE_MAXHP | ANIMAL | MALE | GOOD | FRIENDLY
+X:MALE
+F:UNIQUE | FORCE_MAXHP | ANIMAL | GOOD | FRIENDLY
 F:SPEAK_ALL | NO_FEAR | CAN_FLY | DROP_CORPSE
 F:DROP_GOOD | DROP_3D2
 S:1_IN_3 | BLINK | TELE_TO | TELE_AWAY | TRAPS | FORGET | S_KIN
@@ -25878,7 +26238,8 @@ B:INSULT:SUPERHURT:10d10
 B:INSULT:SUPERHURT:10d10
 B:INSULT:SUPERHURT:10d10
 B:INSULT:SUPERHURT:10d10
-F:UNIQUE | FORCE_MAXHP | HUMAN | MALE | EVIL | GOOD
+X:MALE
+F:UNIQUE | FORCE_MAXHP | HUMAN | EVIL | GOOD
 F:SPEAK_ALL | DROP_CORPSE | ONLY_ITEM | DROP_4D2 | DROP_3D2 | DROP_2D2
 F:IM_FIRE | IM_POIS | RES_SOUN | RES_DISE
 S:1_IN_3 | SHRIEK | DISPEL | FORGET | TELE_AWAY
@@ -25911,7 +26272,8 @@ B:SHOW:CONFUSE:6d9
 B:CHARGE:FIRE:6d9
 B:CHARGE:COLD:6d9
 B:CHARGE:POISON:6d9
-F:UNIQUE | FORCE_MAXHP | MALE | EVIL | ATTR_MULTI | DROP_GREAT | DROP_90
+X:MALE
+F:UNIQUE | FORCE_MAXHP | EVIL | ATTR_MULTI | DROP_GREAT | DROP_90
 F:STUPID | SPEAK_ALL | WEIRD_MIND | ELDRITCH_HORROR | BASH_DOOR | KILL_BODY
 F:IM_FIRE | IM_COLD | IM_POIS | RES_CHAO
 F:TAKE_ITEM | CAN_SWIM | NO_CONF | NO_FEAR
@@ -25933,7 +26295,8 @@ I:120:50d30:20:80:20
 W:36:3:3000:0:0
 B:MOAN:HURT:4d10
 B:CRAWL:HURT:4d10
-F:UNIQUE | FORCE_MAXHP | HUMAN | MALE | UNDEAD | COLD_BLOOD | FRIENDLY
+X:MALE
+F:UNIQUE | FORCE_MAXHP | HUMAN | UNDEAD | COLD_BLOOD | FRIENDLY
 F:DROP_GOOD | DROP_4D2 | DROP_3D2 | DROP_2D2 | DROP_1D2 | DROP_60 | DROP_90
 F:DROP_CORPSE | SMART | IM_ELEC | IM_COLD | IM_POIS | RES_NETH | RES_WATE
 S:1_IN_6 | S_KIN | BO_ELEC | BA_ELEC | BR_ELEC | CAUSE_1 | CAUSE_2 | CAUSE_3
@@ -26000,7 +26363,8 @@ I:110:16d21:20:50:20
 W:23:2:200:0:0
 B:PUNCH:HURT:5d5
 B:PUNCH:HURT:5d5
-F:HUMAN | MALE | DROP_CORPSE | DROP_SKELETON
+X:MALE
+F:HUMAN | DROP_CORPSE | DROP_SKELETON
 F:DROP_60 | DROP_1D2 | OPEN_DOOR | BASH_DOOR | IM_FIRE | IM_POIS
 F:NO_FEAR | NO_CONF | NO_SLEEP
 D:$He is a rough man who has been in a fight in the city.
@@ -26086,7 +26450,8 @@ I:115:4d5:20:5:10
 W:0:3:20:0:0
 B:BITE:HURT:1d4
 B:BITE:HURT:1d4
-F:UNIQUE | FORCE_MAXHP | ANIMAL | FEMALE
+X:FEMALE
+F:UNIQUE | FORCE_MAXHP | ANIMAL |
 F:WILD_TOWN | SPEAK_ALL | CAN_FLY | FRIENDLY | RES_GRAV
 F:ONLY_GOLD | DROP_4D2 | DROP_CORPSE
 S:1_IN_6 | BLINK | TPORT
@@ -26122,7 +26487,7 @@ B:TOUCH:FIRE:12d8
 B:TOUCH:FIRE:12d8
 F:UNIQUE | PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | ONLY_GOLD | AURA_FIRE
 F:NO_CONF | NO_STUN | RES_TELE| EMPTY_MIND | COLD_BLOOD
-F:NO_SLEEP |IM_FIRE | NONLIVING | DROP_4D2 | DROP_3D2 | BASH_DOOR 
+F:NO_SLEEP | IM_FIRE | NONLIVING | DROP_4D2 | DROP_3D2 | BASH_DOOR 
 S:1_IN_3 | 
 S:BR_FIRE | BA_FIRE |
 D:$It is a monster whose whole body is made of lava, hidden in the volcano of Neo Star.
@@ -26138,7 +26503,8 @@ B:HIT:HURT:7d7
 B:HIT:SUPERHURT:6d6
 B:HIT:SUPERHURT:7d7
 B:HIT:SUPERHURT:7d7
-F:UNIQUE | MALE | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC
+X:MALE
+F:UNIQUE | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC
 F:ONLY_ITEM | DROP_60 | DROP_3D2 | DROP_GOOD | SPEAK_ALL
 F:OPEN_DOOR | BASH_DOOR | MOVE_BODY
 F:HUMAN | NO_STUN | NO_CONF | NO_SLEEP
@@ -26162,7 +26528,8 @@ B:CLAW:HURT:4d9
 B:CLAW:HURT:4d9
 B:CLAW:HURT:4d9
 B:BITE:HURT:6d12
-F:UNIQUE | FEMALE | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC |
+X:FEMALE
+F:UNIQUE | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC |
 F:ONLY_ITEM | DROP_3D2 | DROP_4D2 | DROP_GOOD | 
 F:BASH_DOOR | MOVE_BODY | 
 F:EVIL | DRAGON | NO_CONF | NO_SLEEP | CAN_FLY | RIDING |
@@ -26188,7 +26555,8 @@ B:GAZE:TERRIFY
 B:GAZE:PARALYZE
 B:SLASH:EXP_VAMP:4d11
 B:SLASH:EXP_VAMP:4d11
-F:UNIQUE | MALE | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC | REGENERATE
+X:MALE
+F:UNIQUE | FORCE_MAXHP | PREVENT_SUDDEN_MAGIC | REGENERATE
 F:ONLY_ITEM | DROP_2D2 | DROP_3D2 | DROP_GOOD | DROP_60
 F:SMART | COLD_BLOOD | OPEN_DOOR | BASH_DOOR | MOVE_BODY
 F:EVIL | UNDEAD | NO_FEAR | NO_CONF | NO_SLEEP | SELF_DARK_1
@@ -26280,7 +26648,8 @@ E:Voldemort, the Dark Lord
 G:p:D
 I:120:50d100:20:100:0
 W:61:4:30000:0:0
-F:UNIQUE | MALE | REFLECTING | ESCORT | ESCORTS |
+X:MALE
+F:UNIQUE | REFLECTING | ESCORT | ESCORTS |
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | HUMAN | DROP_CORPSE |
 F:DROP_2D2 | DROP_4D2 | DROP_GREAT | NEVER_BLOW
 F:SMART | OPEN_DOOR | BASH_DOOR | CAN_FLY | 
@@ -26341,7 +26710,8 @@ W:43:2:7000:0:0
 B:PUNCH:HURT:5d5
 B:HIT:ELEC:5d5
 B:KICK:SUPERHURT:6d6
-F:UNIQUE | MALE | SPEAK_ALL | FORCE_MAXHP | FRIENDLY
+X:MALE
+F:UNIQUE | SPEAK_ALL | FORCE_MAXHP | FRIENDLY
 F:IM_ELEC | IM_FIRE | RES_PLAS
 F:WEIRD_MIND | BASH_DOOR | MOVE_BODY | HUMAN | NONLIVING | HAS_LITE_2
 F:NO_STUN | NO_SLEEP | NO_CONF | DROP_GOOD | DROP_4D2
@@ -26395,7 +26765,8 @@ B:SHOOT:HURT:13d13
 B:SLASH:HURT:13d13
 B:SLASH:UN_POWER:13d13
 B:ENGULF:CONFUSE:13d13
-F:UNIQUE | FEMALE | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_GREAT
+X:FEMALE
+F:UNIQUE | DROP_1D2 | DROP_2D2 | DROP_3D2 | DROP_GREAT
 F:OPEN_DOOR | BASH_DOOR | DROP_CORPSE | DROP_SKELETON | FORCE_MAXHP
 F:EVIL | GOOD | GIANT | HUMAN | ANGEL | NONLIVING | ANIMAL | SMART
 F:REGENERATE | REFLECTING
@@ -26413,7 +26784,8 @@ E:Pakuman
 G:R:g
 I:115:10d8:15:15:20
 W:6:2:40:0:0
-F:UNIQUE | MALE | FORCE_MAXHP | NONLIVING | OPEN_DOOR | RES_CHAO | COLD_BLOOD
+X:MALE
+F:UNIQUE | FORCE_MAXHP | NONLIVING | OPEN_DOOR | RES_CHAO | COLD_BLOOD
 B:PUNCH:ELEC:3d7
 D:$It has the personality that adds all the dried vegetable
 D:$ and soup powder packages to instant noodles before adding the hot water.
@@ -26488,7 +26860,8 @@ B:GAZE:PARALYZE
 B:GAZE:CONFUSE
 B:HIT:STUN:8d8
 B:HIT:DISEASE:8d8
-F:UNIQUE | MALE | DROP_CORPSE
+X:MALE
+F:UNIQUE | DROP_CORPSE
 F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GREAT
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART
 F:OPEN_DOOR | BASH_DOOR
@@ -26513,7 +26886,8 @@ B:GAZE:PARALYZE
 B:GAZE:CONFUSE
 B:TOUCH:HUNGRY:1500d1
 B:HIT:STUN:8d8
-F:UNIQUE | MALE | DROP_CORPSE
+X:MALE
+F:UNIQUE | DROP_CORPSE
 F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GREAT
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART
 F:OPEN_DOOR | BASH_DOOR
@@ -26537,7 +26911,8 @@ B:GAZE:PARALYZE
 B:GAZE:CONFUSE
 B:HIT:LOSE_ALL:8d8
 B:HIT:EXP_80:8d8
-F:UNIQUE | MALE | DROP_CORPSE | NONLIVING
+X:MALE
+F:UNIQUE | DROP_CORPSE | NONLIVING
 F:ONLY_ITEM | DROP_4D2 | DROP_2D2 | DROP_GREAT
 F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART
 F:OPEN_DOOR | BASH_DOOR
@@ -26719,3 +27094,72 @@ S:1_IN_6 | BR_ABYSS
 V:150
 D:$It's a abyssal whirlpool.
 D:深淵の渦巻きだ。
+
+N:1353:破壊と憎悪の化身『サルーイン』
+E:Saruin, The avatar of destruction and hatred
+G:P:w
+I:125:90d100:100:175:0
+W:79:3:66666:0:0
+B:HIT:HURT:11d13
+B:HIT:HURT:11d13
+B:HIT:HURT:11d13
+B:HIT:HURT:11d13
+X:MALE
+F:UNIQUE | DROP_CORPSE | NONLIVING |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GREAT |
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_WATE | RES_SHAR | RES_LITE | RES_DARK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_STUN | RES_TELE
+S:1_IN_3 | S_DEAD_UNIQUE |
+S:BA_FIRE | BA_WATE | BA_ACID | ROCKET | DISPEL | BLIND | BO_MANA |
+S:HOLD | HEAL | HASTE | CONF | BRAIN_SMASH
+D:$He was born from the heart of Sayva, the goddess of destruction.
+D:$  Apparently, some foolish adventurer had given away all the Destiny Stones.
+D:破壊の女神サイヴァの心臓から生まれた存在だ。
+D:どうやら愚かなる冒険者がすべてのデステニィストーンを捧げてしまったらしい。
+
+N:1354:赤チォコヴォLv99
+E:Lv.99 Red Chiokovo
+G:B:R
+I:135:80d100:30:150:10
+W:99:6:80000:0:0:0
+B:CLAW:HURT:10d10
+B:CRUSH:HURT:8d13
+B:KICK:HURT:30d5
+B:CLAW:HURT:10d10
+F:CAN_SWIM | RIDING | POWERFUL | ANIMAL | EVIL |
+F:DROP_4D2 | DROP_GREAT |
+F:FORCE_MAXHP | ONLY_ONE | NO_INSTANTLY_DEATH |
+F:NO_CONF | NO_SLEEP | NO_FEAR |
+F:IM_FIRE | IM_COLD | IM_POIS | RES_CHAO | RES_LITE | RES_INER | RES_ABYSS | RES_GRAV | RES_METEOR
+S:1_IN_3
+S:BA_METEOR | BO_METEOR | BA_FIRE | BA_LITE | BLIND | HOLD | CONF | HEAL |
+D:$It is seldom found but greatly formidable.
+D:$  You'll be defeated without complete preparation.
+D:それはめったに出会えないが、恐ろしく強力な力を持っている。
+D:生半可な態勢で挑めばあっという間に返り討ちにされるだろう。
+
+N:1355:バグピエロ『カフモ』
+E:Kaufmo, the abstracted clown
+G:q:v
+I:120:30d40:20:100:0
+W:35:3:6000:0:0
+B:CRUSH:CHAOS:12d6
+B:HIT:CHAOS:7d6
+B:HIT:CHAOS:7d6
+B:HIT:CHAOS:7d6
+X:MALE
+F:UNIQUE | ELDRITCH_HORROR | QUANTUM | FORCE_MAXHP | GIANT |
+F:RES_CHAO |
+F:KILL_BODY | BASH_DOOR | COLD_BLOOD | WEIRD_MIND
+F:ATTR_MULTI
+F:DROP_4D2 | DROP_GOOD | ONLY_ITEM
+F:NO_CONF | NO_SLEEP
+D:アメイジング・デジタル・サーカスで出口を求め続け限界を迎えた者の末路だ。
+D:地下室に送られてもなお徘徊しており、
+D:彼に触れられバグる者の姿も時々見える。
+D:$This is the fate of those who continue to seek an exit from the Amazing Digital Circus and reach their breaking point.
+D:$  He is crawling yet after being sent into the cellar.
+D:$  All touched by him start abstracting.
index 50fb619..e68ef20 100644 (file)
@@ -53,8 +53,9 @@
 ?:[EQU $QUEST_NUMBER 12]
 %:quests/012_NodeOfNature.txt
 
-# Quest #13 is still unfinished
-# 欠番、おそらく『海底都市』だったもの
+# 秘術の特異点
+?:[EQU $QUEST_NUMBER 13]
+%:quests/013_NodeOfArcane.txt
 
 # ワーグを殱滅せよ
 ?:[EQU $QUEST_NUMBER 14]
diff --git a/lib/edit/quests/013_NodeOfArcane.txt b/lib/edit/quests/013_NodeOfArcane.txt
new file mode 100644 (file)
index 0000000..7011c5f
--- /dev/null
@@ -0,0 +1,123 @@
+# File: 013_NodeOfArcane.txt
+
+# Created by daradarach
+
+# Name
+Q:$13:N:Node of Arcane
+Q:13:N:秘術の特異点
+
+# Definition
+Q:$13:Q:6:0:0:0:65:0:0:0:6
+Q:13:Q:6:0:0:0:65:0:0:0:6
+
+# Description for quest
+?:[LEQ $QUEST13 2]
+Q:$13:T:Tourists who reached the summit of the mystery confirmed the presence of a burning element singularity in the nearby forest.
+Q:$13:T:You must find the location of the singularity and pump up the flammable element.
+Q:13:T:秘術の頂に至った観光客たちが、近くの森に燃素の特異点の存在を確認した。
+Q:13:T:おまえはその特異点の場所を見つけ燃素を汲み上げてくるのだ。
+?:1
+
+# Description for quest reward
+?:[EQU $QUEST13 3]
+Q:$13:T:You have done well. A powerful spellbook awaits you outside.
+Q:13:T:よくやった。強力な魔法書を外に置いておいた。
+?:1
+
+# Description for quest failed
+?:[EQU $QUEST13 5]
+Q:$13:T:Walk away, you incompetent, no better than a tourist!
+Q:$13:T:The fuel element, which should have been a permanent institution, has vanished and been lost forever!
+Q:$13:T:You have squandered your chance.
+Q:13:T:立ち去れ、観光客にも劣る無能め!
+Q:13:T:永久機関となるべき燃素は消え去って永遠に失われたのだぞ!
+Q:13:T:お前はせっかくのチャンスを棒にふったのだ。
+?:1
+
+# Grass
+F:.:GRASS:8
+
+# Floor with Air spirit
+F:a:GRASS:8:227
+# Floor with Water spirit
+F:b:GRASS:8:303
+# Floor with Earth spirit
+F:c:GRASS:8:305
+# Floor with Fire spirit
+F:d:GRASS:8:306
+# Floor with Fire elemental
+F:e:GRASS:8:510
+# Floor with Water elemental
+F:f:GRASS:8:512
+# Floor with Night stalker
+F:g:GRASS:8:514
+# Floor with Earth elemental
+F:h:GRASS:8:525
+# Floor with Air elemental
+F:i:GRASS:8:526
+# Floor with Smoke elemental
+F:j:GRASS:8:537
+# Floor with Ooze elemental
+F:k:GRASS:8:545
+# Floor with Ice elemental
+F:l:GRASS:8:570
+# Floor with Time elemental
+F:m:GRASS:8:579
+# Floor with Will o' the wisp
+F:n:GRASS:8:582
+# Floor with Magma elemental
+F:o:GRASS:8:584
+# Floor with Shambler
+F:p:GRASS:8:786
+# Floor with Caaws
+F:q:GRASS:8:866
+# Floor with Elder air elemental
+F:r:GRASS:8:1141
+# Floor with Elder magma elemental
+F:s:GRASS:8:1142
+# Floor with Elder fire elemental
+F:t:GRASS:8:1143
+# Floor with Elder ice elemental
+F:u:GRASS:8:1144
+# Floor with Elder ooze elemental
+F:v:GRASS:8:1145
+# Floor with Beast in wheat fields
+F:w:GRASS:8:1310
+
+# Mountain
+F:y:MOUNTAIN_WALL
+# Tree
+F:z:TREE:8
+
+# Node of Arcane layout 
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+D:XzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzX
+D:Xzzzzzz...................zzzzzzX
+D:Xzzzz..........z.z..........zzzzX
+D:Xzzz......zzzzzdddzzzzz......zzzX
+D:Xzz...zzzzyyyyz...zyyyyzzzz...zzX
+D:Xz...zyyyzzzzz..z..zzzzzyyyz...zX
+D:Xz..zyyyznnn...zyz...nnnzyyyz..zX
+D:Xz..zyyznmw...zyyyz..dwmnzyyz..zX
+D:Xz..zyyznwzzzzzzzzzzzzzwnzyyz..zX
+D:Xz..zyz.nzyz...ete...zyzn.zyz..zX
+D:Xz.zyyz..zz..fqzzzqf..zz..zyyz.zX
+D:Xzazyyz..z...izzpzzk...z..zyyzczX
+D:Xzazyyz.hsj..rzpppzv..jsh.zyyzczX
+D:Xzazyyz..z...izzpzzk...z..zyyzczX
+D:Xz.zyyz..zz..fqzzzqf..zz..zyyz.zX
+D:Xz..zyz.nzyz...lul...zyzn.zyz..zX
+D:Xz..zyyznwzzz.......zzzwnzyyz..zX
+D:Xz..zyyznmw...........wmnzyyz..zX
+D:Xz...zyyznnn.zzzzzzz.nnnzyyz...zX
+D:Xz...zyyyzzzzyyyyyyyzzzzyyyz...zX
+D:Xzz...zzyyyyyyyyyyyyyyyyyzz...zzX
+D:Xzz.....zzzzyyyyyyyyyzzzz.....zzX
+D:Xz..........zzzzzzzzz.......zzzzX
+D:Xz<............bbb.........zzzzzX
+D:XzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzX
+D:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+# Starting position
+P:24:2
+
index 48ea1a1..f50fe6f 100644 (file)
@@ -56,7 +56,7 @@ F:%:FLOOR:10:0:395
 
 
 # Cloaker
-F:(:FLOOR:8:243
+F:(:FLOOR:10:243
 # Death sword
 F:|:FLOOR:8:107
 # Killer bee
index 86b4c22..9965fb6 100644 (file)
@@ -7,6 +7,7 @@ angband_files = \
        007_TheTower_3.txt 008_Oberon.txt \
        009_SerpentOfChaos.txt 010_NodeOfSorcery.txt \
        011_NodeOfChaos.txt 012_NodeOfNature.txt \
+       013_NodeOfArcane.txt \
        014_WargProblem.txt 015_EricStronghold.txt \
        016_AssaultOnMontsalvat.txt 018_WaterCave.txt \
        019_DoomQuest1.txt 020_VaporQuest.txt \
index a5b4f6e..46e5fd8 100644 (file)
@@ -9,12 +9,17 @@ F:$:FLOOR:3
 # Default nature tower reward = floor
 F:":FLOOR:3
 
+# Default arcane reward = floor
+F:%:FLOOR:3
+
 F:z:SHALLOW_WATER:3
 
 F:y:MOUNTAIN:3
 
 F:x:TREE:3
 
+F:w:MOUNTAIN:3
+
 #################### Quest 10 - Node of Sorcery ####################
 
 # Quest 10 not started
@@ -119,6 +124,40 @@ F:p:BUILDING_15:3
 
 ?:1
 
+#################### Quest 13 - Node of Arcane ####################
+
+# Quest 13 not yet assigned
+?:[EQU $QUEST13 0]
+F:r:BUILDING_16:3:0:0:0:0:NONE:13
+
+# Quest 13 assigned, entrance is quest entrance
+?:[EQU $QUEST13 1]
+F:w:QUEST_ENTER:3:0:0:0:0:NONE:13
+F:r:BUILDING_16:3:0:0:0:0:NONE:13
+
+# Quest 13 completed
+?:[EQU $QUEST13 2]
+F:r:BUILDING_16:3:0:0:0:0:NONE:13
+
+# Quest 13 rewarding, reward is Manual of Mastery, no new quest available
+?:[EQU $QUEST13 3]
+F:r:BUILDING_16:3
+F:%:GRASS:3:0:519
+
+# Quest 13 finished, no new quest available
+?:[EQU $QUEST13 4]
+F:r:BUILDING_16:3
+
+# Quest 13 failed
+?:[EQU $QUEST13 5]
+F:r:BUILDING_16:3:0:0:0:0:NONE:13
+
+# Quest 13 failed but done, no new quest available
+?:[EQU $QUEST13 6]
+F:r:BUILDING_16:3
+
+?:1
+
 #################### Buildings ####################
 
 B:$4:N:BrokenSkull Tavern:Celebor:Half-Elf
@@ -167,6 +206,13 @@ B:15:A:1:平衡化の儀式:2000:10000:n:41:0
 B:$15:M:0:0:2:0:0:0:0:0:0:0
 B:15:M:0:0:2:0:0:0:0:0:0:0
 
+B:$16:N:Tourist information centre:Nanase:Human
+B:16:N:観光客案内所:ナナセ:人間
+B:$16:A:0:Request quest:0:0:q:6:1
+B:16:A:0:クエスト:0:0:q:6:1
+B:$16:M:0:0:0:0:0:0:2:0:0:0
+B:16:M:0:0:0:0:0:0:2:0:0:0
+
 
 # Town Layout
 
@@ -179,7 +225,7 @@ D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^^^^^^^^^y^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^^^^^^KLLLKKK^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
-D:#^^^^^^^^^^^^^^KKLLLLLLLKKK^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^KKLLLLLLLKKK^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^w^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^^^LLLLLLLLLLLKKK^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^TxT^^^^^^^^---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^KKLLLKLLLKLLLKK^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^T-T^^^^^^^--^---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^LLKLLLLLLLLLKK^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^--^^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
@@ -197,8 +243,8 @@ D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----..-^^^^^^^^^--..LLL^^^^^^L^^^^^
 D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----..----------..-LLL^^^^^^^^^^^^^^^^^^^^LLL..--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---..............-LLL^^^^^^^^^^^^^^^^^^^^LLL...-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------..LLL^^^^^^L^^^^^^L^^^^^^LLL...-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
-D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^9^^^^^^^^^^^--..LLL^^^^LLL^^^^LLL^^^^LLL...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
-D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-..-LLLLLLLLLLLLLLLLLLLL....^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^9^^^^^^^^^^^--..LLL^r^^LLL^^^^LLL^^^^LLL...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
+D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-..-LL%LLLLLLLLLLLLLLLLL....^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^........................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------^^^^^^^^^^^^6^^.-----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
 D:#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------...------^^^^^^^^---.--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^#
@@ -253,3 +299,7 @@ P:7:21
 # Starting position when coming from quest 12
 ?:[EQU $LEAVING_QUEST 12]
 P:9:72
+
+# Starting position when coming from quest 13
+?:[EQU $LEAVING_QUEST 13]
+P:8:83
index 879b32b..ebfcbb3 100644 (file)
@@ -1,8 +1,10 @@
 ## Makefile.am -- Process this file with automake to process Makefile.in
 
+AUTOMAKE_OPTIONS = foreign
+
 angband_files = \
        a_cursed_j.txt a_high_j.txt a_low_j.txt a_med_j.txt \
-       aname_j.txt book-0_jp.txt chainswd_j.txt dead_j.txt \
+       aname_j.txt chainswd_j.txt dead_j.txt \
        death_j.txt elvish_j.txt error_j.txt mondeath_j.txt \
        monfear_j.txt monfrien_j.txt monspeak_j.txt news_j.txt \
        rumors_j.txt seppuku_j.txt silly_j.txt timefun_j.txt \
@@ -19,6 +21,8 @@ angband_files = \
 EXTRA_DIST = \
   $(angband_files)
 
+SUBDIRS = books
+
 if SET_GID
 angbanddir = @DEFAULT_LIB_PATH@/file
 
diff --git a/lib/file/books/Makefile.am b/lib/file/books/Makefile.am
new file mode 100644 (file)
index 0000000..06ed683
--- /dev/null
@@ -0,0 +1,35 @@
+## Makefile.am -- Process this file with automake to process Makefile.in
+
+angband_files = \
+       book-000_en.txt book-000_jp.txt \
+       book-001_en.txt book-001_jp.txt \
+       book-002_en.txt book-002_jp.txt \
+       book-003_en.txt book-003_jp.txt \
+       book-004_en.txt book-004_jp.txt \
+       book-005_en.txt book-005_jp.txt \
+       book-006_en.txt book-006_jp.txt \
+       book-007_en.txt book-007_jp.txt
+
+EXTRA_DIST = \
+       $(angband_files)
+
+if SET_GID
+angbanddir = @DEFAULT_LIB_PATH@/file/books
+
+angband_DATA = \
+       $(angband_files)
+endif
+
+if COCOA
+# APPNAME to APPRES duplicate what's in src/Makefile.am.  It would be nice to
+# avoid that, but until then, they should match.
+APPNAME = $(PACKAGE_NAME)
+APPDIR = $(APPNAME).app
+APPBNDL = $(bindir)/$(APPDIR)
+APPCONT = $(APPBNDL)/Contents
+APPRES = $(APPCONT)/Resources
+
+appfiledir = $(APPRES)/lib/file/books
+appfile_DATA = \
+       $(angband_files)
+endif
diff --git a/lib/file/books/book-000_en.txt b/lib/file/books/book-000_en.txt
new file mode 100644 (file)
index 0000000..c76012a
--- /dev/null
@@ -0,0 +1,139 @@
+#####R             /----------------------------------------\
+#####R            <  Adventurer's guide to the Middle-earth  >
+#####R             \----------------------------------------/
+
+Summary:
+*****/abook-20.txt*1[(a) The Towns]
+*****/bbook-20.txt*2[(b) Other strange and frightening places]
+*****/cbook-20.txt*3[(c) Equipment issues]
+*****/dbook-20.txt*4[(d) Macros]
+
+Introduction:
+
+Middle-earth is vast and mysterious, full of dangers but also full of
+rewards for the brave.
+
+New adventurers should know that pressing < and > can switch
+the wilderness view between a normal scale and a larger map. This map
+makes travelling safer and faster, but you can't enter wilderness
+dungeons from it.
+
+
+~~~~~1
+#####G(a) The Towns
+
+You start in a small village named Bree in the western part of the Middle-earth.
+Here you will also find the entrance to the Barrow-Downs, a fairly safe and
+simple dungeon.
+
+When the Barrow-Downs become too easy for you, and Bree too small,
+you might consider going to Lothlorien, the land of Galadriel. [[[[[BNote that]
+[[[[[Byou should take a lot of food with you, for it is a long journey.] You'll have
+to head south-east following the Moria mountain's chain, then walk around
+the forest of Fangorn to head north to finally find your destination. The Forest
+of Mirkwood (another dungeon) can be found to the north east of Lothlorien.
+
+If you survive this dangerous dungeon, you should head south, following
+the Anduin river. There, near the dark land of Mordor, you will find the
+great town of Gondor, Minas Anor. From there you can want to pay a "visit" to 
+the land of Mordor, which is east of Minas Anor.
+
+After Mordor you should finally travel to Gondolin, the hidden town of the
+Noldor. First go back to Bree, and then from there walk northeast and you
+will find it. From this city, you will be able to attack Angband, the
+dungeon of Morgoth, which is north west west of Gondolin.
+
+
+~~~~~2
+#####G(b) Other strange and frightening places
+
+The Old Forest to the west is the last remains of the big forests of the first
+age, but it has been corrupted. It is said it is guarded by a living tree.
+
+You may also wish to investigate the Orc Caves north of Bree; they are
+another place suitable for those finished with the Barrow-Downs. They also
+are rumored to hold great
+mysteries.
+
+The Maze: To the south of Bree there is a magical Maze. Many adventurers
+that ventured there never came back... It is rumored that a Minotaur is
+lurking down there, guarding an ancient and powerful artifact.
+Bring along digging equipment and some means to recall.
+
+Durin's Bane, the Balrog of Moria, guards the Mines of Moria, to the south east
+of Bree.
+
+During the Second Age of the world there was a great island called
+Numenor. The people who dwelt there were wise and powerful, but as time
+passed their last kings fell under the power of Sauron. Under Sauron's
+orders, they tried to attack Valinor, the blessed land, and for this
+Numenor was destroyed, swallowed by the sea. The ruins are still
+accessible, far out to sea to the west of Bree.
+
+Many other strange places wait to be explored by the valiant adventurer,
+but their locations are secret. You will have to find them yourself!
+
+
+~~~~~3
+#####G(c) Equipment issues
+
+Beware adventurer! If you plan to go down into the dungeons be prepared. Some
+items you will need badly.
+
+First think of some light, maybe a lantern is better than the torches.
+
+Second things to mention are your combat equipment. Sometimes the weapon and
+armor you got from your mentor are not enough for the nasties inside the
+dungeons.
+
+And third and most important, [[[[[Balways carry a shovel or other digger with you],
+because there is much rubble in the dungeons, which you cannot clear with
+your hands.
+
+~~~~~4
+#####G(d) Macros
+
+Spellcasters might find that pressing 4 keys (at least) to cast a spell is a
+lot, they are right. That is why there are macros. You can access the macro
+screen by pressing @. You can find help on the *****macrofaq.txt*0[macros] in the docs.
+
+Now you either have the hard way or the easy way.
+
+**The Hard Way**
+
+What the fellow adventurer should know is how to create a basic spell macro.
+Press @ to enter the macro screen.
+Press 4 to create a new macro.
+Press the key to bind the macro to, usually one uses the F* keys(you can combine
+them with the ctrl, shift, ... keys too)
+Enter the key sequence to be done for the macro.
+Press 2 to save the macro.
+
+Now a problem that might arise, imagine your macro looks like: mcaa*t
+to cast manathrust spell('m' to use skill, 'c' for cast a spell skill,
+'a' for first book, 'a' for first spell, *t to\85 target the first monster).
+This macro will break if you gain a new skill so that "Cast a spell" is no more
+the skill 'c', or if you get a new book. There is a way around that.
+When the game asks for a skill or a spell it allows you to press @ to enter
+the skill/spell name directly, so your macro would become:
+m@Cast a spell\r@Manathrust\r*t
+Now this will always work as long as one of your books have the spell in it.
+
+
+**The Easy Way**
+
+This time you will only use the macro recorder. To do that:
+Press $ to start it
+Now each key you press will be recorded, so press all keys you want.
+It is recommended to start your macro by pressing Escape key a few time, so
+if there are messages when you use the macro it will first erase them instead
+of screwing your macro :)
+it is also recommended to take advantage of the @ key when selecting skills or
+objects whenever the possibility is offered to you. It will make sure you
+always use the good object/skill even if it moves in your inventory.
+Once all keys are pressed press $ again to stop it.
+It you are satisfied with your macro now you get to press the key to bind it
+to.
+
+As in the Hard Way you must use the macro screen if you want to permanently
+save your macros.
diff --git a/lib/file/books/book-001_en.txt b/lib/file/books/book-001_en.txt
new file mode 100644 (file)
index 0000000..f84672c
--- /dev/null
@@ -0,0 +1,86 @@
+
+          Mordekainen's Magical Compendium of Deep Thought, Vol. 1
+          --------------------------------------------------------
+                                  
+If they ever come up with a swashbuckling School, I think one of the
+courses should be Laughing, Then Jumping Off Something.
+
+It takes a big man to cry, but it takes a bigger man to laugh at that man. 
+
+The people in the village were real poor, so none of the children had
+any toys. But this one little boy had gotten an old enema bag and
+filled it with rocks, and he would go around and whap the other
+children across the face with it. Man, I think my heart almost
+broke. Later the boy came up and offered to give me the toy. This was
+too much! I reached out my hand, but then he ran away. I chased him
+down and took the enema bag. He cried a little, but that's the way of
+these people.
+
+Dad always thought laughter was the best medicine, which I guess is
+why several of us died of tuberculosis.
+
+Maybe in order to understand mankind, we have to look at the word
+itself: "Mankind". Basically, it's made up of two separate words -
+"mank" and "ind". What do these words mean? It's a mystery, and
+that's why so is mankind.
+
+Ambition is like a frog sitting on a Venus Flytrap. The flytrap can
+bite and bite, but it won't bother the frog because it only has little
+tiny plant teeth. But some other stuff could happen and it could be
+like ambition.
+
+I'd rather be rich than stupid. 
+
+We tend to scoff at the beliefs of the ancients. But we can't scoff at
+them personally, to their faces, and this is what annoys me.
+
+Probably the earliest flyswatters were nothing more than some sort of
+striking surface attached to the end of a long stick.
+
+As the evening sky faded from a salmon color to a sort of flint gray,
+I thought back to the salmon I caught that morning, and how gray he
+was, and how I named him Flint.
+
+When I was a kid my favorite relative was Uncle Caveman. After school
+we'd all go play in his cave, and every once in a while he would eat
+one of us. It wasn't until later that I found out that Uncle Caveman
+was a bear.
+
+Why do there have to be rules for everything? It's gotten to the point
+that rules dominate just about every aspect of our lives.  In fact, it
+might be said that rules have become the foot-long sticks of mankind.
+
+If I had a mine shaft, I don't think I would just abandon it. There's
+got to be a better way.
+
+If I had a nickname, I think I would want it to be "Prince of
+Weasels", because then I could go up and bite people and they would
+turn around and go, "What the-?" And then they would recognize me, and
+go, "Oh, it's you, the Prince of Weasels."
+
+It's amazing to me that one of the world's most feared diseases would
+be carried by one of the world's smallest animals: the real tiny
+dog. 
+
+Sometimes life seems like a dream, especially when I look down and see
+that I forgot to put on my pants.
+
+I bet it was pretty hard to pick up girls if you had the Black Death. 
+
+It's fascinating to think that all around us there's an invisible
+world we can't even see. I'm speaking, of course, of the World of the
+Invisible Scary Skeletons.
+
+Whenever I hear the sparrow chirping, watch the woodpecker chirp,
+catch a chirping trout, or listen to the sad howl of the chirp rat, I
+think: Oh boy! I'm going insane again.
+
+He was the kind of man who was not ashamed to show affection. I guess
+that's what I hated about him.
+
+The next time I have meat and mashed potatoes, I think I'll put a very
+large blob of potatoes on my plate with just a little piece of
+meat. And if someone asks me why I didn't get more meat, I'll just
+say, "Oh, you mean this?" and pull out a big piece of meat from inside
+the blob of potatoes, where I've hidden it. Good magic trick, huh?
+
diff --git a/lib/file/books/book-001_jp.txt b/lib/file/books/book-001_jp.txt
new file mode 100644 (file)
index 0000000..755cd63
--- /dev/null
@@ -0,0 +1,87 @@
+
+               モルデンカイネン著『洞察の魔法大全』第1巻
+          -------------------------------------------------
+
+
+If they ever come up with a swashbuckling School, I think one of the
+courses should be Laughing, Then Jumping Off Something.
+
+It takes a big man to cry, but it takes a bigger man to laugh at that man. 
+
+The people in the village were real poor, so none of the children had
+any toys. But this one little boy had gotten an old enema bag and
+filled it with rocks, and he would go around and whap the other
+children across the face with it. Man, I think my heart almost
+broke. Later the boy came up and offered to give me the toy. This was
+too much! I reached out my hand, but then he ran away. I chased him
+down and took the enema bag. He cried a little, but that's the way of
+these people.
+
+Dad always thought laughter was the best medicine, which I guess is
+why several of us died of tuberculosis.
+
+Maybe in order to understand mankind, we have to look at the word
+itself: "Mankind". Basically, it's made up of two separate words -
+"mank" and "ind". What do these words mean? It's a mystery, and
+that's why so is mankind.
+
+Ambition is like a frog sitting on a Venus Flytrap. The flytrap can
+bite and bite, but it won't bother the frog because it only has little
+tiny plant teeth. But some other stuff could happen and it could be
+like ambition.
+
+I'd rather be rich than stupid. 
+
+We tend to scoff at the beliefs of the ancients. But we can't scoff at
+them personally, to their faces, and this is what annoys me.
+
+Probably the earliest flyswatters were nothing more than some sort of
+striking surface attached to the end of a long stick.
+
+As the evening sky faded from a salmon color to a sort of flint gray,
+I thought back to the salmon I caught that morning, and how gray he
+was, and how I named him Flint.
+
+When I was a kid my favorite relative was Uncle Caveman. After school
+we'd all go play in his cave, and every once in a while he would eat
+one of us. It wasn't until later that I found out that Uncle Caveman
+was a bear.
+
+Why do there have to be rules for everything? It's gotten to the point
+that rules dominate just about every aspect of our lives.  In fact, it
+might be said that rules have become the foot-long sticks of mankind.
+
+If I had a mine shaft, I don't think I would just abandon it. There's
+got to be a better way.
+
+If I had a nickname, I think I would want it to be "Prince of
+Weasels", because then I could go up and bite people and they would
+turn around and go, "What the-?" And then they would recognize me, and
+go, "Oh, it's you, the Prince of Weasels."
+
+It's amazing to me that one of the world's most feared diseases would
+be carried by one of the world's smallest animals: the real tiny
+dog. 
+
+Sometimes life seems like a dream, especially when I look down and see
+that I forgot to put on my pants.
+
+I bet it was pretty hard to pick up girls if you had the Black Death. 
+
+It's fascinating to think that all around us there's an invisible
+world we can't even see. I'm speaking, of course, of the World of the
+Invisible Scary Skeletons.
+
+Whenever I hear the sparrow chirping, watch the woodpecker chirp,
+catch a chirping trout, or listen to the sad howl of the chirp rat, I
+think: Oh boy! I'm going insane again.
+
+He was the kind of man who was not ashamed to show affection. I guess
+that's what I hated about him.
+
+The next time I have meat and mashed potatoes, I think I'll put a very
+large blob of potatoes on my plate with just a little piece of
+meat. And if someone asks me why I didn't get more meat, I'll just
+say, "Oh, you mean this?" and pull out a big piece of meat from inside
+the blob of potatoes, where I've hidden it. Good magic trick, huh?
+
diff --git a/lib/file/books/book-002_en.txt b/lib/file/books/book-002_en.txt
new file mode 100644 (file)
index 0000000..bddcf08
--- /dev/null
@@ -0,0 +1,83 @@
+
+       Mordekainen's Magical Compendium of Deep Thought, Vol. 2
+       --------------------------------------------------------
+
+
+It makes me mad when people say I turned and ran like a scared
+rabbit. Maybe it was like an angry rabbit, who was running to go fight
+in another fight, away from the first fight.
+
+Perhaps, if I am very lucky, the feeble efforts of my lifetime will
+someday be noticed, and maybe, in small way, they will be acknowledged
+as the greatest works of genius ever created by Man.
+
+Sometimes I think I'd be better off dead. No, wait, not me, you. 
+
+If you ever catch on fire, try to avoid looking in a mirror, because I
+bet that will really throw you into a panic.
+
+Children need encouragement. If a kid gets an answer right, tell him
+it was a lucky guess. That way he develops a good, lucky feeling.
+
+The crows seemed to be calling his name, thought Caw. 
+
+If your friend is already dead, and being eaten by vultures, I think
+it's okay to feed some bits of your friend to one of the vultures, to
+teach him to do some tricks. But only if you're serious about adopting
+the vulture.
+
+Broken promises don't upset me. I just think, why did they believe me?
+
+One thing vampire children have to be taught early on is, don't run
+with a wooden stake.
+
+Consider the daffodil. And while you're doing that, I'll be over here,
+looking through your stuff.
+
+I think my new thing will be to try to be a real happy guy. I'll just
+walk around being real happy until some jerk says something stupid to
+me.
+
+I hope some animal never bores a hole in my head and lays its eggs in
+my brain, because later you might think you're having a good idea but
+it's just eggs hatching.
+
+Whenever you read a good book, it's like the author is right there, in
+the room talking to you, which is why I don't like to read good books.
+
+What is it about a beautiful sunny afternoon, with the birds singing
+and the wind rustling through the leaves, that makes you want to get
+drunk?
+
+Instead of a trap door, what about a trap window? The guy looks out
+it, and if he leans too far, he falls out. Wait. I guess that's like a
+regular window.
+
+If I ever get real rich, I hope I'm not real mean to poor people, like
+I am now.
+
+Most of the time it was probably real bad being stuck down in a
+dungeon. But some days, when there was a bad storm outside, you'd look
+out your little window and think, "Boy, I'm glad I'm not out in that."
+
+Sometimes you have to be careful when selecting a new name for
+yourself. For instance, let's say you have chosen the nickname "Fly
+Head." Normally you would think that "fly Head" would mean a person
+who has beautiful swept-back features, as if flying through the
+air. But think again. Couldn't it also mean "having a head like a
+fly"? I'm afraid some people might actually think that.
+
+I hope that after I die, people will say of me: "That guy sure owed me
+a lot of money."
+
+The tired and thirsty prospector threw himself down at the edge of the
+watering hole and started to drink. But then he looked around and saw
+skulls and bones everywhere. "Uh-oh," he thought. "This watering hole
+is reserved for skeletons."
+
+Anytime I see something screech across a room and latch onto someone's
+neck, and the guy screams and tries to get it off, I have to laugh,
+because what is that thing.
+
+I hope life isn't a big joke, because I don't get it.
+
diff --git a/lib/file/books/book-002_jp.txt b/lib/file/books/book-002_jp.txt
new file mode 100644 (file)
index 0000000..315adc2
--- /dev/null
@@ -0,0 +1,83 @@
+
+               モルデンカイネン著『洞察の魔法大全』第2巻
+          -------------------------------------------------
+
+
+It makes me mad when people say I turned and ran like a scared
+rabbit. Maybe it was like an angry rabbit, who was running to go fight
+in another fight, away from the first fight.
+
+Perhaps, if I am very lucky, the feeble efforts of my lifetime will
+someday be noticed, and maybe, in small way, they will be acknowledged
+as the greatest works of genius ever created by Man.
+
+Sometimes I think I'd be better off dead. No, wait, not me, you. 
+
+If you ever catch on fire, try to avoid looking in a mirror, because I
+bet that will really throw you into a panic.
+
+Children need encouragement. If a kid gets an answer right, tell him
+it was a lucky guess. That way he develops a good, lucky feeling.
+
+The crows seemed to be calling his name, thought Caw. 
+
+If your friend is already dead, and being eaten by vultures, I think
+it's okay to feed some bits of your friend to one of the vultures, to
+teach him to do some tricks. But only if you're serious about adopting
+the vulture.
+
+Broken promises don't upset me. I just think, why did they believe me?
+
+One thing vampire children have to be taught early on is, don't run
+with a wooden stake.
+
+Consider the daffodil. And while you're doing that, I'll be over here,
+looking through your stuff.
+
+I think my new thing will be to try to be a real happy guy. I'll just
+walk around being real happy until some jerk says something stupid to
+me.
+
+I hope some animal never bores a hole in my head and lays its eggs in
+my brain, because later you might think you're having a good idea but
+it's just eggs hatching.
+
+Whenever you read a good book, it's like the author is right there, in
+the room talking to you, which is why I don't like to read good books.
+
+What is it about a beautiful sunny afternoon, with the birds singing
+and the wind rustling through the leaves, that makes you want to get
+drunk?
+
+Instead of a trap door, what about a trap window? The guy looks out
+it, and if he leans too far, he falls out. Wait. I guess that's like a
+regular window.
+
+If I ever get real rich, I hope I'm not real mean to poor people, like
+I am now.
+
+Most of the time it was probably real bad being stuck down in a
+dungeon. But some days, when there was a bad storm outside, you'd look
+out your little window and think, "Boy, I'm glad I'm not out in that."
+
+Sometimes you have to be careful when selecting a new name for
+yourself. For instance, let's say you have chosen the nickname "Fly
+Head." Normally you would think that "fly Head" would mean a person
+who has beautiful swept-back features, as if flying through the
+air. But think again. Couldn't it also mean "having a head like a
+fly"? I'm afraid some people might actually think that.
+
+I hope that after I die, people will say of me: "That guy sure owed me
+a lot of money."
+
+The tired and thirsty prospector threw himself down at the edge of the
+watering hole and started to drink. But then he looked around and saw
+skulls and bones everywhere. "Uh-oh," he thought. "This watering hole
+is reserved for skeletons."
+
+Anytime I see something screech across a room and latch onto someone's
+neck, and the guy screams and tries to get it off, I have to laugh,
+because what is that thing.
+
+I hope life isn't a big joke, because I don't get it.
+
diff --git a/lib/file/books/book-003_en.txt b/lib/file/books/book-003_en.txt
new file mode 100644 (file)
index 0000000..c53b1b3
--- /dev/null
@@ -0,0 +1,90 @@
+
+       Mordekainen's Magical Compendium of Deep Thought, Vol. 3
+       --------------------------------------------------------
+
+
+I think my new thing will be to try to be a real happy guy. I'll just
+walk around being real happy until some jerk says something stupid to
+me.  
+
+When you're going up the stairs and you take a step, kick the other
+leg up high behind you to keep people from following too close.
+
+I wonder if angels believe in ghosts. 
+
+I don't understand people who say life is a mystery, because what is
+it they want to know?
+
+I think people tend to forget that trees are living creatures. They're
+sort of like dogs. Huge, quiet, motionless dogs, with bark instead of
+fur.
+
+Sometimes I think the world has gone completely mad. And then I think,
+"Aw, who cares?" And then I think, "Hey, what's for supper?"
+
+If a kid asks where rain comes from, I think a cute thing to tell him
+is "God is crying". And if he asks why God is crying, another cute
+thing to tell him is "Probably because of something you did".
+
+Contrary to popular belief, the most dangerous animal is not the lion
+or tiger or even the elephant. The most dangerous animal is a shark
+riding on an elephant, just trampling and eating everything they see.
+
+As I bit into the nectarine, it had a crisp juiciness about it that
+was very pleasurable- until I realized it wasn't a nectarine at all,
+but a HUMAN HEAD!!
+
+Anytime I see something screech across a room and latch onto someone's
+neck, and the guy screams and tries to get it off, I have to laugh,
+because what _is_ that thing?!
+
+If you define cowardice as running away at the first sign of danger,
+screaming and tripping and begging for mercy, then yes, Mister Brave
+Man, I guess I am a coward.
+
+Blow ye winds, like the trumpet blows, but without that noise. 
+
+The face of a child can say it all, especially the mouth part of the face. 
+
+When I heard that trees grow a new "ring" for each year they live, I
+thought, we humans are kind of like that; we grow a new layer of skin
+each year; and after many years we are thick and unwieldy from all our
+skin layers.
+
+It's too bad that whole families have been torn apart by something as
+simple as wild dogs.
+
+Even though he was an enemy of mine, I had to admit that what he had
+accomplished was a brilliant piece of strategy. First, he punched me,
+then he kicked me, then he punched me again.
+
+To me, truth is not some vague, foggy notion. Truth is real. And, at
+the same unreal. Fiction and fact and everything in-between, plus some
+things I can't remember, all rolled into one big "thing". This is
+truth, to me.
+
+If you're ever stuck in some thick undergrowth, in your underwear,
+don't stop and start thinking of what other words have "under" in
+them, because that's probably the first sign of jungle madness.
+
+Sometimes the beauty of the world is so overwhelming, I just want to
+throw back my head and gargle. Just gargle and gargle, and I don't
+care who hears me, because I am beautiful.
+
+We used to laugh at Grandpa when he'd head off to go fishing. But we
+wouldn't be laughing when he'd come back with some whore he picked up
+in town.
+
+I think in one of my previous lives I was a mighty king, because I
+like people that do what I say.
+
+A man doesn't automatically get my respect. He has to get down in the
+dirt and beg for it.
+
+People think it would be fun to be a bird because you could fly. But
+they forget the negative side, which is the preening.
+
+When I think back on all the blessings I have been given in my life, I
+can't think of a single one, unless you count that rattlesnake that
+granted me all those wishes.
+
diff --git a/lib/file/books/book-003_jp.txt b/lib/file/books/book-003_jp.txt
new file mode 100644 (file)
index 0000000..6ac78fa
--- /dev/null
@@ -0,0 +1,90 @@
+
+               モルデンカイネン著『洞察の魔法大全』第3巻
+          -------------------------------------------------
+
+
+I think my new thing will be to try to be a real happy guy. I'll just
+walk around being real happy until some jerk says something stupid to
+me.  
+
+When you're going up the stairs and you take a step, kick the other
+leg up high behind you to keep people from following too close.
+
+I wonder if angels believe in ghosts. 
+
+I don't understand people who say life is a mystery, because what is
+it they want to know?
+
+I think people tend to forget that trees are living creatures. They're
+sort of like dogs. Huge, quiet, motionless dogs, with bark instead of
+fur.
+
+Sometimes I think the world has gone completely mad. And then I think,
+"Aw, who cares?" And then I think, "Hey, what's for supper?"
+
+If a kid asks where rain comes from, I think a cute thing to tell him
+is "God is crying". And if he asks why God is crying, another cute
+thing to tell him is "Probably because of something you did".
+
+Contrary to popular belief, the most dangerous animal is not the lion
+or tiger or even the elephant. The most dangerous animal is a shark
+riding on an elephant, just trampling and eating everything they see.
+
+As I bit into the nectarine, it had a crisp juiciness about it that
+was very pleasurable- until I realized it wasn't a nectarine at all,
+but a HUMAN HEAD!!
+
+Anytime I see something screech across a room and latch onto someone's
+neck, and the guy screams and tries to get it off, I have to laugh,
+because what _is_ that thing?!
+
+If you define cowardice as running away at the first sign of danger,
+screaming and tripping and begging for mercy, then yes, Mister Brave
+Man, I guess I am a coward.
+
+Blow ye winds, like the trumpet blows, but without that noise. 
+
+The face of a child can say it all, especially the mouth part of the face. 
+
+When I heard that trees grow a new "ring" for each year they live, I
+thought, we humans are kind of like that; we grow a new layer of skin
+each year; and after many years we are thick and unwieldy from all our
+skin layers.
+
+It's too bad that whole families have been torn apart by something as
+simple as wild dogs.
+
+Even though he was an enemy of mine, I had to admit that what he had
+accomplished was a brilliant piece of strategy. First, he punched me,
+then he kicked me, then he punched me again.
+
+To me, truth is not some vague, foggy notion. Truth is real. And, at
+the same unreal. Fiction and fact and everything in-between, plus some
+things I can't remember, all rolled into one big "thing". This is
+truth, to me.
+
+If you're ever stuck in some thick undergrowth, in your underwear,
+don't stop and start thinking of what other words have "under" in
+them, because that's probably the first sign of jungle madness.
+
+Sometimes the beauty of the world is so overwhelming, I just want to
+throw back my head and gargle. Just gargle and gargle, and I don't
+care who hears me, because I am beautiful.
+
+We used to laugh at Grandpa when he'd head off to go fishing. But we
+wouldn't be laughing when he'd come back with some whore he picked up
+in town.
+
+I think in one of my previous lives I was a mighty king, because I
+like people that do what I say.
+
+A man doesn't automatically get my respect. He has to get down in the
+dirt and beg for it.
+
+People think it would be fun to be a bird because you could fly. But
+they forget the negative side, which is the preening.
+
+When I think back on all the blessings I have been given in my life, I
+can't think of a single one, unless you count that rattlesnake that
+granted me all those wishes.
+
diff --git a/lib/file/books/book-004_en.txt b/lib/file/books/book-004_en.txt
new file mode 100644 (file)
index 0000000..6a648a4
--- /dev/null
@@ -0,0 +1,270 @@
+
+                       Artifact Lore, Vol. I
+                          Ancient Weapons
+                       ---------------------
+
+
+  Notes by an annotator Mumei: 
+       This list is ancient.
+       In modern times, it includes things that have already been lost,
+       things that have been newly created, things that have been
+       brought in from the outside world, and things that have changed
+       over the years.
+
+  The Longsword 'Ringil' (4d5) (+22,+25)
+       The Sword of Fingolfin (High-Elf).  When wielded it will
+       haste its wielder.  It is a blade of such deathly cold that 
+       it shines bright white acting as a permanent light and 
+       delivering cold criticals.  It slays evil, demons, undead
+       and trolls.  Allows you to resist cold, regenerate mana and  
+       hit points more quickly with no extra food consumption. Also
+       lets you see invisible and be immune to paralyzation.  Being
+       made of white eog, it is capable of casting Ice Storms.
+
+  The Longsword 'Anduril' (3d5) (+10,+15) [+5]
+       The  Sword of Aragorn  the  Dunadan  Ranger  and  King.   It 
+       increases your  strength  to  match  true  Kingly  strength,
+       increases  armour class by +5. Being the 'Flame of the West'
+       it delivers  heat criticals and defends  against  fire.   It 
+       slays  evil, orcs and trolls. It allows you to see invisible
+       and avoid paralyzation. So near to the element  fire  is the
+       blade, that  Fire  Balls  can  be  cast  from  its   searing
+       surface.
+
+  The Lead-filled Mace 'Grond' (9d9) (+25,+25) [+10]
+       The Hammer  of  the  Underworld,  this  is  Morgoth's  chief
+       weapon. It weighs so much that it  slows  anything  of  less
+       than godly status. It is so awesome that it  aggravates  all  
+       that see it. It makes it's wielder see all and  resist  all.
+       It slays all of Morgoths personal creations of orcs, trolls,
+       and demons and it executes  dragons  doing five times normal
+       damage against them, (it can kill all but a very few dragons
+       in one mighty blow!).   Plus it causes impact criticals that 
+       cause  earthquakes and it can  tunnel  through solid granite
+       walls!
+
+  The Two-Handed Sword 'Gurthang' (3d6) (+13,+17)
+       This Iron of  Death  belonging  to  Turin  Turambar, made of 
+       black eog, was designed to slay Dragons (and Trolls),  doing
+       five times normal damage against dragons. It gives  you  the 
+       strength to wield it, regenerates your  hit  points and mana 
+       at no extra cost and allows you to be free of paralyzation.
+
+  The Two-Handed Sword 'Mormegil' (6d7) (0,0) [-20]
+       This evil black sword is heavily cursed, slowing its wielder
+       and aggravating all that see it...
+
+  The Broadsword 'Arunruth' (2d5) (+20,+12)
+       This Sword of Accuracy  rarely  misses.  It  increases  the
+       wielders dexterity, saves from falls, slays orcs and demons,
+       and protects from paralyzation.
+
+  The Broadsword 'Glamdring' (2d5) (+10,+15)
+       This High-Elven sword (mate to Orcrist) was made during foul
+       orc wars of long ago. It was once  wielded  by  Gandalf  the
+       Grey Wizard. It slays orcs and  other  evil, shining  bright 
+       red continuously, which aids  searching  and decreases  food  
+       consumption. Its element is flame, and it gives   resistance
+       to flame to the wielder, and slays those who have not.
+
+  The Broadsword 'Orcrist' (2d5) (+10,+15)
+       This High-Elven sword (mate to Glamdring)  was  made  during
+       foul orc wars of long ago.  It was once  wielded  by  Thorin 
+       Oakenshield the Dwarf-King-Under-the-Mountain. It slays orcs 
+       and  other  evil,  shining  bright white continuously, which
+       decreases food consumption, plus  making  the  wielder  more 
+       stealthy. Being of the element frost, it protects from cold,
+       and slays non-cold based creatures.
+
+  The Broadsword 'Aeglin' (2d5) (+12,+16)
+       This High-Elven sword, is the long, lost and forgotten third
+       mate to Orcrist and Glamdring. It is also the most powerful.
+       Like Glamdring and Orcrist, made  during  the  Orc-wars,  it 
+       slays Orcish-kind, shining  bright  blue continuously, which
+       decreases food consumption and aiding  searching.  Being  of
+       electric element, it delivers lightning criticals, which  it
+       also defends against.
+
+  The Long Bow 'Belthronding' (+20,+22) (+3)
+       This Noldorin black-yew bow, belonged to the greatest elven
+       archer, Beleg Cuthalion, who was slain by his own blade, by
+       his best friend Turin Turumbar. The bow  increases  stealth 
+       and dexterity, and rarely missed its target.
+
+  The Long Bow of Bard (+17,+19)
+       This bow of men gives free action and increased dexterity.
+
+  The Light Crossbow 'Cubragol' (+10,+14)
+       This amazing bow of fire hastes its  wielder  and  brands
+       all bolts with its element.
+
+  The Bastard Sword 'Calris' (5d4) (-20,+20)
+       This sword of Lungorthin the Balrog of White  Flame,  is  an
+       evil cursed sword that needs great mastering to control  its
+       powers. If mastered it can execute dragons, slay other  evil
+       including demons and trolls, this naturally aggravates them.
+       Also it gives its wielder far greater internal constitution.
+
+  The Spear 'Aeglos' (3d6) (+15,+25) [+5]
+       This  Snow-thorn of Gil-Galad the  High-Elf,  delivers  very
+       deep cold-criticals, while  protecting  you  from  cold  and
+       increasing  your armour class.  Being  elvish  it  naturally 
+       slays orcs and trolls. It  increases  the  wielders  wisdom, 
+       slows their digestion and frees their actions  from  holding
+       forces of evil, also casting Frost Balls occasionally.
+
+  The Spear 'Nimloth' (1d6) (+11,+13) (+3 to stealth)
+       This elven spear, branded with frost, allows  its  wielder
+       to creep up on the Undead and Slay them.
+
+  The Dagger 'Angrist' (2d5) (+10,+15) [+5]
+       This Iron-cleaver of Beren the Edain, increases and sustains
+       dexterity, increases you protection,  prevents  paralyzation
+       and slays orcs and trolls.
+
+  The Small sword 'Sting' (1d6) (+7,+8)
+       This  small weapon is  one of the  most powerful weapons  of 
+       Westernesse.   Once wielded by Bilbo and Frodo  Baggins  (of
+       Hobbit kind),  Sting slays undead,  evil, and orcs and  also 
+       shines a continuous, bright blue. It increases the wielder's
+       physical statistics  and  its piercing blue light  lights up 
+       those normally invisible to sight.
+
+  The Great Axe of Durin (4d4) (+10,+20) [+15]
+       This  Wonderful  Dwarven  Axe was once  wielded by Durin the 
+       Deathless (Father  and  King  of  the  Dwarves),  gives  its 
+       wielder  high protection, executes dragons, while  resisting
+       fire and acid.  It slays  demons,  trolls  and  orcs,  frees
+       action and increases constitution.
+
+  The War Hammer of Aule (5d5) (+19,+21) [+5]
+       This is the great war hammer of the deity,  Aule  the Smith.
+       Forged in his great furnaces  it  delivers  Shock  criticals
+       causing five times normal damage to those not  resistant  to
+       this element, and even then it executes dragons, slays evil,
+       demons and undead. It resists fire, cold, acid and lightning
+       and allows you to see invisible and be free of paralyzation.
+       It increases its wielder's wisdom  so  that  one may  choose 
+       wisely what to slay with it.  Truly an awesome weapon.
+
+  The Two-Handed Great Flail 'Thunderfist' (3d6) (+5,+18)
+       This weapon of Electricity and  Flame,  delivers  shock  and
+       heat criticals, delivering five times or three times  normal
+       damage against the respective types of creatures, also slays
+       animals, trolls and orcs.  It also gives the  wielder  great
+       strength.
+
+  The Morningstar 'Bloodspike' (2d6) (+8,+22)
+       This Bloody weapon slays animals, trolls, and orcs.  It allows
+       you to see invisible creatures, as well as giving the wielder  
+       great strength.
+
+  The Quarterstaff 'Nar-i-vagil' (1d10) (+10,+20)
+       This fiery staff slays animals and resists fire, doing times
+       fire criticals. It also increases the wielders intelligence.
+
+  The Blade of Chaos 'Doomcaller' (6d5) (+18,+28) [-50]
+       This deadly blade  calls  doom  to  all  who  see  it,  this 
+       naturally aggravates them. It shows you  wherever a creature
+       is,  be  it  invisible  or  blocked  by  a  wall. It resists
+       all elements and executes dragons, slays evil,  animal,  orc
+       and troll. It delivers cold criticals, but severely  impedes
+       its wielders health.
+
+  The Three Daggers, 'Narthanc', 'Nimthanc', 'Dethanc' (1d4) (+4,+6)
+       These elemental daggers  of  flame,  frost, and  electricity
+       respectively do  their    elemental  criticals,  and  defend  
+       against them.  They also cast bolts of their element often.
+
+  The Dagger of Rilia (2d4) (+4,+3)
+       This ancient, and poisonous  dagger  casts  stinking  clouds
+       with great frequency.
+
+  The Dagger 'Belangil' (2d4) (+6,+9)
+       This nimble weapon of cold increases the wielder's dexterity
+       and regeneration, while slowing  digestion.  Being  of  dark 
+       origins it see alls invisible and casts frost balls.
+
+  The Battle Axe of Balli Stonehand (3d6) (+8,+11) [+5]
+       This Dwarvish Battle axe protects from elements,  falls  and
+       the invisible. It slays all demons, trolls and orcs,  giving
+       even dwarves the stealth, strength and  constitution  to  do
+       so, never letting holding spells affect its  use in a fight.
+
+  The Battle Axe 'Lotharang' (2d8) (+4,+3)
+       This petty-dwarvish axe, slays orcs and  trolls,  increasing
+       strength and dexterity. For those of  faint  heart  it  also
+       cures medium wounds and cuts.
+
+  The Morningstar 'Firestar' (2d6) (+5,+7) [+2]
+       This weapon of flame casts fire balls.
+
+  The Quarterstaff 'Eriril' (1d10) (+3,+5)
+       This staff of people who believe in the power of  mind  over
+       matter, greatly increases wisdom and intelligence and  gives
+       the power to identify. It also sees  invisible and slays all
+       evil.
+
+  The Longsword 'Elvagil' (2d5) (+2,+7)
+       This joyful sword increases dexterity, charisma and stealth.
+       It protects from falls and the invisible, and slays orcs and
+       trolls.
+
+  The Glaive of Pain (9d6) (+0,+30)
+       This weapon is designed to cause pain  to  anything  without 
+       discrimination.
+
+  The Lance of the Eorlingas (3d8) (+3,+21)
+       This heavy lance is suprisingly easy  to  control,  allowing 
+       slaughter of orcs, trolls and other evil (visible or not).
+
+  The Broad Axe 'Barukkheled' (2d6) (+13,+19)
+       This beautiful axe slays orcs, trolls, giants and other evil
+       (visible or not),  while  greatly  increasing  the  wielders
+       internal constitution.
+
+  The Trident of Wrath (3d8) (+16,+18)
+       This extremely heavy and dangerous trident belonging to  the
+       greatest Maiar spirit,  Osse,  slaughters  evil  and  undead
+       without mercy wherever they hide, and increases the wielder's
+       strength and dexterity.
+
+  The Scimitar 'Haradekket' (2d5) (+9,+11)
+       This sword of the south slays the invisible undead, evil and
+       animals, and increases the wielder's dexterity. In addition,
+       the  magically enhanced  blade  is  rumored  to  give  extra 
+       attacks in combat.
+
+  The Lochaber Axe 'Mundwine' (3d8) (+12,+17)
+       This strong friend in battle, slays  evil  and  resists  the 
+       elements.
+
+  The Cutlass 'Gondricam' (1d7) (+10,+11)
+       This defender increases the wielders dexterity.
+
+  The Sabre 'Careth Asdriag' (1d7) (+6,+8)      
+       This  lightning-quick blade  slays dragons,  giants, trolls,
+       orcs, and animals.
+
+  The Rapier 'Forasgil' (1d6) (+12,+19)
+       This glittering ice-blade also  slays  animals  as  well  as 
+       lighting the way.
+
+  The Executioner's Sword 'Crisdurian' (4d5) (+18,+19)
+       This executer slays evil, invisible undead, dragons,  giants
+       orcs and trolls.
+
+  The Flail 'Totila' (3d6) (+6,+8) (+2)
+       This flaming flail slays evil  in  stealth.  It  also  casts 
+       confusion.
+
+  The Short sword 'Gilettar' (1d7) (+3,+7)
+       This roguish sword  gives  better  regeneration  and  slower
+       digestion, slaying all animals with uncanny speed.
+
+  The Katana 'Aglarang' (8d4) (+0,+0)
+       This super-light and sharp  katana   greatly  increases  the
+       wielders dexterity and sustains it. Rarely does the  wielder
+       get less than four attacks a round with  it,  and  often  as
+       many as six!
+
diff --git a/lib/file/books/book-004_jp.txt b/lib/file/books/book-004_jp.txt
new file mode 100644 (file)
index 0000000..a1d3bb5
--- /dev/null
@@ -0,0 +1,268 @@
+
+                     アーティファクトの伝承 第1巻
+                                武器編
+                 -----------------------------------
+
+
+  無名の注釈者によるメモ:
+       このリストは太古のものである。
+       現代においては既に失われたもの、新たに作られたもの、外の世界
+       から持ち込まれたもの、そして年月の間に変質したものが含まれる。
+
+  The Longsword 'Ringil' (4d5) (+22,+25)
+       The Sword of Fingolfin (High-Elf).  When wielded it will
+       haste its wielder.  It is a blade of such deathly cold that 
+       it shines bright white acting as a permanent light and 
+       delivering cold criticals.  It slays evil, demons, undead
+       and trolls.  Allows you to resist cold, regenerate mana and  
+       hit points more quickly with no extra food consumption. Also
+       lets you see invisible and be immune to paralyzation.  Being
+       made of white eog, it is capable of casting Ice Storms.
+
+  The Longsword 'Anduril' (3d5) (+10,+15) [+5]
+       The  Sword of Aragorn  the  Dunadan  Ranger  and  King.   It 
+       increases your  strength  to  match  true  Kingly  strength,
+       increases  armour class by +5. Being the 'Flame of the West'
+       it delivers  heat criticals and defends  against  fire.   It 
+       slays  evil, orcs and trolls. It allows you to see invisible
+       and avoid paralyzation. So near to the element  fire  is the
+       blade, that  Fire  Balls  can  be  cast  from  its   searing
+       surface.
+
+  The Lead-filled Mace 'Grond' (9d9) (+25,+25) [+10]
+       The Hammer  of  the  Underworld,  this  is  Morgoth's  chief
+       weapon. It weighs so much that it  slows  anything  of  less
+       than godly status. It is so awesome that it  aggravates  all  
+       that see it. It makes it's wielder see all and  resist  all.
+       It slays all of Morgoths personal creations of orcs, trolls,
+       and demons and it executes  dragons  doing five times normal
+       damage against them, (it can kill all but a very few dragons
+       in one mighty blow!).   Plus it causes impact criticals that 
+       cause  earthquakes and it can  tunnel  through solid granite
+       walls!
+
+  The Two-Handed Sword 'Gurthang' (3d6) (+13,+17)
+       This Iron of  Death  belonging  to  Turin  Turambar, made of 
+       black eog, was designed to slay Dragons (and Trolls),  doing
+       five times normal damage against dragons. It gives  you  the 
+       strength to wield it, regenerates your  hit  points and mana 
+       at no extra cost and allows you to be free of paralyzation.
+
+  The Two-Handed Sword 'Mormegil' (6d7) (0,0) [-20]
+       This evil black sword is heavily cursed, slowing its wielder
+       and aggravating all that see it...
+
+  The Broadsword 'Arunruth' (2d5) (+20,+12)
+       This Sword of Accuracy  rarely  misses.  It  increases  the
+       wielders dexterity, saves from falls, slays orcs and demons,
+       and protects from paralyzation.
+
+  The Broadsword 'Glamdring' (2d5) (+10,+15)
+       This High-Elven sword (mate to Orcrist) was made during foul
+       orc wars of long ago. It was once  wielded  by  Gandalf  the
+       Grey Wizard. It slays orcs and  other  evil, shining  bright 
+       red continuously, which aids  searching  and decreases  food  
+       consumption. Its element is flame, and it gives   resistance
+       to flame to the wielder, and slays those who have not.
+
+  The Broadsword 'Orcrist' (2d5) (+10,+15)
+       This High-Elven sword (mate to Glamdring)  was  made  during
+       foul orc wars of long ago.  It was once  wielded  by  Thorin 
+       Oakenshield the Dwarf-King-Under-the-Mountain. It slays orcs 
+       and  other  evil,  shining  bright white continuously, which
+       decreases food consumption, plus  making  the  wielder  more 
+       stealthy. Being of the element frost, it protects from cold,
+       and slays non-cold based creatures.
+
+  The Broadsword 'Aeglin' (2d5) (+12,+16)
+       This High-Elven sword, is the long, lost and forgotten third
+       mate to Orcrist and Glamdring. It is also the most powerful.
+       Like Glamdring and Orcrist, made  during  the  Orc-wars,  it 
+       slays Orcish-kind, shining  bright  blue continuously, which
+       decreases food consumption and aiding  searching.  Being  of
+       electric element, it delivers lightning criticals, which  it
+       also defends against.
+
+  The Long Bow 'Belthronding' (+20,+22) (+3)
+       This Noldorin black-yew bow, belonged to the greatest elven
+       archer, Beleg Cuthalion, who was slain by his own blade, by
+       his best friend Turin Turumbar. The bow  increases  stealth 
+       and dexterity, and rarely missed its target.
+
+  The Long Bow of Bard (+17,+19)
+       This bow of men gives free action and increased dexterity.
+
+  The Light Crossbow 'Cubragol' (+10,+14)
+       This amazing bow of fire hastes its  wielder  and  brands
+       all bolts with its element.
+
+  The Bastard Sword 'Calris' (5d4) (-20,+20)
+       This sword of Lungorthin the Balrog of White  Flame,  is  an
+       evil cursed sword that needs great mastering to control  its
+       powers. If mastered it can execute dragons, slay other  evil
+       including demons and trolls, this naturally aggravates them.
+       Also it gives its wielder far greater internal constitution.
+
+  The Spear 'Aeglos' (3d6) (+15,+25) [+5]
+       This  Snow-thorn of Gil-Galad the  High-Elf,  delivers  very
+       deep cold-criticals, while  protecting  you  from  cold  and
+       increasing  your armour class.  Being  elvish  it  naturally 
+       slays orcs and trolls. It  increases  the  wielders  wisdom, 
+       slows their digestion and frees their actions  from  holding
+       forces of evil, also casting Frost Balls occasionally.
+
+  The Spear 'Nimloth' (1d6) (+11,+13) (+3 to stealth)
+       This elven spear, branded with frost, allows  its  wielder
+       to creep up on the Undead and Slay them.
+
+  The Dagger 'Angrist' (2d5) (+10,+15) [+5]
+       This Iron-cleaver of Beren the Edain, increases and sustains
+       dexterity, increases you protection,  prevents  paralyzation
+       and slays orcs and trolls.
+
+  The Small sword 'Sting' (1d6) (+7,+8)
+       This  small weapon is  one of the  most powerful weapons  of 
+       Westernesse.   Once wielded by Bilbo and Frodo  Baggins  (of
+       Hobbit kind),  Sting slays undead,  evil, and orcs and  also 
+       shines a continuous, bright blue. It increases the wielder's
+       physical statistics  and  its piercing blue light  lights up 
+       those normally invisible to sight.
+
+  The Great Axe of Durin (4d4) (+10,+20) [+15]
+       This  Wonderful  Dwarven  Axe was once  wielded by Durin the 
+       Deathless (Father  and  King  of  the  Dwarves),  gives  its 
+       wielder  high protection, executes dragons, while  resisting
+       fire and acid.  It slays  demons,  trolls  and  orcs,  frees
+       action and increases constitution.
+
+  The War Hammer of Aule (5d5) (+19,+21) [+5]
+       This is the great war hammer of the deity,  Aule  the Smith.
+       Forged in his great furnaces  it  delivers  Shock  criticals
+       causing five times normal damage to those not  resistant  to
+       this element, and even then it executes dragons, slays evil,
+       demons and undead. It resists fire, cold, acid and lightning
+       and allows you to see invisible and be free of paralyzation.
+       It increases its wielder's wisdom  so  that  one may  choose 
+       wisely what to slay with it.  Truly an awesome weapon.
+
+  The Two-Handed Great Flail 'Thunderfist' (3d6) (+5,+18)
+       This weapon of Electricity and  Flame,  delivers  shock  and
+       heat criticals, delivering five times or three times  normal
+       damage against the respective types of creatures, also slays
+       animals, trolls and orcs.  It also gives the  wielder  great
+       strength.
+
+  The Morningstar 'Bloodspike' (2d6) (+8,+22)
+       This Bloody weapon slays animals, trolls, and orcs.  It allows
+       you to see invisible creatures, as well as giving the wielder  
+       great strength.
+
+  The Quarterstaff 'Nar-i-vagil' (1d10) (+10,+20)
+       This fiery staff slays animals and resists fire, doing times
+       fire criticals. It also increases the wielders intelligence.
+
+  The Blade of Chaos 'Doomcaller' (6d5) (+18,+28) [-50]
+       This deadly blade  calls  doom  to  all  who  see  it,  this 
+       naturally aggravates them. It shows you  wherever a creature
+       is,  be  it  invisible  or  blocked  by  a  wall. It resists
+       all elements and executes dragons, slays evil,  animal,  orc
+       and troll. It delivers cold criticals, but severely  impedes
+       its wielders health.
+
+  The Three Daggers, 'Narthanc', 'Nimthanc', 'Dethanc' (1d4) (+4,+6)
+       These elemental daggers  of  flame,  frost, and  electricity
+       respectively do  their    elemental  criticals,  and  defend  
+       against them.  They also cast bolts of their element often.
+
+  The Dagger of Rilia (2d4) (+4,+3)
+       This ancient, and poisonous  dagger  casts  stinking  clouds
+       with great frequency.
+
+  The Dagger 'Belangil' (2d4) (+6,+9)
+       This nimble weapon of cold increases the wielder's dexterity
+       and regeneration, while slowing  digestion.  Being  of  dark 
+       origins it see alls invisible and casts frost balls.
+
+  The Battle Axe of Balli Stonehand (3d6) (+8,+11) [+5]
+       This Dwarvish Battle axe protects from elements,  falls  and
+       the invisible. It slays all demons, trolls and orcs,  giving
+       even dwarves the stealth, strength and  constitution  to  do
+       so, never letting holding spells affect its  use in a fight.
+
+  The Battle Axe 'Lotharang' (2d8) (+4,+3)
+       This petty-dwarvish axe, slays orcs and  trolls,  increasing
+       strength and dexterity. For those of  faint  heart  it  also
+       cures medium wounds and cuts.
+
+  The Morningstar 'Firestar' (2d6) (+5,+7) [+2]
+       This weapon of flame casts fire balls.
+
+  The Quarterstaff 'Eriril' (1d10) (+3,+5)
+       This staff of people who believe in the power of  mind  over
+       matter, greatly increases wisdom and intelligence and  gives
+       the power to identify. It also sees  invisible and slays all
+       evil.
+
+  The Longsword 'Elvagil' (2d5) (+2,+7)
+       This joyful sword increases dexterity, charisma and stealth.
+       It protects from falls and the invisible, and slays orcs and
+       trolls.
+
+  The Glaive of Pain (9d6) (+0,+30)
+       This weapon is designed to cause pain  to  anything  without 
+       discrimination.
+
+  The Lance of the Eorlingas (3d8) (+3,+21)
+       This heavy lance is suprisingly easy  to  control,  allowing 
+       slaughter of orcs, trolls and other evil (visible or not).
+
+  The Broad Axe 'Barukkheled' (2d6) (+13,+19)
+       This beautiful axe slays orcs, trolls, giants and other evil
+       (visible or not),  while  greatly  increasing  the  wielders
+       internal constitution.
+
+  The Trident of Wrath (3d8) (+16,+18)
+       This extremely heavy and dangerous trident belonging to  the
+       greatest Maiar spirit,  Osse,  slaughters  evil  and  undead
+       without mercy wherever they hide, and increases the wielder's
+       strength and dexterity.
+
+  The Scimitar 'Haradekket' (2d5) (+9,+11)
+       This sword of the south slays the invisible undead, evil and
+       animals, and increases the wielder's dexterity. In addition,
+       the  magically enhanced  blade  is  rumored  to  give  extra 
+       attacks in combat.
+
+  The Lochaber Axe 'Mundwine' (3d8) (+12,+17)
+       This strong friend in battle, slays  evil  and  resists  the 
+       elements.
+
+  The Cutlass 'Gondricam' (1d7) (+10,+11)
+       This defender increases the wielders dexterity.
+
+  The Sabre 'Careth Asdriag' (1d7) (+6,+8)      
+       This  lightning-quick blade  slays dragons,  giants, trolls,
+       orcs, and animals.
+
+  The Rapier 'Forasgil' (1d6) (+12,+19)
+       This glittering ice-blade also  slays  animals  as  well  as 
+       lighting the way.
+
+  The Executioner's Sword 'Crisdurian' (4d5) (+18,+19)
+       This executer slays evil, invisible undead, dragons,  giants
+       orcs and trolls.
+
+  The Flail 'Totila' (3d6) (+6,+8) (+2)
+       This flaming flail slays evil  in  stealth.  It  also  casts 
+       confusion.
+
+  The Short sword 'Gilettar' (1d7) (+3,+7)
+       This roguish sword  gives  better  regeneration  and  slower
+       digestion, slaying all animals with uncanny speed.
+
+  The Katana 'Aglarang' (8d4) (+0,+0)
+       This super-light and sharp  katana   greatly  increases  the
+       wielders dexterity and sustains it. Rarely does the  wielder
+       get less than four attacks a round with  it,  and  often  as
+       many as six!
+
diff --git a/lib/file/books/book-005_en.txt b/lib/file/books/book-005_en.txt
new file mode 100644 (file)
index 0000000..739217b
--- /dev/null
@@ -0,0 +1,148 @@
+
+                       Artifact Lore, Vol. II
+                           Ancient Armor
+                       ----------------------
+
+
+  Notes by an annotator Mumei: 
+       This list is ancient.
+       In modern times, it includes things that have already been lost,
+       things that have been newly created, things that have been
+       brought in from the outside world, and things that have changed
+       over the years.
+
+  Adamantite Plate Mail 'Soulkeeper' [40,+20]
+       This amazing armour protects your soul from cold,  and  from
+       life level loss. It is also capable of fully healing you.
+
+  The Pair of Hard Leather Boots of Feanor [3,+20]
+       These amazing boots belonging to Feanor the High-Elf,  haste
+       the wearer permanently and temporarily in combat, making him
+       or her stealthy as well.
+
+  The Pair of Soft Leather Boots 'Dal-i-thalion' [3,+15]
+       These amazing  boots  of  agility,  ensure  free  action  in 
+       combat, greatly increasing your dexterity and ensuring  that
+       you will never become less agile. It is said that  they  can 
+       also make you more confident and brave.
+
+  Full Plate Armour of Isildur [25,+25]
+       This armour of the Dunedain Lord, Isildur, Resists.
+
+  The Large Metal Shield of Anarion [5,+20]
+       This shield Resists and sustains your stats.
+
+  The Set of Cesti of Fingolfin (+10,+10) [5,+20]
+       These amazing gauntlets increase the wearers dexterity, and
+       slay creatures at (+10,+10). They will never be stopped  by
+       paralyaztion and they also resist damage. They occasionally
+       grow magical spikes that can be fired causing great damage.
+
+  The Set of Leather Gloves 'Cambeleg' (+5,+5) [1,+15] 
+       These Gloves of Might, increase strength and  constitution.
+       They never allow their wearer to  be  paralyzed,  and  help 
+       his/her slaying abilities.
+
+  The Set of Leather Gloves 'Cammithrim' [1,+10]
+       These Gloves of Light, sustain dexterity and give off light
+       so brightly  that  they  can  cast  magic  missiles  almost 
+       endlessly.
+
+  The Set of Gauntlets 'Paurhach' [2,+15]
+       These Fists of Fire resist fire and can cast fire bolts.
+
+  The Set of Gauntlets 'Paurnimmen' [2,+15]
+       These Fists of Frost resist cold and can cast frost bolts.
+
+  The Set of Gauntlets 'Pauraegen' [2,+15]
+       These Fists of Lightning  resist  lightning  and  can  cast 
+       lightning bolts.
+
+  The Set of Gauntlets 'Paurnen' [2,+15]
+       These Fists of Water resist acid and can cast acid bolts.
+
+  The Set of Gauntlets 'Camlost' (-11,-12) [2,+0] (-5)
+       The Empty Hand aggravates  monsters,  and  greatly  reduces
+       fighting ability.  Named after the empty hand of Beren that
+       once clasped a Silmaril.
+
+  Mithril Chain Mail of Belegennon [28,+20]
+       This Chain Mail Resists and makes you stealthy.
+
+  The Iron Helm of Dor-Lomin [8,+20]
+       This is the Dragon Helm of  Turin Turambar.  It is  rumored
+       that its wearer will never die in combat.   It  resists all
+       and sees all, and increases all fighting stats.
+
+  The Iron Helm of Holhenneth [5,+10]
+       This helm of brilliance and vision, greatly increases  your
+       mental prowess. It allows you to see all  that  is  hidden,
+       casting detection spells at frequent intervals.
+
+  The Iron Helm of Gorlim [5,+10] (-125)
+       This unhappy helm of betrayal ruins thought and sight.
+
+  Soft Leather Armour 'Hithlomir' [4,+20] (+4)
+       This dark-misty leather resists the elements and melds  the
+       wearer into the background with incredible stealth.
+
+  Leather Scale Mail 'Thalkettoth' (+3) [11,+25]
+       This  light  leather  scale mail  is  suprisingly  good  at
+       dodging attacks, and is resistant to acid.  Often nicknamed
+       Blade-Turner.
+
+  Chain Mail of Arvedui [14,+15]
+       This wonderful chain mail belonged  to  the  last  king  of  
+       Arnor. It resists the elements and increases  strength  and
+       charisma.
+
+  The Hard Leather Cap of Thranduil [2,+10]
+       This acid resistant leather is a thinker's cap.  Increasing
+       wisdom and intelligence.
+
+  The Metal Cap of Thengel [3,+12]
+       This cap of the Rohan King Thengel, gives kingly wisdom and
+       charisma.
+
+  The Steel Helm 'Hammerhand' [6,+20]
+       This warriors' helm increases the fighting stats.
+
+  The Large Leather Shield of Celegorm [4,+20]
+       A quality shield of Resistance.
+
+  The Pair of Metal Shod Boots of Thror [6,+20]
+       These Dwarf-king boots are  ideal  for  combat,  increasing
+       strength and constitution.
+
+  The Cloak 'Colluin' [1,+15]
+       This cloak of resistance even casts extra resistance spells
+       that can defend against poison.
+
+  The Cloak 'Holcolleth' [1,+4]
+       This mage cloak increases intelligence and wisdom and casts
+       spells to make monsters lose their concentration  and  fall
+       to sleep.
+
+  The Cloak 'Colannon' [1,+15]
+       This Gate-cloak, teleports the player at  will,  and  gives 
+       stealth so as to avoid awkward situations.
+
+  The Iron Crown of Beruthiel [0,+20] (-125)
+       This crown once belonged to the  Cat-Queen  of  Gondor,  who
+       disdained armed combat. Giving  you  cat  like  vision,  and 
+       sight within sight, it allows  its  wearer  to  be  free  of 
+       combat, and infact finding armed combat beyond  his  or  her
+       means.
+
+  The Iron Crown of Morgoth
+       This awesome artifact is a plain iron  crown,  mounted  with
+       three jewels  that  capture the eternal light of  the  Trees
+       of the Valar, Teleperion and Laurelein.  These  Jewels  were 
+       made by the Noldorian High-Elf, Feanor who  named  them  the  
+       Silmarils.  Their  beauty,  unsurpassed, drove  Morgoth   to
+       steal these jewels (with the aid of Ungoliant the  Unlight).
+       The  crown  then, maximises all you stats, sustains all your  
+       stats, is a permanent light source and allows  the wearer to
+       see all.
+
+
diff --git a/lib/file/books/book-005_jp.txt b/lib/file/books/book-005_jp.txt
new file mode 100644 (file)
index 0000000..7fa1eac
--- /dev/null
@@ -0,0 +1,146 @@
+
+                     アーティファクトの伝承 第2巻
+                                防具編
+                 -----------------------------------
+
+
+  無名の注釈者によるメモ:
+       このリストは太古のものである。
+       現代においては既に失われたもの、新たに作られたもの、外の世界
+       から持ち込まれたもの、そして年月の間に変質したものが含まれる。
+
+  Adamantite Plate Mail 'Soulkeeper' [40,+20]
+       This amazing armour protects your soul from cold,  and  from
+       life level loss. It is also capable of fully healing you.
+
+  The Pair of Hard Leather Boots of Feanor [3,+20]
+       These amazing boots belonging to Feanor the High-Elf,  haste
+       the wearer permanently and temporarily in combat, making him
+       or her stealthy as well.
+
+  The Pair of Soft Leather Boots 'Dal-i-thalion' [3,+15]
+       These amazing  boots  of  agility,  ensure  free  action  in 
+       combat, greatly increasing your dexterity and ensuring  that
+       you will never become less agile. It is said that  they  can 
+       also make you more confident and brave.
+
+  Full Plate Armour of Isildur [25,+25]
+       This armour of the Dunedain Lord, Isildur, Resists.
+
+  The Large Metal Shield of Anarion [5,+20]
+       This shield Resists and sustains your stats.
+
+  The Set of Cesti of Fingolfin (+10,+10) [5,+20]
+       These amazing gauntlets increase the wearers dexterity, and
+       slay creatures at (+10,+10). They will never be stopped  by
+       paralyaztion and they also resist damage. They occasionally
+       grow magical spikes that can be fired causing great damage.
+
+  The Set of Leather Gloves 'Cambeleg' (+5,+5) [1,+15] 
+       These Gloves of Might, increase strength and  constitution.
+       They never allow their wearer to  be  paralyzed,  and  help 
+       his/her slaying abilities.
+
+  The Set of Leather Gloves 'Cammithrim' [1,+10]
+       These Gloves of Light, sustain dexterity and give off light
+       so brightly  that  they  can  cast  magic  missiles  almost 
+       endlessly.
+
+  The Set of Gauntlets 'Paurhach' [2,+15]
+       These Fists of Fire resist fire and can cast fire bolts.
+
+  The Set of Gauntlets 'Paurnimmen' [2,+15]
+       These Fists of Frost resist cold and can cast frost bolts.
+
+  The Set of Gauntlets 'Pauraegen' [2,+15]
+       These Fists of Lightning  resist  lightning  and  can  cast 
+       lightning bolts.
+
+  The Set of Gauntlets 'Paurnen' [2,+15]
+       These Fists of Water resist acid and can cast acid bolts.
+
+  The Set of Gauntlets 'Camlost' (-11,-12) [2,+0] (-5)
+       The Empty Hand aggravates  monsters,  and  greatly  reduces
+       fighting ability.  Named after the empty hand of Beren that
+       once clasped a Silmaril.
+
+  Mithril Chain Mail of Belegennon [28,+20]
+       This Chain Mail Resists and makes you stealthy.
+
+  The Iron Helm of Dor-Lomin [8,+20]
+       This is the Dragon Helm of  Turin Turambar.  It is  rumored
+       that its wearer will never die in combat.   It  resists all
+       and sees all, and increases all fighting stats.
+
+  The Iron Helm of Holhenneth [5,+10]
+       This helm of brilliance and vision, greatly increases  your
+       mental prowess. It allows you to see all  that  is  hidden,
+       casting detection spells at frequent intervals.
+
+  The Iron Helm of Gorlim [5,+10] (-125)
+       This unhappy helm of betrayal ruins thought and sight.
+
+  Soft Leather Armour 'Hithlomir' [4,+20] (+4)
+       This dark-misty leather resists the elements and melds  the
+       wearer into the background with incredible stealth.
+
+  Leather Scale Mail 'Thalkettoth' (+3) [11,+25]
+       This  light  leather  scale mail  is  suprisingly  good  at
+       dodging attacks, and is resistant to acid.  Often nicknamed
+       Blade-Turner.
+
+  Chain Mail of Arvedui [14,+15]
+       This wonderful chain mail belonged  to  the  last  king  of  
+       Arnor. It resists the elements and increases  strength  and
+       charisma.
+
+  The Hard Leather Cap of Thranduil [2,+10]
+       This acid resistant leather is a thinker's cap.  Increasing
+       wisdom and intelligence.
+
+  The Metal Cap of Thengel [3,+12]
+       This cap of the Rohan King Thengel, gives kingly wisdom and
+       charisma.
+
+  The Steel Helm 'Hammerhand' [6,+20]
+       This warriors' helm increases the fighting stats.
+
+  The Large Leather Shield of Celegorm [4,+20]
+       A quality shield of Resistance.
+
+  The Pair of Metal Shod Boots of Thror [6,+20]
+       These Dwarf-king boots are  ideal  for  combat,  increasing
+       strength and constitution.
+
+  The Cloak 'Colluin' [1,+15]
+       This cloak of resistance even casts extra resistance spells
+       that can defend against poison.
+
+  The Cloak 'Holcolleth' [1,+4]
+       This mage cloak increases intelligence and wisdom and casts
+       spells to make monsters lose their concentration  and  fall
+       to sleep.
+
+  The Cloak 'Colannon' [1,+15]
+       This Gate-cloak, teleports the player at  will,  and  gives 
+       stealth so as to avoid awkward situations.
+
+  The Iron Crown of Beruthiel [0,+20] (-125)
+       This crown once belonged to the  Cat-Queen  of  Gondor,  who
+       disdained armed combat. Giving  you  cat  like  vision,  and 
+       sight within sight, it allows  its  wearer  to  be  free  of 
+       combat, and infact finding armed combat beyond  his  or  her
+       means.
+
+  The Iron Crown of Morgoth
+       This awesome artifact is a plain iron  crown,  mounted  with
+       three jewels  that  capture the eternal light of  the  Trees
+       of the Valar, Teleperion and Laurelein.  These  Jewels  were 
+       made by the Noldorian High-Elf, Feanor who  named  them  the  
+       Silmarils.  Their  beauty,  unsurpassed, drove  Morgoth   to
+       steal these jewels (with the aid of Ungoliant the  Unlight).
+       The  crown  then, maximises all you stats, sustains all your  
+       stats, is a permanent light source and allows  the wearer to
+       see all.
+
+
diff --git a/lib/file/books/book-006_en.txt b/lib/file/books/book-006_en.txt
new file mode 100644 (file)
index 0000000..c83b8bf
--- /dev/null
@@ -0,0 +1,54 @@
+
+                      Artifact Lore, Vol. III
+                       Ancient Magical Tools
+                      -----------------------
+
+
+  Notes by an annotator Mumei: 
+       This list is ancient.
+       In modern times, it includes things that have already been lost,
+       things that have been newly created, things that have been
+       brought in from the outside world, and things that have changed
+       over the years.
+
+  The Amulet of Ingwe (+3)
+       This amulet belonged to the high king of  the  Vanyar,  the 
+       most powerful of the High Elves. It gives  resistance,  and
+       greatly increases your wisdom and charisma.  It  gives  you
+       good infravision, see invisible, and it casts a x5 strength
+       dispel evil.
+
+  The Amulet of Carlammas (+2)
+       This fiery amulet protects from  flame,    casts protection
+       from evil and increases your constitution.
+
+  The Phial of Galadriel (+4)
+       This wonderful object is an infinite light source, and once
+       identified it can light up rooms. 
+
+  The Three Elven Rings
+       Made by Celebrimbor,  Elf  of  the  Girth-I-Mirdain.  These
+       Rings of Power are of awesome power, and are very rare.
+
+  The Ring of Power 'Narya' (+1)
+       Celeborn gave this to Cirdan who gave it to Gandalf.
+       The least powerful of the Elven  rings  is  of  the element 
+       fire. And as such makes you completely immune to  fire.  It 
+       is also capable of casting very  powerful  fire  balls.  It 
+       increases all your stats by  one.  It  also  protects  from 
+       from life draining and helps you regenerate.
+
+  The Ring of Power 'Nenya' (+2)
+       This was kept by Galadriel.
+       As Narya is to fire, Nenya is to Frost... Plus two  to  all 
+       your stats.
+
+  The Ring of Power 'Vilya' (+3)
+       This was kept by Gil-galad who gave it to Elrond.
+       This gives immunity to lightning and resists poison.  Plus three
+       to all your stats.  Casts very powerful lightning balls.
+
+  Rumors exist of  a Ring of Power known as the One Ring, which was
+  made  to master  the other Rings of Power.   Its  powers are what
+  legends are made of....
+
diff --git a/lib/file/books/book-006_jp.txt b/lib/file/books/book-006_jp.txt
new file mode 100644 (file)
index 0000000..477b77b
--- /dev/null
@@ -0,0 +1,52 @@
+
+                     アーティファクトの伝承 第3巻
+                             アクセサリ編
+                 -----------------------------------
+
+
+  無名の注釈者によるメモ:
+       このリストは太古のものである。
+       現代においては既に失われたもの、新たに作られたもの、外の世界
+       から持ち込まれたもの、そして年月の間に変質したものが含まれる。
+
+  The Amulet of Ingwe (+3)
+       This amulet belonged to the high king of  the  Vanyar,  the
+       most powerful of the High Elves. It gives  resistance,  and
+       greatly increases your wisdom and charisma.  It  gives  you
+       good infravision, see invisible, and it casts a x5 strength
+       dispel evil.
+
+  The Amulet of Carlammas (+2)
+       This fiery amulet protects from  flame,    casts protection
+       from evil and increases your constitution.
+
+  The Phial of Galadriel (+4)
+       This wonderful object is an infinite light source, and once
+       identified it can light up rooms. 
+
+  The Three Elven Rings
+       Made by Celebrimbor,  Elf  of  the  Girth-I-Mirdain.  These
+       Rings of Power are of awesome power, and are very rare.
+
+  The Ring of Power 'Narya' (+1)
+       Celeborn gave this to Cirdan who gave it to Gandalf.
+       The least powerful of the Elven  rings  is  of  the element 
+       fire. And as such makes you completely immune to  fire.  It 
+       is also capable of casting very  powerful  fire  balls.  It 
+       increases all your stats by  one.  It  also  protects  from 
+       from life draining and helps you regenerate.
+
+  The Ring of Power 'Nenya' (+2)
+       This was kept by Galadriel.
+       As Narya is to fire, Nenya is to Frost... Plus two  to  all 
+       your stats.
+
+  The Ring of Power 'Vilya' (+3)
+       This was kept by Gil-galad who gave it to Elrond.
+       This gives immunity to lightning and resists poison.  Plus three
+       to all your stats.  Casts very powerful lightning balls.
+
+  Rumors exist of  a Ring of Power known as the One Ring, which was
+  made  to master  the other Rings of Power.   Its  powers are what
+  legends are made of....
+
diff --git a/lib/file/books/book-007_en.txt b/lib/file/books/book-007_en.txt
new file mode 100644 (file)
index 0000000..7d203f4
--- /dev/null
@@ -0,0 +1,6 @@
+
+            What the fuck are you going to do if you become
+            serious in a game like this?
+
+(The following text is written in Hintabo and cannot be
+deciphered...)
diff --git a/lib/file/books/book-007_jp.txt b/lib/file/books/book-007_jp.txt
new file mode 100644 (file)
index 0000000..3855d2b
--- /dev/null
@@ -0,0 +1,4 @@
+
+            こんなけ゛ーむにまし゛になっちゃってと゛うするの
+
+(以下の文章はひんたぼ語で書かれており解読できない)
index 974c887..430eb4e 100644 (file)
@@ -126,7 +126,7 @@ For Mac OS X with Xcode installed, the Unix instructions can work to build a
 version usable from a terminal.  If XQuartz, https://www.xquartz.org , is
 installed, X11 will be used for display.
 
-For Mac OS X 10.8 or later with Xcode installed, a native version can be
+For Mac OS X 10.15 or later with Xcode installed, a native version can be
 built by downloading the source archive and running
 
 ```
index 11382b3..399b4be 100644 (file)
@@ -17,7 +17,6 @@ hengband_SOURCES = \
        action/tunnel-execution.cpp action/tunnel-execution.h \
        action/weapon-shield.cpp action/weapon-shield.h \
        \
-       artifact/artifact-info.cpp artifact/artifact-info.h \
        artifact/fixed-art-generator.cpp artifact/fixed-art-generator.h \
        artifact/fixed-art-types.h \
        artifact/random-art-activation.cpp artifact/random-art-activation.h \
@@ -152,8 +151,6 @@ hengband_SOURCES = \
        core/magic-effects-timeout-reducer.cpp core/magic-effects-timeout-reducer.h \
        core/object-compressor.cpp core/object-compressor.h \
        core/player-processor.cpp core/player-processor.h \
-       core/player-redraw-types.h \
-       core/player-update-types.h \
        core/score-util.cpp core/score-util.h \
        core/scores.cpp core/scores.h \
        core/show-file.cpp core/show-file.h \
@@ -195,6 +192,9 @@ hengband_SOURCES = \
        effect/effect-processor.cpp effect/effect-processor.h \
        effect/effect-characteristics.h \
        \
+       external-lib/include-json.h \
+       external-lib/json.hpp \
+       \
        flavor/flag-inscriptions-table.cpp flavor/flag-inscriptions-table.h \
        flavor/flavor-describer.cpp flavor/flavor-describer.h \
        flavor/flavor-util.cpp flavor/flavor-util.h \
@@ -296,7 +296,6 @@ hengband_SOURCES = \
        io/exit-panic.cpp io/exit-panic.h \
        io/files-util.cpp io/files-util.h \
        io/gf-descriptions.cpp io/gf-descriptions.h \
-       io/inet.cpp io/inet.h \
        io/input-key-acceptor.cpp io/input-key-acceptor.h \
        io/input-key-processor.cpp io/input-key-processor.h \
        io/input-key-requester.cpp io/input-key-requester.h \
@@ -397,8 +396,10 @@ hengband_SOURCES = \
        main/scene-table-monster.cpp main/scene-table-monster.h \
        main/sound-definitions-table.cpp main/sound-definitions-table.h \
        main/sound-of-music.cpp main/sound-of-music.h \
-       main/x11-gamma-builder.cpp main/x11-gamma-builder.h \
-       main/x11-type-string.cpp main/x11-type-string.h \
+       \
+       main-unix/unix-user-ids.cpp main-unix/unix-user-ids.h \
+       main-unix/x11-gamma-builder.cpp main-unix/x11-gamma-builder.h \
+       main-unix/x11-type-string.cpp main-unix/x11-type-string.h \
        \
        market/arena-info-table.cpp market/arena-info-table.h \
        market/building-initializer.cpp market/building-initializer.h \
@@ -526,6 +527,7 @@ hengband_SOURCES = \
        monster-race/race-kind-flags.h \
        monster-race/race-population-flags.h \
        monster-race/race-resistance-mask.cpp monster-race/race-resistance-mask.h \
+       monster-race/race-sex-const.cpp monster-race/race-sex-const.h \
        monster-race/race-speak-flags.h \
        monster-race/race-visual-flags.h \
        monster-race/race-wilderness-flags.h \
@@ -571,9 +573,13 @@ hengband_SOURCES = \
        mutation/mutation-processor.cpp mutation/mutation-processor.h \
        mutation/mutation-techniques.cpp mutation/mutation-techniques.h \
        \
+       net/curl-easy-session.cpp net/curl-easy-session.h \
+       net/curl-slist.cpp net/curl-slist.h \
+       net/http-client.cpp net/http-client.h \
+       net/report-error.cpp net/report-error.h \
+       \
        object/item-tester-hooker.cpp object/item-tester-hooker.h \
        object/object-broken.cpp object/object-broken.h \
-       object/object-flags.cpp object/object-flags.h \
        object/object-index-list.cpp object/object-index-list.h \
        object/object-info.cpp object/object-info.h \
        object/object-kind-hook.cpp object/object-kind-hook.h \
@@ -700,7 +706,6 @@ hengband_SOURCES = \
        player-ability/player-strength.cpp player-ability/player-strength.h \
        player-ability/player-wisdom.cpp player-ability/player-wisdom.h \
        \
-       player-attack/player-attack-util.h \
        player-attack/attack-chaos-effect.cpp player-attack/attack-chaos-effect.h \
        player-attack/blood-sucking-processor.cpp player-attack/blood-sucking-processor.h \
        player-attack/player-attack.cpp player-attack/player-attack.h \
@@ -910,6 +915,7 @@ hengband_SOURCES = \
        system/alloc-entries.cpp system/alloc-entries.h \
        system/angband.h \
        system/angband-exceptions.h \
+       system/angband-system.h system/angband-system.cpp \
        system/angband-version.cpp system/angband-version.h \
        system/artifact-type-definition.cpp system/artifact-type-definition.h \
        system/baseitem-info.cpp system/baseitem-info.h \
@@ -961,15 +967,17 @@ hengband_SOURCES = \
        util/angband-files.cpp util/angband-files.h \
        util/buffer-shaper.cpp util/buffer-shaper.h \
        util/bit-flags-calculator.h \
+       util/candidate-selector.cpp util/candidate-selector.h \
        util/enum-converter.h \
        util/enum-range.h \
+       util/finalizer.h \
        util/flag-group.h \
        util/int-char-converter.h \
        util/object-sort.cpp util/object-sort.h \
        util/point-2d.h \
        util/probability-table.h \
-       util/quarks.cpp util/quarks.h \
        util/rng-xoshiro.cpp util/rng-xoshiro.h \
+       util/sha256.cpp util/sha256.h \
        util/sort.cpp util/sort.h \
        util/string-processor.cpp util/string-processor.h \
        \
@@ -1033,6 +1041,7 @@ EXTRA_hengband_SOURCES = \
        main-win/main-win-bg.cpp main-win/main-win-bg.h \
        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 \
@@ -1044,6 +1053,7 @@ EXTRA_hengband_SOURCES = \
        main-win/main-win-utils.cpp main-win/main-win-utils.h \
        main-win/wav-reader.cpp main-win/wav-reader.h \
        main-cap.cpp \
+       test/test-sha256.cpp \
        wall.bmp \
        stdafx.cpp stdafx.h
 
@@ -1067,12 +1077,16 @@ cocoa_en_strings_files = \
        cocoa/en.lproj/Localizable.strings \
        cocoa/en.lproj/CommandMenu.strings \
        cocoa/en.lproj/GraphicsMenu.strings
+cocoa_en_misc_files = \
+       cocoa/en.lproj/Credits.html
 cocoa_ja_strings_files = \
        cocoa/ja.lproj/MainMenu.strings \
        cocoa/ja.lproj/SoundAndMusic.strings \
        cocoa/ja.lproj/Localizable.strings \
        cocoa/ja.lproj/CommandMenu.strings \
        cocoa/ja.lproj/GraphicsMenu.strings
+cocoa_ja_misc_files = \
+       cocoa/ja.lproj/Credits.html
 
 EXTRA_DIST = \
        gcc-wrap \
@@ -1083,7 +1097,9 @@ EXTRA_DIST = \
        $(cocoa_plist_files) \
        $(cocoa_en_nib_files) \
        $(cocoa_en_strings_files) \
-       $(cocoa_ja_strings_files)
+       $(cocoa_en_misc_files) \
+       $(cocoa_ja_strings_files) \
+       $(cocoa_ja_misc_files)
 
 if COCOA
 hengband_SOURCES += \
@@ -1128,9 +1144,11 @@ appplist_DATA = $(cocoa_plist_files)
 appplistdir = $(APPRES)
 appennib_DATA = $(cocoa_en_nib_files)
 appennibdir = $(APPRES)/Base.lproj
-appen_DATA = $(cocoa_en_strings_files)
+appen_DATA = $(cocoa_en_strings_files) $(cocoa_en_misc_files) \
+       ../THIRD-PARTY-NOTICES.txt
 appendir = $(APPRES)/en.lproj
-appja_DATA = $(cocoa_ja_strings_files)
+appja_DATA = $(cocoa_ja_strings_files) $(cocoa_ja_misc_files) \
+       ../THIRD-PARTY-NOTICES.txt
 appjadir = $(APPRES)/ja.lproj
 else
 EXTRA_hengband_SOURCES += main-cocoa.mm system/grafmode.h system/grafmode.cpp \
@@ -1142,7 +1160,7 @@ endif
 # directives in the cocoa/*.{h,mm} files when building here or rebuilding the
 # nib files in Xcode according to the procedure in cocoa/AppDelegate.m.
 DEFAULT_INCLUDES = -I$(srcdir) -I$(top_builddir)/src -I$(top_builddir)/src/cocoa
-CPPFLAGS += $(XFT_CFLAGS) $(libcurl_CFLAGS)
+CPPFLAGS += $(XFT_CFLAGS) $(libssl_CFLAGS) $(libcrypto_CFLAGS)
 LIBS += $(XFT_LIBS) $(libcurl_LIBS)
 COMPILE = $(srcdir)/gcc-wrap $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
        $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
index 7812d19..aec7928 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file action-limited.cpp
  * @brief プレイヤーの行動制約判定定義
  */
@@ -28,7 +28,8 @@
  */
 bool cmd_limit_cast(PlayerType *player_ptr)
 {
-    if (player_ptr->current_floor_ptr->is_in_dungeon() && (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MAGIC))) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.is_in_dungeon() && (floor.get_dungeon_definition().flags.has(DungeonFeatureType::NO_MAGIC))) {
         msg_print(_("ダンジョンが魔法を吸収した!", "The dungeon absorbs all attempted magic!"));
         msg_print(nullptr);
         return true;
index 9fcb309..9c46873 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file action-limited.h
  * @brief プレイヤーの行動制約判定ヘッダ
index f3fc281..0411803 100644 (file)
@@ -1,11 +1,10 @@
-/*!
+/*!
  * @file activation-execution.cpp
  * @brief アイテムの発動実行定義
  */
 
 #include "action/activation-execution.h"
 #include "action/action-limited.h"
-#include "artifact/artifact-info.h"
 #include "artifact/random-art-effects.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-getter.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-confusion.h"
 #include "timed-effect/timed-effects.h"
-#include "util/quarks.h"
 #include "util/sort.h"
 #include "view/display-messages.h"
 #include "world/world.h"
@@ -60,9 +59,9 @@ static void decide_activation_level(ae_type *ae_ptr)
     }
 
     if (ae_ptr->o_ptr->is_random_artifact()) {
-        auto act_ptr = find_activation_info(ae_ptr->o_ptr);
-        if (act_ptr.has_value()) {
-            ae_ptr->lev = act_ptr.value()->level;
+        const auto it_activation = ae_ptr->o_ptr->find_activation_info();
+        if (it_activation != activation_info.end()) {
+            ae_ptr->lev = it_activation->level;
         }
 
         return;
@@ -155,28 +154,27 @@ static bool check_activation_conditions(PlayerType *player_ptr, ae_type *ae_ptr)
  */
 static bool activate_artifact(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
-    auto tmp_act_ptr = find_activation_info(o_ptr);
-    if (!tmp_act_ptr.has_value()) {
+    const auto it_activation = o_ptr->find_activation_info();
+    if (it_activation == activation_info.end()) {
         msg_print("Activation information is not found.");
         return false;
     }
 
-    auto *act_ptr = tmp_act_ptr.value();
     const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY | OD_OMIT_PREFIX | OD_BASE_NAME);
-    if (!switch_activation(player_ptr, &o_ptr, act_ptr, item_name.data())) {
+    if (!switch_activation(player_ptr, &o_ptr, it_activation->index, item_name)) {
         return false;
     }
 
-    if (act_ptr->timeout.constant >= 0) {
-        o_ptr->timeout = (int16_t)act_ptr->timeout.constant;
-        if (act_ptr->timeout.dice > 0) {
-            o_ptr->timeout += randint1(act_ptr->timeout.dice);
+    if (it_activation->constant) {
+        o_ptr->timeout = static_cast<short>(*it_activation->constant);
+        if (it_activation->dice > 0) {
+            o_ptr->timeout += static_cast<short>(randint1(it_activation->dice));
         }
 
         return true;
     }
 
-    switch (act_ptr->index) {
+    switch (it_activation->index) {
     case RandomArtActType::BR_FIRE:
         o_ptr->timeout = o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES) ? 200 : 250;
         return true;
@@ -189,7 +187,7 @@ static bool activate_artifact(PlayerType *player_ptr, ItemEntity *o_ptr)
     case RandomArtActType::MURAMASA:
         return true;
     default:
-        msg_format("Special timeout is not implemented: %d.", enum2i(act_ptr->index));
+        msg_format("Special timeout is not implemented: %d.", enum2i(it_activation->index));
         return false;
     }
 }
@@ -216,7 +214,7 @@ static bool activate_whistle(PlayerType *player_ptr, ae_type *ae_ptr)
         }
     }
 
-    uint16_t dummy_why;
+    short dummy_why = 0;
     ang_sort(player_ptr, who.data(), &dummy_why, who.size(), ang_sort_comp_pet, ang_sort_swap_hook);
     for (auto pet_ctr : who) {
         teleport_monster_to(player_ptr, pet_ctr, player_ptr->y, player_ptr->x, 100, TELEPORT_PASSIVE);
@@ -227,23 +225,15 @@ static bool activate_whistle(PlayerType *player_ptr, ae_type *ae_ptr)
 }
 
 /*!
- * @brief 装備を発動するコマンドのサブルーチン /
- * Activate a wielded object.  Wielded objects never stack.
- * And even if they did, activatable objects never stack.
- * @param item 発動するオブジェクトの所持品ID
- * @details
- * <pre>
- * Currently, only (some) artifacts, and Dragon Scale Mail, can be activated.
- * But one could, for example, easily make an activatable "Ring of Plasma".
- * Note that it always takes a turn to activate an artifact, even if
- * the user hits "escape" at the "direction" prompt.
- * </pre>
+ * @brief 装備を発動するコマンドのサブルーチン
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @param i_idx 発動するオブジェクトの所持品ID
  */
-void exe_activate(PlayerType *player_ptr, INVENTORY_IDX item)
+void exe_activate(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
     ae_type tmp_ae;
-    ae_type *ae_ptr = initialize_ae_type(player_ptr, &tmp_ae, item);
+    ae_type *ae_ptr = initialize_ae_type(player_ptr, &tmp_ae, i_idx);
     decide_activation_level(ae_ptr);
     decide_chance_fail(player_ptr, ae_ptr);
     if (cmd_limit_time_walk(player_ptr)) {
@@ -257,9 +247,13 @@ void exe_activate(PlayerType *player_ptr, INVENTORY_IDX item)
 
     msg_print(_("始動させた...", "You activate it..."));
     sound(SOUND_ZAP);
-    if (activation_index(ae_ptr->o_ptr) > RandomArtActType::NONE) {
+    if (ae_ptr->o_ptr->has_activation()) {
         (void)activate_artifact(player_ptr, ae_ptr->o_ptr);
-        player_ptr->window_flags |= PW_INVENTORY | PW_EQUIPMENT;
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::INVENTORY,
+            SubWindowRedrawingFlag::EQUIPMENT,
+        };
+        RedrawingFlagsUpdater::get_instance().set_flags(flags);
         return;
     }
 
index f2ae6a9..2ae422d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file activation-execution.h
  * @brief アイテムの発動実行ヘッダ
@@ -7,4 +7,4 @@
 #include "system/angband.h"
 
 class PlayerType;
-void exe_activate(PlayerType *player_ptr, INVENTORY_IDX item);
+void exe_activate(PlayerType *player_ptr, INVENTORY_IDX i_idx);
index 5b686c8..3c735c3 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file movement-execution.cpp
  * @brief プレイヤーの歩行勝利実行定義
  */
@@ -8,7 +8,6 @@
 #include "artifact/fixed-art-types.h"
 #include "cmd-action/cmd-attack.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "floor/geometry.h"
 #include "floor/pattern-walk.h"
@@ -44,6 +43,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "timed-effect/player-confusion.h"
 #include "timed-effect/player-hallucination.h"
 
 /*!
  * Determine if a "boundary" grid is "floor mimic"
- * @param grid_type *g_ptr
- * @param TerrainType *f_ptr
- * @param TerrainType  *mimic_f_ptr
+ * @param grid グリッドへの参照
+ * @param terrain 地形特性への参照
+ * @param terrain_mimic ミミック地形特性への参照
  * @return 移動不能であればTRUE
  * @todo 負論理なので反転させたい
  */
-static bool boundary_floor(grid_type *g_ptr, TerrainType *f_ptr, TerrainType *mimic_f_ptr)
+static bool boundary_floor(const Grid &grid, const TerrainType &terrain, const TerrainType &terrain_mimic)
 {
-    bool is_boundary_floor = g_ptr->mimic > 0;
-    is_boundary_floor &= permanent_wall(f_ptr);
-    is_boundary_floor &= mimic_f_ptr->flags.has_any_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY });
-    is_boundary_floor &= mimic_f_ptr->flags.has(TerrainCharacteristics::PROJECT);
-    is_boundary_floor &= mimic_f_ptr->flags.has_not(TerrainCharacteristics::OPEN);
+    auto is_boundary_floor = grid.mimic > 0;
+    is_boundary_floor &= terrain.is_permanent_wall();
+    is_boundary_floor &= terrain_mimic.flags.has_any_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY });
+    is_boundary_floor &= terrain_mimic.flags.has(TerrainCharacteristics::PROJECT);
+    is_boundary_floor &= terrain_mimic.flags.has_not(TerrainCharacteristics::OPEN);
     return is_boundary_floor;
 }
 
@@ -89,28 +89,28 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
 {
     POSITION y = player_ptr->y + ddy[dir];
     POSITION x = player_ptr->x + ddx[dir];
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
-    bool p_can_enter = player_can_enter(player_ptr, g_ptr->feat, CEM_P_CAN_ENTER_PATTERN);
-    if (!floor_ptr->dun_level && !player_ptr->wild_mode && ((x == 0) || (x == MAX_WID - 1) || (y == 0) || (y == MAX_HGT - 1))) {
-        if (g_ptr->mimic && player_can_enter(player_ptr, g_ptr->mimic, 0)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &grid = floor.grid_array[y][x];
+    bool p_can_enter = player_can_enter(player_ptr, grid.feat, CEM_P_CAN_ENTER_PATTERN);
+    if (!floor.dun_level && !player_ptr->wild_mode && ((x == 0) || (x == MAX_WID - 1) || (y == 0) || (y == MAX_HGT - 1))) {
+        if (grid.mimic && player_can_enter(player_ptr, grid.mimic, 0)) {
             if ((y == 0) && (x == 0)) {
                 player_ptr->wilderness_y--;
                 player_ptr->wilderness_x--;
-                player_ptr->oldpy = floor_ptr->height - 2;
-                player_ptr->oldpx = floor_ptr->width - 2;
+                player_ptr->oldpy = floor.height - 2;
+                player_ptr->oldpx = floor.width - 2;
                 player_ptr->ambush_flag = false;
             } else if ((y == 0) && (x == MAX_WID - 1)) {
                 player_ptr->wilderness_y--;
                 player_ptr->wilderness_x++;
-                player_ptr->oldpy = floor_ptr->height - 2;
+                player_ptr->oldpy = floor.height - 2;
                 player_ptr->oldpx = 1;
                 player_ptr->ambush_flag = false;
             } else if ((y == MAX_HGT - 1) && (x == 0)) {
                 player_ptr->wilderness_y++;
                 player_ptr->wilderness_x--;
                 player_ptr->oldpy = 1;
-                player_ptr->oldpx = floor_ptr->width - 2;
+                player_ptr->oldpx = floor.width - 2;
                 player_ptr->ambush_flag = false;
             } else if ((y == MAX_HGT - 1) && (x == MAX_WID - 1)) {
                 player_ptr->wilderness_y++;
@@ -120,7 +120,7 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
                 player_ptr->ambush_flag = false;
             } else if (y == 0) {
                 player_ptr->wilderness_y--;
-                player_ptr->oldpy = floor_ptr->height - 2;
+                player_ptr->oldpy = floor.height - 2;
                 player_ptr->oldpx = x;
                 player_ptr->ambush_flag = false;
             } else if (y == MAX_HGT - 1) {
@@ -130,7 +130,7 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
                 player_ptr->ambush_flag = false;
             } else if (x == 0) {
                 player_ptr->wilderness_x--;
-                player_ptr->oldpx = floor_ptr->width - 2;
+                player_ptr->oldpx = floor.width - 2;
                 player_ptr->oldpy = y;
                 player_ptr->ambush_flag = false;
             } else if (x == MAX_WID - 1) {
@@ -148,7 +148,7 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
         p_can_enter = false;
     }
 
-    auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
+    auto *m_ptr = &floor.m_list[grid.m_idx];
 
     // @todo 「特定の武器を装備している」旨のメソッドを別途作る
     constexpr auto stormbringer = FixedArtifactId::STORMBRINGER;
@@ -161,16 +161,16 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
         is_stormbringer = true;
     }
 
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    auto &terrain = grid.get_terrain();
     auto p_can_kill_walls = has_kill_wall(player_ptr);
-    p_can_kill_walls &= f_ptr->flags.has(TerrainCharacteristics::HURT_DISI);
-    p_can_kill_walls &= !p_can_enter || f_ptr->flags.has_not(TerrainCharacteristics::LOS);
-    p_can_kill_walls &= f_ptr->flags.has_not(TerrainCharacteristics::PERMANENT);
+    p_can_kill_walls &= terrain.flags.has(TerrainCharacteristics::HURT_DISI);
+    p_can_kill_walls &= !p_can_enter || terrain.flags.has_not(TerrainCharacteristics::LOS);
+    p_can_kill_walls &= terrain.flags.has_not(TerrainCharacteristics::PERMANENT);
     std::string m_name;
     bool can_move = true;
     bool do_past = false;
-    if (g_ptr->m_idx && (m_ptr->ml || p_can_enter || p_can_kill_walls)) {
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    if (grid.m_idx && (m_ptr->ml || p_can_enter || p_can_kill_walls)) {
+        auto *r_ptr = &m_ptr->get_monrace();
         auto effects = player_ptr->effects();
         auto is_stunned = effects->stun()->is_stunned();
         auto can_cast = !effects->confusion()->is_confused();
@@ -179,21 +179,21 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
         can_cast &= m_ptr->ml;
         can_cast &= !is_stunned;
         can_cast &= player_ptr->muta.has_not(PlayerMutationType::BERS_RAGE) || !is_shero(player_ptr);
-        if (!m_ptr->is_hostile() && can_cast && pattern_seq(player_ptr, player_ptr->y, player_ptr->x, y, x) && (p_can_enter || p_can_kill_walls)) {
-            (void)set_monster_csleep(player_ptr, g_ptr->m_idx, 0);
+        if (!m_ptr->is_hostile() && can_cast && pattern_seq(player_ptr, { y, x }) && (p_can_enter || p_can_kill_walls)) {
+            (void)set_monster_csleep(player_ptr, grid.m_idx, 0);
             m_name = monster_desc(player_ptr, m_ptr, 0);
             if (m_ptr->ml) {
                 if (!is_hallucinated) {
                     monster_race_track(player_ptr, m_ptr->ap_r_idx);
                 }
 
-                health_track(player_ptr, g_ptr->m_idx);
+                health_track(player_ptr, grid.m_idx);
             }
 
             if ((is_stormbringer && (randint1(1000) > 666)) || PlayerClass(player_ptr).equals(PlayerClassType::BERSERKER)) {
                 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
                 can_move = false;
-            } else if (monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[player_ptr->y][player_ptr->x].feat, r_ptr, 0)) {
+            } else if (monster_can_cross_terrain(player_ptr, floor.grid_array[player_ptr->y][player_ptr->x].feat, r_ptr, 0)) {
                 do_past = true;
             } else {
                 msg_format(_("%s^が邪魔だ!", "%s^ is in your way!"), m_name.data());
@@ -206,7 +206,7 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
         }
     }
 
-    MonsterEntity *riding_m_ptr = &floor_ptr->m_list[player_ptr->riding];
+    MonsterEntity *riding_m_ptr = &floor.m_list[player_ptr->riding];
     PlayerEnergy energy(player_ptr);
     if (can_move && player_ptr->riding) {
         const auto *riding_r_ptr = &monraces_info[riding_m_ptr->r_idx];
@@ -223,22 +223,24 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
         } else if (player_ptr->riding_ryoute) {
             can_move = false;
             disturb(player_ptr, false, true);
-        } else if (f_ptr->flags.has(TerrainCharacteristics::CAN_FLY) && (riding_r_ptr->feature_flags.has(MonsterFeatureType::CAN_FLY))) {
+        } else if (terrain.flags.has(TerrainCharacteristics::CAN_FLY) && (riding_r_ptr->feature_flags.has(MonsterFeatureType::CAN_FLY))) {
             /* Allow moving */
-        } else if (f_ptr->flags.has(TerrainCharacteristics::CAN_SWIM) && (riding_r_ptr->feature_flags.has(MonsterFeatureType::CAN_SWIM))) {
+        } else if (terrain.flags.has(TerrainCharacteristics::CAN_SWIM) && (riding_r_ptr->feature_flags.has(MonsterFeatureType::CAN_SWIM))) {
             /* Allow moving */
-        } else if (f_ptr->flags.has(TerrainCharacteristics::WATER) && riding_r_ptr->feature_flags.has_not(MonsterFeatureType::AQUATIC) && (f_ptr->flags.has(TerrainCharacteristics::DEEP) || riding_r_ptr->aura_flags.has(MonsterAuraType::FIRE))) {
-            msg_print(_(format("%sの上に行けない。", terrains_info[g_ptr->get_feat_mimic()].name.data()), "Can't swim."));
+        } else if (terrain.flags.has(TerrainCharacteristics::WATER) && riding_r_ptr->feature_flags.has_not(MonsterFeatureType::AQUATIC) && (terrain.flags.has(TerrainCharacteristics::DEEP) || riding_r_ptr->aura_flags.has(MonsterAuraType::FIRE))) {
+            msg_print(_(format("%sの上に行けない。", grid.get_terrain_mimic().name.data()), "Can't swim."));
             energy.reset_player_turn();
             can_move = false;
             disturb(player_ptr, false, true);
-        } else if (f_ptr->flags.has_not(TerrainCharacteristics::WATER) && riding_r_ptr->feature_flags.has(MonsterFeatureType::AQUATIC)) {
-            msg_print(_(format("%sから上がれない。", terrains_info[floor_ptr->grid_array[player_ptr->y][player_ptr->x].get_feat_mimic()].name.data()), "Can't land."));
+        } else if (terrain.flags.has_not(TerrainCharacteristics::WATER) && riding_r_ptr->feature_flags.has(MonsterFeatureType::AQUATIC)) {
+            constexpr auto fmt = _("%sから上がれない。", "Can't land from %s.");
+            const auto p_pos = player_ptr->get_position();
+            msg_format(fmt, floor.get_grid(p_pos).get_terrain_mimic().name.data());
             energy.reset_player_turn();
             can_move = false;
             disturb(player_ptr, false, true);
-        } else if (f_ptr->flags.has(TerrainCharacteristics::LAVA) && riding_r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_FIRE_MASK)) {
-            msg_print(_(format("%sの上に行けない。", terrains_info[g_ptr->get_feat_mimic()].name.data()), "Too hot to go through."));
+        } else if (terrain.flags.has(TerrainCharacteristics::LAVA) && riding_r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_FIRE_MASK)) {
+            msg_print(_(format("%sの上に行けない。", grid.get_terrain_mimic().name.data()), "Too hot to go through."));
             energy.reset_player_turn();
             can_move = false;
             disturb(player_ptr, false, true);
@@ -253,36 +255,35 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
     }
 
     if (!can_move) {
-    } else if (f_ptr->flags.has_not(TerrainCharacteristics::MOVE) && f_ptr->flags.has(TerrainCharacteristics::CAN_FLY) && !player_ptr->levitation) {
-        msg_format(_("空を飛ばないと%sの上には行けない。", "You need to fly to go through the %s."), terrains_info[g_ptr->get_feat_mimic()].name.data());
+    } else if (terrain.flags.has_not(TerrainCharacteristics::MOVE) && terrain.flags.has(TerrainCharacteristics::CAN_FLY) && !player_ptr->levitation) {
+        msg_format(_("空を飛ばないと%sの上には行けない。", "You need to fly to go through the %s."), grid.get_terrain_mimic().name.data());
         energy.reset_player_turn();
         player_ptr->running = 0;
         can_move = false;
-    } else if (f_ptr->flags.has(TerrainCharacteristics::TREE) && !p_can_kill_walls) {
+    } else if (terrain.flags.has(TerrainCharacteristics::TREE) && !p_can_kill_walls) {
         auto riding_wild_wood = player_ptr->riding && monraces_info[riding_m_ptr->r_idx].wilderness_flags.has(MonsterWildernessType::WILD_WOOD);
         if (!PlayerClass(player_ptr).equals(PlayerClassType::RANGER) && !player_ptr->levitation && !riding_wild_wood) {
             energy.mul_player_turn_energy(2);
         }
-    } else if ((do_pickup != easy_disarm) && f_ptr->flags.has(TerrainCharacteristics::DISARM) && !g_ptr->mimic) {
-        if (!trap_can_be_ignored(player_ptr, g_ptr->feat)) {
+    } else if ((do_pickup != easy_disarm) && terrain.flags.has(TerrainCharacteristics::DISARM) && !grid.mimic) {
+        if (!trap_can_be_ignored(player_ptr, grid.feat)) {
             (void)exe_disarm(player_ptr, y, x, dir);
             return;
         }
     } else if (!p_can_enter && !p_can_kill_walls) {
-        FEAT_IDX feat = g_ptr->get_feat_mimic();
-        TerrainType *mimic_f_ptr = &terrains_info[feat];
-        concptr name = mimic_f_ptr->name.data();
+        const auto &terrain_mimic = grid.get_terrain_mimic();
+        const auto &name = terrain_mimic.name;
         can_move = false;
-        if (!g_ptr->is_mark() && !player_can_see_bold(player_ptr, y, x)) {
-            if (boundary_floor(g_ptr, f_ptr, mimic_f_ptr)) {
+        if (!grid.is_mark() && !player_can_see_bold(player_ptr, y, x)) {
+            if (boundary_floor(grid, terrain, terrain_mimic)) {
                 msg_print(_("それ以上先には進めないようだ。", "You feel you cannot go any more."));
             } else {
 #ifdef JP
-                msg_format("%sが行く手をはばんでいるようだ。", name);
+                msg_format("%sが行く手をはばんでいるようだ。", name.data());
 #else
-                msg_format("You feel %s %s blocking your way.", is_a_vowel(name[0]) ? "an" : "a", name);
+                msg_format("You feel %s %s blocking your way.", is_a_vowel(name[0]) ? "an" : "a", name.data());
 #endif
-                g_ptr->info |= (CAVE_MARK);
+                grid.info |= (CAVE_MARK);
                 lite_spot(player_ptr, y, x);
             }
         } else {
@@ -290,20 +291,20 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
             auto is_confused = effects->confusion()->is_confused();
             auto is_stunned = effects->stun()->is_stunned();
             auto is_hallucinated = effects->hallucination()->is_hallucinated();
-            if (boundary_floor(g_ptr, f_ptr, mimic_f_ptr)) {
+            if (boundary_floor(grid, terrain, terrain_mimic)) {
                 msg_print(_("それ以上先には進めない。", "You cannot go any more."));
                 if (!(is_confused || is_stunned || is_hallucinated)) {
                     energy.reset_player_turn();
                 }
             } else {
-                if (easy_open && is_closed_door(player_ptr, feat) && easy_open_door(player_ptr, y, x)) {
+                if (easy_open && is_closed_door(player_ptr, grid.get_feat_mimic()) && easy_open_door(player_ptr, y, x)) {
                     return;
                 }
 
 #ifdef JP
-                msg_format("%sが行く手をはばんでいる。", name);
+                msg_format("%sが行く手をはばんでいる。", name.data());
 #else
-                msg_format("There is %s %s blocking your way.", is_a_vowel(name[0]) ? "an" : "a", name);
+                msg_format("There is %s %s blocking your way.", is_a_vowel(name[0]) ? "an" : "a", name.data());
 #endif
                 if (!(is_confused || is_stunned || is_hallucinated)) {
                     energy.reset_player_turn();
@@ -312,12 +313,12 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
         }
 
         disturb(player_ptr, false, true);
-        if (!boundary_floor(g_ptr, f_ptr, mimic_f_ptr)) {
+        if (!boundary_floor(grid, terrain, terrain_mimic)) {
             sound(SOUND_HITWALL);
         }
     }
 
-    if (can_move && !pattern_seq(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+    if (can_move && !pattern_seq(player_ptr, { y, x })) {
         auto effects = player_ptr->effects();
         auto is_confused = effects->confusion()->is_confused();
         auto is_stunned = effects->stun()->is_stunned();
@@ -371,7 +372,7 @@ void exe_movement(PlayerType *player_ptr, DIRECTION dir, bool do_pickup, bool br
 
     if (p_can_kill_walls) {
         cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_DISI);
-        player_ptr->update |= PU_FLOW;
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
     }
 
     uint32_t mpe_mode = MPE_ENERGY_USE;
index 084022d..b18c30d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file movement-execution.h
  * @brief プレイヤーの歩行処理実行ヘッダ
index 6888993..a199aa7 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file mutation-execution.cpp
  * @brief プレイヤーの変異能力実行定義
  */
@@ -6,6 +6,7 @@
 #include "action/mutation-execution.h"
 #include "cmd-item/cmd-throw.h"
 #include "core/asking-player.h"
+#include "dungeon/quest.h"
 #include "effect/attribute-types.h"
 #include "effect/spells-effect-util.h"
 #include "floor/geometry.h"
@@ -66,6 +67,7 @@ bool exe_mutation_power(PlayerType *player_ptr, PlayerMutationType power)
 {
     DIRECTION dir = 0;
     PLAYER_LEVEL lvl = player_ptr->lev;
+    auto &floor = *player_ptr->current_floor_ptr;
     switch (power) {
     case PlayerMutationType::SPIT_ACID:
         if (!get_aim_dir(player_ptr, &dir)) {
@@ -166,7 +168,7 @@ bool exe_mutation_power(PlayerType *player_ptr, PlayerMutationType power)
         (void)berserk(player_ptr, randint1(25) + 25);
         return true;
     case PlayerMutationType::POLYMORPH:
-        if (!get_check(_("変身します。よろしいですか?", "You will polymorph your self. Are you sure? "))) {
+        if (!input_check(_("変身します。よろしいですか?", "You will polymorph your self. Are you sure? "))) {
             return false;
         }
 
@@ -221,7 +223,7 @@ bool exe_mutation_power(PlayerType *player_ptr, PlayerMutationType power)
     case PlayerMutationType::STERILITY:
         msg_print(_("突然頭が痛くなった!", "You suddenly have a headache!"));
         take_hit(player_ptr, DAMAGE_LOSELIFE, randint1(17) + 17, _("禁欲を強いた疲労", "the strain of forcing abstinence"));
-        player_ptr->current_floor_ptr->num_repro += MAX_REPRODUCTION;
+        floor.num_repro += MAX_REPRODUCTION;
         return true;
     case PlayerMutationType::HIT_AND_AWAY:
         return hit_and_away(player_ptr);
@@ -240,52 +242,54 @@ bool exe_mutation_power(PlayerType *player_ptr, PlayerMutationType power)
     case PlayerMutationType::RECALL:
         return recall_player(player_ptr, randint0(21) + 15);
     case PlayerMutationType::BANISH: {
-        if (!get_direction(player_ptr, &dir, false, false)) {
+        if (!get_direction(player_ptr, &dir)) {
             return false;
         }
 
-        POSITION y = player_ptr->y + ddy[dir];
-        POSITION x = player_ptr->x + ddx[dir];
-        grid_type *g_ptr;
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-
-        if (!g_ptr->m_idx) {
+        const auto y = player_ptr->y + ddy[dir];
+        const auto x = player_ptr->x + ddx[dir];
+        const auto &grid = floor.grid_array[y][x];
+        if (!grid.m_idx) {
             msg_print(_("邪悪な存在を感じとれません!", "You sense no evil there!"));
             return true;
         }
 
-        MonsterEntity *m_ptr;
-        m_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
-        MonsterRaceInfo *r_ptr;
-        r_ptr = &monraces_info[m_ptr->r_idx];
-        if (r_ptr->kind_flags.has(MonsterKindType::EVIL) && none_bits(r_ptr->flags1, RF1_QUESTOR) && r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) && !player_ptr->current_floor_ptr->inside_arena && !inside_quest(player_ptr->current_floor_ptr->quest_number) && (r_ptr->level < randint1(player_ptr->lev + 50)) && m_ptr->mflag2.has_not(MonsterConstantFlagType::NOGENO)) {
-            if (record_named_pet && m_ptr->is_named_pet()) {
-                const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-                exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_GENOCIDE, m_name.data());
+        auto &monster = floor.m_list[grid.m_idx];
+        const auto &monrace = monster.get_monrace();
+        auto can_banish = monrace.kind_flags.has(MonsterKindType::EVIL);
+        can_banish &= none_bits(monrace.flags1, RF1_QUESTOR);
+        can_banish &= monrace.kind_flags.has_not(MonsterKindType::UNIQUE);
+        can_banish &= !floor.inside_arena;
+        can_banish &= !floor.is_in_quest();
+        can_banish &= (monrace.level < randint1(player_ptr->lev + 50));
+        can_banish &= monster.mflag2.has_not(MonsterConstantFlagType::NOGENO);
+        if (can_banish) {
+            if (record_named_pet && monster.is_named_pet()) {
+                const auto m_name = monster_desc(player_ptr, &monster, MD_INDEF_VISIBLE);
+                exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_GENOCIDE, m_name);
             }
 
-            delete_monster_idx(player_ptr, g_ptr->m_idx);
+            delete_monster_idx(player_ptr, grid.m_idx);
             msg_print(_("その邪悪なモンスターは硫黄臭い煙とともに消え去った!", "The evil creature vanishes in a puff of sulfurous smoke!"));
             return true;
         }
 
         msg_print(_("祈りは効果がなかった!", "Your invocation is ineffectual!"));
         if (one_in_(13)) {
-            m_ptr->mflag2.set(MonsterConstantFlagType::NOGENO);
+            monster.mflag2.set(MonsterConstantFlagType::NOGENO);
         }
 
         return true;
     }
     case PlayerMutationType::COLD_TOUCH: {
-        if (!get_direction(player_ptr, &dir, false, false)) {
+        if (!get_direction(player_ptr, &dir)) {
             return false;
         }
 
-        POSITION y = player_ptr->y + ddy[dir];
-        POSITION x = player_ptr->x + ddx[dir];
-        grid_type *g_ptr;
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-        if (!g_ptr->m_idx) {
+        const auto y = player_ptr->y + ddy[dir];
+        const auto x = player_ptr->x + ddx[dir];
+        auto &grid = floor.grid_array[y][x];
+        if (!grid.m_idx) {
             msg_print(_("あなたは何もない場所で手を振った。", "You wave your hands in the air."));
             return true;
         }
@@ -293,9 +297,8 @@ bool exe_mutation_power(PlayerType *player_ptr, PlayerMutationType power)
         fire_bolt(player_ptr, AttributeType::COLD, dir, 2 * lvl);
         return true;
     }
-    case PlayerMutationType::LAUNCHER: {
+    case PlayerMutationType::LAUNCHER:
         return ThrowCommand(player_ptr).do_cmd_throw(2 + lvl / 40, false, -1);
-    }
     default:
         PlayerEnergy(player_ptr).reset_player_turn();
         msg_format(_("能力 PlayerMutationType::%d は実装されていません。", "Power PlayerMutationType::%d not implemented. Oops."), enum2i(power));
index 55400a4..7043ac5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file mutation-execution.h
  * @brief プレイヤーの変異能力実行ヘッダ
index 510549d..c8a23b9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file open-close-execution.cpp
  * @brief 扉や箱を開ける処理
  * @date 2020/07/11
  */
 bool exe_open(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    auto &terrain = grid.get_terrain();
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-    if (f_ptr->flags.has_not(TerrainCharacteristics::OPEN)) {
-        msg_format(_("%sはがっちりと閉じられているようだ。", "The %s appears to be stuck."), terrains_info[g_ptr->get_feat_mimic()].name.data());
+    if (terrain.flags.has_not(TerrainCharacteristics::OPEN)) {
+        constexpr auto fmt = _("%sはがっちりと閉じられているようだ。", "The %s appears to be stuck.");
+        msg_format(fmt, grid.get_terrain_mimic().name.data());
         return false;
     }
 
-    if (!f_ptr->power) {
+    if (!terrain.power) {
         cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::OPEN);
         sound(SOUND_OPENDOOR);
         return false;
@@ -68,7 +70,7 @@ bool exe_open(PlayerType *player_ptr, POSITION y, POSITION x)
         i = i / 10;
     }
 
-    int j = f_ptr->power;
+    int j = terrain.power;
     j = i - (j * 4);
     if (j < 2) {
         j = 2;
@@ -104,22 +106,26 @@ bool exe_open(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 bool exe_close(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    FEAT_IDX old_feat = g_ptr->feat;
-    bool more = false;
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto terrain_id = grid.feat;
+    auto more = false;
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-    if (terrains_info[old_feat].flags.has_not(TerrainCharacteristics::CLOSE)) {
+    if (grid.get_terrain().flags.has_not(TerrainCharacteristics::CLOSE)) {
         return more;
     }
 
-    int16_t closed_feat = feat_state(player_ptr->current_floor_ptr, old_feat, TerrainCharacteristics::CLOSE);
-    if ((!g_ptr->o_idx_list.empty() || g_ptr->is_object()) && (closed_feat != old_feat) && terrains_info[closed_feat].flags.has_not(TerrainCharacteristics::DROP)) {
+    const auto closed_feat = feat_state(player_ptr->current_floor_ptr, terrain_id, TerrainCharacteristics::CLOSE);
+    auto is_preventing = !grid.o_idx_list.empty() || grid.is_object();
+    is_preventing &= closed_feat != terrain_id;
+    is_preventing &= TerrainList::get_instance()[closed_feat].flags.has_not(TerrainCharacteristics::DROP);
+    if (is_preventing) {
         msg_print(_("何かがつっかえて閉まらない。", "Something prevents it from closing."));
         return more;
     }
 
     cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::CLOSE);
-    if (old_feat == g_ptr->feat) {
+    if (terrain_id == grid.feat) {
         msg_print(_("ドアは壊れてしまっている。", "The door appears to be broken."));
     } else {
         sound(SOUND_SHUTDOOR);
@@ -144,33 +150,34 @@ bool exe_close(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 bool easy_open_door(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    int i, j;
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    if (!is_closed_door(player_ptr, g_ptr->feat)) {
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
+    if (!is_closed_door(player_ptr, grid.feat)) {
         return false;
     }
 
-    if (f_ptr->flags.has_not(TerrainCharacteristics::OPEN)) {
-        msg_format(_("%sはがっちりと閉じられているようだ。", "The %s appears to be stuck."), terrains_info[g_ptr->get_feat_mimic()].name.data());
-    } else if (f_ptr->power) {
-        i = player_ptr->skill_dis;
+    if (terrain.flags.has_not(TerrainCharacteristics::OPEN)) {
+        constexpr auto fmt = _("%sはがっちりと閉じられているようだ。", "The %s appears to be stuck.");
+        msg_format(fmt, grid.get_terrain_mimic().name.data());
+    } else if (terrain.power) {
+        auto power_disarm = player_ptr->skill_dis;
         const auto effects = player_ptr->effects();
         if (effects->blindness()->is_blind() || no_lite(player_ptr)) {
-            i = i / 10;
+            power_disarm = power_disarm / 10;
         }
 
         if (effects->confusion()->is_confused() || effects->hallucination()->is_hallucinated()) {
-            i = i / 10;
+            power_disarm = power_disarm / 10;
         }
 
-        j = f_ptr->power;
-        j = i - (j * 4);
-        if (j < 2) {
-            j = 2;
+        auto power_terrain = terrain.power;
+        power_terrain = power_disarm - (power_terrain * 4);
+        if (power_terrain < 2) {
+            power_terrain = 2;
         }
 
-        if (randint0(100) < j) {
+        if (randint0(100) < power_terrain) {
             msg_print(_("鍵をはずした。", "You have picked the lock."));
             cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::OPEN);
             sound(SOUND_OPENDOOR);
@@ -206,7 +213,7 @@ bool easy_open_door(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 bool exe_disarm_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJECT_IDX o_idx)
 {
-    bool more = false;
+    const Pos2D pos(y, x);
     auto *o_ptr = &player_ptr->current_floor_ptr->o_list[o_idx];
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
     int i = player_ptr->skill_dis;
@@ -219,11 +226,12 @@ bool exe_disarm_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJECT_IDX
         i = i / 10;
     }
 
-    int j = i - o_ptr->pval;
+    auto j = i - o_ptr->pval;
     if (j < 2) {
         j = 2;
     }
 
+    auto more = false;
     if (!o_ptr->is_known()) {
         msg_print(_("トラップが見あたらない。", "I don't see any traps."));
     } else if (o_ptr->pval <= 0) {
@@ -244,7 +252,7 @@ bool exe_disarm_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJECT_IDX
     } else {
         msg_print(_("トラップを作動させてしまった!", "You set off a trap!"));
         sound(SOUND_FAIL);
-        Chest(player_ptr).chest_trap(y, x, o_idx);
+        Chest(player_ptr).fire_trap(pos, o_idx);
     }
 
     return more;
@@ -267,11 +275,11 @@ bool exe_disarm_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJECT_IDX
 
 bool exe_disarm(PlayerType *player_ptr, POSITION y, POSITION x, DIRECTION dir)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    concptr name = f_ptr->name.data();
-    int power = f_ptr->power;
-    bool more = false;
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
+    const auto &name = terrain.name;
+    int power = terrain.power;
     int i = player_ptr->skill_dis;
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
     auto effects = player_ptr->effects();
@@ -288,8 +296,9 @@ bool exe_disarm(PlayerType *player_ptr, POSITION y, POSITION x, DIRECTION dir)
         j = 2;
     }
 
+    auto more = false;
     if (randint0(100) < j) {
-        msg_format(_("%sを解除した。", "You have disarmed the %s."), name);
+        msg_format(_("%sを解除した。", "You have disarmed the %s."), name.data());
         gain_exp(player_ptr, power);
         cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::DISARM);
         exe_movement(player_ptr, dir, easy_disarm, false);
@@ -298,10 +307,10 @@ bool exe_disarm(PlayerType *player_ptr, POSITION y, POSITION x, DIRECTION dir)
             flush();
         }
 
-        msg_format(_("%sの解除に失敗した。", "You failed to disarm the %s."), name);
+        msg_format(_("%sの解除に失敗した。", "You failed to disarm the %s."), name.data());
         more = true;
     } else {
-        msg_format(_("%sを作動させてしまった!", "You set off the %s!"), name);
+        msg_format(_("%sを作動させてしまった!", "You set off the %s!"), name.data());
         exe_movement(player_ptr, dir, easy_disarm, false);
     }
 
@@ -324,27 +333,29 @@ bool exe_disarm(PlayerType *player_ptr, POSITION y, POSITION x, DIRECTION dir)
  */
 bool exe_bash(PlayerType *player_ptr, POSITION y, POSITION x, DIRECTION dir)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(y, x);
+    const auto &grid = floor.get_grid(pos);
+    const auto &terrain = grid.get_terrain();
     int bash = adj_str_blow[player_ptr->stat_index[A_STR]];
-    int temp = f_ptr->power;
-    bool more = false;
-    concptr name = terrains_info[g_ptr->get_feat_mimic()].name.data();
+    int power = terrain.power;
+    const auto &name = grid.get_terrain_mimic().name;
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-    msg_format(_("%sに体当たりをした!", "You smash into the %s!"), name);
-    temp = (bash - (temp * 10));
+    msg_format(_("%sに体当たりをした!", "You smash into the %s!"), name.data());
+    power = (bash - (power * 10));
     if (PlayerClass(player_ptr).equals(PlayerClassType::BERSERKER)) {
-        temp *= 2;
+        power *= 2;
     }
 
-    if (temp < 1) {
-        temp = 1;
+    if (power < 1) {
+        power = 1;
     }
 
-    if (randint0(100) < temp) {
-        msg_format(_("%sを壊した!", "The %s crashes open!"), name);
-        sound(f_ptr->flags.has(TerrainCharacteristics::GLASS) ? SOUND_GLASS : SOUND_OPENDOOR);
-        if ((randint0(100) < 50) || (feat_state(player_ptr->current_floor_ptr, g_ptr->feat, TerrainCharacteristics::OPEN) == g_ptr->feat) || f_ptr->flags.has(TerrainCharacteristics::GLASS)) {
+    auto more = false;
+    if (randint0(100) < power) {
+        msg_format(_("%sを壊した!", "The %s crashes open!"), name.data());
+        sound(terrain.flags.has(TerrainCharacteristics::GLASS) ? SOUND_GLASS : SOUND_OPENDOOR);
+        if ((randint0(100) < 50) || (feat_state(player_ptr->current_floor_ptr, grid.feat, TerrainCharacteristics::OPEN) == grid.feat) || terrain.flags.has(TerrainCharacteristics::GLASS)) {
             cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::BASH);
         } else {
             cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::OPEN);
@@ -352,7 +363,7 @@ bool exe_bash(PlayerType *player_ptr, POSITION y, POSITION x, DIRECTION dir)
 
         exe_movement(player_ptr, dir, false, false);
     } else if (randint0(100) < adj_dex_safe[player_ptr->stat_index[A_DEX]] + player_ptr->lev) {
-        msg_format(_("この%sは頑丈だ。", "The %s holds firm."), name);
+        msg_format(_("この%sは頑丈だ。", "The %s holds firm."), name.data());
         more = true;
     } else {
         msg_print(_("体のバランスをくずしてしまった。", "You are off-balance."));
index 7911f61..ed472aa 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file open-close-execution.h
  * @brief 扉や箱を開ける処理のヘッダ
index 3072426..3e29f2b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file open-util.cpp
  * @brief 開閉処理関連関数
  */
@@ -20,9 +20,9 @@
  * @param trapped TRUEならばトラップが存在する箱のみ、FALSEならば空でない箱全てを対象にする
  * @return 箱が存在する場合そのオブジェクトID、存在しない場合0を返す。
  */
-OBJECT_IDX chest_check(FloorType *floor_ptr, POSITION y, POSITION x, bool trapped)
+short chest_check(FloorType *floor_ptr, const Pos2D &pos, bool trapped)
 {
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
+    auto *g_ptr = &floor_ptr->get_grid(pos);
     for (const auto this_o_idx : g_ptr->o_idx_list) {
         const auto &item = floor_ptr->o_list[this_o_idx];
         const auto is_empty = trapped || (item.pval == 0);
@@ -36,40 +36,33 @@ OBJECT_IDX chest_check(FloorType *floor_ptr, POSITION y, POSITION x, bool trappe
 }
 
 /*!
- * @brief プレイヤーの周辺9マスに箱のあるマスがいくつあるかを返す /
- * Return the number of chests around (or under) the character.
- * @param y 該当するマスの中から1つのY座標を返す参照ポインタ
- * @param x 該当するマスの中から1つのX座標を返す参照ポインタ
+ * @brief プレイヤーの周辺9マスに箱のあるマスがいくつあるかを返す
  * @param trapped TRUEならばトラップの存在が判明している箱のみ対象にする
- * @return 該当する地形の数
- * @details
- * If requested, count only trapped chests.
+ * @return 該当する地形の数と、該当するマスの中から1つの座標
  */
-int count_chests(PlayerType *player_ptr, POSITION *y, POSITION *x, bool trapped)
+std::pair<int, Pos2D> count_chests(PlayerType *player_ptr, bool trapped)
 {
-    int count = 0;
-    for (DIRECTION d = 0; d < 9; d++) {
-        POSITION yy = player_ptr->y + ddy_ddd[d];
-        POSITION xx = player_ptr->x + ddx_ddd[d];
-        OBJECT_IDX o_idx = chest_check(player_ptr->current_floor_ptr, yy, xx, false);
-        if (!o_idx) {
+    Pos2D pos(0, 0);
+    auto count = 0;
+    for (auto d = 0; d < 9; d++) {
+        const Pos2D pos_neighbor(player_ptr->y + ddy_ddd[d], player_ptr->x + ddx_ddd[d]);
+        const auto o_idx = chest_check(player_ptr->current_floor_ptr, pos_neighbor, false);
+        if (o_idx == 0) {
             continue;
         }
 
-        ItemEntity *o_ptr;
-        o_ptr = &player_ptr->current_floor_ptr->o_list[o_idx];
-        if (o_ptr->pval == 0) {
+        const auto &item = player_ptr->current_floor_ptr->o_list[o_idx];
+        if (item.pval == 0) {
             continue;
         }
 
-        if (trapped && (!o_ptr->is_known() || ((o_ptr->pval > 0) && chest_traps[o_ptr->pval].none()))) {
+        if (trapped && (!item.is_known() || ((item.pval > 0) && chest_traps[item.pval].none()))) {
             continue;
         }
 
         ++count;
-        *y = yy;
-        *x = xx;
+        pos = pos_neighbor;
     }
 
-    return count;
+    return { count, pos };
 }
index 3d60a67..6331604 100644 (file)
@@ -1,12 +1,13 @@
-#pragma once
+#pragma once
 /*!
  * @file open-util.h
  * @brief 開閉処理関連関数ヘッダ
  */
 
-#include "system/angband.h"
+#include "util/point-2d.h"
+#include <utility>
 
 class FloorType;
 class PlayerType;
-OBJECT_IDX chest_check(FloorType *floor_ptr, POSITION y, POSITION x, bool trapped);
-int count_chests(PlayerType *player_ptr, POSITION *y, POSITION *x, bool trapped);
+short chest_check(FloorType *floor_ptr, const Pos2D &pos, bool trapped);
+std::pair<int, Pos2D> count_chests(PlayerType *player_ptr, bool trapped);
index 4aebfbc..d354edf 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file racial-execution.cpp
  * @brief レイシャルパワー実行処理実装
  */
@@ -71,7 +71,7 @@ PERCENTAGE racial_chance(PlayerType *player_ptr, rpi_type *rpi_ptr)
 
     auto special_easy = PlayerClass(player_ptr).equals(PlayerClassType::IMITATOR);
     special_easy &= player_ptr->inventory_list[INVEN_NECK].is_specific_artifact(FixedArtifactId::GOGO_PENDANT);
-    special_easy &= rpi_ptr->racial_name.compare("倍返し") == 0;
+    special_easy &= rpi_ptr->racial_name == _("倍返し", "Double Revenge");
     if (special_easy) {
         difficulty -= 12;
     }
@@ -81,9 +81,9 @@ PERCENTAGE racial_chance(PlayerType *player_ptr, rpi_type *rpi_ptr)
     }
 
     difficulty = difficulty / 2;
-    const BASE_STATUS stat = player_ptr->stat_cur[rpi_ptr->stat];
-    int sum = 0;
-    for (int i = 1; i <= stat; i++) {
+    const auto stat = player_ptr->stat_cur[rpi_ptr->stat];
+    auto sum = 0;
+    for (auto i = 1; i <= stat; i++) {
         int val = i - difficulty;
         if (val > 0) {
             sum += (val <= difficulty) ? val : difficulty;
@@ -146,7 +146,7 @@ racial_level_check_result check_racial_level(PlayerType *player_ptr, rpi_type *r
         energy.reset_player_turn();
         return RACIAL_CANCEL;
     } else if (player_ptr->chp < use_hp) {
-        if (!get_check(_("本当に今の衰弱した状態でこの能力を使いますか?", "Really use the power in your weakened state? "))) {
+        if (!input_check(_("本当に今の衰弱した状態でこの能力を使いますか?", "Really use the power in your weakened state? "))) {
             energy.reset_player_turn();
             return RACIAL_CANCEL;
         }
index eb32e1b..f0c0c10 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file racial-execution.h
  * @brief レイシャルパワー実行処理ヘッダ
index 3c83cd5..ac8a6cc 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file run-execution.cpp
  * @brief プレイヤーの走行処理実装
  */
@@ -57,31 +57,29 @@ static bool find_breakleft;
  */
 static bool see_wall(PlayerType *player_ptr, DIRECTION dir, POSITION y, POSITION x)
 {
-    y += ddy[dir];
-    x += ddx[dir];
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!in_bounds2(floor_ptr, y, x)) {
+    const Pos2D pos(y + ddy[dir], x + ddx[dir]);
+    if (!in_bounds2(floor_ptr, pos.y, pos.x)) {
         return false;
     }
 
-    grid_type *g_ptr;
-    g_ptr = &floor_ptr->grid_array[y][x];
-    if (!g_ptr->is_mark()) {
+    const auto &grid = floor_ptr->get_grid(pos);
+    if (!grid.is_mark()) {
         return false;
     }
 
-    int16_t feat = g_ptr->get_feat_mimic();
-    auto *f_ptr = &terrains_info[feat];
-    if (!player_can_enter(player_ptr, feat, 0)) {
-        return f_ptr->flags.has_not(TerrainCharacteristics::DOOR);
+    const auto terrain_id = grid.get_feat_mimic();
+    const auto &terrain = grid.get_terrain_mimic();
+    if (!player_can_enter(player_ptr, terrain_id, 0)) {
+        return terrain.flags.has_not(TerrainCharacteristics::DOOR);
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::AVOID_RUN) && !ignore_avoid_run) {
+    if (terrain.flags.has(TerrainCharacteristics::AVOID_RUN) && !ignore_avoid_run) {
         return true;
     }
 
-    if (f_ptr->flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY })) {
-        return f_ptr->flags.has_not(TerrainCharacteristics::DOOR);
+    if (terrain.flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY })) {
+        return terrain.flags.has_not(TerrainCharacteristics::DOOR);
     }
 
     return false;
@@ -202,12 +200,14 @@ static bool see_nothing(PlayerType *player_ptr, DIRECTION dir, POSITION y, POSIT
  */
 static bool run_test(PlayerType *player_ptr)
 {
-    DIRECTION prev_dir = find_prevdir;
-    int max = (prev_dir & 0x01) + 1;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((disturb_trap_detect || alert_trap_detect) && player_ptr->dtrap && !(floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_IN_DETECT)) {
+    const auto prev_dir = find_prevdir;
+    const auto max = (prev_dir & 0x01) + 1;
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto p_pos = player_ptr->get_position();
+    const auto &p_grid = floor.get_grid(p_pos);
+    if ((disturb_trap_detect || alert_trap_detect) && player_ptr->dtrap && !(p_grid.info & CAVE_IN_DETECT)) {
         player_ptr->dtrap = false;
-        if (!(floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_UNSAFE)) {
+        if (!(p_grid.info & CAVE_UNSAFE)) {
             if (alert_trap_detect) {
                 msg_print(_("* 注意:この先はトラップの感知範囲外です! *", "*Leaving trap detect region!*"));
             }
@@ -219,43 +219,39 @@ static bool run_test(PlayerType *player_ptr)
         }
     }
 
-    DIRECTION check_dir = 0;
-    int option = 0, option2 = 0;
-    for (int i = -max; i <= max; i++) {
-        DIRECTION new_dir = cycle[chome[prev_dir] + i];
-        int row = player_ptr->y + ddy[new_dir];
-        int col = player_ptr->x + ddx[new_dir];
-        grid_type *g_ptr;
-        g_ptr = &floor_ptr->grid_array[row][col];
-        FEAT_IDX feat = g_ptr->get_feat_mimic();
-        TerrainType *f_ptr;
-        f_ptr = &terrains_info[feat];
-        if (g_ptr->m_idx) {
-            auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
-            if (m_ptr->ml) {
+    auto check_dir = 0;
+    auto option = 0;
+    auto option2 = 0;
+    for (auto i = -max; i <= max; i++) {
+        int new_dir = cycle[chome[prev_dir] + i];
+        const Pos2D pos(player_ptr->y + ddy[new_dir], player_ptr->x + ddx[new_dir]);
+        const auto &grid = floor.get_grid(pos);
+        if (grid.m_idx) {
+            const auto &monster = floor.m_list[grid.m_idx];
+            if (monster.ml) {
                 return true;
             }
         }
 
-        for (const auto this_o_idx : g_ptr->o_idx_list) {
-            ItemEntity *o_ptr;
-            o_ptr = &floor_ptr->o_list[this_o_idx];
-            if (o_ptr->marked.has(OmType::FOUND)) {
+        for (const auto this_o_idx : grid.o_idx_list) {
+            const auto &item = floor.o_list[this_o_idx];
+            if (item.marked.has(OmType::FOUND)) {
                 return true;
             }
         }
 
-        bool inv = true;
-        if (g_ptr->is_mark()) {
-            bool notice = f_ptr->flags.has(TerrainCharacteristics::NOTICE);
-            if (notice && f_ptr->flags.has(TerrainCharacteristics::MOVE)) {
-                if (find_ignore_doors && f_ptr->flags.has_all_of({ TerrainCharacteristics::DOOR, TerrainCharacteristics::CLOSE })) {
+        auto inv = true;
+        if (grid.is_mark()) {
+            const auto &terrain = grid.get_terrain_mimic();
+            auto notice = terrain.flags.has(TerrainCharacteristics::NOTICE);
+            if (notice && terrain.flags.has(TerrainCharacteristics::MOVE)) {
+                if (find_ignore_doors && terrain.flags.has_all_of({ TerrainCharacteristics::DOOR, TerrainCharacteristics::CLOSE })) {
                     notice = false;
-                } else if (find_ignore_stairs && f_ptr->flags.has(TerrainCharacteristics::STAIRS)) {
+                } else if (find_ignore_stairs && terrain.flags.has(TerrainCharacteristics::STAIRS)) {
                     notice = false;
-                } else if (f_ptr->flags.has(TerrainCharacteristics::LAVA) && (has_immune_fire(player_ptr) || is_invuln(player_ptr))) {
+                } else if (terrain.flags.has(TerrainCharacteristics::LAVA) && (has_immune_fire(player_ptr) || is_invuln(player_ptr))) {
                     notice = false;
-                } else if (f_ptr->flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP }) && (player_ptr->levitation || player_ptr->can_swim || (calc_inventory_weight(player_ptr) <= calc_weight_limit(player_ptr)))) {
+                } else if (terrain.flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP }) && (player_ptr->levitation || player_ptr->can_swim || (calc_inventory_weight(player_ptr) <= calc_weight_limit(player_ptr)))) {
                     notice = false;
                 }
             }
@@ -267,7 +263,7 @@ static bool run_test(PlayerType *player_ptr)
             inv = false;
         }
 
-        if (!inv && see_wall(player_ptr, 0, row, col)) {
+        if (!inv && see_wall(player_ptr, 0, pos.y, pos.x)) {
             if (find_openarea) {
                 if (i < 0) {
                     find_breakright = true;
@@ -403,7 +399,7 @@ void run_step(PlayerType *player_ptr, DIRECTION dir)
 
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
     exe_movement(player_ptr, find_current, false, false);
-    if (player_bold(player_ptr, player_ptr->run_py, player_ptr->run_px)) {
+    if (player_ptr->is_located_at_running_destination()) {
         player_ptr->run_py = 0;
         player_ptr->run_px = 0;
         disturb(player_ptr, false, false);
index f4f79a4..39a8845 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file run-execution.h
  * @brief プレイヤーの走行処理ヘッダ
index 6e682ce..c785ff6 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file travel-execution.cpp
  * @brief トラベル移動処理実装
  */
@@ -55,7 +55,7 @@ static DIRECTION travel_test(PlayerType *player_ptr, DIRECTION prev_dir)
     }
 
     int max = (prev_dir & 0x01) + 1;
-    const grid_type *g_ptr;
+    const Grid *g_ptr;
     for (int i = -max; i <= max; i++) {
         DIRECTION dir = cycle[chome[prev_dir] + i];
         POSITION row = player_ptr->y + ddy[dir];
index e38d07b..79437f5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file travel-execution.h
  * @brief トラベル移動処理ヘッダ
index cc69aa2..4e88c1b 100644 (file)
@@ -1,10 +1,9 @@
-/*!
+/*!
  * @file tunnel-execution.cpp
  * @brief 掘削処理実装
  */
 #include "action/tunnel-execution.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "floor/cave.h"
 #include "grid/grid.h"
 #include "io/input-key-requester.h"
@@ -15,6 +14,7 @@
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
  * @param x 対象を行うマスのX座標
  * @return
  */
-static bool do_cmd_tunnel_test(FloorType *floor_ptr, POSITION y, POSITION x)
+static bool do_cmd_tunnel_test(const Grid &grid)
 {
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
-    if (!g_ptr->is_mark()) {
+    if (!grid.is_mark()) {
         msg_print(_("そこには何も見当たらない。", "You see nothing there."));
         return false;
     }
 
-    if (!g_ptr->cave_has_flag(TerrainCharacteristics::TUNNEL)) {
+    if (!grid.cave_has_flag(TerrainCharacteristics::TUNNEL)) {
         msg_print(_("そこには掘るものが見当たらない。", "You see nothing there to tunnel."));
         return false;
     }
@@ -55,52 +54,50 @@ static bool do_cmd_tunnel_test(FloorType *floor_ptr, POSITION y, POSITION x)
  */
 bool exe_tunnel(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    grid_type *g_ptr;
-    TerrainType *f_ptr, *mimic_f_ptr;
-    int power;
-    concptr name;
-    bool more = false;
-    if (!do_cmd_tunnel_test(player_ptr->current_floor_ptr, y, x)) {
+    auto more = false;
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    if (!do_cmd_tunnel_test(grid)) {
         return false;
     }
 
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    f_ptr = &terrains_info[g_ptr->feat];
-    power = f_ptr->power;
-    mimic_f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
-    name = mimic_f_ptr->name.data();
+    const auto &terrain = grid.get_terrain();
+    const auto power = terrain.power;
+    const auto &terrain_mimic = grid.get_terrain_mimic();
+    const auto &name = terrain_mimic.name;
     if (command_rep == 0) {
         sound(SOUND_DIG);
     }
-    if (f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
-        if (mimic_f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
+
+    if (terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
+        if (terrain_mimic.flags.has(TerrainCharacteristics::PERMANENT)) {
             msg_print(_("この岩は硬すぎて掘れないようだ。", "This seems to be permanent rock."));
         } else {
             msg_print(_("そこは掘れない!", "You can't tunnel through that!"));
         }
-    } else if (f_ptr->flags.has(TerrainCharacteristics::CAN_DIG)) {
+    } else if (terrain.flags.has(TerrainCharacteristics::CAN_DIG)) {
         if (player_ptr->skill_dig > randint0(20 * power)) {
             sound(SOUND_DIG_THROUGH);
-            msg_format(_("%sをくずした。", "You have removed the %s."), name);
+            msg_format(_("%sをくずした。", "You have removed the %s."), name.data());
             cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::TUNNEL);
-            player_ptr->update |= PU_FLOW;
+            RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
         } else {
-            msg_format(_("%sをくずしている。", "You dig into the %s."), name);
+            msg_format(_("%sをくずしている。", "You dig into the %s."), name.data());
             more = true;
         }
     } else {
-        bool tree = mimic_f_ptr->flags.has(TerrainCharacteristics::TREE);
+        bool tree = terrain_mimic.flags.has(TerrainCharacteristics::TREE);
         if (player_ptr->skill_dig > power + randint0(40 * power)) {
             sound(SOUND_DIG_THROUGH);
             if (tree) {
-                msg_format(_("%sを切り払った。", "You have cleared away the %s."), name);
+                msg_format(_("%sを切り払った。", "You have cleared away the %s."), name.data());
             } else {
                 msg_print(_("穴を掘り終えた。", "You have finished the tunnel."));
-                player_ptr->update |= (PU_FLOW);
+                RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
             }
 
-            if (f_ptr->flags.has(TerrainCharacteristics::GLASS)) {
+            if (terrain.flags.has(TerrainCharacteristics::GLASS)) {
                 sound(SOUND_GLASS);
             }
 
@@ -109,19 +106,19 @@ bool exe_tunnel(PlayerType *player_ptr, POSITION y, POSITION x)
             chg_virtue(player_ptr, Virtue::NATURE, -1);
         } else {
             if (tree) {
-                msg_format(_("%sを切っている。", "You chop away at the %s."), name);
+                msg_format(_("%sを切っている。", "You chop away at the %s."), name.data());
                 if (randint0(100) < 25) {
                     search(player_ptr);
                 }
             } else {
-                msg_format(_("%sに穴を掘っている。", "You tunnel into the %s."), name);
+                msg_format(_("%sに穴を掘っている。", "You tunnel into the %s."), name.data());
             }
 
             more = true;
         }
     }
 
-    if (is_hidden_door(player_ptr, g_ptr) && (randint0(100) < 25)) {
+    if (is_hidden_door(player_ptr, grid) && (randint0(100) < 25)) {
         search(player_ptr);
     }
 
index 6ecc77e..70bef78 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file tunnel-execution.h
  * @brief 掘削処理ヘッダ
index 91b7cec..efbed50 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file weapon-shield.cpp
  * @brief 手装備持ち替え処理実装
  */
 /*!
  * @brief 持ち替え処理
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 持ち替えを行いたい装備部位ID
+ * @param i_idx 持ち替えを行いたい装備部位ID
  */
-void verify_equip_slot(PlayerType *player_ptr, INVENTORY_IDX item)
+void verify_equip_slot(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
     ItemEntity *o_ptr, *new_o_ptr;
     std::string item_name;
-    if (item == INVEN_MAIN_HAND) {
+    if (i_idx == INVEN_MAIN_HAND) {
         if (!has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
             return;
         }
@@ -52,7 +52,7 @@ void verify_equip_slot(PlayerType *player_ptr, INVENTORY_IDX item)
         return;
     }
 
-    if (item != INVEN_SUB_HAND) {
+    if (i_idx != INVEN_SUB_HAND) {
         return;
     }
 
index 7ee5fa3..334119a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file weapon-shield.h
  * @brief 手装備持ち替え処理ヘッダ
@@ -7,4 +7,4 @@
 #include "system/angband.h"
 
 class PlayerType;
-void verify_equip_slot(PlayerType *player_ptr, INVENTORY_IDX item);
+void verify_equip_slot(PlayerType *player_ptr, INVENTORY_IDX i_idx);
index 86e6b9d..2a963eb 100644 (file)
Binary files a/src/ang_jp.rc and b/src/ang_jp.rc differ
diff --git a/src/artifact/artifact-info.cpp b/src/artifact/artifact-info.cpp
deleted file mode 100644 (file)
index db77747..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*!
- * @file artifact-info.cpp
- * @brief アーティファクトの発動効果取得関数定義
- */
-
-#include "artifact/artifact-info.h"
-#include "artifact/random-art-effects.h"
-#include "object-enchant/activation-info-table.h"
-#include "object-enchant/object-ego.h"
-#include "object-enchant/tr-types.h"
-#include "smith/object-smith.h"
-#include "system/artifact-type-definition.h"
-#include "system/baseitem-info.h"
-#include "system/item-entity.h"
-#include "util/bit-flags-calculator.h"
-#include "util/enum-converter.h"
-
-/*!
- * @brief オブジェクトから能力発動IDを取得する。
- * @details いくつかのケースで定義されている発動効果から、
- * 鍛冶師による付与>固定アーティファクト>エゴ>ランダムアーティファクト>ベースアイテムの優先順位で走査していく。
- * @param o_ptr 対象のオブジェクト構造体ポインタ
- * @return 発動効果のIDを返す
- */
-RandomArtActType activation_index(const ItemEntity *o_ptr)
-{
-    if (auto act_idx = Smith::object_activation(o_ptr); act_idx.has_value()) {
-        return act_idx.value();
-    }
-
-    if (o_ptr->is_fixed_artifact()) {
-        const auto &artifact = o_ptr->get_fixed_artifact();
-        if (artifact.flags.has(TR_ACTIVATE)) {
-            return artifact.act_idx;
-        }
-    }
-
-    if (o_ptr->is_ego()) {
-        const auto &ego = o_ptr->get_ego();
-        if (ego.flags.has(TR_ACTIVATE)) {
-            return ego.act_idx;
-        }
-    }
-
-    if (!o_ptr->is_random_artifact()) {
-        const auto &baseitem = o_ptr->get_baseitem();
-        if (baseitem.flags.has(TR_ACTIVATE)) {
-            return baseitem.act_idx;
-        }
-    }
-
-    return o_ptr->activation_id;
-}
-
-/*!
- * @brief オブジェクトから発動効果構造体のポインタを取得する。
- * @details activation_index() 関数の結果から参照する。
- * @param o_ptr 対象のオブジェクト構造体ポインタ
- * @return 発動効果構造体のポインタを返す
- */
-std::optional<const activation_type *> find_activation_info(const ItemEntity *o_ptr)
-{
-    const auto index = activation_index(o_ptr);
-    for (const auto &p : activation_info) {
-        if (p.index == index) {
-            return &p;
-        }
-    }
-
-    return std::nullopt;
-}
diff --git a/src/artifact/artifact-info.h b/src/artifact/artifact-info.h
deleted file mode 100644 (file)
index cee8649..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*!
- * @file artifact-info.h
- * @brief アーティファクトの発動効果取得関数ヘッダ
- */
-
-#pragma once
-
-#include <optional>
-
-enum class RandomArtActType : short;
-struct activation_type;
-class ItemEntity;
-RandomArtActType activation_index(const ItemEntity *o_ptr);
-std::optional<const activation_type *> find_activation_info(const ItemEntity *o_ptr);
index 62c85e4..2a1c4d2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file fixed-art-generator.cpp
  * @brief 固定アーティファクトの生成 / Artifact code
  * @date 2020/07/14
index 2634c1c..dd38e38 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file fixed-art-generator.h
  * @brief 固定アーティファクトの生成処理ヘッダ
index 7d17ddc..4a4664a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file fixed-art-types.h
  * @brief 固定アーティファクトのハードコード処理用ID定義
@@ -6,6 +6,7 @@
 
 enum class FixedArtifactId : short {
     NONE = 0,
+    GALADRIEL_PHIAL = 1,
     JUDGE = 3,
     POWER = 13,
     CRIMSON = 16,
index 0919da1..c7d9353 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file random-art-activation.cpp
  * @brief ランダムアーティファクトの発動実装定義
  */
index bccee9a..a4857a6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file random-art-activation.h
  * @brief ランダムアーティファクトの発動実装ヘッダ
index 5cbc612..8d54583 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file random-art-bias-types.h
  * @brief ランダムアーティファクトのバイアス定義
index 648a729..a53c3ee 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file random-art-characteristics.cpp
  * @brief ランダムアーティファクトのバイアス付加処理実装
  */
@@ -9,7 +9,6 @@
 #include "io/files-util.h"
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
@@ -103,30 +102,26 @@ void curse_artifact(PlayerType *player_ptr, ItemEntity *o_ptr)
  * @param armour 防具かどうか
  * @param power 生成パワー
  * @return ファイル名
- * @detail ss << tmp_grade; と直接呼ぶとC4866警告が出るので、別変数で受けて抑制中.
  */
 static std::string get_random_art_filename(const bool armour, const int power)
 {
-    const std::string_view prefix(armour ? "a_" : "w_");
-    constexpr std::string_view suffix(_("_j.txt", ".txt"));
-    std::string_view tmp_grade;
+    std::stringstream ss;
+    ss << (armour ? "a_" : "w_");
     switch (power) {
     case 0:
-        tmp_grade = "cursed";
+        ss << "cursed";
         break;
     case 1:
-        tmp_grade = "low";
+        ss << "low";
         break;
     case 2:
-        tmp_grade = "med";
+        ss << "med";
         break;
     default:
-        tmp_grade = "high";
+        ss << "high";
     }
 
-    std::stringstream ss;
-    const auto &grade = tmp_grade;
-    ss << prefix << grade << suffix;
+    ss << _("_j.txt", ".txt");
     return ss.str();
 }
 
@@ -155,20 +150,20 @@ std::string get_random_name(const ItemEntity &item, bool armour, int power)
     auto filename = get_random_art_filename(armour, power);
     auto random_artifact_name = get_random_line(filename.data(), item.artifact_bias);
 #ifdef JP
-    if (random_artifact_name.has_value()) {
-        return random_artifact_name.value();
+    if (random_artifact_name) {
+        return *random_artifact_name;
     }
 
     return get_table_name();
 #else
-    return random_artifact_name.value();
+    return *random_artifact_name;
 #endif
 }
 
 /*対邪平均ダメージの計算処理*/
 static int calc_arm_avgdamage(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
     int base, forced, vorpal;
     int s_evil = forced = vorpal = 0;
     int dam = base = (o_ptr->dd * o_ptr->ds + o_ptr->dd) / 2;
@@ -193,13 +188,14 @@ static int calc_arm_avgdamage(PlayerType *player_ptr, ItemEntity *o_ptr)
     }
 
     dam = dam + o_ptr->to_d;
-    msg_format_wizard(player_ptr, CHEAT_OBJECT, "素:%d> 対邪:%d> 理力:%d> 切:%d> 最終:%d", base, s_evil, forced, vorpal, dam);
+    constexpr auto fmt = _("素:%d> 対邪:%d> 理力:%d> 切:%d> 最終:%d", "Normal:%d> Evil:%d> Force:%d> Vorpal:%d> Total:%d");
+    msg_format_wizard(player_ptr, CHEAT_OBJECT, fmt, base, s_evil, forced, vorpal, dam);
     return dam;
 }
 
 bool has_extreme_damage_rate(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
     if (flags.has(TR_VAMPIRIC)) {
         if (flags.has(TR_BLOWS) && (o_ptr->pval == 1) && (calc_arm_avgdamage(player_ptr, o_ptr) > 52)) {
             return true;
index c16d1dc..d8b6a37 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file random-art-characteristics.h
  * @brief ランダムアーティファクトのバイアス付加処理ヘッダ
index 7023242..c5f6b6e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @file random-art-effects.h
index 38ccb4b..2271045 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file random-art-generator.cpp
  * @brief ランダムアーティファクトの生成メイン定義 / Artifact code
  * @date 2020/07/14
@@ -24,7 +24,6 @@
 #include "object-enchant/tr-types.h"
 #include "object-hook/hook-armor.h"
 #include "object-hook/hook-weapon.h"
-#include "object/object-flags.h"
 #include "object/object-kind-hook.h"
 #include "object/object-value-calc.h"
 #include "object/tval-types.h"
@@ -34,8 +33,8 @@
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "view/display-messages.h"
 #include "wizard/artifact-bias-table.h"
 #include "wizard/wizard-messages.h"
@@ -45,9 +44,7 @@
 static bool weakening_artifact(ItemEntity *o_ptr)
 {
     const auto &baseitem = o_ptr->get_baseitem();
-    auto flags = object_flags(o_ptr);
-
-    if (flags.has(TR_KILL_EVIL)) {
+    if (o_ptr->get_flags().has(TR_KILL_EVIL)) {
         o_ptr->art_flags.reset(TR_KILL_EVIL);
         o_ptr->art_flags.set(TR_SLAY_EVIL);
         return true;
@@ -389,9 +386,9 @@ static std::string name_unnatural_random_artifact(PlayerType *player_ptr, ItemEn
         return get_random_name(*o_ptr, o_ptr->is_protector(), power_level);
     }
 
-    concptr ask_msg = _("このアーティファクトを何と名付けますか?", "What do you want to call the artifact? ");
+    constexpr auto prompt = _("このアーティファクトを何と名付けますか?", "What do you want to call the artifact? ");
     object_aware(player_ptr, o_ptr);
-    object_known(o_ptr);
+    o_ptr->mark_as_known();
     o_ptr->ident |= IDENT_FULL_KNOWN;
     o_ptr->randart_name.reset();
     (void)screen_object(player_ptr, o_ptr, 0L);
@@ -401,16 +398,16 @@ static std::string name_unnatural_random_artifact(PlayerType *player_ptr, ItemEn
         ss << _("《", "'") << name << _("》", "'");
         return ss.str();
     };
-    char new_name[160] = "";
-    if (!get_string(ask_msg, new_name, sizeof new_name) || !new_name[0]) {
-        if (one_in_(2)) {
-            return wrap_name(get_table_sindarin_aux());
-        } else {
-            return wrap_name(get_table_name_aux());
-        }
+    const auto new_name = input_string(prompt, 160);
+    if (new_name && !new_name->empty()) {
+        return wrap_name(*new_name);
     }
 
-    return wrap_name(new_name);
+    if (one_in_(2)) {
+        return wrap_name(get_table_sindarin_aux());
+    }
+
+    return wrap_name(get_table_name_aux());
 }
 
 static void generate_unnatural_random_artifact(
@@ -420,7 +417,13 @@ static void generate_unnatural_random_artifact(
     msg_format_wizard(player_ptr, CHEAT_OBJECT,
         _("パワー %d で 価値 %d のランダムアーティファクト生成 バイアスは「%s」", "Random artifact generated - Power:%d Value:%d Bias:%s."), max_powers,
         total_flags, artifact_bias_name[o_ptr->artifact_bias]);
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
 }
 
 /*!
index 72f84f0..80a6293 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file random-art-generator.h
  * @brief ランダムアーティファクトの生成メインヘッダ / Artifact code
index 875f082..927d3c1 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file random-art-misc.cpp
  * @brief ランダムアーティファクト生成のその他特性バイアス付け実装 / Artifact code
  */
@@ -155,28 +155,17 @@ static void invest_misc_hit_dice(ItemEntity *o_ptr)
 
 static void invest_misc_string_esp(ItemEntity *o_ptr)
 {
-    switch (randint1(3)) {
-    case 1:
-        o_ptr->art_flags.set(TR_ESP_EVIL);
-        if (!o_ptr->artifact_bias && one_in_(3)) {
-            o_ptr->artifact_bias = BIAS_LAW;
-        }
-
-        return;
-    case 2:
-        o_ptr->art_flags.set(TR_ESP_NONLIVING);
-        if (!o_ptr->artifact_bias && one_in_(3)) {
-            o_ptr->artifact_bias = BIAS_MAGE;
-        }
+    constexpr std::array<std::tuple<tr_type, random_art_bias_type, int>, 3> candidates = { {
+        { TR_ESP_EVIL, BIAS_LAW, 3 },
+        { TR_ESP_NONLIVING, BIAS_MAGE, 3 },
+        { TR_TELEPATHY, BIAS_MAGE, 9 },
+    } };
 
-        return;
-    case 3:
-        o_ptr->art_flags.set(TR_TELEPATHY);
-        if (!o_ptr->artifact_bias && one_in_(9)) {
-            o_ptr->artifact_bias = BIAS_MAGE;
-        }
+    const auto &[flag, bias, denom] = rand_choice(candidates);
 
-        return;
+    o_ptr->art_flags.set(flag);
+    if ((o_ptr->artifact_bias == BIAS_NONE) && one_in_(denom)) {
+        o_ptr->artifact_bias = bias;
     }
 }
 
index b1c29e1..50d6490 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file random-art-misc.h
  * @brief ランダムアーティファクト生成のその他特性バイアス付けヘッダ / Artifact code
index 035bed8..d9dd0c1 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file random-art-pval-investor.cpp
  * @brief ランダムアーティファクトにpvalを追加する処理
  * @date 2020/07/14
index 25a43d9..f2a3b9e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file random-art-pval-investor.h
  * @brief ランダムアーティファクトのpval付加処理ヘッダ
index 3c5802d..1cc82d9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file random-art-resistance.cpp
  * @brief ランダムアーティファクトの耐性付加処理実装
  */
index d3e9d94..abd29ec 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file random-art-resistance.h
  * @brief ランダムアーティファクトの耐性付加処理ヘッダ
index 8fb530f..1d913c7 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file random-art-slay.cpp
  * @brief ランダムアーティファクトのスレイ付加処理実装
  */
index dbe3e92..98d0ab6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file random-art-slay.h
  * @brief ランダムアーティファクトのスレイ付加処理ヘッダ
index 059308f..7a79eba 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動拾いエディタのコマンドを受け付ける
  * @date 2020/04/26
  * @author Hourier
index 429eda2..cd55b02 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 int do_command_menu(int level, int start);
index 6c8dc15..9b720af 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Editor command id's
index 294a6f0..dfc9a8c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動拾いの記述
  * @date 2020/04/25
  * @author Hourier
@@ -231,15 +231,15 @@ static void describe_autpick_jp(char *buff, const autopick_type &entry, autopick
     if (describer->insc) {
         char tmp[MAX_INSCRIPTION + 1] = "";
         angband_strcat(tmp, describer->insc, MAX_INSCRIPTION);
-        angband_strcat(buff, format("に「%s」", tmp).data(), MAX_INSCRIPTION + 6);
+        angband_strcat(buff, format("に「%s」", tmp), MAX_INSCRIPTION + 6);
 
-        if (angband_strstr(describer->insc, "%%all")) {
+        if (str_find(describer->insc, "%%all")) {
             strcat(buff, "(%%allは全能力を表す英字の記号で置換)");
-        } else if (angband_strstr(describer->insc, "%all")) {
+        } else if (str_find(describer->insc, "%all")) {
             strcat(buff, "(%allは全能力を表す記号で置換)");
-        } else if (angband_strstr(describer->insc, "%%")) {
+        } else if (str_find(describer->insc, "%%")) {
             strcat(buff, "(%%は追加能力を表す英字の記号で置換)");
-        } else if (angband_strstr(describer->insc, "%")) {
+        } else if (str_find(describer->insc, "%")) {
             strcat(buff, "(%は追加能力を表す記号で置換)");
         }
 
index 9068550..bf84a47 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct autopick_type;
 void describe_autopick(char *buff, const autopick_type &entry);
index 3d2a091..21dc574 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動破壊の実行
  * @date 2020/04/25
  * @author Hourier
@@ -8,7 +8,6 @@
 #include "autopick/autopick-methods-table.h"
 #include "autopick/autopick-util.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "flavor/flavor-describer.h"
 #include "game-option/auto-destruction-options.h"
 #include "game-option/input-options.h"
@@ -30,6 +29,7 @@
 #include "system/item-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 
@@ -49,8 +49,8 @@ static bool is_leave_special_item(PlayerType *player_ptr, ItemEntity *o_ptr)
     const auto &bi_key = o_ptr->bi_key;
     const auto tval = bi_key.tval();
     if (PlayerRace(player_ptr).equals(PlayerRaceType::BALROG)) {
-        auto r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
-        if (bi_key == BaseitemKey(ItemKindType::CORPSE, SV_CORPSE) && angband_strchr("pht", monraces_info[r_idx].d_char)) {
+        const auto r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
+        if (o_ptr->is_corpse() && angband_strchr("pht", monraces_info[r_idx].d_char)) {
             return false;
         }
     } else if (pc.equals(PlayerClassType::ARCHER)) {
@@ -149,7 +149,7 @@ void auto_destroy_item(PlayerType *player_ptr, ItemEntity *o_ptr, int autopick_i
     }
 
     disturb(player_ptr, false, false);
-    if (!can_player_destroy_object(player_ptr, o_ptr)) {
+    if (!can_player_destroy_object(o_ptr)) {
         const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
         msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), item_name.data());
         return;
@@ -157,5 +157,5 @@ void auto_destroy_item(PlayerType *player_ptr, ItemEntity *o_ptr, int autopick_i
 
     autopick_last_destroyed_object = *o_ptr;
     o_ptr->marked.set(OmType::AUTODESTROY);
-    player_ptr->update |= PU_AUTO_DESTRUCTION;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::AUTO_DESTRUCTION);
 }
index 8d31f42..297ae63 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index 240ab14..39b532b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Dirty flag for text editor
index c78f594..1a76567 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動拾いエディタを表示させる
  * @date 2020/04/26
  * @author Hourier
@@ -14,6 +14,7 @@
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "view/display-util.h"
+#include <tuple>
 
 #define DESCRIPT_HGT 3
 
@@ -25,7 +26,7 @@ static void process_dirty_expression(PlayerType *player_ptr, text_body_type *tb)
 
     byte state = 0;
     for (int y = 0; tb->lines_list[y]; y++) {
-        concptr s = tb->lines_list[y];
+        auto s = tb->lines_list[y];
         tb->states[y] = state;
 
         if (*s++ != '?') {
@@ -66,7 +67,7 @@ void draw_text_editor(PlayerType *player_ptr, text_body_type *tb)
 {
     int by1 = 0, by2 = 0;
 
-    term_get_size(&tb->wid, &tb->hgt);
+    std::tie(tb->wid, tb->hgt) = term_get_size();
 
     /*
      * Top line (-1), description line (-3), separator (-1)
@@ -119,7 +120,7 @@ void draw_text_editor(PlayerType *player_ptr, text_body_type *tb)
     }
 
     if (tb->dirty_flags & DIRTY_MODE) {
-        char buf[MAX_LINELEN];
+        char buf[MAX_LINELEN]{};
         int sepa_length = tb->wid;
         int j = 0;
         for (; j < sepa_length; j++) {
index 1dd4c8e..094cbb4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct text_body_type;
 class PlayerType;
index 98b70f6..832172a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動拾いエディタ画面でキーを押した時の挙動一式
  * @date 2020/04/26
  * @author Hourier
@@ -26,6 +26,8 @@
 #include "system/player-type-definition.h"
 #include "term/term-color-types.h"
 #include "term/z-form.h"
+#include <string>
+#include <string_view>
 
 /*!
  * @brief
@@ -40,7 +42,7 @@ ape_quittance do_editor_command(PlayerType *player_ptr, text_body_type *tb, int
     switch (com_id) {
     case EC_QUIT: {
         if (tb->changed) {
-            if (!get_check(_("全ての変更を破棄してから終了します。よろしいですか? ", "Discard all changes and quit. Are you sure? "))) {
+            if (!input_check(_("全ての変更を破棄してから終了します。よろしいですか? ", "Discard all changes and quit. Are you sure? "))) {
                 break;
             }
         }
@@ -50,7 +52,7 @@ ape_quittance do_editor_command(PlayerType *player_ptr, text_body_type *tb, int
     case EC_SAVEQUIT:
         return APE_QUIT_AND_SAVE;
     case EC_REVERT: {
-        if (!get_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ", "Discard all changes and revert to original file. Are you sure? "))) {
+        if (!input_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ", "Discard all changes and revert to original file. Are you sure? "))) {
             break;
         }
 
@@ -63,7 +65,7 @@ ape_quittance do_editor_command(PlayerType *player_ptr, text_body_type *tb, int
         break;
     }
     case EC_HELP: {
-        (void)show_file(player_ptr, true, _("jeditor.txt", "editor.txt"), nullptr, 0, 0);
+        (void)show_file(player_ptr, true, _("jeditor.txt", "editor.txt"), 0, 0);
         tb->dirty_flags |= DIRTY_SCREEN;
         break;
     }
@@ -126,13 +128,14 @@ ape_quittance do_editor_command(PlayerType *player_ptr, text_body_type *tb, int
         }
         break;
     case EC_RIGHT: {
+        const int len = strlen(tb->lines_list[tb->cy]);
 #ifdef JP
-        if (iskanji(tb->lines_list[tb->cy][tb->cx])) {
+        if ((tb->cx + 1 < len) && iskanji(tb->lines_list[tb->cy][tb->cx])) {
             tb->cx++;
         }
 #endif
         tb->cx++;
-        int len = strlen(tb->lines_list[tb->cy]);
+
         if (len < tb->cx) {
             tb->cx = len;
             if (!tb->lines_list[tb->cy + 1]) {
@@ -258,9 +261,8 @@ ape_quittance do_editor_command(PlayerType *player_ptr, text_body_type *tb, int
         break;
     }
     case EC_PASTE: {
-        chain_str_type *chain = tb->yank;
         int len = strlen(tb->lines_list[tb->cy]);
-        if (!chain) {
+        if (tb->yank.empty()) {
             break;
         }
         if (tb->cx > len) {
@@ -272,42 +274,30 @@ ape_quittance do_editor_command(PlayerType *player_ptr, text_body_type *tb, int
             tb->dirty_flags |= DIRTY_ALL;
         }
 
-        while (chain) {
-            concptr yank_str = chain->s;
-            char buf[MAX_LINELEN];
-            int i;
-            char rest[MAX_LINELEN], *rest_ptr = rest;
-            for (i = 0; i < tb->cx; i++) {
-                buf[i] = tb->lines_list[tb->cy][i];
-            }
-
-            strcpy(rest, &(tb->lines_list[tb->cy][i]));
-            while (*yank_str && i < MAX_LINELEN - 1) {
-                buf[i++] = *yank_str++;
-            }
+        for (auto i = 0U; i < tb->yank.size(); ++i) {
+            const std::string_view line(tb->lines_list[tb->cy]);
+            std::string buf(line.substr(0, tb->cx));
+            buf.append(tb->yank[i], 0, MAX_LINELEN - buf.length() - 1);
 
-            buf[i] = '\0';
-            chain = chain->next;
-            if (chain || tb->yank_eol) {
+            const auto is_last_line = i + 1 == tb->yank.size();
+            if (!is_last_line || tb->yank_eol) {
                 if (!insert_return_code(tb)) {
                     break;
                 }
                 string_free(tb->lines_list[tb->cy]);
-                tb->lines_list[tb->cy] = string_make(buf);
+                tb->lines_list[tb->cy] = string_make(buf.data());
                 tb->cx = 0;
                 tb->cy++;
 
                 continue;
             }
 
-            tb->cx = strlen(buf);
-            while (*rest_ptr && i < MAX_LINELEN - 1) {
-                buf[i++] = *rest_ptr++;
-            }
+            const auto rest = line.substr(tb->cx);
+            tb->cx = buf.length();
+            buf.append(rest, 0, MAX_LINELEN - buf.length() - 1);
 
-            buf[i] = '\0';
             string_free(tb->lines_list[tb->cy]);
-            tb->lines_list[tb->cy] = string_make(buf);
+            tb->lines_list[tb->cy] = string_make(buf.data());
             break;
         }
 
@@ -357,7 +347,6 @@ ape_quittance do_editor_command(PlayerType *player_ptr, text_body_type *tb, int
 
         if (tb->old_com_id != com_id) {
             kill_yank_chain(tb);
-            tb->yank = nullptr;
         }
 
         if (tb->cx < len) {
index 7bafde6..7173a31 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*! APE means AutoPickEditor*/
 enum ape_quittance {
index cb95932..cd9a31f 100644 (file)
@@ -1,4 +1,4 @@
-#include <cstdlib>
+#include <cstdlib>
 
 #include "autopick/autopick-dirty-flags.h"
 #include "autopick/autopick-editor-util.h"
@@ -44,29 +44,29 @@ void toggle_keyword(text_body_type *tb, BIT_FLAGS flg)
         if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END) {
             int i;
             for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++) {
-                REM_FLG(i);
+                entry->remove(i);
             }
         } else if (FLG_UNAWARE <= flg && flg <= FLG_STAR_IDENTIFIED) {
             int i;
             for (i = FLG_UNAWARE; i <= FLG_STAR_IDENTIFIED; i++) {
-                REM_FLG(i);
+                entry->remove(i);
             }
         } else if (FLG_ARTIFACT <= flg && flg <= FLG_AVERAGE) {
             int i;
             for (i = FLG_ARTIFACT; i <= FLG_AVERAGE; i++) {
-                REM_FLG(i);
+                entry->remove(i);
             }
         } else if (FLG_RARE <= flg && flg <= FLG_COMMON) {
             int i;
             for (i = FLG_RARE; i <= FLG_COMMON; i++) {
-                REM_FLG(i);
+                entry->remove(i);
             }
         }
 
         if (add) {
-            ADD_FLG(flg);
+            entry->add(flg);
         } else {
-            REM_FLG(flg);
+            entry->remove(flg);
         }
 
         tb->lines_list[y] = autopick_line_from_entry(*entry);
@@ -190,11 +190,11 @@ void add_keyword(text_body_type *tb, BIT_FLAGS flg)
         if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END) {
             int i;
             for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++) {
-                REM_FLG(i);
+                entry->remove(i);
             }
         }
 
-        ADD_FLG(flg);
+        entry->add(flg);
         tb->lines_list[y] = autopick_line_from_entry(*entry);
         tb->dirty_flags |= DIRTY_ALL;
         tb->changed = true;
@@ -218,50 +218,16 @@ bool add_empty_line(text_body_type *tb)
     return true;
 }
 
-static chain_str_type *new_chain_str(concptr str)
-{
-    size_t len = strlen(str);
-    auto *chain = static_cast<chain_str_type *>(std::malloc(sizeof(chain_str_type) + len * sizeof(char)));
-    strcpy(chain->s, str);
-    chain->next = nullptr;
-    return chain;
-}
-
 void kill_yank_chain(text_body_type *tb)
 {
-    chain_str_type *chain = tb->yank;
-    tb->yank = nullptr;
+    tb->yank.clear();
     tb->yank_eol = true;
-
-    while (chain) {
-        chain_str_type *next = chain->next;
-
-        std::free(chain);
-
-        chain = next;
-    }
 }
 
 void add_str_to_yank(text_body_type *tb, concptr str)
 {
     tb->yank_eol = false;
-    if (tb->yank == nullptr) {
-        tb->yank = new_chain_str(str);
-        return;
-    }
-
-    chain_str_type *chain;
-    chain = tb->yank;
-
-    while (true) {
-        if (!chain->next) {
-            chain->next = new_chain_str(str);
-            return;
-        }
-
-        /* Go to next */
-        chain = chain->next;
-    }
+    tb->yank.emplace_back(str);
 }
 
 /*!
index 8b0f1f2..2e9d306 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3526fc0..6f1b38a 100644 (file)
@@ -1,4 +1,4 @@
-#include "autopick/autopick-entry.h"
+#include "autopick/autopick-entry.h"
 #include "autopick/autopick-flags-table.h"
 #include "autopick/autopick-key-flag-process.h"
 #include "autopick/autopick-keys-table.h"
 #include "system/item-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
+#include <optional>
+#include <sstream>
+#include <string>
 
 #ifdef JP
 static char kanji_colon[] = ":";
@@ -122,25 +124,25 @@ bool autopick_new_entry(autopick_type *entry, concptr str, bool allow_default)
     while (old_ptr != ptr) {
         old_ptr = ptr;
         if (MATCH_KEY(KEY_ALL)) {
-            ADD_FLG(FLG_ALL);
+            entry->add(FLG_ALL);
         }
         if (MATCH_KEY(KEY_COLLECTING)) {
-            ADD_FLG(FLG_COLLECTING);
+            entry->add(FLG_COLLECTING);
         }
         if (MATCH_KEY(KEY_UNAWARE)) {
-            ADD_FLG(FLG_UNAWARE);
+            entry->add(FLG_UNAWARE);
         }
         if (MATCH_KEY(KEY_UNIDENTIFIED)) {
-            ADD_FLG(FLG_UNIDENTIFIED);
+            entry->add(FLG_UNIDENTIFIED);
         }
         if (MATCH_KEY(KEY_IDENTIFIED)) {
-            ADD_FLG(FLG_IDENTIFIED);
+            entry->add(FLG_IDENTIFIED);
         }
         if (MATCH_KEY(KEY_STAR_IDENTIFIED)) {
-            ADD_FLG(FLG_STAR_IDENTIFIED);
+            entry->add(FLG_STAR_IDENTIFIED);
         }
         if (MATCH_KEY(KEY_BOOSTED)) {
-            ADD_FLG(FLG_BOOSTED);
+            entry->add(FLG_BOOSTED);
         }
 
         /*** Weapons whose dd*ds is more than nn ***/
@@ -160,7 +162,7 @@ bool autopick_new_entry(autopick_type *entry, concptr str, bool allow_default)
 
             if (k > 0 && k <= 2) {
                 (void)MATCH_KEY(KEY_DICE);
-                ADD_FLG(FLG_MORE_DICE);
+                entry->add(FLG_MORE_DICE);
             } else {
                 ptr = prev_ptr;
             }
@@ -189,110 +191,131 @@ bool autopick_new_entry(autopick_type *entry, concptr str, bool allow_default)
                     ptr++;
                 }
 #endif
-                ADD_FLG(FLG_MORE_BONUS);
+                entry->add(FLG_MORE_BONUS);
             } else {
                 ptr = prev_ptr;
             }
         }
 
         if (MATCH_KEY(KEY_WORTHLESS)) {
-            ADD_FLG(FLG_WORTHLESS);
+            entry->add(FLG_WORTHLESS);
         }
         if (MATCH_KEY(KEY_EGO)) {
-            ADD_FLG(FLG_EGO);
+            entry->add(FLG_EGO);
         }
         if (MATCH_KEY(KEY_GOOD)) {
-            ADD_FLG(FLG_GOOD);
+            entry->add(FLG_GOOD);
         }
         if (MATCH_KEY(KEY_NAMELESS)) {
-            ADD_FLG(FLG_NAMELESS);
+            entry->add(FLG_NAMELESS);
         }
         if (MATCH_KEY(KEY_AVERAGE)) {
-            ADD_FLG(FLG_AVERAGE);
+            entry->add(FLG_AVERAGE);
         }
         if (MATCH_KEY(KEY_RARE)) {
-            ADD_FLG(FLG_RARE);
+            entry->add(FLG_RARE);
         }
         if (MATCH_KEY(KEY_COMMON)) {
-            ADD_FLG(FLG_COMMON);
+            entry->add(FLG_COMMON);
         }
         if (MATCH_KEY(KEY_WANTED)) {
-            ADD_FLG(FLG_WANTED);
+            entry->add(FLG_WANTED);
         }
         if (MATCH_KEY(KEY_UNIQUE)) {
-            ADD_FLG(FLG_UNIQUE);
+            entry->add(FLG_UNIQUE);
         }
         if (MATCH_KEY(KEY_HUMAN)) {
-            ADD_FLG(FLG_HUMAN);
+            entry->add(FLG_HUMAN);
         }
         if (MATCH_KEY(KEY_UNREADABLE)) {
-            ADD_FLG(FLG_UNREADABLE);
+            entry->add(FLG_UNREADABLE);
         }
         if (MATCH_KEY(KEY_REALM1)) {
-            ADD_FLG(FLG_REALM1);
+            entry->add(FLG_REALM1);
         }
         if (MATCH_KEY(KEY_REALM2)) {
-            ADD_FLG(FLG_REALM2);
+            entry->add(FLG_REALM2);
         }
         if (MATCH_KEY(KEY_FIRST)) {
-            ADD_FLG(FLG_FIRST);
+            entry->add(FLG_FIRST);
         }
         if (MATCH_KEY(KEY_SECOND)) {
-            ADD_FLG(FLG_SECOND);
+            entry->add(FLG_SECOND);
         }
         if (MATCH_KEY(KEY_THIRD)) {
-            ADD_FLG(FLG_THIRD);
+            entry->add(FLG_THIRD);
         }
         if (MATCH_KEY(KEY_FOURTH)) {
-            ADD_FLG(FLG_FOURTH);
+            entry->add(FLG_FOURTH);
         }
     }
 
-    int prev_flg = -1;
+    std::optional<int> previous_flag = std::nullopt;
     if (MATCH_KEY2(KEY_ARTIFACT)) {
-        ADD_FLG_NOUN(FLG_ARTIFACT);
+        entry->add(FLG_ARTIFACT);
+        previous_flag = FLG_ARTIFACT;
     }
 
     if (MATCH_KEY2(KEY_ITEMS)) {
-        ADD_FLG_NOUN(FLG_ITEMS);
+        entry->add(FLG_ITEMS);
+        previous_flag = FLG_ITEMS;
     } else if (MATCH_KEY2(KEY_WEAPONS)) {
-        ADD_FLG_NOUN(FLG_WEAPONS);
+        entry->add(FLG_WEAPONS);
+        previous_flag = FLG_WEAPONS;
     } else if (MATCH_KEY2(KEY_FAVORITE_WEAPONS)) {
-        ADD_FLG_NOUN(FLG_FAVORITE_WEAPONS);
+        entry->add(FLG_FAVORITE_WEAPONS);
+        previous_flag = FLG_FAVORITE_WEAPONS;
     } else if (MATCH_KEY2(KEY_ARMORS)) {
-        ADD_FLG_NOUN(FLG_ARMORS);
+        entry->add(FLG_ARMORS);
+        previous_flag = FLG_ARMORS;
     } else if (MATCH_KEY2(KEY_MISSILES)) {
-        ADD_FLG_NOUN(FLG_MISSILES);
+        entry->add(FLG_MISSILES);
+        previous_flag = FLG_MISSILES;
     } else if (MATCH_KEY2(KEY_DEVICES)) {
-        ADD_FLG_NOUN(FLG_DEVICES);
+        entry->add(FLG_DEVICES);
+        previous_flag = FLG_DEVICES;
     } else if (MATCH_KEY2(KEY_LIGHTS)) {
-        ADD_FLG_NOUN(FLG_LIGHTS);
+        entry->add(FLG_LIGHTS);
+        previous_flag = FLG_LIGHTS;
     } else if (MATCH_KEY2(KEY_JUNKS)) {
-        ADD_FLG_NOUN(FLG_JUNKS);
+        entry->add(FLG_JUNKS);
+        previous_flag = FLG_JUNKS;
     } else if (MATCH_KEY2(KEY_CORPSES)) {
-        ADD_FLG_NOUN(FLG_CORPSES);
+        entry->add(FLG_CORPSES);
+        previous_flag = FLG_CORPSES;
     } else if (MATCH_KEY2(KEY_SPELLBOOKS)) {
-        ADD_FLG_NOUN(FLG_SPELLBOOKS);
+        entry->add(FLG_SPELLBOOKS);
+        previous_flag = FLG_SPELLBOOKS;
     } else if (MATCH_KEY2(KEY_HAFTED)) {
-        ADD_FLG_NOUN(FLG_HAFTED);
+        entry->add(FLG_HAFTED);
+        previous_flag = FLG_HAFTED;
     } else if (MATCH_KEY2(KEY_SHIELDS)) {
-        ADD_FLG_NOUN(FLG_SHIELDS);
+        entry->add(FLG_SHIELDS);
+        previous_flag = FLG_SHIELDS;
     } else if (MATCH_KEY2(KEY_BOWS)) {
-        ADD_FLG_NOUN(FLG_BOWS);
+        entry->add(FLG_BOWS);
+        previous_flag = FLG_BOWS;
     } else if (MATCH_KEY2(KEY_RINGS)) {
-        ADD_FLG_NOUN(FLG_RINGS);
+        entry->add(FLG_RINGS);
+        previous_flag = FLG_RINGS;
     } else if (MATCH_KEY2(KEY_AMULETS)) {
-        ADD_FLG_NOUN(FLG_AMULETS);
+        entry->add(FLG_AMULETS);
+        previous_flag = FLG_AMULETS;
     } else if (MATCH_KEY2(KEY_SUITS)) {
-        ADD_FLG_NOUN(FLG_SUITS);
+        entry->add(FLG_SUITS);
+        previous_flag = FLG_SUITS;
     } else if (MATCH_KEY2(KEY_CLOAKS)) {
-        ADD_FLG_NOUN(FLG_CLOAKS);
+        entry->add(FLG_CLOAKS);
+        previous_flag = FLG_CLOAKS;
     } else if (MATCH_KEY2(KEY_HELMS)) {
-        ADD_FLG_NOUN(FLG_HELMS);
+        entry->add(FLG_HELMS);
+        previous_flag = FLG_HELMS;
     } else if (MATCH_KEY2(KEY_GLOVES)) {
-        ADD_FLG_NOUN(FLG_GLOVES);
+        entry->add(FLG_GLOVES);
+        previous_flag = FLG_GLOVES;
     } else if (MATCH_KEY2(KEY_BOOTS)) {
-        ADD_FLG_NOUN(FLG_BOOTS);
+        entry->add(FLG_BOOTS);
+        previous_flag = FLG_BOOTS;
     }
 
     if (*ptr == ':') {
@@ -304,12 +327,13 @@ bool autopick_new_entry(autopick_type *entry, concptr str, bool allow_default)
     }
 #endif
     else if (*ptr == '\0') {
-        if (prev_flg == -1) {
-            ADD_FLG_NOUN(FLG_ITEMS);
+        if (!previous_flag) {
+            entry->add(FLG_ITEMS);
+            previous_flag = FLG_ITEMS;
         }
     } else {
-        if (prev_flg != -1) {
-            entry->flags[prev_flg / 32] &= ~(1UL << (prev_flg % 32));
+        if (previous_flag) {
+            entry->remove(*previous_flag);
             ptr = prev_ptr;
         }
     }
@@ -338,34 +362,34 @@ void autopick_entry_from_object(PlayerType *player_ptr, autopick_type *entry, It
     // We can always use the ^ mark in English.
     bool is_hat_added = _(false, true);
     if (!o_ptr->is_aware()) {
-        ADD_FLG(FLG_UNAWARE);
+        entry->add(FLG_UNAWARE);
         is_hat_added = true;
     } else if (!o_ptr->is_known()) {
         if (!(o_ptr->ident & IDENT_SENSE)) {
-            ADD_FLG(FLG_UNIDENTIFIED);
+            entry->add(FLG_UNIDENTIFIED);
             is_hat_added = true;
         } else {
             switch (o_ptr->feeling) {
             case FEEL_AVERAGE:
             case FEEL_GOOD:
-                ADD_FLG(FLG_NAMELESS);
+                entry->add(FLG_NAMELESS);
                 is_hat_added = true;
                 break;
 
             case FEEL_BROKEN:
             case FEEL_CURSED:
-                ADD_FLG(FLG_NAMELESS);
-                ADD_FLG(FLG_WORTHLESS);
+                entry->add(FLG_NAMELESS);
+                entry->add(FLG_WORTHLESS);
                 is_hat_added = true;
                 break;
 
             case FEEL_TERRIBLE:
             case FEEL_WORTHLESS:
-                ADD_FLG(FLG_WORTHLESS);
+                entry->add(FLG_WORTHLESS);
                 break;
 
             case FEEL_EXCELLENT:
-                ADD_FLG(FLG_EGO);
+                entry->add(FLG_EGO);
                 break;
 
             case FEEL_UNCURSED:
@@ -389,16 +413,16 @@ void autopick_entry_from_object(PlayerType *player_ptr, autopick_type *entry, It
 #endif
                 name = false;
                 if (!o_ptr->is_rare()) {
-                    ADD_FLG(FLG_COMMON);
+                    entry->add(FLG_COMMON);
                 }
             }
 
-            ADD_FLG(FLG_EGO);
+            entry->add(FLG_EGO);
         } else if (o_ptr->is_fixed_or_random_artifact()) {
-            ADD_FLG(FLG_ARTIFACT);
+            entry->add(FLG_ARTIFACT);
         } else {
             if (o_ptr->is_equipment()) {
-                ADD_FLG(FLG_NAMELESS);
+                entry->add(FLG_NAMELESS);
             }
 
             is_hat_added = true;
@@ -408,28 +432,28 @@ void autopick_entry_from_object(PlayerType *player_ptr, autopick_type *entry, It
     if (o_ptr->is_melee_weapon()) {
         const auto &baseitem = o_ptr->get_baseitem();
         if ((o_ptr->dd != baseitem.dd) || (o_ptr->ds != baseitem.ds)) {
-            ADD_FLG(FLG_BOOSTED);
+            entry->add(FLG_BOOSTED);
         }
     }
 
     if (object_is_bounty(player_ptr, o_ptr)) {
-        REM_FLG(FLG_WORTHLESS);
-        ADD_FLG(FLG_WANTED);
+        entry->remove(FLG_WORTHLESS);
+        entry->add(FLG_WANTED);
     }
 
     const auto r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
     const auto &bi_key = o_ptr->bi_key;
     const auto tval = bi_key.tval();
     if ((tval == ItemKindType::CORPSE || tval == ItemKindType::STATUE) && monraces_info[r_idx].kind_flags.has(MonsterKindType::UNIQUE)) {
-        ADD_FLG(FLG_UNIQUE);
+        entry->add(FLG_UNIQUE);
     }
 
     if (tval == ItemKindType::CORPSE && angband_strchr("pht", monraces_info[r_idx].d_char)) {
-        ADD_FLG(FLG_HUMAN);
+        entry->add(FLG_HUMAN);
     }
 
     if (o_ptr->is_spell_book() && !check_book_realm(player_ptr, bi_key)) {
-        ADD_FLG(FLG_UNREADABLE);
+        entry->add(FLG_UNREADABLE);
         if (tval != ItemKindType::ARCANE_BOOK) {
             name = false;
         }
@@ -439,61 +463,61 @@ void autopick_entry_from_object(PlayerType *player_ptr, autopick_type *entry, It
     auto realm_except_class = pc.equals(PlayerClassType::SORCERER) || pc.equals(PlayerClassType::RED_MAGE);
 
     if ((get_realm1_book(player_ptr) == tval) && !realm_except_class) {
-        ADD_FLG(FLG_REALM1);
+        entry->add(FLG_REALM1);
         name = false;
     }
 
     if ((get_realm2_book(player_ptr) == tval) && !realm_except_class) {
-        ADD_FLG(FLG_REALM2);
+        entry->add(FLG_REALM2);
         name = false;
     }
 
     const auto sval = bi_key.sval();
     if (o_ptr->is_spell_book() && (sval == 0)) {
-        ADD_FLG(FLG_FIRST);
+        entry->add(FLG_FIRST);
     }
     if (o_ptr->is_spell_book() && (sval == 1)) {
-        ADD_FLG(FLG_SECOND);
+        entry->add(FLG_SECOND);
     }
     if (o_ptr->is_spell_book() && (sval == 2)) {
-        ADD_FLG(FLG_THIRD);
+        entry->add(FLG_THIRD);
     }
     if (o_ptr->is_spell_book() && (sval == 3)) {
-        ADD_FLG(FLG_FOURTH);
+        entry->add(FLG_FOURTH);
     }
 
     if (o_ptr->is_ammo()) {
-        ADD_FLG(FLG_MISSILES);
+        entry->add(FLG_MISSILES);
     } else if (tval == ItemKindType::SCROLL || o_ptr->is_wand_staff() || o_ptr->is_wand_rod()) {
-        ADD_FLG(FLG_DEVICES);
+        entry->add(FLG_DEVICES);
     } else if (tval == ItemKindType::LITE) {
-        ADD_FLG(FLG_LIGHTS);
+        entry->add(FLG_LIGHTS);
     } else if (o_ptr->is_junk()) {
-        ADD_FLG(FLG_JUNKS);
+        entry->add(FLG_JUNKS);
     } else if (tval == ItemKindType::CORPSE) {
-        ADD_FLG(FLG_CORPSES);
+        entry->add(FLG_CORPSES);
     } else if (o_ptr->is_spell_book()) {
-        ADD_FLG(FLG_SPELLBOOKS);
+        entry->add(FLG_SPELLBOOKS);
     } else if (o_ptr->is_melee_weapon()) {
-        ADD_FLG(FLG_WEAPONS);
+        entry->add(FLG_WEAPONS);
     } else if (tval == ItemKindType::SHIELD) {
-        ADD_FLG(FLG_SHIELDS);
+        entry->add(FLG_SHIELDS);
     } else if (tval == ItemKindType::BOW) {
-        ADD_FLG(FLG_BOWS);
+        entry->add(FLG_BOWS);
     } else if (tval == ItemKindType::RING) {
-        ADD_FLG(FLG_RINGS);
+        entry->add(FLG_RINGS);
     } else if (tval == ItemKindType::AMULET) {
-        ADD_FLG(FLG_AMULETS);
+        entry->add(FLG_AMULETS);
     } else if (o_ptr->is_armour()) {
-        ADD_FLG(FLG_SUITS);
+        entry->add(FLG_SUITS);
     } else if (tval == ItemKindType::CLOAK) {
-        ADD_FLG(FLG_CLOAKS);
+        entry->add(FLG_CLOAKS);
     } else if (tval == ItemKindType::HELM) {
-        ADD_FLG(FLG_HELMS);
+        entry->add(FLG_HELMS);
     } else if (tval == ItemKindType::GLOVES) {
-        ADD_FLG(FLG_GLOVES);
+        entry->add(FLG_GLOVES);
     } else if (tval == ItemKindType::BOOTS) {
-        ADD_FLG(FLG_BOOTS);
+        entry->add(FLG_BOOTS);
     }
 
     if (!name) {
@@ -511,199 +535,206 @@ void autopick_entry_from_object(PlayerType *player_ptr, autopick_type *entry, It
     str_tolower(entry->name.data());
 }
 
+std::string shape_autopick_key(const std::string &key)
+{
+#ifdef JP
+    return key;
+#else
+    std::stringstream ss;
+    ss << key << ' ';
+    return ss.str();
+#endif
+}
+
 /*!
  * @brief Reconstruct preference line from entry
  */
 concptr autopick_line_from_entry(const autopick_type &entry)
 {
-    char buf[MAX_LINELEN]{};
+    std::stringstream ss;
     if (!(entry.action & DO_DISPLAY)) {
-        strcat(buf, "(");
+        ss << '(';
     }
+
     if (entry.action & DO_QUERY_AUTOPICK) {
-        strcat(buf, ";");
+        ss << ';';
     }
+
     if (entry.action & DO_AUTODESTROY) {
-        strcat(buf, "!");
+        ss << '!';
     }
+
     if (entry.action & DONT_AUTOPICK) {
-        strcat(buf, "~");
+        ss << '~';
     }
 
-    char *ptr;
-    ptr = buf;
     if (entry.has(FLG_ALL)) {
-        ADD_KEY(KEY_ALL);
+        ss << shape_autopick_key(KEY_ALL);
     }
     if (entry.has(FLG_COLLECTING)) {
-        ADD_KEY(KEY_COLLECTING);
+        ss << shape_autopick_key(KEY_COLLECTING);
     }
     if (entry.has(FLG_UNAWARE)) {
-        ADD_KEY(KEY_UNAWARE);
+        ss << shape_autopick_key(KEY_UNAWARE);
     }
     if (entry.has(FLG_UNIDENTIFIED)) {
-        ADD_KEY(KEY_UNIDENTIFIED);
+        ss << shape_autopick_key(KEY_UNIDENTIFIED);
     }
     if (entry.has(FLG_IDENTIFIED)) {
-        ADD_KEY(KEY_IDENTIFIED);
+        ss << shape_autopick_key(KEY_IDENTIFIED);
     }
     if (entry.has(FLG_STAR_IDENTIFIED)) {
-        ADD_KEY(KEY_STAR_IDENTIFIED);
+        ss << shape_autopick_key(KEY_STAR_IDENTIFIED);
     }
     if (entry.has(FLG_BOOSTED)) {
-        ADD_KEY(KEY_BOOSTED);
+        ss << shape_autopick_key(KEY_BOOSTED);
     }
 
     if (entry.has(FLG_MORE_DICE)) {
-        ADD_KEY(KEY_MORE_THAN);
-        strcat(ptr, format("%d", entry.dice).data());
-        ADD_KEY(KEY_DICE);
+        ss << shape_autopick_key(KEY_MORE_THAN);
+        ss << entry.dice;
+        ss << shape_autopick_key(KEY_DICE);
     }
 
     if (entry.has(FLG_MORE_BONUS)) {
-        ADD_KEY(KEY_MORE_BONUS);
-        strcat(ptr, format("%d", entry.bonus).data());
-        ADD_KEY(KEY_MORE_BONUS2);
+        ss << shape_autopick_key(KEY_MORE_BONUS);
+        ss << entry.bonus;
+        ss << shape_autopick_key(KEY_MORE_BONUS2);
     }
 
     if (entry.has(FLG_UNREADABLE)) {
-        ADD_KEY(KEY_UNREADABLE);
+        ss << shape_autopick_key(KEY_UNREADABLE);
     }
+
     if (entry.has(FLG_REALM1)) {
-        ADD_KEY(KEY_REALM1);
+        ss << shape_autopick_key(KEY_REALM1);
     }
+
     if (entry.has(FLG_REALM2)) {
-        ADD_KEY(KEY_REALM2);
+        ss << shape_autopick_key(KEY_REALM2);
     }
+
     if (entry.has(FLG_FIRST)) {
-        ADD_KEY(KEY_FIRST);
+        ss << shape_autopick_key(KEY_FIRST);
     }
+
     if (entry.has(FLG_SECOND)) {
-        ADD_KEY(KEY_SECOND);
+        ss << shape_autopick_key(KEY_SECOND);
     }
+
     if (entry.has(FLG_THIRD)) {
-        ADD_KEY(KEY_THIRD);
+        ss << shape_autopick_key(KEY_THIRD);
     }
+
     if (entry.has(FLG_FOURTH)) {
-        ADD_KEY(KEY_FOURTH);
+        ss << shape_autopick_key(KEY_FOURTH);
     }
+
     if (entry.has(FLG_WANTED)) {
-        ADD_KEY(KEY_WANTED);
+        ss << shape_autopick_key(KEY_WANTED);
     }
+
     if (entry.has(FLG_UNIQUE)) {
-        ADD_KEY(KEY_UNIQUE);
+        ss << shape_autopick_key(KEY_UNIQUE);
     }
+
     if (entry.has(FLG_HUMAN)) {
-        ADD_KEY(KEY_HUMAN);
+        ss << shape_autopick_key(KEY_HUMAN);
     }
+
     if (entry.has(FLG_WORTHLESS)) {
-        ADD_KEY(KEY_WORTHLESS);
+        ss << shape_autopick_key(KEY_WORTHLESS);
     }
+
     if (entry.has(FLG_GOOD)) {
-        ADD_KEY(KEY_GOOD);
+        ss << shape_autopick_key(KEY_GOOD);
     }
+
     if (entry.has(FLG_NAMELESS)) {
-        ADD_KEY(KEY_NAMELESS);
+        ss << shape_autopick_key(KEY_NAMELESS);
     }
+
     if (entry.has(FLG_AVERAGE)) {
-        ADD_KEY(KEY_AVERAGE);
+        ss << shape_autopick_key(KEY_AVERAGE);
     }
+
     if (entry.has(FLG_RARE)) {
-        ADD_KEY(KEY_RARE);
+        ss << shape_autopick_key(KEY_RARE);
     }
+
     if (entry.has(FLG_COMMON)) {
-        ADD_KEY(KEY_COMMON);
+        ss << shape_autopick_key(KEY_COMMON);
     }
+
     if (entry.has(FLG_EGO)) {
-        ADD_KEY(KEY_EGO);
+        ss << shape_autopick_key(KEY_EGO);
     }
 
     if (entry.has(FLG_ARTIFACT)) {
-        ADD_KEY(KEY_ARTIFACT);
+        ss << shape_autopick_key(KEY_ARTIFACT);
     }
 
-    bool sepa_flag = true;
+    auto should_separate = true;
     if (entry.has(FLG_ITEMS)) {
-        ADD_KEY2(KEY_ITEMS);
+        ss << KEY_ITEMS;
     } else if (entry.has(FLG_WEAPONS)) {
-        ADD_KEY2(KEY_WEAPONS);
+        ss << KEY_WEAPONS;
     } else if (entry.has(FLG_FAVORITE_WEAPONS)) {
-        ADD_KEY2(KEY_FAVORITE_WEAPONS);
+        ss << KEY_FAVORITE_WEAPONS;
     } else if (entry.has(FLG_ARMORS)) {
-        ADD_KEY2(KEY_ARMORS);
+        ss << KEY_ARMORS;
     } else if (entry.has(FLG_MISSILES)) {
-        ADD_KEY2(KEY_MISSILES);
+        ss << KEY_MISSILES;
     } else if (entry.has(FLG_DEVICES)) {
-        ADD_KEY2(KEY_DEVICES);
+        ss << KEY_DEVICES;
     } else if (entry.has(FLG_LIGHTS)) {
-        ADD_KEY2(KEY_LIGHTS);
+        ss << KEY_LIGHTS;
     } else if (entry.has(FLG_JUNKS)) {
-        ADD_KEY2(KEY_JUNKS);
+        ss << KEY_JUNKS;
     } else if (entry.has(FLG_CORPSES)) {
-        ADD_KEY2(KEY_CORPSES);
+        ss << KEY_CORPSES;
     } else if (entry.has(FLG_SPELLBOOKS)) {
-        ADD_KEY2(KEY_SPELLBOOKS);
+        ss << KEY_SPELLBOOKS;
     } else if (entry.has(FLG_HAFTED)) {
-        ADD_KEY2(KEY_HAFTED);
+        ss << KEY_HAFTED;
     } else if (entry.has(FLG_SHIELDS)) {
-        ADD_KEY2(KEY_SHIELDS);
+        ss << KEY_SHIELDS;
     } else if (entry.has(FLG_BOWS)) {
-        ADD_KEY2(KEY_BOWS);
+        ss << KEY_BOWS;
     } else if (entry.has(FLG_RINGS)) {
-        ADD_KEY2(KEY_RINGS);
+        ss << KEY_RINGS;
     } else if (entry.has(FLG_AMULETS)) {
-        ADD_KEY2(KEY_AMULETS);
+        ss << KEY_AMULETS;
     } else if (entry.has(FLG_SUITS)) {
-        ADD_KEY2(KEY_SUITS);
+        ss << KEY_SUITS;
     } else if (entry.has(FLG_CLOAKS)) {
-        ADD_KEY2(KEY_CLOAKS);
+        ss << KEY_CLOAKS;
     } else if (entry.has(FLG_HELMS)) {
-        ADD_KEY2(KEY_HELMS);
+        ss << KEY_HELMS;
     } else if (entry.has(FLG_GLOVES)) {
-        ADD_KEY2(KEY_GLOVES);
+        ss << KEY_GLOVES;
     } else if (entry.has(FLG_BOOTS)) {
-        ADD_KEY2(KEY_BOOTS);
+        ss << KEY_BOOTS;
     } else if (!entry.has(FLG_ARTIFACT)) {
-        sepa_flag = false;
+        should_separate = false;
     }
 
     if (!entry.name.empty()) {
-        if (sepa_flag) {
-            strcat(buf, ":");
+        if (should_separate) {
+            ss << ":";
         }
 
-        int i = strlen(buf);
-        int j = 0;
-        while (entry.name[j] && i < MAX_LINELEN - 2 - 1) {
-#ifdef JP
-            if (iskanji(entry.name[j])) {
-                buf[i++] = entry.name[j++];
-            }
-#endif
-            buf[i++] = entry.name[j++];
-        }
-        buf[i] = '\0';
+        ss << entry.name;
     }
 
     if (entry.insc.empty()) {
-        return string_make(buf);
+        auto str = ss.str();
+        return string_make(str.data());
     }
 
-    int i, j = 0;
-    strcat(buf, "#");
-    i = strlen(buf);
-
-    while (entry.insc[j] && i < MAX_LINELEN - 2) {
-#ifdef JP
-        if (iskanji(entry.insc[j])) {
-            buf[i++] = entry.insc[j++];
-        }
-#endif
-        buf[i++] = entry.insc[j++];
-    }
-
-    buf[i] = '\0';
-    return string_make(buf);
+    ss << '#' << entry.insc;
+    auto str = ss.str();
+    return string_make(str.data());
 }
 
 /*!
index e794885..1570257 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 663f03d..047c21b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動拾いの検索
  * @date 2020/04/26
  * @author Hourier
@@ -56,8 +56,8 @@ int find_autopick_list(PlayerType *player_ptr, ItemEntity *o_ptr)
  */
 bool get_object_for_search(PlayerType *player_ptr, ItemEntity **o_handle, concptr *search_strp)
 {
-    concptr q = _("どのアイテムを検索しますか? ", "Enter which item? ");
-    concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
+    constexpr auto q = _("どのアイテムを検索しますか? ", "Enter which item? ");
+    constexpr auto s = _("アイテムを持っていない。", "You have nothing to enter.");
     ItemEntity *o_ptr;
     o_ptr = choose_object(player_ptr, nullptr, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP);
     if (!o_ptr) {
@@ -115,7 +115,7 @@ byte get_string_for_search(PlayerType *player_ptr, ItemEntity **o_handle, concpt
     int pos = 0;
     while (true) {
         bool back = false;
-        term_erase(col, 0, 255);
+        term_erase(col, 0);
         term_putstr(col, 0, -1, color, buf);
         term_gotoxy(col + pos, 0);
 
index dd6e0e9..29ffa57 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e7ad81c..fe30846 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Macros for Keywords
index 189dc5a..a079f0d 100644 (file)
@@ -1,4 +1,4 @@
-#include "autopick/autopick-initializer.h"
+#include "autopick/autopick-initializer.h"
 #include "autopick/autopick-entry.h"
 #include "autopick/autopick-util.h"
 #include "system/angband.h"
index 572f799..f145131 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 void init_autopick(void);
index c815ada..bbecb21 100644 (file)
@@ -1,4 +1,4 @@
-#include "autopick/autopick-inserter-killer.h"
+#include "autopick/autopick-inserter-killer.h"
 #include "autopick/autopick-dirty-flags.h"
 #include "autopick/autopick-util.h"
 #include "cmd-io/macro-util.h"
@@ -15,7 +15,7 @@
  */
 void check_expression_line(text_body_type *tb, int y)
 {
-    concptr s = tb->lines_list[y];
+    auto s = tb->lines_list[y];
 
     if ((s[0] == '?' && s[1] == ':') || (tb->states[y] & LSTAT_BYPASS)) {
         tb->dirty_flags |= DIRTY_EXPRESSION;
@@ -40,7 +40,7 @@ bool can_insert_line(text_body_type *tb, int add_num)
  */
 bool insert_return_code(text_body_type *tb)
 {
-    char buf[MAX_LINELEN];
+    char buf[MAX_LINELEN]{};
     int i, j, num_lines;
 
     num_lines = count_line(tb);
@@ -85,7 +85,7 @@ bool insert_macro_line(text_body_type *tb)
     flush();
     inkey_base = true;
     i = inkey();
-    char buf[1024];
+    char buf[1024]{};
     while (i) {
         buf[n++] = (char)i;
         inkey_base = true;
@@ -111,7 +111,7 @@ bool insert_macro_line(text_body_type *tb)
     if (i == -1) {
         tmp[0] = '\0';
     } else {
-        ascii_to_text(tmp, macro__act[i], sizeof(tmp));
+        ascii_to_text(tmp, macro_actions[i], sizeof(tmp));
     }
 
     insert_return_code(tb);
@@ -137,7 +137,7 @@ bool insert_keymap_line(text_body_type *tb)
     }
 
     flush();
-    char buf[2];
+    char buf[2]{};
     buf[0] = inkey();
     buf[1] = '\0';
 
@@ -171,7 +171,7 @@ bool insert_keymap_line(text_body_type *tb)
 void insert_single_letter(text_body_type *tb, int key)
 {
     int i, j, len;
-    char buf[MAX_LINELEN];
+    char buf[MAX_LINELEN]{};
 
     for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++) {
         buf[j++] = tb->lines_list[tb->cy][i];
@@ -221,7 +221,7 @@ void insert_single_letter(text_body_type *tb, int key)
  */
 void kill_line_segment(text_body_type *tb, int y, int x0, int x1, bool whole)
 {
-    concptr s = tb->lines_list[y];
+    auto s = tb->lines_list[y];
     if (whole && x0 == 0 && s[x1] == '\0' && tb->lines_list[y + 1]) {
         string_free(tb->lines_list[y]);
 
@@ -240,7 +240,7 @@ void kill_line_segment(text_body_type *tb, int y, int x0, int x1, bool whole)
         return;
     }
 
-    char buf[MAX_LINELEN];
+    char buf[MAX_LINELEN]{};
     char *d = buf;
     for (int x = 0; x < x0; x++) {
         *(d++) = s[x];
index 3742526..63c3178 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct text_body_type;
 void check_expression_line(text_body_type *tb, int y);
index e74ee80..0680aa2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #define MATCH_KEY(KEY) (!strncmp(ptr, KEY, strlen(KEY))                             \
                             ? (ptr += strlen(KEY), (' ' == *ptr) ? ptr++ : 0, true) \
@@ -6,14 +6,3 @@
 #define MATCH_KEY2(KEY) (!strncmp(ptr, KEY, strlen(KEY))                                             \
                              ? (prev_ptr = ptr, ptr += strlen(KEY), (' ' == *ptr) ? ptr++ : 0, true) \
                              : false)
-
-#ifdef JP
-#define ADD_KEY(KEY) strcat(ptr, KEY)
-#else
-#define ADD_KEY(KEY) (strcat(ptr, KEY), strcat(ptr, " "))
-#endif
-#define ADD_KEY2(KEY) strcat(ptr, KEY)
-
-#define ADD_FLG(FLG) (entry->flags[FLG / 32] |= (1UL << (FLG % 32)))
-#define REM_FLG(FLG) (entry->flags[FLG / 32] &= ~(1UL << (FLG % 32)))
-#define ADD_FLG_NOUN(FLG) (ADD_FLG(FLG), prev_flg = FLG)
index c37ce20..a8c1b4f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/h-basic.h"
 
index 86e9f5a..73a7521 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 床のアイテムが自動拾いに一致するかどうかを調べる関数だけを格納したファイル
  * @date 2020/04/25
  * @author Hourier
@@ -113,7 +113,7 @@ static bool check_item_features(PlayerType *player_ptr, const autopick_type &ent
     }
 
     if (entry.has(FLG_HELMS)) {
-        return (tval != ItemKindType::CROWN) && (tval != ItemKindType::HELM);
+        return (tval == ItemKindType::CROWN) || (tval == ItemKindType::HELM);
     }
 
     if (entry.has(FLG_GLOVES)) {
@@ -297,7 +297,7 @@ bool is_autopick_match(PlayerType *player_ptr, ItemEntity *o_ptr, const autopick
     // @details このタイミングでは、svalは絶対にnulloptにならない、はず.
     const auto &bi_key = o_ptr->bi_key;
     const auto tval = bi_key.tval();
-    const auto sval = bi_key.sval().value();
+    const auto sval = *bi_key.sval();
     const auto r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
     if (entry.has(FLG_UNIQUE) && ((tval != ItemKindType::CORPSE && tval != ItemKindType::STATUE) || monraces_info[r_idx].kind_flags.has_not(MonsterKindType::UNIQUE))) {
         return false;
@@ -347,7 +347,7 @@ bool is_autopick_match(PlayerType *player_ptr, ItemEntity *o_ptr, const autopick
             return false;
         }
     } else {
-        if (angband_strstr(item_name.data(), entry.name.data()) == nullptr) {
+        if (!str_find(std::string(item_name), entry.name)) {
             return false;
         }
     }
index 8bdae3b..be0660c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 58091b5..32a6272 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動拾いのユーティリティ
  * @date 2020/04/25
  * @author Hourier
index 0c0ca7f..cd462da 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index c5d50e1..5e33c3a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #define DO_AUTOPICK 0x01
 #define DO_AUTODESTROY 0x02
index 5ba8eb1..2bfe0bf 100644 (file)
@@ -1,4 +1,4 @@
-#include "autopick/autopick-pref-processor.h"
+#include "autopick/autopick-pref-processor.h"
 #include "autopick/autopick-entry.h"
 #include "autopick/autopick-util.h"
 #include "system/angband.h"
index 14c4482..657e47e 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 void process_autopick_file_command(char *buf);
index e161c0a..3f1b2dc 100644 (file)
@@ -1,14 +1,14 @@
-#include "autopick/autopick-reader-writer.h"
+#include "autopick/autopick-reader-writer.h"
 #include "autopick/autopick-initializer.h"
 #include "autopick/autopick-pref-processor.h"
 #include "autopick/autopick-util.h"
 #include "io/files-util.h"
 #include "io/read-pref-file.h"
+#include "system/angband-exceptions.h"
 #include "system/player-type-definition.h"
 #include "util/angband-files.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
-#include <stdexcept>
 #include <string>
 #include <string_view>
 #include <vector>
  */
 void autopick_load_pref(PlayerType *player_ptr, bool disp_mes)
 {
-    GAME_TEXT buf[80];
     init_autopick();
-    angband_strcpy(buf, pickpref_filename(player_ptr, PT_WITH_PNAME).data(), sizeof(buf));
-    errr err = process_autopick_file(player_ptr, buf);
-    if (err == 0 && disp_mes) {
-        msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
-    }
 
-    if (err < 0) {
-        angband_strcpy(buf, pickpref_filename(player_ptr, PT_DEFAULT).data(), sizeof(buf));
-        err = process_autopick_file(player_ptr, buf);
-        if (err == 0 && disp_mes) {
-            msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
+    const auto path = search_pickpref_path(player_ptr);
+    if (!path.empty()) {
+        const auto pickpref_filename = path.filename().string();
+        if (process_autopick_file(player_ptr, pickpref_filename) == 0) {
+            if (disp_mes) {
+                msg_format(_("%sを読み込みました。", "Loaded '%s'."), pickpref_filename.data());
+            }
+            return;
         }
     }
 
-    if (err && disp_mes) {
+    if (disp_mes) {
         msg_print(_("自動拾い設定ファイルの読み込みに失敗しました。", "Failed to reload autopick preference."));
     }
 }
 
 /*!
+ * @brief 自動拾い設定ファイルのパスを返す
+ *
+ * ユーザディレクトリを "picktype-プレイヤー名.prf"、"picktype.prf" の順にファイルが存在するかどうかを確認し、
+ * 存在した場合はそのパスを返す。どちらも存在しない場合は空のパスを返す。
+ *
+ * @return 見つかった自動拾い設定ファイルのパス。見つからなかった場合は空のパス。
+ */
+std::filesystem::path search_pickpref_path(PlayerType *player_ptr)
+{
+    for (const auto filename_mode : { PT_WITH_PNAME, PT_DEFAULT }) {
+        const auto filename = pickpref_filename(player_ptr, filename_mode);
+        const auto path = path_build(ANGBAND_DIR_USER, filename);
+        if (std::filesystem::exists(path)) {
+            return path;
+        }
+    }
+
+    return {};
+}
+
+/*!
  * @brief Get file name for autopick preference
  */
 std::string pickpref_filename(PlayerType *player_ptr, int filename_mode)
@@ -53,8 +71,10 @@ std::string pickpref_filename(PlayerType *player_ptr, int filename_mode)
     case PT_WITH_PNAME:
         return format("%s-%s.prf", namebase, player_ptr->base_name);
 
-    default:
-        throw std::invalid_argument(format("The value of argument 'filename_mode' is invalid: %d", filename_mode));
+    default: {
+        const auto msg = format("The value of argument 'filename_mode' is invalid: %d", filename_mode);
+        THROW_EXCEPTION(std::invalid_argument, msg);
+    }
     }
 }
 
@@ -63,15 +83,15 @@ std::string pickpref_filename(PlayerType *player_ptr, int filename_mode)
  */
 static std::vector<concptr> read_text_lines(std::string_view filename)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
-    auto *fff = angband_fopen(buf, FileOpenMode::READ);
+    const auto &path = path_build(ANGBAND_DIR_USER, filename);
+    auto *fff = angband_fopen(path, FileOpenMode::READ);
     if (!fff) {
         return {};
     }
 
     auto lines = 0;
     std::vector<concptr> lines_list(MAX_LINES);
+    char buf[1024]{};
     while (angband_fgets(fff, buf, sizeof(buf)) == 0) {
         lines_list[lines++] = string_make(buf);
         if (is_greater_autopick_max_line(lines)) {
@@ -102,9 +122,8 @@ static void prepare_default_pickpref(PlayerType *player_ptr)
     }
 
     msg_print(nullptr);
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
-    auto *user_fp = angband_fopen(buf, FileOpenMode::WRITE);
+    const auto &path_user = path_build(ANGBAND_DIR_USER, filename);
+    auto *user_fp = angband_fopen(path_user, FileOpenMode::WRITE);
     if (!user_fp) {
         return;
     }
@@ -115,13 +134,14 @@ static void prepare_default_pickpref(PlayerType *player_ptr)
     }
 
     fprintf(user_fp, "#***\n\n\n");
-    path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, filename);
-    auto *pref_fp = angband_fopen(buf, FileOpenMode::READ);
+    const auto &path_pref = path_build(ANGBAND_DIR_PREF, filename);
+    auto *pref_fp = angband_fopen(path_pref, FileOpenMode::READ);
     if (!pref_fp) {
         angband_fclose(user_fp);
         return;
     }
 
+    char buf[1024]{};
     while (!angband_fgets(pref_fp, buf, sizeof(buf))) {
         fprintf(user_fp, "%s\n", buf);
     }
@@ -165,9 +185,8 @@ std::vector<concptr> read_pickpref_text_lines(PlayerType *player_ptr, int *filen
  */
 bool write_text_lines(std::string_view filename, const std::vector<concptr> &lines)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
-    auto *fff = angband_fopen(buf, FileOpenMode::WRITE);
+    const auto &path = path_build(ANGBAND_DIR_USER, filename);
+    auto *fff = angband_fopen(path, FileOpenMode::WRITE);
     if (!fff) {
         return false;
     }
index d006245..c912d14 100644 (file)
@@ -1,12 +1,14 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
+#include <filesystem>
 #include <string>
 #include <string_view>
 #include <vector>
 
 class PlayerType;
 void autopick_load_pref(PlayerType *player_ptr, bool disp_mes);
+std::filesystem::path search_pickpref_path(PlayerType *player_ptr);
 std::vector<concptr> read_pickpref_text_lines(PlayerType *player_ptr, int *filename_mode_p);
 bool write_text_lines(std::string_view filename, const std::vector<concptr> &lines);
 std::string pickpref_filename(PlayerType *player_ptr, int filename_mode);
index 7619c2b..ec6ec37 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動拾いにアイテムを登録する
  * @date 2020/04/26
  * @author Hourier
@@ -28,14 +28,11 @@ static const char autoregister_header[] = "?:$AUTOREGISTER";
  */
 static bool clear_auto_register(PlayerType *player_ptr)
 {
-    char pref_file[1024];
-    path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
-    auto *pref_fff = angband_fopen(pref_file, FileOpenMode::READ);
-    if (!pref_fff) {
-        path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
-        pref_fff = angband_fopen(pref_file, FileOpenMode::READ);
+    const auto path_pref = search_pickpref_path(player_ptr);
+    if (path_pref.empty()) {
+        return true;
     }
-
+    auto *pref_fff = angband_fopen(path_pref, FileOpenMode::READ);
     if (!pref_fff) {
         return true;
     }
@@ -51,8 +48,8 @@ static bool clear_auto_register(PlayerType *player_ptr)
 
     auto autoregister = false;
     auto num = 0;
-    char buf[1024];
     while (true) {
+        char buf[1024]{};
         if (angband_fgets(pref_fff, buf, sizeof(buf))) {
             break;
         }
@@ -77,9 +74,9 @@ static bool clear_auto_register(PlayerType *player_ptr)
     bool okay = true;
     if (num) {
         msg_format(_("以前のキャラクター用の自動設定(%d行)が残っています。", "Auto registered lines (%d lines) for previous character are remaining."), num);
-        strcpy(buf, _("古い設定行は削除します。よろしいですか?", "These lines will be deleted.  Are you sure? "));
+        constexpr auto mes = _("古い設定行は削除します。よろしいですか?", "These lines will be deleted.  Are you sure? ");
 
-        if (!get_check(buf)) {
+        if (!input_check(mes)) {
             okay = false;
             autoregister = false;
 
@@ -89,8 +86,8 @@ static bool clear_auto_register(PlayerType *player_ptr)
 
     if (autoregister) {
         tmp_fff = angband_fopen(tmp_file, FileOpenMode::READ);
-        pref_fff = angband_fopen(pref_file, FileOpenMode::WRITE);
-
+        pref_fff = angband_fopen(path_pref, FileOpenMode::WRITE);
+        char buf[1024]{};
         while (!angband_fgets(tmp_fff, buf, sizeof(buf))) {
             fprintf(pref_fff, "%s\n", buf);
         }
@@ -139,17 +136,12 @@ bool autopick_autoregister(PlayerType *player_ptr, ItemEntity *o_ptr)
         }
     }
 
-    char buf[1024];
-    char pref_file[1024];
-    path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
-    auto *pref_fff = angband_fopen(pref_file, FileOpenMode::READ);
-    if (!pref_fff) {
-        path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
-        pref_fff = angband_fopen(pref_file, FileOpenMode::READ);
-    }
+    const auto path_pref = search_pickpref_path(player_ptr);
+    auto *pref_fff = !path_pref.empty() ? angband_fopen(path_pref, FileOpenMode::READ) : nullptr;
 
     if (pref_fff) {
         while (true) {
+            char buf[1024]{};
             if (angband_fgets(pref_fff, buf, sizeof(buf))) {
                 player_ptr->autopick_autoregister = false;
                 break;
@@ -170,9 +162,10 @@ bool autopick_autoregister(PlayerType *player_ptr, ItemEntity *o_ptr)
         player_ptr->autopick_autoregister = false;
     }
 
-    pref_fff = angband_fopen(pref_file, FileOpenMode::APPEND);
+    pref_fff = angband_fopen(path_pref, FileOpenMode::APPEND);
     if (!pref_fff) {
-        msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), pref_file);
+        const auto filename_pref = path_pref.string();
+        msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), filename_pref.data());
         msg_print(nullptr);
         return false;
     }
index f479c69..967a3e5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index b4b0e7a..5c1a532 100644 (file)
@@ -1,6 +1,5 @@
-#include "autopick/autopick-util.h"
+#include "autopick/autopick-util.h"
 #include "autopick/autopick-menu-data-table.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "game-option/input-options.h"
 #include "main/sound-of-music.h"
@@ -8,7 +7,8 @@
 #include "object-enchant/item-feeling.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
-#include "util/quarks.h"
+#include "system/redrawing-flags-updater.h"
+#include "util/bit-flags-calculator.h"
 
 /*!
  * @brief 自動拾い/破壊設定のリストに関する変数 / List for auto-picker/destroyer entries
@@ -28,6 +28,16 @@ bool autopick_type::has(int flag) const
     return this->flags[flag / 32] & (1UL << (flag % 32));
 }
 
+void autopick_type::add(int flag)
+{
+    set_bits(this->flags[flag / 32], 1UL << (flag % 32));
+}
+
+void autopick_type::remove(int flag)
+{
+    reset_bits(this->flags[flag / 32], 1UL << (flag % 32));
+}
+
 /*!
  * @brief Free memory of lines_list.
  */
@@ -57,7 +67,7 @@ int get_com_id(char key)
 /*!
  * @brief Auto inscription
  */
-void auto_inscribe_item(PlayerType *player_ptr, ItemEntity *o_ptr, int idx)
+void auto_inscribe_item(ItemEntity *o_ptr, int idx)
 {
     if (idx < 0 || autopick_list[idx].insc.empty()) {
         return;
@@ -67,9 +77,17 @@ void auto_inscribe_item(PlayerType *player_ptr, ItemEntity *o_ptr, int idx)
         o_ptr->inscription = autopick_list[idx].insc;
     }
 
-    player_ptr->window_flags |= (PW_EQUIPMENT | PW_INVENTORY);
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->update |= (PU_COMBINATION);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+    };
+    rfu.set_flags(flags_swrf);
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::COMBINATION,
+    };
+    rfu.set_flags(flags_srf);
 }
 
 /*!
index 4159183..b1dcb02 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
  * @brief 自動拾い/破壊設定データの構造体 / A structure type for entry of auto-picker/destroyer
  */
 struct autopick_type {
-    std::string name; /*!< 自動拾い/破壊定義の名称一致基準 / Items which have 'name' as part of its name match */
-    std::string insc; /*!< 対象となったアイテムに自動で刻む内容 / Items will be auto-inscribed as 'insc' */
-    BIT_FLAGS flags[2]; /*!< キーワードに関する汎用的な条件フラグ / Misc. keyword to be matched */
-    byte action; /*!< 対象のアイテムを拾う/破壊/放置するかの指定フラグ / Auto-pickup or Destroy or Leave items */
-    byte dice; /*!< 武器のダイス値基準値 / Weapons which have more than 'dice' dice match */
-    byte bonus; /*!< アイテムのボーナス基準値 / Items which have more than 'bonus' magical bonus match */
+    std::string name = ""; /*!< 自動拾い/破壊定義の名称一致基準 / Items which have 'name' as part of its name match */
+    std::string insc = ""; /*!< 対象となったアイテムに自動で刻む内容 / Items will be auto-inscribed as 'insc' */
+    BIT_FLAGS flags[2]{}; /*!< キーワードに関する汎用的な条件フラグ / Misc. keyword to be matched */
+    byte action = 0; /*!< 対象のアイテムを拾う/破壊/放置するかの指定フラグ / Auto-pickup or Destroy or Leave items */
+    byte dice = 0; /*!< 武器のダイス値基準値 / Weapons which have more than 'dice' dice match */
+    byte bonus = 0; /*!< アイテムのボーナス基準値 / Items which have more than 'bonus' magical bonus match */
     bool has(int flag) const;
-};
-
-/*
- * Struct for yank buffer
- */
-struct chain_str_type {
-    struct chain_str_type *next;
-    char s[1];
+    void add(int flag);
+    void remove(int flag);
 };
 
 /*
  * Data struct for text editor
  */
 class ItemEntity;
-;
 struct text_body_type {
-    int wid, hgt;
-    int cx, cy;
-    int upper, left;
-    int old_wid, old_hgt;
-    int old_cy;
-    int old_upper, old_left;
-    int mx, my;
-    byte mark;
-
-    ItemEntity *search_o_ptr;
-    concptr search_str;
-    concptr last_destroyed;
-
-    chain_str_type *yank;
-    bool yank_eol;
-
-    std::vector<concptr> lines_list;
-    byte states[MAX_LINES];
-
-    uint16_t dirty_flags;
-    int dirty_line;
-    int filename_mode;
-    int old_com_id;
-
-    bool changed;
+    int wid = 0;
+    int hgt = 0;
+    int cx = 0;
+    int cy = 0;
+    int upper = 0;
+    int left = 0;
+    int old_wid = 0;
+    int old_hgt = 0;
+    int old_cy = 0;
+    int old_upper = 0;
+    int old_left = 0;
+    int mx = 0;
+    int my = 0;
+    byte mark = 0;
+
+    ItemEntity *search_o_ptr = nullptr;
+    concptr search_str = "";
+    concptr last_destroyed = "";
+
+    std::vector<std::string> yank{};
+    bool yank_eol = false;
+
+    std::vector<concptr> lines_list{};
+    byte states[MAX_LINES]{};
+
+    uint16_t dirty_flags = 0;
+    int dirty_line = 0;
+    int filename_mode = 0;
+    int old_com_id = 0;
+
+    bool changed = false;
 };
 
 /*
@@ -81,10 +80,9 @@ struct text_body_type {
 extern std::vector<autopick_type> autopick_list;
 extern ItemEntity autopick_last_destroyed_object;
 
-class PlayerType;
 void free_text_lines(std::vector<concptr> &lines_list);
 int get_com_id(char key);
-void auto_inscribe_item(PlayerType *player_ptr, ItemEntity *o_ptr, int idx);
+void auto_inscribe_item(ItemEntity *o_ptr, int idx);
 int count_line(text_body_type *tb);
 
 /*!
index 1e92434..2dc3bca 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file autopick.c
  * @brief 自動拾い機能の実装 / Object Auto-picker/Destroyer
  * @date 2014/01/02
 /*!
  * @brief Auto-destroy marked item
  */
-static void autopick_delayed_alter_aux(PlayerType *player_ptr, INVENTORY_IDX item)
+static void autopick_delayed_alter_aux(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
-    const auto *o_ptr = ref_item(player_ptr, item);
+    const auto *o_ptr = ref_item(player_ptr, i_idx);
     if (!o_ptr->is_valid() || o_ptr->marked.has_not(OmType::AUTODESTROY)) {
         return;
     }
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
-    if (item >= 0) {
-        inven_item_increase(player_ptr, item, -(o_ptr->number));
-        inven_item_optimize(player_ptr, item);
+    if (i_idx >= 0) {
+        inven_item_increase(player_ptr, i_idx, -(o_ptr->number));
+        inven_item_optimize(player_ptr, i_idx);
     } else {
-        delete_object_idx(player_ptr, 0 - item);
+        delete_object_idx(player_ptr, 0 - i_idx);
     }
 
     msg_format(_("%sを自動破壊します。", "Auto-destroying %s."), item_name.data());
@@ -64,18 +64,19 @@ static void autopick_delayed_alter_aux(PlayerType *player_ptr, INVENTORY_IDX ite
  */
 void autopick_delayed_alter(PlayerType *player_ptr)
 {
-    for (INVENTORY_IDX item = INVEN_TOTAL - 1; item >= 0; item--) {
-        autopick_delayed_alter_aux(player_ptr, item);
+    for (INVENTORY_IDX i_idx = INVEN_TOTAL - 1; i_idx >= 0; i_idx--) {
+        autopick_delayed_alter_aux(player_ptr, i_idx);
     }
 
-    auto &grid = player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
+    const auto p_pos = player_ptr->get_position();
+    auto &grid = player_ptr->current_floor_ptr->get_grid(p_pos);
     for (auto it = grid.o_idx_list.begin(); it != grid.o_idx_list.end();) {
-        INVENTORY_IDX item = *it++;
-        autopick_delayed_alter_aux(player_ptr, -item);
+        INVENTORY_IDX i_idx = *it++;
+        autopick_delayed_alter_aux(player_ptr, -i_idx);
     }
 
     // PW_FLOOR_ITEM_LISTは遅れるので即時更新
-    fix_floor_item_list(player_ptr, player_ptr->y, player_ptr->x);
+    fix_floor_item_list(player_ptr, p_pos);
 }
 
 /*!
@@ -84,13 +85,13 @@ void autopick_delayed_alter(PlayerType *player_ptr)
  * Auto-destroyer works only on inventory or on floor stack only when
  * requested.
  */
-void autopick_alter_item(PlayerType *player_ptr, INVENTORY_IDX item, bool destroy)
+void autopick_alter_item(PlayerType *player_ptr, INVENTORY_IDX i_idx, bool destroy)
 {
     ItemEntity *o_ptr;
-    o_ptr = ref_item(player_ptr, item);
+    o_ptr = ref_item(player_ptr, i_idx);
     int idx = find_autopick_list(player_ptr, o_ptr);
-    auto_inscribe_item(player_ptr, o_ptr, idx);
-    if (destroy && item <= INVEN_PACK) {
+    auto_inscribe_item(o_ptr, idx);
+    if (destroy && i_idx <= INVEN_PACK) {
         auto_destroy_item(player_ptr, o_ptr, idx);
     }
 }
@@ -98,13 +99,13 @@ void autopick_alter_item(PlayerType *player_ptr, INVENTORY_IDX item, bool destro
 /*!
  * @brief Automatically pickup/destroy items in this grid.
  */
-void autopick_pickup_items(PlayerType *player_ptr, grid_type *g_ptr)
+void autopick_pickup_items(PlayerType *player_ptr, Grid *g_ptr)
 {
     for (auto it = g_ptr->o_idx_list.begin(); it != g_ptr->o_idx_list.end();) {
         OBJECT_IDX this_o_idx = *it++;
         auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
         int idx = find_autopick_list(player_ptr, o_ptr);
-        auto_inscribe_item(player_ptr, o_ptr, idx);
+        auto_inscribe_item(o_ptr, idx);
         if ((idx < 0) || (autopick_list[idx].action & (DO_AUTOPICK | DO_QUERY_AUTOPICK)) == 0) {
             auto_destroy_item(player_ptr, o_ptr, idx);
             continue;
@@ -130,7 +131,7 @@ void autopick_pickup_items(PlayerType *player_ptr, grid_type *g_ptr)
         const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
         std::stringstream ss;
         ss << _(item_name, "Pick up ") << _("を拾いますか", item_name) << "? ";
-        if (!get_check(ss.str())) {
+        if (!input_check(ss.str())) {
             o_ptr->marked.set({ OmType::SUPRESS_MESSAGE, OmType::NO_QUERY });
             continue;
         }
index 716735a..eea3641 100644 (file)
@@ -1,10 +1,9 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-struct grid_type;
-;
+class Grid;
 class PlayerType;
-void autopick_alter_item(PlayerType *player_ptr, INVENTORY_IDX item, bool destroy);
+void autopick_alter_item(PlayerType *player_ptr, INVENTORY_IDX i_idx, bool destroy);
 void autopick_delayed_alter(PlayerType *player_ptr);
-void autopick_pickup_items(PlayerType *player_ptr, grid_type *g_ptr);
+void autopick_pickup_items(PlayerType *player_ptr, Grid *g_ptr);
index a7e0fe8..0713c36 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 敵への攻撃によって徳を変化させる処理
  * @date 2021/08/05
  * @author Hourier
@@ -37,7 +37,7 @@ void AvatarChanger::change_virtue()
 {
     this->change_virtue_non_beginner();
     this->change_virtue_unique();
-    const auto &r_ref = this->m_ptr->get_real_r_ref();
+    const auto &r_ref = this->m_ptr->get_real_monrace();
     if (m_ptr->r_idx == MonsterRaceId::BEGGAR || m_ptr->r_idx == MonsterRaceId::LEPER) {
         chg_virtue(this->player_ptr, Virtue::COMPASSION, -1);
     }
@@ -62,8 +62,8 @@ void AvatarChanger::change_virtue()
 void AvatarChanger::change_virtue_non_beginner()
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (dungeons_info[this->player_ptr->dungeon_idx].flags.has(DungeonFeatureType::BEGINNER)) {
+    auto *r_ptr = &m_ptr->get_monrace();
+    if (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::BEGINNER)) {
         return;
     }
 
@@ -89,7 +89,7 @@ void AvatarChanger::change_virtue_non_beginner()
  */
 void AvatarChanger::change_virtue_unique()
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
         return;
     }
@@ -115,7 +115,7 @@ void AvatarChanger::change_virtue_unique()
 void AvatarChanger::change_virtue_good_evil()
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->kind_flags.has(MonsterKindType::GOOD) && ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100))) {
         chg_virtue(this->player_ptr, Virtue::UNLIFE, 1);
     }
@@ -146,7 +146,7 @@ void AvatarChanger::change_virtue_good_evil()
 void AvatarChanger::change_virtue_revenge()
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->r_deaths == 0) {
         return;
     }
@@ -167,15 +167,15 @@ void AvatarChanger::change_virtue_revenge()
 void AvatarChanger::change_virtue_wild_thief()
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     auto innocent = true;
     auto thief = false;
-    for (auto i = 0; i < MAX_NUM_BLOWS; i++) {
-        if (r_ptr->blow[i].d_dice != 0) {
+    for (const auto &blow : r_ptr->blows) {
+        if (blow.d_dice != 0) {
             innocent = false;
         }
 
-        if ((r_ptr->blow[i].effect == RaceBlowEffectType::EAT_ITEM) || (r_ptr->blow[i].effect == RaceBlowEffectType::EAT_GOLD)) {
+        if ((blow.effect == RaceBlowEffectType::EAT_ITEM) || (blow.effect == RaceBlowEffectType::EAT_GOLD)) {
             thief = true;
         }
     }
@@ -207,7 +207,7 @@ void AvatarChanger::change_virtue_wild_thief()
  */
 void AvatarChanger::change_virtue_good_animal()
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     auto magic_ability_flags = r_ptr->ability_flags;
     magic_ability_flags.reset(RF_ABILITY_NOMAGIC_MASK);
     if (r_ptr->kind_flags.has_not(MonsterKindType::ANIMAL) || r_ptr->kind_flags.has(MonsterKindType::EVIL) || magic_ability_flags.any()) {
index e7a0cfe..1760c6d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index de630b1..0296c04 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ウルティマ4を参考にした徳のシステムの実装 / Enable an Ultima IV style "avatar" game where you try to achieve perfection in various virtues.
  * @date 2013/12/23
  * @author
  */
 
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "game-option/text-display-options.h"
 #include "player-info/class-info.h"
 #include "player-info/race-types.h"
 #include "realm/realm-names-table.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/enum-converter.h"
+#include "util/probability-table.h"
 
 /*!
  * 徳の名称 / The names of the virtues
@@ -82,60 +83,24 @@ int virtue_number(PlayerType *player_ptr, Virtue virtue)
  */
 static void get_random_virtue(PlayerType *player_ptr, int which)
 {
-    auto type = Virtue::NONE;
-    while ((type == Virtue::NONE) || virtue_number(player_ptr, type)) {
-        switch (randint1(29)) {
-        case 1:
-        case 2:
-        case 3:
-            type = Virtue::SACRIFICE;
-            break;
-        case 4:
-        case 5:
-        case 6:
-            type = Virtue::COMPASSION;
-            break;
-        case 7:
-        case 8:
-        case 9:
-        case 10:
-        case 11:
-        case 12:
-            type = Virtue::VALOUR;
-            break;
-        case 13:
-        case 14:
-        case 15:
-        case 16:
-        case 17:
-            type = Virtue::HONOUR;
-            break;
-        case 18:
-        case 19:
-        case 20:
-        case 21:
-            type = Virtue::JUSTICE;
-            break;
-        case 22:
-        case 23:
-            type = Virtue::TEMPERANCE;
-            break;
-        case 24:
-        case 25:
-            type = Virtue::HARMONY;
-            break;
-        case 26:
-        case 27:
-        case 28:
-            type = Virtue::PATIENCE;
-            break;
-        default:
-            type = Virtue::DILIGENCE;
-            break;
+    ProbabilityTable<Virtue> pt;
+    pt.entry_item(Virtue::SACRIFICE, 3);
+    pt.entry_item(Virtue::COMPASSION, 3);
+    pt.entry_item(Virtue::VALOUR, 6);
+    pt.entry_item(Virtue::HONOUR, 5);
+    pt.entry_item(Virtue::JUSTICE, 4);
+    pt.entry_item(Virtue::TEMPERANCE, 2);
+    pt.entry_item(Virtue::HARMONY, 2);
+    pt.entry_item(Virtue::PATIENCE, 3);
+    pt.entry_item(Virtue::DILIGENCE, 1);
+
+    while (true) {
+        const auto type = pt.pick_one_at_random();
+        if (virtue_number(player_ptr, type) == 0) {
+            player_ptr->vir_types[which] = type;
+            return;
         }
     }
-
-    player_ptr->vir_types[which] = type;
 }
 
 /*!
@@ -497,7 +462,7 @@ void chg_virtue(PlayerType *player_ptr, Virtue virtue_id, int amount)
             }
         }
 
-        player_ptr->update |= PU_BONUS;
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
         return;
     }
 }
@@ -531,7 +496,7 @@ void dump_virtues(PlayerType *player_ptr, FILE *out_file)
         GAME_TEXT vir_name[20];
         int tester = player_ptr->virtues[v_nr];
         strcpy(vir_name, virtue_names.at(player_ptr->vir_types[v_nr]).data());
-        const std::string vir_val_str = format(" (%d)", tester);
+        const auto vir_val_str = format(" (%d)", tester);
         const auto vir_val = show_actual_value ? vir_val_str.data() : "";
         if ((player_ptr->vir_types[v_nr] == Virtue::NONE) || (player_ptr->vir_types[v_nr] >= Virtue::MAX)) {
             fprintf(out_file, _("おっと。%sの情報なし。", "Oops. No info about %s."), vir_name);
index 5cafbc3..335451e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <map>
index 5ecbb13..bfae185 100644 (file)
@@ -1,8 +1,9 @@
-#include "birth/auto-roller.h"
+#include "birth/auto-roller.h"
 #include "birth/birth-stat.h"
 #include "birth/birth-util.h"
 #include "cmd-io/cmd-gameoption.h"
 #include "io/input-key-acceptor.h"
+#include "locale/japanese.h"
 #include "main/sound-of-music.h"
 #include "player-info/class-info.h"
 #include "player-info/race-info.h"
@@ -225,7 +226,7 @@ bool get_stat_limits(PlayerType *player_ptr)
     decide_initial_stat(player_ptr, cval);
 
     for (int i = 0; i < A_MAX; i++) {
-        put_str(cursor_of_adjusted_stat(cval, i).data(), 14 + i, 10);
+        put_str(cursor_of_adjusted_stat(cval, i), 14 + i, 10);
     }
 
     display_autoroller_chance(cval);
@@ -240,14 +241,14 @@ bool get_stat_limits(PlayerType *player_ptr)
             } else if (os == A_MAX) {
                 c_put_str(TERM_WHITE, _("決定する", "Accept"), 21, 35);
             } else if (os < A_MAX) {
-                c_put_str(TERM_WHITE, cur.data(), 14 + os, 10);
+                c_put_str(TERM_WHITE, cur, 14 + os, 10);
             }
 
             if (cs == A_MAX) {
                 c_put_str(TERM_YELLOW, _("決定する", "Accept"), 21, 35);
             } else {
                 cur = cursor_of_adjusted_stat(cval, cs);
-                c_put_str(TERM_YELLOW, cur.data(), 14 + cs, 10);
+                c_put_str(TERM_YELLOW, cur, 14 + cs, 10);
             }
 
             os = cs;
@@ -371,7 +372,7 @@ bool get_chara_limits(PlayerType *player_ptr, chara_limit_type *chara_limit_ptr)
 {
 #define MAXITEMS 8
 
-    concptr itemname[] = { _("年齢", "age"), _("身長(インチ)", "height"), _("体重(ポンド)", "weight"), _("社会的地位", "social class") };
+    concptr itemname[] = { _("年齢", "age"), _("身長(cm)", "height"), _("体重(kg)", "weight"), _("社会的地位", "social class") };
 
     clear_from(10);
     put_str(_("2/4/6/8で項目選択、+/-で値の増減、Enterで次へ", "2/4/6/8 for Select, +/- for Change value, Enter for Goto next"), 11, 10);
@@ -441,7 +442,16 @@ bool get_chara_limits(PlayerType *player_ptr, chara_limit_type *chara_limit_ptr)
         }
 
         mval[i] = m;
-        cval[i] = m;
+    }
+#ifdef JP
+    /*身長と体重の単位をcmとkgに*/
+    mval[2] = inch_to_cm(mval[2]);
+    mval[3] = inch_to_cm(mval[3]);
+    mval[4] = lb_to_kg(mval[4]);
+    mval[5] = lb_to_kg(mval[5]);
+#endif
+    for (auto i = 0; i < MAXITEMS; i++) {
+        cval[i] = mval[i];
     }
 
     for (int i = 0; i < 4; i++) {
@@ -459,7 +469,7 @@ bool get_chara_limits(PlayerType *player_ptr, chara_limit_type *chara_limit_ptr)
     int os = MAXITEMS;
     while (true) {
         if (cs != os) {
-            const char accept[] = _("決定する", "Accept");
+            constexpr auto accept = _("決定する", "Accept");
             if (os == MAXITEMS) {
                 c_put_str(TERM_WHITE, accept, 19, 35);
             } else {
index f4ab0ed..cb59bec 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 34fab8e..15c5dd5 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/birth-body-spec.h"
+#include "birth/birth-body-spec.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/race-info.h"
index af8f3e5..addcc76 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void get_height_weight(PlayerType *player_ptr);
index de509b2..faa3092 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/birth-explanations-table.h"
+#include "birth/birth-explanations-table.h"
 #include "system/angband.h"
 
 /*! 種族の解説メッセージテーブル */
index 559bb39..29d47f1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 #include <vector>
index 4454dfd..992d0b7 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/birth-select-class.h"
+#include "birth/birth-select-class.h"
 #include "birth/birth-util.h"
 #include "io/input-key-acceptor.h"
 #include "player-info/class-info.h"
 #include "world/world.h"
 #include <sstream>
 
-static TERM_COLOR birth_class_color(PlayerClassType cs)
-{
-    if (cs < PlayerClassType::MAX) {
-        if (is_retired_class(cs)) {
-            return TERM_L_DARK;
-        }
-        if (is_winner_class(cs)) {
-            return TERM_SLATE;
-        }
-    }
-    return TERM_WHITE;
-}
-
 static std::string birth_class_label(int cs, concptr sym)
 {
-    const char p2 = ')';
+    constexpr auto p2 = ')';
     std::stringstream ss;
-
     if (cs < 0 || cs >= PLAYER_CLASS_TYPE_MAX) {
         ss << '*' << p2 << _("ランダム", "Random");
+        return ss.str();
+    }
+
+    ss << sym[cs] << p2;
+    if (!(rp_ptr->choice & (1UL << cs))) {
+        ss << '(' << class_info[cs].title << ')';
     } else {
-        ss << sym[cs] << p2;
-        if (!(rp_ptr->choice & (1UL << cs))) {
-            ss << '(' << class_info[cs].title << ')';
-        } else {
-            ss << class_info[cs].title;
-        }
+        ss << class_info[cs].title;
     }
+
     return ss.str();
 }
 
@@ -55,7 +43,7 @@ static void enumerate_class_list(char *sym)
         }
 
         auto cs = i2enum<PlayerClassType>(n);
-        c_put_str(birth_class_color(cs), birth_class_label(n, sym), 13 + (n / 4), 2 + 19 * (n % 4));
+        c_put_str(w_ptr->get_birth_class_color(cs), birth_class_label(n, sym), 13 + (n / 4), 2 + 19 * (n % 4));
     }
 }
 
@@ -66,7 +54,7 @@ static std::string display_class_stat(int cs, int *os, const std::string &cur, c
     }
 
     auto pclass = i2enum<PlayerClassType>(*os);
-    c_put_str(birth_class_color(pclass), cur, 13 + (*os / 4), 2 + 19 * (*os % 4));
+    c_put_str(w_ptr->get_birth_class_color(pclass), cur, 13 + (*os / 4), 2 + 19 * (*os % 4));
     put_str("                                   ", 3, 40);
     auto result = birth_class_label(cs, sym);
     if (cs == PLAYER_CLASS_TYPE_MAX) {
@@ -197,7 +185,7 @@ static bool select_class(PlayerType *player_ptr, concptr sym, int *k)
             *k = -1;
         }
 
-        birth_help_option(player_ptr, c, BK_CLASS);
+        birth_help_option(player_ptr, c, BirthKind::CLASS);
     }
 
     return true;
index ca724dd..4de79a7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool get_player_class(PlayerType *player_ptr);
index d490a91..faa1e2e 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/birth-select-personality.h"
+#include "birth/birth-select-personality.h"
 #include "birth/birth-util.h"
 #include "io/input-key-acceptor.h"
 #include "player/player-personality.h"
@@ -7,6 +7,7 @@
 #include "term/term-color-types.h"
 #include "term/z-form.h"
 #include "util/int-char-converter.h"
+#include "view/display-player-misc-info.h"
 #include <sstream>
 
 static std::string birth_personality_label(int cs, concptr sym)
@@ -76,58 +77,82 @@ static std::string display_personality_stat(int cs, int *os, const std::string &
     return result;
 }
 
-static void interpret_personality_select_key_move(PlayerType *player_ptr, char c, int *cs)
+static bool check_selected_sex(int pp_idx, player_sex psex)
 {
-    if (c == '8') {
-        if (*cs >= 4) {
-            *cs -= 4;
+    const auto ppersonality = personality_info[pp_idx];
+    return (ppersonality.sex != 0) && (ppersonality.sex != (psex + 1));
+}
+
+static int interpret_personality_select_key_move(PlayerType *player_ptr, char key, int initial_personality)
+{
+    auto pp_idx = initial_personality;
+    switch (key) {
+    case '8':
+        if (pp_idx >= 4) {
+            pp_idx -= 4;
         }
-        if ((*cs != MAX_PERSONALITIES) && personality_info[*cs].sex && (personality_info[*cs].sex != (player_ptr->psex + 1))) {
-            if ((*cs - 4) > 0) {
-                *cs -= 4;
-            } else {
-                *cs += 4;
-            }
+
+        if ((pp_idx >= MAX_PERSONALITIES) || !check_selected_sex(pp_idx, player_ptr->psex)) {
+            return pp_idx;
         }
-    }
 
-    if (c == '4') {
-        if (*cs > 0) {
-            (*cs)--;
+        if ((pp_idx - 4) > 0) {
+            pp_idx -= 4;
+        } else {
+            pp_idx += 4;
         }
-        if ((*cs != MAX_PERSONALITIES) && personality_info[*cs].sex && (personality_info[*cs].sex != (player_ptr->psex + 1))) {
-            if ((*cs - 1) > 0) {
-                (*cs)--;
-            } else {
-                (*cs)++;
-            }
+
+        return pp_idx;
+    case '4':
+        if (pp_idx > 0) {
+            (pp_idx)--;
         }
-    }
 
-    if (c == '6') {
-        if (*cs < MAX_PERSONALITIES) {
-            (*cs)++;
+        if ((pp_idx >= MAX_PERSONALITIES) || !check_selected_sex(pp_idx, player_ptr->psex)) {
+            return pp_idx;
         }
-        if ((*cs != MAX_PERSONALITIES) && personality_info[*cs].sex && (personality_info[*cs].sex != (player_ptr->psex + 1))) {
-            if ((*cs + 1) <= MAX_PERSONALITIES) {
-                (*cs)++;
-            } else {
-                (*cs)--;
-            }
+
+        if ((pp_idx - 1) > 0) {
+            (pp_idx)--;
+        } else {
+            (pp_idx)++;
         }
-    }
 
-    if (c == '2') {
-        if ((*cs + 4) <= MAX_PERSONALITIES) {
-            *cs += 4;
+        return pp_idx;
+    case '6':
+        if (pp_idx < MAX_PERSONALITIES) {
+            (pp_idx)++;
         }
-        if ((*cs != MAX_PERSONALITIES) && personality_info[*cs].sex && (personality_info[*cs].sex != (player_ptr->psex + 1))) {
-            if ((*cs + 4) <= MAX_PERSONALITIES) {
-                *cs += 4;
-            } else {
-                *cs -= 4;
-            }
+
+        if ((pp_idx >= MAX_PERSONALITIES) || !check_selected_sex(pp_idx, player_ptr->psex)) {
+            return pp_idx;
+        }
+
+        if ((pp_idx + 1) <= MAX_PERSONALITIES) {
+            (pp_idx)++;
+        } else {
+            (pp_idx)--;
+        }
+
+        return pp_idx;
+    case '2':
+        if ((pp_idx + 4) <= MAX_PERSONALITIES) {
+            pp_idx += 4;
         }
+
+        if ((pp_idx >= MAX_PERSONALITIES) || !check_selected_sex(pp_idx, player_ptr->psex)) {
+            return pp_idx;
+        }
+
+        if ((pp_idx + 4) <= MAX_PERSONALITIES) {
+            pp_idx += 4;
+        } else {
+            pp_idx -= 4;
+        }
+
+        return pp_idx;
+    default:
+        return pp_idx;
     }
 }
 
@@ -168,11 +193,17 @@ static bool select_personality(PlayerType *player_ptr, int *k, concptr sym)
             }
         }
 
-        interpret_personality_select_key_move(player_ptr, c, &cs);
+        cs = interpret_personality_select_key_move(player_ptr, c, cs);
         if (c == '*') {
+            player_personality ppersonality{};
             do {
                 *k = randint0(MAX_PERSONALITIES);
-            } while (personality_info[*k].sex && (personality_info[*k].sex != (player_ptr->psex + 1)));
+                if (*k < 0) {
+                    continue; // 静的解析対応.
+                }
+
+                ppersonality = personality_info[*k];
+            } while (ppersonality.sex && (ppersonality.sex != (player_ptr->psex + 1)));
 
             cs = *k;
             continue;
@@ -196,7 +227,7 @@ static bool select_personality(PlayerType *player_ptr, int *k, concptr sym)
             *k = -1;
         }
 
-        birth_help_option(player_ptr, c, BK_PERSONALITY);
+        birth_help_option(player_ptr, c, BirthKind::PERSONALITY);
     }
 
     return true;
@@ -221,17 +252,6 @@ bool get_player_personality(PlayerType *player_ptr)
 
     player_ptr->ppersonality = (player_personality_type)k;
     ap_ptr = &personality_info[player_ptr->ppersonality];
-    char tmp[64];
-#ifdef JP
-    strcpy(tmp, ap_ptr->title);
-    if (ap_ptr->no == 1) {
-        strcat(tmp, "の");
-    }
-#else
-    strcpy(tmp, ap_ptr->title);
-    strcat(tmp, " ");
-#endif
-    strcat(tmp, player_ptr->name);
-    c_put_str(TERM_L_BLUE, tmp, 1, 34);
+    display_player_name(player_ptr);
     return true;
 }
index dd8c648..cbc1485 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool get_player_personality(PlayerType *player_ptr);
index 619e796..f1384d1 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/birth-select-race.h"
+#include "birth/birth-select-race.h"
 #include "birth/birth-util.h"
 #include "io/input-key-acceptor.h"
 #include "player-info/race-info.h"
@@ -161,7 +161,7 @@ static bool select_race(PlayerType *player_ptr, char *sym, int *k)
             *k = -1;
         }
 
-        birth_help_option(player_ptr, c, BK_RACE);
+        birth_help_option(player_ptr, c, BirthKind::RACE);
     }
 
     return true;
index 2b3a93a..bc377fc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool get_player_race(PlayerType *player_ptr);
index 43a9359..b8a0b34 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/birth-select-realm.h"
+#include "birth/birth-select-realm.h"
 #include "birth/birth-explanations-table.h"
 #include "birth/birth-util.h"
 #include "core/asking-player.h"
@@ -172,7 +172,7 @@ static void move_birth_realm_cursor(birth_realm_type *birth_realm_ptr)
         strnfmt(birth_realm_ptr->buf, sizeof(birth_realm_ptr->buf), "%s", realm_names[birth_realm_ptr->picks[birth_realm_ptr->cs]]);
         c_put_str(TERM_L_BLUE, birth_realm_ptr->buf, 3, 40);
         prt(_("の特徴", ": Characteristic"), 3, 40 + strlen(birth_realm_ptr->buf));
-        prt(realm_subinfo[technic2magic(birth_realm_ptr->picks[birth_realm_ptr->cs]) - 1].data(), 4, 40);
+        prt(realm_subinfo[technic2magic(birth_realm_ptr->picks[birth_realm_ptr->cs]) - 1], 4, 40);
     }
 
     c_put_str(TERM_YELLOW, birth_realm_ptr->cur, 12 + (birth_realm_ptr->cs / 5), 2 + 15 * (birth_realm_ptr->cs % 5));
@@ -258,7 +258,7 @@ static bool get_a_realm(PlayerType *player_ptr, birth_realm_type *birth_realm_pt
             birth_realm_ptr->k = -1;
         }
 
-        birth_help_option(player_ptr, c, BK_REALM);
+        birth_help_option(player_ptr, c, BirthKind::REALM);
     }
 
     return false;
@@ -315,7 +315,7 @@ static bool check_realm_selection(PlayerType *player_ptr, int count)
         (void)inkey();
         prt("", 0, 0);
         return true;
-    } else if (get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y)) {
+    } else if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::DEFAULT_Y)) {
         return true;
     }
 
index ec348b4..f130d5c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool get_player_realms(PlayerType *player_ptr);
index b967459..303c892 100644 (file)
@@ -1,6 +1,5 @@
-#include "birth/birth-stat.h"
+#include "birth/birth-stat.h"
 #include "birth/auto-roller.h"
-#include "core/player-redraw-types.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/class-info.h"
 #include "spell/spells-status.h"
 #include "sv-definition/sv-weapon-types.h"
 #include "system/player-type-definition.h"
-
-/*! オートロール能力値の乱数分布 / emulate 5 + 1d3 + 1d4 + 1d5 by randint0(60) */
-BASE_STATUS rand3_4_5[60] = {
-    8, 9, 9, 9, 10, 10, 10, 10, 10, 10, /*00-09*/
-    11, 11, 11, 11, 11, 11, 11, 11, 11, 12, /*10-19*/
-    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /*20-29*/
-    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, /*30-49*/
-    13, 14, 14, 14, 14, 14, 14, 14, 14, 14, /*40-49*/
-    15, 15, 15, 15, 15, 15, 16, 16, 16, 17 /*50-59*/
+#include "system/redrawing-flags-updater.h"
+#include <array>
+
+namespace {
+
+constexpr auto random_distribution = 60;
+
+/*! オートロール能力値の乱数分布 (1d3, 1d4, 1d5 を3 * 4 * 5 = 60個で表現) */
+constexpr std::array<short, random_distribution> auto_roller_distribution = {
+    {
+        8, 9, 9, 9, 10, 10, 10, 10, 10, 10, /*00-09*/
+        11, 11, 11, 11, 11, 11, 11, 11, 11, 12, /*10-19*/
+        12, 12, 12, 12, 12, 12, 12, 12, 12, 12, /*20-29*/
+        13, 13, 13, 13, 13, 13, 13, 13, 13, 13, /*30-49*/
+        13, 14, 14, 14, 14, 14, 14, 14, 14, 14, /*40-49*/
+        15, 15, 15, 15, 15, 15, 16, 16, 16, 17 /*50-59*/
+    }
 };
+}
 
 /*!
  * @brief プレイヤーの能力値表現に基づいて加減算を行う。
@@ -64,21 +72,15 @@ int adjust_stat(int value, int amount)
 void get_stats(PlayerType *player_ptr)
 {
     while (true) {
-        int sum = 0;
-        for (int i = 0; i < 2; i++) {
-            int32_t tmp = randint0(60 * 60 * 60);
-            BASE_STATUS val;
-
-            for (int j = 0; j < 3; j++) {
-                int stat = i * 3 + j;
-
-                /* Extract 5 + 1d3 + 1d4 + 1d5 */
-                val = rand3_4_5[tmp % 60];
-
+        auto sum = 0;
+        for (auto i = 0; i < 2; i++) {
+            auto tmp = randint0(random_distribution * random_distribution * random_distribution);
+            for (auto j = 0; j < 3; j++) {
+                auto stat = i * 3 + j;
+                auto val = auto_roller_distribution[tmp % random_distribution];
                 sum += val;
                 player_ptr->stat_cur[stat] = player_ptr->stat_max[stat] = val;
-
-                tmp /= 60;
+                tmp /= random_distribution;
             }
         }
 
@@ -163,10 +165,10 @@ void get_extra(PlayerType *player_ptr, bool roll_hitdie)
  */
 void get_max_stats(PlayerType *player_ptr)
 {
-    int dice[6];
+    int dice[6]{};
     while (true) {
-        int j = 0;
-        for (int i = 0; i < A_MAX; i++) {
+        auto j = 0;
+        for (auto i = 0; i < A_MAX; i++) {
             dice[i] = randint1(7);
             j += dice[i];
         }
@@ -176,8 +178,8 @@ void get_max_stats(PlayerType *player_ptr)
         }
     }
 
-    for (int i = 0; i < A_MAX; i++) {
-        BASE_STATUS max_max = 18 + 60 + dice[i] * 10;
+    for (auto i = 0; i < A_MAX; i++) {
+        short max_max = 18 + 60 + dice[i] * 10;
         player_ptr->stat_max_max[i] = max_max;
         if (player_ptr->stat_max[i] > max_max) {
             player_ptr->stat_max[i] = max_max;
@@ -188,5 +190,5 @@ void get_max_stats(PlayerType *player_ptr)
     }
 
     player_ptr->knowledge &= ~(KNOW_STAT);
-    player_ptr->redraw |= (PR_ABILITY_SCORE);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
 }
index e17a174..16f51f2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 9260384..d029467 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/birth-util.h"
+#include "birth/birth-util.h"
 #include "cmd-io/cmd-gameoption.h"
 #include "core/show-file.h"
 #include "main/sound-of-music.h"
@@ -21,27 +21,27 @@ void birth_quit(void)
 void show_help(PlayerType *player_ptr, concptr helpfile)
 {
     screen_save();
-    (void)show_file(player_ptr, true, helpfile, nullptr, 0, 0);
+    (void)show_file(player_ptr, true, helpfile, 0, 0);
     screen_load();
 }
 
-void birth_help_option(PlayerType *player_ptr, char c, birth_kind bk)
+void birth_help_option(PlayerType *player_ptr, char c, BirthKind bk)
 {
     concptr help_file;
     switch (bk) {
-    case BK_RACE:
+    case BirthKind::RACE:
         help_file = _("jraceclas.txt#TheRaces", "raceclas.txt#TheRaces");
         break;
-    case BK_CLASS:
+    case BirthKind::CLASS:
         help_file = _("jraceclas.txt#TheClasses", "raceclas.txt#TheClasses");
         break;
-    case BK_REALM:
+    case BirthKind::REALM:
         help_file = _("jmagic.txt#MagicRealms", "magic.txt#MagicRealms");
         break;
-    case BK_PERSONALITY:
+    case BirthKind::PERSONALITY:
         help_file = _("jraceclas.txt#ThePersonalities", "raceclas.txt#ThePersonalities");
         break;
-    case BK_AUTO_ROLLER:
+    case BirthKind::AUTO_ROLLER:
         help_file = _("jbirth.txt#AutoRoller", "birth.txt#AutoRoller");
         break;
     default:
index 75bfa1b..0523296 100644 (file)
@@ -1,16 +1,16 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-enum birth_kind {
-    BK_REALM,
-    BK_RACE,
-    BK_CLASS,
-    BK_PERSONALITY,
-    BK_AUTO_ROLLER,
+enum class BirthKind {
+    REALM,
+    RACE,
+    CLASS,
+    PERSONALITY,
+    AUTO_ROLLER,
 };
 
 class PlayerType;
 void birth_quit(void);
 void show_help(PlayerType *player_ptr, concptr helpfile);
-void birth_help_option(PlayerType *player_ptr, char c, birth_kind bk);
+void birth_help_option(PlayerType *player_ptr, char c, BirthKind bk);
index dc37c96..ff8b02d 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/birth-wizard.h"
+#include "birth/birth-wizard.h"
 #include "avatar/avatar.h"
 #include "birth/auto-roller.h"
 #include "birth/birth-body-spec.h"
@@ -16,9 +16,9 @@
 #include "cmd-io/cmd-gameoption.h"
 #include "cmd-io/cmd-help.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "game-option/birth-options.h"
 #include "io/input-key-acceptor.h"
+#include "locale/japanese.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
 #include "player-base/player-class.h"
@@ -32,6 +32,7 @@
 #include "player/process-name.h"
 #include "system/game-option-types.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "term/z-form.h"
@@ -39,6 +40,7 @@
 #include "util/int-char-converter.h"
 #include "util/string-processor.h"
 #include "view/display-birth.h" // 暫定。後で消す予定。
+#include "view/display-player-misc-info.h"
 #include "view/display-player.h" // 暫定。後で消す.
 #include "view/display-util.h"
 #include "world/world.h"
 static void display_initial_birth_message(PlayerType *player_ptr)
 {
     term_clear();
-    put_str(_("名前  :", "Name  :"), 1, 26);
+    display_player_name(player_ptr, true);
     put_str(_("性別        :", "Sex         :"), 3, 1);
     put_str(_("種族        :", "Race        :"), 4, 1);
     put_str(_("職業        :", "Class       :"), 5, 1);
-    c_put_str(TERM_L_BLUE, player_ptr->name, 1, 34);
     put_str(_("キャラクターを作成します。('S'やり直す, 'Q'終了, '?'ヘルプ)", "Make your character. ('S' Restart, 'Q' Quit, '?' Help)"), 8, 10);
     put_str(_("注意:《性別》の違いはゲーム上ほとんど影響を及ぼしません。", "Note: Your 'sex' does not have any significant gameplay effects."), 23, 5);
 }
@@ -188,7 +189,7 @@ static bool let_player_select_race(PlayerType *player_ptr)
 
         clear_from(10);
         display_wrap_around(race_explanations[enum2i(player_ptr->prace)], 74, 12, 3);
-        if (get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y)) {
+        if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::DEFAULT_Y)) {
             break;
         }
 
@@ -211,7 +212,7 @@ static bool let_player_select_class(PlayerType *player_ptr)
         clear_from(10);
         display_wrap_around(class_explanations[enum2i(player_ptr->pclass)], 74, 12, 3);
 
-        if (get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y)) {
+        if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::DEFAULT_Y)) {
             break;
         }
 
@@ -232,12 +233,11 @@ static bool let_player_select_personality(PlayerType *player_ptr)
         clear_from(10);
         display_wrap_around(personality_explanations[player_ptr->ppersonality], 74, 12, 3);
 
-        if (get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y)) {
+        if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::DEFAULT_Y)) {
             break;
         }
 
-        c_put_str(TERM_L_BLUE, player_ptr->name, 1, 34);
-        prt("", 1, 34 + strlen(player_ptr->name));
+        display_player_name(player_ptr, true);
     }
 
     return true;
@@ -381,10 +381,12 @@ static bool decide_body_spec(PlayerType *player_ptr, chara_limit_type chara_limi
         if ((player_ptr->age < chara_limit.agemin) || (player_ptr->age > chara_limit.agemax)) {
             *accept = false;
         }
-        if ((player_ptr->ht < chara_limit.htmin) || (player_ptr->ht > chara_limit.htmax)) {
+        const auto ht = _(inch_to_cm(player_ptr->ht), player_ptr->ht);
+        if ((ht < chara_limit.htmin) || (ht > chara_limit.htmax)) {
             *accept = false;
         }
-        if ((player_ptr->wt < chara_limit.wtmin) || (player_ptr->wt > chara_limit.wtmax)) {
+        const auto wt = _(lb_to_kg(player_ptr->wt), player_ptr->wt);
+        if ((wt < chara_limit.wtmin) || (wt > chara_limit.wtmax)) {
             *accept = false;
         }
         if ((player_ptr->sc < chara_limit.scmin) || (player_ptr->sc > chara_limit.scmax)) {
@@ -438,8 +440,13 @@ static void exe_auto_roller(PlayerType *player_ptr, chara_limit_type chara_limit
 static bool display_auto_roller_result(PlayerType *player_ptr, bool prev, char *c)
 {
     BIT_FLAGS mode = 0;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+    };
     while (true) {
-        player_ptr->update |= (PU_BONUS | PU_HP);
+        rfu.set_flags(flags);
         update_creature(player_ptr);
         player_ptr->chp = player_ptr->mhp;
         player_ptr->csp = player_ptr->msp;
@@ -488,7 +495,7 @@ static bool display_auto_roller_result(PlayerType *player_ptr, bool prev, char *
             continue;
         }
 
-        birth_help_option(player_ptr, *c, BK_AUTO_ROLLER);
+        birth_help_option(player_ptr, *c, BirthKind::AUTO_ROLLER);
         bell();
     }
 
index 3f0ea95..1b85997 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool player_birth_wizard(PlayerType *player_ptr);
index bf0ffaa..24cc00a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file birth.c
  * @brief プレイヤーの作成を行う / Create a player character
  * @date 2013/12/28
@@ -37,6 +37,7 @@
 #include "store/store-owners.h"
 #include "store/store.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/z-form.h"
 #include "util/enum-converter.h"
@@ -57,29 +58,31 @@ static void write_birth_diary(PlayerType *player_ptr)
     message_add(" ");
     message_add("  ");
 
-    exe_write_diary(player_ptr, DIARY_GAMESTART, 1, _("-------- 新規ゲーム開始 --------", "------- Started New Game -------"));
-    exe_write_diary(player_ptr, DIARY_DIALY, 0, nullptr);
-    char buf[80];
-    strnfmt(buf, sizeof(buf), _("%s性別に%sを選択した。", "%schose %s gender."), indent, sex_info[player_ptr->psex].title);
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, buf);
-    strnfmt(buf, sizeof(buf), _("%s種族に%sを選択した。", "%schose %s race."), indent, race_info[enum2i(player_ptr->prace)].title);
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, buf);
-    strnfmt(buf, sizeof(buf), _("%s職業に%sを選択した。", "%schose %s class."), indent, class_info[enum2i(player_ptr->pclass)].title);
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, buf);
+    exe_write_diary(player_ptr, DiaryKind::GAMESTART, 1, _("-------- 新規ゲーム開始 --------", "------- Started New Game -------"));
+    exe_write_diary(player_ptr, DiaryKind::DIALY, 0);
+    const auto mes_sex = format(_("%s性別に%sを選択した。", "%schose %s gender."), indent, sex_info[player_ptr->psex].title);
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, mes_sex);
+    const auto mes_race = format(_("%s種族に%sを選択した。", "%schose %s race."), indent, race_info[enum2i(player_ptr->prace)].title);
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, mes_race);
+    const auto mes_class = format(_("%s職業に%sを選択した。", "%schose %s class."), indent, class_info[enum2i(player_ptr->pclass)].title);
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, mes_class);
     if (player_ptr->realm1) {
-        strnfmt(buf, sizeof(buf), _("%s魔法の領域に%s%sを選択した。", "%schose %s%s."), indent, realm_names[player_ptr->realm1],
-            player_ptr->realm2 ? format(_("と%s", " and %s realms"), realm_names[player_ptr->realm2]).data() : _("", " realm"));
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, buf);
+        const auto mes_realm2 = player_ptr->realm2 ? format(_("と%s", " and %s realms"), realm_names[player_ptr->realm2]) : _("", " realm");
+        const auto mes_realm = format(_("%s魔法の領域に%s%sを選択した。", "%schose %s%s."), indent, realm_names[player_ptr->realm1], mes_realm2.data());
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, mes_realm);
     }
+
     if (player_ptr->element) {
-        strnfmt(buf, sizeof(buf), _("%s元素系統に%sを選択した。", "%schose %s system."), indent, get_element_title(player_ptr->element));
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, buf);
+        const auto mes_element = format(_("%s元素系統に%sを選択した。", "%schose %s system."), indent, get_element_title(player_ptr->element));
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, mes_element);
     }
-    strnfmt(buf, sizeof(buf), _("%s性格に%sを選択した。", "%schose %s personality."), indent, personality_info[player_ptr->ppersonality].title);
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, buf);
+
+    const auto mes_personality = format(_("%s性格に%sを選択した。", "%schose %s personality."), indent, personality_info[player_ptr->ppersonality].title);
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, mes_personality);
     if (PlayerClass(player_ptr).equals(PlayerClassType::CHAOS_WARRIOR)) {
-        strnfmt(buf, sizeof(buf), _("%s守護神%sと契約を交わした。", "%smade a contract with patron %s."), indent, patron_list[player_ptr->chaos_patron].name.data());
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, buf);
+        const auto fmt_patron = _("%s守護神%sと契約を交わした。", "%smade a contract with patron %s.");
+        const auto mes_patron = format(fmt_patron, indent, patron_list[player_ptr->chaos_patron].name.data());
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, mes_patron);
     }
 }
 
@@ -121,11 +124,11 @@ void player_birth(PlayerType *player_ptr)
         player_ptr->hack_mutation = false;
     }
 
-    if (!window_flag[1]) {
-        window_flag[1] |= PW_MESSAGE;
+    if (g_window_flags[1].none()) {
+        g_window_flags[1].set(SubWindowRedrawingFlag::MESSAGE);
     }
 
-    if (!window_flag[2]) {
-        window_flag[2] |= PW_INVENTORY;
+    if (g_window_flags[2].none()) {
+        g_window_flags[2].set(SubWindowRedrawingFlag::INVENTORY);
     }
 }
index 451717d..25484c0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void player_birth(PlayerType *player_ptr);
index 1602a99..10100b8 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/game-play-initializer.h"
+#include "birth/game-play-initializer.h"
 #include "dungeon/quest.h"
 #include "floor/floor-util.h"
 #include "game-option/birth-options.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 #include "util/enum-range.h"
+#include "util/string-processor.h"
 #include "world/world.h"
+#include <algorithm>
+#include <string>
 
 /*!
  * @brief ベースアイテム構造体の鑑定済みフラグをリセットする。
@@ -45,11 +48,7 @@ static void reset_baseitem_idenditication_flags()
  */
 void player_wipe_without_name(PlayerType *player_ptr)
 {
-    auto tmp = *player_ptr;
-    if (player_ptr->last_message) {
-        string_free(player_ptr->last_message);
-    }
-
+    const std::string backup_name = player_ptr->name;
     *player_ptr = {};
 
     // TODO: キャラ作成からゲーム開始までに  current_floor_ptr を参照しなければならない処理は今後整理して外す。
@@ -88,9 +87,9 @@ void player_wipe_without_name(PlayerType *player_ptr)
             continue;
         }
         r_ref.cur_num = 0;
-        r_ref.max_num = 100;
+        r_ref.max_num = MAX_MONSTER_NUM;
         if (r_ref.kind_flags.has(MonsterKindType::UNIQUE)) {
-            r_ref.max_num = 1;
+            r_ref.max_num = MAX_UNIQUE_NUM;
         } else if (r_ref.population_flags.has(MonsterPopulationType::NAZGUL)) {
             r_ref.max_num = MAX_NAZGUL_NUM;
         }
@@ -148,10 +147,7 @@ void player_wipe_without_name(PlayerType *player_ptr)
 
     player_ptr->max_plv = player_ptr->lev = 1;
     player_ptr->arena_number = 0;
-    player_ptr->current_floor_ptr->inside_arena = false;
-    player_ptr->current_floor_ptr->quest_number = QuestId::NONE;
-
-    player_ptr->exit_bldg = true;
+    w_ptr->set_arena(true);
     player_ptr->knows_daily_bounty = false;
     update_gambling_monsters(player_ptr);
     player_ptr->muta.clear();
@@ -160,24 +156,13 @@ void player_wipe_without_name(PlayerType *player_ptr)
         player_ptr->virtues[i] = 0;
     }
 
-    player_ptr->dungeon_idx = 0;
     if (vanilla_town || ironman_downward) {
         player_ptr->recall_dungeon = DUNGEON_ANGBAND;
     } else {
         player_ptr->recall_dungeon = DUNGEON_GALGALS;
     }
 
-    memcpy(player_ptr->name, tmp.name, sizeof(tmp.name));
-
-#ifdef SET_UID
-    player_ptr->player_uid = tmp.player_uid;
-#ifdef SAFE_SETUID
-#ifdef SAFE_SETUID_POSIX
-    player_ptr->player_euid = tmp.player_euid;
-    player_ptr->player_egid = tmp.player_egid;
-#endif
-#endif
-#endif
+    std::copy_n(backup_name.begin(), backup_name.length(), player_ptr->name);
 }
 
 /*!
index ff36144..ed8caf6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void player_wipe_without_name(PlayerType *player_ptr);
index b85c159..e2b4d29 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/history-editor.h"
+#include "birth/history-editor.h"
 #include "io/input-key-acceptor.h"
 #include "io/read-pref-file.h"
 #include "locale/japanese.h"
@@ -110,15 +110,15 @@ void edit_history(PlayerType *player_ptr)
             }
 #endif
         } else if (c == '\r' || c == '\n') {
-            term_erase(0, 11, 255);
-            term_erase(0, 17, 255);
+            term_erase(0, 11);
+            term_erase(0, 17);
             put_str(_("(キャラクターの生い立ち - 編集済み)", "(Character Background - Edited)"), 11, 20);
             break;
         } else if (c == ESCAPE) {
             clear_from(11);
             put_str(_("(キャラクターの生い立ち)", "(Character Background)"), 11, 25);
             for (int i = 0; i < 4; i++) {
-                angband_strcpy(player_ptr->history[i], old_history[i].data(), sizeof(player_ptr->history[i]));
+                angband_strcpy(player_ptr->history[i], old_history[i], sizeof(player_ptr->history[i]));
                 put_str(player_ptr->history[i], i + 12, 10);
             }
 
index 0d7ce7e..336ca01 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void edit_history(PlayerType *player_ptr);
index 0e320f5..65b8e36 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/history-generator.h"
+#include "birth/history-generator.h"
 #include "birth/history.h"
 #include "player-info/race-types.h"
 #include "system/player-type-definition.h"
@@ -136,6 +136,6 @@ void get_history(PlayerType *player_ptr)
     const auto history_lines = shape_buffer(social_class.data(), max_line_len);
     const auto max_lines = std::min<int>(lines, history_lines.size());
     for (auto i = 0; i < max_lines; ++i) {
-        angband_strcpy(player_ptr->history[i], history_lines[i].data(), max_line_len);
+        angband_strcpy(player_ptr->history[i], history_lines[i], max_line_len);
     }
 }
index b843996..59df81e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void get_history(PlayerType *player_ptr);
index aac3811..3eaef0a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 生い立ちメッセージテーブル / Forward declare
  * @date 2002/01/12
  * @author mogami
index 8edc526..f72745a 100644 (file)
@@ -1,4 +1,4 @@
-#include "system/angband.h"
+#include "system/angband.h"
 #include <vector>
 
 /*!
index db13fb7..563d1f2 100644 (file)
@@ -1,4 +1,4 @@
-#include "birth/initial-equipments-table.h"
+#include "birth/initial-equipments-table.h"
 #include "object/tval-types.h"
 #include "sv-definition/sv-armor-types.h"
 #include "sv-definition/sv-bow-types.h"
index 663e1a2..a7bf4b9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <tuple>
index 9b04274..b5d832b 100644 (file)
@@ -1,9 +1,10 @@
-#include "birth/inventory-initializer.h"
+#include "birth/inventory-initializer.h"
 #include "autopick/autopick.h"
 #include "birth/initial-equipments-table.h"
 #include "floor/floor-object.h"
 #include "inventory/inventory-object.h"
 #include "inventory/inventory-slot-types.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster/monster-list.h"
 #include "monster/monster-util.h"
@@ -40,9 +41,9 @@
 void wield_all(PlayerType *player_ptr)
 {
     ItemEntity ObjectType_body;
-    for (INVENTORY_IDX item = INVEN_PACK - 1; item >= 0; item--) {
+    for (INVENTORY_IDX i_idx = INVEN_PACK - 1; i_idx >= 0; i_idx--) {
         ItemEntity *o_ptr;
-        o_ptr = &player_ptr->inventory_list[item];
+        o_ptr = &player_ptr->inventory_list[i_idx];
         if (!o_ptr->is_valid()) {
             continue;
         }
@@ -63,12 +64,12 @@ void wield_all(PlayerType *player_ptr)
         i_ptr->copy_from(o_ptr);
         i_ptr->number = 1;
 
-        if (item >= 0) {
-            inven_item_increase(player_ptr, item, -1);
-            inven_item_optimize(player_ptr, item);
+        if (i_idx >= 0) {
+            inven_item_increase(player_ptr, i_idx, -1);
+            inven_item_optimize(player_ptr, i_idx);
         } else {
-            floor_item_increase(player_ptr, 0 - item, -1);
-            floor_item_optimize(player_ptr, 0 - item);
+            floor_item_increase(player_ptr, 0 - i_idx, -1);
+            floor_item_optimize(player_ptr, 0 - i_idx);
         }
 
         o_ptr = &player_ptr->inventory_list[slot];
@@ -85,7 +86,7 @@ void wield_all(PlayerType *player_ptr)
 void add_outfit(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
     object_aware(player_ptr, o_ptr);
-    object_known(o_ptr);
+    o_ptr->mark_as_known();
     int16_t slot = store_item_to_inventory(player_ptr, o_ptr);
     autopick_alter_item(player_ptr, slot, false);
     wield_all(player_ptr);
@@ -103,7 +104,7 @@ static void decide_initial_items(PlayerType *player_ptr, ItemEntity *q_ptr)
         get_mon_num_prep(player_ptr, monster_hook_human, nullptr);
         for (int i = rand_range(3, 4); i > 0; i--) {
             q_ptr->prep(lookup_baseitem_id({ ItemKindType::CORPSE, SV_CORPSE }));
-            q_ptr->pval = enum2i(get_mon_num(player_ptr, 0, 2, 0));
+            q_ptr->pval = enum2i(get_mon_num(player_ptr, 0, 2, PM_NONE));
             if (q_ptr->pval) {
                 q_ptr->number = 1;
                 add_outfit(player_ptr, q_ptr);
index 4995f78..49aba40 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index 035b147..45e0978 100644 (file)
@@ -1,8 +1,7 @@
-#include "birth/quick-start.h"
+#include "birth/quick-start.h"
 #include "birth/birth-stat.h"
 #include "birth/birth-util.h"
 #include "birth/game-play-initializer.h"
-#include "core/player-update-types.h"
 #include "io/input-key-acceptor.h"
 #include "player-base/player-class.h"
 #include "player-info/class-info.h"
@@ -13,6 +12,7 @@
 #include "player/process-name.h"
 #include "player/race-info-table.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "util/enum-converter.h"
 
@@ -64,7 +64,11 @@ bool ask_quick_start(PlayerType *player_ptr)
     ap_ptr = &personality_info[player_ptr->ppersonality];
 
     get_extra(player_ptr, false);
-    player_ptr->update |= (PU_BONUS | PU_HP);
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     update_creature(player_ptr);
     player_ptr->chp = player_ptr->mhp;
     player_ptr->csp = player_ptr->msp;
index 8370c9b..0e3cff2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-info/class-types.h"
 #include "player-info/race-types.h"
@@ -26,8 +26,8 @@ struct birther {
 
     PRICE au{}; /*!< 初期の所持金 */
 
-    BASE_STATUS stat_max[6]{}; /* Current "maximal" stat values */
-    BASE_STATUS stat_max_max[6]{}; /* Maximal "maximal" stat values */
+    short stat_max[6]{}; /* Current "maximal" stat values */
+    short stat_max_max[6]{}; /* Maximal "maximal" stat values */
     int player_hp[PY_MAX_LEVEL]{};
 
     int16_t chaos_patron{}; /*! カオスパトロンのID */
index 88aa130..a7a59da 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file blue-magic-ball-bolt.cpp
  * @brief 青魔法のボール/ボルト系呪文定義
  */
@@ -188,6 +188,18 @@ bool cast_blue_ball_abyss(PlayerType *player_ptr, bmc_type *bmc_ptr)
     return true;
 }
 
+bool cast_blue_ball_meteor(PlayerType *player_ptr, bmc_type *bmc_ptr)
+{
+    if (!get_aim_dir(player_ptr, &bmc_ptr->dir)) {
+        return false;
+    }
+
+    msg_print(_("メテオスウォームの呪文を念じた。", "You invoke a meteor swarm."));
+    bmc_ptr->damage = monspell_bluemage_damage(player_ptr, MonsterAbilityType::BA_METEOR, bmc_ptr->plev, DAM_ROLL);
+    fire_ball(player_ptr, AttributeType::METEOR, bmc_ptr->dir, bmc_ptr->damage, 4);
+    return true;
+}
+
 bool cast_blue_bolt_acid(PlayerType *player_ptr, bmc_type *bmc_ptr)
 {
     if (!get_aim_dir(player_ptr, &bmc_ptr->dir)) {
@@ -331,3 +343,26 @@ bool cast_blue_bolt_void(PlayerType *player_ptr, bmc_type *bmc_ptr)
     fire_bolt(player_ptr, AttributeType::VOID_MAGIC, bmc_ptr->dir, bmc_ptr->damage);
     return true;
 }
+
+bool cast_blue_bolt_meteor(PlayerType *player_ptr, bmc_type *bmc_ptr)
+{
+    if (!get_aim_dir(player_ptr, &bmc_ptr->dir)) {
+        return false;
+    }
+
+    msg_print(_("メテオストライクの呪文を唱えた。", "You cast a meteor strike."));
+    bmc_ptr->damage = monspell_bluemage_damage(player_ptr, MonsterAbilityType::BO_METEOR, bmc_ptr->plev, DAM_ROLL);
+    fire_bolt(player_ptr, AttributeType::METEOR, bmc_ptr->dir, bmc_ptr->damage);
+    return true;
+}
+bool cast_blue_bolt_lite(PlayerType *player_ptr, bmc_type *bmc_ptr)
+{
+    if (!get_aim_dir(player_ptr, &bmc_ptr->dir)) {
+        return false;
+    }
+
+    msg_print(_("スターライトアローの呪文を唱えた。", "You cast a starlight arrow."));
+    bmc_ptr->damage = monspell_bluemage_damage(player_ptr, MonsterAbilityType::BO_LITE, bmc_ptr->plev, DAM_ROLL);
+    fire_bolt(player_ptr, AttributeType::LITE, bmc_ptr->dir, bmc_ptr->damage);
+    return true;
+}
index 03e75a3..e5bfbd0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file blue-magic-ball-bolt.h
  * @brief 青魔法のボール/ボルト系呪文ヘッダ
@@ -20,6 +20,7 @@ bool cast_blue_ball_dark_storm(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_ball_mana_storm(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_ball_void(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_ball_abyss(PlayerType *player_ptr, bmc_type *bmc_ptr);
+bool cast_blue_ball_meteor(PlayerType *player_ptr, bmc_type *bmc_ptr);
 
 bool cast_blue_bolt_acid(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_bolt_elec(PlayerType *player_ptr, bmc_type *bmc_ptr);
@@ -32,4 +33,6 @@ bool cast_blue_bolt_plasma(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_bolt_icee(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_bolt_void(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_bolt_abyss(PlayerType *player_ptr, bmc_type *bmc_ptr);
+bool cast_blue_bolt_meteor(PlayerType *player_ptr, bmc_type *bmc_ptr);
+bool cast_blue_bolt_lite(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_bolt_missile(PlayerType *player_ptr, bmc_type *bmc_ptr);
index a190d80..0b76ea0 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file blue-magic-breath.cpp
  * @brief 青魔法のブレス系呪文定義
  */
index ed3271c..90351d9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file blue-magic-breath.h
  * @brief 青魔法のブレス系呪文ヘッダ
index d6e13b3..c13afda 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file blue-magic-caster.cpp
  * @brief 青魔法のその他系統の呪文定義と詠唱時分岐処理
  */
@@ -11,7 +11,6 @@
 #include "blue-magic/blue-magic-summon.h"
 #include "blue-magic/blue-magic-util.h"
 #include "blue-magic/learnt-info.h"
-#include "floor/cave.h"
 #include "hpmp/hp-mp-processor.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-ability-flags.h"
@@ -49,8 +48,10 @@ static bool cast_blue_dispel(PlayerType *player_ptr)
         return false;
     }
 
-    MONSTER_IDX m_idx = player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx;
-    if ((m_idx == 0) || !player_has_los_bold(player_ptr, target_row, target_col) || !projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
+    const Pos2D pos(target_row, target_col);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto m_idx = grid.m_idx;
+    if ((m_idx == 0) || !grid.has_los() || !projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
         return true;
     }
 
@@ -96,35 +97,35 @@ static bool cast_blue_hand_doom(PlayerType *player_ptr, bmc_type *bmc_ptr)
 /* 効果が抵抗された場合、返される std::optional には値がありません。*/
 static std::optional<std::string> exe_blue_teleport_back(PlayerType *player_ptr)
 {
-    MonsterEntity *m_ptr;
-    MonsterRaceInfo *r_ptr;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((floor_ptr->grid_array[target_row][target_col].m_idx == 0) || !player_has_los_bold(player_ptr, target_row, target_col) || !projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(target_row, target_col);
+    const auto &grid = floor.get_grid(pos);
+    if ((grid.m_idx == 0) || !grid.has_los() || !projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
         return std::nullopt;
     }
 
-    m_ptr = &floor_ptr->m_list[floor_ptr->grid_array[target_row][target_col].m_idx];
-    r_ptr = &monraces_info[m_ptr->r_idx];
+    const auto *m_ptr = &floor.m_list[grid.m_idx];
+    auto &monrace = m_ptr->get_monrace();
     auto m_name = monster_desc(player_ptr, m_ptr, 0);
-    if (r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_TELEPORT)) {
+    if (monrace.resistance_flags.has_not(MonsterResistanceType::RESIST_TELEPORT)) {
         return m_name;
     }
 
-    if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
+    if (monrace.kind_flags.has(MonsterKindType::UNIQUE) || monrace.resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
         if (is_original_ap_and_seen(player_ptr, m_ptr)) {
-            r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
+            monrace.r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
         }
 
         msg_format(_("%sには効果がなかった!", "%s is unaffected!"), m_name.data());
         return std::nullopt;
     }
 
-    if (r_ptr->level <= randint1(100)) {
+    if (monrace.level <= randint1(100)) {
         return m_name;
     }
 
     if (is_original_ap_and_seen(player_ptr, m_ptr)) {
-        r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
+        monrace.r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
     }
 
     msg_format(_("%sには耐性がある!", "%s resists!"), m_name.data());
@@ -138,7 +139,7 @@ static bool cast_blue_teleport_back(PlayerType *player_ptr)
     }
 
     const auto m_name = exe_blue_teleport_back(player_ptr);
-    if (!m_name.has_value()) {
+    if (!m_name) {
         return true;
     }
 
@@ -275,6 +276,8 @@ static bool switch_cast_blue_magic(PlayerType *player_ptr, bmc_type *bmc_ptr, Mo
         return cast_blue_ball_void(player_ptr, bmc_ptr);
     case MonsterAbilityType::BA_ABYSS:
         return cast_blue_ball_abyss(player_ptr, bmc_ptr);
+    case MonsterAbilityType::BA_METEOR:
+        return cast_blue_ball_meteor(player_ptr, bmc_ptr);
     case MonsterAbilityType::DRAIN_MANA:
         return cast_blue_drain_mana(player_ptr, bmc_ptr);
     case MonsterAbilityType::MIND_BLAST:
@@ -311,6 +314,10 @@ static bool switch_cast_blue_magic(PlayerType *player_ptr, bmc_type *bmc_ptr, Mo
         return cast_blue_bolt_abyss(player_ptr, bmc_ptr);
     case MonsterAbilityType::BO_VOID:
         return cast_blue_bolt_void(player_ptr, bmc_ptr);
+    case MonsterAbilityType::BO_METEOR:
+        return cast_blue_bolt_meteor(player_ptr, bmc_ptr);
+    case MonsterAbilityType::BO_LITE:
+        return cast_blue_bolt_lite(player_ptr, bmc_ptr);
     case MonsterAbilityType::MISSILE:
         return cast_blue_bolt_missile(player_ptr, bmc_ptr);
     case MonsterAbilityType::SCARE:
@@ -404,6 +411,8 @@ static bool switch_cast_blue_magic(PlayerType *player_ptr, bmc_type *bmc_ptr, Mo
         return cast_blue_summon_amberite(player_ptr, bmc_ptr);
     case MonsterAbilityType::S_UNIQUE:
         return cast_blue_summon_unique(player_ptr, bmc_ptr);
+    case MonsterAbilityType::S_DEAD_UNIQUE:
+        return cast_blue_summon_dead_unique(player_ptr, bmc_ptr);
     default:
         msg_print("hoge?");
         return true;
index cff0d0c..7556575 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file blue-magic-caster.h
  * @brief 青魔法のその他系統の呪文定義と詠唱時分岐処理ヘッダ
index 20fcdec..f2ec72c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file blue-magic-checker.cpp
  * @brief 青魔法の処理実装 / Blue magic
  * @date 2014/01/15
@@ -11,7 +11,6 @@
  */
 
 #include "blue-magic/blue-magic-checker.h"
-#include "core/player-redraw-types.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
 #include "monster-race/race-ability-mask.h"
@@ -22,6 +21,7 @@
 #include "status/experience.h"
 #include "system/angband.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/player-confusion.h"
 #include "timed-effect/player-hallucination.h"
@@ -62,7 +62,7 @@ void learn_spell(PlayerType *player_ptr, MonsterAbilityType monspell)
         gain_exp(player_ptr, monster_power.level * monster_power.smana);
         sound(SOUND_STUDY);
         bluemage_data->new_magic_learned = true;
-        player_ptr->redraw |= PR_ACTION;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
     }
 }
 
index 61e60dc..6ea9263 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file blue-magic-checker.h
  * @brief 青魔法の処理ヘッダ / Blue magic
index a763531..c477b22 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file blue-magic-spirit-curse.cpp
  * @brief 青魔法の呪い系処理定義
  */
index f3e6516..3bd8f88 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file blue-magic-spirit-curse.h
  * @brief 青魔法の呪い系処理ヘッダ
index 59d42d1..c2e09bf 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file blue-magic-status.cpp
  * @brief 青魔法の状態異常系スペル定義
  */
index c3ca2d8..ef2f82a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file blue-magic-status.h
  * @brief 青魔法の状態異常系スペルヘッダ
index f23adb7..9daddcf 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file blue-magic-summon.cpp
  * @brief 青魔法の召喚系スペル定義
  */
@@ -271,3 +271,19 @@ bool cast_blue_summon_unique(PlayerType *player_ptr, bmc_type *bmc_ptr)
 
     return true;
 }
+
+bool cast_blue_summon_dead_unique(PlayerType *player_ptr, bmc_type *bmc_ptr)
+{
+    BIT_FLAGS mode = bmc_ptr->g_mode | bmc_ptr->p_mode | PM_ALLOW_UNIQUE | PM_CLONE;
+
+    msg_print(_("特別な強敵を蘇らせた!", "You summon a special dead opponent!"));
+    if (summon_specific(player_ptr, (bmc_ptr->pet ? -1 : 0), player_ptr->y, player_ptr->x, bmc_ptr->summon_lev, SUMMON_DEAD_UNIQUE, mode)) {
+        if (!bmc_ptr->pet) {
+            msg_print(_("蘇生されたユニーク・モンスターは怒っている!", "The summoned special dead opponent is angry!"));
+        }
+    } else {
+        bmc_ptr->no_trump = true;
+    }
+
+    return true;
+}
index 79d90b2..321ae57 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file blue-magic-summon.h
  * @brief 青魔法の召喚系スペルヘッダ
@@ -22,3 +22,4 @@ bool cast_blue_summon_high_undead(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_summon_high_dragon(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_summon_amberite(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_summon_unique(PlayerType *player_ptr, bmc_type *bmc_ptr);
+bool cast_blue_summon_dead_unique(PlayerType *player_ptr, bmc_type *bmc_ptr);
index 61c97f0..9346cb5 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file blue-magic-util.cpp
  * @brief 青魔法の構造体、初期化処理定義
  */
index 527e93b..9f760e1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file blue-magic-util.h
  * @brief 青魔法の構造体、初期化処理ヘッダ
index 5bc20c5..ae8b906 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file learnt-info.cpp
  * @brief 青魔法の情報表示処理定義
  */
@@ -91,6 +91,7 @@ std::string learnt_info(PlayerType *player_ptr, MonsterAbilityType power)
     case MonsterAbilityType::BA_WATE:
     case MonsterAbilityType::BA_VOID:
     case MonsterAbilityType::BA_ABYSS:
+    case MonsterAbilityType::BA_METEOR:
         return set_bluemage_damage(player_ptr, power, plev, KWD_DAM);
     case MonsterAbilityType::DRAIN_MANA:
         return set_bluemage_damage(player_ptr, power, plev, KWD_HEAL);
@@ -111,6 +112,8 @@ std::string learnt_info(PlayerType *player_ptr, MonsterAbilityType power)
     case MonsterAbilityType::BO_ABYSS:
     case MonsterAbilityType::BO_VOID:
     case MonsterAbilityType::BO_ICEE:
+    case MonsterAbilityType::BO_METEOR:
+    case MonsterAbilityType::BO_LITE:
     case MonsterAbilityType::MISSILE:
         return set_bluemage_damage(player_ptr, power, plev, KWD_DAM);
     case MonsterAbilityType::HASTE:
index 66a8755..f119036 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file learnt-info.h
  * @brief 青魔法の情報表示処理ヘッダ
index a87caef..21cdcc3 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file learnt-power-getter.cpp
  * @brief 青魔法の処理実行定義
  */
@@ -23,6 +23,7 @@
 #include "realm/realm-types.h"
 #include "spell/spell-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-stun.h"
 #include "timed-effect/timed-effects.h"
@@ -31,7 +32,6 @@
 #include "util/int-char-converter.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
-
 #include <algorithm>
 #include <iterator>
 #include <optional>
@@ -69,7 +69,7 @@ static std::optional<BlueMagicType> select_blue_magic_type_by_menu()
 
     screen_save();
 
-    while (!type.has_value()) {
+    while (!type) {
         prt(format(_(" %s ボルト", " %s bolt"), (menu_line == 1) ? _("》", "> ") : "  "), 2, 14);
         prt(format(_(" %s ボール", " %s ball"), (menu_line == 2) ? _("》", "> ") : "  "), 3, 14);
         prt(format(_(" %s ブレス", " %s breath"), (menu_line == 3) ? _("》", "> ") : "  "), 4, 14);
@@ -120,15 +120,15 @@ static std::optional<BlueMagicType> select_blue_magic_type_by_menu()
  */
 static std::optional<BlueMagicType> select_blue_magic_kind_by_symbol()
 {
-    auto candidate_desc = _("[A]ボルト, [B]ボール, [C]ブレス, [D]召喚, [E]その他:", "[A] bolt, [B] ball, [C] breath, [D] summoning, [E] others:");
-
+    constexpr auto candidate_desc = _("[A]ボルト, [B]ボール, [C]ブレス, [D]召喚, [E]その他:",
+        "[A] bolt, [B] ball, [C] breath, [D] summoning, [E] others:");
     while (true) {
-        char ch;
-        if (!get_com(candidate_desc, &ch, true)) {
+        const auto command = input_command(candidate_desc, true);
+        if (!command) {
             return std::nullopt;
         }
 
-        switch (ch) {
+        switch (*command) {
         case 'A':
         case 'a':
             return BlueMagicType::BOLT;
@@ -185,7 +185,7 @@ static std::optional<std::vector<MonsterAbilityType>> sweep_learnt_spells(const
  * @param blue_magics 青魔法のリスト(覚えていないものも含まれているが、カーソル移動時に選択をスキップする)
  * @return 選択確定キーが入力された場合は true、そうでなければ false
  */
-static bool switch_blue_magic_choice(char key, int &menu_line, const bluemage_data_type &bluemage_data, const std::vector<MonsterAbilityType> blue_magics)
+static bool switch_blue_magic_choice(const char key, int &menu_line, const bluemage_data_type &bluemage_data, const std::vector<MonsterAbilityType> blue_magics)
 {
     const auto &learnt_blue_magics = bluemage_data.learnt_blue_magics;
     const int blue_magics_count = blue_magics.size();
@@ -349,7 +349,7 @@ static bool confirm_cast_blue_magic(MonsterAbilityType spell)
 {
     char tmp_val[160];
     (void)strnfmt(tmp_val, 78, _("%sの魔法を唱えますか?", "Use %s? "), monster_powers.at(spell).name);
-    return get_check(tmp_val);
+    return input_check(tmp_val);
 }
 
 /*!
@@ -361,18 +361,22 @@ static bool confirm_cast_blue_magic(MonsterAbilityType spell)
  */
 static std::optional<MonsterAbilityType> select_learnt_spells_by_symbol(PlayerType *player_ptr, const bluemage_data_type &bluemage_data, std::vector<MonsterAbilityType> spells)
 {
-    char out_val[80];
-    (void)strnfmt(out_val, sizeof(out_val), _("(%c-%c, '*'で一覧, ESC) どの%sを唱えますか?", "(%c-%c, *=List, ESC=exit) Use which %s? "),
-        I2A(0), I2A(spells.size() - 1), _("魔法", "magic"));
+    constexpr auto fmt = _("(%c-%c, '*'で一覧, ESC) どの%sを唱えますか?", "(%c-%c, *=List, ESC=exit) Use which %s? ");
+    const auto prompt = format(fmt, I2A(0), I2A(spells.size() - 1), _("魔法", "magic"));
 
     bool first_show_list = always_show_list;
     auto show_list = false;
     std::optional<MonsterAbilityType> selected_spell;
 
-    while (!selected_spell.has_value()) {
-        char choice = 0;
-        if (!first_show_list && !get_com(out_val, &choice, true)) {
-            break;
+    while (!selected_spell) {
+        auto choice = '\0';
+        if (!first_show_list) {
+            const auto choice_opt = input_command(prompt, true);
+            if (!choice_opt) {
+                break;
+            }
+
+            choice = *choice_opt;
         }
 
         if (first_show_list || (choice == ' ') || (choice == '*') || (choice == '?')) {
@@ -385,6 +389,7 @@ static std::optional<MonsterAbilityType> select_learnt_spells_by_symbol(PlayerTy
             } else {
                 screen_load();
             }
+
             continue;
         }
 
@@ -418,24 +423,28 @@ static std::optional<MonsterAbilityType> select_learnt_spells_by_symbol(PlayerTy
  */
 static std::optional<MonsterAbilityType> select_learnt_spells_by_menu(PlayerType *player_ptr, const bluemage_data_type &bluemage_data, std::vector<MonsterAbilityType> spells)
 {
-    char out_val[80];
-    angband_strcpy(out_val, _("(ESC=中断) どの魔法を唱えますか?", "(ESC=exit) Use which magic? "), sizeof(out_val));
+    constexpr auto prompt = _("(ESC=中断) どの魔法を唱えますか?", "(ESC=exit) Use which magic? ");
 
-    auto it = std::find_if(spells.begin(), spells.end(), [&bluemage_data](const auto &spell) { return bluemage_data.learnt_blue_magics.has(spell); });
+    auto it = std::find_if(
+        spells.begin(), spells.end(), [&bluemage_data](const auto &spell) { return bluemage_data.learnt_blue_magics.has(spell); });
     int menu_line = std::distance(spells.begin(), it) + 1;
     std::optional<MonsterAbilityType> selected_spell;
 
     screen_save();
 
-    while (!selected_spell.has_value()) {
+    while (!selected_spell) {
         describe_blue_magic_name(player_ptr, menu_line, bluemage_data, spells);
 
-        char choice;
-        if (!get_com(out_val, &choice, true) || choice == '0') {
+        const auto choice = input_command(prompt, true);
+        if (!choice) {
+            break;
+        }
+
+        if (choice == '0') {
             break;
         }
 
-        if (!switch_blue_magic_choice(choice, menu_line, bluemage_data, spells)) {
+        if (!switch_blue_magic_choice(*choice, menu_line, bluemage_data, spells)) {
             continue;
         }
 
@@ -479,33 +488,33 @@ std::optional<MonsterAbilityType> get_learned_power(PlayerType *player_ptr)
     }
 
     if (auto repeat_spell = check_blue_magic_repeat();
-        repeat_spell.has_value()) {
+        repeat_spell) {
         return repeat_spell;
     }
 
     auto type = (use_menu)
                     ? select_blue_magic_type_by_menu()
                     : select_blue_magic_kind_by_symbol();
-    if (!type.has_value()) {
+    if (!type) {
         return std::nullopt;
     }
 
-    auto spells = sweep_learnt_spells(*bluemage_data, type.value());
-    if (!spells.has_value() || spells->empty()) {
+    auto spells = sweep_learnt_spells(*bluemage_data, *type);
+    if (!spells || spells->empty()) {
         return std::nullopt;
     }
 
     auto selected_spell = (use_menu)
-                              ? select_learnt_spells_by_menu(player_ptr, *bluemage_data, spells.value())
-                              : select_learnt_spells_by_symbol(player_ptr, *bluemage_data, spells.value());
+                              ? select_learnt_spells_by_menu(player_ptr, *bluemage_data, *spells)
+                              : select_learnt_spells_by_symbol(player_ptr, *bluemage_data, *spells);
 
-    player_ptr->window_flags |= PW_SPELL;
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::SPELL);
     handle_stuff(player_ptr);
 
-    if (!selected_spell.has_value()) {
+    if (!selected_spell) {
         return std::nullopt;
     }
 
-    repeat_push(static_cast<COMMAND_CODE>(selected_spell.value()));
+    repeat_push(static_cast<COMMAND_CODE>(*selected_spell));
     return selected_spell;
 }
index c3049a3..f3a093a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file learnt-power-getter.h
  * @brief 青魔法の処理実行ヘッダ
index 7aac9e2..88d8c3d 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 攻撃コマンド処理
  * @date 2020/05/23
  * @author Hourier
@@ -11,7 +11,6 @@
 #include "combat/attack-criticality.h"
 #include "core/asking-player.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "effect/effect-characteristics.h"
@@ -72,7 +71,7 @@ static void natural_attack(PlayerType *player_ptr, MONSTER_IDX m_idx, PlayerMuta
 {
     WEIGHT n_weight = 0;
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     int dice_num, dice_side;
     concptr atk_desc;
@@ -152,7 +151,7 @@ static void natural_attack(PlayerType *player_ptr, MONSTER_IDX m_idx, PlayerMuta
     case PlayerMutationType::TENTACLES:
     default: {
         MonsterDamageProcessor mdp(player_ptr, m_idx, k, fear, AttributeType::ATTACK);
-        *mdeath = mdp.mon_take_hit(nullptr);
+        *mdeath = mdp.mon_take_hit("");
         break;
     }
     }
@@ -171,11 +170,18 @@ static void natural_attack(PlayerType *player_ptr, MONSTER_IDX m_idx, PlayerMuta
  */
 bool do_cmd_attack(PlayerType *player_ptr, POSITION y, POSITION x, combat_options mode)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-
-    const std::initializer_list<PlayerMutationType> mutation_attack_methods = { PlayerMutationType::HORNS, PlayerMutationType::BEAK, PlayerMutationType::SCOR_TAIL, PlayerMutationType::TRUNK, PlayerMutationType::TENTACLES };
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto *g_ptr = &floor.grid_array[y][x];
+    auto *m_ptr = &floor.m_list[g_ptr->m_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
+
+    const auto mutation_attack_methods = {
+        PlayerMutationType::HORNS,
+        PlayerMutationType::BEAK,
+        PlayerMutationType::SCOR_TAIL,
+        PlayerMutationType::TRUNK,
+        PlayerMutationType::TENTACLES,
+    };
 
     disturb(player_ptr, false, true);
 
@@ -200,7 +206,7 @@ bool do_cmd_attack(PlayerType *player_ptr, POSITION y, POSITION x, combat_option
 
     auto is_confused = effects->confusion()->is_confused();
     auto is_stunned = effects->stun()->is_stunned();
-    if (any_bits(r_ptr->flags1, RF1_FEMALE) && !(is_stunned || is_confused || is_hallucinated || !m_ptr->ml)) {
+    if (is_female(*r_ptr) && !(is_stunned || is_confused || is_hallucinated || !m_ptr->ml)) {
         // @todo 「特定の武器を装備している」旨のメソッドを別途作る
         constexpr auto zantetsu = FixedArtifactId::ZANTETSU;
         const auto is_main_hand_zantetsu = player_ptr->inventory_list[INVEN_MAIN_HAND].is_specific_artifact(zantetsu);
@@ -212,7 +218,7 @@ bool do_cmd_attack(PlayerType *player_ptr, POSITION y, POSITION x, combat_option
         }
     }
 
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::NO_MELEE)) {
         sound(SOUND_ATTACK_FAILED);
         msg_print(_("なぜか攻撃することができない。", "Something prevents you from attacking."));
         return false;
@@ -236,7 +242,7 @@ bool do_cmd_attack(PlayerType *player_ptr, POSITION y, POSITION x, combat_option
             chg_virtue(player_ptr, Virtue::JUSTICE, -1);
             chg_virtue(player_ptr, Virtue::COMPASSION, -1);
         } else if (!PlayerClass(player_ptr).equals(PlayerClassType::BERSERKER)) {
-            if (get_check(_("本当に攻撃しますか?", "Really hit it? "))) {
+            if (input_check(_("本当に攻撃しますか?", "Really hit it? "))) {
                 chg_virtue(player_ptr, Virtue::INDIVIDUALISM, 1);
                 chg_virtue(player_ptr, Virtue::HONOUR, -1);
                 chg_virtue(player_ptr, Virtue::JUSTICE, -1);
index 62fdd66..a03ea54 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "combat/combat-options-type.h"
 #include "system/angband.h"
index e6823ec..c042ee0 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 剣術の実装 / Blade arts
  * @date 2014/01/17
  * @author
@@ -12,8 +12,6 @@
 #include "action/action-limited.h"
 #include "cmd-action/cmd-spell.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "floor/floor-object.h"
@@ -38,6 +36,7 @@
 #include "status/action-setter.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/int-char-converter.h"
  */
 static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
 {
-    SPELL_IDX i;
     int j = 0;
     int num = 0;
     POSITION y = 1;
     POSITION x = 15;
     PLAYER_LEVEL plev = player_ptr->lev;
     char choice;
-    char out_val[160];
-    SPELL_IDX sentaku[32];
     concptr p = _("必殺剣", "special attack");
     COMMAND_CODE code;
     magic_type spell;
-    bool flag, redraw;
     int menu_line = (use_menu ? 1 : 0);
 
     /* Assume cancelled */
@@ -92,19 +87,20 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
         }
     }
 
-    flag = false;
-    redraw = false;
+    auto flag = false;
+    auto redraw = false;
 
+    int i;
+    int selections[32]{};
     for (i = 0; i < 32; i++) {
         if (technic_info[TECHNIC_HISSATSU][i].slevel <= PY_MAX_LEVEL) {
-            sentaku[num] = i;
+            selections[num] = i;
             num++;
         }
     }
 
-    /* Build a prompt (accept all spells) */
-    (void)strnfmt(out_val, 78, _("(%s^ %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? "), p, I2A(0),
-        "abcdefghijklmnopqrstuvwxyz012345"[num - 1], p);
+    constexpr auto fmt = _("(%s^ %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? ");
+    const auto prompt = format(fmt, p, I2A(0), "abcdefghijklmnopqrstuvwxyz012345"[num - 1], p);
 
     if (use_menu) {
         screen_save();
@@ -114,8 +110,13 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
     while (!flag) {
         if (choice == ESCAPE) {
             choice = ' ';
-        } else if (!get_com(out_val, &choice, false)) {
-            break;
+        } else {
+            const auto new_choice = input_command(prompt);
+            if (!new_choice) {
+                break;
+            }
+
+            choice = *new_choice;
         }
 
         auto should_redraw_cursor = true;
@@ -271,12 +272,12 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
         }
 
         /* Totally Illegal */
-        if ((i < 0) || (i >= 32) || !(player_ptr->spell_learned1 & (1U << sentaku[i]))) {
+        if ((i < 0) || (i >= 32) || !(player_ptr->spell_learned1 & (1U << selections[i]))) {
             bell();
             continue;
         }
 
-        j = sentaku[i];
+        j = selections[i];
 
         /* Stop the loop */
         flag = true;
@@ -285,7 +286,7 @@ static int get_hissatsu_power(PlayerType *player_ptr, SPELL_IDX *sn)
         screen_load();
     }
 
-    player_ptr->window_flags |= (PW_SPELL);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::SPELL);
     handle_stuff(player_ptr);
 
     /* Abort if needed */
@@ -351,16 +352,18 @@ void do_cmd_hissatsu(PlayerType *player_ptr)
     }
 
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-
-    /* Use some mana */
     player_ptr->csp -= spell.smana;
-
-    /* Limit */
     if (player_ptr->csp < 0) {
         player_ptr->csp = 0;
     }
-    player_ptr->redraw |= (PR_MP);
-    player_ptr->window_flags |= (PW_PLAYER | PW_SPELL);
+
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags);
 }
 
 /*!
@@ -384,15 +387,16 @@ void do_cmd_gain_hissatsu(PlayerType *player_ptr)
     msg_format("You can learn %d new special attack%s.", player_ptr->new_spells, (player_ptr->new_spells == 1 ? "" : "s"));
 #endif
 
-    const auto q = _("どの書から学びますか? ", "Study which book? ");
-    const auto s = _("読める書がない。", "You have no books that you can read.");
-    short item;
-    const auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), TvalItemTester(ItemKindType::HISSATSU_BOOK));
+    constexpr auto q = _("どの書から学びますか? ", "Study which book? ");
+    constexpr auto s = _("読める書がない。", "You have no books that you can read.");
+    constexpr auto options = USE_INVEN | USE_FLOOR;
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, TvalItemTester(ItemKindType::HISSATSU_BOOK));
     if (o_ptr == nullptr) {
         return;
     }
 
-    const auto sval = o_ptr->bi_key.sval().value();
+    const auto sval = *o_ptr->bi_key.sval();
     auto gain = false;
     for (auto i = sval * 8; i < sval * 8 + 8; i++) {
         if (player_ptr->spell_learned1 & (1UL << i)) {
@@ -425,5 +429,5 @@ void do_cmd_gain_hissatsu(PlayerType *player_ptr)
         PlayerEnergy(player_ptr).set_player_turn_energy(100);
     }
 
-    player_ptr->update |= (PU_SPELLS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::SPELLS);
 }
index cdafa6e..293b442 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_hissatsu(PlayerType *player_ptr);
index fb76491..d51ad6c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ものまねの処理実装 / Imitation code
  * @date 2014/01/14
  * @author
 #include "artifact/fixed-art-types.h"
 #include "cmd-action/cmd-spell.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
-#include "floor/cave.h"
 #include "floor/floor-object.h"
 #include "game-option/disturbance-options.h"
 #include "game-option/text-display-options.h"
@@ -30,6 +28,7 @@
 #include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-ability-flags.h"
+#include "monster-race/race-ability-mask.h"
 #include "monster-race/race-flags-resistance.h"
 #include "monster-race/race-flags1.h"
 #include "monster/monster-describer.h"
@@ -59,6 +58,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
 #include "target/target-getter.h"
@@ -86,9 +86,14 @@ static std::string mane_info(PlayerType *player_ptr, MonsterAbilityType power, i
 {
     PLAYER_LEVEL plev = player_ptr->lev;
 
-    const auto power_int = enum2i(power);
-
-    if ((power_int > 2 && power_int < 41) || (power_int > 41 && power_int < 59) || (power == MonsterAbilityType::PSY_SPEAR) || (power == MonsterAbilityType::BO_VOID) || (power == MonsterAbilityType::BO_ABYSS) || (power == MonsterAbilityType::BA_VOID) || (power == MonsterAbilityType::BA_ABYSS) || (power == MonsterAbilityType::BR_VOID) || (power == MonsterAbilityType::BR_ABYSS)) {
+    using Mat = MonsterAbilityType;
+    const auto flags =
+        (RF_ABILITY_BALL_MASK |
+            RF_ABILITY_BOLT_MASK |
+            RF_ABILITY_BEAM_MASK)
+            .set(
+                { Mat::MIND_BLAST, Mat::BRAIN_SMASH, Mat::CAUSE_1, Mat::CAUSE_2, Mat::CAUSE_3, Mat::CAUSE_4 });
+    if (flags.has(power)) {
         return format(" %s%d", KWD_DAM, (int)dam);
     }
     switch (power) {
@@ -138,8 +143,6 @@ static int get_mane_power(PlayerType *player_ptr, int *sn, bool baigaesi)
     PERCENTAGE minfail = 0;
     PLAYER_LEVEL plev = player_ptr->lev;
     PERCENTAGE chance = 0;
-    char choice;
-    char out_val[MAX_MONSTER_NAME];
     concptr p = _("能力", "power");
 
     monster_power spell;
@@ -156,14 +159,20 @@ static int get_mane_power(PlayerType *player_ptr, int *sn, bool baigaesi)
     num = mane_data->mane_list.size();
 
     /* Build a prompt (accept all spells) */
-    (void)strnfmt(out_val, 78, _("(%c-%c, '*'で一覧, ESC) どの%sをまねますか?", "(%c-%c, *=List, ESC=exit) Use which %s? "), I2A(0), I2A(num - 1), p);
+    constexpr auto fmt = _("(%c-%c, '*'で一覧, ESC) どの%sをまねますか?", "(%c-%c, *=List, ESC=exit) Use which %s? ");
+    const auto prompt = format(fmt, I2A(0), I2A(num - 1), p);
 
-    choice = always_show_list ? ESCAPE : 1;
+    char choice = always_show_list ? ESCAPE : '\1';
     while (!flag) {
         if (choice == ESCAPE) {
             choice = ' ';
-        } else if (!get_com(out_val, &choice, true)) {
-            break;
+        } else {
+            const auto new_choice = input_command(prompt, true);
+            if (!new_choice) {
+                break;
+            }
+
+            choice = *new_choice;
         }
 
         /* Request redraw */
@@ -259,7 +268,7 @@ static int get_mane_power(PlayerType *player_ptr, int *sn, bool baigaesi)
         screen_load();
     }
 
-    player_ptr->window_flags |= (PW_SPELL);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::SPELL);
     handle_stuff(player_ptr);
 
     /* Abort if needed */
@@ -305,21 +314,20 @@ static bool use_mane(PlayerType *player_ptr, MonsterAbilityType spell)
         break;
 
     case MonsterAbilityType::DISPEL: {
-        MONSTER_IDX m_idx;
-
         if (!target_set(player_ptr, TARGET_KILL)) {
             return false;
         }
-        m_idx = player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx;
-        if (!m_idx) {
-            break;
-        }
-        if (!player_has_los_bold(player_ptr, target_row, target_col)) {
-            break;
-        }
-        if (!projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
+
+        const Pos2D pos(target_row, target_col);
+        const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+        const auto m_idx = grid.m_idx;
+        auto should_dispel = m_idx == 0;
+        should_dispel &= grid.has_los();
+        should_dispel &= projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col);
+        if (!should_dispel) {
             break;
         }
+
         dispel_monster_status(player_ptr, m_idx);
         break;
     }
@@ -687,6 +695,15 @@ static bool use_mane(PlayerType *player_ptr, MonsterAbilityType spell)
 
         fire_ball(player_ptr, AttributeType::ABYSS, dir, damage, 4);
         break;
+    case MonsterAbilityType::BA_METEOR:
+        if (!get_aim_dir(player_ptr, &dir)) {
+            return false;
+        } else {
+            msg_print(_("メテオスウォームの呪文を念じた。", "You cast a meteor swarm."));
+        }
+
+        fire_ball(player_ptr, AttributeType::METEOR, dir, damage, 4);
+        break;
     case MonsterAbilityType::DRAIN_MANA:
         if (!get_aim_dir(player_ptr, &dir)) {
             return false;
@@ -837,6 +854,24 @@ static bool use_mane(PlayerType *player_ptr, MonsterAbilityType spell)
 
         fire_bolt(player_ptr, AttributeType::ABYSS, dir, damage);
         break;
+    case MonsterAbilityType::BO_METEOR:
+        if (!get_aim_dir(player_ptr, &dir)) {
+            return false;
+        } else {
+            msg_print(_("メテオストライクの呪文を唱えた。", "You cast a meteor strike."));
+        }
+
+        fire_bolt(player_ptr, AttributeType::METEOR, dir, damage);
+        break;
+    case MonsterAbilityType::BO_LITE:
+        if (!get_aim_dir(player_ptr, &dir)) {
+            return false;
+        } else {
+            msg_print(_("スターライトアローの呪文を唱えた。", "You cast a starlight arrow."));
+        }
+
+        fire_bolt(player_ptr, AttributeType::LITE, dir, damage);
+        break;
     case MonsterAbilityType::MISSILE:
         if (!get_aim_dir(player_ptr, &dir)) {
             return false;
@@ -922,29 +957,31 @@ static bool use_mane(PlayerType *player_ptr, MonsterAbilityType spell)
         if (!target_set(player_ptr, TARGET_KILL)) {
             return false;
         }
-        if (!player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx) {
-            break;
-        }
-        if (!player_has_los_bold(player_ptr, target_row, target_col)) {
-            break;
-        }
-        if (!projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
+
+        const auto &floor = *player_ptr->current_floor_ptr;
+        const Pos2D pos(target_row, target_col);
+        const auto &grid_target = floor.get_grid(pos);
+        auto should_teleport = grid_target.m_idx == 0;
+        should_teleport &= grid_target.has_los();
+        should_teleport &= projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col);
+        if (!should_teleport) {
             break;
         }
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
-        const auto m_name = monster_desc(player_ptr, m_ptr, 0);
-        if (r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT)) {
-            if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
-                if (is_original_ap_and_seen(player_ptr, m_ptr)) {
-                    r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
+
+        const auto &monster = floor.m_list[grid_target.m_idx];
+        auto &monrace = monster.get_monrace();
+        const auto m_name = monster_desc(player_ptr, &monster, 0);
+        if (monrace.resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT)) {
+            if (monrace.kind_flags.has(MonsterKindType::UNIQUE) || monrace.resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
+                if (is_original_ap_and_seen(player_ptr, &monster)) {
+                    monrace.r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
                 }
                 msg_format(_("%sには効果がなかった!", "%s is unaffected!"), m_name.data());
 
                 break;
-            } else if (r_ptr->level > randint1(100)) {
-                if (is_original_ap_and_seen(player_ptr, m_ptr)) {
-                    r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
+            } else if (monrace.level > randint1(100)) {
+                if (is_original_ap_and_seen(player_ptr, &monster)) {
+                    monrace.r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
                 }
                 msg_format(_("%sには耐性がある!", "%s resists!"), m_name.data());
 
@@ -953,8 +990,7 @@ static bool use_mane(PlayerType *player_ptr, MonsterAbilityType spell)
         }
         msg_format(_("%sを引き戻した。", "You command %s to return."), m_name.data());
 
-        teleport_monster_to(
-            player_ptr, player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx, player_ptr->y, player_ptr->x, 100, TELEPORT_PASSIVE);
+        teleport_monster_to(player_ptr, grid_target.m_idx, player_ptr->y, player_ptr->x, 100, TELEPORT_PASSIVE);
         break;
     }
     case MonsterAbilityType::TELE_AWAY:
@@ -1183,6 +1219,19 @@ static bool use_mane(PlayerType *player_ptr, MonsterAbilityType spell)
         }
         break;
     }
+    case MonsterAbilityType::S_DEAD_UNIQUE: {
+        auto count = 0;
+        if (!target_set(player_ptr, TARGET_KILL)) {
+            return false;
+        }
+        msg_print(_("特別な強敵を蘇生した!", "You summon special dead opponents!"));
+        for (auto k = 0; k < 4; k++) {
+            if (summon_specific(player_ptr, -1, target_row, target_col, plev, SUMMON_DEAD_UNIQUE, (mode | PM_ALLOW_UNIQUE | PM_CLONE))) {
+                count++;
+            }
+        }
+        break;
+    }
     default:
         msg_print("hoge?");
     }
@@ -1280,12 +1329,13 @@ bool do_cmd_mane(PlayerType *player_ptr, bool baigaesi)
     }
 
     mane_data->mane_list.erase(std::next(mane_data->mane_list.begin(), n));
-
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-
-    player_ptr->redraw |= (PR_IMITATION);
-    player_ptr->window_flags |= (PW_PLAYER);
-    player_ptr->window_flags |= (PW_SPELL);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::IMITATION);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags);
     return true;
 }
index 6338c34..166e9dd 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool do_cmd_mane(PlayerType *player_ptr, bool baigaesi);
index 4a3520e..1b669d9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 各職業の特殊技能実装 / Special magics
  * @date 2014/01/15
  * @author
@@ -13,7 +13,6 @@
 #include "cmd-action/cmd-mind.h"
 #include "action/action-limited.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
@@ -47,6 +46,7 @@
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-stun.h"
 #include "timed-effect/timed-effects.h"
@@ -168,7 +168,7 @@ static bool check_mind_hp_mp_sufficiency(PlayerType *player_ptr, cm_type *cm_ptr
         return false;
     }
 
-    return get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
+    return input_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
 }
 
 static void decide_mind_chance(PlayerType *player_ptr, cm_type *cm_ptr)
@@ -374,7 +374,7 @@ static void process_hard_concentration(PlayerType *player_ptr, cm_type *cm_ptr)
 {
     if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU)) {
         take_hit(player_ptr, DAMAGE_USELIFE, cm_ptr->mana_cost, _("過度の集中", "concentrating too hard"));
-        player_ptr->redraw |= PR_HP;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::HP);
         return;
     }
 
@@ -425,9 +425,13 @@ void do_cmd_mind(PlayerType *player_ptr)
 
     mind_turn_passing(player_ptr, cm_ptr);
     process_hard_concentration(player_ptr, cm_ptr);
-    player_ptr->redraw |= PR_MP;
-    player_ptr->window_flags |= PW_PLAYER;
-    player_ptr->window_flags |= PW_SPELL;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags);
 }
 
 static MindKindType decide_use_mind_browse(PlayerType *player_ptr)
@@ -462,12 +466,12 @@ void do_cmd_mind_browse(PlayerType *player_ptr)
             return;
         }
 
-        term_erase(12, 21, 255);
-        term_erase(12, 20, 255);
-        term_erase(12, 19, 255);
-        term_erase(12, 18, 255);
-        term_erase(12, 17, 255);
-        term_erase(12, 16, 255);
+        term_erase(12, 21);
+        term_erase(12, 20);
+        term_erase(12, 19);
+        term_erase(12, 18);
+        term_erase(12, 17);
+        term_erase(12, 16);
         display_wrap_around(mind_tips[enum2i(use_mind)][n], 62, 17, 15);
 
         switch (use_mind) {
index fe8dac1..3e3114d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_mind(PlayerType *player_ptr);
index 853fc6e..8d943d7 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-action/cmd-move.h"
+#include "cmd-action/cmd-move.h"
 #include "action/action-limited.h"
 #include "action/movement-execution.h"
 #include "action/run-execution.h"
@@ -6,8 +6,6 @@
 #include "cmd-io/cmd-save.h"
 #include "core/asking-player.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "dungeon/quest.h"
 #include "floor/cave.h"
@@ -38,6 +36,7 @@
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/target-getter.h"
 #include "timed-effect/player-cut.h"
@@ -45,6 +44,7 @@
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
+#include <algorithm>
 
 /*!
  * @brief フロア脱出時に出戻りが不可能だった場合に警告を加える処理
@@ -63,9 +63,9 @@ static bool confirm_leave_level(PlayerType *player_ptr, bool down_stair)
     caution_in_quest |= q_ptr->flags & QUEST_FLAG_ONCE && q_ptr->status != QuestStatusType::COMPLETED;
     caution_in_quest |= caution_in_tower;
 
-    if (confirm_quest && inside_quest(player_ptr->current_floor_ptr->quest_number) && caution_in_quest) {
+    if (confirm_quest && player_ptr->current_floor_ptr->is_in_quest() && caution_in_quest) {
         msg_print(_("この階を一度去ると二度と戻って来られません。", "You can't come back here once you leave this floor."));
-        return get_check(_("本当にこの階を去りますか?", "Really leave this floor? "));
+        return input_check(_("本当にこの階を去りますか?", "Really leave this floor? "));
     }
 
     return true;
@@ -77,19 +77,17 @@ static bool confirm_leave_level(PlayerType *player_ptr, bool down_stair)
 void do_cmd_go_up(PlayerType *player_ptr)
 {
     auto &quest_list = QuestList::get_instance();
-    bool go_up = false;
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    int up_num = 0;
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.get_grid({ player_ptr->y, player_ptr->x });
+    const auto &terrain = grid.get_terrain();
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
 
-    if (f_ptr->flags.has_not(TerrainCharacteristics::LESS)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::LESS)) {
         msg_print(_("ここには上り階段が見当たらない。", "I see no up staircase here."));
         return;
     }
 
-    const auto &floor_ptr = player_ptr->current_floor_ptr;
-    if (f_ptr->flags.has(TerrainCharacteristics::QUEST)) {
+    if (terrain.flags.has(TerrainCharacteristics::QUEST)) {
         if (!confirm_leave_level(player_ptr, false)) {
             return;
         }
@@ -103,8 +101,8 @@ void do_cmd_go_up(PlayerType *player_ptr)
         sound(SOUND_STAIRWAY);
 
         leave_quest_check(player_ptr);
-        floor_ptr->quest_number = i2enum<QuestId>(g_ptr->special);
-        const auto quest_number = floor_ptr->quest_number;
+        floor.quest_number = i2enum<QuestId>(grid.special);
+        const auto quest_number = floor.quest_number;
         auto &quest = quest_list[quest_number];
         if (quest.status == QuestStatusType::UNTAKEN) {
             if (quest.type != QuestKindType::RANDOM) {
@@ -116,7 +114,7 @@ void do_cmd_go_up(PlayerType *player_ptr)
         }
 
         if (!inside_quest(quest_number)) {
-            floor_ptr->dun_level = 0;
+            floor.dun_level = 0;
             player_ptr->word_recall = 0;
         }
 
@@ -127,7 +125,8 @@ void do_cmd_go_up(PlayerType *player_ptr)
         return;
     }
 
-    if (!floor_ptr->is_in_dungeon()) {
+    auto go_up = false;
+    if (!floor.is_in_dungeon()) {
         go_up = true;
     } else {
         go_up = confirm_leave_level(player_ptr, false);
@@ -151,13 +150,14 @@ void do_cmd_go_up(PlayerType *player_ptr)
         player_ptr->current_floor_ptr->quest_number = QuestId::NONE;
     }
 
+    auto up_num = 0;
     if (inside_quest(quest_number) && quest.type != QuestKindType::RANDOM) {
         leave_quest_check(player_ptr);
-        player_ptr->current_floor_ptr->quest_number = i2enum<QuestId>(g_ptr->special);
+        player_ptr->current_floor_ptr->quest_number = i2enum<QuestId>(grid.special);
         player_ptr->current_floor_ptr->dun_level = 0;
         up_num = 0;
     } else {
-        if (f_ptr->flags.has(TerrainCharacteristics::SHAFT)) {
+        if (terrain.flags.has(TerrainCharacteristics::SHAFT)) {
             prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_UP | CFM_SHAFT);
             up_num = 2;
         } else {
@@ -165,13 +165,13 @@ void do_cmd_go_up(PlayerType *player_ptr)
             up_num = 1;
         }
 
-        if (player_ptr->current_floor_ptr->dun_level - up_num < dungeons_info[player_ptr->dungeon_idx].mindepth) {
+        if (player_ptr->current_floor_ptr->dun_level - up_num < floor.get_dungeon_definition().mindepth) {
             up_num = player_ptr->current_floor_ptr->dun_level;
         }
     }
 
     if (record_stair) {
-        exe_write_diary(player_ptr, DIARY_STAIR, 0 - up_num, _("階段を上った", "climbed up the stairs to"));
+        exe_write_diary(player_ptr, DiaryKind::STAIR, 0 - up_num, _("階段を上った", "climbed up the stairs to"));
     }
 
     if (up_num == player_ptr->current_floor_ptr->dun_level) {
@@ -204,24 +204,24 @@ void do_cmd_go_down(PlayerType *player_ptr)
     int down_num = 0;
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
 
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ptr->grid_array[player_ptr->y][player_ptr->x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    if (f_ptr->flags.has_not(TerrainCharacteristics::MORE)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &grid = floor.grid_array[player_ptr->y][player_ptr->x];
+    auto &terrain = grid.get_terrain();
+    if (terrain.flags.has_not(TerrainCharacteristics::MORE)) {
         msg_print(_("ここには下り階段が見当たらない。", "I see no down staircase here."));
         return;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::TRAP)) {
+    if (terrain.flags.has(TerrainCharacteristics::TRAP)) {
         fall_trap = true;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER)) {
+    if (terrain.flags.has(TerrainCharacteristics::QUEST_ENTER)) {
         do_cmd_quest(player_ptr);
         return;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::QUEST)) {
+    if (terrain.flags.has(TerrainCharacteristics::QUEST)) {
         auto &quest_list = QuestList::get_instance();
         if (!confirm_leave_level(player_ptr, true)) {
             return;
@@ -237,9 +237,9 @@ void do_cmd_go_down(PlayerType *player_ptr)
 
         leave_quest_check(player_ptr);
         leave_tower_check(player_ptr);
-        floor_ptr->quest_number = i2enum<QuestId>(g_ptr->special);
+        floor.quest_number = i2enum<QuestId>(grid.special);
 
-        auto &current_quest = quest_list[floor_ptr->quest_number];
+        auto &current_quest = quest_list[floor.quest_number];
         if (current_quest.status == QuestStatusType::UNTAKEN) {
             if (current_quest.type != QuestKindType::RANDOM) {
                 init_flags = INIT_ASSIGN;
@@ -249,8 +249,8 @@ void do_cmd_go_down(PlayerType *player_ptr)
             current_quest.status = QuestStatusType::TAKEN;
         }
 
-        if (!inside_quest(floor_ptr->quest_number)) {
-            floor_ptr->dun_level = 0;
+        if (!floor.is_in_quest()) {
+            floor.dun_level = 0;
             player_ptr->word_recall = 0;
         }
 
@@ -261,9 +261,9 @@ void do_cmd_go_down(PlayerType *player_ptr)
         return;
     }
 
-    DUNGEON_IDX target_dungeon = 0;
-    if (!floor_ptr->is_in_dungeon()) {
-        target_dungeon = f_ptr->flags.has(TerrainCharacteristics::ENTRANCE) ? g_ptr->special : DUNGEON_ANGBAND;
+    short target_dungeon = 0;
+    if (!floor.is_in_dungeon()) {
+        target_dungeon = terrain.flags.has(TerrainCharacteristics::ENTRANCE) ? grid.special : DUNGEON_ANGBAND;
         if (ironman_downward && (target_dungeon != DUNGEON_ANGBAND)) {
             msg_print(_("ダンジョンの入口は塞がれている!", "The entrance of this dungeon is closed!"));
             return;
@@ -273,14 +273,14 @@ void do_cmd_go_down(PlayerType *player_ptr)
             const auto mes = _("ここには%sの入り口(%d階相当)があります", "There is the entrance of %s (Danger level: %d)");
             const auto &dungeon = dungeons_info[target_dungeon];
             msg_format(mes, dungeon.name.data(), dungeon.mindepth);
-            if (!get_check(_("本当にこのダンジョンに入りますか?", "Do you really get in this dungeon? "))) {
+            if (!input_check(_("本当にこのダンジョンに入りますか?", "Do you really get in this dungeon? "))) {
                 return;
             }
         }
 
         player_ptr->oldpx = player_ptr->x;
         player_ptr->oldpy = player_ptr->y;
-        player_ptr->dungeon_idx = target_dungeon;
+        floor.set_dungeon_index(target_dungeon);
         prepare_change_floor_mode(player_ptr, CFM_FIRST_FLOOR);
     }
 
@@ -289,22 +289,23 @@ void do_cmd_go_down(PlayerType *player_ptr)
         do_cmd_save_game(player_ptr, true);
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::SHAFT)) {
+    if (terrain.flags.has(TerrainCharacteristics::SHAFT)) {
         down_num += 2;
     } else {
         down_num += 1;
     }
 
-    if (!floor_ptr->is_in_dungeon()) {
+    const auto &dungeon = floor.get_dungeon_definition();
+    if (!floor.is_in_dungeon()) {
         player_ptr->enter_dungeon = true;
-        down_num = dungeons_info[player_ptr->dungeon_idx].mindepth;
+        down_num = dungeon.mindepth;
     }
 
     if (record_stair) {
         if (fall_trap) {
-            exe_write_diary(player_ptr, DIARY_STAIR, down_num, _("落とし戸に落ちた", "fell through a trap door"));
+            exe_write_diary(player_ptr, DiaryKind::STAIR, down_num, _("落とし戸に落ちた", "fell through a trap door"));
         } else {
-            exe_write_diary(player_ptr, DIARY_STAIR, down_num, _("階段を下りた", "climbed down the stairs to"));
+            exe_write_diary(player_ptr, DiaryKind::STAIR, down_num, _("階段を下りた", "climbed down the stairs to"));
         }
     }
 
@@ -312,7 +313,7 @@ void do_cmd_go_down(PlayerType *player_ptr)
         msg_print(_("わざと落とし戸に落ちた。", "You deliberately jump through the trap door."));
     } else {
         if (target_dungeon) {
-            msg_format(_("%sへ入った。", "You entered %s."), dungeons_info[player_ptr->dungeon_idx].text.data());
+            msg_format(_("%sへ入った。", "You entered %s."), dungeon.text.data());
         } else {
             if (is_echizen(player_ptr)) {
                 msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
@@ -331,7 +332,7 @@ void do_cmd_go_down(PlayerType *player_ptr)
         return;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::SHAFT)) {
+    if (terrain.flags.has(TerrainCharacteristics::SHAFT)) {
         prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_SHAFT);
     } else {
         prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN);
@@ -348,13 +349,13 @@ void do_cmd_walk(PlayerType *player_ptr, bool pickup)
 {
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= PR_ACTION;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
     bool more = false;
     DIRECTION dir;
-    if (get_rep_dir(player_ptr, &dir, false)) {
+    if (get_rep_dir(player_ptr, &dir)) {
         PlayerEnergy energy(player_ptr);
         energy.set_player_turn_energy(100);
         if (dir != 5) {
@@ -408,7 +409,7 @@ void do_cmd_run(PlayerType *player_ptr)
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
 
-    if (get_rep_dir(player_ptr, &dir, false)) {
+    if (get_rep_dir(player_ptr, &dir)) {
         player_ptr->running = (command_arg ? command_arg : 1000);
         run_step(player_ptr, dir);
     }
@@ -426,7 +427,7 @@ void do_cmd_stay(PlayerType *player_ptr, bool pickup)
     uint32_t mpe_mode = MPE_STAYING | MPE_ENERGY_USE;
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= (PR_ACTION);
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
@@ -439,6 +440,37 @@ void do_cmd_stay(PlayerType *player_ptr, bool pickup)
 }
 
 /*!
+ * @brief 休憩ターン数のコマンド受付
+ */
+static bool input_rest_turns()
+{
+    constexpr auto p = _("休憩 (0-9999, '*' で HP/MP全快, '&' で必要なだけ): ", "Rest (0-9999, '*' for HP/SP, '&' as needed): ");
+    while (true) {
+        const auto rest_turns = input_string(p, 4, "&");
+        if (!rest_turns) {
+            return false;
+        }
+
+        if (rest_turns->starts_with('&')) {
+            command_arg = COMMAND_ARG_REST_UNTIL_DONE;
+            return true;
+        }
+
+        if (rest_turns->starts_with('*')) {
+            command_arg = COMMAND_ARG_REST_FULL_HEALING;
+            return true;
+        }
+
+        try {
+            command_arg = static_cast<short>(std::clamp(std::stoi(*rest_turns), 0, 9999));
+            return true;
+        } catch (std::invalid_argument const &) {
+            msg_print(_("数値を入力して下さい。", "Please input numeric value."));
+        }
+    }
+}
+
+/*!
  * @brief 「休む」動作コマンドのメインルーチン /
  * Resting allows a player to safely restore his hp    -RAK-
  * @param player_ptr プレイヤーへの参照ポインタ
@@ -446,8 +478,12 @@ void do_cmd_stay(PlayerType *player_ptr, bool pickup)
 void do_cmd_rest(PlayerType *player_ptr)
 {
     set_action(player_ptr, ACTION_NONE);
-    if (PlayerClass(player_ptr).equals(PlayerClassType::BARD) && ((get_singing_song_effect(player_ptr) != 0) || (get_interrupting_song_effect(player_ptr) != 0))) {
-        stop_singing(player_ptr);
+    if (PlayerClass(player_ptr).equals(PlayerClassType::BARD)) {
+        auto is_singing = get_singing_song_effect(player_ptr) != 0;
+        is_singing |= get_interrupting_song_effect(player_ptr) != 0;
+        if (is_singing) {
+            stop_singing(player_ptr);
+        }
     }
 
     SpellHex spell_hex(player_ptr);
@@ -455,28 +491,8 @@ void do_cmd_rest(PlayerType *player_ptr)
         (void)spell_hex.stop_all_spells();
     }
 
-    if (command_arg <= 0) {
-        concptr p = _("休憩 (0-9999, '*' で HP/MP全快, '&' で必要なだけ): ", "Rest (0-9999, '*' for HP/SP, '&' as needed): ");
-        char out_val[80];
-        strcpy(out_val, "&");
-        if (!get_string(p, out_val, 4)) {
-            return;
-        }
-
-        if (out_val[0] == '&') {
-            command_arg = COMMAND_ARG_REST_UNTIL_DONE;
-        } else if (out_val[0] == '*') {
-            command_arg = COMMAND_ARG_REST_FULL_HEALING;
-        } else {
-            command_arg = (COMMAND_ARG)atoi(out_val);
-            if (command_arg <= 0) {
-                return;
-            }
-        }
-    }
-
-    if (command_arg > 9999) {
-        command_arg = 9999;
+    if (!input_rest_turns()) {
+        return;
     }
 
     set_superstealth(player_ptr, false);
@@ -492,8 +508,9 @@ void do_cmd_rest(PlayerType *player_ptr)
 
     player_ptr->resting = command_arg;
     player_ptr->action = ACTION_REST;
-    player_ptr->update |= PU_BONUS;
-    player_ptr->redraw |= (PR_ACTION);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(MainWindowRedrawingFlag::ACTION);
     handle_stuff(player_ptr);
     term_fresh();
 }
index 9871eaa..f751d48 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_go_up(PlayerType *player_ptr);
index 0f955e4..f359ec5 100644 (file)
@@ -1,9 +1,8 @@
-#include "cmd-action/cmd-open-close.h"
+#include "cmd-action/cmd-open-close.h"
 #include "action/open-close-execution.h"
 #include "action/open-util.h"
 #include "cmd-action/cmd-attack.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "floor/geometry.h"
 #include "game-option/disturbance-options.h"
 #include "game-option/input-options.h"
@@ -25,6 +24,7 @@
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/target-getter.h"
 #include "term/screen-processor.h"
  * @details
  * Assume there is no monster blocking the destination
  */
-static bool exe_open_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJECT_IDX o_idx)
+static bool exe_open_chest(PlayerType *player_ptr, const Pos2D &pos, OBJECT_IDX o_idx)
 {
-    bool flag = true;
-    bool more = false;
+    auto flag = true;
+    auto more = false;
     auto *o_ptr = &player_ptr->current_floor_ptr->o_list[o_idx];
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
     if (o_ptr->pval > 0) {
@@ -84,8 +84,8 @@ static bool exe_open_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJEC
 
     if (flag) {
         Chest chest(player_ptr);
-        chest.chest_trap(y, x, o_idx);
-        chest.chest_death(false, y, x, o_idx);
+        chest.fire_trap(pos, o_idx);
+        chest.open(false, pos, o_idx);
     }
 
     return more;
@@ -99,51 +99,45 @@ static bool exe_open_chest(PlayerType *player_ptr, POSITION y, POSITION x, OBJEC
  */
 void do_cmd_open(PlayerType *player_ptr)
 {
-    POSITION y, x;
-    DIRECTION dir;
-    OBJECT_IDX o_idx;
-    bool more = false;
+    auto more = false;
     if (player_ptr->wild_mode) {
         return;
     }
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
-
     if (easy_open) {
-        int num_doors = count_dt(player_ptr, &y, &x, is_closed_door, false);
-        int num_chests = count_chests(player_ptr, &y, &x, false);
-        if (num_doors || num_chests) {
-            bool too_many = (num_doors && num_chests) || (num_doors > 1) || (num_chests > 1);
+        const auto &[num_doors, pos_door] = count_dt(player_ptr, is_closed_door, false);
+        const auto &[num_chests, pos_chest] = count_chests(player_ptr, false);
+        if ((num_doors > 0) || (num_chests > 0)) {
+            const auto pos = pos_chest == Pos2D(0, 0) ? pos_door : pos_chest;
+            const auto too_many = (num_doors && num_chests) || (num_doors > 1) || (num_chests > 1);
             if (!too_many) {
-                command_dir = coords_to_dir(player_ptr, y, x);
+                command_dir = coords_to_dir(player_ptr, pos.y, pos.x);
             }
         }
     }
 
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= PR_ACTION;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
+    int dir;
     if (get_rep_dir(player_ptr, &dir, true)) {
-        FEAT_IDX feat;
-        grid_type *g_ptr;
-        y = player_ptr->y + ddy[dir];
-        x = player_ptr->x + ddx[dir];
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-        feat = g_ptr->get_feat_mimic();
-        o_idx = chest_check(player_ptr->current_floor_ptr, y, x, false);
-        if (terrains_info[feat].flags.has_not(TerrainCharacteristics::OPEN) && !o_idx) {
+        const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+        const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+        const auto o_idx = chest_check(player_ptr->current_floor_ptr, pos, false);
+        if (grid.get_terrain_mimic().flags.has_not(TerrainCharacteristics::OPEN) && !o_idx) {
             msg_print(_("そこには開けるものが見当たらない。", "You see nothing there to open."));
-        } else if (g_ptr->m_idx && player_ptr->riding != g_ptr->m_idx) {
+        } else if (grid.m_idx && player_ptr->riding != grid.m_idx) {
             PlayerEnergy(player_ptr).set_player_turn_energy(100);
             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
-            do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+            do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
         } else if (o_idx) {
-            more = exe_open_chest(player_ptr, y, x, o_idx);
+            more = exe_open_chest(player_ptr, pos, o_idx);
         } else {
-            more = exe_open(player_ptr, y, x);
+            more = exe_open(player_ptr, pos.y, pos.x);
         }
     }
 
@@ -160,40 +154,37 @@ void do_cmd_open(PlayerType *player_ptr)
  */
 void do_cmd_close(PlayerType *player_ptr)
 {
-    POSITION y, x;
-    DIRECTION dir;
-    bool more = false;
     if (player_ptr->wild_mode) {
         return;
     }
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
-
-    if (easy_open && (count_dt(player_ptr, &y, &x, is_open, false) == 1)) {
-        command_dir = coords_to_dir(player_ptr, y, x);
+    if (easy_open) {
+        const auto &[num_doors, pos] = count_dt(player_ptr, is_open, false);
+        if (num_doors == 1) {
+            command_dir = coords_to_dir(player_ptr, pos.y, pos.x);
+        }
     }
 
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= (PR_ACTION);
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
-    if (get_rep_dir(player_ptr, &dir, false)) {
-        grid_type *g_ptr;
-        FEAT_IDX feat;
-        y = player_ptr->y + ddy[dir];
-        x = player_ptr->x + ddx[dir];
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-        feat = g_ptr->get_feat_mimic();
-        if (terrains_info[feat].flags.has_not(TerrainCharacteristics::CLOSE)) {
+    auto more = false;
+    int dir;
+    if (get_rep_dir(player_ptr, &dir)) {
+        const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+        const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+        if (grid.get_terrain_mimic().flags.has_not(TerrainCharacteristics::CLOSE)) {
             msg_print(_("そこには閉じるものが見当たらない。", "You see nothing there to close."));
-        } else if (g_ptr->m_idx) {
+        } else if (grid.m_idx) {
             PlayerEnergy(player_ptr).set_player_turn_energy(100);
             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
-            do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+            do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
         } else {
-            more = exe_close(player_ptr, y, x);
+            more = exe_close(player_ptr, pos.y, pos.x);
         }
     }
 
@@ -208,50 +199,45 @@ void do_cmd_close(PlayerType *player_ptr)
  */
 void do_cmd_disarm(PlayerType *player_ptr)
 {
-    POSITION y, x;
-    DIRECTION dir;
-    OBJECT_IDX o_idx;
-    bool more = false;
     if (player_ptr->wild_mode) {
         return;
     }
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
-
     if (easy_disarm) {
-        int num_traps = count_dt(player_ptr, &y, &x, is_trap, true);
-        int num_chests = count_chests(player_ptr, &y, &x, true);
-        if (num_traps || num_chests) {
-            bool too_many = (num_traps && num_chests) || (num_traps > 1) || (num_chests > 1);
+        const auto &[num_traps, pos_trap] = count_dt(player_ptr, is_trap, true);
+        const auto &[num_chests, pos_chest] = count_chests(player_ptr, true);
+        if ((num_traps > 0) || (num_chests > 0)) {
+            const auto pos = pos_chest == Pos2D(0, 0) ? pos_trap : pos_chest;
+            const auto too_many = (num_traps && num_chests) || (num_traps > 1) || (num_chests > 1);
             if (!too_many) {
-                command_dir = coords_to_dir(player_ptr, y, x);
+                command_dir = coords_to_dir(player_ptr, pos.y, pos.x);
             }
         }
     }
 
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= (PR_ACTION);
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
+    int dir;
+    auto more = false;
     if (get_rep_dir(player_ptr, &dir, true)) {
-        grid_type *g_ptr;
-        FEAT_IDX feat;
-        y = player_ptr->y + ddy[dir];
-        x = player_ptr->x + ddx[dir];
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-        feat = g_ptr->get_feat_mimic();
-        o_idx = chest_check(player_ptr->current_floor_ptr, y, x, true);
+        const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+        const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+        const auto feat = grid.get_feat_mimic();
+        const auto o_idx = chest_check(player_ptr->current_floor_ptr, pos, true);
         if (!is_trap(player_ptr, feat) && !o_idx) {
             msg_print(_("そこには解除するものが見当たらない。", "You see nothing there to disarm."));
-        } else if (g_ptr->m_idx && player_ptr->riding != g_ptr->m_idx) {
+        } else if (grid.m_idx && player_ptr->riding != grid.m_idx) {
             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
-            do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+            do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
         } else if (o_idx) {
-            more = exe_disarm_chest(player_ptr, y, x, o_idx);
+            more = exe_disarm_chest(player_ptr, pos.y, pos.x, o_idx);
         } else {
-            more = exe_disarm(player_ptr, y, x, dir);
+            more = exe_disarm(player_ptr, pos.y, pos.x, dir);
         }
     }
 
@@ -279,10 +265,7 @@ void do_cmd_disarm(PlayerType *player_ptr)
  */
 void do_cmd_bash(PlayerType *player_ptr)
 {
-    POSITION y, x;
-    DIRECTION dir;
-    grid_type *g_ptr;
-    bool more = false;
+    auto more = false;
     if (player_ptr->wild_mode) {
         return;
     }
@@ -291,24 +274,22 @@ void do_cmd_bash(PlayerType *player_ptr)
 
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= (PR_ACTION);
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
-    if (get_rep_dir(player_ptr, &dir, false)) {
-        FEAT_IDX feat;
-        y = player_ptr->y + ddy[dir];
-        x = player_ptr->x + ddx[dir];
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-        feat = g_ptr->get_feat_mimic();
-        if (terrains_info[feat].flags.has_not(TerrainCharacteristics::BASH)) {
+    int dir;
+    if (get_rep_dir(player_ptr, &dir)) {
+        const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+        const Grid &grid = player_ptr->current_floor_ptr->get_grid(pos);
+        if (grid.get_terrain_mimic().flags.has_not(TerrainCharacteristics::BASH)) {
             msg_print(_("そこには体当たりするものが見当たらない。", "You see nothing there to bash."));
-        } else if (g_ptr->m_idx) {
+        } else if (grid.m_idx) {
             PlayerEnergy(player_ptr).set_player_turn_energy(100);
             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
-            do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+            do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
         } else {
-            more = exe_bash(player_ptr, y, x, dir);
+            more = exe_bash(player_ptr, pos.y, pos.x, dir);
         }
     }
 
@@ -362,28 +343,26 @@ void do_cmd_spike(PlayerType *player_ptr)
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
 
-    if (!get_rep_dir(player_ptr, &dir, false)) {
+    if (!get_rep_dir(player_ptr, &dir)) {
         return;
     }
 
-    POSITION y = player_ptr->y + ddy[dir];
-    POSITION x = player_ptr->x + ddx[dir];
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    FEAT_IDX feat = g_ptr->get_feat_mimic();
-    INVENTORY_IDX item;
-    if (terrains_info[feat].flags.has_not(TerrainCharacteristics::SPIKE)) {
+    const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain_mimic = grid.get_terrain_mimic();
+    INVENTORY_IDX i_idx;
+    if (terrain_mimic.flags.has_not(TerrainCharacteristics::SPIKE)) {
         msg_print(_("そこにはくさびを打てるものが見当たらない。", "You see nothing there to spike."));
-    } else if (!get_spike(player_ptr, &item)) {
+    } else if (!get_spike(player_ptr, &i_idx)) {
         msg_print(_("くさびを持っていない!", "You have no spikes!"));
-    } else if (g_ptr->m_idx) {
+    } else if (grid.m_idx) {
         PlayerEnergy(player_ptr).set_player_turn_energy(100);
         msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
-        do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+        do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
     } else {
         PlayerEnergy(player_ptr).set_player_turn_energy(100);
-        msg_format(_("%sにくさびを打ち込んだ。", "You jam the %s with a spike."), terrains_info[feat].name.data());
-        cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::SPIKE);
-        vary_item(player_ptr, item, -1);
+        msg_format(_("%sにくさびを打ち込んだ。", "You jam the %s with a spike."), terrain_mimic.name.data());
+        cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::SPIKE);
+        vary_item(player_ptr, i_idx, -1);
     }
 }
index 68b4c71..ea73287 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_open(PlayerType *player_ptr);
index c210c85..b856e5b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief その他の小さなコマンド処理群 (探索、汎用グリッド処理、自殺/引退/切腹)
  * @date 2014/01/02
  * @author
@@ -15,7 +15,6 @@
 #include "cmd-action/cmd-attack.h"
 #include "core/asking-player.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "floor/geometry.h"
 #include "game-option/game-play-options.h"
 #include "grid/grid.h"
@@ -34,6 +33,7 @@
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/target-getter.h"
 #include "term/screen-processor.h"
@@ -48,7 +48,7 @@ void do_cmd_search(PlayerType *player_ptr)
 {
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= PR_ACTION;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
@@ -67,37 +67,33 @@ static bool exe_alter(PlayerType *player_ptr)
         return false;
     }
 
-    POSITION y = player_ptr->y + ddy[dir];
-    POSITION x = player_ptr->x + ddx[dir];
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    FEAT_IDX feat = g_ptr->get_feat_mimic();
-    TerrainType *f_ptr;
-    f_ptr = &terrains_info[feat];
+    const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain_mimic();
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-    if (g_ptr->m_idx) {
-        do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+    if (grid.m_idx) {
+        do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
         return false;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::OPEN)) {
-        return exe_open(player_ptr, y, x);
+    if (terrain.flags.has(TerrainCharacteristics::OPEN)) {
+        return exe_open(player_ptr, pos.y, pos.x);
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::BASH)) {
-        return exe_bash(player_ptr, y, x, dir);
+    if (terrain.flags.has(TerrainCharacteristics::BASH)) {
+        return exe_bash(player_ptr, pos.y, pos.x, dir);
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::TUNNEL)) {
-        return exe_tunnel(player_ptr, y, x);
+    if (terrain.flags.has(TerrainCharacteristics::TUNNEL)) {
+        return exe_tunnel(player_ptr, pos.y, pos.x);
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::CLOSE)) {
-        return exe_close(player_ptr, y, x);
+    if (terrain.flags.has(TerrainCharacteristics::CLOSE)) {
+        return exe_close(player_ptr, pos.y, pos.x);
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::DISARM)) {
-        return exe_disarm(player_ptr, y, x, dir);
+    if (terrain.flags.has(TerrainCharacteristics::DISARM)) {
+        return exe_disarm(player_ptr, pos.y, pos.x, dir);
     }
 
     msg_print(_("何もない空中を攻撃した。", "You attack the empty air."));
@@ -114,7 +110,7 @@ void do_cmd_alter(PlayerType *player_ptr)
 
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= PR_ACTION;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
@@ -147,16 +143,21 @@ static void accept_winner_message(PlayerType *player_ptr)
         return;
     }
 
-    char buf[1024] = "";
     play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_WINNER);
-    do {
-        while (!get_string(_("*勝利*メッセージ: ", "*Winning* message: "), buf, sizeof(buf))) {
-            ;
+    std::optional<std::string> buf;
+    while (true) {
+        buf = input_string(_("*勝利*メッセージ: ", "*Winning* message: "), 1024);
+        if (!buf) {
+            continue;
+        }
+
+        if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::NO_HISTORY)) {
+            break;
         }
-    } while (!get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_NO_HISTORY));
+    }
 
-    if (buf[0]) {
-        player_ptr->last_message = string_make(buf);
+    if (!buf->empty()) {
+        player_ptr->last_message = *buf;
         msg_print(player_ptr->last_message);
     }
 }
@@ -170,11 +171,11 @@ void do_cmd_suicide(PlayerType *player_ptr)
 {
     flush();
     if (w_ptr->total_winner) {
-        if (!get_check_strict(player_ptr, _("引退しますか? ", "Do you want to retire? "), CHECK_NO_HISTORY)) {
+        if (!input_check_strict(player_ptr, _("引退しますか? ", "Do you want to retire? "), UserCheck::NO_HISTORY)) {
             return;
         }
     } else {
-        if (!get_check(_("本当に自殺しますか?", "Do you really want to commit suicide? "))) {
+        if (!input_check(_("本当に自殺しますか?", "Do you really want to commit suicide? "))) {
             return;
         }
     }
@@ -183,22 +184,18 @@ void do_cmd_suicide(PlayerType *player_ptr)
         return;
     }
 
-    if (player_ptr->last_message) {
-        string_free(player_ptr->last_message);
-    }
-
-    player_ptr->last_message = nullptr;
+    player_ptr->last_message = "";
     player_ptr->playing = false;
     player_ptr->is_dead = true;
     player_ptr->leaving = true;
     if (w_ptr->total_winner) {
         accept_winner_message(player_ptr);
-        add_retired_class(player_ptr->pclass);
+        w_ptr->add_retired_class(player_ptr->pclass);
     } else {
         play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_GAMEOVER);
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, _("ダンジョンの探索に絶望して自殺した。", "gave up all hope to commit suicide."));
-        exe_write_diary(player_ptr, DIARY_GAMESTART, 1, _("-------- ゲームオーバー --------", "--------   Game  Over   --------"));
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, "\n\n\n\n");
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, _("ダンジョンの探索に絶望して自殺した。", "gave up all hope to commit suicide."));
+        exe_write_diary(player_ptr, DiaryKind::GAMESTART, 1, _("-------- ゲームオーバー --------", "--------   Game  Over   --------"));
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, "\n\n\n\n");
     }
 
     player_ptr->died_from = _("途中終了", "Quitting");
index 8c0ac9c..f42f452 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_search(PlayerType *player_ptr);
index 10dc0a1..be4f18b 100644 (file)
@@ -1,10 +1,8 @@
-#include "cmd-action/cmd-pet.h"
+#include "cmd-action/cmd-pet.h"
 #include "action/action-limited.h"
 #include "cmd-action/cmd-attack.h"
 #include "cmd-io/cmd-dump.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "effect/spells-effect-util.h"
@@ -54,6 +52,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/target-checker.h"
 #include "target/target-getter.h"
@@ -64,7 +63,6 @@
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
 #include "util/int-char-converter.h"
-#include "util/quarks.h"
 #include "util/sort.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
@@ -102,6 +100,7 @@ void do_cmd_pet_dismiss(PlayerType *player_ptr)
     ang_sort(player_ptr, who.data(), &dummy_why, who.size(), ang_sort_comp_pet_dismiss, ang_sort_swap_hook);
 
     /* Process the monsters (backwards) */
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     for (auto i = 0U; i < who.size(); i++) {
         auto pet_ctr = who[i];
         m_ptr = &player_ptr->current_floor_ptr->m_list[pet_ctr];
@@ -114,8 +113,8 @@ void do_cmd_pet_dismiss(PlayerType *player_ptr)
             /* Hack -- health bar for this monster */
             health_track(player_ptr, pet_ctr);
             handle_stuff(player_ptr);
-
-            msg_format(_("%sを放しますか? [Yes/No/Unnamed (%lu体)]", "Dismiss %s? [Yes/No/Unnamed (%lu remain)]"), friend_name.data(), who.size() - i);
+            constexpr auto mes = _("%sを放しますか? [Yes/No/Unnamed (%lu体)]", "Dismiss %s? [Yes/No/Unnamed (%lu remain)]");
+            msg_format(mes, friend_name.data(), who.size() - i);
 
             if (m_ptr->ml) {
                 move_cursor_relative(m_ptr->fy, m_ptr->fx);
@@ -153,22 +152,24 @@ void do_cmd_pet_dismiss(PlayerType *player_ptr)
         if ((all_pets && !should_ask) || (!all_pets && delete_this)) {
             if (record_named_pet && m_ptr->is_named()) {
                 const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-                exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_DISMISS, m_name.data());
+                exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_DISMISS, m_name);
             }
 
             if (pet_ctr == player_ptr->riding) {
                 msg_format(_("%sから降りた。", "You dismount from %s. "), friend_name.data());
 
                 player_ptr->riding = 0;
-
-                player_ptr->update |= (PU_MONSTER_STATUSES);
-                player_ptr->redraw |= (PR_EXTRA | PR_UHEALTH);
+                rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+                static constexpr auto flags = {
+                    MainWindowRedrawingFlag::EXTRA,
+                    MainWindowRedrawingFlag::UHEALTH,
+                };
+                rfu.set_flags(flags);
             }
 
-            /* HACK : Add the line to message buffer */
             msg_format(_("%s を放した。", "Dismissed %s."), friend_name.data());
-            player_ptr->update |= (PU_BONUS);
-            player_ptr->window_flags |= (PW_MESSAGE);
+            rfu.set_flag(StatusRecalculatingFlag::BONUS);
+            rfu.set_flag(SubWindowRedrawingFlag::MESSAGE);
 
             delete_monster_idx(player_ptr, pet_ctr);
             Dismissed++;
@@ -198,37 +199,33 @@ void do_cmd_pet_dismiss(PlayerType *player_ptr)
  */
 bool do_cmd_riding(PlayerType *player_ptr, bool force)
 {
-    POSITION x, y;
-    DIRECTION dir = 0;
-    grid_type *g_ptr;
-    MonsterEntity *m_ptr;
-
-    if (!get_direction(player_ptr, &dir, false, false)) {
+    int dir;
+    if (!get_direction(player_ptr, &dir)) {
         return false;
     }
-    y = player_ptr->y + ddy[dir];
-    x = player_ptr->x + ddx[dir];
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+
+    const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+    auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
 
     if (player_ptr->riding) {
         /* Skip non-empty grids */
-        if (!can_player_ride_pet(player_ptr, g_ptr, false)) {
+        if (!can_player_ride_pet(player_ptr, &grid, false)) {
             msg_print(_("そちらには降りられません。", "You cannot go that direction."));
             return false;
         }
 
-        if (!pattern_seq(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+        if (!pattern_seq(player_ptr, pos)) {
             return false;
         }
 
-        if (g_ptr->m_idx) {
+        if (grid.m_idx) {
             PlayerEnergy(player_ptr).set_player_turn_energy(100);
 
             msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
 
-            do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+            do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
             return false;
         }
 
@@ -240,9 +237,9 @@ bool do_cmd_riding(PlayerType *player_ptr, bool force)
             return false;
         }
 
-        m_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
+        const auto *m_ptr = &player_ptr->current_floor_ptr->m_list[grid.m_idx];
 
-        if (!g_ptr->m_idx || !m_ptr->ml) {
+        if (!grid.m_idx || !m_ptr->ml) {
             msg_print(_("その場所にはモンスターはいません。", "There is no monster here."));
             return false;
         }
@@ -250,29 +247,30 @@ bool do_cmd_riding(PlayerType *player_ptr, bool force)
             msg_print(_("そのモンスターはペットではありません。", "That monster is not a pet."));
             return false;
         }
-        if (!(monraces_info[m_ptr->r_idx].flags7 & RF7_RIDING)) {
+        if (!(m_ptr->get_monrace().flags7 & RF7_RIDING)) {
             msg_print(_("そのモンスターには乗れなさそうだ。", "This monster doesn't seem suitable for riding."));
             return false;
         }
 
-        if (!pattern_seq(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+        if (!pattern_seq(player_ptr, pos)) {
             return false;
         }
 
-        if (!can_player_ride_pet(player_ptr, g_ptr, true)) {
+        if (!can_player_ride_pet(player_ptr, &grid, true)) {
             /* Feature code (applying "mimic" field) */
-            auto *f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
+            const auto &terrain = grid.get_terrain_mimic();
+            using Tc = TerrainCharacteristics;
 #ifdef JP
-            msg_format("そのモンスターは%sの%sにいる。", f_ptr->name.data(),
-                (f_ptr->flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY }) || f_ptr->flags.has_none_of({ TerrainCharacteristics::LOS, TerrainCharacteristics::TREE })) ? "中" : "上");
+            msg_format("そのモンスターは%sの%sにいる。", terrain.name.data(),
+                (terrain.flags.has_none_of({ Tc::MOVE, Tc::CAN_FLY }) || terrain.flags.has_none_of({ Tc::LOS, Tc::TREE })) ? "中" : "上");
 #else
             msg_format("This monster is %s the %s.",
-                (f_ptr->flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY }) || f_ptr->flags.has_none_of({ TerrainCharacteristics::LOS, TerrainCharacteristics::TREE })) ? "in" : "on", f_ptr->name.data());
+                (terrain.flags.has_none_of({ Tc::MOVE, Tc::CAN_FLY }) || terrain.flags.has_none_of({ Tc::LOS, Tc::TREE })) ? "in" : "on", terrain.name.data());
 #endif
 
             return false;
         }
-        if (monraces_info[m_ptr->r_idx].level > randint1((player_ptr->skill_exp[PlayerSkillKindType::RIDING] / 50 + player_ptr->lev / 2 + 20))) {
+        if (m_ptr->get_monrace().level > randint1((player_ptr->skill_exp[PlayerSkillKindType::RIDING] / 50 + player_ptr->lev / 2 + 20))) {
             msg_print(_("うまく乗れなかった。", "You failed to ride."));
             PlayerEnergy(player_ptr).set_player_turn_energy(100);
             return false;
@@ -280,7 +278,7 @@ bool do_cmd_riding(PlayerType *player_ptr, bool force)
 
         if (m_ptr->is_asleep()) {
             const auto m_name = monster_desc(player_ptr, m_ptr, 0);
-            (void)set_monster_csleep(player_ptr, g_ptr->m_idx, 0);
+            (void)set_monster_csleep(player_ptr, grid.m_idx, 0);
             msg_format(_("%sを起こした。", "You have woken %s up."), m_name.data());
         }
 
@@ -288,7 +286,7 @@ bool do_cmd_riding(PlayerType *player_ptr, bool force)
             set_action(player_ptr, ACTION_NONE);
         }
 
-        player_ptr->riding = g_ptr->m_idx;
+        player_ptr->riding = grid.m_idx;
 
         /* Hack -- remove tracked monster */
         if (player_ptr->riding == player_ptr->health_who) {
@@ -298,14 +296,20 @@ bool do_cmd_riding(PlayerType *player_ptr, bool force)
 
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
 
-    /* Mega-Hack -- Forget the view and lite */
-    player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->redraw |= (PR_MAP | PR_EXTRA);
-    player_ptr->redraw |= (PR_UHEALTH);
-
-    (void)move_player_effect(player_ptr, y, x, MPE_HANDLE_STUFF | MPE_ENERGY_USE | MPE_DONT_PICKUP | MPE_DONT_SWAP_MON);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::UN_VIEW,
+        StatusRecalculatingFlag::UN_LITE,
+        StatusRecalculatingFlag::BONUS,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::UHEALTH,
+    };
+    rfu.set_flags(flags_mwrf);
+    (void)move_player_effect(player_ptr, pos.y, pos.x, MPE_HANDLE_STUFF | MPE_ENERGY_USE | MPE_DONT_PICKUP | MPE_DONT_SWAP_MON);
     return true;
 }
 
@@ -314,10 +318,7 @@ bool do_cmd_riding(PlayerType *player_ptr, bool force)
  */
 static void do_name_pet(PlayerType *player_ptr)
 {
-    MonsterEntity *m_ptr;
-    bool old_name = false;
-    bool old_target_pet = target_pet;
-
+    auto old_target_pet = target_pet;
     target_pet = true;
     if (!target_set(player_ptr, TARGET_KILL)) {
         target_pet = old_target_pet;
@@ -325,48 +326,52 @@ static void do_name_pet(PlayerType *player_ptr)
     }
 
     target_pet = old_target_pet;
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.grid_array[target_row][target_col];
+    if (grid.m_idx == 0) {
+        return;
+    }
 
-    if (player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx) {
-        m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx];
+    auto *m_ptr = &floor.m_list[grid.m_idx];
+    if (!m_ptr->is_pet()) {
+        msg_print(_("そのモンスターはペットではない。", "This monster is not a pet."));
+        return;
+    }
 
-        if (!m_ptr->is_pet()) {
-            msg_print(_("そのモンスターはペットではない。", "This monster is not a pet."));
-            return;
-        }
-        if (monraces_info[m_ptr->r_idx].kind_flags.has(MonsterKindType::UNIQUE)) {
-            msg_print(_("そのモンスターの名前は変えられない!", "You cannot change the name of this monster!"));
-            return;
-        }
+    if (m_ptr->get_monrace().kind_flags.has(MonsterKindType::UNIQUE)) {
+        msg_print(_("そのモンスターの名前は変えられない!", "You cannot change the name of this monster!"));
+        return;
+    }
 
-        msg_format(_("%sに名前をつける。", "Name %s."), monster_desc(player_ptr, m_ptr, 0).data());
-        msg_print(nullptr);
+    msg_format(_("%sに名前をつける。", "Name %s."), monster_desc(player_ptr, m_ptr, 0).data());
+    msg_print(nullptr);
 
-        /* Start with nothing */
-        char out_val[20]{};
+    auto old_name = false;
+    std::string initial_name("");
+    if (m_ptr->is_named()) {
+        initial_name = m_ptr->nickname;
+        old_name = true;
+    }
 
-        /* Use old inscription */
-        if (m_ptr->is_named()) {
-            /* Start with the old inscription */
-            angband_strcpy(out_val, m_ptr->nickname.data(), sizeof(out_val));
-            old_name = true;
-        }
+    const auto new_name = input_string(_("名前: ", "Name: "), 15, initial_name);
+    if (!new_name) {
+        return;
+    }
 
-        /* Get a new inscription (possibly empty) */
-        if (get_string(_("名前: ", "Name: "), out_val, 15)) {
-            if (out_val[0]) {
-                /* Save the inscription */
-                m_ptr->nickname = out_val;
-                if (record_named_pet) {
-                    exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_NAME, monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE).data());
-                }
-            } else {
-                if (record_named_pet && old_name) {
-                    exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_UNNAME, monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE).data());
-                }
-                m_ptr->nickname.clear();
-            }
+    if (!new_name->empty()) {
+        m_ptr->nickname = *new_name;
+        if (record_named_pet) {
+            exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_NAME, monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE));
         }
+
+        return;
     }
+
+    if (record_named_pet && old_name) {
+        exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_UNNAME, monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE));
+    }
+
+    m_ptr->nickname.clear();
 }
 
 /*!
@@ -503,7 +508,7 @@ void do_cmd_pet(PlayerType *player_ptr)
             switch (player_ptr->pclass) {
             case PlayerClassType::MONK:
             case PlayerClassType::FORCETRAINER:
-            case PlayerClassType::BERSERKER:
+            case PlayerClassType::BERSERKER: {
                 if (empty_hands(player_ptr, false) == (EMPTY_HAND_MAIN | EMPTY_HAND_SUB)) {
                     if (player_ptr->pet_extra_flags & PF_TWO_HANDS) {
                         power_desc[num] = _("片手で格闘する", "use one hand to control the pet you are riding");
@@ -512,7 +517,12 @@ void do_cmd_pet(PlayerType *player_ptr)
                     }
 
                     powers[num++] = PET_TWO_HANDS;
-                } else if ((empty_hands(player_ptr, false) != EMPTY_HAND_NONE) && !has_melee_weapon(player_ptr, INVEN_MAIN_HAND) && !has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
+                    break;
+                }
+
+                auto has_any_melee_weapon = has_melee_weapon(player_ptr, INVEN_MAIN_HAND);
+                has_any_melee_weapon |= has_melee_weapon(player_ptr, INVEN_SUB_HAND);
+                if ((empty_hands(player_ptr, false) != EMPTY_HAND_NONE) && !has_any_melee_weapon) {
                     if (player_ptr->pet_extra_flags & PF_TWO_HANDS) {
                         power_desc[num] = _("格闘を行わない", "use one hand to control the pet you are riding");
                     } else {
@@ -520,9 +530,11 @@ void do_cmd_pet(PlayerType *player_ptr)
                     }
 
                     powers[num++] = PET_TWO_HANDS;
+                    break;
                 }
-                break;
 
+                break;
+            }
             default:
                 break;
             }
@@ -538,18 +550,24 @@ void do_cmd_pet(PlayerType *player_ptr)
             screen_save();
             prompt = _("(コマンド、ESC=終了) コマンドを選んでください:", "(Command, ESC=exit) Choose command from menu.");
         } else {
-            prompt = format(_("(コマンド %c-%c、'*'=一覧、ESC=終了) コマンドを選んでください:", "(Command %c-%c, *=List, ESC=exit) Select a command: "),
-                I2A(0), I2A(num - 1));
+            constexpr auto fmt = _("(コマンド %c-%c、'*'=一覧、ESC=終了) コマンドを選んでください:",
+                "(Command %c-%c, *=List, ESC=exit) Select a command: ");
+            prompt = format(fmt, I2A(0), I2A(num - 1));
         }
 
-        choice = (always_show_list || use_menu) ? ESCAPE : 1;
+        choice = (always_show_list || use_menu) ? ESCAPE : '\1';
 
         /* Get a command from the user */
         while (!flag) {
             if (choice == ESCAPE) {
                 choice = ' ';
-            } else if (!get_com(prompt.data(), &choice, true)) {
-                break;
+            } else {
+                const auto new_choice = input_command(prompt, true);
+                if (!new_choice) {
+                    break;
+                }
+
+                choice = *new_choice;
             }
 
             auto should_redraw_cursor = true;
@@ -620,7 +638,7 @@ void do_cmd_pet(PlayerType *player_ptr)
                         }
 
                         ss << power_desc[control];
-                        prt(ss.str().data(), y + control, x);
+                        prt(ss.str(), y + control, x);
                     }
 
                     prt("", y + std::min(control, 17), x);
@@ -803,7 +821,8 @@ void do_cmd_pet(PlayerType *player_ptr)
         } else {
             player_ptr->pet_extra_flags |= (PF_TWO_HANDS);
         }
-        player_ptr->update |= (PU_BONUS);
+
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
         handle_stuff(player_ptr);
         break;
     }
index ad49110..5212b16 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool do_cmd_riding(PlayerType *player_ptr, bool force);
index 68a74b0..60768f9 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief クラス、種族、突然変異に関するコマンド処理
  * @author Hourier
  * @date 2022/02/24
@@ -9,8 +9,6 @@
 #include "action/mutation-execution.h"
 #include "action/racial-execution.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "game-option/text-display-options.h"
 #include "io/command-repeater.h"
@@ -30,7 +28,9 @@
 #include "racial/race-racial-command-setter.h"
 #include "racial/racial-util.h"
 #include "status/action-setter.h"
+#include "system/angband-exceptions.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-util.h"
 #include <string>
 
-#define RC_PAGE_SIZE 18
-
-#define RC_CANCEL true
-#define RC_CONTINUE false
+constexpr auto RC_PAGE_SIZE = 18;
 
 static void racial_power_display_cursor(rc_type *rc_ptr)
 {
@@ -60,14 +57,11 @@ static void racial_power_erase_cursor(rc_type *rc_ptr)
  * @brief レイシャルパワー一覧を表示
  * @param player_ptr プレイヤー情報への参照ポインタ
  * @param rc_ptr レイシャルパワー情報への参照ポインタ
- * @return キャンセルしたらRC_CANCEL、それ以外ならRC_CONTINUE
  */
 static void racial_power_display_list(PlayerType *player_ptr, rc_type *rc_ptr)
 {
     TERM_LEN x = 11;
-
     prt(_("                                   Lv   MP 失率 効果", "                                   Lv   MP Fail Effect"), 1, x);
-
     auto y = 0;
     for (; y < RC_PAGE_SIZE; y++) {
         auto ctr = RC_PAGE_SIZE * rc_ptr->page + y;
@@ -99,7 +93,6 @@ static void racial_power_display_list(PlayerType *player_ptr, rc_type *rc_ptr)
     }
 
     prt("", 2 + y, x);
-
     if (use_menu) {
         racial_power_display_cursor(rc_ptr);
     }
@@ -137,9 +130,11 @@ static void racial_power_add_index(PlayerType *player_ptr, rc_type *rc_ptr, int
             return;
         }
     }
+
     if (n < 0) {
         n = rc_ptr->power_count() - 1;
     }
+
     if (n >= rc_ptr->power_count()) {
         n = 0;
     }
@@ -160,46 +155,46 @@ static void racial_power_add_index(PlayerType *player_ptr, rc_type *rc_ptr, int
 /*!
  * @brief メニューによる選択のキーを処理する
  * @param rc_ptr レイシャルパワー情報への参照ポインタ
- * @return キャンセルならRC_CANCEL、そうでないならRC_CONTINUE
+ * @return キャンセルならfalse、それ以外ならtrue
  */
 static bool racial_power_interpret_menu_keys(PlayerType *player_ptr, rc_type *rc_ptr)
 {
     switch (rc_ptr->choice) {
     case '0':
-        return RC_CANCEL;
+        return false;
     case '8':
     case 'k':
     case 'K':
         racial_power_add_index(player_ptr, rc_ptr, -1);
-        return RC_CONTINUE;
+        return true;
     case '2':
     case 'j':
     case 'J':
         racial_power_add_index(player_ptr, rc_ptr, 1);
-        return RC_CONTINUE;
+        return true;
     case '6':
     case 'l':
     case 'L':
         racial_power_add_index(player_ptr, rc_ptr, RC_PAGE_SIZE);
-        return RC_CONTINUE;
+        return true;
     case '4':
     case 'h':
     case 'H':
         racial_power_add_index(player_ptr, rc_ptr, 0 - RC_PAGE_SIZE);
-        return RC_CONTINUE;
+        return true;
     case 'x':
     case 'X':
     case '\r':
         rc_ptr->command_code = (COMMAND_CODE)rc_ptr->menu_line;
         rc_ptr->is_chosen = true;
         rc_ptr->ask = false;
-        return RC_CONTINUE;
+        return true;
     case '/':
         rc_ptr->browse_mode = !rc_ptr->browse_mode;
         racial_power_make_prompt(rc_ptr);
-        return RC_CONTINUE;
+        return true;
     default:
-        return RC_CONTINUE;
+        return true;
     }
 }
 
@@ -207,23 +202,23 @@ static bool racial_power_interpret_menu_keys(PlayerType *player_ptr, rc_type *rc
  * @brief メニューからの選択決定を処理
  * @param player_ptr プレイヤー情報への参照ポインタ
  * @param rc_ptr レイシャルパワー情報への参照ポインタ
- * @return キャンセルしたらRC_CANCEL、それ以外ならRC_CONTINUE
+ * @return キャンセルしたらfalse、それ以外ならtrue
  */
 static bool racial_power_select_by_menu(PlayerType *player_ptr, rc_type *rc_ptr)
 {
     if (!use_menu || rc_ptr->choice == ' ') {
-        return RC_CONTINUE;
+        return true;
     }
 
-    if (racial_power_interpret_menu_keys(player_ptr, rc_ptr)) {
-        return RC_CANCEL;
+    if (!racial_power_interpret_menu_keys(player_ptr, rc_ptr)) {
+        return false;
     }
 
     if (rc_ptr->menu_line > rc_ptr->power_count()) {
         rc_ptr->menu_line -= rc_ptr->power_count();
     }
 
-    return RC_CONTINUE;
+    return true;
 }
 
 /*!
@@ -243,6 +238,7 @@ static bool racial_power_interpret_choise(PlayerType *player_ptr, rc_type *rc_pt
         if (rc_ptr->page > rc_ptr->max_page) {
             rc_ptr->page = 0;
         }
+
         screen_load();
         screen_save();
         racial_power_display_list(player_ptr, rc_ptr);
@@ -299,19 +295,19 @@ static bool ask_invoke_racial_power(rc_type *rc_ptr)
 
     char tmp_val[160];
     (void)strnfmt(tmp_val, 78, _("%sを使いますか? ", "Use %s? "), rc_ptr->power_desc[rc_ptr->command_code].racial_name.data());
-    return get_check(tmp_val);
+    return input_check(tmp_val);
 }
 
 static void racial_power_display_explanation(PlayerType *player_ptr, rc_type *rc_ptr)
 {
     auto &rpi = rc_ptr->power_desc[rc_ptr->command_code];
 
-    term_erase(12, 21, 255);
-    term_erase(12, 20, 255);
-    term_erase(12, 19, 255);
-    term_erase(12, 18, 255);
-    term_erase(12, 17, 255);
-    term_erase(12, 16, 255);
+    term_erase(12, 21);
+    term_erase(12, 20);
+    term_erase(12, 19);
+    term_erase(12, 18);
+    term_erase(12, 17);
+    term_erase(12, 16);
     display_wrap_around(rpi.text, 62, 17, 15);
 
     prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);
@@ -327,7 +323,7 @@ static void racial_power_display_explanation(PlayerType *player_ptr, rc_type *rc
  * @brief レイシャルパワー選択処理のメインループ
  * @param player_ptr プレイヤー情報への参照ポインタ
  * @param rc_ptr レイシャルパワー情報への参照ポインタ
- * @return コマンド選択したらRC_CONTINUE、キャンセルしたらRC_CANCEL
+ * @return コマンド選択したらtrue、キャンセルしたらfalse
  */
 static bool racial_power_process_input(PlayerType *player_ptr, rc_type *rc_ptr)
 {
@@ -336,12 +332,17 @@ static bool racial_power_process_input(PlayerType *player_ptr, rc_type *rc_ptr)
     while (true) {
         if (rc_ptr->choice == ESCAPE) {
             rc_ptr->choice = ' ';
-        } else if (!get_com(rc_ptr->out_val, &rc_ptr->choice, false)) {
-            return RC_CANCEL;
+        } else {
+            const auto choice = input_command(rc_ptr->out_val);
+            if (!choice) {
+                return false;
+            }
+
+            rc_ptr->choice = *choice;
         }
 
-        if (racial_power_select_by_menu(player_ptr, rc_ptr) == RC_CANCEL) {
-            return RC_CANCEL;
+        if (!racial_power_select_by_menu(player_ptr, rc_ptr)) {
+            return false;
         }
 
         if (!rc_ptr->is_chosen && racial_power_interpret_choise(player_ptr, rc_ptr)) {
@@ -360,64 +361,58 @@ static bool racial_power_process_input(PlayerType *player_ptr, rc_type *rc_ptr)
         }
     }
 
-    return RC_CONTINUE;
+    return true;
 }
 
 /*!
  * @brief レイシャル/クラスパワー選択を処理
  * @param player_ptr プレイヤー情報への参照ポインタ
  * @param rc_ptr レイシャルパワー情報への参照ポインタ
- * @return コマンド選択したらRC_CONTINUE、キャンセルしたらRC_CANCEL
+ * @return コマンド選択したらtrue、キャンセルしたらfalse
  */
 static bool racial_power_select_power(PlayerType *player_ptr, rc_type *rc_ptr)
 {
     if (repeat_pull(&rc_ptr->command_code) && rc_ptr->command_code >= 0 && rc_ptr->command_code < rc_ptr->power_count()) {
-        return RC_CONTINUE;
+        return true;
     }
 
     screen_save();
-
     if (use_menu) {
         racial_power_display_list(player_ptr, rc_ptr);
     }
 
-    auto canceled = racial_power_process_input(player_ptr, rc_ptr) == RC_CANCEL;
-
+    const auto is_selected = racial_power_process_input(player_ptr, rc_ptr);
     screen_load();
-
-    if (canceled) {
-        return RC_CANCEL;
+    if (!is_selected) {
+        return false;
     }
 
     repeat_push(rc_ptr->command_code);
-    return RC_CONTINUE;
+    return true;
 }
 
 /*!
  * @brief レイシャルパワーの使用を試みる
  * @param player_ptr プレイヤー情報への参照ポインタ
  * @param rc_ptr レイシャルパワー情報への参照ポインタ
- * @details
- * 戻り値の代わりにrc_ptr->castに使用の有無を入れる。
+ * @return レイシャルパワーの使用有無
  */
-static void racial_power_cast_power(PlayerType *player_ptr, rc_type *rc_ptr)
+static bool racial_power_cast_power(PlayerType *player_ptr, rc_type *rc_ptr)
 {
     auto *rpi_ptr = &rc_ptr->power_desc[rc_ptr->command_code];
-
     switch (check_racial_level(player_ptr, rpi_ptr)) {
     case RACIAL_SUCCESS:
         if (rpi_ptr->number < 0) {
-            rc_ptr->cast = exe_racial_power(player_ptr, rpi_ptr->number);
-        } else {
-            rc_ptr->cast = exe_mutation_power(player_ptr, i2enum<PlayerMutationType>(rpi_ptr->number));
+            return exe_racial_power(player_ptr, rpi_ptr->number);
         }
-        break;
+
+        return exe_mutation_power(player_ptr, i2enum<PlayerMutationType>(rpi_ptr->number));
     case RACIAL_FAILURE:
-        rc_ptr->cast = true;
-        break;
+        return true;
     case RACIAL_CANCEL:
-        rc_ptr->cast = false;
-        break;
+        return false;
+    default:
+        THROW_EXCEPTION(std::logic_error, "Invalid racial level check!");
     }
 }
 
@@ -438,7 +433,6 @@ static bool racial_power_reduce_mana(PlayerType *player_ptr, rc_type *rc_ptr)
     }
 
     int actual_racial_cost = racial_cost / 2 + randint1(racial_cost / 2);
-
     if (player_ptr->csp >= actual_racial_cost) {
         player_ptr->csp -= actual_racial_cost;
     } else {
@@ -451,7 +445,7 @@ static bool racial_power_reduce_mana(PlayerType *player_ptr, rc_type *rc_ptr)
 }
 
 /*!
- * @brief レイシャル・パワーコマンドのメインルーチン / Allow user to choose a power (racial / mutation) to activate
+ * @brief レイシャル・パワーコマンドのメインルーチン
  * @param player_ptr プレイヤーへの参照ポインタ
  */
 void do_cmd_racial_power(PlayerType *player_ptr)
@@ -467,12 +461,9 @@ void do_cmd_racial_power(PlayerType *player_ptr)
     }
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
-
     auto tmp_r = rc_type(player_ptr);
     auto *rc_ptr = &tmp_r;
-
     switch_class_racial(player_ptr, rc_ptr);
-
     if (player_ptr->mimic_form != MimicKindType::NONE) {
         set_mimic_racial_command(player_ptr, rc_ptr);
     } else {
@@ -480,7 +471,6 @@ void do_cmd_racial_power(PlayerType *player_ptr)
     }
 
     select_mutation_racial(player_ptr, rc_ptr);
-
     if (rc_ptr->power_count() == 0) {
         msg_print(_("特殊能力はありません。", "You have no special powers."));
         return;
@@ -489,12 +479,12 @@ void do_cmd_racial_power(PlayerType *player_ptr)
     rc_ptr->max_page = 1 + (rc_ptr->power_count() - 1) / RC_PAGE_SIZE;
     rc_ptr->page = use_menu ? 0 : -1;
     racial_power_make_prompt(rc_ptr);
-
-    if (racial_power_select_power(player_ptr, rc_ptr) == RC_CONTINUE) {
-        racial_power_cast_power(player_ptr, rc_ptr);
+    auto should_cast = false;
+    if (racial_power_select_power(player_ptr, rc_ptr)) {
+        should_cast = racial_power_cast_power(player_ptr, rc_ptr);
     }
 
-    if (!rc_ptr->cast) {
+    if (!should_cast) {
         energy.reset_player_turn();
         return;
     }
@@ -503,6 +493,15 @@ void do_cmd_racial_power(PlayerType *player_ptr)
         return;
     }
 
-    set_bits(player_ptr->redraw, PR_HP | PR_MP);
-    set_bits(player_ptr->window_flags, PW_PLAYER | PW_SPELL);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    const auto &flags_mwrf = {
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
+    rfu.set_flags(flags_mwrf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags_swrf);
 }
index 191696d..e6cebff 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_racial_power(PlayerType *player_ptr);
index 21b856d..387c577 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-action/cmd-shoot.h"
+#include "cmd-action/cmd-shoot.h"
 #include "combat/shoot.h"
 #include "floor/floor-object.h"
 #include "inventory/inventory-slot-types.h"
@@ -53,22 +53,22 @@ void do_cmd_fire(PlayerType *player_ptr, SPELL_IDX snipe_type)
     }
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
-    const auto q = _("どれを撃ちますか? ", "Fire which item? ");
-    const auto s = _("発射されるアイテムがありません。", "You have nothing to fire.");
-    short item;
-    const auto *ammo_ptr = choose_object(player_ptr, &item, q, s, USE_INVEN | USE_FLOOR, TvalItemTester(player_ptr->tval_ammo));
+    constexpr auto q = _("どれを撃ちますか? ", "Fire which item? ");
+    constexpr auto s = _("発射されるアイテムがありません。", "You have nothing to fire.");
+    short i_idx;
+    const auto *ammo_ptr = choose_object(player_ptr, &i_idx, q, s, USE_INVEN | USE_FLOOR, TvalItemTester(player_ptr->tval_ammo));
     if (!ammo_ptr) {
         flush();
         return;
     }
 
-    exe_fire(player_ptr, item, item_ptr, snipe_type);
+    exe_fire(player_ptr, i_idx, item_ptr, snipe_type);
     if (!player_ptr->is_fired || !PlayerClass(player_ptr).equals(PlayerClassType::SNIPER)) {
         return;
     }
 
     if (snipe_type == SP_AWAY) {
-        auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+        auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
         teleport_player(player_ptr, 10 + (sniper_data->concent * 2), TELEPORT_SPONTANEOUS);
     }
 
index ae6e94a..ffd6e2f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3eb24bc..829ed11 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 魔法のインターフェイスと発動 / Purpose: Do everything for each spell
  * @date 2013/12/31
  * @author
@@ -12,8 +12,6 @@
 #include "cmd-action/cmd-mind.h"
 #include "cmd-io/cmd-dump.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "floor/floor-object.h"
@@ -62,6 +60,7 @@
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "timed-effect/player-blindness.h"
@@ -70,6 +69,7 @@
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
 #include "view/display-util.h"
+#include <string_view>
 
 static const int extra_magic_gain_exp = 4;
 
@@ -305,20 +305,13 @@ static bool spell_okay(PlayerType *player_ptr, int spell, bool learned, bool stu
  * The "known" should be TRUE for cast/pray, FALSE for study
  * </pre>
  */
-static int get_spell(PlayerType *player_ptr, SPELL_IDX *sn, concptr prompt, OBJECT_SUBTYPE_VALUE sval, bool learned, int16_t use_realm)
+static int get_spell(PlayerType *player_ptr, SPELL_IDX *sn, std::string_view prompt_verb, int sval, bool learned, int16_t use_realm)
 {
     int i;
     SPELL_IDX spell = -1;
     int num = 0;
-    SPELL_IDX spells[64];
-    bool flag, redraw, okay;
-    char choice;
-    char out_val[160];
-    concptr p;
+    SPELL_IDX spells[64]{};
     COMMAND_CODE code;
-#ifdef JP
-    char jverb_buf[128];
-#endif
     int menu_line = (use_menu ? 1 : 0);
 
     /* Get the spell, if available */
@@ -331,8 +324,6 @@ static int get_spell(PlayerType *player_ptr, SPELL_IDX *sn, concptr prompt, OBJE
         }
     }
 
-    p = spell_category_name(mp_ptr->spell_book);
-
     /* Extract spells */
     for (spell = 0; spell < 32; spell++) {
         /* Check for this spell */
@@ -343,7 +334,7 @@ static int get_spell(PlayerType *player_ptr, SPELL_IDX *sn, concptr prompt, OBJE
     }
 
     /* Assume no usable spells */
-    okay = false;
+    auto okay = false;
 
     /* Assume no spells available */
     (*sn) = -2;
@@ -376,26 +367,32 @@ static int get_spell(PlayerType *player_ptr, SPELL_IDX *sn, concptr prompt, OBJE
     /* Assume cancelled */
     *sn = (-1);
 
-    flag = false;
-    redraw = false;
+    auto flag = false;
+    auto redraw = false;
 
-    player_ptr->window_flags |= (PW_SPELL);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::SPELL);
     handle_stuff(player_ptr);
 
-    /* Build a prompt (accept all spells) */
+    const auto spell_category = spell_category_name(mp_ptr->spell_book);
+    constexpr auto fmt = _("(%s^:%c-%c, '*'で一覧, ESCで中断) どの%sを%s^ますか? ", "(%s^s %c-%c, *=List, ESC=exit) %s^ which %s? ");
 #ifdef JP
-    jverb(prompt, jverb_buf, JVERB_AND);
-    (void)strnfmt(out_val, 78, "(%s^:%c-%c, '*'で一覧, ESCで中断) どの%sを%s^ますか? ", p, I2A(0), I2A(num - 1), p, jverb_buf);
+    const auto verb = conjugate_jverb(prompt_verb, JVerbConjugationType::AND);
+    const auto prompt = format(fmt, spell_category.data(), I2A(0), I2A(num - 1), spell_category.data(), verb.data());
 #else
-    (void)strnfmt(out_val, 78, "(%s^s %c-%c, *=List, ESC=exit) %s^ which %s? ", p, I2A(0), I2A(num - 1), prompt, p);
+    const auto prompt = format(fmt, spell_category.data(), I2A(0), I2A(num - 1), prompt_verb.data(), spell_category.data());
 #endif
 
-    choice = (always_show_list || use_menu) ? ESCAPE : 1;
+    auto choice = (always_show_list || use_menu) ? ESCAPE : '\1';
     while (!flag) {
         if (choice == ESCAPE) {
             choice = ' ';
-        } else if (!get_com(out_val, &choice, true)) {
-            break;
+        } else {
+            const auto new_choice = input_command(prompt, true);
+            if (!new_choice) {
+                break;
+            }
+
+            choice = *new_choice;
         }
 
         auto should_redraw_cursor = true;
@@ -480,9 +477,9 @@ static int get_spell(PlayerType *player_ptr, SPELL_IDX *sn, concptr prompt, OBJE
         if (!spell_okay(player_ptr, spell, learned, false, use_realm)) {
             bell();
 #ifdef JP
-            msg_format("その%sを%sことはできません。", p, prompt);
+            msg_format("その%sを%sことはできません。", spell_category.data(), prompt_verb.data());
 #else
-            msg_format("You may not %s that %s.", prompt, p);
+            msg_format("You may not %s that %s.", prompt.data(), spell_category.data());
 #endif
 
             continue;
@@ -496,7 +493,7 @@ static int get_spell(PlayerType *player_ptr, SPELL_IDX *sn, concptr prompt, OBJE
         screen_load();
     }
 
-    player_ptr->window_flags |= (PW_SPELL);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::SPELL);
     handle_stuff(player_ptr);
 
     /* Abort if needed */
@@ -579,7 +576,6 @@ static FuncItemTester get_learnable_spellbook_tester(PlayerType *player_ptr)
  */
 void do_cmd_browse(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
     SPELL_IDX spell = -1;
     int num = 0;
 
@@ -604,11 +600,13 @@ void do_cmd_browse(PlayerType *player_ptr)
     /* Restrict choices to "useful" books */
     auto item_tester = get_learnable_spellbook_tester(player_ptr);
 
-    const auto q = _("どの本を読みますか? ", "Browse which book? ");
-    const auto s = _("読める本がない。", "You have no books that you can read.");
-    const auto *o_ptr = choose_object(player_ptr, &item, q, s, USE_INVEN | USE_FLOOR | (pc.equals(PlayerClassType::FORCETRAINER) ? USE_FORCE : 0), item_tester);
+    constexpr auto q = _("どの本を読みますか? ", "Browse which book? ");
+    constexpr auto s = _("読める本がない。", "You have no books that you can read.");
+    constexpr auto options = USE_INVEN | USE_FLOOR;
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options | (pc.equals(PlayerClassType::FORCETRAINER) ? USE_FORCE : 0), item_tester);
     if (o_ptr == nullptr) {
-        if (item == INVEN_FORCE) /* the_force */
+        if (i_idx == INVEN_FORCE) /* the_force */
         {
             do_cmd_mind_browse(player_ptr);
             return;
@@ -618,7 +616,7 @@ void do_cmd_browse(PlayerType *player_ptr)
 
     /* Access the item's sval */
     const auto tval = o_ptr->bi_key.tval();
-    const auto sval = o_ptr->bi_key.sval().value();
+    const auto sval = *o_ptr->bi_key.sval();
     short use_realm = tval2realm(tval);
 
     /* Track the object kind */
@@ -663,13 +661,13 @@ void do_cmd_browse(PlayerType *player_ptr)
         }
 
         /* Clear lines, position cursor  (really should use strlen here) */
-        term_erase(14, 14, 255);
-        term_erase(14, 13, 255);
-        term_erase(14, 12, 255);
-        term_erase(14, 11, 255);
+        term_erase(14, 14);
+        term_erase(14, 13);
+        term_erase(14, 12);
+        term_erase(14, 11);
 
         const auto spell_desc = exe_spell(player_ptr, use_realm, spell, SpellProcessType::DESCRIPTION);
-        display_wrap_around(spell_desc.value(), 62, 11, 15);
+        display_wrap_around(*spell_desc, 62, 11, 15);
     }
     screen_load();
 }
@@ -682,8 +680,6 @@ void do_cmd_browse(PlayerType *player_ptr)
 static void change_realm2(PlayerType *player_ptr, int16_t next_realm)
 {
     int i, j = 0;
-    char tmp[80];
-
     for (i = 0; i < 64; i++) {
         player_ptr->spell_order[j] = player_ptr->spell_order[i];
         if (player_ptr->spell_order[i] < 32) {
@@ -701,13 +697,17 @@ static void change_realm2(PlayerType *player_ptr, int16_t next_realm)
     player_ptr->spell_worked2 = 0L;
     player_ptr->spell_forgotten2 = 0L;
 
-    strnfmt(tmp, sizeof(tmp), _("魔法の領域を%sから%sに変更した。", "changed magic realm from %s to %s."), realm_names[player_ptr->realm2], realm_names[next_realm]);
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, tmp);
+    constexpr auto fmt_realm = _("魔法の領域を%sから%sに変更した。", "changed magic realm from %s to %s.");
+    const auto mes = format(fmt_realm, realm_names[player_ptr->realm2], realm_names[next_realm]);
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, mes);
     player_ptr->old_realm |= 1U << (player_ptr->realm2 - 1);
     player_ptr->realm2 = next_realm;
 
-    player_ptr->update |= (PU_REORDER);
-    player_ptr->update |= (PU_SPELLS);
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::REORDER,
+        StatusRecalculatingFlag::SPELLS,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     handle_stuff(player_ptr);
 
     /* Load an autopick preference file */
@@ -725,7 +725,7 @@ void do_cmd_study(PlayerType *player_ptr)
 
     /* Spells of realm2 will have an increment of +32 */
     SPELL_IDX spell = -1;
-    const auto p = spell_category_name(mp_ptr->spell_book);
+    const auto spell_category = spell_category_name(mp_ptr->spell_book);
     if (!player_ptr->realm1) {
         msg_print(_("本を読むことができない!", "You cannot read books!"));
         return;
@@ -736,7 +736,7 @@ void do_cmd_study(PlayerType *player_ptr)
     }
 
     if (player_ptr->new_spells == 0) {
-        msg_format(_("新しい%sを覚えることはできない!", "You cannot learn any new %ss!"), p);
+        msg_format(_("新しい%sを覚えることはできない!", "You cannot learn any new %ss!"), spell_category.data());
         return;
     }
 
@@ -744,12 +744,12 @@ void do_cmd_study(PlayerType *player_ptr)
 
 #ifdef JP
     if (player_ptr->new_spells < 10) {
-        msg_format("あと %d つの%sを学べる。", player_ptr->new_spells, p);
+        msg_format("あと %d つの%sを学べる。", player_ptr->new_spells, spell_category.data());
     } else {
-        msg_format("あと %d 個の%sを学べる。", player_ptr->new_spells, p);
+        msg_format("あと %d 個の%sを学べる。", player_ptr->new_spells, spell_category.data());
     }
 #else
-    msg_format("You can learn %d new %s%s.", player_ptr->new_spells, p, (player_ptr->new_spells == 1 ? "" : "s"));
+    msg_format("You can learn %d new %s%s.", player_ptr->new_spells, spell_category.data(), (player_ptr->new_spells == 1 ? "" : "s"));
 #endif
 
     msg_print(nullptr);
@@ -757,21 +757,21 @@ void do_cmd_study(PlayerType *player_ptr)
     /* Restrict choices to "useful" books */
     auto item_tester = get_learnable_spellbook_tester(player_ptr);
 
-    const auto q = _("どの本から学びますか? ", "Study which book? ");
-    const auto s = _("読める本がない。", "You have no books that you can read.");
+    constexpr auto q = _("どの本から学びますか? ", "Study which book? ");
+    constexpr auto s = _("読める本がない。", "You have no books that you can read.");
 
-    short item;
-    const auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), item_tester);
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), item_tester);
     if (o_ptr == nullptr) {
         return;
     }
 
     const auto tval = o_ptr->bi_key.tval();
-    const auto sval = o_ptr->bi_key.sval().value();
+    const auto sval = *o_ptr->bi_key.sval();
     if (tval == get_realm2_book(player_ptr)) {
         increment = 32;
     } else if (tval != get_realm1_book(player_ptr)) {
-        if (!get_check(_("本当に魔法の領域を変更しますか?", "Really, change magic realm? "))) {
+        if (!input_check(_("本当に魔法の領域を変更しますか?", "Really, change magic realm? "))) {
             return;
         }
 
@@ -821,7 +821,7 @@ void do_cmd_study(PlayerType *player_ptr)
 
     /* Nothing to study */
     if (spell < 0) {
-        msg_format(_("その本には学ぶべき%sがない。", "You cannot learn any %ss in that book."), p);
+        msg_format(_("その本には学ぶべき%sがない。", "You cannot learn any %ss in that book."), spell_category.data());
 
         /* Abort */
         return;
@@ -848,17 +848,18 @@ void do_cmd_study(PlayerType *player_ptr)
 
     if (learned) {
         auto max_exp = PlayerSkill::spell_exp_at((spell < 32) ? PlayerSkillRank::MASTER : PlayerSkillRank::EXPERT);
-        int old_exp = player_ptr->spell_exp[spell];
-        const auto spell_name = exe_spell(player_ptr, increment ? player_ptr->realm2 : player_ptr->realm1, spell % 32, SpellProcessType::NAME);
+        const auto old_exp = player_ptr->spell_exp[spell];
+        const auto realm = increment ? player_ptr->realm2 : player_ptr->realm1;
+        const auto spell_name = exe_spell(player_ptr, realm, spell % 32, SpellProcessType::NAME);
 
         if (old_exp >= max_exp) {
-            msg_format(_("その%sは完全に使いこなせるので学ぶ必要はない。", "You don't need to study this %s anymore."), p);
+            msg_format(_("その%sは完全に使いこなせるので学ぶ必要はない。", "You don't need to study this %s anymore."), spell_category.data());
             return;
         }
 #ifdef JP
-        if (!get_check(format("%sの%sをさらに学びます。よろしいですか?", spell_name->data(), p)))
+        if (!input_check(format("%sの%sをさらに学びます。よろしいですか?", spell_name->data(), spell_category.data())))
 #else
-        if (!get_check(format("You will study a %s of %s again. Are you sure? ", p, spell_name->data())))
+        if (!input_check(format("You will study a %s of %s again. Are you sure? ", spell_category.data(), spell_name->data())))
 #endif
         {
             return;
@@ -881,16 +882,16 @@ void do_cmd_study(PlayerType *player_ptr)
         player_ptr->spell_order[i++] = spell;
 
         /* Mention the result */
-        const auto spell_name = exe_spell(player_ptr, increment ? player_ptr->realm2 : player_ptr->realm1, spell % 32, SpellProcessType::NAME);
+        const auto realm = increment ? player_ptr->realm2 : player_ptr->realm1;
+        const auto spell_name = exe_spell(player_ptr, realm, spell % 32, SpellProcessType::NAME);
 #ifdef JP
-        /* 英日切り替え機能に対応 */
         if (mp_ptr->spell_book == ItemKindType::MUSIC_BOOK) {
             msg_format("%sを学んだ。", spell_name->data());
         } else {
-            msg_format("%sの%sを学んだ。", spell_name->data(), p);
+            msg_format("%sの%sを学んだ。", spell_name->data(), spell_category.data());
         }
 #else
-        msg_format("You have learned the %s of %s.", p, spell_name->data());
+        msg_format("You have learned the %s of %s.", spell_category.data(), spell_name->data());
 #endif
     }
 
@@ -916,12 +917,10 @@ void do_cmd_study(PlayerType *player_ptr)
     /* One less spell available */
     player_ptr->learned_spells++;
 
-    /* Update Study */
-    player_ptr->update |= (PU_SPELLS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::SPELLS);
     update_creature(player_ptr);
-
-    /* Redraw object recall */
-    player_ptr->window_flags |= (PW_ITEM_KNOWLEDGTE);
+    rfu.set_flag(SubWindowRedrawingFlag::ITEM_KNOWLEDGE);
 }
 
 /*!
@@ -988,14 +987,14 @@ bool do_cmd_cast(PlayerType *player_ptr)
     }
 
     const auto prayer = spell_category_name(mp_ptr->spell_book);
-    const auto q = _("どの呪文書を使いますか? ", "Use which book? ");
-    const auto s = _("呪文書がない!", "You have no spell books!");
+    constexpr auto q = _("どの呪文書を使いますか? ", "Use which book? ");
+    constexpr auto s = _("呪文書がない!", "You have no spell books!");
     auto item_tester = get_castable_spellbook_tester(player_ptr);
     const auto options = USE_INVEN | USE_FLOOR | (pc.equals(PlayerClassType::FORCETRAINER) ? USE_FORCE : 0);
-    short item;
-    const auto *o_ptr = choose_object(player_ptr, &item, q, s, options, item_tester);
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, item_tester);
     if (o_ptr == nullptr) {
-        if (item == INVEN_FORCE) {
+        if (i_idx == INVEN_FORCE) {
             do_cmd_mind(player_ptr);
             return true; //!< 錬気キャンセル時の処理がない
         }
@@ -1004,7 +1003,7 @@ bool do_cmd_cast(PlayerType *player_ptr)
     }
 
     const auto tval = o_ptr->bi_key.tval();
-    const auto sval = o_ptr->bi_key.sval().value();
+    const auto sval = *o_ptr->bi_key.sval();
     if (!is_every_magic && (tval == get_realm2_book(player_ptr))) {
         increment = 32;
     }
@@ -1029,14 +1028,14 @@ bool do_cmd_cast(PlayerType *player_ptr)
                                                                    : "唱える"),
             sval, true, realm)) {
         if (spell == -2) {
-            msg_format("その本には知っている%sがない。", prayer);
+            msg_format("その本には知っている%sがない。", prayer.data());
         }
         return false;
     }
 #else
     if (!get_spell(player_ptr, &spell, ((mp_ptr->spell_book == ItemKindType::LIFE_BOOK) ? "recite" : "cast"), sval, true, realm)) {
         if (spell == -2) {
-            msg_format("You don't know any %ss in that book.", prayer);
+            msg_format("You don't know any %ss in that book.", prayer.data());
         }
         return false;
     }
@@ -1067,12 +1066,12 @@ bool do_cmd_cast(PlayerType *player_ptr)
 
         /* Warning */
 #ifdef JP
-        msg_format("その%sを%sのに十分なマジックポイントがない。", prayer,
+        msg_format("その%sを%sのに十分なマジックポイントがない。", prayer.data(),
             ((mp_ptr->spell_book == ItemKindType::LIFE_BOOK)      ? "詠唱する"
                 : (mp_ptr->spell_book == ItemKindType::LIFE_BOOK) ? "歌う"
                                                                   : "唱える"));
 #else
-        msg_format("You do not have enough mana to %s this %s.", ((mp_ptr->spell_book == ItemKindType::LIFE_BOOK) ? "recite" : "cast"), prayer);
+        msg_format("You do not have enough mana to %s this %s.", ((mp_ptr->spell_book == ItemKindType::LIFE_BOOK) ? "recite" : "cast"), prayer.data());
 #endif
 
         if (!over_exert) {
@@ -1080,7 +1079,7 @@ bool do_cmd_cast(PlayerType *player_ptr)
         }
 
         /* Verify */
-        if (!get_check_strict(player_ptr, _("それでも挑戦しますか? ", "Attempt it anyway? "), CHECK_OKAY_CANCEL)) {
+        if (!input_check_strict(player_ptr, _("それでも挑戦しますか? ", "Attempt it anyway? "), UserCheck::OKAY_CANCEL)) {
             return false;
         }
     }
@@ -1094,7 +1093,7 @@ bool do_cmd_cast(PlayerType *player_ptr)
             flush();
         }
 
-        msg_format(_("%sをうまく唱えられなかった!", "You failed to get the %s off!"), prayer);
+        msg_format(_("%sをうまく唱えられなかった!", "You failed to get the %s off!"), prayer.data());
         sound(SOUND_FAIL);
 
         switch (realm) {
@@ -1184,7 +1183,7 @@ bool do_cmd_cast(PlayerType *player_ptr)
             }
 
             gain_exp(player_ptr, e * s_ptr->slevel);
-            player_ptr->window_flags |= (PW_ITEM_KNOWLEDGTE);
+            RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::ITEM_KNOWLEDGE);
 
             switch (realm) {
             case REALM_LIFE:
@@ -1320,7 +1319,8 @@ bool do_cmd_cast(PlayerType *player_ptr)
     } else {
         over_exerted = true;
     }
-    player_ptr->redraw |= (PR_MP);
+
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
 
     /* Over-exert the player */
     if (over_exerted) {
@@ -1364,8 +1364,10 @@ bool do_cmd_cast(PlayerType *player_ptr)
         }
     }
 
-    player_ptr->window_flags |= (PW_PLAYER);
-    player_ptr->window_flags |= (PW_SPELL);
-
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     return true; //!< @note 詠唱した
 }
index 6ba38d1..43899e2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
index fa10e48..adce947 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-action/cmd-travel.h"
+#include "cmd-action/cmd-travel.h"
 #include "action/travel-execution.h"
 #include "core/asking-player.h"
 #include "floor/cave.h"
 static int travel_flow_cost(PlayerType *player_ptr, POSITION y, POSITION x)
 {
     int cost = 1;
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    if (f_ptr->flags.has(TerrainCharacteristics::AVOID_RUN)) {
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
+    if (terrain.flags.has(TerrainCharacteristics::AVOID_RUN)) {
         cost += 1;
     }
 
-    if (f_ptr->flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP }) && !player_ptr->levitation) {
+    if (terrain.flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP }) && !player_ptr->levitation) {
         cost += 5;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::LAVA)) {
+    if (terrain.flags.has(TerrainCharacteristics::LAVA)) {
         int lava = 2;
         if (!has_resist_fire(player_ptr)) {
             lava *= 2;
@@ -46,19 +47,19 @@ static int travel_flow_cost(PlayerType *player_ptr, POSITION y, POSITION x)
             lava *= 2;
         }
 
-        if (f_ptr->flags.has(TerrainCharacteristics::DEEP)) {
+        if (terrain.flags.has(TerrainCharacteristics::DEEP)) {
             lava *= 2;
         }
 
         cost += lava;
     }
 
-    if (g_ptr->is_mark()) {
-        if (f_ptr->flags.has(TerrainCharacteristics::DOOR)) {
+    if (grid.is_mark()) {
+        if (terrain.flags.has(TerrainCharacteristics::DOOR)) {
             cost += 1;
         }
 
-        if (f_ptr->flags.has(TerrainCharacteristics::TRAP)) {
+        if (terrain.flags.has(TerrainCharacteristics::TRAP)) {
             cost += 10;
         }
     }
@@ -74,41 +75,47 @@ static int travel_flow_cost(PlayerType *player_ptr, POSITION y, POSITION x)
  * @param n 現在のコスト
  * @param wall プレイヤーが壁の中にいるならばTRUE
  */
-static void travel_flow_aux(PlayerType *player_ptr, POSITION y, POSITION x, int n, bool wall)
+static void travel_flow_aux(PlayerType *player_ptr, const Pos2D pos, int n, bool wall)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    if (!in_bounds(floor_ptr, y, x)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &grid = floor.get_grid(pos);
+    auto &terrain = grid.get_terrain();
+    if (!in_bounds(&floor, pos.y, pos.x)) {
         return;
     }
 
-    if (floor_ptr->dun_level > 0 && !(g_ptr->info & CAVE_KNOWN)) {
+    if (floor.dun_level > 0 && !(grid.info & CAVE_KNOWN)) {
         return;
     }
 
-    int add_cost = 1;
-    int from_wall = (n / TRAVEL_UNABLE);
-    if (f_ptr->flags.has(TerrainCharacteristics::WALL) || f_ptr->flags.has(TerrainCharacteristics::CAN_DIG) || (f_ptr->flags.has(TerrainCharacteristics::DOOR) && floor_ptr->grid_array[y][x].mimic) || (f_ptr->flags.has_not(TerrainCharacteristics::MOVE) && f_ptr->flags.has(TerrainCharacteristics::CAN_FLY) && !player_ptr->levitation)) {
+    auto add_cost = 1;
+    auto from_wall = (n / TRAVEL_UNABLE);
+    auto is_wall = terrain.flags.has_any_of({ TerrainCharacteristics::WALL, TerrainCharacteristics::CAN_DIG });
+    is_wall |= terrain.flags.has(TerrainCharacteristics::DOOR) && (grid.mimic > 0);
+    auto can_move = terrain.flags.has_not(TerrainCharacteristics::MOVE);
+    can_move &= terrain.flags.has(TerrainCharacteristics::CAN_FLY);
+    can_move &= !player_ptr->levitation;
+    if (is_wall || can_move) {
         if (!wall || !from_wall) {
             return;
         }
 
         add_cost += TRAVEL_UNABLE;
     } else {
-        add_cost = travel_flow_cost(player_ptr, y, x);
+        add_cost = travel_flow_cost(player_ptr, pos.y, pos.x);
     }
 
-    int base_cost = (n % TRAVEL_UNABLE);
-    int cost = base_cost + add_cost;
-    if (travel.cost[y][x] <= cost) {
+    auto base_cost = (n % TRAVEL_UNABLE);
+    auto cost = base_cost + add_cost;
+    auto &travel_cost = travel.cost[pos.y][pos.x];
+    if (travel_cost <= cost) {
         return;
     }
 
-    travel.cost[y][x] = cost;
-    int old_head = flow_head;
-    temp2_y[flow_head] = y;
-    temp2_x[flow_head] = x;
+    travel_cost = cost;
+    auto old_head = flow_head;
+    temp2_y[flow_head] = pos.y;
+    temp2_x[flow_head] = pos.x;
     if (++flow_head == MAX_SHORT) {
         flow_head = 0;
     }
@@ -124,26 +131,22 @@ static void travel_flow_aux(PlayerType *player_ptr, POSITION y, POSITION x, int
  * @param ty 目標地点のY座標
  * @param tx 目標地点のX座標
  */
-static void travel_flow(PlayerType *player_ptr, POSITION ty, POSITION tx)
+static void travel_flow(PlayerType *player_ptr, const Pos2D pos)
 {
     flow_head = flow_tail = 0;
-    bool wall = false;
-    auto *f_ptr = &terrains_info[player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].feat];
-    if (f_ptr->flags.has_not(TerrainCharacteristics::MOVE)) {
-        wall = true;
-    }
+    const auto &terrain = player_ptr->current_floor_ptr->get_grid(player_ptr->get_position()).get_terrain();
+    auto wall = terrain.flags.has(TerrainCharacteristics::MOVE);
 
-    travel_flow_aux(player_ptr, ty, tx, 0, wall);
-    POSITION x, y;
+    travel_flow_aux(player_ptr, pos, 0, wall);
     while (flow_head != flow_tail) {
-        y = temp2_y[flow_tail];
-        x = temp2_x[flow_tail];
+        const Pos2D pos_flow(temp2_y[flow_tail], temp2_x[flow_tail]);
         if (++flow_tail == MAX_SHORT) {
             flow_tail = 0;
         }
 
-        for (DIRECTION d = 0; d < 8; d++) {
-            travel_flow_aux(player_ptr, y + ddy_ddd[d], x + ddx_ddd[d], travel.cost[y][x], wall);
+        for (auto d = 0; d < 8; d++) {
+            const Pos2D pos_neighbor(pos_flow.y + ddy_ddd[d], pos_flow.x + ddx_ddd[d]);
+            travel_flow_aux(player_ptr, pos_neighbor, travel.cost[pos_flow.y][pos_flow.x], wall);
         }
     }
 
@@ -155,38 +158,42 @@ static void travel_flow(PlayerType *player_ptr, POSITION ty, POSITION tx)
  */
 void do_cmd_travel(PlayerType *player_ptr)
 {
-    POSITION x, y;
-    if ((travel.x != 0) && (travel.y != 0) && (travel.x != player_ptr->x) && (travel.y != player_ptr->y) && get_check(_("トラベルを継続しますか?", "Do you continue to travel? "))) {
+    int x, y;
+    if ((travel.x != 0) && (travel.y != 0) && (travel.x != player_ptr->x) && (travel.y != player_ptr->y) && input_check(_("トラベルを継続しますか?", "Do you continue to travel? "))) {
         y = travel.y;
         x = travel.x;
     } else if (!tgt_pt(player_ptr, &x, &y)) {
         return;
     }
 
-    if ((x == player_ptr->x) && (y == player_ptr->y)) {
+    const Pos2D pos(y, x);
+    if (player_ptr->is_located_at(pos)) {
         msg_print(_("すでにそこにいます!", "You are already there!!"));
         return;
     }
 
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    TerrainType *f_ptr;
-    f_ptr = &terrains_info[floor_ptr->grid_array[y][x].feat];
-    if ((floor_ptr->grid_array[y][x].info & CAVE_MARK) && (f_ptr->flags.has(TerrainCharacteristics::WALL) || f_ptr->flags.has(TerrainCharacteristics::CAN_DIG) || (f_ptr->flags.has(TerrainCharacteristics::DOOR) && floor_ptr->grid_array[y][x].mimic))) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.get_grid(pos);
+    const auto &terrain = grid.get_terrain();
+    const auto is_marked = any_bits(grid.info, CAVE_MARK);
+    const auto is_wall = terrain.flags.has_any_of({ TerrainCharacteristics::WALL, TerrainCharacteristics::CAN_DIG });
+    const auto is_door = terrain.flags.has(TerrainCharacteristics::DOOR) && (grid.mimic > 0);
+    if (is_marked && (is_wall || is_door)) {
         msg_print(_("そこには行くことができません!", "You cannot travel there!"));
         return;
     }
 
     forget_travel_flow(player_ptr->current_floor_ptr);
-    travel_flow(player_ptr, y, x);
+    travel_flow(player_ptr, pos);
     travel.x = x;
     travel.y = y;
     travel.run = 255;
     travel.dir = 0;
-    POSITION dx = abs(player_ptr->x - x);
-    POSITION dy = abs(player_ptr->y - y);
-    POSITION sx = ((x == player_ptr->x) || (dx < dy)) ? 0 : ((x > player_ptr->x) ? 1 : -1);
-    POSITION sy = ((y == player_ptr->y) || (dy < dx)) ? 0 : ((y > player_ptr->y) ? 1 : -1);
-    for (int i = 1; i <= 9; i++) {
+    auto dx = std::abs(player_ptr->x - x);
+    auto dy = std::abs(player_ptr->y - y);
+    auto sx = ((x == player_ptr->x) || (dx < dy)) ? 0 : ((x > player_ptr->x) ? 1 : -1);
+    auto sy = ((y == player_ptr->y) || (dy < dx)) ? 0 : ((y > player_ptr->y) ? 1 : -1);
+    for (auto i = 1; i <= 9; i++) {
         if ((sx == ddx[i]) && (sy == ddy[i])) {
             travel.dir = i;
         }
index d4a34b6..2c0633a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_travel(PlayerType *player_ptr);
index b3ec8c8..98c0246 100644 (file)
@@ -1,8 +1,7 @@
-#include "cmd-action/cmd-tunnel.h"
+#include "cmd-action/cmd-tunnel.h"
 #include "action/tunnel-execution.h"
 #include "cmd-action/cmd-attack.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "floor/geometry.h"
 #include "grid/grid.h"
 #include "io/input-key-requester.h"
@@ -15,6 +14,7 @@
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/target-getter.h"
 #include "util/bit-flags-calculator.h"
  */
 void do_cmd_tunnel(PlayerType *player_ptr)
 {
-    bool more = false;
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
 
     if (command_arg) {
         command_rep = command_arg - 1;
-        player_ptr->redraw |= PR_ACTION;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
         command_arg = 0;
     }
 
-    DIRECTION dir;
-    if (!get_rep_dir(player_ptr, &dir, false)) {
-        if (!more) {
-            disturb(player_ptr, false, false);
-        }
-
+    int dir;
+    if (!get_rep_dir(player_ptr, &dir)) {
+        disturb(player_ptr, false, false);
         return;
     }
 
-    POSITION y = player_ptr->y + ddy[dir];
-    POSITION x = player_ptr->x + ddx[dir];
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    FEAT_IDX feat = g_ptr->get_feat_mimic();
-    if (terrains_info[feat].flags.has(TerrainCharacteristics::DOOR)) {
+    auto more = false;
+    const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain_mimic = grid.get_terrain_mimic();
+    if (terrain_mimic.flags.has(TerrainCharacteristics::DOOR)) {
         msg_print(_("ドアは掘れない。", "You cannot tunnel through doors."));
-    } else if (terrains_info[feat].flags.has_not(TerrainCharacteristics::TUNNEL)) {
+    } else if (terrain_mimic.flags.has_not(TerrainCharacteristics::TUNNEL)) {
         msg_print(_("そこは掘れない。", "You can't tunnel through that."));
-    } else if (g_ptr->m_idx) {
+    } else if (grid.m_idx) {
         PlayerEnergy(player_ptr).set_player_turn_energy(100);
         msg_print(_("モンスターが立ちふさがっている!", "There is a monster in the way!"));
-        do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+        do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
     } else {
-        more = exe_tunnel(player_ptr, y, x);
+        more = exe_tunnel(player_ptr, pos.y, pos.x);
     }
 
     if (!more) {
index 264ba96..2e6c328 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_tunnel(PlayerType *player_ptr);
index 7e15692..617ef99 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 町の施設処理 / Building commands
  * @date 2013/12/23
  * @author
@@ -17,8 +17,6 @@
 #include "cmd-building/cmd-inn.h"
 #include "cmd-io/cmd-dump.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/scores.h"
 #include "core/show-file.h"
 #include "core/special-internal-keys.h"
 #include "spell-kind/spells-perception.h"
 #include "spell-kind/spells-world.h"
 #include "spell/spells-status.h"
+#include "system/angband-exceptions.h"
+#include "system/angband-system.h"
 #include "system/building-type-definition.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
@@ -84,178 +85,184 @@ bool reinit_wilderness = false;
 static void town_history(PlayerType *player_ptr)
 {
     screen_save();
-    (void)show_file(player_ptr, true, _("jbldg.txt", "bldg.txt"), nullptr, 0, 0);
+    (void)show_file(player_ptr, true, _("jbldg.txt", "bldg.txt"), 0, 0);
     screen_load();
 }
 
 /*!
- * @brief 施設の処理実行メインルーチン / Execute a building command
+ * @brief 施設の処理実行メインルーチン
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param bldg 施設構造体の参照ポインタ
  * @param i 実行したい施設のサービステーブルの添字
+ * @return 施設から別フロアへ移動するか否か (アリーナ/モンスター闘技場のみtrue)
  */
-static void bldg_process_command(PlayerType *player_ptr, building_type *bldg, int i)
+static bool bldg_process_command(PlayerType *player_ptr, building_type *bldg, int i)
 {
     msg_flag = false;
     msg_erase();
-
-    PRICE bcost;
-    if (is_owner(player_ptr, bldg)) {
-        bcost = bldg->member_costs[i];
-    } else {
-        bcost = bldg->other_costs[i];
-    }
-
-    /* action restrictions */
-    if (((bldg->action_restr[i] == 1) && !is_member(player_ptr, bldg)) || ((bldg->action_restr[i] == 2) && !is_owner(player_ptr, bldg))) {
+    const auto can_be_owner = is_owner(player_ptr, bldg);
+    const auto building_cost = can_be_owner ? bldg->member_costs[i] : bldg->other_costs[i];
+    if (((bldg->action_restr[i] == 1) && !is_member(player_ptr, bldg)) || ((bldg->action_restr[i] == 2) && !can_be_owner)) {
         msg_print(_("それを選択する権利はありません!", "You have no right to choose that!"));
-        return;
+        return false;
     }
 
-    auto bact = bldg->actions[i];
-    if ((bact != BACT_RECHARGE) && (((bldg->member_costs[i] > player_ptr->au) && is_owner(player_ptr, bldg)) || ((bldg->other_costs[i] > player_ptr->au) && !is_owner(player_ptr, bldg)))) {
+    const auto building_action = bldg->actions[i];
+    if ((building_action != BACT_RECHARGE) && (((bldg->member_costs[i] > player_ptr->au) && can_be_owner) || ((bldg->other_costs[i] > player_ptr->au) && !can_be_owner))) {
         msg_print(_("お金が足りません!", "You do not have the gold!"));
-        return;
+        return false;
     }
 
-    bool paid = false;
-    switch (bact) {
+    switch (building_action) {
     case BACT_NOTHING:
         /* Do nothing */
-        break;
+        return false;
     case BACT_RESEARCH_ITEM:
-        paid = identify_fully(player_ptr, false);
-        break;
+        if (identify_fully(player_ptr, false)) {
+            player_ptr->au -= building_cost;
+        }
+
+        return false;
     case BACT_TOWN_HISTORY:
         town_history(player_ptr);
-        break;
+        return false;
     case BACT_RACE_LEGENDS:
         race_legends(player_ptr);
-        break;
+        return false;
     case BACT_QUEST:
         castle_quest(player_ptr);
-        break;
+        return false;
     case BACT_KING_LEGENDS:
     case BACT_ARENA_LEGENDS:
     case BACT_LEGENDS:
         show_highclass(player_ptr);
-        break;
+        return false;
     case BACT_POSTER:
     case BACT_ARENA_RULES:
     case BACT_ARENA:
-        arena_comm(player_ptr, bact);
-        break;
+        return arena_comm(player_ptr, building_action);
     case BACT_IN_BETWEEN:
     case BACT_CRAPS:
     case BACT_SPIN_WHEEL:
     case BACT_DICE_SLOTS:
     case BACT_GAMBLE_RULES:
     case BACT_POKER:
-        gamble_comm(player_ptr, bact);
-        break;
+        gamble_comm(player_ptr, building_action);
+        return false;
     case BACT_REST:
     case BACT_RUMORS:
     case BACT_FOOD:
-        paid = inn_comm(player_ptr, bact);
-        break;
+        if (inn_comm(player_ptr, building_action)) {
+            player_ptr->au -= building_cost;
+        }
+
+        return false;
     case BACT_RESEARCH_MONSTER:
-        paid = research_mon(player_ptr);
-        break;
+        if (research_mon(player_ptr)) {
+            player_ptr->au -= building_cost;
+        }
+
+        return false;
     case BACT_COMPARE_WEAPONS:
-        paid = true;
-        bcost = compare_weapons(player_ptr, bcost);
-        break;
+        player_ptr->au -= compare_weapons(player_ptr, building_cost);
+        return false;
     case BACT_ENCHANT_WEAPON:
-        enchant_item(player_ptr, bcost, 1, 1, 0, FuncItemTester(&ItemEntity::allow_enchant_melee_weapon));
-        break;
+        enchant_item(player_ptr, building_cost, 1, 1, 0, FuncItemTester(&ItemEntity::allow_enchant_melee_weapon));
+        return false;
     case BACT_ENCHANT_ARMOR:
-        enchant_item(player_ptr, bcost, 0, 0, 1, FuncItemTester(&ItemEntity::is_protector));
-        break;
+        enchant_item(player_ptr, building_cost, 0, 0, 1, FuncItemTester(&ItemEntity::is_protector));
+        return false;
     case BACT_RECHARGE:
         building_recharge(player_ptr);
-        break;
+        return false;
     case BACT_RECHARGE_ALL:
         building_recharge_all(player_ptr);
-        break;
+        return false;
     case BACT_IDENTS:
-        if (!get_check(_("持ち物を全て鑑定してよろしいですか?", "Do you pay to identify all your possession? "))) {
-            break;
+        if (!input_check(_("持ち物を全て鑑定してよろしいですか?", "Do you pay to identify all your possession? "))) {
+            return false;
         }
+
         identify_pack(player_ptr);
         msg_print(_(" 持ち物全てが鑑定されました。", "Your possessions have been identified."));
-        paid = true;
-        break;
+        player_ptr->au -= building_cost;
+        return false;
     case BACT_IDENT_ONE:
-        paid = ident_spell(player_ptr, false);
-        break;
+        if (ident_spell(player_ptr, false)) {
+            player_ptr->au -= building_cost;
+        }
+
+        return false;
     case BACT_LEARN:
         do_cmd_study(player_ptr);
-        break;
+        return false;
     case BACT_HEALING:
-        paid = cure_critical_wounds(player_ptr, 200);
-        break;
+        if (cure_critical_wounds(player_ptr, 200)) {
+            player_ptr->au -= building_cost;
+        }
+
+        return false;
     case BACT_RESTORE:
-        paid = restore_all_status(player_ptr);
-        break;
+        if (restore_all_status(player_ptr)) {
+            player_ptr->au -= building_cost;
+        }
+
+        return false;
     case BACT_ENCHANT_ARROWS:
-        enchant_item(player_ptr, bcost, 1, 1, 0, FuncItemTester(&ItemEntity::is_ammo));
-        break;
+        enchant_item(player_ptr, building_cost, 1, 1, 0, FuncItemTester(&ItemEntity::is_ammo));
+        return false;
     case BACT_ENCHANT_BOW:
-        enchant_item(player_ptr, bcost, 1, 1, 0, TvalItemTester(ItemKindType::BOW));
-        break;
-
+        enchant_item(player_ptr, building_cost, 1, 1, 0, TvalItemTester(ItemKindType::BOW));
+        return false;
     case BACT_RECALL:
         if (recall_player(player_ptr, 1)) {
-            paid = true;
+            player_ptr->au -= building_cost;
         }
-        break;
 
+        return false;
     case BACT_TELEPORT_LEVEL:
         screen_save();
         clear_bldg(4, 20);
-        paid = free_level_recall(player_ptr);
-        screen_load();
-        break;
+        if (free_level_recall(player_ptr)) {
+            player_ptr->au -= building_cost;
+        }
 
+        screen_load();
+        return false;
     case BACT_LOSE_MUTATION: {
         auto muta = player_ptr->muta;
         if (player_ptr->ppersonality == PERSONALITY_LUCKY) {
             // ラッキーマンの白オーラは突然変異治療の対象外
             muta.reset(PlayerMutationType::GOOD_LUCK);
         }
+
         if (muta.any()) {
             while (!lose_mutation(player_ptr, 0)) {
                 ;
             }
-            paid = true;
-            break;
+
+            player_ptr->au -= building_cost;
+            return false;
         }
 
         msg_print(_("治すべき突然変異が無い。", "You have no mutations."));
         msg_print(nullptr);
-        break;
+        return false;
     }
-
     case BACT_BATTLE:
-        monster_arena_comm(player_ptr);
-        break;
-
+        return monster_arena_comm(player_ptr);
     case BACT_TSUCHINOKO:
         tsuchinoko();
-        break;
-
+        return false;
     case BACT_BOUNTY:
         show_bounty();
-        break;
-
+        return false;
     case BACT_TARGET:
         today_target(player_ptr);
-        break;
-
+        return false;
     case BACT_KANKIN:
         exchange_cash(player_ptr);
-        break;
-
+        return false;
     case BACT_HEIKOUKA:
         msg_print(_("平衡化の儀式を行なった。", "You received an equalization ritual."));
         set_virtue(player_ptr, Virtue::COMPASSION, 0);
@@ -277,25 +284,26 @@ static void bldg_process_command(PlayerType *player_ptr, building_type *bldg, in
         set_virtue(player_ptr, Virtue::VALOUR, 0);
         set_virtue(player_ptr, Virtue::INDIVIDUALISM, 0);
         initialize_virtues(player_ptr);
-        paid = true;
-        break;
-
+        player_ptr->au -= building_cost;
+        return false;
     case BACT_TELE_TOWN:
-        paid = tele_town(player_ptr);
-        break;
+        if (!tele_town(player_ptr)) {
+            return false;
+        }
 
+        player_ptr->au -= building_cost;
+        return true;
     case BACT_EVAL_AC:
-        paid = eval_ac(player_ptr->dis_ac + player_ptr->dis_to_a);
-        break;
+        if (eval_ac(player_ptr->dis_ac + player_ptr->dis_to_a)) {
+            player_ptr->au -= building_cost;
+        }
 
+        return false;
     case BACT_BROKEN_WEAPON:
-        paid = true;
-        bcost = repair_broken_weapon(player_ptr, bcost);
-        break;
-    }
-
-    if (paid) {
-        player_ptr->au -= bcost;
+        player_ptr->au -= repair_broken_weapon(player_ptr, building_cost);
+        return false;
+    default:
+        THROW_EXCEPTION(std::logic_error, "Invalid building action is specified!");
     }
 }
 
@@ -311,26 +319,26 @@ void do_cmd_building(PlayerType *player_ptr)
 
     PlayerEnergy energy(player_ptr);
     energy.set_player_turn_energy(100);
-
-    if (!cave_has_flag_bold(player_ptr->current_floor_ptr, player_ptr->y, player_ptr->x, TerrainCharacteristics::BLDG)) {
+    const auto p_pos = player_ptr->get_position();
+    if (!cave_has_flag_bold(player_ptr->current_floor_ptr, p_pos.y, p_pos.x, TerrainCharacteristics::BLDG)) {
         msg_print(_("ここには建物はない。", "You see no building here."));
         return;
     }
 
-    TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
-
-    int which = terrains_info[player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].feat].subtype;
+    int which = player_ptr->current_floor_ptr->get_grid(p_pos).get_terrain().subtype;
 
     building_type *bldg;
-    bldg = &building[which];
+    bldg = &buildings[which];
 
     reinit_wilderness = false;
 
     if ((which == 2) && (player_ptr->arena_number < 0)) {
         msg_print(_("「敗者に用はない。」", "'There's no place here for a LOSER like you!'"));
         return;
-    } else if ((which == 2) && player_ptr->current_floor_ptr->inside_arena) {
-        if (!player_ptr->exit_bldg && player_ptr->current_floor_ptr->m_cnt > 0) {
+    }
+
+    if ((which == 2) && player_ptr->current_floor_ptr->inside_arena) {
+        if (!w_ptr->get_arena() && player_ptr->current_floor_ptr->m_cnt > 0) {
             prt(_("ゲートは閉まっている。モンスターがあなたを待っている!", "The gates are closed.  The monster awaits!"), 0, 0);
         } else {
             prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_NO_RETURN);
@@ -341,18 +349,22 @@ void do_cmd_building(PlayerType *player_ptr)
         }
 
         return;
-    } else if (player_ptr->phase_out) {
+    }
+
+    TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
+
+    auto &system = AngbandSystem::get_instance();
+    if (system.is_phase_out()) {
         prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_NO_RETURN);
         player_ptr->leaving = true;
-        player_ptr->phase_out = false;
+        system.set_phase_out(false);
         command_new = SPECIAL_KEY_BUILDING;
         energy.reset_player_turn();
         return;
-    } else {
-        player_ptr->oldpy = player_ptr->y;
-        player_ptr->oldpx = player_ptr->x;
     }
 
+    player_ptr->oldpy = player_ptr->y;
+    player_ptr->oldpx = player_ptr->x;
     forget_lite(player_ptr->current_floor_ptr);
     forget_view(player_ptr->current_floor_ptr);
     w_ptr->character_icky_depth++;
@@ -362,38 +374,32 @@ void do_cmd_building(PlayerType *player_ptr)
     command_new = 0;
 
     display_buikding_service(player_ptr, bldg);
-    player_ptr->leave_bldg = false;
     play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_BUILD);
 
-    bool validcmd;
-    while (!player_ptr->leave_bldg) {
-        validcmd = false;
+    while (true) {
         prt("", 1, 0);
-
         building_prt_gold(player_ptr);
-
-        char command = inkey();
-
+        const auto command = inkey();
         if (command == ESCAPE) {
-            player_ptr->leave_bldg = true;
             player_ptr->current_floor_ptr->inside_arena = false;
-            player_ptr->phase_out = false;
+            system.set_phase_out(false);
             break;
         }
 
+        auto is_valid_command = false;
         int i;
         for (i = 0; i < 8; i++) {
             if (bldg->letters[i] && (bldg->letters[i] == command)) {
-                validcmd = true;
+                is_valid_command = true;
                 break;
             }
         }
 
-        if (validcmd) {
-            bldg_process_command(player_ptr, bldg, i);
-        }
-
+        const auto should_leave = is_valid_command ? bldg_process_command(player_ptr, bldg, i) : false;
         handle_stuff(player_ptr);
+        if (should_leave) {
+            break;
+        }
     }
 
     select_floor_music(player_ptr);
@@ -408,7 +414,25 @@ void do_cmd_building(PlayerType *player_ptr)
     w_ptr->character_icky_depth--;
     term_clear();
 
-    player_ptr->update |= (PU_VIEW | PU_MONSTER_STATUSES | PU_BONUS | PU_LITE | PU_MONSTER_LITE);
-    player_ptr->redraw |= (PR_BASIC | PR_EXTRA | PR_EQUIPPY | PR_MAP);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::EQUIPPY,
+        MainWindowRedrawingFlag::MAP,
+    };
+    rfu.set_flags(flags_mwrf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
 }
index 90107dc..8e543ae 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 #include "system/angband.h"
index bc51153..fe61097 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-building/cmd-inn.h"
+#include "cmd-building/cmd-inn.h"
 #include "cmd-item/cmd-magiceat.h"
 #include "core/turn-compensator.h"
 #include "game-option/birth-options.h"
@@ -57,12 +57,10 @@ static bool is_healthy_stay(PlayerType *player_ptr)
     return false;
 }
 
-#ifdef JP
 static bool is_player_undead(PlayerType *player_ptr)
 {
     return PlayerRace(player_ptr, true).life() == PlayerRaceLifeType::UNDEAD;
 }
-#endif
 
 /*!
  * @brief 宿屋に泊まったことを日記に残す
@@ -72,13 +70,13 @@ static bool is_player_undead(PlayerType *player_ptr)
 static void write_diary_stay_inn(PlayerType *player_ptr, int prev_hour)
 {
     if ((prev_hour >= 6) && (prev_hour < 18)) {
-        concptr stay_message = _(is_player_undead(player_ptr) ? "宿屋に泊まった。" : "日が暮れるまで宿屋で過ごした。", "stayed during the day at the inn.");
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, stay_message);
+        const auto stay_message = _(is_player_undead(player_ptr) ? "宿屋に泊まった。" : "日が暮れるまで宿屋で過ごした。", "stayed during the day at the inn.");
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, stay_message);
         return;
     }
 
-    concptr stay_message = _(is_player_undead(player_ptr) ? "夜が明けるまで宿屋で過ごした。" : "宿屋に泊まった。", "stayed overnight at the inn.");
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, stay_message);
+    const auto stay_message = _(is_player_undead(player_ptr) ? "夜が明けるまで宿屋で過ごした。" : "宿屋に泊まった。", "stayed overnight at the inn.");
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, stay_message);
 }
 
 /*!
@@ -121,7 +119,7 @@ static bool has_a_nightmare(PlayerType *player_ptr)
     }
 
     msg_print(_("あなたは絶叫して目を覚ました。", "You awake screaming."));
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, _("悪夢にうなされてよく眠れなかった。", "had a nightmare."));
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, _("悪夢にうなされてよく眠れなかった。", "had a nightmare."));
     return true;
 }
 
@@ -171,16 +169,16 @@ static void display_stay_result(PlayerType *player_ptr, int prev_hour)
 #if JP
         msg_format("あなたはリフレッシュして目覚め、%sを迎えた。", is_player_undead(player_ptr) ? "夜" : "夕方");
 #else
-        msg_print("You awake refreshed for the evening.");
+        msg_format("You awake refreshed for the %s.", is_player_undead(player_ptr) ? "evening" : "twilight");
 #endif
-        concptr awake_message = _(is_player_undead(player_ptr) ? "すがすがしい夜を迎えた。" : "夕方を迎えた。", "awoke refreshed.");
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, awake_message);
+        const auto awake_message = _(is_player_undead(player_ptr) ? "すがすがしい夜を迎えた。" : "夕方を迎えた。", "awoke refreshed.");
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, awake_message);
         return;
     }
 
     msg_print(_("あなたはリフレッシュして目覚め、新たな日を迎えた。", "You awake refreshed for the new day."));
-    concptr awake_message = _(is_player_undead(player_ptr) ? "すがすがしい朝を迎えた。" : "朝を迎えた。", "awoke refreshed.");
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, awake_message);
+    const auto awake_message = _(is_player_undead(player_ptr) ? "すがすがしい朝を迎えた。" : "朝を迎えた。", "awoke refreshed.");
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, awake_message);
 }
 
 /*!
@@ -194,8 +192,7 @@ static bool stay_inn(PlayerType *player_ptr)
         return false;
     }
 
-    int prev_day, prev_hour, prev_min;
-    extract_day_hour_min(player_ptr, &prev_day, &prev_hour, &prev_min);
+    const auto &[prev_day, prev_hour, prev_min] = w_ptr->extract_date_time(player_ptr->start_race);
     write_diary_stay_inn(player_ptr, prev_hour);
 
     pass_game_turn_by_stay();
@@ -203,7 +200,7 @@ static bool stay_inn(PlayerType *player_ptr)
 
     if ((prev_hour >= 18) && (prev_hour <= 23)) {
         determine_daily_bounty(player_ptr, false); /* Update daily bounty */
-        exe_write_diary(player_ptr, DIARY_DIALY, 0, nullptr);
+        exe_write_diary(player_ptr, DiaryKind::DIALY, 0);
     }
 
     player_ptr->chp = player_ptr->mhp;
index d98267d..71b515e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool inn_comm(PlayerType *player_ptr, int cmd);
index af89961..032881c 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-io/cmd-autopick.h"
+#include "cmd-io/cmd-autopick.h"
 #include "autopick/autopick-command-menu.h"
 #include "autopick/autopick-commands-table.h"
 #include "autopick/autopick-dirty-flags.h"
@@ -118,7 +118,7 @@ void do_cmd_edit_autopick(PlayerType *player_ptr)
     tb->old_wid = tb->old_hgt = -1;
     tb->old_com_id = 0;
 
-    tb->yank = nullptr;
+    tb->yank.clear();
     tb->search_o_ptr = nullptr;
     tb->search_str = nullptr;
     tb->last_destroyed = nullptr;
@@ -137,7 +137,7 @@ void do_cmd_edit_autopick(PlayerType *player_ptr)
         old_autosave_turn = w_ptr->game_turn;
     }
 
-    update_playtime();
+    w_ptr->update_playtime();
     init_autopick();
     if (autopick_last_destroyed_object.is_valid()) {
         autopick_entry_from_object(player_ptr, entry, &autopick_last_destroyed_object);
@@ -204,7 +204,7 @@ void do_cmd_edit_autopick(PlayerType *player_ptr)
     const auto filename = pickpref_filename(player_ptr, tb->filename_mode);
 
     if (quit == APE_QUIT_AND_SAVE) {
-        write_text_lines(filename.data(), tb->lines_list);
+        write_text_lines(filename, tb->lines_list);
     }
 
     free_text_lines(tb->lines_list);
@@ -212,7 +212,7 @@ void do_cmd_edit_autopick(PlayerType *player_ptr)
     string_free(tb->last_destroyed);
     kill_yank_chain(tb);
 
-    process_autopick_file(player_ptr, filename.data());
+    process_autopick_file(player_ptr, filename);
     w_ptr->start_time = (uint32_t)time(nullptr);
     cx_save = tb->cx;
     cy_save = tb->cy;
index 32a19c9..e922c0e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_edit_autopick(PlayerType *player_ptr);
index f2abcd5..158a374 100644 (file)
@@ -1,5 +1,4 @@
-#include "cmd-io/cmd-diary.h"
-#include "cmd-io/diary-subtitle-table.h"
+#include "cmd-io/cmd-diary.h"
 #include "core/asking-player.h"
 #include "core/show-file.h"
 #include "game-option/play-record-options.h"
@@ -11,6 +10,7 @@
 #include "player-base/player-class.h"
 #include "player/player-personality.h"
 #include "system/player-type-definition.h"
+#include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/angband-files.h"
  */
 static void display_diary(PlayerType *player_ptr)
 {
-    std::stringstream ss;
-    ss << _("playrecord-", "playrec-") << savefile_base << ".txt";
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, ss.str());
-
-    PlayerClass pc(player_ptr);
-    const auto max_subtitles = diary_subtitles.size();
-    std::string subtitle;
-    if (pc.is_tough()) {
-        subtitle = diary_subtitles[randint0(max_subtitles - 1)];
-    } else if (pc.is_wizard()) {
-        subtitle = diary_subtitles[randint0(max_subtitles - 1) + 1];
-    } else {
-        subtitle = diary_subtitles[randint0(max_subtitles - 2) + 1];
-    }
-
-    char diary_title[256];
+    const auto subtitle_candidates = PlayerClass(player_ptr).get_subtitle_candidates();
+    const auto choice = Rand_external(subtitle_candidates.size());
+    const auto &subtitle = subtitle_candidates[choice];
 #ifdef JP
-    strnfmt(diary_title, sizeof(diary_title), "「%s%s%sの伝説 -%s-」", ap_ptr->title, ap_ptr->no ? "の" : "", player_ptr->name, subtitle.data());
+    const auto diary_title = format("「%s%s%sの伝説 -%s-」", ap_ptr->title, ap_ptr->no ? "の" : "", player_ptr->name, subtitle.data());
 #else
-    strnfmt(diary_title, sizeof(diary_title), "Legend of %s %s '%s'", ap_ptr->title, player_ptr->name, subtitle.data());
+    const auto diary_title = format("Legend of %s %s '%s'", ap_ptr->title, player_ptr->name, subtitle.data());
 #endif
 
-    (void)show_file(player_ptr, false, buf, diary_title, -1, 0);
+    std::stringstream ss;
+    ss << _("playrecord-", "playrec-") << savefile_base << ".txt";
+    const auto &path = path_build(ANGBAND_DIR_USER, ss.str());
+    (void)show_file(player_ptr, false, path.string(), -1, 0, diary_title);
 }
 
 /*!
@@ -57,11 +46,9 @@ static void display_diary(PlayerType *player_ptr)
  */
 static void add_diary_note(PlayerType *player_ptr)
 {
-    char tmp[80] = "\0";
-    char bunshou[80] = "\0";
-    if (get_string(_("内容: ", "diary note: "), tmp, 79)) {
-        strcpy(bunshou, tmp);
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, bunshou);
+    const auto input_str = input_string(_("内容: ", "diary note: "), 1000);
+    if (input_str) {
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, *input_str);
     }
 }
 
@@ -74,16 +61,15 @@ static void do_cmd_last_get(PlayerType *player_ptr)
         return;
     }
 
-    char buf[256];
-    strnfmt(buf, sizeof(buf), _("%sの入手を記録します。", "Do you really want to record getting %s? "), record_o_name);
-    if (!get_check(buf)) {
+    const auto record = format(_("%sの入手を記録します。", "Do you really want to record getting %s? "), record_o_name);
+    if (!input_check(record)) {
         return;
     }
 
     GAME_TURN turn_tmp = w_ptr->game_turn;
     w_ptr->game_turn = record_turn;
-    strnfmt(buf, sizeof(buf), _("%sを手に入れた。", "discover %s."), record_o_name);
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, buf);
+    const auto mes = format(_("%sを手に入れた。", "discover %s."), record_o_name);
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, mes);
     w_ptr->game_turn = turn_tmp;
 }
 
@@ -92,22 +78,22 @@ static void do_cmd_last_get(PlayerType *player_ptr)
  */
 static void do_cmd_erase_diary()
 {
-    if (!get_check(_("本当に記録を消去しますか?", "Do you really want to delete all your records? "))) {
+    if (!input_check(_("本当に記録を消去しますか?", "Do you really want to delete all your records? "))) {
         return;
     }
 
     std::stringstream ss;
     ss << _("playrecord-", "playrec-") << savefile_base << ".txt";
-    char buf[256];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, ss.str());
-    fd_kill(buf);
+    const auto &path = path_build(ANGBAND_DIR_USER, ss.str());
+    fd_kill(path);
 
-    auto *fff = angband_fopen(buf, FileOpenMode::WRITE);
+    auto *fff = angband_fopen(path, FileOpenMode::WRITE);
     if (fff) {
         angband_fclose(fff);
         msg_format(_("記録を消去しました。", "deleted record."));
     } else {
-        msg_format(_("%s の消去に失敗しました。", "failed to delete %s."), buf);
+        const auto &filename = path.string();
+        msg_format(_("%s の消去に失敗しました。", "failed to delete %s."), filename.data());
     }
 
     msg_print(nullptr);
@@ -120,6 +106,8 @@ static void do_cmd_erase_diary()
 void do_cmd_diary(PlayerType *player_ptr)
 {
     screen_save();
+    TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
+
     while (true) {
         term_clear();
         prt(_("[ 記録の設定 ]", "[ Play Record ]"), 2, 0);
index dea2d48..3f95a2b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_diary(PlayerType *player_ptr);
index ec3fc57..65b34c1 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーのインターフェイスに関するコマンドの実装 / Interface commands
  * @date 2014/01/02
  * @author
  */
 void do_cmd_pref(PlayerType *player_ptr)
 {
-    char buf[80];
-    strcpy(buf, "");
-    if (!get_string(_("設定変更コマンド: ", "Pref: "), buf, 80)) {
+    const auto input_str = input_string(_("設定変更コマンド: ", "Pref: "), 80);
+    if (!input_str) {
         return;
     }
 
-    (void)interpret_pref_file(player_ptr, buf);
+    auto buf(*input_str);
+    (void)interpret_pref_file(player_ptr, buf.data());
 }
 
 /*
@@ -64,11 +64,9 @@ void do_cmd_pref(PlayerType *player_ptr)
  */
 void do_cmd_colors(PlayerType *player_ptr)
 {
-    int i;
-    char tmp[160];
-    char buf[1024];
     FILE *auto_dump_stream;
     screen_save();
+    const auto initial_filename = format("%s.prf", player_ptr->base_name);
     while (true) {
         term_clear();
         prt(_("[ カラーの設定 ]", "Interact with Colors"), 2, 0);
@@ -76,38 +74,41 @@ void do_cmd_colors(PlayerType *player_ptr)
         prt(_("(2) カラーの設定をファイルに書き出す", "(2) Dump colors"), 5, 5);
         prt(_("(3) カラーの設定を変更する", "(3) Modify colors"), 6, 5);
         prt(_("コマンド: ", "Command: "), 8, 0);
-        i = inkey();
-        if (i == ESCAPE) {
+        const auto key = inkey();
+        if (key == ESCAPE) {
             break;
         }
 
-        if (i == '1') {
+        switch (key) {
+        case '1': {
             prt(_("コマンド: ユーザー設定ファイルをロードします", "Command: Load a user pref file"), 8, 0);
             prt(_("ファイル: ", "File: "), 10, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 70)) {
+            const auto ask_result = askfor(70, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            (void)process_pref_file(player_ptr, tmp, true);
+            (void)process_pref_file(player_ptr, *ask_result, true);
             term_xtra(TERM_XTRA_REACT, 0);
             term_redraw();
-        } else if (i == '2') {
+            break;
+        }
+        case '2': {
             constexpr auto mark = "Colors";
             prt(_("コマンド: カラーの設定をファイルに書き出します", "Command: Dump colors"), 8, 0);
             prt(_("ファイル: ", "File: "), 10, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 70)) {
+            const auto ask_result = askfor(70, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
-            if (!open_auto_dump(&auto_dump_stream, buf, mark)) {
+            const auto &path = path_build(ANGBAND_DIR_USER, *ask_result);
+            if (!open_auto_dump(&auto_dump_stream, path, mark)) {
                 continue;
             }
 
             auto_dump_printf(auto_dump_stream, _("\n# カラーの設定\n\n", "\n# Color redefinitions\n\n"));
-            for (i = 0; i < 256; i++) {
+            for (auto i = 0; i < 256; i++) {
                 int kv = angband_color_table[i][0];
                 int rv = angband_color_table[i][1];
                 int gv = angband_color_table[i][2];
@@ -128,15 +129,17 @@ void do_cmd_colors(PlayerType *player_ptr)
 
             close_auto_dump(&auto_dump_stream, mark);
             msg_print(_("カラーの設定をファイルに書き出しました。", "Dumped color redefinitions."));
-        } else if (i == '3') {
+            break;
+        }
+        case '3': {
             static byte a = 0;
             prt(_("コマンド: カラーの設定を変更します", "Command: Modify colors"), 8, 0);
             while (true) {
                 concptr name;
                 clear_from(10);
-                for (byte j = 0; j < 16; j++) {
-                    term_putstr(j * 4, 20, -1, a, "###");
-                    term_putstr(j * 4, 22, -1, j, format("%3d", j));
+                for (byte i = 0; i < 16; i++) {
+                    term_putstr(i * 4, 20, -1, a, "###");
+                    term_putstr(i * 4, 22, -1, i, format("%3d", i));
                 }
 
                 name = ((a < 16) ? color_names[a] : _("未定義", "undefined"));
@@ -145,47 +148,55 @@ void do_cmd_colors(PlayerType *player_ptr)
                     format("K = 0x%02x / R,G,B = 0x%02x,0x%02x,0x%02x", angband_color_table[a][0], angband_color_table[a][1], angband_color_table[a][2],
                         angband_color_table[a][3]));
                 term_putstr(0, 14, -1, TERM_WHITE, _("コマンド (n/N/k/K/r/R/g/G/b/B): ", "Command (n/N/k/K/r/R/g/G/b/B): "));
-                i = inkey();
-                if (i == ESCAPE) {
+                auto ch = inkey();
+                if (ch == ESCAPE) {
                     break;
                 }
 
-                if (i == 'n') {
-                    a = (byte)(a + 1);
-                }
-                if (i == 'N') {
-                    a = (byte)(a - 1);
-                }
-                if (i == 'k') {
+                switch (ch) {
+                case 'b':
+                    angband_color_table[a][3] = (byte)(angband_color_table[a][3] + 1);
+                    break;
+                case 'B':
+                    angband_color_table[a][3] = (byte)(angband_color_table[a][3] - 1);
+                    break;
+                case 'g':
+                    angband_color_table[a][2] = (byte)(angband_color_table[a][2] + 1);
+                    break;
+                case 'G':
+                    angband_color_table[a][2] = (byte)(angband_color_table[a][2] - 1);
+                    break;
+                case 'k':
                     angband_color_table[a][0] = (byte)(angband_color_table[a][0] + 1);
-                }
-                if (i == 'K') {
+                    break;
+                case 'K':
                     angband_color_table[a][0] = (byte)(angband_color_table[a][0] - 1);
-                }
-                if (i == 'r') {
+                    break;
+                case 'n':
+                    a++;
+                    break;
+                case 'N':
+                    a--;
+                    break;
+                case 'r':
                     angband_color_table[a][1] = (byte)(angband_color_table[a][1] + 1);
-                }
-                if (i == 'R') {
+                    break;
+                case 'R':
                     angband_color_table[a][1] = (byte)(angband_color_table[a][1] - 1);
-                }
-                if (i == 'g') {
-                    angband_color_table[a][2] = (byte)(angband_color_table[a][2] + 1);
-                }
-                if (i == 'G') {
-                    angband_color_table[a][2] = (byte)(angband_color_table[a][2] - 1);
-                }
-                if (i == 'b') {
-                    angband_color_table[a][3] = (byte)(angband_color_table[a][3] + 1);
-                }
-                if (i == 'B') {
-                    angband_color_table[a][3] = (byte)(angband_color_table[a][3] - 1);
+                    break;
+                default:
+                    break;
                 }
 
                 term_xtra(TERM_XTRA_REACT, 0);
                 term_redraw();
             }
-        } else {
+
+            break;
+        }
+        default:
             bell();
+            break;
         }
 
         msg_erase();
@@ -199,16 +210,12 @@ void do_cmd_colors(PlayerType *player_ptr)
  */
 void do_cmd_note(void)
 {
-    char buf[80];
-    strcpy(buf, "");
-    if (!get_string(_("メモ: ", "Note: "), buf, 60)) {
-        return;
-    }
-    if (!buf[0] || (buf[0] == ' ')) {
+    const auto note = input_string(_("メモ: ", "Note: "), 60);
+    if (!note || note->empty()) {
         return;
     }
 
-    msg_format(_("メモ: %s", "Note: %s"), buf);
+    msg_format(_("メモ: %s", "Note: %s"), (*note).data());
 }
 
 /*
@@ -229,14 +236,14 @@ void do_cmd_feeling(PlayerType *player_ptr)
         return;
     }
 
-    const auto &floor_ref = *player_ptr->current_floor_ptr;
-    if (inside_quest(floor_ref.quest_number) && !inside_quest(random_quest_number(player_ptr, floor_ref.dun_level))) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.is_in_quest() && !inside_quest(floor.get_random_quest_id())) {
         msg_print(_("典型的なクエストのダンジョンのようだ。", "Looks like a typical quest level."));
         return;
     }
 
-    if (player_ptr->town_num && !floor_ref.is_in_dungeon()) {
-        if (!strcmp(towns_info[player_ptr->town_num].name, _("荒野", "wilderness"))) {
+    if (player_ptr->town_num && !floor.is_in_dungeon()) {
+        if (towns_info[player_ptr->town_num].name == _("荒野", "wilderness")) {
             msg_print(_("何かありそうな荒野のようだ。", "Looks like a strange wilderness."));
             return;
         }
@@ -245,7 +252,7 @@ void do_cmd_feeling(PlayerType *player_ptr)
         return;
     }
 
-    if (!floor_ref.is_in_dungeon()) {
+    if (!floor.is_in_dungeon()) {
         msg_print(_("典型的な荒野のようだ。", "Looks like a typical wilderness."));
         return;
     }
@@ -265,28 +272,28 @@ void do_cmd_feeling(PlayerType *player_ptr)
  */
 void do_cmd_time(PlayerType *player_ptr)
 {
-    int day, hour, min;
-    extract_day_hour_min(player_ptr, &day, &hour, &min);
-    std::string desc = _("変な時刻だ。", "It is a strange time.");
+    const auto &[day, hour, min] = w_ptr->extract_date_time(player_ptr->start_race);
     std::string day_buf = (day < MAX_DAYS) ? std::to_string(day) : "*****";
     constexpr auto mes = _("%s日目, 時刻は%d:%02d %sです。", "This is day %s. The time is %d:%02d %s.");
     msg_format(mes, day_buf.data(), (hour % 12 == 0) ? 12 : (hour % 12), min, (hour < 12) ? "AM" : "PM");
-    char buf[1024];
+    std::filesystem::path path;
     if (!randint0(10) || player_ptr->effects()->hallucination()->is_hallucinated()) {
-        path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("timefun_j.txt", "timefun.txt"));
+        path = path_build(ANGBAND_DIR_FILE, _("timefun_j.txt", "timefun.txt"));
     } else {
-        path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("timenorm_j.txt", "timenorm.txt"));
+        path = path_build(ANGBAND_DIR_FILE, _("timenorm_j.txt", "timenorm.txt"));
     }
 
-    auto *fff = angband_fopen(buf, FileOpenMode::READ);
+    auto *fff = angband_fopen(path, FileOpenMode::READ);
     if (!fff) {
         return;
     }
 
+    std::string desc = _("変な時刻だ。", "It is a strange time.");
     auto full = hour * 100 + min;
     auto start = 9999;
     auto end = -9999;
     auto num = 0;
+    char buf[1024]{};
     while (!angband_fgets(fff, buf, sizeof(buf))) {
         if (!buf[0] || (buf[0] == '#')) {
             continue;
index 1932e96..f9100fe 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_pref(PlayerType *player_ptr);
index 3e8d8ab..2abd7e8 100644 (file)
@@ -1,7 +1,5 @@
-#include "cmd-io/cmd-floor.h"
+#include "cmd-io/cmd-floor.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "floor/geometry.h"
@@ -10,6 +8,7 @@
 #include "io/screen-util.h"
 #include "main/sound-of-music.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "target/target-setter.h"
 #include "target/target-types.h"
@@ -41,7 +40,11 @@ void do_cmd_target(PlayerType *player_ptr)
  */
 void do_cmd_look(PlayerType *player_ptr)
 {
-    set_bits(player_ptr->window_flags, PW_SIGHT_MONSTERS | PW_FLOOR_ITEMS);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::SIGHT_MONSTERS,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     handle_stuff(player_ptr);
     if (target_set(player_ptr, TARGET_LOOK)) {
         msg_print(_("ターゲット決定。", "Target Selected."));
@@ -54,36 +57,33 @@ void do_cmd_look(PlayerType *player_ptr)
  */
 void do_cmd_locate(PlayerType *player_ptr)
 {
-    const char *dirstrings[3][3] = {
-        { _("北西", " northwest of"), _("北", " north of"), _("北東", " northeast of") },
-        { _("西", " west of"), _("真上", ""), _("東", " east of") },
-        { _("南西", " southwest of"), _("南", " south of"), _("南東", " southeast of") },
-    };
-    DIRECTION dir;
+    static constexpr std::array<std::array<std::string_view, 3>, 3> dirstrings = { {
+        { { _("北西", " northwest of"), _("北", " north of"), _("北東", " northeast of") } },
+        { { _("西", " west of"), _("真上", ""), _("東", " east of") } },
+        { { _("南西", " southwest of"), _("南", " south of"), _("南東", " southeast of") } },
+    } };
     POSITION y1, x1;
-    TERM_LEN wid, hgt;
-    get_screen_size(&wid, &hgt);
+    const auto &[wid, hgt] = get_screen_size();
     POSITION y2 = y1 = panel_row_min;
     POSITION x2 = x1 = panel_col_min;
+    constexpr auto fmt = _("マップ位置 [%d(%02d),%d(%02d)] (プレイヤーの%s)  方向?", "Map sector [%d(%02d),%d(%02d)], which is%s your sector.  Direction?");
     while (true) {
-        std::string_view dirstring = dirstrings[(y2 < y1) ? 0 : ((y2 > y1) ? 2 : 1)][(x2 < x1) ? 0 : ((x2 > x1) ? 2 : 1)];
-        std::string out_val = format(_("マップ位置 [%d(%02d),%d(%02d)] (プレイヤーの%s)  方向?", "Map sector [%d(%02d),%d(%02d)], which is%s your sector.  Direction?"),
-            y2 / (hgt / 2), y2 % (hgt / 2), x2 / (wid / 2), x2 % (wid / 2), dirstring.data());
-
-        dir = 0;
-        while (!dir) {
-            char command;
-            if (!get_com(out_val, &command, true)) {
+        const auto &dirstring = dirstrings[(y2 < y1) ? 0 : ((y2 > y1) ? 2 : 1)][(x2 < x1) ? 0 : ((x2 > x1) ? 2 : 1)];
+        const auto prompt = format(fmt, y2 / (hgt / 2), y2 % (hgt / 2), x2 / (wid / 2), x2 % (wid / 2), dirstring.data());
+        auto dir = 0;
+        while (dir == 0) {
+            const auto command = input_command(prompt, true);
+            if (!command) {
                 break;
             }
 
-            dir = get_keymap_dir(command);
-            if (!dir) {
+            dir = get_keymap_dir(*command);
+            if (dir == 0) {
                 bell();
             }
         }
 
-        if (!dir) {
+        if (dir == 0) {
             break;
         }
 
@@ -94,8 +94,13 @@ void do_cmd_locate(PlayerType *player_ptr)
     }
 
     verify_panel(player_ptr);
-    player_ptr->update |= PU_MONSTER_STATUSES;
-    player_ptr->redraw |= PR_MAP;
-    player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags);
     handle_stuff(player_ptr);
 }
index b6db78b..40d9f18 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_target(PlayerType *player_ptr);
index 796ad40..16ecb9b 100644 (file)
@@ -1,9 +1,8 @@
-#include "cmd-io/cmd-gameoption.h"
+#include "cmd-io/cmd-gameoption.h"
 #include "autopick/autopick.h"
 #include "cmd-io/cmd-autopick.h"
 #include "cmd-io/cmd-dump.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/show-file.h"
 #include "core/window-redrawer.h"
 #include "floor/geometry.h"
@@ -17,6 +16,7 @@
 #include "main/sound-of-music.h"
 #include "system/game-option-types.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
@@ -153,7 +153,7 @@ static void do_cmd_options_autosave(PlayerType *player_ptr, concptr info)
         }
 
         case '?': {
-            (void)show_file(player_ptr, true, _("joption.txt#Autosave", "option.txt#Autosave"), nullptr, 0, 0);
+            (void)show_file(player_ptr, true, _("joption.txt#Autosave", "option.txt#Autosave"), 0, 0);
             term_clear();
             break;
         }
@@ -170,12 +170,16 @@ static void do_cmd_options_autosave(PlayerType *player_ptr, concptr info)
  * @brief 指定のサブウィンドウが指定のウィンドウフラグを持つか調べる
  * @param x ウィンドウ番号
  * @param y ウィンドウフラグ番号
- * @return 持つならTRUE、持たないならFALSE
+ * @return æ\8c\81ã\81¤ã\81ªã\82\89TRUEã\80\81æ\8c\81ã\81\9fã\81ªã\81\84ã\81\8bã\83¡ã\82¤ã\83³ã\82¦ã\82£ã\83³ã\83\89ã\82¦ã\81ªã\82\89FALSE
  */
 static bool has_window_flag(int x, int y)
 {
-    auto flag = i2enum<window_redraw_type>(1UL << y);
-    return any_bits(window_flag[x], flag);
+    if (x == 0) {
+        return false;
+    }
+
+    auto flag = i2enum<SubWindowRedrawingFlag>(y);
+    return g_window_flags[x].has(flag);
 }
 
 /*!
@@ -187,10 +191,12 @@ static bool has_window_flag(int x, int y)
  */
 static void set_window_flag(int x, int y)
 {
-    auto flag = i2enum<window_redraw_type>(1UL << y);
-    if (any_bits(PW_ALL, flag)) {
-        set_bits(window_flag[x], flag);
+    if (x == 0) {
+        return;
     }
+
+    auto flag = i2enum<SubWindowRedrawingFlag>(y);
+    g_window_flags[x].set(flag);
 }
 
 /*!
@@ -199,11 +205,14 @@ static void set_window_flag(int x, int y)
  */
 static void clear_window_flag(int x, int y)
 {
-    window_flag[x] = 0;
+    g_window_flags[x].clear();
+    if (x == 0) {
+        return;
+    }
 
-    auto flag = i2enum<window_redraw_type>(1UL << y);
-    for (int i = 0; i < 8; i++) {
-        reset_bits(window_flag[i], flag);
+    auto flag = i2enum<SubWindowRedrawingFlag>(y);
+    for (auto &window_flag : g_window_flags) {
+        window_flag.reset(flag);
     }
 }
 
@@ -218,18 +227,13 @@ static void do_cmd_options_win(PlayerType *player_ptr)
     TERM_LEN x = 0;
     char ch;
     bool go = true;
-    uint32_t old_flag[8];
-
-    for (j = 0; j < 8; j++) {
-        old_flag[j] = window_flag[j];
-    }
-
+    const auto old_flags = g_window_flags;
     term_clear();
     while (go) {
         prt(_("ウィンドウ・フラグ (<方向>で移動, 't'でON/OFF,'s'でON(他窓OFF), ESC)", "Window Flags (<dir>, <t>oggle, <s>et, ESC) "), 0, 0);
         for (j = 0; j < 8; j++) {
             byte a = TERM_WHITE;
-            concptr s = angband_term_name[j];
+            auto s = angband_term_name[j];
             if (j == x) {
                 a = TERM_L_BLUE;
             }
@@ -256,7 +260,7 @@ static void do_cmd_options_win(PlayerType *player_ptr)
                     a = TERM_L_BLUE;
                 }
 
-                if (window_flag[j] & (1UL << i)) {
+                if (g_window_flags[j].has(i2enum<SubWindowRedrawingFlag>(i))) {
                     c = 'X';
                 }
 
@@ -275,7 +279,7 @@ static void do_cmd_options_win(PlayerType *player_ptr)
         case 't':
         case 'T':
             has_flag = has_window_flag(x, y);
-            window_flag[x] = 0;
+            g_window_flags[x].clear();
             if (x > 0 && !has_flag) {
                 set_window_flag(x, y);
             }
@@ -285,12 +289,12 @@ static void do_cmd_options_win(PlayerType *player_ptr)
             if (x == 0) {
                 break;
             }
-            window_flag[x] = 0;
+            g_window_flags[x].clear();
             clear_window_flag(x, y);
             set_window_flag(x, y);
             break;
         case '?':
-            (void)show_file(player_ptr, true, _("joption.txt#Window", "option.txt#Window"), nullptr, 0, 0);
+            (void)show_file(player_ptr, true, _("joption.txt#Window", "option.txt#Window"), 0, 0);
             term_clear();
             break;
         default:
@@ -310,7 +314,7 @@ static void do_cmd_options_win(PlayerType *player_ptr)
             continue;
         }
 
-        if (window_flag[term_index] == old_flag[term_index]) {
+        if (g_window_flags[term_index] == old_flags[term_index]) {
             continue;
         }
 
@@ -347,7 +351,8 @@ static void do_cmd_options_cheat(PlayerType *player_ptr, concptr info)
                 a = TERM_L_BLUE;
             }
 
-            c_prt(enum2i(a), format("%-48s: %s (%s)", cheat_info[i].o_desc, (*cheat_info[i].o_var ? _("はい  ", "yes") : _("いいえ", "no ")), cheat_info[i].o_text), i + 2, 0);
+            const auto yesno = *cheat_info[i].o_var ? _("はい  ", "yes") : _("いいえ", "no ");
+            c_prt(enum2i(a), format("%-48s: %s (%s)", cheat_info[i].o_desc, yesno, cheat_info[i].o_text), i + 2, 0);
         }
 
         move_cursor(k + 2, 50);
@@ -374,7 +379,7 @@ static void do_cmd_options_cheat(PlayerType *player_ptr, concptr info)
         case 'Y':
         case '6':
             if (!w_ptr->noscore) {
-                exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0,
+                exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0,
                     _("詐欺オプションをONにして、スコアを残せなくなった。", "gave up sending score to use cheating options."));
             }
 
@@ -389,7 +394,7 @@ static void do_cmd_options_cheat(PlayerType *player_ptr, concptr info)
             k = (k + 1) % n;
             break;
         case '?':
-            (void)show_file(player_ptr, true, std::string(_("joption.txt#", "option.txt#")).append(cheat_info[k].o_text).data(), nullptr, 0, 0);
+            (void)show_file(player_ptr, true, std::string(_("joption.txt#", "option.txt#")).append(cheat_info[k].o_text), 0, 0);
             term_clear();
             break;
         default:
@@ -408,7 +413,7 @@ void extract_option_vars(void)
         int os = option_info[i].o_set;
         int ob = option_info[i].o_bit;
         if (option_info[i].o_var) {
-            if (option_flag[os] & (1UL << ob)) {
+            if (g_option_flags[os] & (1UL << ob)) {
                 (*option_info[i].o_var) = true;
             } else {
                 (*option_info[i].o_var) = false;
@@ -554,7 +559,7 @@ void do_cmd_options(PlayerType *player_ptr)
         case 'W':
         case 'w': {
             do_cmd_options_win(player_ptr);
-            player_ptr->window_flags = PW_ALL;
+            RedrawingFlagsUpdater::get_instance().fill_up_sub_flags();
             break;
         }
         case 'P':
@@ -566,7 +571,12 @@ void do_cmd_options(PlayerType *player_ptr)
         case 'd': {
             clear_from(18);
             prt(format(_("現在ウェイト量(msec): %d", "Current Delay Factor(msec): %d"), delay_factor), 19, 0);
-            (void)get_value(_("コマンド: ウェイト量(msec)", "Command: Delay Factor(msec)"), 0, 1000, &delay_factor);
+            constexpr auto prompt = _("コマンド: ウェイト量(msec)", "Command: Delay Factor(msec)");
+            const auto new_delay_factor = input_integer(prompt, 0, 1000, delay_factor);
+            if (new_delay_factor) {
+                delay_factor = *new_delay_factor;
+            }
+
             clear_from(18);
             break;
         }
@@ -581,7 +591,7 @@ void do_cmd_options(PlayerType *player_ptr)
                 if (k == ESCAPE) {
                     break;
                 } else if (k == '?') {
-                    (void)show_file(player_ptr, true, _("joption.txt#Hitpoint", "option.txt#Hitpoint"), nullptr, 0, 0);
+                    (void)show_file(player_ptr, true, _("joption.txt#Hitpoint", "option.txt#Hitpoint"), 0, 0);
                     term_clear();
                 } else if (isdigit(k)) {
                     hitpoint_warn = D2I(k);
@@ -603,7 +613,7 @@ void do_cmd_options(PlayerType *player_ptr)
                 if (k == ESCAPE) {
                     break;
                 } else if (k == '?') {
-                    (void)show_file(player_ptr, true, _("joption.txt#Manapoint", "option.txt#Manapoint"), nullptr, 0, 0);
+                    (void)show_file(player_ptr, true, _("joption.txt#Manapoint", "option.txt#Manapoint"), 0, 0);
                     term_clear();
                 } else if (isdigit(k)) {
                     mana_warn = D2I(k);
@@ -615,7 +625,7 @@ void do_cmd_options(PlayerType *player_ptr)
             break;
         }
         case '?':
-            (void)show_file(player_ptr, true, _("joption.txt", "option.txt"), nullptr, 0, 0);
+            (void)show_file(player_ptr, true, _("joption.txt", "option.txt"), 0, 0);
             term_clear();
             break;
         default: {
@@ -628,7 +638,7 @@ void do_cmd_options(PlayerType *player_ptr)
     }
 
     screen_load();
-    player_ptr->redraw |= (PR_EQUIPPY);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::EQUIPPY);
 }
 
 /*!
@@ -641,7 +651,7 @@ void do_cmd_options_aux(PlayerType *player_ptr, game_option_types page, concptr
 {
     char ch;
     int i, k = 0, n = 0, l;
-    int opt[MAIN_TERM_MIN_ROWS];
+    int opt[MAIN_TERM_MIN_ROWS]{};
     bool browse_only = (page == OPT_PAGE_BIRTH) && w_ptr->character_generated && (!w_ptr->wizard || !allow_debug_opts);
 
     for (i = 0; i < MAIN_TERM_MIN_ROWS; i++) {
@@ -657,10 +667,11 @@ void do_cmd_options_aux(PlayerType *player_ptr, game_option_types page, concptr
     term_clear();
     while (true) {
         DIRECTION dir;
-        prt(format(_("%s (リターン:次, %sESC:終了, ?:ヘルプ) ", "%s (RET:next, %s, ?:help) "), info, browse_only ? _("", "ESC:exit") : _("y/n:変更, ", "y/n:change, ESC:accept")), 0, 0);
+        constexpr auto command = _("%s (リターン:次, %sESC:終了, ?:ヘルプ) ", "%s (RET:next, %s, ?:help) ");
+        prt(format(command, info, browse_only ? _("", "ESC:exit") : _("y/n:変更, ", "y/n:change, ESC:accept")), 0, 0);
         if (page == OPT_PAGE_AUTODESTROY) {
-            c_prt(TERM_YELLOW, _("以下のオプションは、簡易自動破壊を使用するときのみ有効", "Following options will protect items from easy auto-destroyer."), 6,
-                _(6, 3));
+            constexpr auto mes = _("以下のオプションは、簡易自動破壊を使用するときのみ有効", "Following options will protect items from easy auto-destroyer.");
+            c_prt(TERM_YELLOW, mes, 6, _(6, 3));
         }
 
         for (i = 0; i < n; i++) {
@@ -669,8 +680,8 @@ void do_cmd_options_aux(PlayerType *player_ptr, game_option_types page, concptr
                 a = TERM_L_BLUE;
             }
 
-            std::string label = format("%-48s: %s (%.19s)", option_info[opt[i]].o_desc, (*option_info[opt[i]].o_var ? _("はい  ", "yes") : _("いいえ", "no ")),
-                option_info[opt[i]].o_text);
+            const auto reply = *option_info[opt[i]].o_var ? _("はい  ", "yes") : _("いいえ", "no ");
+            const auto label = format("%-48s: %s (%.19s)", option_info[opt[i]].o_desc, reply, option_info[opt[i]].o_text);
             if ((page == OPT_PAGE_AUTODESTROY) && i > 2) {
                 c_prt(a, label, i + 5, 0);
             } else {
@@ -735,7 +746,7 @@ void do_cmd_options_aux(PlayerType *player_ptr, game_option_types page, concptr
             break;
         }
         case '?': {
-            (void)show_file(player_ptr, true, std::string(_("joption.txt#", "option.txt#")).append(option_info[opt[k]].o_text).data(), nullptr, 0, 0);
+            (void)show_file(player_ptr, true, std::string(_("joption.txt#", "option.txt#")).append(option_info[opt[k]].o_text), 0, 0);
             term_clear();
             break;
         }
index fa9b023..4de1125 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "system/game-option-types.h"
index b5f09a4..115203f 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-io/cmd-help.h"
+#include "cmd-io/cmd-help.h"
 #include "core/show-file.h"
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h"
@@ -12,6 +12,6 @@
 void do_cmd_help(PlayerType *player_ptr)
 {
     screen_save();
-    (void)show_file(player_ptr, true, _("jhelp.hlp", "help.hlp"), nullptr, 0, 0);
+    (void)show_file(player_ptr, true, _("jhelp.hlp", "help.hlp"), 0, 0);
     screen_load();
 }
index f3ed4a0..0efaff1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_help(PlayerType *player_ptr);
index c983ca5..b00641a 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-io/cmd-knowledge.h"
+#include "cmd-io/cmd-knowledge.h"
 #include "cmd-visual/cmd-draw.h"
 #include "game-option/birth-options.h"
 #include "grid/feature.h"
@@ -15,6 +15,7 @@
 #include "knowledge/knowledge-uniques.h"
 #include "main/sound-of-music.h"
 #include "system/player-type-definition.h"
+#include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
@@ -27,6 +28,7 @@ void do_cmd_knowledge(PlayerType *player_ptr)
     int i, p = 0;
     bool need_redraw = false;
     screen_save();
+    TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
     while (true) {
         term_clear();
         prt(format(_("%d/2 ページ", "page %d/2"), (p + 1)), 2, 65);
index f0a92df..38ff4ec 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_knowledge(PlayerType *player_ptr);
index 76a7d62..4f5e46c 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-io/cmd-lore.h"
+#include "cmd-io/cmd-lore.h"
 #include "core/asking-player.h"
 #include "core/stuff-handler.h"
 #include "game-option/cheat-options.h"
  */
 void do_cmd_query_symbol(PlayerType *player_ptr)
 {
-    char sym, query;
-
     bool all = false;
     bool uniq = false;
     bool norm = false;
     bool ride = false;
-    char temp[MAX_MONSTER_NAME] = "";
-
     bool recall = false;
 
     uint16_t why = 0;
 
-    if (!get_com(_("知りたい文字を入力して下さい(記号 or ^A全,^Uユ,^N非ユ,^R乗馬,^M名前): ",
-                     "Enter character to be identified(^A:All,^U:Uniqs,^N:Non uniqs,^M:Name): "),
-            &sym, false)) {
+    constexpr auto prompt = _("知りたい文字を入力して下さい(記号 or ^A全,^Uユ,^N非ユ,^R乗馬,^M名前): ",
+        "Enter character to be identified(^A:All,^U:Uniqs,^N:Non uniqs,^M:Name): ");
+    const auto symbol = input_command(prompt);
+    if (!symbol) {
         return;
     }
 
     int ident_i;
     for (ident_i = 0; ident_info[ident_i]; ++ident_i) {
-        if (sym == ident_info[ident_i][0]) {
+        if (symbol == ident_info[ident_i][0]) {
             break;
         }
     }
 
     std::string buf;
-    if (sym == KTRL('A')) {
+    std::string monster_name("");
+    if (symbol == KTRL('A')) {
         all = true;
         buf = _("全モンスターのリスト", "Full monster list.");
-    } else if (sym == KTRL('U')) {
+    } else if (symbol == KTRL('U')) {
         all = uniq = true;
         buf = _("ユニーク・モンスターのリスト", "Unique monster list.");
-    } else if (sym == KTRL('N')) {
+    } else if (symbol == KTRL('N')) {
         all = norm = true;
         buf = _("ユニーク外モンスターのリスト", "Non-unique monster list.");
-    } else if (sym == KTRL('R')) {
+    } else if (symbol == KTRL('R')) {
         all = ride = true;
         buf = _("乗馬可能モンスターのリスト", "Ridable monster list.");
-    } else if (sym == KTRL('M')) {
+    } else if (symbol == KTRL('M')) {
         all = true;
-        if (!get_string(_("名前(英語の場合小文字で可)", "Enter name:"), temp, 70)) {
-            temp[0] = 0;
+        const auto monster_name_opt = input_string(_("名前(英語の場合小文字で可)", "Enter name:"), MAX_MONSTER_NAME);
+        if (!monster_name_opt) {
             return;
         }
-        buf = format(_("名前:%sにマッチ", "Monsters' names with \"%s\""), temp);
+
+        monster_name = *monster_name_opt;
+        buf = format(_("名前:%sにマッチ", "Monsters' names with \"%s\""), monster_name.data());
     } else if (ident_info[ident_i]) {
-        buf = format("%c - %s.", sym, ident_info[ident_i] + 2);
+        buf = format("%c - %s.", *symbol, ident_info[ident_i] + 2);
     } else {
-        buf = format("%c - %s", sym, _("無効な文字", "Unknown Symbol"));
+        buf = format("%c - %s", *symbol, _("無効な文字", "Unknown Symbol"));
     }
 
     prt(buf, 0, 0);
-    std::vector<MonsterRaceId> who;
-    for (const auto &[r_idx, r_ref] : monraces_info) {
-        if (!cheat_know && !r_ref.r_sights) {
+    std::vector<MonsterRaceId> monraces;
+    for (const auto &[monrace_id, monrace] : monraces_info) {
+        if (!cheat_know && !monrace.r_sights) {
             continue;
         }
 
-        if (norm && r_ref.kind_flags.has(MonsterKindType::UNIQUE)) {
+        if (norm && monrace.kind_flags.has(MonsterKindType::UNIQUE)) {
             continue;
         }
 
-        if (uniq && r_ref.kind_flags.has_not(MonsterKindType::UNIQUE)) {
+        if (uniq && monrace.kind_flags.has_not(MonsterKindType::UNIQUE)) {
             continue;
         }
 
-        if (ride && !(r_ref.flags7 & (RF7_RIDING))) {
+        if (ride && !(monrace.flags7 & (RF7_RIDING))) {
             continue;
         }
 
-        if (temp[0]) {
-            TERM_LEN xx;
-            char temp2[MAX_MONSTER_NAME];
-
-            for (xx = 0; temp[xx] && xx < MAX_MONSTER_NAME; xx++) {
+        if (!monster_name.empty()) {
+            for (size_t xx = 0; xx < monster_name.length(); xx++) {
 #ifdef JP
-                if (iskanji(temp[xx])) {
+                if (iskanji(monster_name[xx])) {
                     xx++;
                     continue;
                 }
 #endif
-                if (isupper(temp[xx])) {
-                    temp[xx] = (char)tolower(temp[xx]);
+                if (isupper(monster_name[xx])) {
+                    monster_name[xx] = (char)tolower(monster_name[xx]);
                 }
             }
 
 #ifdef JP
-            strcpy(temp2, r_ref.E_name.data());
+            auto temp2(monrace.E_name);
 #else
-            strcpy(temp2, r_ref.name.data());
+            auto temp2(monrace.name);
 #endif
-            for (xx = 0; temp2[xx] && xx < MAX_MONSTER_NAME; xx++) {
+            for (size_t xx = 0; xx < temp2.length(); xx++) {
                 if (isupper(temp2[xx])) {
                     temp2[xx] = (char)tolower(temp2[xx]);
                 }
             }
 
 #ifdef JP
-            if (angband_strstr(temp2, temp) || angband_strstr(r_ref.name.data(), temp))
+            if (str_find(temp2, monster_name) || str_find(monrace.name, monster_name))
 #else
-            if (angband_strstr(temp2, temp))
+            if (str_find(temp2, monster_name))
 #endif
-                who.push_back(r_ref.idx);
+                monraces.push_back(monrace_id);
         }
 
-        else if (all || (r_ref.d_char == sym)) {
-            who.push_back(r_ref.idx);
+        else if (all || (monrace.d_char == symbol)) {
+            monraces.push_back(monrace_id);
         }
     }
 
-    if (who.empty()) {
+    if (monraces.empty()) {
         return;
     }
 
     put_str(_("思い出を見ますか? (k:殺害順/y/n): ", "Recall details? (k/y/n): "), 0, _(36, 40));
-    query = inkey();
+    auto query = inkey();
     prt(buf, 0, 0);
     why = 2;
-    ang_sort(player_ptr, who.data(), &why, who.size(), ang_sort_comp_hook, ang_sort_swap_hook);
+    ang_sort(player_ptr, monraces.data(), &why, monraces.size(), ang_sort_comp_hook, ang_sort_swap_hook);
     if (query == 'k') {
         why = 4;
         query = 'y';
@@ -166,18 +163,18 @@ void do_cmd_query_symbol(PlayerType *player_ptr)
     }
 
     if (why == 4) {
-        ang_sort(player_ptr, who.data(), &why, who.size(), ang_sort_comp_hook, ang_sort_swap_hook);
+        ang_sort(player_ptr, monraces.data(), &why, monraces.size(), ang_sort_comp_hook, ang_sort_swap_hook);
     }
 
-    auto i = who.size() - 1;
+    auto i = monraces.size() - 1;
     while (true) {
-        auto r_idx = who[i];
+        auto r_idx = monraces[i];
         monster_race_track(player_ptr, r_idx);
         handle_stuff(player_ptr);
         while (true) {
             if (recall) {
                 screen_save();
-                screen_roff(player_ptr, who[i], MONSTER_LORE_NORMAL);
+                screen_roff(player_ptr, monraces[i], MONSTER_LORE_NORMAL);
             }
 
             roff_top(r_idx);
@@ -198,7 +195,7 @@ void do_cmd_query_symbol(PlayerType *player_ptr)
         }
 
         if (query == '-') {
-            if (++i == who.size()) {
+            if (++i == monraces.size()) {
                 i = 0;
                 if (!expand_list) {
                     break;
@@ -206,7 +203,7 @@ void do_cmd_query_symbol(PlayerType *player_ptr)
             }
         } else {
             if (i-- == 0) {
-                i = who.size() - 1;
+                i = monraces.size() - 1;
                 if (!expand_list) {
                     break;
                 }
index e4b2b42..11be101 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_query_symbol(PlayerType *player_ptr);
index cc0f9db..c8b885e 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-io/cmd-macro.h"
+#include "cmd-io/cmd-macro.h"
 #include "cmd-io/cmd-gameoption.h"
 #include "cmd-io/macro-util.h"
 #include "core/asking-player.h"
 #include "view/display-messages.h"
 
 /*!
- * @brief マクロ情報をprefファイルに保存する /
- * @param fname ファイル名
+ * @brief マクロ情報をprefファイルに保存する
+ * @param filename ファイル名
  */
-static void macro_dump(FILE **fpp, concptr fname)
+static void macro_dump(FILE **fpp, std::string_view filename)
 {
     constexpr auto mark = "Macro Dump";
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
-    if (!open_auto_dump(fpp, buf, mark)) {
+    const auto &path = path_build(ANGBAND_DIR_USER, filename);
+    if (!open_auto_dump(fpp, path, mark)) {
         return;
     }
 
     auto_dump_printf(*fpp, _("\n# 自動マクロセーブ\n\n", "\n# Automatic macro dump\n\n"));
 
-    for (auto i = 0; i < macro__num; i++) {
-        ascii_to_text(buf, macro__act[i], sizeof(buf));
+    for (auto i = 0; i < active_macros; i++) {
+        char buf[1024]{};
+        ascii_to_text(buf, macro_actions[i], sizeof(buf));
         auto_dump_printf(*fpp, "A:%s\n", buf);
-        ascii_to_text(buf, macro__pat[i], sizeof(buf));
+        ascii_to_text(buf, macro_patterns[i], sizeof(buf));
         auto_dump_printf(*fpp, "P:%s\n", buf);
         auto_dump_printf(*fpp, "\n");
     }
@@ -96,17 +96,14 @@ static void do_cmd_macro_aux_keymap(char *buf)
 }
 
 /*!
- * @brief キーマップをprefファイルにダンプする /
- * Hack -- append all keymaps to the given file
- * @param fname ファイルネーム
+ * @brief キーマップをprefファイルにダンプする
+ * @param filename ファイルネーム
  * @return エラーコード
- * @details
  */
-static errr keymap_dump(concptr fname)
+static errr keymap_dump(std::string_view filename)
 {
     FILE *auto_dump_stream;
     char key[1024];
-    char buf[1024];
     BIT_FLAGS mode;
     if (rogue_like_commands) {
         mode = KEYMAP_MODE_ROGUE;
@@ -114,9 +111,9 @@ static errr keymap_dump(concptr fname)
         mode = KEYMAP_MODE_ORIG;
     }
 
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
+    const auto &path = path_build(ANGBAND_DIR_USER, filename);
     constexpr auto mark = "Keymap Dump";
-    if (!open_auto_dump(&auto_dump_stream, buf, mark)) {
+    if (!open_auto_dump(&auto_dump_stream, path, mark)) {
         return -1;
     }
 
@@ -128,8 +125,8 @@ static errr keymap_dump(concptr fname)
             continue;
         }
 
+        char buf[1024]{};
         buf[0] = (char)i;
-        buf[1] = '\0';
         ascii_to_text(key, buf, sizeof(key));
         ascii_to_text(buf, act, sizeof(buf));
         auto_dump_printf(auto_dump_stream, "A:%s\n", buf);
@@ -152,7 +149,6 @@ static errr keymap_dump(concptr fname)
  */
 void do_cmd_macros(PlayerType *player_ptr)
 {
-    char tmp[1024];
     char buf[1024];
     static char macro_buf[1024];
     FILE *auto_dump_stream;
@@ -175,60 +171,70 @@ void do_cmd_macros(PlayerType *player_ptr)
     };
     print_macro_menu();
 
+    const auto initial_filename = format("%s.prf", player_ptr->base_name);
     while (true) {
         msg_print(_("コマンド: ", "Command: "));
-        const int key = inkey();
+        const auto key = inkey();
         if (key == ESCAPE) {
             break;
         }
         clear_from(1);
         print_macro_menu();
 
-        if (key == '1') {
+        switch (key) {
+        case '1': {
             prt(_("コマンド: ユーザー設定ファイルのロード", "Command: Load a user pref file"), 16, 0);
             prt(_("ファイル: ", "File: "), 18, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 80)) {
+            const auto ask_result = askfor(70, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            errr err = process_pref_file(player_ptr, tmp, true);
+            const auto err = process_pref_file(player_ptr, *ask_result, true);
+            const auto *mes = ask_result->data();
             if (-2 == err) {
-                msg_format(_("標準の設定ファイル'%s'を読み込みました。", "Loaded default '%s'."), tmp);
+                msg_format(_("標準の設定ファイル'%s'を読み込みました。", "Loaded default '%s'."), mes);
             } else if (err) {
-                msg_format(_("'%s'の読み込みに失敗しました!", "Failed to load '%s'!"), tmp);
+                msg_format(_("'%s'の読み込みに失敗しました!", "Failed to load '%s'!"), mes);
             } else {
-                msg_format(_("'%s'を読み込みました。", "Loaded '%s'."), tmp);
+                msg_format(_("'%s'を読み込みました。", "Loaded '%s'."), mes);
             }
-        } else if (key == '2') {
+
+            break;
+        }
+        case '2': {
             prt(_("コマンド: マクロをファイルに追加する", "Command: Append macros to a file"), 16, 0);
             prt(_("ファイル: ", "File: "), 18, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 80)) {
+            const auto ask_result = askfor(70, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            macro_dump(&auto_dump_stream, tmp);
+            macro_dump(&auto_dump_stream, *ask_result);
             msg_print(_("マクロを追加しました。", "Appended macros."));
-        } else if (key == '3') {
+            break;
+        }
+        case '3': {
             prt(_("コマンド: マクロの確認", "Command: Query a macro"), 16, 0);
             prt(_("マクロ行動が(もしあれば)下に表示されます:", "Current action (if any) shown below:"), 20, 0);
             prt(_("トリガーキー: ", "Trigger: "), 18, 0);
             do_cmd_macro_aux(buf);
-            int k = macro_find_exact(buf);
+            const auto k = macro_find_exact(buf);
             if (k < 0) {
                 msg_print(_("そのキーにはマクロは定義されていません。", "Found no macro."));
-            } else {
-                // マクロの作成時に参照するためmacro_bufにコピーする
-                strncpy(macro_buf, macro__act[k].data(), sizeof(macro_buf) - 1);
-                // too long macro must die
-                strncpy(tmp, macro_buf, 80);
-                tmp[80] = '\0';
-                ascii_to_text(buf, tmp, sizeof(buf));
-                prt(buf, 22, 0);
-                msg_print(_("マクロを確認しました。", "Found a macro."));
+                break;
             }
-        } else if (key == '4') {
+
+            // マクロの作成時に参照するためmacro_bufにコピーする
+            angband_strcpy(macro_buf, macro_actions[k].data(), sizeof(macro_buf));
+            char tmp[81]{};
+            angband_strcpy(tmp, macro_buf, sizeof(tmp));
+            ascii_to_text(buf, tmp, sizeof(buf));
+            prt(buf, 22, 0);
+            msg_print(_("マクロを確認しました。", "Found a macro."));
+            break;
+        }
+        case '4': {
             prt(_("コマンド: マクロの作成", "Command: Create a macro"), 16, 0);
             prt(_("トリガーキー: ", "Trigger: "), 18, 0);
             do_cmd_macro_aux(buf);
@@ -239,29 +245,38 @@ void do_cmd_macros(PlayerType *player_ptr)
             prt(_("マクロ行動: ", "Action: "), 20, 0);
             // 最後に参照したマクロデータを元に作成する(コピーを行えるように)
             macro_buf[80] = '\0';
+            char tmp[81]{};
             ascii_to_text(tmp, macro_buf, sizeof(tmp));
-            if (askfor(tmp, 80)) {
-                text_to_ascii(macro_buf, tmp, sizeof(macro_buf));
-                macro_add(buf, macro_buf);
-                msg_print(_("マクロを追加しました。", "Added a macro."));
+            const auto ask_result = askfor(80, tmp);
+            if (!ask_result) {
+                break;
             }
-        } else if (key == '5') {
+
+            text_to_ascii(macro_buf, *ask_result, sizeof(macro_buf));
+            macro_add(buf, macro_buf);
+            msg_print(_("マクロを追加しました。", "Added a macro."));
+            break;
+        }
+        case '5':
             prt(_("コマンド: マクロの削除", "Command: Remove a macro"), 16, 0);
             prt(_("トリガーキー: ", "Trigger: "), 18, 0);
             do_cmd_macro_aux(buf);
             macro_add(buf, buf);
             msg_print(_("マクロを削除しました。", "Removed a macro."));
-        } else if (key == '6') {
+            break;
+        case '6': {
             prt(_("コマンド: キー配置をファイルに追加する", "Command: Append keymaps to a file"), 16, 0);
             prt(_("ファイル: ", "File: "), 18, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 80)) {
+            const auto ask_result = askfor(80, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            (void)keymap_dump(tmp);
+            (void)keymap_dump(*ask_result);
             msg_print(_("キー配置を追加しました。", "Appended keymaps."));
-        } else if (key == '7') {
+            break;
+        }
+        case '7': {
             prt(_("コマンド: キー配置の確認", "Command: Query a keymap"), 16, 0);
             prt(_("マクロ行動が(もしあれば)下に表示されます:", "Current action (if any) shown below:"), 20, 0);
             prt(_("押すキー: ", "Keypress: "), 18, 0);
@@ -269,17 +284,20 @@ void do_cmd_macros(PlayerType *player_ptr)
             concptr act = keymap_act[mode][(byte)(buf[0])];
             if (!act) {
                 msg_print(_("キー配置は定義されていません。", "Found no keymap."));
-            } else {
-                // マクロの作成時に参照するためmacro_bufにコピーする
-                strncpy(macro_buf, act, sizeof(macro_buf) - 1);
-                // too long macro must die
-                strncpy(tmp, macro_buf, 80);
-                tmp[80] = '\0';
-                ascii_to_text(buf, tmp, sizeof(buf));
-                prt(buf, 22, 0);
-                msg_print(_("キー配置を確認しました。", "Found a keymap."));
+                break;
             }
-        } else if (key == '8') {
+
+            // マクロの作成時に参照するためmacro_bufにコピーする
+            angband_strcpy(macro_buf, act, sizeof(macro_buf));
+            // too long macro must die
+            char tmp[81]{};
+            angband_strcpy(tmp, macro_buf, sizeof(tmp));
+            ascii_to_text(buf, tmp, sizeof(buf));
+            prt(buf, 22, 0);
+            msg_print(_("キー配置を確認しました。", "Found a keymap."));
+            break;
+        }
+        case '8': {
             prt(_("コマンド: キー配置の作成", "Command: Create a keymap"), 16, 0);
             prt(_("押すキー: ", "Keypress: "), 18, 0);
             do_cmd_macro_aux_keymap(buf);
@@ -290,35 +308,45 @@ void do_cmd_macros(PlayerType *player_ptr)
             prt(_("行動: ", "Action: "), 20, 0);
             // 最後に参照したマクロデータを元に作成する(コピーを行えるように)
             macro_buf[80] = '\0';
+            char tmp[81]{};
             ascii_to_text(tmp, macro_buf, sizeof(tmp));
-            if (askfor(tmp, 80)) {
-                text_to_ascii(macro_buf, tmp, sizeof(macro_buf));
-                string_free(keymap_act[mode][(byte)(buf[0])]);
-                keymap_act[mode][(byte)(buf[0])] = string_make(macro_buf);
-                msg_print(_("キー配置を追加しました。", "Added a keymap."));
+            const auto ask_result = askfor(80, tmp);
+            if (!ask_result) {
+                break;
             }
-        } else if (key == '9') {
+
+            text_to_ascii(macro_buf, *ask_result, sizeof(macro_buf));
+            string_free(keymap_act[mode][(byte)(buf[0])]);
+            keymap_act[mode][(byte)(buf[0])] = string_make(macro_buf);
+            msg_print(_("キー配置を追加しました。", "Added a keymap."));
+            break;
+        }
+        case '9':
             prt(_("コマンド: キー配置の削除", "Command: Remove a keymap"), 16, 0);
             prt(_("押すキー: ", "Keypress: "), 18, 0);
             do_cmd_macro_aux_keymap(buf);
             string_free(keymap_act[mode][(byte)(buf[0])]);
             keymap_act[mode][(byte)(buf[0])] = nullptr;
             msg_print(_("キー配置を削除しました。", "Removed a keymap."));
-        } else if (key == '0') {
+            break;
+        case '0': {
             prt(_("コマンド: マクロ行動の入力", "Command: Enter a new action"), 16, 0);
             c_prt(TERM_L_RED,
                 _("カーソルキーの左右でカーソル位置を移動。BackspaceかDeleteで一文字削除。",
                     "Press Left/Right arrow keys to move cursor. Backspace/Delete to delete a char."),
                 22, 0);
             prt(_("マクロ行動: ", "Action: "), 20, 0);
-            buf[0] = '\0';
-            if (!askfor(buf, 80)) {
+            const auto ask_result = askfor(80);
+            if (!ask_result) {
                 continue;
             }
 
-            text_to_ascii(macro_buf, buf, sizeof(macro_buf));
-        } else {
+            text_to_ascii(macro_buf, *ask_result, sizeof(macro_buf));
+            break;
+        }
+        default:
             bell();
+            break;
         }
 
         msg_erase();
index 0f95108..3b83812 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_macros(PlayerType *player_ptr);
index 3c72bd8..4c38dcb 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-io/cmd-menu-content-table.h"
+#include "cmd-io/cmd-menu-content-table.h"
 #include "player-info/class-types.h"
 #include "util/enum-converter.h"
 #include "util/int-char-converter.h"
index fc290b3..cdf65e5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <optional>
index 045b94a..fcb8f46 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 記念撮影のセーブとロード
  * @date 2020/04/22
  * @Author Hourier
@@ -7,18 +7,22 @@
 #include "cmd-io/cmd-process-screen.h"
 #include "cmd-visual/cmd-draw.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "core/visuals-reseter.h"
 #include "game-option/special-options.h"
 #include "io/files-util.h"
 #include "io/input-key-acceptor.h"
+#include "system/angband-exceptions.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "util/angband-files.h"
 #include "view/display-messages.h"
+#include <optional>
+#include <string>
+#include <string_view>
 
 // Encode the screen colors
 static char hack[17] = "dwsorgbuDWvyRGBU";
@@ -44,16 +48,15 @@ static concptr html_foot[3] = {
  * @brief 一時ファイルを読み込み、ファイルに書き出す
  * @param fff ファイルへの参照ポインタ
  * @param tempfff 一時ファイルへの参照ポインタ
- * @param buf バッファ
- * @param buf_size バッファサイズ
  * @param num_tag タグ番号
  * @todo io/ 以下に移したいところだが、このファイルの行数も大したことがないので一旦保留
  */
-static void read_temporary_file(FILE *fff, FILE *tmpfff, char buf[], size_t buf_size, int num_tag)
+static void read_temporary_file(FILE *fff, FILE *tmpfff, int num_tag)
 {
     bool is_first_line = true;
     int next_tag = num_tag + 1;
-    while (!angband_fgets(tmpfff, buf, buf_size)) {
+    char buf[2048]{};
+    while (!angband_fgets(tmpfff, buf, sizeof(buf))) {
         if (is_first_line) {
             if (strncmp(buf, tags[num_tag], strlen(tags[num_tag])) == 0) {
                 is_first_line = false;
@@ -141,34 +144,34 @@ static void screen_dump_lines(int wid, int hgt, FILE *fff)
 /*!
  * @brief ファイルへ書き込めない場合にエラーを表示する
  * @param fff ダンプファイルへの参照ポインタ
- * @param buf バッファ
- * @return ファイルへ書き込めるならTRUE、書き込めないならFALSE
+ * @param path 保存先HTMLファイルのパス
+ * @param need_message メッセージ表示の必要性
+ * @return メッセージを表示して後続処理を実行するか否か
  */
-static bool check_screen_html_can_open(FILE *fff, char *filename, int message)
+static bool check_screen_html_can_open(FILE *fff, const std::filesystem::path &path, bool need_message)
 {
     if (fff) {
         return true;
     }
-    if (message == 0) {
+
+    if (!need_message) {
         return false;
     }
 
-    msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), filename);
-    msg_print(nullptr);
-    return false;
+    const auto &path_str = path.string();
+    const auto mes = format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), path_str.data());
+    THROW_EXCEPTION(std::runtime_error, mes);
 }
 
 /*!
  * @brief HTMLヘッダを書き込む
  * @param tmpfff 一時ファイルへの参照ポインタ
  * @param fff 記念撮影ファイルへの参照ポインタ
- * @param buf バッファ
- * @param buf_size バッファサイズ
  */
-static void write_html_header(FILE *tmpfff, FILE *fff, char buf[], size_t buf_size)
+static void write_html_header(FILE *tmpfff, FILE *fff)
 {
     if (tmpfff) {
-        read_temporary_file(fff, tmpfff, buf, buf_size, 0);
+        read_temporary_file(fff, tmpfff, 0);
         return;
     }
 
@@ -181,10 +184,8 @@ static void write_html_header(FILE *tmpfff, FILE *fff, char buf[], size_t buf_si
  * @brief HTMLフッタを書き込む
  * @param tmpfff 一時ファイルへの参照ポインタ
  * @param fff 記念撮影ファイルへの参照ポインタ
- * @param buf バッファ
- * @param buf_size バッファサイズ
  */
-static void write_html_footer(FILE *tmpfff, FILE *fff, char buf[], size_t buf_size)
+static void write_html_footer(FILE *tmpfff, FILE *fff)
 {
     fprintf(fff, "</font>");
     if (!tmpfff) {
@@ -193,57 +194,54 @@ static void write_html_footer(FILE *tmpfff, FILE *fff, char buf[], size_t buf_si
         }
     } else {
         rewind(tmpfff);
-        read_temporary_file(fff, tmpfff, buf, buf_size, 2);
+        read_temporary_file(fff, tmpfff, 2);
         angband_fclose(tmpfff);
     }
 
     fprintf(fff, "\n");
 }
 
-void do_cmd_save_screen_html_aux(char *filename, int message)
+void exe_cmd_save_screen_html(const std::filesystem::path &path, bool need_message)
 {
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-    auto *fff = angband_fopen(filename, FileOpenMode::WRITE);
-    if (!check_screen_html_can_open(fff, filename, message)) {
+    const auto &[wid, hgt] = term_get_size();
+    auto *fff = angband_fopen(path, FileOpenMode::WRITE, false, FileOpenType::HTML);
+    if (!check_screen_html_can_open(fff, path, need_message)) {
         return;
     }
 
-    if (message) {
+    if (need_message) {
         screen_save();
     }
 
-    char buf[2048];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "htmldump.prf");
-    auto *tmpfff = angband_fopen(buf, FileOpenMode::READ);
-    write_html_header(tmpfff, fff, buf, sizeof(buf));
+    const auto &path_prf = path_build(ANGBAND_DIR_USER, "htmldump.prf");
+    auto *tmpfff = angband_fopen(path_prf, FileOpenMode::READ);
+    write_html_header(tmpfff, fff);
     screen_dump_lines(wid, hgt, fff);
-    write_html_footer(tmpfff, fff, buf, sizeof(buf));
+    write_html_footer(tmpfff, fff);
     angband_fclose(fff);
-    if (message) {
-        msg_print(_("画面(記念撮影)をファイルに書き出しました。", "Screen dump saved."));
-        msg_print(nullptr);
+    if (!need_message) {
+        return;
     }
 
-    if (message) {
-        screen_load();
-    }
+    msg_print(_("画面(記念撮影)をファイルに書き出しました。", "Screen dump saved."));
+    msg_print(nullptr);
+    screen_load();
 }
 
 /*!
  * @brief HTML方式で記念撮影する / Save a screen dump to a file
  * @param なし
  */
-static void do_cmd_save_screen_html(void)
+static void exe_cmd_save_screen_html_with_naming()
 {
-    char buf[1024], tmp[256] = "screen.html";
-    if (!get_string(_("ファイル名: ", "File name: "), tmp, 80)) {
+    const auto filename = input_string(_("ファイル名: ", "File name: "), 80, "screen.html");
+    if (!filename) {
         return;
     }
 
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
+    auto path = path_build(ANGBAND_DIR_USER, *filename);
     msg_print(nullptr);
-    do_cmd_save_screen_html_aux(buf, 1);
+    exe_cmd_save_screen_html(path, true);
 }
 
 /*!
@@ -276,16 +274,15 @@ static bool ask_html_dump(bool *html_dump)
 /*!
  * @brief ファイルへ書き込めない場合にエラーを表示する
  * @param fff ダンプファイルへの参照ポインタ
- * @param buf バッファ
  * @return ファイルへ書き込めるならTRUE、書き込めないならFALSE
  */
-static bool check_screen_text_can_open(FILE *fff, char buf[])
+static bool check_screen_text_can_open(FILE *fff, const std::string_view filename)
 {
     if (fff) {
         return true;
     }
 
-    msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), buf);
+    msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), filename.data());
     msg_print(nullptr);
     return false;
 }
@@ -301,16 +298,16 @@ static bool do_cmd_save_screen_text(int wid, int hgt)
 {
     TERM_COLOR a = 0;
     auto c = ' ';
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "dump.txt");
-    auto *fff = angband_fopen(buf, FileOpenMode::WRITE);
-    if (!check_screen_text_can_open(fff, buf)) {
+    const auto &path = path_build(ANGBAND_DIR_USER, "dump.txt");
+    auto *fff = angband_fopen(path, FileOpenMode::WRITE);
+    if (!check_screen_text_can_open(fff, path.string())) {
         return false;
     }
 
     screen_save();
     for (TERM_LEN y = 0; y < hgt; y++) {
         TERM_LEN x;
+        char buf[1024]{};
         for (x = 0; x < wid - 1; x++) {
             (void)(term_what(x, y, &a, &c));
             buf[x] = c;
@@ -323,6 +320,7 @@ static bool do_cmd_save_screen_text(int wid, int hgt)
     fprintf(fff, "\n");
     for (TERM_LEN y = 0; y < hgt; y++) {
         TERM_LEN x;
+        char buf[1024]{};
         for (x = 0; x < wid - 1; x++) {
             (void)(term_what(x, y, &a, &c));
             buf[x] = hack[a & 0x0F];
@@ -353,7 +351,14 @@ static bool update_use_graphics(PlayerType *player_ptr)
 
     use_graphics = false;
     reset_visuals(player_ptr);
-    player_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
+    static constexpr auto flags = {
+        MainWindowRedrawingFlag::WIPE,
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::EQUIPPY,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     handle_stuff(player_ptr);
     return false;
 }
@@ -370,13 +375,11 @@ void do_cmd_save_screen(PlayerType *player_ptr)
         return;
     }
 
-    int wid, hgt;
-    term_get_size(&wid, &hgt);
-
-    bool old_use_graphics = update_use_graphics(player_ptr);
+    const auto &[wid, hgt] = term_get_size();
+    const auto old_use_graphics = update_use_graphics(player_ptr);
 
     if (html_dump) {
-        do_cmd_save_screen_html();
+        exe_cmd_save_screen_html_with_naming();
         do_cmd_redraw(player_ptr);
     } else if (!do_cmd_save_screen_text(wid, hgt)) {
         return;
@@ -388,7 +391,14 @@ void do_cmd_save_screen(PlayerType *player_ptr)
 
     use_graphics = true;
     reset_visuals(player_ptr);
-    player_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
+    static constexpr auto flags = {
+        MainWindowRedrawingFlag::WIPE,
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::EQUIPPY,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     handle_stuff(player_ptr);
 }
 
@@ -401,11 +411,12 @@ void do_cmd_save_screen(PlayerType *player_ptr)
  * @todo 目的は不明瞭
  * @return ファイルが読み込めなくなったらFALSEで抜ける
  */
-static bool draw_white_characters(char buf[], FILE *fff, int wid, int hgt)
+static bool draw_white_characters(FILE *fff, int wid, int hgt)
 {
     bool okay = true;
     for (TERM_LEN y = 0; okay; y++) {
-        if (!fgets(buf, 1024, fff)) {
+        char buf[1024]{};
+        if (!fgets(buf, sizeof(buf), fff)) {
             okay = false;
         }
 
@@ -430,19 +441,19 @@ static bool draw_white_characters(char buf[], FILE *fff, int wid, int hgt)
 
 /*!
  * @brief 白以外の文字を画面に描画する
- * @param buf 描画用バッファ
  * @param fff 記念撮影ファイルへの参照ポインタ
  * @param wid 幅
  * @param hgt 高さ
  * @param 白文字が途中で読み込めなくなっていたらTRUE
  * @todo 目的は不明瞭
  */
-static void draw_colored_characters(char buf[], FILE *fff, int wid, int hgt, bool okay)
+static void draw_colored_characters(FILE *fff, int wid, int hgt, bool okay)
 {
     TERM_COLOR a = TERM_DARK;
     auto c = ' ';
     for (TERM_LEN y = 0; okay; y++) {
-        if (!fgets(buf, 1024, fff)) {
+        char buf[1024]{};
+        if (!fgets(buf, sizeof(buf), fff)) {
             okay = false;
         }
 
@@ -476,21 +487,20 @@ static void draw_colored_characters(char buf[], FILE *fff, int wid, int hgt, boo
  */
 void do_cmd_load_screen(void)
 {
-    char buf[1024];
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "dump.txt");
-    auto *fff = angband_fopen(buf, FileOpenMode::READ);
+    const auto &[wid, hgt] = term_get_size();
+    const auto path = path_build(ANGBAND_DIR_USER, "dump.txt");
+    auto *fff = angband_fopen(path, FileOpenMode::READ);
     if (!fff) {
-        msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), buf);
+        const auto filename = path.string();
+        msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), filename.data());
         msg_print(nullptr);
         return;
     }
 
     screen_save();
     term_clear();
-    bool okay = draw_white_characters(buf, fff, wid, hgt);
-    draw_colored_characters(buf, fff, wid, hgt, okay);
+    bool okay = draw_white_characters(fff, wid, hgt);
+    draw_colored_characters(fff, wid, hgt, okay);
 
     angband_fclose(fff);
     prt(_("ファイルに書き出された画面(記念撮影)をロードしました。", "Screen dump loaded."), 0, 0);
index 42b81c3..e826de6 100644 (file)
@@ -1,6 +1,8 @@
-#pragma once
+#pragma once
+
+#include <filesystem>
 
 class PlayerType;
-void do_cmd_save_screen_html_aux(char *filename, int message);
+void exe_cmd_save_screen_html(const std::filesystem::path &path, bool need_message);
 void do_cmd_save_screen(PlayerType *player_ptr);
 void do_cmd_load_screen(void);
index 7b7a8d8..f788d02 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-io/cmd-save.h"
+#include "cmd-io/cmd-save.h"
 #include "cmd-io/cmd-dump.h"
 #include "core/disturbance.h"
 #include "core/stuff-handler.h"
@@ -52,5 +52,5 @@ void do_cmd_save_and_exit(PlayerType *player_ptr)
 {
     player_ptr->playing = false;
     player_ptr->leaving = true;
-    exe_write_diary(player_ptr, DIARY_GAMESTART, 0, _("----ゲーム中断----", "--- Saved and Exited Game ---"));
+    exe_write_diary(player_ptr, DiaryKind::GAMESTART, 0, _("----ゲーム中断----", "--- Saved and Exited Game ---"));
 }
index f72b6a7..d537b25 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_save_game(PlayerType *player_ptr, int is_autosave);
index 35b8aaf..837a763 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 日記のサブタイトルを表すテキストの配列群
  * @date 2023/04/22
  * @author Hourier
index 75de647..2783da6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
index 471a901..74d94fe 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 雰囲気を表すテキストの配列群
  * @date 2020/03/08
  * @author Hourier
index 5a504f7..9f757c6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 8a3e7b9..e1a7ccb 100644 (file)
@@ -1,32 +1,32 @@
-#include "cmd-io/macro-util.h"
+#include "cmd-io/macro-util.h"
 
 /* Current macro action [1024] */
-std::vector<char> macro__buf;
+std::vector<char> macro_buffers;
 
 /* Array of macro patterns [MACRO_MAX] */
-std::vector<std::string> macro__pat;
+std::vector<std::string> macro_patterns;
 
 /* Array of macro actions [MACRO_MAX] */
-std::vector<std::string> macro__act;
+std::vector<std::string> macro_actions;
 
 /* Number of active macros */
-int16_t macro__num;
+int16_t active_macros;
 
 /* Expand macros in "get_com" or not */
 bool get_com_no_macros = false;
 
 /* Determine if any macros have ever started with a given character */
-static bool macro__use[256];
+static bool macro_uses[256];
 
 /* Find the macro (if any) which exactly matches the given pattern */
 int macro_find_exact(concptr pat)
 {
-    if (!macro__use[(byte)(pat[0])]) {
+    if (!macro_uses[(byte)(pat[0])]) {
         return -1;
     }
 
-    for (int i = 0; i < macro__num; ++i) {
-        if (!streq(macro__pat[i], pat)) {
+    for (int i = 0; i < active_macros; ++i) {
+        if (!streq(macro_patterns[i], pat)) {
             continue;
         }
 
@@ -41,12 +41,12 @@ int macro_find_exact(concptr pat)
  */
 int macro_find_check(concptr pat)
 {
-    if (!macro__use[(byte)(pat[0])]) {
+    if (!macro_uses[(byte)(pat[0])]) {
         return -1;
     }
 
-    for (int i = 0; i < macro__num; ++i) {
-        if (!prefix(macro__pat[i], pat)) {
+    for (int i = 0; i < active_macros; ++i) {
+        if (!prefix(macro_patterns[i], pat)) {
             continue;
         }
 
@@ -61,15 +61,15 @@ int macro_find_check(concptr pat)
  */
 int macro_find_maybe(concptr pat)
 {
-    if (!macro__use[(byte)(pat[0])]) {
+    if (!macro_uses[(byte)(pat[0])]) {
         return -1;
     }
 
-    for (int i = 0; i < macro__num; ++i) {
-        if (!prefix(macro__pat[i], pat)) {
+    for (int i = 0; i < active_macros; ++i) {
+        if (!prefix(macro_patterns[i], pat)) {
             continue;
         }
-        if (streq(macro__pat[i], pat)) {
+        if (streq(macro_patterns[i], pat)) {
             continue;
         }
 
@@ -86,16 +86,16 @@ int macro_find_ready(concptr pat)
 {
     int t, n = -1, s = -1;
 
-    if (!macro__use[(byte)(pat[0])]) {
+    if (!macro_uses[(byte)(pat[0])]) {
         return -1;
     }
 
-    for (int i = 0; i < macro__num; ++i) {
-        if (!prefix(pat, macro__pat[i])) {
+    for (int i = 0; i < active_macros; ++i) {
+        if (!prefix(pat, macro_patterns[i])) {
             continue;
         }
 
-        t = macro__pat[i].size();
+        t = macro_patterns[i].size();
         if ((n >= 0) && (s > t)) {
             continue;
         }
@@ -132,11 +132,11 @@ errr macro_add(concptr pat, concptr act)
 
     int n = macro_find_exact(pat);
     if (n < 0) {
-        n = macro__num++;
-        macro__pat[n] = pat;
+        n = active_macros++;
+        macro_patterns[n] = pat;
     }
 
-    macro__act[n] = act;
-    macro__use[(byte)(pat[0])] = true;
+    macro_actions[n] = act;
+    macro_uses[(byte)(pat[0])] = true;
     return 0;
 }
index 17d3930..543e723 100644 (file)
@@ -1,17 +1,17 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 #include <string>
 #include <vector>
 
-extern std::vector<char> macro__buf;
+extern std::vector<char> macro_buffers;
 
 extern bool get_com_no_macros;
 
-extern std::vector<std::string> macro__pat;
-extern std::vector<std::string> macro__act;
-extern int16_t macro__num;
+extern std::vector<std::string> macro_patterns;
+extern std::vector<std::string> macro_actions;
+extern int16_t active_macros;
 
 int macro_find_exact(concptr pat);
 int macro_find_check(concptr pat);
index 39cb216..574af00 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-item/cmd-destroy.h"
+#include "cmd-item/cmd-destroy.h"
 #include "autopick/autopick-registry.h"
 #include "autopick/autopick.h"
 #include "avatar/avatar.h"
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
 
 struct destroy_type {
-    OBJECT_IDX item;
-    QUANTITY amt;
-    QUANTITY old_number;
-    bool force;
-    ItemEntity *o_ptr;
-    ItemEntity *q_ptr;
-    std::string item_name;
-    char out_val[MAX_NLEN + 40];
+    short i_idx = 0;
+    QUANTITY amt = 0;
+    QUANTITY old_number = 0;
+    bool force = false;
+    ItemEntity *o_ptr = nullptr;
+    ItemEntity *q_ptr = nullptr;
+    std::string item_name = "";
+    char out_val[MAX_NLEN + 40]{};
 };
 
 static destroy_type *initialize_destroy_type(destroy_type *destroy_ptr, ItemEntity *o_ptr)
@@ -68,7 +69,7 @@ static bool check_destory_item(PlayerType *player_ptr, destroy_type *destroy_ptr
     strnfmt(destroy_ptr->out_val, sizeof(destroy_ptr->out_val), mes, destroy_ptr->item_name.data());
     msg_print(nullptr);
     message_add(destroy_ptr->out_val);
-    player_ptr->window_flags |= PW_MESSAGE;
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::MESSAGE);
     handle_stuff(player_ptr);
     while (true) {
         prt(destroy_ptr->out_val, 0, 0);
@@ -87,7 +88,7 @@ static bool check_destory_item(PlayerType *player_ptr, destroy_type *destroy_ptr
         }
 
         if (autopick_autoregister(player_ptr, destroy_ptr->o_ptr)) {
-            autopick_alter_item(player_ptr, destroy_ptr->item, true);
+            autopick_alter_item(player_ptr, destroy_ptr->i_idx, true);
         }
 
         return false;
@@ -96,9 +97,9 @@ static bool check_destory_item(PlayerType *player_ptr, destroy_type *destroy_ptr
 
 static bool select_destroying_item(PlayerType *player_ptr, destroy_type *destroy_ptr)
 {
-    concptr q = _("どのアイテムを壊しますか? ", "Destroy which item? ");
-    concptr s = _("壊せるアイテムを持っていない。", "You have nothing to destroy.");
-    destroy_ptr->o_ptr = choose_object(player_ptr, &destroy_ptr->item, q, s, USE_INVEN | USE_FLOOR);
+    constexpr auto q = _("どのアイテムを壊しますか? ", "Destroy which item? ");
+    constexpr auto s = _("壊せるアイテムを持っていない。", "You have nothing to destroy.");
+    destroy_ptr->o_ptr = choose_object(player_ptr, &destroy_ptr->i_idx, q, s, USE_INVEN | USE_FLOOR);
     if (destroy_ptr->o_ptr == nullptr) {
         return false;
     }
@@ -111,7 +112,7 @@ static bool select_destroying_item(PlayerType *player_ptr, destroy_type *destroy
         return true;
     }
 
-    destroy_ptr->amt = get_quantity(std::nullopt, destroy_ptr->o_ptr->number);
+    destroy_ptr->amt = input_quantity(destroy_ptr->o_ptr->number);
     return destroy_ptr->amt > 0;
 }
 
@@ -204,13 +205,13 @@ static void exe_destroy_item(PlayerType *player_ptr, destroy_type *destroy_ptr)
     msg_format(_("%sを壊した。", "You destroy %s."), destroy_ptr->item_name.data());
     sound(SOUND_DESTITEM);
     reduce_charges(destroy_ptr->o_ptr, destroy_ptr->amt);
-    vary_item(player_ptr, destroy_ptr->item, -destroy_ptr->amt);
+    vary_item(player_ptr, destroy_ptr->i_idx, -destroy_ptr->amt);
     process_destroy_magic_book(player_ptr, destroy_ptr);
     if ((destroy_ptr->q_ptr->to_a != 0) || (destroy_ptr->q_ptr->to_d != 0) || (destroy_ptr->q_ptr->to_h != 0)) {
         chg_virtue(player_ptr, Virtue::HARMONY, 1);
     }
 
-    if (destroy_ptr->item >= INVEN_MAIN_HAND) {
+    if (destroy_ptr->i_idx >= INVEN_MAIN_HAND) {
         calc_android_exp(player_ptr);
     }
 }
@@ -240,7 +241,7 @@ void do_cmd_destroy(PlayerType *player_ptr)
     destroy_ptr->o_ptr->number = destroy_ptr->old_number;
     PlayerEnergy energy(player_ptr);
     energy.set_player_turn_energy(100);
-    if (!can_player_destroy_object(player_ptr, destroy_ptr->o_ptr)) {
+    if (!can_player_destroy_object(destroy_ptr->o_ptr)) {
         energy.reset_player_turn();
         msg_format(_("%sは破壊不可能だ。", "You cannot destroy %s."), destroy_ptr->item_name.data());
         return;
index 366ad5d..e9d1e7f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_destroy(PlayerType *player_ptr);
index f09355c..6ab4658 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーの食べるコマンド実装
  * @date 2018/09/07
  @ @author deskull
@@ -6,7 +6,6 @@
 
 #include "cmd-item/cmd-eat.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -48,6 +47,7 @@
 #include "system/item-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 #include "view/object-describer.h"
@@ -65,7 +65,7 @@ static bool exe_eat_food_type_object(PlayerType *player_ptr, const BaseitemKey &
     }
 
     BadStatusSetter bss(player_ptr);
-    switch (bi_key.sval().value()) {
+    switch (*bi_key.sval()) {
     case SV_FOOD_POISON:
         return (!(has_resist_pois(player_ptr) || is_oppose_pois(player_ptr))) && bss.mod_poison(randint0(10) + 10);
     case SV_FOOD_BLINDNESS:
@@ -148,28 +148,28 @@ static bool exe_eat_food_type_object(PlayerType *player_ptr, const BaseitemKey &
  * @brief 魔法道具のチャージをの食料として食べたときの効果を発動
  * @param player_ptr プレイヤー情報への参照ポインタ
  * @param o_ptr 食べるオブジェクト
- * @param inventory オブジェクトのインベントリ番号
+ * @param i_idx オブジェクトのインベントリ番号
  * @return 食べようとしたらTRUE、しなかったらFALSE
  */
-static bool exe_eat_charge_of_magic_device(PlayerType *player_ptr, ItemEntity *o_ptr, short inventory)
+static bool exe_eat_charge_of_magic_device(PlayerType *player_ptr, ItemEntity *o_ptr, short i_idx)
 {
     if (!o_ptr->is_wand_staff() || (PlayerRace(player_ptr).food() != PlayerRaceFoodType::MANA)) {
         return false;
     }
 
     const auto is_staff = o_ptr->bi_key.tval() == ItemKindType::STAFF;
-    if (is_staff && (inventory < 0) && (o_ptr->number > 1)) {
+    if (is_staff && (i_idx < 0) && (o_ptr->number > 1)) {
         msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));
         return true;
     }
 
     const auto staff = is_staff ? _("杖", "staff") : _("魔法棒", "wand");
 
-    /* "Eat" charges */
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (o_ptr->pval == 0) {
         msg_format(_("この%sにはもう魔力が残っていない。", "The %s has no charges left."), staff);
         o_ptr->ident |= IDENT_EMPTY;
-        player_ptr->window_flags |= PW_INVENTORY;
+        rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
         return true;
     }
 
@@ -182,7 +182,7 @@ static bool exe_eat_charge_of_magic_device(PlayerType *player_ptr, ItemEntity *o
     set_food(player_ptr, player_ptr->food + 5000);
 
     /* XXX Hack -- unstack if necessary */
-    if (is_staff && (inventory >= 0) && (o_ptr->number > 1)) {
+    if (is_staff && (i_idx >= 0) && (o_ptr->number > 1)) {
         auto item = *o_ptr;
 
         /* Modify quantity */
@@ -193,25 +193,29 @@ static bool exe_eat_charge_of_magic_device(PlayerType *player_ptr, ItemEntity *o
 
         /* Unstack the used item */
         o_ptr->number--;
-        inventory = store_item_to_inventory(player_ptr, &item);
+        i_idx = store_item_to_inventory(player_ptr, &item);
         msg_format(_("杖をまとめなおした。", "You unstack your staff."));
     }
 
-    if (inventory >= 0) {
-        inven_item_charges(player_ptr->inventory_list[inventory]);
+    if (i_idx >= 0) {
+        inven_item_charges(player_ptr->inventory_list[i_idx]);
     } else {
-        floor_item_charges(player_ptr->current_floor_ptr, 0 - inventory);
+        floor_item_charges(player_ptr->current_floor_ptr, 0 - i_idx);
     }
 
-    player_ptr->window_flags |= PW_INVENTORY | PW_EQUIPMENT;
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+    };
+    rfu.set_flags(flags);
     return true;
 }
 
 /*!
  * @brief 食料を食べるコマンドのサブルーチン
- * @param item 食べるオブジェクトの所持品ID
+ * @param i_idx 食べるオブジェクトの所持品ID
  */
-void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item)
+void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
     if (music_singing_any(player_ptr)) {
         stop_singing(player_ptr);
@@ -222,7 +226,7 @@ void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item)
         (void)spell_hex.stop_all_spells();
     }
 
-    auto *o_ptr = ref_item(player_ptr, item);
+    auto *o_ptr = ref_item(player_ptr, i_idx);
 
     sound(SOUND_EAT);
 
@@ -240,9 +244,14 @@ void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item)
      * do not rearrange the inventory before the food item is destroyed in
      * the pack.
      */
-    BIT_FLAGS inventory_flags = (PU_COMBINATION | PU_REORDER | (player_ptr->update & PU_AUTO_DESTRUCTION));
-    player_ptr->update &= ~(PU_COMBINATION | PU_REORDER | PU_AUTO_DESTRUCTION);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    using Srf = StatusRecalculatingFlag;
+    EnumClassFlagGroup<Srf> flags_srf = { Srf::COMBINATION, Srf::REORDER };
+    if (rfu.has(Srf::AUTO_DESTRUCTION)) {
+        flags_srf.set(Srf::AUTO_DESTRUCTION);
+    }
 
+    rfu.reset_flags(flags_srf);
     if (!(o_ptr->is_aware())) {
         chg_virtue(player_ptr, Virtue::KNOWLEDGE, -1);
         chg_virtue(player_ptr, Virtue::PATIENCE, -1);
@@ -252,7 +261,7 @@ void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item)
     /* We have tried it */
     const auto tval = bi_key.tval();
     if (tval == ItemKindType::FOOD) {
-        object_tried(o_ptr);
+        o_ptr->mark_as_tried();
     }
 
     /* The player is now aware of the object */
@@ -261,11 +270,16 @@ void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item)
         gain_exp(player_ptr, (lev + (player_ptr->lev >> 1)) / player_ptr->lev);
     }
 
-    player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags_swrf);
 
     /* Undeads drain recharge of magic device */
-    if (exe_eat_charge_of_magic_device(player_ptr, o_ptr, item)) {
-        player_ptr->update |= inventory_flags;
+    if (exe_eat_charge_of_magic_device(player_ptr, o_ptr, i_idx)) {
+        rfu.set_flags(flags_srf);
         return;
     }
 
@@ -273,13 +287,14 @@ void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item)
 
     /* Balrogs change humanoid corpses to energy */
     const auto corpse_r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
-    if (food_type == PlayerRaceFoodType::CORPSE && (bi_key == BaseitemKey(ItemKindType::CORPSE, SV_CORPSE) && angband_strchr("pht", monraces_info[corpse_r_idx].d_char))) {
+    const auto search = angband_strchr("pht", monraces_info[corpse_r_idx].d_char);
+    if (food_type == PlayerRaceFoodType::CORPSE && o_ptr->is_corpse() && (search != nullptr)) {
         const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
         msg_format(_("%sは燃え上り灰になった。精力を吸収した気がする。", "%s^ is burnt to ashes.  You absorb its vitality!"), item_name.data());
         (void)set_food(player_ptr, PY_FOOD_MAX - 1);
 
-        player_ptr->update |= inventory_flags;
-        vary_item(player_ptr, item, -1);
+        rfu.set_flags(flags_srf);
+        vary_item(player_ptr, i_idx, -1);
         return;
     }
 
@@ -321,8 +336,8 @@ void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item)
         }
     }
 
-    player_ptr->update |= inventory_flags;
-    vary_item(player_ptr, item, -1);
+    rfu.set_flags(flags_srf);
+    vary_item(player_ptr, i_idx, -1);
 }
 
 /*!
@@ -331,17 +346,13 @@ void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item)
  */
 void do_cmd_eat_food(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    concptr q, s;
-
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
-
-    q = _("どれを食べますか? ", "Eat which item? ");
-    s = _("食べ物がない。", "You have nothing to eat.");
-
-    if (!choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(item_tester_hook_eatable, player_ptr))) {
+    constexpr auto q = _("どれを食べますか? ", "Eat which item? ");
+    constexpr auto s = _("食べ物がない。", "You have nothing to eat.");
+    short i_idx;
+    if (!choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(item_tester_hook_eatable, player_ptr))) {
         return;
     }
 
-    exe_eat_food(player_ptr, item);
+    exe_eat_food(player_ptr, i_idx);
 }
index 7af0611..a20a74a 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 class PlayerType;
 void do_cmd_eat_food(PlayerType *player_ptr);
-void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX item);
+void exe_eat_food(PlayerType *player_ptr, INVENTORY_IDX i_idx);
index a2c5843..20a5ef4 100644 (file)
@@ -1,11 +1,9 @@
-#include "cmd-item/cmd-equipment.h"
+#include "cmd-item/cmd-equipment.h"
 #include "action/weapon-shield.h"
 #include "artifact/fixed-art-types.h"
 #include "autopick/autopick.h"
 #include "avatar/avatar.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "dungeon/quest.h" //!< @todo 違和感、何故アイテムを装備するとクエストの成功判定が走るのか?.
 #include "flavor/flavor-describer.h"
@@ -28,7 +26,6 @@
 #include "object-hook/hook-weapon.h"
 #include "object/item-tester-hooker.h"
 #include "object/item-use-flags.h"
-#include "object/object-flags.h"
 #include "object/object-info.h"
 #include "object/object-mark-types.h"
 #include "perception/object-perception.h"
@@ -47,6 +44,7 @@
 #include "status/shape-changer.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/bit-flags-calculator.h"
@@ -59,6 +57,7 @@
  */
 static void do_curse_on_equip(OBJECT_IDX slot, ItemEntity *o_ptr, PlayerType *player_ptr)
 {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (set_anubis_and_chariot(player_ptr) && ((slot == INVEN_MAIN_HAND) || (slot == INVEN_SUB_HAND))) {
 
         ItemEntity *anubis = &(player_ptr->inventory_list[INVEN_MAIN_HAND]);
@@ -72,11 +71,11 @@ static void do_curse_on_equip(OBJECT_IDX slot, ItemEntity *o_ptr, PlayerType *pl
         chariot->curse_flags.set(CurseTraitType::VUL_CURSE);
 
         msg_format(_("『銀の戦車』プラス『アヌビス神』二刀流ッ!", "*Silver Chariot* plus *Anubis God* Two Swords!"));
-        player_ptr->update |= (PU_BONUS);
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
         return;
     }
 
-    auto should_curse = object_flags(o_ptr).has(TR_PERSISTENT_CURSE) || o_ptr->curse_flags.has(CurseTraitType::PERSISTENT_CURSE);
+    auto should_curse = o_ptr->get_flags().has(TR_PERSISTENT_CURSE) || o_ptr->curse_flags.has(CurseTraitType::PERSISTENT_CURSE);
     should_curse &= o_ptr->curse_flags.has_not(CurseTraitType::HEAVY_CURSE);
     if (!should_curse) {
         return;
@@ -86,7 +85,7 @@ static void do_curse_on_equip(OBJECT_IDX slot, ItemEntity *o_ptr, PlayerType *pl
     o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
     msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), item_name.data());
     o_ptr->feeling = FEEL_NONE;
-    player_ptr->update |= (PU_BONUS);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 /*!
@@ -119,8 +118,7 @@ void do_cmd_equip(PlayerType *player_ptr)
         return;
     }
 
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
+    const auto &[wid, hgt] = term_get_size();
     command_new = 0;
     command_gap = wid - 30;
 }
@@ -131,23 +129,21 @@ void do_cmd_equip(PlayerType *player_ptr)
  */
 void do_cmd_wield(PlayerType *player_ptr)
 {
-    OBJECT_IDX item, slot;
     ItemEntity forge;
     ItemEntity *q_ptr;
-    ItemEntity *o_ptr;
     concptr act;
     OBJECT_IDX need_switch_wielding = 0;
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
 
-    concptr q = _("どれを装備しますか? ", "Wear/Wield which item? ");
-    concptr s = _("装備可能なアイテムがない。", "You have nothing you can wear or wield.");
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(item_tester_hook_wear, player_ptr));
+    constexpr auto selection_q = _("どれを装備しますか? ", "Wear/Wield which item? ");
+    constexpr auto selection_s = _("装備可能なアイテムがない。", "You have nothing you can wear or wield.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, selection_q, selection_s, (USE_INVEN | USE_FLOOR), FuncItemTester(item_tester_hook_wear, player_ptr));
     if (!o_ptr) {
         return;
     }
 
-    slot = wield_slot(player_ptr, o_ptr);
-
+    auto slot = wield_slot(player_ptr, o_ptr);
     const auto o_ptr_mh = &player_ptr->inventory_list[INVEN_MAIN_HAND];
     const auto o_ptr_sh = &player_ptr->inventory_list[INVEN_SUB_HAND];
     const auto tval = o_ptr->bi_key.tval();
@@ -156,8 +152,8 @@ void do_cmd_wield(PlayerType *player_ptr)
     case ItemKindType::SHIELD:
     case ItemKindType::CARD:
         if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND) && has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
-            q = _("どちらの武器と取り替えますか?", "Replace which weapon? ");
-            s = _("おっと。", "Oops.");
+            constexpr auto q = _("どちらの武器と取り替えますか?", "Replace which weapon? ");
+            constexpr auto s = _("おっと。", "Oops.");
             if (!choose_object(player_ptr, &slot, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT), FuncItemTester(&ItemEntity::is_melee_weapon))) {
                 return;
             }
@@ -169,8 +165,8 @@ void do_cmd_wield(PlayerType *player_ptr)
             slot = INVEN_MAIN_HAND;
         } else if (o_ptr_mh->is_valid() && o_ptr_sh->is_valid() &&
                    ((tval == ItemKindType::CAPTURE) || (!o_ptr_mh->is_melee_weapon() && !o_ptr_sh->is_melee_weapon()))) {
-            q = _("どちらの手に装備しますか?", "Equip which hand? ");
-            s = _("おっと。", "Oops.");
+            constexpr auto q = _("どちらの手に装備しますか?", "Equip which hand? ");
+            constexpr auto s = _("おっと。", "Oops.");
             if (!choose_object(player_ptr, &slot, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_wieldable_in_etheir_hand))) {
                 return;
             }
@@ -182,16 +178,16 @@ void do_cmd_wield(PlayerType *player_ptr)
     case ItemKindType::POLEARM:
     case ItemKindType::SWORD:
         if (slot == INVEN_SUB_HAND) {
-            if (!get_check(_("二刀流で戦いますか?", "Dual wielding? "))) {
+            if (!input_check(_("二刀流で戦いますか?", "Dual wielding? "))) {
                 slot = INVEN_MAIN_HAND;
             }
         } else if (!o_ptr_mh->is_valid() && has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
-            if (!get_check(_("二刀流で戦いますか?", "Dual wielding? "))) {
+            if (!input_check(_("二刀流で戦いますか?", "Dual wielding? "))) {
                 slot = INVEN_SUB_HAND;
             }
         } else if (o_ptr_mh->is_valid() && o_ptr_sh->is_valid()) {
-            q = _("どちらの手に装備しますか?", "Equip which hand? ");
-            s = _("おっと。", "Oops.");
+            constexpr auto q = _("どちらの手に装備しますか?", "Equip which hand? ");
+            constexpr auto s = _("おっと。", "Oops.");
             if (!choose_object(player_ptr, &slot, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_wieldable_in_etheir_hand))) {
                 return;
             }
@@ -202,23 +198,24 @@ void do_cmd_wield(PlayerType *player_ptr)
         }
 
         break;
-    case ItemKindType::RING:
+    case ItemKindType::RING: {
+        std::string q;
         if (player_ptr->inventory_list[INVEN_SUB_RING].is_valid() && player_ptr->inventory_list[INVEN_MAIN_RING].is_valid()) {
             q = _("どちらの指輪と取り替えますか?", "Replace which ring? ");
         } else {
             q = _("どちらの手に装備しますか?", "Equip which hand? ");
         }
 
-        s = _("おっと。", "Oops.");
+        constexpr auto s = _("おっと。", "Oops.");
         player_ptr->select_ring_slot = true;
-        if (!choose_object(player_ptr, &slot, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT))) {
+        if (!choose_object(player_ptr, &slot, q.data(), s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT))) {
             player_ptr->select_ring_slot = false;
             return;
         }
 
         player_ptr->select_ring_slot = false;
         break;
-
+    }
     default:
         break;
     }
@@ -238,7 +235,7 @@ void do_cmd_wield(PlayerType *player_ptr)
     should_equip_cursed &= confirm_wear;
     if (should_equip_cursed) {
         const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
-        if (!get_check(format(_("本当に%s{呪われている}を使いますか?", "Really use the %s {cursed}? "), item_name.data()))) {
+        if (!input_check(format(_("本当に%s{呪われている}を使いますか?", "Really use the %s {cursed}? "), item_name.data()))) {
             return;
         }
     }
@@ -252,7 +249,7 @@ void do_cmd_wield(PlayerType *player_ptr)
         const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
         constexpr auto mes = _("%sを装備すると吸血鬼になります。よろしいですか?",
             "%s will transform you into a vampire permanently when equipped. Do you become a vampire? ");
-        if (!get_check(format(mes, item_name.data()))) {
+        if (!input_check(format(mes, item_name.data()))) {
             return;
         }
     }
@@ -275,19 +272,19 @@ void do_cmd_wield(PlayerType *player_ptr)
     check_find_art_quest_completion(player_ptr, o_ptr);
     if (player_ptr->ppersonality == PERSONALITY_MUNCHKIN) {
         identify_item(player_ptr, o_ptr);
-        autopick_alter_item(player_ptr, item, false);
+        autopick_alter_item(player_ptr, i_idx, false);
     }
 
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
     q_ptr = &forge;
     q_ptr->copy_from(o_ptr);
     q_ptr->number = 1;
-    if (item >= 0) {
-        inven_item_increase(player_ptr, item, -1);
-        inven_item_optimize(player_ptr, item);
+    if (i_idx >= 0) {
+        inven_item_increase(player_ptr, i_idx, -1);
+        inven_item_optimize(player_ptr, i_idx);
     } else {
-        floor_item_increase(player_ptr, 0 - item, -1);
-        floor_item_optimize(player_ptr, 0 - item);
+        floor_item_increase(player_ptr, 0 - i_idx, -1);
+        floor_item_optimize(player_ptr, 0 - i_idx);
     }
 
     o_ptr = &player_ptr->inventory_list[slot];
@@ -340,14 +337,29 @@ void do_cmd_wield(PlayerType *player_ptr)
     }
 
     do_curse_on_equip(slot, o_ptr, player_ptr);
-    if (o_ptr->is_specific_artifact(FixedArtifactId::STONEMASK) && !pr.equals(PlayerRaceType::VAMPIRE) && !pr.equals(PlayerRaceType::ANDROID)) {
-        change_race(player_ptr, PlayerRaceType::VAMPIRE, "");
+    if (o_ptr->is_specific_artifact(FixedArtifactId::STONEMASK)) {
+        auto is_specific_race = pr.equals(PlayerRaceType::VAMPIRE);
+        is_specific_race |= pr.equals(PlayerRaceType::ANDROID);
+        if (!is_specific_race) {
+            change_race(player_ptr, PlayerRaceType::VAMPIRE, "");
+        }
     }
 
     calc_android_exp(player_ptr);
-    player_ptr->update |= PU_BONUS | PU_TORCH | PU_MP;
-    player_ptr->redraw |= PR_EQUIPPY;
-    player_ptr->window_flags |= PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER;
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::TORCH,
+        StatusRecalculatingFlag::MP,
+    };
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(MainWindowRedrawingFlag::EQUIPPY);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
@@ -355,19 +367,19 @@ void do_cmd_wield(PlayerType *player_ptr)
  */
 void do_cmd_takeoff(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
     PlayerClass pc(player_ptr);
     pc.break_samurai_stance({ SamuraiStanceType::MUSOU });
 
-    concptr q = _("どれを装備からはずしますか? ", "Take off which item? ");
-    concptr s = _("はずせる装備がない。", "You are not wearing anything to take off.");
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT));
+    constexpr auto q = _("どれを装備からはずしますか? ", "Take off which item? ");
+    constexpr auto s = _("はずせる装備がない。", "You are not wearing anything to take off.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT));
     if (!o_ptr) {
         return;
     }
 
     PlayerEnergy energy(player_ptr);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (o_ptr->is_cursed()) {
         if (o_ptr->curse_flags.has(CurseTraitType::PERMA_CURSE) || !pc.equals(PlayerClassType::BERSERKER)) {
             msg_print(_("ふーむ、どうやら呪われているようだ。", "Hmmm, it seems to be cursed."));
@@ -379,8 +391,8 @@ void do_cmd_takeoff(PlayerType *player_ptr)
             o_ptr->ident |= (IDENT_SENSE);
             o_ptr->curse_flags.clear();
             o_ptr->feeling = FEEL_NONE;
-            player_ptr->update |= PU_BONUS;
-            player_ptr->window_flags |= PW_EQUIPMENT;
+            rfu.set_flag(StatusRecalculatingFlag::BONUS);
+            rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
             msg_print(_("呪いを打ち破った。", "You break the curse."));
         } else {
             msg_print(_("装備を外せなかった。", "You couldn't remove the equipment."));
@@ -391,10 +403,20 @@ void do_cmd_takeoff(PlayerType *player_ptr)
 
     sound(SOUND_TAKE_OFF);
     energy.set_player_turn_energy(50);
-    (void)inven_takeoff(player_ptr, item, 255);
-    verify_equip_slot(player_ptr, item);
+    (void)inven_takeoff(player_ptr, i_idx, 255);
+    verify_equip_slot(player_ptr, i_idx);
     calc_android_exp(player_ptr);
-    player_ptr->update |= PU_BONUS | PU_TORCH | PU_MP;
-    player_ptr->redraw |= PR_EQUIPPY;
-    player_ptr->window_flags |= PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER;
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::TORCH,
+        StatusRecalculatingFlag::MP,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(MainWindowRedrawingFlag::EQUIPPY);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags_swrf);
 }
index 2163ff7..04be04f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_equip(PlayerType *player_ptr);
index 8c77949..000b839 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  *  @brief プレイヤーのアイテムに関するコマンドの実装1 / Inventory and equipment commands
  *  @date 2014/01/02
  *  @author
@@ -22,8 +22,6 @@
 #include "cmd-item/cmd-zapwand.h"
 #include "combat/shoot.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "status/action-setter.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/bit-flags-calculator.h"
 #include "util/int-char-converter.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include "view/display-inventory.h"
 #include "view/display-messages.h"
@@ -101,8 +99,7 @@ void do_cmd_inven(PlayerType *player_ptr)
         return;
     }
 
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
+    const auto &[wid, hgt] = term_get_size();
     command_new = 0;
     command_gap = wid - 30;
 }
@@ -112,38 +109,37 @@ void do_cmd_inven(PlayerType *player_ptr)
  */
 void do_cmd_drop(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
     int amt = 1;
-    ItemEntity *o_ptr;
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
 
-    concptr q = _("どのアイテムを落としますか? ", "Drop which item? ");
-    concptr s = _("落とせるアイテムを持っていない。", "You have nothing to drop.");
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | IGNORE_BOTHHAND_SLOT));
+    constexpr auto q = _("どのアイテムを落としますか? ", "Drop which item? ");
+    constexpr auto s = _("落とせるアイテムを持っていない。", "You have nothing to drop.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | IGNORE_BOTHHAND_SLOT));
     if (!o_ptr) {
         return;
     }
 
-    if ((item >= INVEN_MAIN_HAND) && o_ptr->is_cursed()) {
+    if ((i_idx >= INVEN_MAIN_HAND) && o_ptr->is_cursed()) {
         msg_print(_("ふーむ、どうやら呪われているようだ。", "Hmmm, it seems to be cursed."));
         return;
     }
 
     if (o_ptr->number > 1) {
-        amt = get_quantity(std::nullopt, o_ptr->number);
+        amt = input_quantity(o_ptr->number);
         if (amt <= 0) {
             return;
         }
     }
 
     PlayerEnergy(player_ptr).set_player_turn_energy(50);
-    drop_from_inventory(player_ptr, item, amt);
-    if (item >= INVEN_MAIN_HAND) {
-        verify_equip_slot(player_ptr, item);
+    drop_from_inventory(player_ptr, i_idx, amt);
+    if (i_idx >= INVEN_MAIN_HAND) {
+        verify_equip_slot(player_ptr, i_idx);
         calc_android_exp(player_ptr);
     }
 
-    player_ptr->redraw |= (PR_EQUIPPY);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::EQUIPPY);
 }
 
 /*!
@@ -151,10 +147,10 @@ void do_cmd_drop(PlayerType *player_ptr)
  */
 void do_cmd_observe(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    const auto q = _("どのアイテムを調べますか? ", "Examine which item? ");
-    const auto s = _("調べられるアイテムがない。", "You have nothing to examine.");
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
+    constexpr auto q = _("どのアイテムを調べますか? ", "Examine which item? ");
+    constexpr auto s = _("調べられるアイテムがない。", "You have nothing to examine.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
     if (!o_ptr) {
         return;
     }
@@ -177,11 +173,10 @@ void do_cmd_observe(PlayerType *player_ptr)
  */
 void do_cmd_uninscribe(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
-    concptr q = _("どのアイテムの銘を消しますか? ", "Un-inscribe which item? ");
-    concptr s = _("銘を消せるアイテムがない。", "You have nothing to un-inscribe.");
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
+    constexpr auto q = _("どのアイテムの銘を消しますか? ", "Un-inscribe which item? ");
+    constexpr auto s = _("銘を消せるアイテムがない。", "You have nothing to un-inscribe.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
     if (!o_ptr) {
         return;
     }
@@ -193,9 +188,19 @@ void do_cmd_uninscribe(PlayerType *player_ptr)
 
     msg_print(_("銘を消した。", "Inscription removed."));
     o_ptr->inscription.reset();
-    set_bits(player_ptr->update, PU_COMBINATION);
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
-    set_bits(player_ptr->update, PU_BONUS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::BONUS,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
@@ -204,11 +209,10 @@ void do_cmd_uninscribe(PlayerType *player_ptr)
  */
 void do_cmd_inscribe(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    char out_val[MAX_INSCRIPTION + 1] = "";
-    const auto q = _("どのアイテムに銘を刻みますか? ", "Inscribe which item? ");
-    const auto s = _("銘を刻めるアイテムがない。", "You have nothing to inscribe.");
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
+    constexpr auto q = _("どのアイテムに銘を刻みますか? ", "Inscribe which item? ");
+    constexpr auto s = _("銘を刻めるアイテムがない。", "You have nothing to inscribe.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
     if (!o_ptr) {
         return;
     }
@@ -216,17 +220,26 @@ void do_cmd_inscribe(PlayerType *player_ptr)
     const auto item_name = describe_flavor(player_ptr, o_ptr, OD_OMIT_INSCRIPTION);
     msg_format(_("%sに銘を刻む。", "Inscribing %s."), item_name.data());
     msg_print(nullptr);
-    strcpy(out_val, "");
-    if (o_ptr->is_inscribed()) {
-        angband_strcpy(out_val, o_ptr->inscription->data(), MAX_INSCRIPTION);
+    const auto initial_inscription = o_ptr->is_inscribed() ? *o_ptr->inscription : "";
+    const auto input_inscription = input_string(_("銘: ", "Inscription: "), MAX_INSCRIPTION, initial_inscription);
+    if (!input_inscription) {
+        return;
     }
 
-    if (get_string(_("銘: ", "Inscription: "), out_val, MAX_INSCRIPTION)) {
-        o_ptr->inscription.emplace(out_val);
-        set_bits(player_ptr->update, PU_COMBINATION);
-        set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
-        set_bits(player_ptr->update, PU_BONUS);
-    }
+    o_ptr->inscription.emplace(*input_inscription);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::BONUS,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
@@ -242,11 +255,11 @@ void do_cmd_use(PlayerType *player_ptr)
     }
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
-    const auto q = _("どれを使いますか?", "Use which item? ");
-    const auto s = _("使えるものがありません。", "You have nothing to use.");
+    constexpr auto q = _("どれを使いますか?", "Use which item? ");
+    constexpr auto s = _("使えるものがありません。", "You have nothing to use.");
     const auto options = USE_INVEN | USE_EQUIP | USE_FLOOR | IGNORE_BOTHHAND_SLOT;
-    short item;
-    const auto *o_ptr = choose_object(player_ptr, &item, q, s, options, FuncItemTester(item_tester_hook_use, player_ptr));
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, FuncItemTester(item_tester_hook_use, player_ptr));
     if (o_ptr == nullptr) {
         return;
     }
@@ -256,34 +269,34 @@ void do_cmd_use(PlayerType *player_ptr)
         do_cmd_spike(player_ptr);
         break;
     case ItemKindType::FOOD:
-        exe_eat_food(player_ptr, item);
+        exe_eat_food(player_ptr, i_idx);
         break;
     case ItemKindType::WAND:
-        ObjectZapWandEntity(player_ptr).execute(item);
+        ObjectZapWandEntity(player_ptr).execute(i_idx);
         break;
     case ItemKindType::STAFF:
-        ObjectUseEntity(player_ptr, item).execute();
+        ObjectUseEntity(player_ptr, i_idx).execute();
         break;
     case ItemKindType::ROD:
-        ObjectZapRodEntity(player_ptr).execute(item);
+        ObjectZapRodEntity(player_ptr).execute(i_idx);
         break;
     case ItemKindType::POTION:
-        ObjectQuaffEntity(player_ptr).execute(item);
+        ObjectQuaffEntity(player_ptr).execute(i_idx);
         break;
     case ItemKindType::SCROLL:
         if (cmd_limit_blind(player_ptr) || cmd_limit_confused(player_ptr)) {
             return;
         }
 
-        ObjectReadEntity(player_ptr, item).execute(true);
+        ObjectReadEntity(player_ptr, i_idx).execute(true);
         break;
     case ItemKindType::SHOT:
     case ItemKindType::ARROW:
     case ItemKindType::BOLT:
-        exe_fire(player_ptr, item, &player_ptr->inventory_list[INVEN_BOW], SP_NONE);
+        exe_fire(player_ptr, i_idx, &player_ptr->inventory_list[INVEN_BOW], SP_NONE);
         break;
     default:
-        exe_activate(player_ptr, item);
+        exe_activate(player_ptr, i_idx);
         break;
     }
 }
@@ -294,18 +307,17 @@ void do_cmd_use(PlayerType *player_ptr)
  */
 void do_cmd_activate(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
     if (player_ptr->wild_mode || cmd_limit_arena(player_ptr)) {
         return;
     }
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
-
-    concptr q = _("どのアイテムを始動させますか? ", "Activate which item? ");
-    concptr s = _("始動できるアイテムを装備していない。", "You have nothing to activate.");
-    if (!choose_object(player_ptr, &item, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT), FuncItemTester(&ItemEntity::is_activatable))) {
+    constexpr auto q = _("どのアイテムを始動させますか? ", "Activate which item? ");
+    constexpr auto s = _("始動できるアイテムを装備していない。", "You have nothing to activate.");
+    short i_idx;
+    if (!choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT), FuncItemTester(&ItemEntity::is_activatable))) {
         return;
     }
 
-    exe_activate(player_ptr, item);
+    exe_activate(player_ptr, i_idx);
 }
index e3c0eef..b549a74 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_inven(PlayerType *player_ptr);
index 2bd675e..806f704 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーのアイテムに関するコマンドの実装2 / Spell/Prayer commands
  * @date 2014/01/27
  * @author
@@ -136,18 +136,14 @@ static std::optional<BaseitemKey> check_magic_eater_spell_repeat(magic_eater_dat
  */
 static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, bool only_browse)
 {
-    char choice;
     bool flag, request_list;
     auto tval = ItemKindType::NONE;
-    OBJECT_SUBTYPE_VALUE i = 0;
-    char out_val[160];
-
     int menu_line = (use_menu ? 1 : 0);
 
     auto magic_eater_data = PlayerClass(player_ptr).get_specific_data<magic_eater_data_type>();
 
     if (auto result = check_magic_eater_spell_repeat(magic_eater_data.get());
-        result.has_value()) {
+        result) {
         return result;
     }
 
@@ -171,7 +167,7 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
                 prt(_("どの種類の魔法を使いますか?", "Which type of magic do you use?"), 0, 0);
             }
 
-            choice = inkey();
+            const auto choice = inkey();
             switch (choice) {
             case ESCAPE:
             case 'z':
@@ -207,17 +203,21 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
         screen_load();
     } else {
         while (true) {
-            if (!get_com(_("[A] 杖, [B] 魔法棒, [C] ロッド:", "[A] staff, [B] wand, [C] rod:"), &choice, true)) {
+            const auto choice = input_command(_("[A] 杖, [B] 魔法棒, [C] ロッド:", "[A] staff, [B] wand, [C] rod:"), true);
+            if (!choice) {
                 return std::nullopt;
             }
+
             if (choice == 'A' || choice == 'a') {
                 tval = ItemKindType::STAFF;
                 break;
             }
+
             if (choice == 'B' || choice == 'b') {
                 tval = ItemKindType::WAND;
                 break;
             }
+
             if (choice == 'C' || choice == 'c') {
                 tval = ItemKindType::ROD;
                 break;
@@ -241,21 +241,22 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
     /* Nothing chosen yet */
     flag = false;
 
+    std::string prompt;
     if (only_browse) {
-        strnfmt(out_val, 78, _("('*'で一覧, ESCで中断) どの魔力を見ますか?", "(*=List, ESC=exit) Browse which power? "));
+        prompt = _("('*'で一覧, ESCで中断) どの魔力を見ますか?", "(*=List, ESC=exit) Browse which power? ");
     } else {
-        strnfmt(out_val, 78, _("('*'で一覧, ESCで中断) どの魔力を使いますか?", "(*=List, ESC=exit) Use which power? "));
+        prompt = _("('*'で一覧, ESCで中断) どの魔力を使いますか?", "(*=List, ESC=exit) Use which power? ");
     }
-    screen_save();
 
+    screen_save();
     request_list = always_show_list;
 
-    const int ITEM_GROUP_SIZE = item_group.size();
+    const int item_group_size = item_group.size();
+    auto sval = 0;
     while (!flag) {
         /* Show the list */
         if (request_list || use_menu) {
             byte y, x = 0;
-            OBJECT_SUBTYPE_VALUE ctr;
             PERCENTAGE chance;
             short bi_id;
             POSITION x1, y1;
@@ -280,17 +281,17 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
 #endif
 
             /* Print list */
-            for (ctr = 0; ctr < ITEM_GROUP_SIZE; ctr++) {
-                auto &item = item_group[ctr];
+            for (auto sval_ctr = 0; sval_ctr < item_group_size; sval_ctr++) {
+                auto &item = item_group[sval_ctr];
                 if (item.count == 0) {
                     continue;
                 }
 
-                bi_id = lookup_baseitem_id({ tval, ctr });
+                bi_id = lookup_baseitem_id({ tval, sval_ctr });
 
                 std::string dummy;
                 if (use_menu) {
-                    if (ctr == (menu_line - 1)) {
+                    if (sval_ctr == (menu_line - 1)) {
                         dummy = _("》", "> ");
                     } else {
                         dummy = "  ";
@@ -299,15 +300,15 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
                 /* letter/number for power selection */
                 else {
                     char letter;
-                    if (ctr < 26) {
-                        letter = I2A(ctr);
+                    if (sval_ctr < 26) {
+                        letter = I2A(sval_ctr);
                     } else {
-                        letter = '0' + ctr - 26;
+                        letter = '0' + sval_ctr - 26;
                     }
                     dummy = format("%c)", letter);
                 }
-                x1 = ((ctr < ITEM_GROUP_SIZE / 2) ? x : x + 40);
-                y1 = ((ctr < ITEM_GROUP_SIZE / 2) ? y + ctr : y + ctr - ITEM_GROUP_SIZE / 2);
+                x1 = ((sval_ctr < item_group_size / 2) ? x : x + 40);
+                y1 = ((sval_ctr < item_group_size / 2) ? y + sval_ctr : y + sval_ctr - item_group_size / 2);
                 const auto &baseitem = baseitems_info[bi_id];
                 level = (tval == ItemKindType::ROD ? baseitem.level * 5 / 6 - 5 : baseitem.level);
                 chance = level * 4 / 5 + 20;
@@ -354,13 +355,14 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
             }
         }
 
-        if (!get_com(out_val, &choice, false)) {
+        const auto choice = input_command(prompt);
+        if (!choice) {
             break;
         }
 
         auto should_redraw_cursor = true;
         if (use_menu && choice != ' ') {
-            switch (choice) {
+            switch (*choice) {
             case '0': {
                 screen_load();
                 return std::nullopt;
@@ -370,9 +372,9 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
             case 'k':
             case 'K': {
                 do {
-                    menu_line += ITEM_GROUP_SIZE - 1;
-                    if (menu_line > ITEM_GROUP_SIZE) {
-                        menu_line -= ITEM_GROUP_SIZE;
+                    menu_line += item_group_size - 1;
+                    if (menu_line > item_group_size) {
+                        menu_line -= item_group_size;
                     }
                 } while (item_group[menu_line - 1].count == 0);
                 break;
@@ -383,8 +385,8 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
             case 'J': {
                 do {
                     menu_line++;
-                    if (menu_line > ITEM_GROUP_SIZE) {
-                        menu_line -= ITEM_GROUP_SIZE;
+                    if (menu_line > item_group_size) {
+                        menu_line -= item_group_size;
                     }
                 } while (item_group[menu_line - 1].count == 0);
                 break;
@@ -400,11 +402,11 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
                 if ((choice == '4') || (choice == 'h') || (choice == 'H')) {
                     reverse = true;
                 }
-                if (menu_line > ITEM_GROUP_SIZE / 2) {
-                    menu_line -= ITEM_GROUP_SIZE / 2;
+                if (menu_line > item_group_size / 2) {
+                    menu_line -= item_group_size / 2;
                     reverse = true;
                 } else {
-                    menu_line += ITEM_GROUP_SIZE / 2;
+                    menu_line += item_group_size / 2;
                 }
                 while (item_group[menu_line - 1].count == 0) {
                     if (reverse) {
@@ -414,7 +416,7 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
                         }
                     } else {
                         menu_line++;
-                        if (menu_line > ITEM_GROUP_SIZE - 1) {
+                        if (menu_line > item_group_size - 1) {
                             reverse = true;
                         }
                     }
@@ -425,7 +427,7 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
             case 'x':
             case 'X':
             case '\r': {
-                i = menu_line - 1;
+                sval = menu_line - 1;
                 should_redraw_cursor = false;
                 break;
             }
@@ -454,23 +456,23 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
         }
 
         if (!use_menu) {
-            if (isalpha(choice)) {
-                i = A2I(choice);
+            if (isalpha(*choice)) {
+                sval = A2I(*choice);
             } else {
-                i = choice - '0' + 26;
+                sval = *choice - '0' + 26;
             }
         }
 
         /* Totally Illegal */
-        if ((i < 0) || (i > ITEM_GROUP_SIZE) || item_group[i].count == 0) {
+        if ((sval < 0) || (sval > item_group_size) || item_group[sval].count == 0) {
             bell();
             continue;
         }
 
         if (!only_browse) {
-            auto &item = item_group[i];
+            auto &item = item_group[sval];
             if (tval == ItemKindType::ROD) {
-                if (item.charge > baseitems_info[lookup_baseitem_id({ tval, i })].pval * (item.count - 1) * EATER_ROD_CHARGE) {
+                if (item.charge > baseitems_info[lookup_baseitem_id({ tval, sval })].pval * (item.count - 1) * EATER_ROD_CHARGE) {
                     msg_print(_("その魔法はまだ充填している最中だ。", "The magic is still charging."));
                     msg_print(nullptr);
                     continue;
@@ -487,12 +489,12 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
         /* Browse */
         else {
             /* Clear lines, position cursor  (really should use strlen here) */
-            term_erase(7, 23, 255);
-            term_erase(7, 22, 255);
-            term_erase(7, 21, 255);
-            term_erase(7, 20, 255);
+            term_erase(7, 23);
+            term_erase(7, 22);
+            term_erase(7, 21);
+            term_erase(7, 20);
 
-            display_wrap_around(baseitems_info[lookup_baseitem_id({ tval, i })].text, 62, 21, 10);
+            display_wrap_around(baseitems_info[lookup_baseitem_id({ tval, sval })].text, 62, 21, 10);
             continue;
         }
 
@@ -520,9 +522,9 @@ static std::optional<BaseitemKey> select_magic_eater(PlayerType *player_ptr, boo
         break;
     }
 
-    repeat_push(base + i);
+    repeat_push(base + sval);
 
-    return BaseitemKey(tval, i);
+    return BaseitemKey(tval, sval);
 }
 
 /*!
@@ -542,11 +544,11 @@ bool do_cmd_magic_eater(PlayerType *player_ptr, bool only_browse, bool powerful)
 
     auto result = select_magic_eater(player_ptr, only_browse);
     PlayerEnergy energy(player_ptr);
-    if (!result.has_value()) {
+    if (!result) {
         energy.reset_player_turn();
         return false;
     }
-    auto &bi_key = result.value();
+    auto &bi_key = *result;
 
     const auto bi_id = lookup_baseitem_id(bi_key);
     const auto &baseitem = baseitems_info[bi_id];
@@ -586,7 +588,7 @@ bool do_cmd_magic_eater(PlayerType *player_ptr, bool only_browse, bool powerful)
         switch (bi_key.tval()) {
         case ItemKindType::ROD: {
             const auto sval = bi_key.sval();
-            if (!sval.has_value()) {
+            if (!sval) {
                 return false;
             }
 
@@ -594,7 +596,7 @@ bool do_cmd_magic_eater(PlayerType *player_ptr, bool only_browse, bool powerful)
                 return false;
             }
 
-            (void)rod_effect(player_ptr, sval.value(), dir, &use_charge, powerful);
+            (void)rod_effect(player_ptr, *sval, dir, &use_charge, powerful);
             if (!use_charge) {
                 return false;
             }
@@ -603,7 +605,7 @@ bool do_cmd_magic_eater(PlayerType *player_ptr, bool only_browse, bool powerful)
         }
         case ItemKindType::WAND: {
             const auto sval = bi_key.sval();
-            if (!sval.has_value()) {
+            if (!sval) {
                 return false;
             }
 
@@ -611,16 +613,16 @@ bool do_cmd_magic_eater(PlayerType *player_ptr, bool only_browse, bool powerful)
                 return false;
             }
 
-            (void)wand_effect(player_ptr, sval.value(), dir, powerful, true);
+            (void)wand_effect(player_ptr, *sval, dir, powerful, true);
             break;
         }
         default:
             const auto sval = bi_key.sval();
-            if (!sval.has_value()) {
+            if (!sval) {
                 return false;
             }
 
-            (void)staff_effect(player_ptr, sval.value(), &use_charge, powerful, true, true);
+            (void)staff_effect(player_ptr, *sval, &use_charge, powerful, true, true);
             if (!use_charge) {
                 return false;
             }
@@ -634,14 +636,13 @@ bool do_cmd_magic_eater(PlayerType *player_ptr, bool only_browse, bool powerful)
     }
 
     auto magic_eater_data = PlayerClass(player_ptr).get_specific_data<magic_eater_data_type>();
-    const auto opt_sval = bi_key.sval();
-    if (!opt_sval.has_value()) {
+    const auto sval = bi_key.sval();
+    if (!sval) {
         return false;
     }
 
     const auto tval = bi_key.tval();
-    const auto sval = opt_sval.value();
-    auto &item = magic_eater_data->get_item_group(tval)[sval];
+    auto &item = magic_eater_data->get_item_group(tval)[*sval];
 
     energy.set_player_turn_energy(100);
     if (tval == ItemKindType::ROD) {
index 18224ed..07c180f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool do_cmd_magic_eater(PlayerType *player_ptr, bool only_browse, bool powerful);
index 5822882..8562d8f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーの飲むコマンド実装
  * @date 2018/09/07
  * @author deskull
@@ -36,13 +36,13 @@ void do_cmd_quaff_potion(PlayerType *player_ptr)
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
 
-    concptr q = _("どの薬を飲みますか? ", "Quaff which potion? ");
-    concptr s = _("飲める薬がない。", "You have no potions to quaff.");
+    constexpr auto q = _("どの薬を飲みますか? ", "Quaff which potion? ");
+    constexpr auto s = _("飲める薬がない。", "You have no potions to quaff.");
 
-    OBJECT_IDX item;
-    if (!choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(item_tester_hook_quaff, player_ptr))) {
+    short i_idx;
+    if (!choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(item_tester_hook_quaff, player_ptr))) {
         return;
     }
 
-    ObjectQuaffEntity(player_ptr).execute(item);
+    ObjectQuaffEntity(player_ptr).execute(i_idx);
 }
index 335a526..470781b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_quaff_potion(PlayerType *player_ptr);
index 3520787..aa90dbb 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @todo いずれcmd-item.c/h に統合したい
  * @brief プレイヤーの読むコマンド実装
  * @date 2018/09/07
@@ -37,14 +37,13 @@ void do_cmd_read_scroll(PlayerType *player_ptr)
         return;
     }
 
-    concptr q = _("どの巻物を読みますか? ", "Read which scroll? ");
-    concptr s = _("読める巻物がない。", "You have no scrolls to read.");
-    ItemEntity *o_ptr;
-    OBJECT_IDX item;
-    o_ptr = choose_object(player_ptr, &item, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::is_readable));
+    constexpr auto q = _("どの巻物を読みますか? ", "Read which scroll? ");
+    constexpr auto s = _("読める巻物がない。", "You have no scrolls to read.");
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::is_readable));
     if (!o_ptr) {
         return;
     }
 
-    ObjectReadEntity(player_ptr, item).execute(o_ptr->is_aware());
+    ObjectReadEntity(player_ptr, i_idx).execute(o_ptr->is_aware());
 }
index afb5da3..01940f3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_read_scroll(PlayerType *player_ptr);
index 7ef97a1..a8ac6c6 100644 (file)
@@ -1,6 +1,4 @@
-#include "cmd-item/cmd-refill.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "cmd-item/cmd-refill.h"
 #include "floor/floor-object.h"
 #include "inventory/inventory-object.h"
 #include "inventory/inventory-slot-types.h"
@@ -9,7 +7,6 @@
 #include "object-hook/hook-expendable.h"
 #include "object/item-tester-hooker.h"
 #include "object/item-use-flags.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-info/samurai-data-type.h"
 #include "player-status/player-energy.h"
@@ -19,6 +16,7 @@
 #include "sv-definition/sv-lite-types.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
  */
 static void do_cmd_refill_lamp(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
-    ItemEntity *j_ptr;
-    concptr q = _("どの油つぼから注ぎますか? ", "Refill with which flask? ");
-    concptr s = _("油つぼがない。", "You have no flasks of oil.");
-    o_ptr = choose_object(player_ptr, &item, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::can_refill_lantern));
+    constexpr auto q = _("どの油つぼから注ぎますか? ", "Refill with which flask? ");
+    constexpr auto s = _("油つぼがない。", "You have no flasks of oil.");
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::can_refill_lantern));
     if (!o_ptr) {
         return;
     }
 
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
 
     PlayerEnergy(player_ptr).set_player_turn_energy(50);
-    j_ptr = &player_ptr->inventory_list[INVEN_LITE];
-    auto flags2 = object_flags(j_ptr);
+    auto *j_ptr = &player_ptr->inventory_list[INVEN_LITE];
+    const auto flags2 = j_ptr->get_flags();
     j_ptr->fuel += o_ptr->fuel;
     msg_print(_("ランプに油を注いだ。", "You fuel your lamp."));
     if (flags.has(TR_DARK_SOURCE) && (j_ptr->fuel > 0)) {
@@ -56,8 +52,8 @@ static void do_cmd_refill_lamp(PlayerType *player_ptr)
         msg_print(_("ランプの油は一杯だ。", "Your lamp is full."));
     }
 
-    vary_item(player_ptr, item, -1);
-    player_ptr->update |= PU_TORCH;
+    vary_item(player_ptr, i_idx, -1);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::TORCH);
 }
 
 /*!
@@ -66,21 +62,19 @@ static void do_cmd_refill_lamp(PlayerType *player_ptr)
  */
 static void do_cmd_refill_torch(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
-    ItemEntity *j_ptr;
-    concptr q = _("どの松明で明かりを強めますか? ", "Refuel with which torch? ");
-    concptr s = _("他に松明がない。", "You have no extra torches.");
-    o_ptr = choose_object(player_ptr, &item, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::can_refill_torch));
+    constexpr auto q = _("どの松明で明かりを強めますか? ", "Refuel with which torch? ");
+    constexpr auto s = _("他に松明がない。", "You have no extra torches.");
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::can_refill_torch));
     if (!o_ptr) {
         return;
     }
 
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
 
     PlayerEnergy(player_ptr).set_player_turn_energy(50);
-    j_ptr = &player_ptr->inventory_list[INVEN_LITE];
-    auto flags2 = object_flags(j_ptr);
+    auto *j_ptr = &player_ptr->inventory_list[INVEN_LITE];
+    const auto flags2 = j_ptr->get_flags();
     j_ptr->fuel += o_ptr->fuel + 5;
     msg_print(_("松明を結合した。", "You combine the torches."));
     if (flags.has(TR_DARK_SOURCE) && (j_ptr->fuel > 0)) {
@@ -96,8 +90,8 @@ static void do_cmd_refill_torch(PlayerType *player_ptr)
         msg_print(_("松明はいっそう明るく輝いた。", "Your torch glows more brightly."));
     }
 
-    vary_item(player_ptr, item, -1);
-    player_ptr->update |= PU_TORCH;
+    vary_item(player_ptr, i_idx, -1);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::TORCH);
 }
 
 /*!
index 90d28fe..9b20802 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_refill(PlayerType *player_ptr);
index 074f70d..585ff31 100644 (file)
@@ -1,10 +1,9 @@
-/*
+/*
  * @brief アイテム投擲コマンドの実装
  * @date 2021/08/20
  * @author Hourier
  */
 #include "cmd-item/cmd-throw.h"
-#include "core/player-redraw-types.h"
 #include "game-option/special-options.h"
 #include "inventory/inventory-slot-types.h"
 #include "object-use/throw-execution.h"
@@ -17,6 +16,7 @@
 #include "status/action-setter.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 
 ThrowCommand::ThrowCommand(PlayerType *player_ptr)
     : player_ptr(player_ptr)
@@ -61,9 +61,9 @@ bool ThrowCommand::do_cmd_throw(int mult, bool boomerang, OBJECT_IDX shuriken)
     }
 
     ote.reflect_inventory_by_throw();
-    if (ote.item >= INVEN_MAIN_HAND) {
+    if (ote.i_idx >= INVEN_MAIN_HAND) {
         ote.equiped_item = true;
-        this->player_ptr->redraw |= PR_EQUIPPY;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::EQUIPPY);
     }
 
     ote.set_class_specific_throw_params();
index af820b5..2ac87d2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index c854f38..6064951 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-item/cmd-usestaff.h"
+#include "cmd-item/cmd-usestaff.h"
 #include "action/action-limited.h"
 #include "floor/floor-object.h"
 #include "monster-floor/monster-summon.h"
@@ -50,7 +50,7 @@
  * @param known 判明済ならばTRUE
  * @return 発動により効果内容が確定したならばTRUEを返す
  */
-int staff_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, bool *use_charge, bool powerful, bool magic, bool known)
+int staff_effect(PlayerType *player_ptr, int sval, bool *use_charge, bool powerful, bool magic, bool known)
 {
     int k;
     bool ident = false;
@@ -307,9 +307,6 @@ int staff_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, bool *use_ch
  */
 void do_cmd_use_staff(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    concptr q, s;
-
     if (player_ptr->wild_mode) {
         return;
     }
@@ -319,12 +316,12 @@ void do_cmd_use_staff(PlayerType *player_ptr)
     }
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
-
-    q = _("どの杖を使いますか? ", "Use which staff? ");
-    s = _("使える杖がない。", "You have no staff to use.");
-    if (!choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), TvalItemTester(ItemKindType::STAFF))) {
+    constexpr auto q = _("どの杖を使いますか? ", "Use which staff? ");
+    constexpr auto s = _("使える杖がない。", "You have no staff to use.");
+    short i_idx;
+    if (!choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), TvalItemTester(ItemKindType::STAFF))) {
         return;
     }
 
-    ObjectUseEntity(player_ptr, item).execute();
+    ObjectUseEntity(player_ptr, i_idx).execute();
 }
index 8fc9b1d..9386cc4 100644 (file)
@@ -1,7 +1,5 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 class PlayerType;
-int staff_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, bool *use_charge, bool powerful, bool magic, bool known);
+int staff_effect(PlayerType *player_ptr, int sval, bool *use_charge, bool powerful, bool magic, bool known);
 void do_cmd_use_staff(PlayerType *player_ptr);
index f517827..8a2631d 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-item/cmd-zaprod.h"
+#include "cmd-item/cmd-zaprod.h"
 #include "action/action-limited.h"
 #include "effect/attribute-types.h"
 #include "floor/floor-object.h"
@@ -42,7 +42,7 @@
  * @param powerful 強力発動上の処理ならばTRUE
  * @return 発動により効果内容が確定したならばTRUEを返す
  */
-int rod_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, DIRECTION dir, bool *use_charge, bool powerful)
+int rod_effect(PlayerType *player_ptr, int sval, int dir, bool *use_charge, bool powerful)
 {
     int ident = false;
     PLAYER_LEVEL lev = powerful ? player_ptr->lev * 2 : player_ptr->lev;
@@ -297,12 +297,12 @@ void do_cmd_zap_rod(PlayerType *player_ptr)
 
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
 
-    auto q = _("どのロッドを振りますか? ", "Zap which rod? ");
-    auto s = _("使えるロッドがない。", "You have no rod to zap.");
-    OBJECT_IDX item;
-    if (!choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), TvalItemTester(ItemKindType::ROD))) {
+    constexpr auto q = _("どのロッドを振りますか? ", "Zap which rod? ");
+    constexpr auto s = _("使えるロッドがない。", "You have no rod to zap.");
+    short i_idx;
+    if (!choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), TvalItemTester(ItemKindType::ROD))) {
         return;
     }
 
-    ObjectZapRodEntity(player_ptr).execute(item);
+    ObjectZapRodEntity(player_ptr).execute(i_idx);
 }
index 847d4ba..5ac503c 100644 (file)
@@ -1,7 +1,5 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 class PlayerType;
-int rod_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, DIRECTION dir, bool *use_charge, bool powerful);
+int rod_effect(PlayerType *player_ptr, int sval, int dir, bool *use_charge, bool powerful);
 void do_cmd_zap_rod(PlayerType *player_ptr);
index a8f4adf..91a07a7 100644 (file)
@@ -1,7 +1,6 @@
-#include "cmd-item/cmd-zapwand.h"
+#include "cmd-item/cmd-zapwand.h"
 #include "action/action-limited.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
 #include "floor/floor-object.h"
@@ -51,7 +50,7 @@
  * @param magic 魔道具術上の処理ならばTRUE
  * @return 発動により効果内容が確定したならばTRUEを返す
  */
-bool wand_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, DIRECTION dir, bool powerful, bool magic)
+bool wand_effect(PlayerType *player_ptr, int sval, int dir, bool powerful, bool magic)
 {
     bool ident = false;
     PLAYER_LEVEL lev = powerful ? player_ptr->lev * 2 : player_ptr->lev;
@@ -60,7 +59,7 @@ bool wand_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, DIRECTION di
     /* XXX Hack -- Wand of wonder can do anything before it */
     if (sval == SV_WAND_WONDER) {
         int vir = virtue_number(player_ptr, Virtue::CHANCE);
-        sval = (OBJECT_SUBTYPE_VALUE)randint0(SV_WAND_WONDER);
+        sval = randint0(SV_WAND_WONDER);
 
         if (vir) {
             if (player_ptr->virtues[vir - 1] > 0) {
@@ -273,37 +272,21 @@ bool wand_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, DIRECTION di
     }
 
     case SV_WAND_DRAGON_BREATH: {
-        int dam;
-        AttributeType typ;
-
-        switch (randint1(5)) {
-        case 1:
-            dam = 240;
-            typ = AttributeType::ACID;
-            break;
-        case 2:
-            dam = 210;
-            typ = AttributeType::ELEC;
-            break;
-        case 3:
-            dam = 240;
-            typ = AttributeType::FIRE;
-            break;
-        case 4:
-            dam = 210;
-            typ = AttributeType::COLD;
-            break;
-        default:
-            dam = 180;
-            typ = AttributeType::POIS;
-            break;
-        }
+        constexpr std::array<std::pair<int, AttributeType>, 5> candidates = { {
+            { 240, AttributeType::ACID },
+            { 210, AttributeType::ELEC },
+            { 240, AttributeType::FIRE },
+            { 210, AttributeType::COLD },
+            { 180, AttributeType::POIS },
+        } };
+
+        auto [dam, type] = rand_choice(candidates);
 
         if (powerful) {
             dam = (dam * 3) / 2;
         }
 
-        fire_breath(player_ptr, typ, dir, dam, 3);
+        fire_breath(player_ptr, type, dir, dam, 3);
 
         ident = true;
         break;
@@ -342,9 +325,6 @@ bool wand_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, DIRECTION di
  */
 void do_cmd_aim_wand(PlayerType *player_ptr)
 {
-    OBJECT_IDX item;
-    concptr q, s;
-
     if (player_ptr->wild_mode) {
         return;
     }
@@ -353,11 +333,12 @@ void do_cmd_aim_wand(PlayerType *player_ptr)
     }
     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
 
-    q = _("どの魔法棒で狙いますか? ", "Aim which wand? ");
-    s = _("使える魔法棒がない。", "You have no wand to aim.");
-    if (!choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), TvalItemTester(ItemKindType::WAND))) {
+    constexpr auto q = _("どの魔法棒で狙いますか? ", "Aim which wand? ");
+    constexpr auto s = _("使える魔法棒がない。", "You have no wand to aim.");
+    short i_idx;
+    if (!choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), TvalItemTester(ItemKindType::WAND))) {
         return;
     }
 
-    ObjectZapWandEntity(player_ptr).execute(item);
+    ObjectZapWandEntity(player_ptr).execute(i_idx);
 }
index d52173e..7b18ec4 100644 (file)
@@ -1,7 +1,5 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 class PlayerType;
-bool wand_effect(PlayerType *player_ptr, OBJECT_SUBTYPE_VALUE sval, DIRECTION dir, bool powerful, bool magic);
+bool wand_effect(PlayerType *player_ptr, int sval, int dir, bool powerful, bool magic);
 void do_cmd_aim_wand(PlayerType *player_ptr);
index 585001f..f0b35ef 100644 (file)
@@ -1,7 +1,5 @@
-#include "cmd-visual/cmd-draw.h"
+#include "cmd-visual/cmd-draw.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "io/files-util.h"
@@ -12,6 +10,7 @@
 #include "player/process-name.h"
 #include "racial/racial-android.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
@@ -21,6 +20,7 @@
 #include "view/display-messages.h"
 #include "view/display-player.h"
 #include "world/world.h"
+#include <optional>
 
 /*!
  * @brief 画面を再描画するコマンドのメインルーチン
@@ -41,19 +41,44 @@ void do_cmd_redraw(PlayerType *player_ptr)
 {
     term_xtra(TERM_XTRA_REACT, 0);
 
-    player_ptr->update |= (PU_COMBINATION | PU_REORDER);
-    player_ptr->update |= (PU_TORCH);
-    player_ptr->update |= (PU_BONUS | PU_HP | PU_MP | PU_SPELLS);
-    player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
-    player_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTER_LITE);
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-
-    player_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
-
-    player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT | PW_SPELL | PW_PLAYER);
-    player_ptr->window_flags |= (PW_MESSAGE | PW_OVERHEAD | PW_DUNGEON | PW_MONSTER_LORE | PW_ITEM_KNOWLEDGTE);
-
-    update_playtime();
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+        StatusRecalculatingFlag::TORCH,
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+        StatusRecalculatingFlag::UN_VIEW,
+        StatusRecalculatingFlag::UN_LITE,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::WIPE,
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::EQUIPPY,
+        MainWindowRedrawingFlag::MAP,
+    };
+    rfu.set_flags(flags_mwrf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::SPELL,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::MESSAGE,
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+        SubWindowRedrawingFlag::MONSTER_LORE,
+        SubWindowRedrawingFlag::ITEM_KNOWLEDGE,
+    };
+    rfu.set_flags(flags_swrf);
+    w_ptr->update_playtime();
     handle_stuff(player_ptr);
     if (PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
         calc_android_exp(player_ptr);
@@ -72,54 +97,77 @@ void do_cmd_redraw(PlayerType *player_ptr)
     }
 }
 
+static std::optional<int> input_status_command(PlayerType *player_ptr, int page)
+{
+    auto c = inkey();
+    switch (c) {
+    case 'c':
+        get_name(player_ptr);
+        process_player_name(player_ptr);
+        return page;
+    case 'f': {
+        const auto initial_filename = format("%s.txt", player_ptr->base_name);
+        const auto input_filename = input_string(_("ファイル名: ", "File name: "), 80, initial_filename);
+        if (!input_filename) {
+            return page;
+        }
+
+        const auto &filename = str_ltrim(*input_filename);
+        if (!filename.empty()) {
+            w_ptr->update_playtime();
+            file_character(player_ptr, filename);
+        }
+
+        return page;
+    }
+    case 'h':
+        return page + 1;
+    case ESCAPE:
+        return std::nullopt;
+    default:
+        bell();
+        return page;
+    }
+}
+
 /*!
  * @brief プレイヤーのステータス表示
  */
 void do_cmd_player_status(PlayerType *player_ptr)
 {
-    int mode = 0;
-    char tmp[160];
+    auto page = 0;
     screen_save();
+    constexpr auto prompt = _("['c'で名前変更, 'f'でファイルへ書出, 'h'でモード変更, ESCで終了]", "['c' to change name, 'f' to file, 'h' to change mode, or ESC]");
     while (true) {
         TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
 
-        update_playtime();
-        (void)display_player(player_ptr, mode);
-
-        if (mode == 5) {
-            mode = 0;
-            (void)display_player(player_ptr, mode);
+        w_ptr->update_playtime();
+        (void)display_player(player_ptr, page);
+        if (page == 5) {
+            page = 0;
+            (void)display_player(player_ptr, page);
         }
 
-        term_putstr(2, 23, -1, TERM_WHITE,
-            _("['c'で名前変更, 'f'でファイルへ書出, 'h'でモード変更, ESCで終了]", "['c' to change name, 'f' to file, 'h' to change mode, or ESC]"));
-        char c = inkey();
-        if (c == ESCAPE) {
+        term_putstr(2, 23, -1, TERM_WHITE, prompt);
+        auto next_page = input_status_command(player_ptr, page);
+        if (!next_page) {
             break;
         }
 
-        if (c == 'c') {
-            get_name(player_ptr);
-            process_player_name(player_ptr);
-        } else if (c == 'f') {
-            strnfmt(tmp, sizeof(tmp), "%s.txt", player_ptr->base_name);
-            if (get_string(_("ファイル名: ", "File name: "), tmp, 80)) {
-                if (tmp[0] && (tmp[0] != ' ')) {
-                    update_playtime();
-                    file_character(player_ptr, tmp);
-                }
-            }
-        } else if (c == 'h') {
-            mode++;
-        } else {
-            bell();
-        }
-
+        page = *next_page;
         msg_erase();
     }
 
     screen_load();
-    player_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::WIPE,
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::EQUIPPY,
+        MainWindowRedrawingFlag::MAP,
+    };
+    rfu.set_flags(flags_mwrf);
     handle_stuff(player_ptr);
 }
 
@@ -129,7 +177,7 @@ void do_cmd_player_status(PlayerType *player_ptr)
  */
 void do_cmd_message_one(void)
 {
-    prt(format("> %s", message_str(0)), 0, 0);
+    prt(format("> %s", message_str(0)->data()), 0, 0);
 }
 
 /*!
@@ -154,39 +202,42 @@ void do_cmd_message_one(void)
  */
 void do_cmd_messages(int num_now)
 {
-    char shower_str[81];
-    char finder_str[81];
-    char back_str[81];
-    concptr shower = nullptr;
-    int wid, hgt;
-    term_get_size(&wid, &hgt);
-    int num_lines = hgt - 4;
-    strcpy(finder_str, "");
-    strcpy(shower_str, "");
-    int n = message_num();
-    int i = 0;
+    std::string shower_str("");
+    std::string finder_str("");
+    std::string shower("");
+    const auto &[wid, hgt] = term_get_size();
+    auto num_lines = hgt - 4;
+    auto n = message_num();
+    auto i = 0;
     screen_save();
     term_clear();
     while (true) {
         int j;
         int skey;
         for (j = 0; (j < num_lines) && (i + j < n); j++) {
-            concptr msg = message_str(i + j);
+            const auto msg_str = message_str(i + j);
+            const auto *msg = msg_str->data();
             c_prt((i + j < num_now ? TERM_WHITE : TERM_SLATE), msg, num_lines + 1 - j, 0);
-            if (!shower || !shower[0]) {
+            if (shower.empty()) {
                 continue;
             }
 
-            concptr str = msg;
-            while ((str = angband_strstr(str, shower)) != nullptr) {
-                int len = strlen(shower);
+            // @details ダメ文字対策でstringを使わない.
+            const auto *str = msg;
+            while (true) {
+                str = angband_strstr(str, shower);
+                if (str == nullptr) {
+                    break;
+                }
+
+                const auto len = shower.length();
                 term_putstr(str - msg, num_lines + 1 - j, len, TERM_YELLOW, shower);
                 str += len;
             }
         }
 
         for (; j < num_lines; j++) {
-            term_erase(0, num_lines + 1 - j, 255);
+            term_erase(0, num_lines + 1 - j);
         }
 
         prt(format(_("以前のメッセージ %d-%d 全部で(%d)", "Message Recall (%d-%d of %d)"), i, i + j - 1, n), 0, 0);
@@ -198,40 +249,42 @@ void do_cmd_messages(int num_now)
 
         j = i;
         switch (skey) {
-        case '=':
+        case '=': {
             prt(_("強調: ", "Show: "), hgt - 1, 0);
-            strcpy(back_str, shower_str);
-            if (askfor(shower_str, 80)) {
-                shower = shower_str[0] ? shower_str : nullptr;
-            } else {
-                strcpy(shower_str, back_str);
+            const auto ask_result = askfor(80, shower_str);
+            if (ask_result) {
+                shower = *ask_result;
+                shower_str = *ask_result;
             }
 
             continue;
+        }
         case '/':
         case KTRL('s'): {
             prt(_("検索: ", "Find: "), hgt - 1, 0);
-            strcpy(back_str, finder_str);
-            if (!askfor(finder_str, 80)) {
-                strcpy(finder_str, back_str);
+            const auto ask_result = askfor(80, finder_str);
+            if (!ask_result) {
                 continue;
-            } else if (!finder_str[0]) {
-                shower = nullptr;
+            }
+
+            finder_str = *ask_result;
+            if (finder_str.empty()) {
+                shower = "";
                 continue;
             }
 
             shower = finder_str;
             for (int z = i + 1; z < n; z++) {
-                concptr msg = message_str(z);
-                if (angband_strstr(msg, finder_str)) {
+                // @details ダメ文字対策でstringを使わない.
+                const auto msg = message_str(z);
+                if (str_find(*msg, finder_str)) {
                     i = z;
                     break;
                 }
             }
-        }
-
-        break;
 
+            break;
+        }
         case SKEY_TOP:
             i = n - num_lines;
             break;
index 1363d8b..730ab1e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_redraw(PlayerType *player_ptr);
index a40f581..ce15e34 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-visual/cmd-map.h"
+#include "cmd-visual/cmd-map.h"
 #include "autopick/autopick-methods-table.h"
 #include "autopick/autopick-util.h"
 #include "io/input-key-acceptor.h"
@@ -6,6 +6,7 @@
 #include "term/screen-processor.h"
 #include "view/display-map.h"
 #include "window/main-window-util.h"
+#include <string_view>
 
 /*
  * Display a "small-scale" map of the dungeon for the player
@@ -23,7 +24,10 @@ void do_cmd_view_map(PlayerType *player_ptr)
     int cy, cx;
     display_map(player_ptr, &cy, &cx);
     if (autopick_list.empty() || player_ptr->wild_mode) {
-        put_str(_("何かキーを押すとゲームに戻ります", "Hit any key to continue"), 23, 30);
+        const auto &[wid, hgt] = term_get_size();
+        constexpr auto msg = _("何かキーを押すとゲームに戻ります", "Hit any key to continue");
+        const auto center_x = (wid - std::string_view(msg).length()) / 2;
+        put_str(msg, hgt - 1, center_x);
         move_cursor(cy, cx);
         inkey(true);
         screen_load();
@@ -32,8 +36,7 @@ void do_cmd_view_map(PlayerType *player_ptr)
 
     display_autopick = ITEM_DISPLAY;
     while (true) {
-        int wid, hgt;
-        term_get_size(&wid, &hgt);
+        const auto &[wid, hgt] = term_get_size();
         int row_message = hgt - 1;
         put_str(_("何かキーを押してください('M':拾う 'N':放置 'D':M+N 'K':壊すアイテムを表示)",
                     " Hit M, N(for ~), K(for !), or D(same as M+N) to display auto-picker items."),
index 999f78b..a77d5ba 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_view_map(PlayerType *player_ptr);
index 8ab9f7f..0ab1046 100644 (file)
@@ -1,4 +1,4 @@
-#include "cmd-visual/cmd-visuals.h"
+#include "cmd-visual/cmd-visuals.h"
 #include "cmd-visual/cmd-draw.h"
 #include "core/asking-player.h"
 #include "core/visuals-reseter.h"
 #include "util/angband-files.h"
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
+#include <optional>
 
 /*!
- * @brief キャラクタのビジュアルIDを変更する際の対象指定関数
+ * @brief キャラクタのビジュアルIDを変更する際の対象指定
  * @param i 指定対象となるキャラクタコード
- * @param num 指定されたビジュアルIDを返す参照ポインタ
+ * @param initial_visual_id 指定されたビジュアルID
  * @param max ビジュアルIDの最大数
- * @return æ\8c\87å®\9aã\81\8cå®\9fé\9a\9bã\81«è¡\8cã\82\8fã\82\8cã\81\9få ´å\90\88TRUEã\80\81ã\82­ã\83£ã\83³ã\82»ã\83«ã\81\95ã\82\8cã\81\9få ´å\90\88FALSE
+ * @return æ\96°ã\81\97ã\81\84ã\83\93ã\82¸ã\83¥ã\82¢ã\83«ID
  */
-static bool cmd_visuals_aux(int i, IDX *num, IDX max)
+template <typename T>
+static std::optional<T> input_new_visual_id(int i, T initial_visual_id, int max)
 {
     if (iscntrl(i)) {
-        char str[10] = "";
-        strnfmt(str, sizeof(str), "%d", *num);
-        if (!get_string(format("Input new number(0-%d): ", max - 1), str, 4)) {
-            return false;
+        const auto new_visual_id = input_integer("Input new number", 0, max - 1, initial_visual_id);
+        if (!new_visual_id) {
+            return std::nullopt;
         }
 
-        IDX tmp = (IDX)strtol(str, nullptr, 0);
-        if (tmp >= 0 && tmp < max) {
-            *num = tmp;
-        }
-    } else if (isupper(i)) {
-        *num = (*num + max - 1) % max;
-    } else {
-        *num = (*num + 1) % max;
+        return static_cast<T>(*new_visual_id);
+    }
+
+    if (isupper(i)) {
+        return static_cast<T>((initial_visual_id + max - 1) % max);
     }
 
-    return true;
+    return static_cast<T>((initial_visual_id + 1) % max);
 }
 
 /*!
@@ -84,8 +82,6 @@ static void print_visuals_menu(concptr choice_msg)
 void do_cmd_visuals(PlayerType *player_ptr)
 {
     FILE *auto_dump_stream;
-    char tmp[160];
-    char buf[1024];
     bool need_redraw = false;
     concptr empty_symbol = "<< ? >>";
     if (use_bigtile) {
@@ -93,49 +89,46 @@ void do_cmd_visuals(PlayerType *player_ptr)
     }
 
     screen_save();
+    const auto initial_filename = format("%s.prf", player_ptr->base_name);
     while (true) {
         term_clear();
         print_visuals_menu(nullptr);
-        int i = inkey();
-        if (i == ESCAPE) {
+        const auto key = inkey();
+        if (key == ESCAPE) {
             break;
         }
 
-        switch (i) {
+        switch (key) {
         case '0': {
             prt(_("コマンド: ユーザー設定ファイルのロード", "Command: Load a user pref file"), 15, 0);
             prt(_("ファイル: ", "File: "), 17, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 70)) {
+            const auto ask_result = askfor(70, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            (void)process_pref_file(player_ptr, tmp, true);
+            (void)process_pref_file(player_ptr, *ask_result, true);
             need_redraw = true;
             break;
         }
         case '1': {
             prt(_("コマンド: モンスターの[色/文字]をファイルに書き出します", "Command: Dump monster attr/chars"), 15, 0);
             prt(_("ファイル: ", "File: "), 17, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 70)) {
+            const auto ask_result = askfor(70, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
+            const auto &path = path_build(ANGBAND_DIR_USER, *ask_result);
             constexpr auto mark = "Monster attr/chars";
-            if (!open_auto_dump(&auto_dump_stream, buf, mark)) {
+            if (!open_auto_dump(&auto_dump_stream, path, mark)) {
                 continue;
             }
 
             auto_dump_printf(auto_dump_stream, _("\n# モンスターの[色/文字]の設定\n\n", "\n# Monster attr/char definitions\n\n"));
-            for (const auto &[r_idx, r_ref] : monraces_info) {
-                if (r_ref.name.empty()) {
-                    continue;
-                }
-
-                auto_dump_printf(auto_dump_stream, "# %s\n", r_ref.name.data());
-                auto_dump_printf(auto_dump_stream, "R:%d:0x%02X/0x%02X\n\n", enum2i(r_ref.idx), (byte)(r_ref.x_attr), (byte)(r_ref.x_char));
+            for (const auto &[monrace_id, monrace] : monraces_info) {
+                auto_dump_printf(auto_dump_stream, "# %s\n", monrace.name.data());
+                auto_dump_printf(auto_dump_stream, "R:%d:0x%02X/0x%02X\n\n", enum2i(monrace_id), monrace.x_attr, monrace.x_char);
             }
 
             close_auto_dump(&auto_dump_stream, mark);
@@ -145,14 +138,14 @@ void do_cmd_visuals(PlayerType *player_ptr)
         case '2': {
             prt(_("コマンド: アイテムの[色/文字]をファイルに書き出します", "Command: Dump object attr/chars"), 15, 0);
             prt(_("ファイル: ", "File: "), 17, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 70)) {
+            const auto ask_result = askfor(70, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
+            const auto &path = path_build(ANGBAND_DIR_USER, *ask_result);
             constexpr auto mark = "Object attr/chars";
-            if (!open_auto_dump(&auto_dump_stream, buf, mark)) {
+            if (!open_auto_dump(&auto_dump_stream, path, mark)) {
                 continue;
             }
 
@@ -182,30 +175,30 @@ void do_cmd_visuals(PlayerType *player_ptr)
         case '3': {
             prt(_("コマンド: 地形の[色/文字]をファイルに書き出します", "Command: Dump feature attr/chars"), 15, 0);
             prt(_("ファイル: ", "File: "), 17, 0);
-            strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
-            if (!askfor(tmp, 70)) {
+            const auto ask_result = askfor(70, initial_filename);
+            if (!ask_result) {
                 continue;
             }
 
-            path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
+            const auto &path = path_build(ANGBAND_DIR_USER, *ask_result);
             constexpr auto mark = "Feature attr/chars";
-            if (!open_auto_dump(&auto_dump_stream, buf, mark)) {
+            if (!open_auto_dump(&auto_dump_stream, path, mark)) {
                 continue;
             }
 
             auto_dump_printf(auto_dump_stream, _("\n# 地形の[色/文字]の設定\n\n", "\n# Feature attr/char definitions\n\n"));
-            for (const auto &f_ref : terrains_info) {
-                if (f_ref.name.empty()) {
+            for (const auto &terrain : TerrainList::get_instance()) {
+                if (terrain.name.empty()) {
                     continue;
                 }
-                if (f_ref.mimic != f_ref.idx) {
+                if (terrain.mimic != terrain.idx) {
                     continue;
                 }
 
-                auto_dump_printf(auto_dump_stream, "# %s\n", (f_ref.name.data()));
-                auto_dump_printf(auto_dump_stream, "F:%d:0x%02X/0x%02X:0x%02X/0x%02X:0x%02X/0x%02X\n\n", f_ref.idx, (byte)(f_ref.x_attr[F_LIT_STANDARD]),
-                    (byte)(f_ref.x_char[F_LIT_STANDARD]), (byte)(f_ref.x_attr[F_LIT_LITE]), (byte)(f_ref.x_char[F_LIT_LITE]),
-                    (byte)(f_ref.x_attr[F_LIT_DARK]), (byte)(f_ref.x_char[F_LIT_DARK]));
+                auto_dump_printf(auto_dump_stream, "# %s\n", (terrain.name.data()));
+                auto_dump_printf(auto_dump_stream, "F:%d:0x%02X/0x%02X:0x%02X/0x%02X:0x%02X/0x%02X\n\n", terrain.idx, (byte)(terrain.x_attr[F_LIT_STANDARD]),
+                    (byte)(terrain.x_char[F_LIT_STANDARD]), (byte)(terrain.x_attr[F_LIT_LITE]), (byte)(terrain.x_char[F_LIT_LITE]),
+                    (byte)(terrain.x_attr[F_LIT_DARK]), (byte)(terrain.x_char[F_LIT_DARK]));
             }
 
             close_auto_dump(&auto_dump_stream, mark);
@@ -214,20 +207,18 @@ void do_cmd_visuals(PlayerType *player_ptr)
         }
         case '4': {
             IDX num = 0;
-            static concptr choice_msg = _("モンスターの[色/文字]を変更します", "Change monster attr/chars");
-            static MonsterRaceId r = monraces_info.begin()->second.idx;
+            static auto choice_msg = _("モンスターの[色/文字]を変更します", "Change monster attr/chars");
+            static auto monrace_id = monraces_info.begin()->second.idx;
             prt(format(_("コマンド: %s", "Command: %s"), choice_msg), 15, 0);
             while (true) {
-                auto *r_ptr = &monraces_info[r];
+                auto *r_ptr = &monraces_info[monrace_id];
                 int c;
-                IDX t;
-
                 TERM_COLOR da = r_ptr->d_attr;
                 byte dc = r_ptr->d_char;
                 TERM_COLOR ca = r_ptr->x_attr;
                 byte cc = r_ptr->x_char;
 
-                term_putstr(5, 17, -1, TERM_WHITE, format(_("モンスター = %d, 名前 = %-40.40s", "Monster = %d, Name = %-40.40s"), enum2i(r), r_ptr->name.data()));
+                term_putstr(5, 17, -1, TERM_WHITE, format(_("モンスター = %d, 名前 = %-40.40s", "Monster = %d, Name = %-40.40s"), enum2i(monrace_id), r_ptr->name.data()));
                 term_putstr(10, 19, -1, TERM_WHITE, format(_("初期値  色 / 文字 = %3u / %3u", "Default attr/char = %3u / %3u"), da, dc));
                 term_putstr(40, 19, -1, TERM_WHITE, empty_symbol);
                 term_queue_bigchar(43, 19, da, dc, 0, 0);
@@ -235,46 +226,53 @@ void do_cmd_visuals(PlayerType *player_ptr)
                 term_putstr(40, 20, -1, TERM_WHITE, empty_symbol);
                 term_queue_bigchar(43, 20, ca, cc, 0, 0);
                 term_putstr(0, 22, -1, TERM_WHITE, _("コマンド (n/N/^N/a/A/^A/c/C/^C/v/V/^V): ", "Command (n/N/^N/a/A/^A/c/C/^C/v/V/^V): "));
-                i = inkey();
-                if (i == ESCAPE) {
+                const auto ch = inkey();
+                if (ch == ESCAPE) {
                     break;
                 }
 
-                if (iscntrl(i)) {
-                    c = 'a' + i - KTRL('A');
-                } else if (isupper(i)) {
-                    c = 'a' + i - 'A';
+                if (iscntrl(ch)) {
+                    c = 'a' + ch - KTRL('A');
+                } else if (isupper(ch)) {
+                    c = 'a' + ch - 'A';
                 } else {
-                    c = i;
+                    c = ch;
                 }
 
                 switch (c) {
                 case 'n': {
-                    auto prev_r = r;
-                    do {
-                        if (!cmd_visuals_aux(i, &num, static_cast<IDX>(monraces_info.size()))) {
-                            r = prev_r;
-                            break;
-                        }
-                        r = i2enum<MonsterRaceId>(num);
-                    } while (monraces_info[r].name.empty());
+                    const auto new_monrace_id_opt = input_new_visual_id(ch, num, static_cast<short>(monraces_info.size()));
+                    if (!new_monrace_id_opt) {
+                        break;
+                    }
+
+                    const auto new_monrace_id = *new_monrace_id_opt;
+                    monrace_id = i2enum<MonsterRaceId>(new_monrace_id);
+                    num = new_monrace_id;
+                    break;
                 }
+                case 'a': {
+                    const auto visual_id = input_new_visual_id(ch, r_ptr->x_attr, 256);
+                    if (!visual_id) {
+                        break;
+                    }
 
-                break;
-                case 'a':
-                    t = (int)r_ptr->x_attr;
-                    (void)cmd_visuals_aux(i, &t, 256);
-                    r_ptr->x_attr = (byte)t;
+                    r_ptr->x_attr = *visual_id;
                     need_redraw = true;
                     break;
-                case 'c':
-                    t = (int)r_ptr->x_char;
-                    (void)cmd_visuals_aux(i, &t, 256);
-                    r_ptr->x_char = (byte)t;
+                }
+                case 'c': {
+                    const auto visual_id = input_new_visual_id(ch, r_ptr->x_char, 256);
+                    if (!visual_id) {
+                        break;
+                    }
+
+                    r_ptr->x_char = *visual_id;
                     need_redraw = true;
                     break;
+                }
                 case 'v':
-                    do_cmd_knowledge_monsters(player_ptr, &need_redraw, true, r);
+                    do_cmd_knowledge_monsters(player_ptr, &need_redraw, true, monrace_id);
                     term_clear();
                     print_visuals_menu(choice_msg);
                     break;
@@ -284,14 +282,12 @@ void do_cmd_visuals(PlayerType *player_ptr)
             break;
         }
         case '5': {
-            static concptr choice_msg = _("アイテムの[色/文字]を変更します", "Change object attr/chars");
-            static short k = 0;
+            static auto choice_msg = _("アイテムの[色/文字]を変更します", "Change object attr/chars");
+            static short bi_id = 0;
             prt(format(_("コマンド: %s", "Command: %s"), choice_msg), 15, 0);
             while (true) {
-                auto &baseitem = baseitems_info[k];
+                auto &baseitem = baseitems_info[bi_id];
                 int c;
-                IDX t;
-
                 TERM_COLOR da = baseitem.d_attr;
                 auto dc = baseitem.d_char;
                 TERM_COLOR ca = baseitem.x_attr;
@@ -299,7 +295,7 @@ void do_cmd_visuals(PlayerType *player_ptr)
 
                 term_putstr(5, 17, -1, TERM_WHITE,
                     format(
-                        _("アイテム = %d, 名前 = %-40.40s", "Object = %d, Name = %-40.40s"), k, (!baseitem.flavor ? baseitem.name : baseitem.flavor_name).data()));
+                        _("アイテム = %d, 名前 = %-40.40s", "Object = %d, Name = %-40.40s"), bi_id, (!baseitem.flavor ? baseitem.name : baseitem.flavor_name).data()));
                 term_putstr(10, 19, -1, TERM_WHITE, format(_("初期値  色 / 文字 = %3d / %3d", "Default attr/char = %3d / %3d"), da, dc));
                 term_putstr(40, 19, -1, TERM_WHITE, empty_symbol);
                 term_queue_bigchar(43, 19, da, dc, 0, 0);
@@ -308,45 +304,60 @@ void do_cmd_visuals(PlayerType *player_ptr)
                 term_queue_bigchar(43, 20, ca, cc, 0, 0);
                 term_putstr(0, 22, -1, TERM_WHITE, _("コマンド (n/N/^N/a/A/^A/c/C/^C/v/V/^V): ", "Command (n/N/^N/a/A/^A/c/C/^C/v/V/^V): "));
 
-                i = inkey();
-                if (i == ESCAPE) {
+                const auto ch = inkey();
+                if (ch == ESCAPE) {
                     break;
                 }
 
-                if (iscntrl(i)) {
-                    c = 'a' + i - KTRL('A');
-                } else if (isupper(i)) {
-                    c = 'a' + i - 'A';
+                if (iscntrl(ch)) {
+                    c = 'a' + ch - KTRL('A');
+                } else if (isupper(ch)) {
+                    c = 'a' + ch - 'A';
                 } else {
-                    c = i;
+                    c = ch;
                 }
 
                 switch (c) {
                 case 'n': {
-                    short prev_k = k;
-                    do {
-                        if (!cmd_visuals_aux(i, &k, static_cast<short>(baseitems_info.size()))) {
-                            k = prev_k;
+                    std::optional<short> new_baseitem_id(std::nullopt);
+                    const auto previous_bi_id = bi_id;
+                    while (true) {
+                        new_baseitem_id = input_new_visual_id(ch, bi_id, static_cast<short>(baseitems_info.size()));
+                        if (!new_baseitem_id) {
+                            bi_id = previous_bi_id;
                             break;
                         }
-                    } while (baseitems_info[k].name.empty());
+
+                        bi_id = *new_baseitem_id;
+                        if (!baseitems_info[bi_id].name.empty()) {
+                            break;
+                        }
+                    }
+
+                    break;
                 }
+                case 'a': {
+                    const auto visual_id = input_new_visual_id(ch, baseitem.x_attr, 256);
+                    if (!visual_id) {
+                        break;
+                    }
 
-                break;
-                case 'a':
-                    t = (int)baseitem.x_attr;
-                    (void)cmd_visuals_aux(i, &t, 256);
-                    baseitem.x_attr = (byte)t;
+                    baseitem.x_attr = *visual_id;
                     need_redraw = true;
                     break;
-                case 'c':
-                    t = (int)baseitem.x_char;
-                    (void)cmd_visuals_aux(i, &t, 256);
-                    baseitem.x_char = (byte)t;
+                }
+                case 'c': {
+                    const auto visual_id = input_new_visual_id(ch, baseitem.x_char, 256);
+                    if (!visual_id) {
+                        break;
+                    }
+
+                    baseitem.x_char = *visual_id;
                     need_redraw = true;
                     break;
+                }
                 case 'v':
-                    do_cmd_knowledge_objects(player_ptr, &need_redraw, true, k);
+                    do_cmd_knowledge_objects(player_ptr, &need_redraw, true, bi_id);
                     term_clear();
                     print_visuals_menu(choice_msg);
                     break;
@@ -356,23 +367,22 @@ void do_cmd_visuals(PlayerType *player_ptr)
             break;
         }
         case '6': {
-            static concptr choice_msg = _("地形の[色/文字]を変更します", "Change feature attr/chars");
-            static IDX f = 0;
-            static IDX lighting_level = F_LIT_STANDARD;
+            static auto choice_msg = _("地形の[色/文字]を変更します", "Change feature attr/chars");
+            static short terrain_id = 0;
+            static short lighting_level = F_LIT_STANDARD;
             prt(format(_("コマンド: %s", "Command: %s"), choice_msg), 15, 0);
+            auto &terrains = TerrainList::get_instance();
             while (true) {
-                auto *f_ptr = &terrains_info[f];
+                auto &terrain = terrains[terrain_id];
                 int c;
-                IDX t;
-
-                TERM_COLOR da = f_ptr->d_attr[lighting_level];
-                byte dc = f_ptr->d_char[lighting_level];
-                TERM_COLOR ca = f_ptr->x_attr[lighting_level];
-                byte cc = f_ptr->x_char[lighting_level];
+                TERM_COLOR da = terrain.d_attr[lighting_level];
+                byte dc = terrain.d_char[lighting_level];
+                TERM_COLOR ca = terrain.x_attr[lighting_level];
+                byte cc = terrain.x_char[lighting_level];
 
                 prt("", 17, 5);
                 term_putstr(5, 17, -1, TERM_WHITE,
-                    format(_("地形 = %d, 名前 = %s, 明度 = %s", "Terrain = %d, Name = %s, Lighting = %s"), f, (f_ptr->name.data()),
+                    format(_("地形 = %d, 名前 = %s, 明度 = %s", "Terrain = %d, Name = %s, Lighting = %s"), terrain_id, (terrain.name.data()),
                         lighting_level_str[lighting_level]));
                 term_putstr(10, 19, -1, TERM_WHITE, format(_("初期値  色 / 文字 = %3d / %3d", "Default attr/char = %3d / %3d"), da, dc));
                 term_putstr(40, 19, -1, TERM_WHITE, empty_symbol);
@@ -383,52 +393,74 @@ void do_cmd_visuals(PlayerType *player_ptr)
                 term_putstr(0, 22, -1, TERM_WHITE,
                     _("コマンド (n/N/^N/a/A/^A/c/C/^C/l/L/^L/d/D/^D/v/V/^V): ", "Command (n/N/^N/a/A/^A/c/C/^C/l/L/^L/d/D/^D/v/V/^V): "));
 
-                i = inkey();
-                if (i == ESCAPE) {
+                const auto ch = inkey();
+                if (ch == ESCAPE) {
                     break;
                 }
 
-                if (iscntrl(i)) {
-                    c = 'a' + i - KTRL('A');
-                } else if (isupper(i)) {
-                    c = 'a' + i - 'A';
+                if (iscntrl(ch)) {
+                    c = 'a' + ch - KTRL('A');
+                } else if (isupper(ch)) {
+                    c = 'a' + ch - 'A';
                 } else {
-                    c = i;
+                    c = ch;
                 }
 
                 switch (c) {
                 case 'n': {
-                    IDX prev_f = f;
-                    do {
-                        if (!cmd_visuals_aux(i, &f, static_cast<IDX>(terrains_info.size()))) {
-                            f = prev_f;
+                    std::optional<short> new_terrain_id(std::nullopt);
+                    const auto previous_terrain_id = terrain_id;
+                    while (true) {
+                        new_terrain_id = input_new_visual_id(ch, terrain_id, static_cast<short>(TerrainList::get_instance().size()));
+                        if (!new_terrain_id) {
+                            terrain_id = previous_terrain_id;
                             break;
                         }
-                    } while (terrains_info[f].name.empty() || (terrains_info[f].mimic != f));
+
+                        terrain_id = *new_terrain_id;
+                        const auto &new_terrain = terrains[terrain_id];
+                        if (!new_terrain.name.empty() && (new_terrain.mimic == terrain_id)) {
+                            break;
+                        }
+                    }
+
+                    break;
                 }
+                case 'a': {
+                    const auto visual_id = input_new_visual_id(ch, terrain.x_attr[lighting_level], 256);
+                    if (!visual_id) {
+                        break;
+                    }
 
-                break;
-                case 'a':
-                    t = (int)f_ptr->x_attr[lighting_level];
-                    (void)cmd_visuals_aux(i, &t, 256);
-                    f_ptr->x_attr[lighting_level] = (byte)t;
+                    terrain.x_attr[lighting_level] = *visual_id;
                     need_redraw = true;
                     break;
-                case 'c':
-                    t = (int)f_ptr->x_char[lighting_level];
-                    (void)cmd_visuals_aux(i, &t, 256);
-                    f_ptr->x_char[lighting_level] = (byte)t;
+                }
+                case 'c': {
+                    const auto visual_id = input_new_visual_id(ch, terrain.x_char[lighting_level], 256);
+                    if (!visual_id) {
+                        break;
+                    }
+
+                    terrain.x_char[lighting_level] = *visual_id;
                     need_redraw = true;
                     break;
-                case 'l':
-                    (void)cmd_visuals_aux(i, &lighting_level, F_LIT_MAX);
+                }
+                case 'l': {
+                    const auto visual_id = input_new_visual_id(ch, lighting_level, F_LIT_MAX);
+                    if (!visual_id) {
+                        break;
+                    }
+
+                    lighting_level = *visual_id;
                     break;
+                }
                 case 'd':
-                    apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
+                    apply_default_feat_lighting(terrain.x_attr, terrain.x_char);
                     need_redraw = true;
                     break;
                 case 'v':
-                    do_cmd_knowledge_features(&need_redraw, true, f, &lighting_level);
+                    do_cmd_knowledge_features(&need_redraw, true, terrain_id, &lighting_level);
                     term_clear();
                     print_visuals_menu(choice_msg);
                     break;
@@ -444,12 +476,12 @@ void do_cmd_visuals(PlayerType *player_ptr)
             do_cmd_knowledge_objects(player_ptr, &need_redraw, true, -1);
             break;
         case '9': {
-            IDX lighting_level = F_LIT_STANDARD;
+            short lighting_level = F_LIT_STANDARD;
             do_cmd_knowledge_features(&need_redraw, true, -1, &lighting_level);
             break;
         }
-        case 'R':
         case 'r':
+        case 'R':
             reset_visuals(player_ptr);
             msg_print(_("画面上の[色/文字]を初期値にリセットしました。", "Visual attr/char tables reset."));
             need_redraw = true;
index 81968f7..aca17ec 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_visuals(PlayerType *player_ptr);
index 7c20a8a..f64f28a 100644 (file)
@@ -45,7 +45,7 @@
                        <string>$NAME$ saved game</string>
                        <key>CFBundleTypeOSTypes</key>
                        <array>
-                               <string>SAVE</string>
+                               <string>HENG</string>
                        </array>
                        <key>CFBundleTypeRole</key>
                        <string>Editor</string>
index 4e0ed94..b2520c8 100644 (file)
@@ -551,16 +551,16 @@ static AngbandAudioManager *_sharedManager = nil;
 
 + (NSMutableDictionary *)setupSoundArraysByEvent
 {
-       char sound_dir[1024], path[1024];
+       std::filesystem::path psound, p;
        FILE *fff;
        NSMutableDictionary *arraysByEvent;
 
        /* Build the "sound" path. */
-       path_build(sound_dir, sizeof(sound_dir), ANGBAND_DIR_XTRA, "sound");
+       psound = path_build(ANGBAND_DIR_XTRA, "sound");
 
        /* Find and open the config file. */
-       path_build(path, sizeof(path), sound_dir, "sound.cfg");
-       fff = angband_fopen(path, FileOpenMode::READ);
+       p = path_build(psound, "sound.cfg");
+       fff = angband_fopen(p, FileOpenMode::READ);
 
        if (!fff) {
                NSLog(@"The sound configuration file could not be opened");
@@ -674,12 +674,11 @@ static AngbandAudioManager *_sharedManager = nil;
                                         */
                                        struct stat stb;
 
-                                       path_build(path, sizeof(path),
-                                               sound_dir, sample_name);
-                                       if (stat(path, &stb) == 0
+                                       p = path_build(psound, sample_name);
+                                       if (stat(p.native().data(), &stb) == 0
                                                        && (stb.st_mode & S_IFREG)) {
                                                NSData *audioData = [NSData
-                                                       dataWithContentsOfFile:[NSString stringWithUTF8String:path]];
+                                                       dataWithContentsOfFile:[NSString stringWithUTF8String:p.native().data()]];
 
                                                player = [[AVAudioPlayer alloc]
                                                        initWithData:audioData
@@ -729,16 +728,16 @@ static AngbandAudioManager *_sharedManager = nil;
                        get_monster_id },
                { NULL, 0, NULL, NULL } /* terminating sentinel */
        };
-       char music_dir[1024], path[1024];
+       std::filesystem::path pmusic, p;
        FILE *fff;
        NSMutableDictionary *catalog;
 
-       /* Build the "sound" path. */
-       path_build(music_dir, sizeof(music_dir), ANGBAND_DIR_XTRA, "music");
+       /* Build the "music" path. */
+       pmusic = path_build(ANGBAND_DIR_XTRA, "music");
 
        /* Find and open the config file. */
-       path_build(path, sizeof(path), music_dir, "music.cfg");
-       fff = angband_fopen(path, FileOpenMode::READ);
+       p = path_build(pmusic, "music.cfg");
+       fff = angband_fopen(p, FileOpenMode::READ);
 
        if (!fff) {
                NSLog(@"The music configuration file could not be opened");
@@ -878,14 +877,13 @@ static AngbandAudioManager *_sharedManager = nil;
                                 * file.  Also restrict the number of samples
                                 * stored for any type/ID combination.
                                 */
-                               path_build(path, sizeof(path), music_dir,
-                                       sample_name);
-                               if (stat(path, &stb) == 0
+                               p = path_build(pmusic, sample_name);
+                               if (stat(p.native().data(), &stb) == 0
                                                && (stb.st_mode & S_IFREG)
                                                && (int)samples.count
                                                < [AngbandAudioManager maxSamples]) {
                                        [samples addObject:[NSString
-                                               stringWithUTF8String:path]];
+                                               stringWithUTF8String:p.native().data()]];
                                }
 
                                if (done) {
index 9d972f9..e42206c 100644 (file)
 - (BOOL)isSoundEnabled
 {
        return ([self soundEnabledControl]
-               && [self soundEnabledControl].state != NSOffState) ? YES : NO;
+               && [self soundEnabledControl].state != NSControlStateValueOff)
+               ? YES : NO;
 }
 
 
 - (void)setSoundEnabled:(BOOL)v
 {
        if ([self soundEnabledControl]) {
-               [self soundEnabledControl].state = (v) ? NSOnState : NSOffState;
+               [self soundEnabledControl].state = (v) ?
+                       NSControlStateValueOn : NSControlStateValueOff;
        }
 }
 
 - (BOOL)isMusicEnabled
 {
        return ([self musicEnabledControl]
-               && [self musicEnabledControl].state != NSOffState) ? YES : NO;
+               && [self musicEnabledControl].state != NSControlStateValueOff)
+               ? YES : NO;
 }
 
 
 - (void)setMusicEnabled:(BOOL)v
 {
        if ([self musicEnabledControl]) {
-               [self musicEnabledControl].state = (v) ? NSOnState : NSOffState;
+               [self musicEnabledControl].state = (v) ?
+                       NSControlStateValueOn : NSControlStateValueOff;
        }
 }
 
@@ -86,8 +90,8 @@
 - (BOOL)isMusicPausedWhenInactive
 {
        return ([self musicPausedWhenInactiveControl]
-               && [self musicPausedWhenInactiveControl].state != NSOnState)
-               ? NO : YES;
+               && [self musicPausedWhenInactiveControl].state
+               != NSControlStateValueOn) ? NO : YES;
 }
 
 
@@ -95,7 +99,7 @@
 {
        if ([self musicPausedWhenInactiveControl]) {
                [self musicPausedWhenInactiveControl].state =
-                       (v) ? NSOnState : NSOffState;
+                       (v) ? NSControlStateValueOn : NSControlStateValueOff;
        }
 }
 
diff --git a/src/cocoa/en.lproj/Credits.html b/src/cocoa/en.lproj/Credits.html
new file mode 100644 (file)
index 0000000..871e004
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
+   "http://www.w3.org/TR/1998/REC-html40-19980424/strict.dtd">
+<HTML>
+  <HEAD lang="en">
+    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <TITLE>Hengband for macOS Credits</TITLE>
+  </HEAD>
+
+  <BODY>
+    <P>Hengband incorporates material from other projects:  see
+      <A HREF="THIRD-PARTY-NOTICES.txt">THIRD-PARTY-NOTICES.txt</A> for details.
+  </BODY>
+</HTML>
diff --git a/src/cocoa/ja.lproj/Credits.html b/src/cocoa/ja.lproj/Credits.html
new file mode 100644 (file)
index 0000000..e5345fb
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
+   "http://www.w3.org/TR/1998/REC-html40-19980424/strict.dtd">
+<HTML>
+  <HEAD lang="ja">
+    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <TITLE>macOS 用 変愚蛮怒 クレジット</TITLE>
+  </HEAD>
+
+  <BODY>
+    <P>変愚蛮怒 には他のプロジェクトの素材が組み込まれています。詳細については、<A HREF="THIRD-PARTY-NOTICES.txt">THIRD-PARTY-NOTICES.txt</A> (英語) を参照してください。
+  </BODY>
+</HTML>
index 91b6fdb..71c515a 100644 (file)
@@ -1,4 +1,4 @@
-#include "combat/attack-accuracy.h"
+#include "combat/attack-accuracy.h"
 #include "combat/combat-options-type.h"
 #include "inventory/inventory-slot-types.h"
 #include "main/sound-definitions-table.h"
@@ -6,7 +6,7 @@
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags-resistance.h"
 #include "object/tval-types.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "player-base/player-class.h"
 #include "player/attack-defense-types.h"
 #include "player/player-status-flags.h"
@@ -126,7 +126,7 @@ static bool decide_attack_hit(PlayerType *player_ptr, player_attack_type *pa_ptr
 {
     bool success_hit = false;
     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     if ((o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) || (pa_ptr->mode == HISSATSU_KYUSHO)) {
         int n = 1;
 
index 01f2b77..e8fdb9f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index c3d03ba..083380a 100644 (file)
@@ -1,4 +1,4 @@
-#include "combat/attack-criticality.h"
+#include "combat/attack-criticality.h"
 #include "combat/combat-options-type.h"
 #include "inventory/inventory-slot-types.h"
 #include "main/sound-of-music.h"
@@ -6,7 +6,7 @@
 #include "monster-race/race-flags1.h"
 #include "monster-race/race-flags7.h"
 #include "object/tval-types.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "player-base/player-class.h"
 #include "player-info/equipment-info.h"
 #include "sv-definition/sv-weapon-types.h"
@@ -89,7 +89,7 @@ int critical_norm(PlayerType *player_ptr, WEIGHT weight, int plus, int dam, int1
  */
 static void ninja_critical(PlayerType *player_ptr, player_attack_type *pa_ptr)
 {
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     int maxhp = pa_ptr->m_ptr->maxhp;
     if (one_in_(pa_ptr->backstab ? 13 : (pa_ptr->stab_fleeing || pa_ptr->surprise_attack) ? 15
                                                                                           : 27)) {
@@ -99,14 +99,18 @@ static void ninja_critical(PlayerType *player_ptr, player_attack_type *pa_ptr)
         return;
     }
 
+    const auto no_instantly_death = r_ptr->resistance_flags.has(MonsterResistanceType::NO_INSTANTLY_DEATH);
     bool is_weaken = pa_ptr->m_ptr->hp < maxhp / 2;
-    bool is_unique = (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) || ((r_ptr->flags7 & RF7_UNIQUE2) != 0);
+    bool is_unique = r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || no_instantly_death;
     bool is_critical = (is_weaken && one_in_((player_ptr->num_blow[0] + player_ptr->num_blow[1] + 1) * 10)) || ((one_in_(666) || ((pa_ptr->backstab || pa_ptr->surprise_attack) && one_in_(11))) && !is_unique);
     if (!is_critical) {
         return;
     }
 
     if (is_unique || !is_weaken) {
+        if (no_instantly_death) {
+            r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_INSTANTLY_DEATH);
+        }
         pa_ptr->attack_damage = std::max(pa_ptr->attack_damage * 5, pa_ptr->m_ptr->hp / 2);
         pa_ptr->drain_result *= 2;
         msg_format(_("%sに致命傷を負わせた!", "You fatally injured %s!"), pa_ptr->m_name);
@@ -124,12 +128,16 @@ static void ninja_critical(PlayerType *player_ptr, player_attack_type *pa_ptr)
 void critical_attack(PlayerType *player_ptr, player_attack_type *pa_ptr)
 {
     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
+    const auto no_instantly_death = r_ptr->resistance_flags.has(MonsterResistanceType::NO_INSTANTLY_DEATH);
     if ((o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) || (pa_ptr->mode == HISSATSU_KYUSHO)) {
-        if ((randint1(randint1(r_ptr->level / 7) + 5) == 1) && r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) && !(r_ptr->flags7 & RF7_UNIQUE2)) {
+        if ((randint1(randint1(r_ptr->level / 7) + 5) == 1) && r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) && !no_instantly_death) {
             pa_ptr->attack_damage = pa_ptr->m_ptr->hp + 1;
             msg_format(_("%sの急所を突き刺した!", "You hit %s on a fatal spot!"), pa_ptr->m_name);
         } else {
+            if (no_instantly_death) {
+                r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_INSTANTLY_DEATH);
+            }
             pa_ptr->attack_damage = 1;
         }
 
index 2c71944..fce5a86 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "combat/combat-options-type.h"
 #include "main/sound-definitions-table.h"
index 0df47ad..a43f6bb 100644 (file)
@@ -1,4 +1,4 @@
-#include "combat/attack-power-table.h"
+#include "combat/attack-power-table.h"
 
 /*!
  * @brief 修行僧のターンダメージ算出テーブル
index f365fd1..64f70a7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "system/system-variables.h"
index 3661460..b515e47 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターから直接攻撃を受けた時に、プレイヤーのオーラダメージで反撃する処理
  * @date 2020/05/31
  * @author Hourier
@@ -37,7 +37,7 @@ static void aura_fire_by_monster_attack(PlayerType *player_ptr, MonsterAttackPla
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_FIRE_MASK)) {
         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_FIRE_MASK);
@@ -62,7 +62,7 @@ static void aura_elec_by_monster_attack(PlayerType *player_ptr, MonsterAttackPla
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_ELEC_MASK)) {
         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_ELEC_MASK);
@@ -87,7 +87,7 @@ static void aura_cold_by_monster_attack(PlayerType *player_ptr, MonsterAttackPla
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_COLD_MASK)) {
         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_COLD_MASK);
@@ -112,7 +112,7 @@ static void aura_shards_by_monster_attack(PlayerType *player_ptr, MonsterAttackP
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (r_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_SHARDS_MASK)) {
         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
             r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_RESIST_SHARDS_MASK);
@@ -139,7 +139,7 @@ static void aura_holy_by_monster_attack(PlayerType *player_ptr, MonsterAttackPla
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (r_ptr->kind_flags.has_not(MonsterKindType::EVIL)) {
         return;
     }
@@ -172,7 +172,7 @@ static void aura_force_by_monster_attack(PlayerType *player_ptr, MonsterAttackPl
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
         if (is_original_ap_and_seen(player_ptr, monap_ptr->m_ptr)) {
             r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_ALL);
@@ -199,7 +199,7 @@ static void aura_shadow_by_monster_attack(PlayerType *player_ptr, MonsterAttackP
 
     int dam = 1;
     ItemEntity *o_armed_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND];
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     const EnumClassFlagGroup<MonsterResistanceType> resist_flags = { MonsterResistanceType::RESIST_ALL, MonsterResistanceType::RESIST_DARK };
 
     if (r_ptr->resistance_flags.has_any_of(resist_flags)) {
index cf682a2..309105d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class MonsterAttackPlayer;
 class PlayerType;
index b896301..d239b32 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum combat_options {
     HISSATSU_NONE = 0,
index e285007..630cd54 100644 (file)
@@ -1,4 +1,4 @@
-#include "combat/hallucination-attacks-table.h"
+#include "combat/hallucination-attacks-table.h"
 
 /*!
  * @brief 幻覚時の打撃記述テーブル / Weird melee attack types when hallucinating
index 622181d..1c0d5df 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e487081..70d3e5c 100644 (file)
@@ -1,4 +1,4 @@
-#include "combat/martial-arts-table.h"
+#include "combat/martial-arts-table.h"
 /*!
  * @brief マーシャルアーツ打撃テーブル
  */
index 9ef6c31..a0fc865 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index a118253..a5729dc 100644 (file)
@@ -1,9 +1,7 @@
-#include "combat/shoot.h"
+#include "combat/shoot.h"
 #include "artifact/fixed-art-types.h"
 #include "avatar/avatar.h"
 #include "combat/attack-criticality.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
@@ -45,7 +43,6 @@
 #include "monster/monster-status.h"
 #include "monster/monster-update.h"
 #include "object/object-broken.h"
-#include "object/object-flags.h"
 #include "object/object-info.h"
 #include "object/object-mark-types.h"
 #include "player-base/player-class.h"
@@ -64,6 +61,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
 #include "target/target-getter.h"
@@ -85,11 +83,9 @@ AttributeFlags shot_attribute(PlayerType *player_ptr, ItemEntity *bow_ptr, ItemE
     AttributeFlags attribute_flags{};
     attribute_flags.set(AttributeType::PLAYER_SHOOT);
 
-    TrFlags flags{};
-    auto arrow_flags = object_flags(arrow_ptr);
-    auto bow_flags = object_flags(bow_ptr);
-
-    flags = bow_flags | arrow_flags;
+    const auto arrow_flags = arrow_ptr->get_flags();
+    const auto bow_flags = bow_ptr->get_flags();
+    const auto flags = bow_flags | arrow_flags;
 
     static const struct snipe_convert_table_t {
         SPELL_IDX snipe_type;
@@ -157,148 +153,146 @@ static MULTIPLY calc_shot_damage_with_slay(
 {
     MULTIPLY mult = 10;
 
-    MonsterRaceInfo *race_ptr = &monraces_info[monster_ptr->r_idx];
-
-    TrFlags flags{};
-    auto arrow_flags = object_flags(arrow_ptr);
-    auto bow_flags = object_flags(bow_ptr);
+    auto &monrace = monster_ptr->get_monrace();
 
-    flags = bow_flags | arrow_flags;
+    const auto arrow_flags = arrow_ptr->get_flags();
+    const auto bow_flags = bow_ptr->get_flags();
+    const auto flags = bow_flags | arrow_flags;
 
     /* Some "weapons" and "ammo" do extra damage */
     switch (arrow_ptr->bi_key.tval()) {
     case ItemKindType::SHOT:
     case ItemKindType::ARROW:
     case ItemKindType::BOLT: {
-        if ((flags.has(TR_SLAY_ANIMAL)) && race_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
+        if ((flags.has(TR_SLAY_ANIMAL)) && monrace.kind_flags.has(MonsterKindType::ANIMAL)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::ANIMAL);
+                monrace.r_kind_flags.set(MonsterKindType::ANIMAL);
             }
             if (mult < 17) {
                 mult = 17;
             }
         }
 
-        if ((flags.has(TR_KILL_ANIMAL)) && race_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
+        if ((flags.has(TR_KILL_ANIMAL)) && monrace.kind_flags.has(MonsterKindType::ANIMAL)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::ANIMAL);
+                monrace.r_kind_flags.set(MonsterKindType::ANIMAL);
             }
             if (mult < 27) {
                 mult = 27;
             }
         }
 
-        if ((flags.has(TR_SLAY_EVIL)) && race_ptr->kind_flags.has(MonsterKindType::EVIL)) {
+        if ((flags.has(TR_SLAY_EVIL)) && monrace.kind_flags.has(MonsterKindType::EVIL)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::EVIL);
+                monrace.r_kind_flags.set(MonsterKindType::EVIL);
             }
             if (mult < 15) {
                 mult = 15;
             }
         }
 
-        if ((flags.has(TR_KILL_EVIL)) && race_ptr->kind_flags.has(MonsterKindType::EVIL)) {
+        if ((flags.has(TR_KILL_EVIL)) && monrace.kind_flags.has(MonsterKindType::EVIL)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::EVIL);
+                monrace.r_kind_flags.set(MonsterKindType::EVIL);
             }
             if (mult < 25) {
                 mult = 25;
             }
         }
 
-        if ((flags.has(TR_SLAY_GOOD)) && race_ptr->kind_flags.has(MonsterKindType::GOOD)) {
+        if ((flags.has(TR_SLAY_GOOD)) && monrace.kind_flags.has(MonsterKindType::GOOD)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::GOOD);
+                monrace.r_kind_flags.set(MonsterKindType::GOOD);
             }
             if (mult < 15) {
                 mult = 15;
             }
         }
 
-        if ((flags.has(TR_KILL_GOOD)) && race_ptr->kind_flags.has(MonsterKindType::GOOD)) {
+        if ((flags.has(TR_KILL_GOOD)) && monrace.kind_flags.has(MonsterKindType::GOOD)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::GOOD);
+                monrace.r_kind_flags.set(MonsterKindType::GOOD);
             }
             if (mult < 25) {
                 mult = 25;
             }
         }
 
-        if ((flags.has(TR_SLAY_HUMAN)) && race_ptr->kind_flags.has(MonsterKindType::HUMAN)) {
+        if ((flags.has(TR_SLAY_HUMAN)) && monrace.kind_flags.has(MonsterKindType::HUMAN)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::HUMAN);
+                monrace.r_kind_flags.set(MonsterKindType::HUMAN);
             }
             if (mult < 17) {
                 mult = 17;
             }
         }
 
-        if ((flags.has(TR_KILL_HUMAN)) && race_ptr->kind_flags.has(MonsterKindType::HUMAN)) {
+        if ((flags.has(TR_KILL_HUMAN)) && monrace.kind_flags.has(MonsterKindType::HUMAN)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::HUMAN);
+                monrace.r_kind_flags.set(MonsterKindType::HUMAN);
             }
             if (mult < 27) {
                 mult = 27;
             }
         }
 
-        if ((flags.has(TR_SLAY_UNDEAD)) && race_ptr->kind_flags.has(MonsterKindType::UNDEAD)) {
+        if ((flags.has(TR_SLAY_UNDEAD)) && monrace.kind_flags.has(MonsterKindType::UNDEAD)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::UNDEAD);
+                monrace.r_kind_flags.set(MonsterKindType::UNDEAD);
             }
             if (mult < 20) {
                 mult = 20;
             }
         }
 
-        if ((flags.has(TR_KILL_UNDEAD)) && race_ptr->kind_flags.has(MonsterKindType::UNDEAD)) {
+        if ((flags.has(TR_KILL_UNDEAD)) && monrace.kind_flags.has(MonsterKindType::UNDEAD)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::UNDEAD);
+                monrace.r_kind_flags.set(MonsterKindType::UNDEAD);
             }
             if (mult < 30) {
                 mult = 30;
             }
         }
 
-        if ((flags.has(TR_SLAY_DEMON)) && race_ptr->kind_flags.has(MonsterKindType::DEMON)) {
+        if ((flags.has(TR_SLAY_DEMON)) && monrace.kind_flags.has(MonsterKindType::DEMON)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::DEMON);
+                monrace.r_kind_flags.set(MonsterKindType::DEMON);
             }
             if (mult < 20) {
                 mult = 20;
             }
         }
 
-        if ((flags.has(TR_KILL_DEMON)) && race_ptr->kind_flags.has(MonsterKindType::DEMON)) {
+        if ((flags.has(TR_KILL_DEMON)) && monrace.kind_flags.has(MonsterKindType::DEMON)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::DEMON);
+                monrace.r_kind_flags.set(MonsterKindType::DEMON);
             }
             if (mult < 30) {
                 mult = 30;
             }
         }
 
-        if ((flags.has(TR_SLAY_ORC)) && race_ptr->kind_flags.has(MonsterKindType::ORC)) {
+        if ((flags.has(TR_SLAY_ORC)) && monrace.kind_flags.has(MonsterKindType::ORC)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::ORC);
+                monrace.r_kind_flags.set(MonsterKindType::ORC);
             }
             if (mult < 20) {
                 mult = 20;
             }
         }
 
-        if ((flags.has(TR_KILL_ORC)) && race_ptr->kind_flags.has(MonsterKindType::ORC)) {
+        if ((flags.has(TR_KILL_ORC)) && monrace.kind_flags.has(MonsterKindType::ORC)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::ORC);
+                monrace.r_kind_flags.set(MonsterKindType::ORC);
             }
             if (mult < 30) {
                 mult = 30;
             }
         }
 
-        if ((flags.has(TR_SLAY_TROLL)) && race_ptr->kind_flags.has(MonsterKindType::TROLL)) {
+        if ((flags.has(TR_SLAY_TROLL)) && monrace.kind_flags.has(MonsterKindType::TROLL)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::TROLL);
+                monrace.r_kind_flags.set(MonsterKindType::TROLL);
             }
 
             if (mult < 20) {
@@ -306,45 +300,45 @@ static MULTIPLY calc_shot_damage_with_slay(
             }
         }
 
-        if ((flags.has(TR_KILL_TROLL)) && race_ptr->kind_flags.has(MonsterKindType::TROLL)) {
+        if ((flags.has(TR_KILL_TROLL)) && monrace.kind_flags.has(MonsterKindType::TROLL)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::TROLL);
+                monrace.r_kind_flags.set(MonsterKindType::TROLL);
             }
             if (mult < 30) {
                 mult = 30;
             }
         }
 
-        if ((flags.has(TR_SLAY_GIANT)) && race_ptr->kind_flags.has(MonsterKindType::GIANT)) {
+        if ((flags.has(TR_SLAY_GIANT)) && monrace.kind_flags.has(MonsterKindType::GIANT)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::GIANT);
+                monrace.r_kind_flags.set(MonsterKindType::GIANT);
             }
             if (mult < 20) {
                 mult = 20;
             }
         }
 
-        if ((flags.has(TR_KILL_GIANT)) && race_ptr->kind_flags.has(MonsterKindType::GIANT)) {
+        if ((flags.has(TR_KILL_GIANT)) && monrace.kind_flags.has(MonsterKindType::GIANT)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::GIANT);
+                monrace.r_kind_flags.set(MonsterKindType::GIANT);
             }
             if (mult < 30) {
                 mult = 30;
             }
         }
 
-        if ((flags.has(TR_SLAY_DRAGON)) && race_ptr->kind_flags.has(MonsterKindType::DRAGON)) {
+        if ((flags.has(TR_SLAY_DRAGON)) && monrace.kind_flags.has(MonsterKindType::DRAGON)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::DRAGON);
+                monrace.r_kind_flags.set(MonsterKindType::DRAGON);
             }
             if (mult < 20) {
                 mult = 20;
             }
         }
 
-        if ((flags.has(TR_KILL_DRAGON)) && race_ptr->kind_flags.has(MonsterKindType::DRAGON)) {
+        if ((flags.has(TR_KILL_DRAGON)) && monrace.kind_flags.has(MonsterKindType::DRAGON)) {
             if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                race_ptr->r_kind_flags.set(MonsterKindType::DRAGON);
+                monrace.r_kind_flags.set(MonsterKindType::DRAGON);
             }
             if (mult < 30) {
                 mult = 30;
@@ -360,9 +354,9 @@ static MULTIPLY calc_shot_damage_with_slay(
 
         if (flags.has(TR_BRAND_ACID)) {
             /* Notice immunity */
-            if (race_ptr->resistance_flags.has_any_of(RFR_EFF_IM_ACID_MASK)) {
+            if (monrace.resistance_flags.has_any_of(RFR_EFF_IM_ACID_MASK)) {
                 if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                    race_ptr->r_resistance_flags.set(race_ptr->resistance_flags & RFR_EFF_IM_ACID_MASK);
+                    monrace.r_resistance_flags.set(monrace.resistance_flags & RFR_EFF_IM_ACID_MASK);
                 }
             } else {
                 if (mult < 17) {
@@ -373,9 +367,9 @@ static MULTIPLY calc_shot_damage_with_slay(
 
         if (flags.has(TR_BRAND_ELEC)) {
             /* Notice immunity */
-            if (race_ptr->resistance_flags.has_any_of(RFR_EFF_IM_ELEC_MASK)) {
+            if (monrace.resistance_flags.has_any_of(RFR_EFF_IM_ELEC_MASK)) {
                 if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                    race_ptr->r_resistance_flags.set(race_ptr->resistance_flags & RFR_EFF_IM_ELEC_MASK);
+                    monrace.r_resistance_flags.set(monrace.resistance_flags & RFR_EFF_IM_ELEC_MASK);
                 }
             } else {
                 if (mult < 17) {
@@ -386,19 +380,19 @@ static MULTIPLY calc_shot_damage_with_slay(
 
         if (flags.has(TR_BRAND_FIRE)) {
             /* Notice immunity */
-            if (race_ptr->resistance_flags.has_any_of(RFR_EFF_IM_FIRE_MASK)) {
+            if (monrace.resistance_flags.has_any_of(RFR_EFF_IM_FIRE_MASK)) {
                 if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                    race_ptr->r_resistance_flags.set(race_ptr->resistance_flags & RFR_EFF_IM_FIRE_MASK);
+                    monrace.r_resistance_flags.set(monrace.resistance_flags & RFR_EFF_IM_FIRE_MASK);
                 }
             }
             /* Otherwise, take the damage */
             else {
-                if (race_ptr->resistance_flags.has(MonsterResistanceType::HURT_FIRE)) {
+                if (monrace.resistance_flags.has(MonsterResistanceType::HURT_FIRE)) {
                     if (mult < 25) {
                         mult = 25;
                     }
                     if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                        race_ptr->r_resistance_flags.set(MonsterResistanceType::HURT_FIRE);
+                        monrace.r_resistance_flags.set(MonsterResistanceType::HURT_FIRE);
                     }
                 } else if (mult < 17) {
                     mult = 17;
@@ -408,19 +402,19 @@ static MULTIPLY calc_shot_damage_with_slay(
 
         if (flags.has(TR_BRAND_COLD)) {
             /* Notice immunity */
-            if (race_ptr->resistance_flags.has_any_of(RFR_EFF_IM_COLD_MASK)) {
+            if (monrace.resistance_flags.has_any_of(RFR_EFF_IM_COLD_MASK)) {
                 if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                    race_ptr->r_resistance_flags.set(race_ptr->resistance_flags & RFR_EFF_IM_COLD_MASK);
+                    monrace.r_resistance_flags.set(monrace.resistance_flags & RFR_EFF_IM_COLD_MASK);
                 }
             }
             /* Otherwise, take the damage */
             else {
-                if (race_ptr->resistance_flags.has(MonsterResistanceType::HURT_COLD)) {
+                if (monrace.resistance_flags.has(MonsterResistanceType::HURT_COLD)) {
                     if (mult < 25) {
                         mult = 25;
                     }
                     if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                        race_ptr->r_resistance_flags.set(MonsterResistanceType::HURT_COLD);
+                        monrace.r_resistance_flags.set(MonsterResistanceType::HURT_COLD);
                     }
                 } else if (mult < 17) {
                     mult = 17;
@@ -430,9 +424,9 @@ static MULTIPLY calc_shot_damage_with_slay(
 
         if (flags.has(TR_BRAND_POIS)) {
             /* Notice immunity */
-            if (race_ptr->resistance_flags.has_any_of(RFR_EFF_IM_POISON_MASK)) {
+            if (monrace.resistance_flags.has_any_of(RFR_EFF_IM_POISON_MASK)) {
                 if (is_original_ap_and_seen(player_ptr, monster_ptr)) {
-                    race_ptr->r_resistance_flags.set(race_ptr->resistance_flags & RFR_EFF_IM_POISON_MASK);
+                    monrace.r_resistance_flags.set(monrace.resistance_flags & RFR_EFF_IM_POISON_MASK);
                 }
             }
             /* Otherwise, take the damage */
@@ -445,7 +439,7 @@ static MULTIPLY calc_shot_damage_with_slay(
 
         if ((flags.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (player_ptr->msp / 30))) {
             player_ptr->csp -= (1 + (player_ptr->msp / 30));
-            set_bits(player_ptr->redraw, PR_MP);
+            RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
             mult = mult * 5 / 2;
         }
         break;
@@ -465,29 +459,11 @@ static MULTIPLY calc_shot_damage_with_slay(
 }
 
 /*!
- * @brief 射撃処理実行 /
- * Fire an object from the pack or floor.
- * @param item 射撃するオブジェクトの所持ID
+ * @brief 射撃処理実行
+ * @param i_idx 射撃するオブジェクトの所持ID
  * @param bow_ptr 射撃武器のオブジェクト参照ポインタ
- * @details
- * <pre>
- * You may only fire items that "match" your missile launcher.
- * You must use slings + pebbles/shots, bows + arrows, xbows + bolts.
- * See "calc_bonuses()" for more calculations and such.
- * Note that "firing" a missile is MUCH better than "throwing" it.
- * Note: "unseen" monsters are very hard to hit.
- * Objects are more likely to break if they "attempt" to hit a monster.
- * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots.
- * The "extra shot" code works by decreasing the amount of energy
- * required to make each shot, spreading the shots out over time.
- * Note that when firing missiles, the launcher multiplier is applied
- * after all the bonuses are added in, making multipliers very useful.
- * Note that Bows of "Extra Might" get extra range and an extra bonus
- * for the damage multiplier.
- * Note that Bows of "Extra Shots" give an extra shot.
- * </pre>
  */
-void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPELL_IDX snipe_type)
+void exe_fire(PlayerType *player_ptr, INVENTORY_IDX i_idx, ItemEntity *j_ptr, SPELL_IDX snipe_type)
 {
     POSITION y, x, ny, nx, ty, tx, prev_y, prev_x;
     ItemEntity forge;
@@ -501,10 +477,11 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
     auto stick_to = false;
 
     /* Access the item (if in the pack) */
-    if (item >= 0) {
-        o_ptr = &player_ptr->inventory_list[item];
+    auto *floor_ptr = player_ptr->current_floor_ptr;
+    if (i_idx >= 0) {
+        o_ptr = &player_ptr->inventory_list[i_idx];
     } else {
-        o_ptr = &player_ptr->current_floor_ptr->o_list[0 - item];
+        o_ptr = &floor_ptr->o_list[0 - i_idx];
     }
 
     /* Sniper - Cannot shot a single arrow twice */
@@ -534,7 +511,7 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
     if (tval == ItemKindType::NONE) {
         chance = (player_ptr->skill_thb + ((weapon_exps[0] - median_skill_exp) / bow_magnification + bonus) * BTH_PLUS_ADJ);
     } else {
-        const auto sval = j_ptr->bi_key.sval().value();
+        const auto sval = *j_ptr->bi_key.sval();
         if (j_ptr->is_cross_bow()) {
             chance = (player_ptr->skill_thb + (weapon_exps[sval] / xbow_magnification + bonus) * BTH_PLUS_ADJ);
         } else {
@@ -556,7 +533,7 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
     tdam_base *= tmul;
     tdam_base /= 100;
 
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     auto sniper_concent = sniper_data ? sniper_data->concent : 0;
 
     /* Base range */
@@ -630,7 +607,7 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
         /* Single object */
         q_ptr->number = 1;
 
-        vary_item(player_ptr, item, -1);
+        vary_item(player_ptr, i_idx, -1);
 
         sound(SOUND_SHOOT);
         handle_stuff(player_ptr);
@@ -643,7 +620,7 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
 
         /* Travel until stopped */
         for (auto cur_dis = 0; cur_dis <= tdis;) {
-            grid_type *g_ptr;
+            Grid *g_ptr;
 
             /* Hack -- Stop at the target */
             if ((y == ty) && (x == tx)) {
@@ -651,13 +628,13 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
             }
 
             /* Calculate the new location (see "project()") */
-            ny = y;
-            nx = x;
-            mmove2(&ny, &nx, player_ptr->y, player_ptr->x, ty, tx);
+            const auto pos = mmove2({ y, x }, player_ptr->get_position(), { ty, tx });
+            ny = pos.y;
+            nx = pos.x;
 
             /* Shatter Arrow */
             if (snipe_type == SP_KILL_WALL) {
-                g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
+                g_ptr = &floor_ptr->grid_array[ny][nx];
 
                 if (g_ptr->cave_has_flag(TerrainCharacteristics::HURT_ROCK) && !g_ptr->m_idx) {
                     if (any_bits(g_ptr->info, (CAVE_MARK))) {
@@ -665,7 +642,13 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
                     }
                     /* Forget the wall */
                     reset_bits(g_ptr->info, (CAVE_MARK));
-                    set_bits(player_ptr->update, PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTER_LITE);
+                    static constexpr auto flags = {
+                        StatusRecalculatingFlag::VIEW,
+                        StatusRecalculatingFlag::LITE,
+                        StatusRecalculatingFlag::FLOW,
+                        StatusRecalculatingFlag::MONSTER_LITE,
+                    };
+                    RedrawingFlagsUpdater::get_instance().set_flags(flags);
 
                     /* Destroy the wall */
                     cave_alter_feat(player_ptr, ny, nx, TerrainCharacteristics::HURT_ROCK);
@@ -676,7 +659,7 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
             }
 
             /* Stopped by walls/doors */
-            if (!cave_has_flag_bold(player_ptr->current_floor_ptr, ny, nx, TerrainCharacteristics::PROJECT) && !player_ptr->current_floor_ptr->grid_array[ny][nx].m_idx) {
+            if (!cave_has_flag_bold(floor_ptr, ny, nx, TerrainCharacteristics::PROJECT) && !floor_ptr->grid_array[ny][nx].m_idx) {
                 break;
             }
 
@@ -685,7 +668,7 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
 
             /* Sniper */
             if (snipe_type == SP_LITE) {
-                set_bits(player_ptr->current_floor_ptr->grid_array[ny][nx].info, CAVE_GLOW);
+                set_bits(floor_ptr->grid_array[ny][nx].info, CAVE_GLOW);
                 note_spot(player_ptr, ny, nx);
                 lite_spot(player_ptr, ny, nx);
             }
@@ -716,12 +699,13 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
 
             /* Sniper */
             if (snipe_type == SP_KILL_TRAP) {
-                project(player_ptr, 0, 0, ny, nx, 0, AttributeType::KILL_TRAP, (PROJECT_JUMP | PROJECT_HIDE | PROJECT_GRID | PROJECT_ITEM));
+                constexpr auto flags = PROJECT_JUMP | PROJECT_HIDE | PROJECT_GRID | PROJECT_ITEM;
+                project(player_ptr, 0, 0, ny, nx, 0, AttributeType::KILL_TRAP, flags);
             }
 
             /* Sniper */
             if (snipe_type == SP_EVILNESS) {
-                reset_bits(player_ptr->current_floor_ptr->grid_array[ny][nx].info, (CAVE_GLOW | CAVE_MARK));
+                reset_bits(floor_ptr->grid_array[ny][nx].info, (CAVE_GLOW | CAVE_MARK));
                 note_spot(player_ptr, ny, nx);
                 lite_spot(player_ptr, ny, nx);
             }
@@ -734,12 +718,12 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
             y = ny;
 
             /* Monster here, Try to hit it */
-            if (player_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
+            if (floor_ptr->grid_array[y][x].m_idx) {
                 sound(SOUND_SHOOT_HIT);
-                grid_type *c_mon_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+                Grid *c_mon_ptr = &floor_ptr->grid_array[y][x];
 
-                auto *m_ptr = &player_ptr->current_floor_ptr->m_list[c_mon_ptr->m_idx];
-                auto *r_ptr = &monraces_info[m_ptr->r_idx];
+                auto *m_ptr = &floor_ptr->m_list[c_mon_ptr->m_idx];
+                auto *r_ptr = &m_ptr->get_monrace();
 
                 /* Check the visibility */
                 auto visible = m_ptr->ml;
@@ -798,7 +782,8 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
                     if (snipe_type == SP_NEEDLE) {
                         const auto is_unique = r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
                         const auto fatality = randint1(r_ptr->level / (3 + sniper_concent)) + (8 - sniper_concent);
-                        if ((randint1(fatality) == 1) && !is_unique && none_bits(r_ptr->flags7, RF7_UNIQUE2)) {
+                        const auto no_instantly_death = r_ptr->resistance_flags.has(MonsterResistanceType::NO_INSTANTLY_DEATH);
+                        if ((randint1(fatality) == 1) && !is_unique && !no_instantly_death) {
                             /* Get "the monster" or "it" */
                             const auto m_name = monster_desc(player_ptr, m_ptr, 0);
 
@@ -806,6 +791,9 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
                             base_dam = tdam;
                             msg_format(_("%sの急所に突き刺さった!", "Your shot hit a fatal spot of %s!"), m_name.data());
                         } else {
+                            if (no_instantly_death) {
+                                r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_INSTANTLY_DEATH);
+                            }
                             tdam = 1;
                             base_dam = tdam;
                         }
@@ -840,14 +828,14 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
 
                     /* Sniper */
                     if (snipe_type == SP_HOLYNESS) {
-                        set_bits(player_ptr->current_floor_ptr->grid_array[ny][nx].info, CAVE_GLOW);
+                        set_bits(floor_ptr->grid_array[ny][nx].info, CAVE_GLOW);
                         note_spot(player_ptr, ny, nx);
                         lite_spot(player_ptr, ny, nx);
                     }
 
                     /* Hit the monster, check for death */
                     MonsterDamageProcessor mdp(player_ptr, c_mon_ptr->m_idx, tdam, &fear, attribute_flags);
-                    if (mdp.mon_take_hit(extract_note_dies(m_ptr->get_real_r_idx()))) {
+                    if (mdp.mon_take_hit(m_ptr->get_died_message())) {
                         /* Dead monster */
                     }
 
@@ -893,15 +881,17 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
                                 }
 
                                 /* Calculate the new location (see "project()") */
-                                mmove2(&ny, &nx, player_ptr->y, player_ptr->x, ty, tx);
+                                const auto pos_to = mmove2({ ny, nx }, player_ptr->get_position(), { ty, tx });
+                                ny = pos_to.y;
+                                nx = pos_to.x;
 
                                 /* Stopped by wilderness boundary */
-                                if (!in_bounds2(player_ptr->current_floor_ptr, ny, nx)) {
+                                if (!in_bounds2(floor_ptr, ny, nx)) {
                                     break;
                                 }
 
                                 /* Stopped by walls/doors */
-                                if (!player_can_enter(player_ptr, player_ptr->current_floor_ptr->grid_array[ny][nx].feat, 0)) {
+                                if (!player_can_enter(player_ptr, floor_ptr->grid_array[ny][nx].feat, 0)) {
                                     break;
                                 }
 
@@ -910,8 +900,8 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
                                     break;
                                 }
 
-                                player_ptr->current_floor_ptr->grid_array[ny][nx].m_idx = m_idx;
-                                player_ptr->current_floor_ptr->grid_array[oy][ox].m_idx = 0;
+                                floor_ptr->grid_array[ny][nx].m_idx = m_idx;
+                                floor_ptr->grid_array[oy][ox].m_idx = 0;
 
                                 m_ptr->fx = nx;
                                 m_ptr->fy = ny;
@@ -949,9 +939,9 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
         auto j = (hit_body ? breakage_chance(player_ptr, q_ptr, PlayerClass(player_ptr).equals(PlayerClassType::ARCHER), snipe_type) : 0);
 
         if (stick_to) {
-            MONSTER_IDX m_idx = player_ptr->current_floor_ptr->grid_array[y][x].m_idx;
-            auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-            OBJECT_IDX o_idx = o_pop(player_ptr->current_floor_ptr);
+            MONSTER_IDX m_idx = floor_ptr->grid_array[y][x].m_idx;
+            auto *m_ptr = &floor_ptr->m_list[m_idx];
+            OBJECT_IDX o_idx = o_pop(floor_ptr);
 
             if (!o_idx) {
                 msg_format(_("%sはどこかへ行った。", "The %s went somewhere."), item_name.data());
@@ -961,7 +951,7 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
                 return;
             }
 
-            o_ptr = &player_ptr->current_floor_ptr->o_list[o_idx];
+            o_ptr = &floor_ptr->o_list[o_idx];
             o_ptr->copy_from(q_ptr);
 
             /* Forget mark */
@@ -974,8 +964,8 @@ void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPE
             o_ptr->held_m_idx = m_idx;
 
             /* Carry object */
-            m_ptr->hold_o_idx_list.add(player_ptr->current_floor_ptr, o_idx);
-        } else if (cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
+            m_ptr->hold_o_idx_list.add(floor_ptr, o_idx);
+        } else if (cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
             /* Drop (or break) near that location */
             (void)drop_near(player_ptr, q_ptr, j, y, x);
         } else {
@@ -1003,12 +993,12 @@ bool test_hit_fire(PlayerType *player_ptr, int chance, MonsterEntity *m_ptr, int
 {
     int k;
     ARMOUR_CLASS ac;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     /* Percentile dice */
     k = randint1(100);
 
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     auto sniper_concent = sniper_data ? sniper_data->concent : 0;
 
     /* Snipers with high-concentration reduce instant miss percentage.*/
@@ -1079,7 +1069,7 @@ int critical_shot(PlayerType *player_ptr, WEIGHT weight, int plus_ammo, int plus
     if (tval == ItemKindType::NONE) {
         power = player_ptr->skill_thb + ((weapon_exps[0] - median_skill_exp) / bow_magnification + bonus) * BTH_PLUS_ADJ;
     } else {
-        const auto sval = item.bi_key.sval().value();
+        const auto sval = *item.bi_key.sval();
         const auto weapon_exp = weapon_exps[sval];
         if (player_ptr->tval_ammo == ItemKindType::BOLT) {
             power = (player_ptr->skill_thb + (weapon_exp / xbow_magnification + bonus) * BTH_PLUS_ADJ);
@@ -1089,7 +1079,7 @@ int critical_shot(PlayerType *player_ptr, WEIGHT weight, int plus_ammo, int plus
     }
 
     PlayerClass pc(player_ptr);
-    const auto sniper_data = pc.get_specific_data<sniper_data_type>();
+    const auto sniper_data = pc.get_specific_data<SniperData>();
     const auto sniper_concent = sniper_data ? sniper_data->concent : 0;
 
     /* Snipers can shot more critically with crossbows */
@@ -1134,7 +1124,7 @@ int calc_crit_ratio_shot(PlayerType *player_ptr, int plus_ammo, int plus_bow)
     /* Extract "shot" power */
     auto i = player_ptr->to_h_b + plus_ammo;
     const auto tval = j_ptr->bi_key.tval();
-    const auto sval = j_ptr->bi_key.sval().value();
+    const auto sval = *j_ptr->bi_key.sval();
     if (player_ptr->tval_ammo == ItemKindType::BOLT) {
         i = (player_ptr->skill_thb + (player_ptr->weapon_exp[tval][sval] / 400 + i) * BTH_PLUS_ADJ);
     } else {
@@ -1142,7 +1132,7 @@ int calc_crit_ratio_shot(PlayerType *player_ptr, int plus_ammo, int plus_bow)
     }
 
     PlayerClass pc(player_ptr);
-    auto sniper_data = pc.get_specific_data<sniper_data_type>();
+    auto sniper_data = pc.get_specific_data<SniperData>();
     auto sniper_concent = sniper_data ? sniper_data->concent : 0;
 
     /* Snipers can shot more critically with crossbows */
index e4d3603..70fd1ff 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
@@ -11,4 +11,4 @@ int critical_shot(PlayerType *player_ptr, WEIGHT weight, int plus_ammo, int plus
 int calc_crit_ratio_shot(PlayerType *player_ptr, int plus_ammo, int plus_bow);
 int calc_expect_crit_shot(PlayerType *player_ptr, WEIGHT weight, int plus_ammo, int plus_bow, int dam);
 int calc_expect_crit(PlayerType *player_ptr, WEIGHT weight, int plus, int dam, int16_t meichuu, bool dokubari, bool impact);
-void exe_fire(PlayerType *player_ptr, INVENTORY_IDX item, ItemEntity *j_ptr, SPELL_IDX snipe_type);
+void exe_fire(PlayerType *player_ptr, INVENTORY_IDX i_idx, ItemEntity *j_ptr, SPELL_IDX snipe_type);
index 3ceed85..36ae1f5 100644 (file)
@@ -1,6 +1,5 @@
-#include "combat/slaying.h"
+#include "combat/slaying.h"
 #include "artifact/fixed-art-types.h"
-#include "core/player-redraw-types.h"
 #include "effect/attribute-types.h"
 #include "mind/mind-samurai.h"
 #include "monster-race/monster-race.h"
@@ -11,7 +10,6 @@
 #include "monster-race/race-resistance-mask.h"
 #include "monster/monster-info.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "player-base/player-class.h"
 #include "player/attack-defense-types.h"
@@ -22,6 +20,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 
 /*!
@@ -61,7 +60,7 @@ MULTIPLY mult_slaying(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flag
         { TR_KILL_DRAGON, MonsterKindType::DRAGON, 50 },
     };
 
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     for (size_t i = 0; i < sizeof(slay_table) / sizeof(slay_table[0]); ++i) {
         const struct slay_table_t *p = &slay_table[i];
 
@@ -101,7 +100,7 @@ MULTIPLY mult_brand(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags,
         { TR_BRAND_POIS, RFR_EFF_IM_POISON_MASK, MonsterResistanceType::MAX },
     };
 
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     for (size_t i = 0; i < sizeof(brand_table) / sizeof(brand_table[0]); ++i) {
         const struct brand_table_t *p = &brand_table[i];
 
@@ -152,7 +151,7 @@ MULTIPLY mult_brand(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags,
  */
 int calc_attack_damage_with_slay(PlayerType *player_ptr, ItemEntity *o_ptr, int tdam, MonsterEntity *m_ptr, combat_options mode, bool thrown)
 {
-    auto flags = object_flags(o_ptr);
+    auto flags = o_ptr->get_flags();
     torch_flags(o_ptr, flags); /* torches has secret flags */
 
     if (!thrown) {
@@ -198,7 +197,7 @@ int calc_attack_damage_with_slay(PlayerType *player_ptr, ItemEntity *o_ptr, int
 
         if (!pc.equals(PlayerClassType::SAMURAI) && (flags.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5))) {
             player_ptr->csp -= (1 + (o_ptr->dd * o_ptr->ds / 5));
-            player_ptr->redraw |= (PR_MP);
+            RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
             mult = mult * 3 / 2 + 20;
         }
 
@@ -244,7 +243,7 @@ AttributeFlags melee_attribute(PlayerType *player_ptr, ItemEntity *o_ptr, combat
         }
     }
 
-    auto flags = object_flags(o_ptr);
+    auto flags = o_ptr->get_flags();
 
     if (player_ptr->special_attack & (ATTACK_ACID)) {
         flags.set(TR_BRAND_ACID);
index 47cf3f6..8a02ca8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 1c77d8c..3332111 100644 (file)
@@ -1,4 +1,4 @@
-#include "core/asking-player.h"
+#include "core/asking-player.h"
 #include "cmd-io/macro-util.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
@@ -8,6 +8,7 @@
 #include "io/input-key-requester.h" //!< @todo 相互依存している、後で何とかする.
 #include "main/sound-of-music.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "util/int-char-converter.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
-
 #include <algorithm>
 #include <charconv>
 #include <climits>
 #include <iostream>
 #include <sstream>
+#include <stdexcept>
 #include <string>
 
+namespace {
+std::vector<char> clear_buffer(int len, std::string_view initial_value)
+{
+    std::vector<char> buf(len + 1, '\0');
+    initial_value.copy(buf.data(), len);
+    return buf;
+}
+}
+
 /*
  * Get some string input at the cursor location.
  * Assume the buffer is initialized to a default string.
@@ -40,7 +50,7 @@
  * ESCAPE clears the buffer and the window and returns FALSE.
  * RETURN accepts the current buffer contents and returns TRUE.
  */
-bool askfor(char *buf, int len, bool numpad_cursor)
+std::optional<std::string> askfor(int len, std::string_view initial_value, bool numpad_cursor)
 {
     /*
      * Text color
@@ -63,11 +73,11 @@ bool askfor(char *buf, int len, bool numpad_cursor)
         len = MAIN_TERM_MIN_COLS - x;
     }
 
-    buf[len] = '\0';
+    auto buf = clear_buffer(len, initial_value);
     auto pos = 0;
     while (true) {
         term_erase(x, y, len);
-        term_putstr(x, y, -1, color, buf);
+        term_putstr(x, y, -1, color, buf.data());
         term_gotoxy(x + pos, y);
         const auto skey = inkey_special(numpad_cursor);
         switch (skey) {
@@ -113,12 +123,21 @@ bool askfor(char *buf, int len, bool numpad_cursor)
             pos++;
 #endif
             break;
+        case SKEY_TOP:
+        case KTRL('a'):
+            color = TERM_WHITE;
+            pos = 0;
+            break;
+        case SKEY_BOTTOM:
+        case KTRL('e'):
+            color = TERM_WHITE;
+            pos = std::string_view(buf.data()).length();
+            break;
         case ESCAPE:
-            buf[0] = '\0';
-            return false;
+            return std::nullopt;
         case '\n':
         case '\r':
-            return true;
+            return buf.data();
         case '\010': {
             auto i = 0;
             color = TERM_WHITE;
@@ -164,18 +183,17 @@ bool askfor(char *buf, int len, bool numpad_cursor)
             break;
         }
         default: {
-            char tmp[100];
             if (skey & SKEY_MASK) {
                 break;
             }
 
             const auto c = static_cast<char>(skey);
             if (color == TERM_YELLOW) {
-                buf[0] = '\0';
+                buf = clear_buffer(len, "");
                 color = TERM_WHITE;
             }
 
-            strcpy(tmp, buf + pos);
+            const auto str_right_cursor = std::string(buf.data()).substr(pos);
 #ifdef JP
             if (iskanji(c)) {
                 inkey_base = true;
@@ -198,7 +216,7 @@ bool askfor(char *buf, int len, bool numpad_cursor)
             }
 
             buf[pos] = '\0';
-            angband_strcat(buf, tmp, len + 1);
+            angband_strcat(buf.data(), str_right_cursor, buf.size());
             break;
         }
         }
@@ -215,14 +233,13 @@ bool askfor(char *buf, int len, bool numpad_cursor)
  *
  * We clear the input, and return FALSE, on "ESCAPE".
  */
-bool get_string(std::string_view prompt, char *buf, int len)
+std::optional<std::string> input_string(std::string_view prompt, int len, std::string_view initial_value, bool numpad_cursor)
 {
-    bool res;
     msg_print(nullptr);
     prt(prompt, 0, 0);
-    res = askfor(buf, len);
+    const auto ask_result = askfor(len, initial_value, numpad_cursor);
     prt("", 0, 0);
-    return res;
+    return ask_result;
 }
 
 /*
@@ -232,38 +249,48 @@ bool get_string(std::string_view prompt, char *buf, int len)
  *
  * Note that "[y/n]" is appended to the prompt.
  */
-bool get_check(std::string_view prompt)
+bool input_check(std::string_view prompt)
 {
-    return get_check_strict(p_ptr, prompt, 0);
+    return input_check_strict(p_ptr, prompt, UserCheck::NONE);
+}
+
+/*!
+ * @details initializer_list を使うと再帰呼び出し扱いになるので一旦FlagGroup で受ける
+ */
+bool input_check_strict(PlayerType *player_ptr, std::string_view prompt, UserCheck one_mode)
+{
+    EnumClassFlagGroup<UserCheck> mode = { one_mode };
+    return input_check_strict(player_ptr, prompt, mode);
 }
 
 /*
  * Verify something with the user strictly
  *
- * mode & CHECK_OKAY_CANCEL : force user to answer 'O'kay or 'C'ancel
- * mode & CHECK_NO_ESCAPE   : don't allow ESCAPE key
- * mode & CHECK_NO_HISTORY  : no message_add
- * mode & CHECK_DEFAULT_Y   : accept any key as y, except n and Esc.
+ * OKAY_CANCEL : force user to answer 'O'kay or 'C'ancel
+ * NO_ESCAPE   : don't allow ESCAPE key
+ * NO_HISTORY  : no message_add
+ * DEFAULT_Y   : accept any key as y, except n and Esc.
  */
-bool get_check_strict(PlayerType *player_ptr, std::string_view prompt, BIT_FLAGS mode)
+bool input_check_strict(PlayerType *player_ptr, std::string_view prompt, EnumClassFlagGroup<UserCheck> mode)
 {
     if (!rogue_like_commands) {
-        mode &= ~CHECK_OKAY_CANCEL;
+        mode.reset(UserCheck::OKAY_CANCEL);
     }
 
     std::stringstream ss;
     ss << prompt;
-    if (mode & CHECK_OKAY_CANCEL) {
+    if (mode.has(UserCheck::OKAY_CANCEL)) {
         ss << "[(O)k/(C)ancel]";
-    } else if (mode & CHECK_DEFAULT_Y) {
+    } else if (mode.has(UserCheck::DEFAULT_Y)) {
         ss << "[Y/n]";
     } else {
         ss << "[y/n]";
     }
-    const auto buf = ss.str();
 
+    const auto buf = ss.str();
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (auto_more) {
-        player_ptr->window_flags |= PW_MESSAGE;
+        rfu.set_flag(SubWindowRedrawingFlag::MESSAGE);
         handle_stuff(player_ptr);
         num_more = 0;
     }
@@ -271,9 +298,9 @@ bool get_check_strict(PlayerType *player_ptr, std::string_view prompt, BIT_FLAGS
     msg_print(nullptr);
 
     prt(buf, 0, 0);
-    if (!(mode & CHECK_NO_HISTORY) && player_ptr->playing) {
+    if (mode.has_not(UserCheck::NO_HISTORY) && player_ptr->playing) {
         message_add(buf);
-        player_ptr->window_flags |= (PW_MESSAGE);
+        rfu.set_flag(SubWindowRedrawingFlag::MESSAGE);
         handle_stuff(player_ptr);
     }
 
@@ -281,14 +308,14 @@ bool get_check_strict(PlayerType *player_ptr, std::string_view prompt, BIT_FLAGS
     while (true) {
         int i = inkey();
 
-        if (!(mode & CHECK_NO_ESCAPE)) {
+        if (mode.has_not(UserCheck::NO_ESCAPE)) {
             if (i == ESCAPE) {
                 flag = false;
                 break;
             }
         }
 
-        if (mode & CHECK_OKAY_CANCEL) {
+        if (mode.has(UserCheck::OKAY_CANCEL)) {
             if (i == 'o' || i == 'O') {
                 flag = true;
                 break;
@@ -306,7 +333,7 @@ bool get_check_strict(PlayerType *player_ptr, std::string_view prompt, BIT_FLAGS
             }
         }
 
-        if (mode & CHECK_DEFAULT_Y) {
+        if (mode.has(UserCheck::DEFAULT_Y)) {
             flag = true;
             break;
         }
@@ -325,42 +352,35 @@ bool get_check_strict(PlayerType *player_ptr, std::string_view prompt, BIT_FLAGS
  *
  * Returns TRUE unless the character is "Escape"
  */
-bool get_com(std::string_view prompt, char *command, bool z_escape)
+std::optional<char> input_command(std::string_view prompt, bool z_escape)
 {
     msg_print(nullptr);
     prt(prompt, 0, 0);
+    char command;
     if (get_com_no_macros) {
-        *command = (char)inkey_special(false);
+        command = static_cast<char>(inkey_special(false));
     } else {
-        *command = inkey();
+        command = inkey();
     }
 
     prt("", 0, 0);
-    if (*command == ESCAPE) {
-        return false;
-    }
-    if (z_escape && ((*command == 'z') || (*command == 'Z'))) {
-        return false;
+    const auto is_z = (command == 'z') || (command == 'Z');
+    if ((command == ESCAPE) || (z_escape && is_z)) {
+        return std::nullopt;
     }
 
-    return true;
+    return command;
 }
 
 /*
- * Request a "quantity" from the user
- *
- * Hack -- allow "command_arg" to specify a quantity
+ * @brief 数量をユーザ入力する
+ * @param max 最大値 (売出し商品の個数等)
+ * @param initial_prompt 初期値
+ * @details 数値でない値 ('a'等)を入力したら最大数を選択したとみなす.
  */
-QUANTITY get_quantity(std::optional<std::string_view> prompt_opt, QUANTITY max)
+int input_quantity(int max, std::string_view initial_prompt)
 {
-    // FIXME : QUANTITY、COMMAND_CODE、その他の型サイズがまちまちな変数とのやり取りが多数ある。この処理での数の入力を0からSHRT_MAXに制限することで不整合の発生を回避する。
-    max = std::clamp<QUANTITY>(max, 0, SHRT_MAX);
-
-    bool res;
-    char tmp[80];
-    char buf[80];
-
-    QUANTITY amt;
+    int amt;
     if (command_arg) {
         amt = command_arg;
         command_arg = 0;
@@ -371,52 +391,46 @@ QUANTITY get_quantity(std::optional<std::string_view> prompt_opt, QUANTITY max)
         return amt;
     }
 
-    COMMAND_CODE code;
-    bool result = repeat_pull(&code);
-    amt = (QUANTITY)code;
+    short code;
+    auto result = repeat_pull(&code);
+    amt = code;
     if ((max != 1) && result) {
         if (amt > max) {
-            amt = max;
+            return max;
         }
+
         if (amt < 0) {
-            amt = 0;
+            return 0;
         }
 
         return amt;
     }
 
-    std::string_view prompt;
-    if (prompt_opt.has_value()) {
-        prompt = prompt_opt.value();
+    std::string prompt;
+    if (!initial_prompt.empty()) {
+        prompt = initial_prompt;
     } else {
-        strnfmt(tmp, sizeof(tmp), _("いくつですか (1-%d): ", "Quantity (1-%d): "), max);
-        prompt = tmp;
+        prompt = format(_("いくつですか (1-%d): ", "Quantity (1-%d): "), max);
     }
 
     msg_print(nullptr);
-    prt(prompt, 0, 0);
-    amt = 1;
-    strnfmt(buf, sizeof(buf), "%d", amt);
-
-    /*
-     * Ask for a quantity
-     * Don't allow to use numpad as cursor key.
-     */
-    res = askfor(buf, 6, false);
-
-    prt("", 0, 0);
-    if (!res) {
+    const auto input_amount = input_string(prompt, 6, "1", false);
+    if (!input_amount) {
         return 0;
     }
 
-    if (isalpha(buf[0])) {
+    if (isalpha((*input_amount)[0])) {
         amt = max;
     } else {
-        amt = std::clamp<int>(atoi(buf), 0, max);
+        try {
+            amt = std::clamp<int>(std::stoi(*input_amount), 0, max);
+        } catch (const std::exception &) {
+            amt = 0;
+        }
     }
 
-    if (amt) {
-        repeat_push((COMMAND_CODE)amt);
+    if (amt > 0) {
+        repeat_push(static_cast<short>(amt));
     }
 
     return amt;
@@ -434,31 +448,31 @@ void pause_line(int row)
     prt("", row, 0);
 }
 
-bool get_value(std::string_view prompt, int min, int max, int *value)
+std::optional<int> input_integer(std::string_view prompt, int min, int max, int initial_value)
 {
-    std::stringstream st;
-    int val;
-    char tmp_val[12] = "";
-    /* std::to_chars() requires Mac OS X 10.15 or later. */
-#if !defined(MACH_O_COCOA) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_15)
-    std::to_chars(std::begin(tmp_val), std::end(tmp_val) - 1, *value);
-#else
-    snprintf(tmp_val, sizeof(tmp_val), "%d", *value);
-#endif
-    st << prompt << "(" << min << "-" << max << "): ";
-    int digit = std::max(std::to_string(min).length(), std::to_string(max).length());
+    std::stringstream ss;
+    ss << prompt << "(" << min << "-" << max << "): ";
+    auto digit = std::max(std::to_string(min).length(), std::to_string(max).length());
     while (true) {
-        if (!get_string(st.str().data(), tmp_val, digit)) {
-            return false;
+        const auto input_str = input_string(ss.str(), digit, std::to_string(initial_value), false);
+        if (!input_str) {
+            return std::nullopt;
         }
 
-        val = atoi(tmp_val);
+        try {
+            auto val = std::stoi(*input_str);
+            if ((val < min) || (val > max)) {
+                msg_format(_("%dから%dの間で指定して下さい。", "It must be between %d to %d."), min, max);
+                continue;
+            }
 
-        if (min <= val && max >= val) {
-            break;
+            return val;
+        } catch (std::invalid_argument const &) {
+            msg_print(_("数値を入力して下さい。", "Please input numeric value."));
+            continue;
+        } catch (std::out_of_range const &) {
+            msg_print(_("入力可能な数値の範囲を超えています。", "Input value overflows the maximum number."));
+            continue;
         }
-        msg_format(_("%dから%dの間で指定して下さい。", "It must be between %d to %d."), min, max);
     }
-    *value = val;
-    return true;
 }
index a59ba84..eb24a7d 100644 (file)
@@ -1,23 +1,38 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include "util/flag-group.h"
 #include <optional>
 #include <string_view>
+#include <type_traits>
 
-/*
- * Bit flags for control of get_check_strict()
- */
-#define CHECK_OKAY_CANCEL 0x01
-#define CHECK_NO_ESCAPE 0x02
-#define CHECK_NO_HISTORY 0x04
-#define CHECK_DEFAULT_Y 0x08
+enum class UserCheck {
+    NONE = 0,
+    OKAY_CANCEL = 1,
+    NO_ESCAPE = 2,
+    NO_HISTORY = 3,
+    DEFAULT_Y = 4,
+    MAX = 5,
+};
 
 class PlayerType;
-bool askfor(char *buf, int len, bool numpad_cursor = true);
-bool get_string(std::string_view prompt, char *buf, int len);
-bool get_check(std::string_view prompt);
-bool get_check_strict(PlayerType *player_ptr, std::string_view prompt, BIT_FLAGS mode);
-bool get_com(std::string_view prompt, char *command, bool z_escape);
-QUANTITY get_quantity(std::optional<std::string_view> prompt_opt, QUANTITY max);
+std::optional<std::string> askfor(int len, std::string_view initial_value = "", bool numpad_cursor = true);
+std::optional<std::string> input_string(std::string_view prompt, int len, std::string_view initial_value = "", bool numpad_cursor = true);
+bool input_check(std::string_view prompt);
+bool input_check_strict(PlayerType *player_ptr, std::string_view prompt, UserCheck one_mode);
+bool input_check_strict(PlayerType *player_ptr, std::string_view prompt, EnumClassFlagGroup<UserCheck> mode);
+std::optional<char> input_command(std::string_view prompt, bool z_escape = false);
+int input_quantity(int max, std::string_view initial_prompt = "");
 void pause_line(int row);
-bool get_value(std::string_view prompt, int min, int max, int *value);
+std::optional<int> input_integer(std::string_view prompt, int min, int max, int initial_value = 0);
+
+template <typename T>
+std::optional<T> input_numerics(std::string_view prompt, int min, int max, T initial_value = static_cast<T>(0))
+    requires std::is_integral_v<T> || std::is_enum_v<T>
+{
+    auto result = input_integer(prompt, min, max, static_cast<int>(initial_value));
+    if (!result) {
+        return std::nullopt;
+    }
+
+    return std::make_optional(static_cast<T>(*result));
+}
index 99006a1..ef8da97 100644 (file)
@@ -1,13 +1,12 @@
-#include "core/disturbance.h"
+#include "core/disturbance.h"
 #include "action/travel-execution.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "game-option/disturbance-options.h"
 #include "game-option/map-screen-options.h"
 #include "io/input-key-requester.h"
 #include "player/attack-defense-types.h"
 #include "status/action-setter.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "term/screen-processor.h"
 
  */
 void disturb(PlayerType *player_ptr, bool stop_search, bool stop_travel)
 {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (command_rep) {
         command_rep = 0;
-        player_ptr->redraw |= PR_ACTION;
+        rfu.set_flag(MainWindowRedrawingFlag::ACTION);
     }
 
     if ((player_ptr->action == ACTION_REST) || (player_ptr->action == ACTION_FISH) || (stop_search && (player_ptr->action == ACTION_SEARCH))) {
@@ -34,8 +34,11 @@ void disturb(PlayerType *player_ptr, bool stop_search, bool stop_travel)
             verify_panel(player_ptr);
         }
 
-        player_ptr->update |= PU_TORCH;
-        player_ptr->update |= PU_FLOW;
+        static constexpr auto flags = {
+            StatusRecalculatingFlag::TORCH,
+            StatusRecalculatingFlag::FLOW,
+        };
+        rfu.set_flags(flags);
     }
 
     if (stop_travel) {
@@ -44,7 +47,7 @@ void disturb(PlayerType *player_ptr, bool stop_search, bool stop_travel)
             verify_panel(player_ptr);
         }
 
-        player_ptr->update |= PU_TORCH;
+        rfu.set_flag(StatusRecalculatingFlag::TORCH);
     }
 
     if (flush_disturb) {
index 1421e4b..2a9e929 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void disturb(PlayerType *player_ptr, bool stop_search, bool flush_output);
index e5b632b..aada48a 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @file game-closer.cpp
  * @brief ゲーム終了処理
  * @author Hourier
@@ -48,8 +48,8 @@ static void send_world_score_on_closing(PlayerType *player_ptr, bool do_send)
         return;
     }
 
-    if (!get_check_strict(
-            player_ptr, _("後でスコアを登録するために待機しますか?", "Stand by for later score registration? "), (CHECK_NO_ESCAPE | CHECK_NO_HISTORY))) {
+    if (!input_check_strict(
+            player_ptr, _("後でスコアを登録するために待機しますか?", "Stand by for later score registration? "), { UserCheck::NO_ESCAPE, UserCheck::NO_HISTORY })) {
         return;
     }
 
@@ -124,9 +124,9 @@ static void kingly(PlayerType *player_ptr)
 #endif
 
     if (!seppuku) {
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, _("ダンジョンの探索から引退した。", "retired exploring dungeons."));
-        exe_write_diary(player_ptr, DIARY_GAMESTART, 1, _("-------- ゲームオーバー --------", "--------   Game  Over   --------"));
-        exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, "\n\n\n\n");
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, _("ダンジョンの探索から引退した。", "retired exploring dungeons."));
+        exe_write_diary(player_ptr, DiaryKind::GAMESTART, 1, _("-------- ゲームオーバー --------", "--------   Game  Over   --------"));
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, "\n\n\n\n");
     }
 
     flush();
@@ -150,10 +150,9 @@ void close_game(PlayerType *player_ptr)
     signals_ignore_tstp();
 
     w_ptr->character_icky_depth = 1;
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
-    safe_setuid_grab(player_ptr);
-    highscore_fd = fd_open(buf, O_RDWR);
+    const auto &path = path_build(ANGBAND_DIR_APEX, "scores.raw");
+    safe_setuid_grab();
+    highscore_fd = fd_open(path, O_RDWR);
     safe_setuid_drop();
 
     if (!check_death(player_ptr)) {
@@ -165,9 +164,11 @@ void close_game(PlayerType *player_ptr)
         kingly(player_ptr);
     }
 
+    print_tomb(player_ptr);
+
     auto do_send = true;
-    if (!cheat_save || get_check(_("死んだデータをセーブしますか? ", "Save death? "))) {
-        update_playtime();
+    if (!cheat_save || input_check(_("死んだデータをセーブしますか? ", "Save death? "))) {
+        w_ptr->update_playtime();
         w_ptr->sf_play_time += w_ptr->play_time;
 
         if (!save_player(player_ptr, SaveType::CLOSE_GAME)) {
@@ -177,7 +178,6 @@ void close_game(PlayerType *player_ptr)
         do_send = false;
     }
 
-    print_tomb(player_ptr);
     flush();
     show_death_info(player_ptr);
     term_clear();
index e6571e6..efcb76d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * @file game-closer.h
index bbe5fc8..d6dbd9e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ゲームプレイのメインルーチン
  * @date 2020/05/10
  * @author Hourier
@@ -18,7 +18,6 @@
 #include "core/asking-player.h"
 #include "core/game-closer.h"
 #include "core/player-processor.h"
-#include "core/player-update-types.h"
 #include "core/score-util.h"
 #include "core/scores.h"
 #include "core/speed-table.h"
@@ -26,6 +25,7 @@
 #include "core/visuals-reseter.h"
 #include "core/window-redrawer.h"
 #include "dungeon/dungeon-processor.h"
+#include "dungeon/quest.h"
 #include "floor/cave.h"
 #include "floor/floor-changer.h"
 #include "floor/floor-events.h"
@@ -42,7 +42,6 @@
 #include "grid/grid.h"
 #include "info-reader/fixed-map-parser.h"
 #include "io/files-util.h"
-#include "io/inet.h"
 #include "io/input-key-acceptor.h"
 #include "io/input-key-processor.h"
 #include "io/read-pref-file.h"
 #include "store/store-util.h"
 #include "store/store.h"
 #include "sv-definition/sv-weapon-types.h"
+#include "system/angband-system.h"
 #include "system/angband-version.h"
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
@@ -119,24 +120,29 @@ static void send_waiting_record(PlayerType *player_ptr)
         return;
     }
 
-    char buf[1024];
-    if (!get_check_strict(player_ptr, _("待機していたスコア登録を今行ないますか?", "Do you register score now? "), CHECK_NO_HISTORY)) {
+    if (!input_check_strict(player_ptr, _("待機していたスコア登録を今行ないますか?", "Do you register score now? "), UserCheck::NO_HISTORY)) {
         quit(0);
     }
 
-    player_ptr->update |= (PU_BONUS | PU_HP | PU_MP | PU_SPELLS);
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     update_creature(player_ptr);
     player_ptr->is_dead = true;
     w_ptr->start_time = (uint32_t)time(nullptr);
     signals_ignore_tstp();
     w_ptr->character_icky_depth = 1;
-    path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
-    highscore_fd = fd_open(buf, O_RDWR);
+    const auto &path = path_build(ANGBAND_DIR_APEX, "scores.raw");
+    highscore_fd = fd_open(path, O_RDWR);
 
     /* 町名消失バグ対策(#38205)のためここで世界マップ情報を読み出す */
     parse_fixed_map(player_ptr, WILDERNESS_DEFINITION, 0, 0, w_ptr->max_wild_y, w_ptr->max_wild_x);
     bool success = send_world_score(player_ptr, true);
-    if (!success && !get_check_strict(player_ptr, _("スコア登録を諦めますか?", "Do you give up score registration? "), CHECK_NO_HISTORY)) {
+    if (!success && !input_check_strict(player_ptr, _("スコア登録を諦めますか?", "Do you give up score registration? "), UserCheck::NO_HISTORY)) {
         prt(_("引き続き待機します。", "standing by for future registration..."), 0, 0);
         (void)inkey();
     } else {
@@ -178,10 +184,11 @@ static void init_world_floor_info(PlayerType *player_ptr)
 {
     w_ptr->character_dungeon = false;
     auto *floor_ptr = player_ptr->current_floor_ptr;
+    floor_ptr->reset_dungeon_index();
     floor_ptr->dun_level = 0;
     floor_ptr->quest_number = QuestId::NONE;
     floor_ptr->inside_arena = false;
-    player_ptr->phase_out = false;
+    AngbandSystem::get_instance().set_phase_out(false);
     write_level = true;
     w_ptr->seed_flavor = randint0(0x10000000);
     w_ptr->seed_town = randint0(0x10000000);
@@ -203,16 +210,20 @@ static void init_world_floor_info(PlayerType *player_ptr)
 static void restore_world_floor_info(PlayerType *player_ptr)
 {
     write_level = false;
-    exe_write_diary(player_ptr, DIARY_GAMESTART, 1, _("                            ----ゲーム再開----", "                            --- Restarted Game ---"));
-
-    if (player_ptr->riding == -1) {
-        player_ptr->riding = 0;
-        auto *floor_ptr = player_ptr->current_floor_ptr;
-        for (MONSTER_IDX i = floor_ptr->m_max; i > 0; i--) {
-            if (player_bold(player_ptr, floor_ptr->m_list[i].fy, floor_ptr->m_list[i].fx)) {
-                player_ptr->riding = i;
-                break;
-            }
+    constexpr auto mes = _("                            ----ゲーム再開----", "                            --- Restarted Game ---");
+    exe_write_diary(player_ptr, DiaryKind::GAMESTART, 1, mes);
+
+    if (player_ptr->riding != -1) {
+        return;
+    }
+
+    player_ptr->riding = 0;
+    auto *floor_ptr = player_ptr->current_floor_ptr;
+    for (short i = floor_ptr->m_max; i > 0; i--) {
+        const auto &monster = floor_ptr->m_list[i];
+        if (player_ptr->is_located_at({ monster.fy, monster.fx })) {
+            player_ptr->riding = i;
+            break;
         }
     }
 }
@@ -232,7 +243,7 @@ static void reset_world_info(PlayerType *player_ptr)
 static void generate_wilderness(PlayerType *player_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((floor_ptr->dun_level == 0) && inside_quest(floor_ptr->quest_number)) {
+    if ((floor_ptr->dun_level == 0) && floor_ptr->is_in_quest()) {
         return;
     }
 
@@ -272,7 +283,7 @@ static void generate_world(PlayerType *player_ptr, bool new_game)
     panel_row_min = floor_ptr->height;
     panel_col_min = floor_ptr->width;
 
-    set_floor_and_wall(player_ptr->dungeon_idx);
+    set_floor_and_wall(floor_ptr->dungeon_idx);
     initialize_items_flavor();
     prt(_("お待ち下さい...", "Please wait..."), 0, 0);
     term_fresh();
@@ -284,15 +295,14 @@ static void generate_world(PlayerType *player_ptr, bool new_game)
         return;
     }
 
-    char buf[80];
-    strnfmt(buf, sizeof(buf), _("%sに降り立った。", "arrived in %s."), map_name(player_ptr));
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, buf);
+    const auto mes = format(_("%sに降り立った。", "arrived in %s."), map_name(player_ptr).data());
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, mes);
 }
 
 static void init_io(PlayerType *player_ptr)
 {
     term_xtra(TERM_XTRA_REACT, 0);
-    player_ptr->window_flags = PW_ALL;
+    RedrawingFlagsUpdater::get_instance().fill_up_sub_flags();
     handle_stuff(player_ptr);
     if (arg_force_original) {
         rogue_like_commands = false;
@@ -312,7 +322,7 @@ static void init_riding_pet(PlayerType *player_ptr, bool new_game)
 
     MonsterRaceId pet_r_idx = pc.equals(PlayerClassType::CAVALRY) ? MonsterRaceId::HORSE : MonsterRaceId::YASE_HORSE;
     auto *r_ptr = &monraces_info[pet_r_idx];
-    place_monster_aux(player_ptr, 0, player_ptr->y, player_ptr->x - 1, pet_r_idx, (PM_FORCE_PET | PM_NO_KAGE));
+    place_specific_monster(player_ptr, 0, player_ptr->y, player_ptr->x - 1, pet_r_idx, (PM_FORCE_PET | PM_NO_KAGE));
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[hack_m_idx_ii];
     m_ptr->mspeed = r_ptr->speed;
     m_ptr->maxhp = r_ptr->hdice * (r_ptr->hside + 1) / 2;
@@ -330,7 +340,7 @@ static void decide_arena_death(PlayerType *player_ptr)
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     if (!floor_ptr->inside_arena) {
-        if ((w_ptr->wizard || cheat_live) && !get_check(_("死にますか? ", "Die? "))) {
+        if ((w_ptr->wizard || cheat_live) && !input_check(_("死にますか? ", "Die? "))) {
             cheat_death(player_ptr);
         }
 
@@ -347,7 +357,7 @@ static void decide_arena_death(PlayerType *player_ptr)
     player_ptr->is_dead = false;
     player_ptr->chp = 0;
     player_ptr->chp_frac = 0;
-    player_ptr->exit_bldg = true;
+    w_ptr->set_arena(true);
     reset_tim_flags(player_ptr);
     prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_RAND_CONNECT);
     leave_floor(player_ptr);
index 738ff87..377442b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void play_game(PlayerType *player_ptr, bool new_game, bool browsing_movie);
index 501c4ef..1b57208 100644 (file)
@@ -1,4 +1,4 @@
-#include "core/magic-effects-timeout-reducer.h"
+#include "core/magic-effects-timeout-reducer.h"
 #include "game-option/birth-options.h"
 #include "mind/mind-force-trainer.h"
 #include "mind/mind-magic-resistance.h"
index 2ab31b6..bce2309 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void reduce_magic_effects_timeout(PlayerType *player_ptr);
index 1479602..c0e70df 100644 (file)
@@ -1,5 +1,4 @@
-#include "core/object-compressor.h"
-#include "core/player-redraw-types.h"
+#include "core/object-compressor.h"
 #include "core/window-redrawer.h"
 #include "floor/floor-object.h"
 #include "floor/geometry.h"
@@ -9,6 +8,7 @@
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 #include <algorithm>
 
@@ -56,8 +56,13 @@ void compact_objects(PlayerType *player_ptr, int size)
     ItemEntity *o_ptr;
     if (size) {
         msg_print(_("アイテム情報を圧縮しています...", "Compacting objects..."));
-        player_ptr->redraw |= PR_MAP;
-        player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::MAP);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::OVERHEAD,
+            SubWindowRedrawingFlag::DUNGEON,
+        };
+        rfu.set_flags(flags_swrf);
     }
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
index cd9e6fb..36b6cd7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void compact_objects(PlayerType *player_ptr, int size);
index 1e95fd8..933cd85 100644 (file)
@@ -1,9 +1,7 @@
-#include "core/player-processor.h"
+#include "core/player-processor.h"
 #include "action/run-execution.h"
 #include "action/travel-execution.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/special-internal-keys.h"
 #include "core/speed-table.h"
 #include "core/stuff-handler.h"
 #include "spell-realm/spells-hex.h"
 #include "spell-realm/spells-song.h"
 #include "status/action-setter.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/player-confusion.h"
@@ -80,13 +80,13 @@ static void process_fishing(PlayerType *player_ptr)
         auto *floor_ptr = player_ptr->current_floor_ptr;
         const auto wild_level = wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].level;
         const auto level = floor_ptr->is_in_dungeon() ? floor_ptr->dun_level : wild_level;
-        const auto r_idx = get_mon_num(player_ptr, 0, level, 0);
+        const auto r_idx = get_mon_num(player_ptr, 0, level, PM_NONE);
         msg_print(nullptr);
         if (MonsterRace(r_idx).is_valid() && one_in_(2)) {
             POSITION y, x;
             y = player_ptr->y + ddy[player_ptr->fishing_dir];
             x = player_ptr->x + ddx[player_ptr->fishing_dir];
-            if (place_monster_aux(player_ptr, 0, y, x, r_idx, PM_NO_KAGE)) {
+            if (place_specific_monster(player_ptr, 0, y, x, r_idx, PM_NO_KAGE)) {
                 const auto m_name = monster_desc(player_ptr, &floor_ptr->m_list[floor_ptr->grid_array[y][x].m_idx], 0);
                 msg_print(_(format("%sが釣れた!", m_name.data()), "You have a good catch!"));
                 success = true;
@@ -127,7 +127,8 @@ void process_player(PlayerType *player_ptr)
         player_ptr->invoking_midnight_curse = false;
     }
 
-    if (player_ptr->phase_out) {
+    const auto &system = AngbandSystem::get_instance();
+    if (system.is_phase_out()) {
         for (MONSTER_IDX m_idx = 1; m_idx < player_ptr->current_floor_ptr->m_max; m_idx++) {
             auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
             if (!m_ptr->is_valid()) {
@@ -184,7 +185,7 @@ void process_player(PlayerType *player_ptr)
     const auto effects = player_ptr->effects();
     if (player_ptr->riding && !effects->confusion()->is_confused() && !effects->blindness()->is_blind()) {
         auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
         if (m_ptr->is_asleep()) {
             const auto m_name = monster_desc(player_ptr, m_ptr, 0);
             (void)set_monster_csleep(player_ptr, player_ptr->riding, 0);
@@ -223,13 +224,14 @@ void process_player(PlayerType *player_ptr)
         set_lightspeed(player_ptr, player_ptr->lightspeed - 1, true);
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (PlayerClass(player_ptr).equals(PlayerClassType::FORCETRAINER) && get_current_ki(player_ptr)) {
         if (get_current_ki(player_ptr) < 40) {
             set_current_ki(player_ptr, true, 0);
         } else {
             set_current_ki(player_ptr, false, -40);
         }
-        player_ptr->update |= (PU_BONUS);
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
     }
 
     if (player_ptr->action == ACTION_LEARN) {
@@ -244,7 +246,7 @@ void process_player(PlayerType *player_ptr)
             s64b_sub(&(player_ptr->csp), &(player_ptr->csp_frac), cost, cost_frac);
         }
 
-        player_ptr->redraw |= PR_MP;
+        rfu.set_flag(MainWindowRedrawingFlag::MP);
     }
 
     if (PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU)) {
@@ -252,13 +254,13 @@ void process_player(PlayerType *player_ptr)
             set_action(player_ptr, ACTION_NONE);
         } else {
             player_ptr->csp -= 2;
-            player_ptr->redraw |= (PR_MP);
+            rfu.set_flag(MainWindowRedrawingFlag::MP);
         }
     }
 
     /*** Handle actual user input ***/
     while (player_ptr->energy_need <= 0) {
-        player_ptr->window_flags |= PW_PLAYER;
+        rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
         player_ptr->sutemi = false;
         player_ptr->counter = false;
         player_ptr->now_damaged = false;
@@ -279,7 +281,7 @@ void process_player(PlayerType *player_ptr)
         energy.reset_player_turn();
         auto is_knocked_out = effects->stun()->is_knocked_out();
         auto is_paralyzed = effects->paralysis()->is_paralyzed();
-        if (player_ptr->phase_out) {
+        if (system.is_phase_out()) {
             move_cursor_relative(player_ptr->y, player_ptr->x);
             command_cmd = SPECIAL_KEY_BUILDING;
             process_command(player_ptr);
@@ -291,7 +293,8 @@ void process_player(PlayerType *player_ptr)
                 if (!player_ptr->resting) {
                     set_action(player_ptr, ACTION_NONE);
                 }
-                player_ptr->redraw |= (PR_ACTION);
+
+                rfu.set_flag(MainWindowRedrawingFlag::ACTION);
             }
 
             energy.set_player_turn_energy(100);
@@ -303,7 +306,7 @@ void process_player(PlayerType *player_ptr)
             travel_step(player_ptr);
         } else if (command_rep) {
             command_rep--;
-            player_ptr->redraw |= (PR_ACTION);
+            rfu.set_flag(MainWindowRedrawingFlag::ACTION);
             handle_stuff(player_ptr);
             msg_flag = false;
             prt("", 0, 0);
@@ -311,7 +314,11 @@ void process_player(PlayerType *player_ptr)
         } else {
             move_cursor_relative(player_ptr->y, player_ptr->x);
 
-            player_ptr->window_flags |= PW_SIGHT_MONSTERS;
+            static constexpr auto flags = {
+                SubWindowRedrawingFlag::SIGHT_MONSTERS,
+                SubWindowRedrawingFlag::PETS,
+            };
+            rfu.set_flags(flags);
             window_stuff(player_ptr);
 
             can_save = true;
@@ -329,7 +336,7 @@ void process_player(PlayerType *player_ptr)
             }
 
             if (effects->hallucination()->is_hallucinated()) {
-                player_ptr->redraw |= (PR_MAP);
+                rfu.set_flag(MainWindowRedrawingFlag::MAP);
             }
 
             for (MONSTER_IDX m_idx = 1; m_idx < player_ptr->current_floor_ptr->m_max; m_idx++) {
@@ -340,7 +347,7 @@ void process_player(PlayerType *player_ptr)
                     continue;
                 }
 
-                r_ptr = &monraces_info[m_ptr->ap_r_idx];
+                r_ptr = &m_ptr->get_appearance_monrace();
 
                 // モンスターのシンボル/カラーの更新
                 if (m_ptr->ml && r_ptr->visual_flags.has_any_of({ MonsterVisualType::MULTI_COLOR, MonsterVisualType::SHAPECHANGER })) {
@@ -367,10 +374,11 @@ void process_player(PlayerType *player_ptr)
                         m_ptr->ml = false;
                         update_monster(player_ptr, m_idx, false);
                         if (player_ptr->health_who == m_idx) {
-                            player_ptr->redraw |= (PR_HEALTH);
+                            rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
                         }
+
                         if (player_ptr->riding == m_idx) {
-                            player_ptr->redraw |= (PR_UHEALTH);
+                            rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
                         }
 
                         lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
@@ -386,20 +394,23 @@ void process_player(PlayerType *player_ptr)
                 }
 
                 mane_data->new_mane = false;
-                player_ptr->redraw |= (PR_IMITATION);
+                rfu.set_flag(MainWindowRedrawingFlag::IMITATION);
             }
 
             if (player_ptr->action == ACTION_LEARN) {
                 auto mane_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
                 mane_data->new_magic_learned = false;
-                player_ptr->redraw |= (PR_ACTION);
+                rfu.set_flag(MainWindowRedrawingFlag::ACTION);
             }
 
             if (player_ptr->timewalk && (player_ptr->energy_need > -1000)) {
-                player_ptr->redraw |= (PR_MAP);
-                player_ptr->update |= (PU_MONSTER_STATUSES);
-                player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
-
+                rfu.set_flag(MainWindowRedrawingFlag::MAP);
+                rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+                static constexpr auto flags_swrf = {
+                    SubWindowRedrawingFlag::OVERHEAD,
+                    SubWindowRedrawingFlag::DUNGEON,
+                };
+                rfu.set_flags(flags_swrf);
                 msg_print(_("「時は動きだす…」", "You feel time flowing around you once more."));
                 msg_print(nullptr);
                 player_ptr->timewalk = false;
@@ -414,7 +425,7 @@ void process_player(PlayerType *player_ptr)
             break;
         }
 
-        auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+        auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
         if (player_ptr->energy_use && sniper_data && sniper_data->reset_concent) {
             reset_concentration(player_ptr, true);
         }
index e6c209d..55a37c1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 extern bool load; /*!<ロード処理中の分岐フラグ*/
 extern bool can_save;
diff --git a/src/core/player-redraw-types.h b/src/core/player-redraw-types.h
deleted file mode 100644 (file)
index 6f8a16c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-// clang-format off
-enum player_redraw_type {
-    PR_MISC          = 0x00000001L, /*!< 再描画フラグ: 種族と職業 / Display Race/Class */
-    PR_TITLE         = 0x00000002L, /*!< 再描画フラグ: 称号 / Display Title */
-    PR_LEVEL         = 0x00000004L, /*!< 再描画フラグ: レベル / Display Level */
-    PR_EXP           = 0x00000008L, /*!< 再描画フラグ: 経験値 / Display Experience */
-    PR_ABILITY_SCORE = 0x00000010L, /*!< 再描画フラグ: ステータス /  Display Stats */
-    PR_AC            = 0x00000020L, /*!< 再描画フラグ: AC / Display Armor */
-    PR_HP            = 0x00000040L, /*!< 再描画フラグ: HP / Display Hitpoints */
-    PR_MP            = 0x00000080L, /*!< 再描画フラグ: MP / Display Mana */
-    PR_GOLD          = 0x00000100L, /*!< 再描画フラグ: 所持金 / Display Gold */
-    PR_DEPTH         = 0x00000200L, /*!< 再描画フラグ: ダンジョンの階 / Display Depth */
-    PR_EQUIPPY       = 0x00000400L, /*!< 再描画フラグ: 装備シンボル / Display equippy chars */
-    PR_HEALTH        = 0x00000800L, /*!< 再描画フラグ: モンスターのステータス / Display Health Bar */
-    PR_CUT           = 0x00001000L, /*!< 再描画フラグ: 負傷度 / Display Extra (Cut) */
-    PR_STUN          = 0x00002000L, /*!< 再描画フラグ: 朦朧度 / Display Extra (Stun) */
-    PR_HUNGER        = 0x00004000L, /*!< 再描画フラグ: 空腹度 / Display Extra (Hunger) */
-    PR_TIMED_EFFECT  = 0x00008000L, /*!< 再描画フラグ: プレイヤーの付与状態 /  Display Status Bar */
-    PR_XXX0          = 0x00010000L, /*!< (unused) */
-    PR_UHEALTH       = 0x00020000L, /*!< 再描画フラグ: ペットのステータス / Display Uma Health Bar */
-    PR_XXX1          = 0x00040000L, /*!< (unused) */
-    PR_XXX2          = 0x00080000L, /*!< (unused) */
-    PR_ACTION        = 0x00100000L, /*!< 再描画フラグ: プレイヤーの行動状態 / Display Extra (State) */
-    PR_SPEED         = 0x00200000L, /*!< 再描画フラグ: 加速 / Display Extra (Speed) */
-    PR_STUDY         = 0x00400000L, /*!< 再描画フラグ: 学習 / Display Extra (Study) */
-    PR_IMITATION     = 0x00800000L, /*!< 再描画フラグ: ものまね / Display Extra (Imitation) */
-    PR_EXTRA         = 0x01000000L, /*!< 再描画フラグ: 拡張ステータス全体 / Display Extra Info */
-    PR_BASIC         = 0x02000000L, /*!< 再描画フラグ: 基本ステータス全体 / Display Basic Info */
-    PR_MAP           = 0x04000000L, /*!< 再描画フラグ: ゲームマップ / Display Map */
-    PR_WIPE          = 0x08000000L, /*!< 再描画フラグ: 画面消去 / Hack -- Total Redraw */
-};
-
-// clang-format on
diff --git a/src/core/player-update-types.h b/src/core/player-update-types.h
deleted file mode 100644 (file)
index 979bec0..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-
-// clang-format off
-enum player_update_type {
-    PU_BONUS            = 0x00000001L, /*!< ステータス更新フラグ: 能力値修正 / Calculate bonuses */
-    PU_TORCH            = 0x00000002L, /*!< ステータス更新フラグ: 光源半径 / Calculate torch radius */
-    PU_HP               = 0x00000010L, /*!< ステータス更新フラグ: HP / Calculate chp and mhp */
-    PU_MP               = 0x00000020L, /*!< ステータス更新フラグ: MP / Calculate csp and msp */
-    PU_SPELLS           = 0x00000040L, /*!< ステータス更新フラグ: 魔法学習数 / Calculate spells */
-    PU_COMBINATION      = 0x00000100L, /*!< アイテム処理フラグ: アイテムの結合を要する / Combine the pack */
-    PU_REORDER          = 0x00000200L, /*!< アイテム処理フラグ: アイテムの並び替えを要する / Reorder the pack */
-    PU_AUTO_DESTRUCTION = 0x00000400L, /*!< アイテム処理フラグ: アイテムの自動破壊を要する / Auto-destroy marked item */
-    PU_UN_VIEW          = 0x00010000L, /*!< ステータス更新フラグ: 地形の視界外化 / Forget view */
-    PU_UN_LITE          = 0x00020000L, /*!< ステータス更新フラグ: 明暗範囲の視界外化 / Forget lite */
-    PU_VIEW             = 0x00100000L, /*!< ステータス更新フラグ: 視界 / Update view */
-    PU_LITE             = 0x00200000L, /*!< ステータス更新フラグ: 明暗範囲 / Update lite */
-    PU_MONSTER_LITE     = 0x00400000L, /*!< ステータス更新フラグ: モンスターの光源範囲 / Monster illumination */
-    PU_DELAY_VISIBILITY = 0x00800000L, /*!< ステータス更新フラグ: 視界の追加更新 / Mega-Hack -- Delayed visual update */
-    PU_MONSTER_STATUSES = 0x01000000L, /*!< ステータス更新フラグ: モンスターのステータス / Update monsters */
-    PU_DISTANCE         = 0x02000000L, /*!< ステータス更新フラグ: プレイヤーとモンスターの距離 / Update distances */
-    PU_FLOW             = 0x10000000L, /*!< ステータス更新フラグ: プレイヤーから各マスへの到達距離 / Update flow */
-};
-
-// clang-format on
index b20b046..83c1ff2 100644 (file)
@@ -1,5 +1,13 @@
-#include "core/score-util.h"
+#include "core/score-util.h"
+#include "system/dungeon-info.h"
+#include "system/floor-type-definition.h"
+#include "system/player-type-definition.h"
 #include "util/angband-files.h"
+#include "util/string-processor.h"
+#include <algorithm>
+#ifdef SET_UID
+#include "main-unix/unix-user-ids.h"
+#endif
 
 /*
  * The "highscore" file descriptor, if available.
@@ -25,3 +33,33 @@ errr highscore_read(high_score *score)
 {
     return fd_read(highscore_fd, (char *)(score), sizeof(high_score));
 }
+
+void high_score::copy_info(const PlayerType &player)
+{
+    const auto name = format("%-.15s", player.name);
+    std::copy_n(name.begin(), name.length(), this->who);
+
+#ifdef SET_UID
+    const auto tmp_uid = UnixUserIds::get_instance().get_user_id();
+#else
+    const auto tmp_uid = 0;
+#endif
+    const auto uid_str = format("%7u", tmp_uid);
+    std::copy_n(uid_str.begin(), uid_str.length(), this->uid);
+    this->sex[0] = player.psex ? 'm' : 'f';
+    const auto prace = format("%2d", std::min(enum2i(player.prace), MAX_RACES));
+    std::copy_n(prace.begin(), prace.length(), this->p_r);
+    const auto pclass = format("%2d", enum2i(std::min(player.pclass, PlayerClassType::MAX)));
+    std::copy_n(pclass.begin(), pclass.length(), this->p_c);
+    const auto ppersonality = format("%2d", std::min(player.ppersonality, MAX_PERSONALITIES));
+    std::copy_n(ppersonality.begin(), ppersonality.length(), this->p_a);
+    const auto current_level = format("%3d", std::min<ushort>(player.lev, 999));
+    std::copy_n(current_level.begin(), current_level.length(), this->cur_lev);
+    const auto &floor = *player.current_floor_ptr;
+    const auto current_dungeon = format("%3d", floor.dun_level);
+    std::copy_n(current_dungeon.begin(), current_dungeon.length(), this->cur_dun);
+    const auto max_level = format("%3d", std::min<ushort>(player.max_plv, 999));
+    std::copy_n(max_level.begin(), max_level.length(), this->max_lev);
+    const auto max_dungeon = format("%3d", max_dlv[floor.dungeon_idx]);
+    std::copy_n(max_dungeon.begin(), max_dungeon.length(), this->max_dun);
+}
index edf1273..cd76f12 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
  *
  * Note that "string comparisons" are thus valid on "pts".
  */
+class PlayerType;
 struct high_score {
-    GAME_TEXT what[8]; /* Version info (string) */
-    GAME_TEXT pts[10]; /* Total Score (number) */
-    GAME_TEXT gold[10]; /* Total Gold (number) */
-    GAME_TEXT turns[10]; /* Turns Taken (number) */
-    GAME_TEXT day[10]; /* Time stamp (string) */
-    GAME_TEXT who[16]; /* Player Name (string) */
-    GAME_TEXT uid[8]; /* Player UID (number) */
-    GAME_TEXT sex[2]; /* Player Sex (string) */
-    GAME_TEXT p_r[3]; /* Player Race (number) */
-    GAME_TEXT p_c[3]; /* Player Class (number) */
-    GAME_TEXT p_a[3]; /* Player Seikaku (number) */
-
-    GAME_TEXT cur_lev[4]; /* Current Player Level (number) */
-    GAME_TEXT cur_dun[4]; /* Current Dungeon Level (number) */
-    GAME_TEXT max_lev[4]; /* Max Player Level (number) */
-    GAME_TEXT max_dun[4]; /* Max Dungeon Level (number) */
-
-    GAME_TEXT how[40]; /* Method of death (string) */
+    GAME_TEXT what[8]{}; /* Version info (string) */
+    GAME_TEXT pts[10]{}; /* Total Score (number) */
+    GAME_TEXT gold[10]{}; /* Total Gold (number) */
+    GAME_TEXT turns[10]{}; /* Turns Taken (number) */
+    GAME_TEXT day[10]{}; /* Time stamp (string) */
+    GAME_TEXT who[16]{}; /* Player Name (string) */
+    GAME_TEXT uid[8]{}; /* Player UID (number) */
+    GAME_TEXT sex[2]{}; /* Player Sex (string) */
+    GAME_TEXT p_r[3]{}; /* Player Race (number) */
+    GAME_TEXT p_c[3]{}; /* Player Class (number) */
+    GAME_TEXT p_a[3]{}; /* Player Seikaku (number) */
+
+    GAME_TEXT cur_lev[4]{}; /* Current Player Level (number) */
+    GAME_TEXT cur_dun[4]{}; /* Current Dungeon Level (number) */
+    GAME_TEXT max_lev[4]{}; /* Max Player Level (number) */
+    GAME_TEXT max_dun[4]{}; /* Max Dungeon Level (number) */
+
+    GAME_TEXT how[40]{}; /* Method of death (string) */
+
+    void copy_info(const PlayerType &player);
 };
 
 extern int highscore_fd;
index 73ca982..8309fef 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file scores.c
  * @brief ハイスコア処理 / Highscores handling
  * @date 2014/07/14
@@ -29,8 +29,6 @@
 #include "player/player-status.h"
 #include "player/race-info-table.h"
 #include "system/angband-version.h"
-#include "system/dungeon-info.h"
-#include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
@@ -152,8 +150,8 @@ bool send_world_score(PlayerType *player_ptr, bool do_send)
         return true;
     }
 
-    auto is_registration = get_check_strict(
-        player_ptr, _("スコアをスコア・サーバに登録しますか? ", "Do you send score to the world score server? "), (CHECK_NO_ESCAPE | CHECK_NO_HISTORY));
+    auto is_registration = input_check_strict(
+        player_ptr, _("スコアをスコア・サーバに登録しますか? ", "Do you send score to the world score server? "), { UserCheck::NO_ESCAPE, UserCheck::NO_HISTORY });
     if (!is_registration) {
         return true;
     }
@@ -189,96 +187,52 @@ bool send_world_score(PlayerType *player_ptr, bool do_send)
 errr top_twenty(PlayerType *player_ptr)
 {
     high_score the_score = {};
-    char buf[32];
-
-    /* Save the version */
     snprintf(the_score.what, sizeof(the_score.what), "%u.%u.%u", H_VER_MAJOR, H_VER_MINOR, H_VER_PATCH);
-
-    /* Calculate and save the points */
     snprintf(the_score.pts, sizeof(the_score.pts), "%9ld", (long)calc_score(player_ptr));
     the_score.pts[9] = '\0';
 
-    /* Save the current gold */
     snprintf(the_score.gold, sizeof(the_score.gold), "%9lu", (long)player_ptr->au);
     the_score.gold[9] = '\0';
 
-    /* Save the current turn */
     snprintf(the_score.turns, sizeof(the_score.turns), "%9lu", (long)turn_real(player_ptr, w_ptr->game_turn));
     the_score.turns[9] = '\0';
 
-    time_t ct = time((time_t *)0);
+    auto ct = time((time_t *)0);
 
-    /* Save the date in standard encoded form (9 chars) */
     strftime(the_score.day, 10, "@%Y%m%d", localtime(&ct));
-
-    /* Save the player name (15 chars) */
-    snprintf(the_score.who, sizeof(the_score.who), "%-.15s", player_ptr->name);
-
-    /* Save the player info */
-    snprintf(the_score.uid, sizeof(the_score.uid), "%7u", player_ptr->player_uid);
-    snprintf(the_score.sex, sizeof(the_score.sex), "%c", (player_ptr->psex ? 'm' : 'f'));
-    snprintf(buf, sizeof(buf), "%2d", std::min(enum2i(player_ptr->prace), MAX_RACES));
-    memcpy(the_score.p_r, buf, 3);
-    snprintf(buf, sizeof(buf), "%2d", enum2i(std::min(player_ptr->pclass, PlayerClassType::MAX)));
-    memcpy(the_score.p_c, buf, 3);
-    snprintf(buf, sizeof(buf), "%2d", std::min(player_ptr->ppersonality, MAX_PERSONALITIES));
-    memcpy(the_score.p_a, buf, 3);
-
-    /* Save the level and such */
-    snprintf(the_score.cur_lev, sizeof(the_score.cur_lev), "%3d", std::min<ushort>(player_ptr->lev, 999));
-    snprintf(the_score.cur_dun, sizeof(the_score.cur_dun), "%3d", (int)player_ptr->current_floor_ptr->dun_level);
-    snprintf(the_score.max_lev, sizeof(the_score.max_lev), "%3d", std::min<ushort>(player_ptr->max_plv, 999));
-    snprintf(the_score.max_dun, sizeof(the_score.max_dun), "%3d", (int)max_dlv[player_ptr->dungeon_idx]);
-
-    /* Save the cause of death (31 chars) */
+    the_score.copy_info(*player_ptr);
     if (player_ptr->died_from.size() >= sizeof(the_score.how)) {
 #ifdef JP
-        angband_strcpy(the_score.how, player_ptr->died_from.data(), sizeof(the_score.how) - 2);
+        angband_strcpy(the_score.how, player_ptr->died_from, sizeof(the_score.how) - 2);
         angband_strcat(the_score.how, "…", sizeof(the_score.how));
 #else
-        angband_strcpy(the_score.how, player_ptr->died_from.data(), sizeof(the_score.how) - 3);
+        angband_strcpy(the_score.how, player_ptr->died_from, sizeof(the_score.how) - 3);
         angband_strcat(the_score.how, "...", sizeof(the_score.how));
 #endif
     } else {
-        angband_strcpy(the_score.how, player_ptr->died_from.data(), sizeof(the_score.how));
+        angband_strcpy(the_score.how, player_ptr->died_from, sizeof(the_score.how));
     }
 
-    /* Grab permissions */
-    safe_setuid_grab(player_ptr);
-
-    /* Lock (for writing) the highscore file, or fail */
-    errr err = fd_lock(highscore_fd, F_WRLCK);
-
-    /* Drop permissions */
+    safe_setuid_grab();
+    auto err = fd_lock(highscore_fd, F_WRLCK);
     safe_setuid_drop();
-
     if (err) {
         return 1;
     }
 
-    /* Add a new entry to the score list, see where it went */
-    int j = highscore_add(&the_score);
-
-    /* Grab permissions */
-    safe_setuid_grab(player_ptr);
-
-    /* Unlock the highscore file, or fail */
+    auto j = highscore_add(&the_score);
+    safe_setuid_grab();
     err = fd_lock(highscore_fd, F_UNLCK);
-
-    /* Drop permissions */
     safe_setuid_drop();
-
     if (err) {
         return 1;
     }
 
-    /* Hack -- Display the top fifteen scores */
     if (j < 10) {
         display_scores(0, 15, j, nullptr);
         return 0;
     }
 
-    /* Display the scores surrounding the player */
     display_scores(0, 5, j, nullptr);
     display_scores(j - 2, j + 7, j, nullptr);
     return 0;
@@ -292,56 +246,20 @@ errr top_twenty(PlayerType *player_ptr)
 errr predict_score(PlayerType *player_ptr)
 {
     high_score the_score;
-    char buf[32];
-
-    /* No score file */
     if (highscore_fd < 0) {
         msg_print(_("スコア・ファイルが使用できません。", "Score file unavailable."));
         msg_print(nullptr);
         return 0;
     }
 
-    /* Save the version */
     snprintf(the_score.what, sizeof(the_score.what), "%u.%u.%u", H_VER_MAJOR, H_VER_MINOR, H_VER_PATCH);
-
-    /* Calculate and save the points */
     snprintf(the_score.pts, sizeof(the_score.pts), "%9ld", (long)calc_score(player_ptr));
-
-    /* Save the current gold */
     snprintf(the_score.gold, sizeof(the_score.gold), "%9lu", (long)player_ptr->au);
-
-    /* Save the current turn */
     snprintf(the_score.turns, sizeof(the_score.turns), "%9lu", (long)turn_real(player_ptr, w_ptr->game_turn));
-
-    /* Hack -- no time needed */
     angband_strcpy(the_score.day, _("今日", "TODAY"), sizeof(the_score.day));
-
-    /* Save the player name (15 chars) */
-    snprintf(the_score.who, sizeof(the_score.who), "%-.15s", player_ptr->name);
-
-    /* Save the player info */
-    snprintf(the_score.uid, sizeof(the_score.uid), "%7u", player_ptr->player_uid);
-    snprintf(the_score.sex, sizeof(the_score.sex), "%c", (player_ptr->psex ? 'm' : 'f'));
-    snprintf(buf, sizeof(buf), "%2d", std::min(enum2i(player_ptr->prace), MAX_RACES));
-    memcpy(the_score.p_r, buf, 3);
-    snprintf(buf, sizeof(buf), "%2d", enum2i(std::min(player_ptr->pclass, PlayerClassType::MAX)));
-    memcpy(the_score.p_c, buf, 3);
-    snprintf(buf, sizeof(buf), "%2d", std::min(player_ptr->ppersonality, MAX_PERSONALITIES));
-    memcpy(the_score.p_a, buf, 3);
-
-    /* Save the level and such */
-    snprintf(the_score.cur_lev, sizeof(the_score.cur_lev), "%3d", std::min<ushort>(player_ptr->lev, 999));
-    snprintf(the_score.cur_dun, sizeof(the_score.cur_dun), "%3d", (int)player_ptr->current_floor_ptr->dun_level);
-    snprintf(the_score.max_lev, sizeof(the_score.max_lev), "%3d", std::min<ushort>(player_ptr->max_plv, 999));
-    snprintf(the_score.max_dun, sizeof(the_score.max_dun), "%3d", (int)max_dlv[player_ptr->dungeon_idx]);
-
-    /* まだ死んでいないときの識別文字 */
+    the_score.copy_info(*player_ptr);
     strcpy(the_score.how, _("yet", "nobody (yet!)"));
-
-    /* See where the entry would be placed */
-    int j = highscore_where(&the_score);
-
-    /* Hack -- Display the top fifteen scores */
+    auto j = highscore_where(&the_score);
     if (j < 10) {
         display_scores(0, 15, j, &the_score);
         return 0;
@@ -359,9 +277,8 @@ errr predict_score(PlayerType *player_ptr)
 void show_highclass(PlayerType *player_ptr)
 {
     screen_save();
-    char buf[1024], out_val[256];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
-    highscore_fd = fd_open(buf, O_RDONLY);
+    const auto &path = path_build(ANGBAND_DIR_APEX, "scores.raw");
+    highscore_fd = fd_open(path, O_RDONLY);
     if (highscore_fd < 0) {
         msg_print(_("スコア・ファイルが使用できません。", "Score file unavailable."));
         msg_print(nullptr);
@@ -383,6 +300,7 @@ void show_highclass(PlayerType *player_ptr)
     int j = 0;
     PLAYER_LEVEL clev = 0;
     int pr;
+    char out_val[256];
     while ((m < 9) && (j < MAX_HISCORES)) {
         if (highscore_seek(j)) {
             break;
@@ -432,16 +350,14 @@ void show_highclass(PlayerType *player_ptr)
 void race_score(PlayerType *player_ptr, int race_num)
 {
     int i = 0, j, m = 0;
-    int pr, clev, lastlev;
+    int pr, clev;
     high_score the_score;
-    char buf[1024], out_val[256];
-
-    lastlev = 0;
+    auto lastlev = 0;
 
     /* rr9: TODO - pluralize the race */
     prt(std::string(_("最高の", "The Greatest of all the ")).append(race_info[race_num].title), 5, 15);
-    path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
-    highscore_fd = fd_open(buf, O_RDONLY);
+    const auto &path = path_build(ANGBAND_DIR_APEX, "scores.raw");
+    highscore_fd = fd_open(path, O_RDONLY);
     if (highscore_fd < 0) {
         msg_print(_("スコア・ファイルが使用できません。", "Score file unavailable."));
         msg_print(nullptr);
@@ -472,6 +388,7 @@ void race_score(PlayerType *player_ptr, int race_num)
         clev = atoi(the_score.cur_lev);
 
         if (pr == race_num) {
+            char out_val[256];
 #ifdef JP
             snprintf(out_val, sizeof(out_val), "   %3d) %sの%s (レベル %2d)", (m + 1), race_info[pr].title, the_score.who, clev);
 #else
@@ -487,6 +404,7 @@ void race_score(PlayerType *player_ptr, int race_num)
 
     /* add player if qualified */
     if ((enum2i(player_ptr->prace) == race_num) && (player_ptr->lev >= lastlev)) {
+        char out_val[256];
 #ifdef JP
         snprintf(out_val, sizeof(out_val), "あなた) %sの%s (レベル %2d)", race_info[enum2i(player_ptr->prace)].title, player_ptr->name, player_ptr->lev);
 #else
index ab93764..892d429 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f8e2ae0..f336d59 100644 (file)
@@ -1,8 +1,9 @@
-#include "core/show-file.h"
+#include "core/show-file.h"
 #include "core/asking-player.h"
 #include "io/files-util.h"
 #include "io/input-key-acceptor.h"
 #include "main/sound-of-music.h"
+#include "system/angband-exceptions.h"
 #include "system/angband-version.h"
 #include "system/player-type-definition.h"
 #include "term/gameterm.h"
@@ -13,6 +14,9 @@
 #include "util/int-char-converter.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
+#include <sstream>
+#include <string>
+#include <string_view>
 
 /*!
  * @brief ファイル内容の一行をコンソールに出力する
  * </pre>
  * @todo 表示とそれ以外を分割する
  */
-static void show_file_aux_line(concptr str, int cy, concptr shower)
+static void show_file_aux_line(std::string_view str, int cy, std::string_view shower)
 {
     char lcstr[1024];
     concptr ptr;
     byte textcolor = TERM_WHITE;
     byte focuscolor = TERM_YELLOW;
 
-    if (shower) {
-        strcpy(lcstr, str);
+    if (!shower.empty()) {
+        strcpy(lcstr, str.data());
         str_tolower(lcstr);
 
         ptr = angband_strstr(lcstr, shower);
@@ -51,12 +55,12 @@ static void show_file_aux_line(concptr str, int cy, concptr shower)
     static const char tag_str[] = "[[[[";
     byte color = textcolor;
     char in_tag = '\0';
-    for (int i = 0; str[i];) {
+    for (size_t i = 0; i < str.length();) {
         int len = strlen(&str[i]);
         int showercol = len + 1;
         int bracketcol = len + 1;
         int endcol = len;
-        if (shower) {
+        if (!shower.empty()) {
             ptr = angband_strstr(&lcstr[i], shower);
             if (ptr) {
                 showercol = ptr - &lcstr[i];
@@ -78,8 +82,8 @@ static void show_file_aux_line(concptr str, int cy, concptr shower)
         cx += endcol;
         i += endcol;
 
-        if (shower && endcol == showercol) {
-            int showerlen = strlen(shower);
+        if (!shower.empty() && (endcol == showercol)) {
+            const auto showerlen = shower.length();
             term_addstr(showerlen, focuscolor, &str[i]);
             cx += showerlen;
             i += showerlen;
@@ -111,7 +115,7 @@ static void show_file_aux_line(concptr str, int cy, concptr shower)
         i++;
     }
 
-    term_erase(cx, cy, 255);
+    term_erase(cx, cy);
 }
 
 /*!
@@ -131,82 +135,62 @@ static void show_file_aux_line(concptr str, int cy, concptr shower)
  * </pre>
  * @todo 表示とそれ以外を分割する
  */
-bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr what, int line, BIT_FLAGS mode)
+bool show_file(PlayerType *player_ptr, bool show_version, std::string_view name_with_tag, int initial_line, uint32_t mode, std::string_view what)
 {
     TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, std::nullopt);
 
-    int wid, hgt;
-    term_get_size(&wid, &hgt);
-
-    char finder_str[81] = "";
-
-    char shower_str[81] = "";
-
-    std::string caption;
-
-    char hook[68][32];
-    for (int i = 0; i < 68; i++) {
-        hook[i][0] = '\0';
-    }
-
-    std::string stripped_name;
-    concptr tag = angband_strstr(name, "#");
-    if (tag) {
-        stripped_name.append(name, tag - name);
-        name = stripped_name.data();
-        ++tag;
-    }
+    const auto &[wid, hgt] = term_get_size();
 
+    char hook[68][32]{};
+    auto stripped_names = str_split(name_with_tag, '#');
+    auto &name = stripped_names[0];
+    auto tag = stripped_names.size() > 1 ? stripped_names[1] : "";
+    std::filesystem::path path_reopen("");
     FILE *fff = nullptr;
-    char path[1024];
-    if (what) {
-        caption = what;
-        angband_strcpy(path, name, sizeof(path));
-        fff = angband_fopen(path, FileOpenMode::READ);
+    std::stringstream caption;
+    if (!what.empty()) {
+        caption << what;
+        path_reopen = name;
+        fff = angband_fopen(path_reopen, FileOpenMode::READ);
     }
 
     if (!fff) {
-        caption = _("ヘルプ・ファイル'", "Help file '");
-        caption.append(name).append("'");
-        path_build(path, sizeof(path), ANGBAND_DIR_HELP, name);
-        fff = angband_fopen(path, FileOpenMode::READ);
+        caption.clear();
+        caption << _("ヘルプ・ファイル'", "Help file '");
+        caption << name << "'";
+        path_reopen = path_build(ANGBAND_DIR_HELP, name);
+        fff = angband_fopen(path_reopen, FileOpenMode::READ);
     }
 
     if (!fff) {
-        caption = _("スポイラー・ファイル'", "Info file '");
-        caption.append(name).append("'");
-        path_build(path, sizeof(path), ANGBAND_DIR_INFO, name);
-        fff = angband_fopen(path, FileOpenMode::READ);
+        caption.clear();
+        caption << _("スポイラー・ファイル'", "Info file '");
+        caption << name << "'";
+        path_reopen = path_build(ANGBAND_DIR_INFO, name);
+        fff = angband_fopen(path_reopen, FileOpenMode::READ);
     }
 
     if (!fff) {
-        path_build(path, sizeof(path), ANGBAND_DIR, name);
-
-        for (int i = 0; path[i]; i++) {
-            if ('\\' == path[i]) {
-                path[i] = PATH_SEP[0];
-            }
-        }
-
-        caption = _("スポイラー・ファイル'", "Info file '");
-        caption.append(name).append("'");
-        fff = angband_fopen(path, FileOpenMode::READ);
+        caption.clear();
+        path_reopen = path_build(ANGBAND_DIR, name);
+        caption << _("スポイラー・ファイル'", "Info file '");
+        caption << name << "'";
+        fff = angband_fopen(path_reopen, FileOpenMode::READ);
     }
 
+    const auto open_error_mes = format(_("'%s'をオープンできません。", "Cannot open '%s'."), name.data());
     if (!fff) {
-        msg_format(_("'%s'をオープンできません。", "Cannot open '%s'."), name);
-        msg_print(nullptr);
-
-        return true;
+        THROW_EXCEPTION(std::runtime_error, open_error_mes);
     }
 
+    const auto caption_str = caption.str();
     int skey;
-    int next = 0;
-    int size = 0;
-    int back = 0;
-    bool menu = false;
-    char buf[1024];
-    bool reverse = (line < 0);
+    auto next = 0;
+    auto back = 0;
+    auto menu = false;
+    char buf[1024]{};
+    auto reverse = initial_line < 0;
+    auto line = initial_line;
     while (true) {
         char *str = buf;
         if (angband_fgets(fff, buf, sizeof(buf))) {
@@ -221,8 +205,7 @@ bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr
             int k = str[7] - 'A';
             menu = true;
             if ((str[8] == ']') && (str[9] == ' ')) {
-                memcpy(hook[k], str + 10, 31);
-                hook[k][31] = '\0';
+                angband_strcpy(hook[k], str + 10, sizeof(hook[k]));
             }
 
             continue;
@@ -235,13 +218,13 @@ bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr
         size_t len = strlen(str);
         if (str[len - 1] == '>') {
             str[len - 1] = '\0';
-            if (tag && streq(str + 7, tag)) {
+            if (!tag.empty() && streq(str + 7, tag)) {
                 line = next;
             }
         }
     }
 
-    size = next;
+    auto size = next;
     int rows = hgt - 4;
     if (line == -1) {
         line = ((size - 1) / rows) * rows;
@@ -249,8 +232,10 @@ bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr
 
     term_clear();
 
-    concptr find = nullptr;
-    concptr shower = nullptr;
+    std::string find;
+    std::string finder_str;
+    std::string shower;
+    std::string shower_str;
     while (true) {
         if (line >= size - rows) {
             line = size - rows;
@@ -261,9 +246,9 @@ bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr
 
         if (next > line) {
             angband_fclose(fff);
-            fff = angband_fopen(path, FileOpenMode::READ);
+            fff = angband_fopen(path_reopen, FileOpenMode::READ);
             if (!fff) {
-                return false;
+                THROW_EXCEPTION(std::runtime_error, open_error_mes);
             }
 
             next = 0;
@@ -292,40 +277,38 @@ bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr
                 continue;
             }
             next++;
-            if (find && !row_count) {
+            if (!find.empty() && !row_count) {
                 char lc_buf[1024];
                 strcpy(lc_buf, str);
                 str_tolower(lc_buf);
-                if (!angband_strstr(lc_buf, find)) {
+                if (!str_find(lc_buf, find)) {
                     continue;
                 }
             }
 
-            find = nullptr;
+            find.clear();
             show_file_aux_line(str, row_count + 2, shower);
             row_count++;
         }
 
         while (row_count < rows) {
-            term_erase(0, row_count + 2, 255);
+            term_erase(0, row_count + 2);
             row_count++;
         }
 
-        if (find) {
+        if (!find.empty()) {
             bell();
             line = back;
-            find = nullptr;
+            find.clear();
             continue;
         }
 
-        prt(format(_("[変愚蛮怒 %d.%d.%d, %s, %d/%d]", "[Hengband %d.%d.%d, %s, Line %d/%d]"), H_VER_MAJOR, H_VER_MINOR, H_VER_PATCH, caption.data(),
-                line, size),
-            0, 0);
-
         if (show_version) {
-            prt(format("[%s]", get_version().data()), 0, 0);
+            constexpr auto title = _("[%s, %s, %d/%d]", "[%s, %s, Line %d/%d]");
+            prt(format(title, get_version().data(), caption_str.data(), line, size), 0, 0);
         } else {
-            prt(format(_("[%s, %d/%d]", "[%s, Line %d/%d]"), caption.data(), line, size), 0, 0);
+            constexpr auto title = _("[%s, %d/%d]", "[%s, Line %d/%d]");
+            prt(format(title, caption_str.data(), line, size), 0, 0);
         }
 
         if (size <= rows) {
@@ -345,155 +328,161 @@ bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr
         skey = inkey_special(true);
         switch (skey) {
         case '?':
-            if (strcmp(name, _("jhelpinfo.txt", "helpinfo.txt")) != 0) {
-                show_file(player_ptr, true, _("jhelpinfo.txt", "helpinfo.txt"), nullptr, 0, mode);
+            if (name != _("jhelpinfo.txt", "helpinfo.txt")) {
+                show_file(player_ptr, true, _("jhelpinfo.txt", "helpinfo.txt"), 0, mode);
             }
+
             break;
-        case '=':
+        case '=': {
             prt(_("強調: ", "Show: "), hgt - 1, 0);
+            auto ask_result = askfor(80, shower_str);
+            if (!ask_result) {
+                break;
+            }
 
-            char back_str[81];
-            strcpy(back_str, shower_str);
-            if (askfor(shower_str, 80)) {
-                if (shower_str[0]) {
-                    str_tolower(shower_str);
-                    shower = shower_str;
-                } else {
-                    shower = nullptr;
-                }
-            } else {
-                strcpy(shower_str, back_str);
+            shower_str = *ask_result;
+            if (shower_str.empty()) {
+                shower.clear();
+                break;
             }
-            break;
 
+            str_tolower(shower_str.data());
+            shower = shower_str;
+            break;
+        }
         case '/':
-        case KTRL('s'):
+        case KTRL('s'): {
             prt(_("検索: ", "Find: "), hgt - 1, 0);
-            strcpy(back_str, finder_str);
-            if (askfor(finder_str, 80)) {
-                if (finder_str[0]) {
-                    find = finder_str;
-                    back = line;
-                    line = line + 1;
-                    str_tolower(finder_str);
-                    shower = finder_str;
-                } else {
-                    shower = nullptr;
-                }
-            } else {
-                strcpy(finder_str, back_str);
+            auto ask_result = askfor(80, finder_str);
+            if (!ask_result) {
+                break;
             }
-            break;
 
+            finder_str = *ask_result;
+            if (finder_str.empty()) {
+                shower.clear();
+                break;
+            }
+
+            find = finder_str;
+            back = line;
+            line = line + 1;
+            str_tolower(finder_str.data());
+            shower = finder_str;
+            break;
+        }
         case '#': {
-            char tmp[81];
             prt(_("行: ", "Goto Line: "), hgt - 1, 0);
-            strcpy(tmp, "0");
+            constexpr auto initial_goto = "0";
+            while (true) {
+                const auto ask_result = askfor(10, initial_goto);
+                if (!ask_result) {
+                    break;
+                }
 
-            if (askfor(tmp, 80)) {
-                line = atoi(tmp);
+                try {
+                    line = std::stoi(*ask_result);
+                    break;
+                } catch (std::invalid_argument const &) {
+                    prt(_("数値を入力して下さい。", "Please input numeric value."), hgt - 1, 0);
+                } catch (std::out_of_range const &) {
+                    prt(_("入力可能な数値の範囲を超えています。", "Input value overflows the maximum number."), hgt - 1, 0);
+                }
             }
+
             break;
         }
-
         case SKEY_TOP:
             line = 0;
             break;
-
         case SKEY_BOTTOM:
             line = ((size - 1) / rows) * rows;
             break;
-
         case '%': {
-            char tmp[81];
             prt(_("ファイル・ネーム: ", "Goto File: "), hgt - 1, 0);
-            strcpy(tmp, _("jhelp.hlp", "help.hlp"));
+            const auto ask_result = askfor(80, _("jhelp.hlp", "help.hlp"));
+            if (!ask_result) {
+                break;
+            }
 
-            if (askfor(tmp, 80)) {
-                if (!show_file(player_ptr, true, tmp, nullptr, 0, mode)) {
-                    skey = 'q';
-                }
+            if (!show_file(player_ptr, true, *ask_result, 0, mode)) {
+                skey = 'q';
             }
 
             break;
         }
-
         case '-':
             line = line + (reverse ? rows : -rows);
             if (line < 0) {
                 line = 0;
             }
-            break;
 
+            break;
         case SKEY_PGUP:
             line = line - rows;
             if (line < 0) {
                 line = 0;
             }
-            break;
 
+            break;
         case '\n':
         case '\r':
             line = line + (reverse ? -1 : 1);
             if (line < 0) {
                 line = 0;
             }
-            break;
 
+            break;
         case '8':
         case SKEY_UP:
             line--;
             if (line < 0) {
                 line = 0;
             }
-            break;
 
+            break;
         case '2':
         case SKEY_DOWN:
             line++;
             break;
-
         case ' ':
             line = line + (reverse ? -rows : rows);
             if (line < 0) {
                 line = 0;
             }
-            break;
 
+            break;
         case SKEY_PGDOWN:
             line = line + rows;
             break;
+        default:
+            break;
         }
 
         if (menu) {
-            int key = -1;
+            auto key = -1;
             if (!(skey & SKEY_MASK) && isalpha(skey)) {
                 key = skey - 'A';
             }
 
             if ((key > -1) && hook[key][0]) {
                 /* Recurse on that file */
-                if (!show_file(player_ptr, true, hook[key], nullptr, 0, mode)) {
+                if (!show_file(player_ptr, true, hook[key], 0, mode)) {
                     skey = 'q';
                 }
             }
         }
 
         if (skey == '|') {
-            FILE *ffp;
-            char buff[1024];
-            char xtmp[81] = "";
-
-            if (!get_string(_("ファイル名: ", "File name: "), xtmp, 80)) {
+            const auto xtmp = input_string(_("ファイル名: ", "File name: "), 80);
+            if (!xtmp) {
                 continue;
             }
-            angband_fclose(fff);
-            path_build(buff, sizeof(buff), ANGBAND_DIR_USER, xtmp);
 
-            /* Hack -- Re-Open the file */
-            fff = angband_fopen(path, FileOpenMode::READ);
-
-            ffp = angband_fopen(buff, FileOpenMode::WRITE);
+            angband_fclose(fff);
+            fff = angband_fopen(path_reopen, FileOpenMode::READ);
+            const auto &path_xtemp = path_build(ANGBAND_DIR_USER, *xtmp);
+            auto *ffp = angband_fopen(path_xtemp, FileOpenMode::WRITE);
 
             if (!(fff && ffp)) {
                 msg_print(_("ファイルを開けません。", "Failed to open file."));
@@ -501,14 +490,14 @@ bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr
                 break;
             }
 
-            fprintf(ffp, "%s: %s\n", player_ptr->name, what ? what : caption.data());
-
+            fprintf(ffp, "%s: %s\n", player_ptr->name, !what.empty() ? what.data() : caption_str.data());
+            char buff[1024]{};
             while (!angband_fgets(fff, buff, sizeof(buff))) {
                 angband_fputs(ffp, buff, 80);
             }
             angband_fclose(fff);
             angband_fclose(ffp);
-            fff = angband_fopen(path, FileOpenMode::READ);
+            fff = angband_fopen(path_reopen, FileOpenMode::READ);
         }
 
         if ((skey == ESCAPE) || (skey == '<')) {
index 682a56b..4d2051f 100644 (file)
@@ -1,7 +1,8 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <stdint.h>
+#include <string_view>
 
 class PlayerType;
-bool show_file(PlayerType *player_ptr, bool show_version, concptr name, concptr what, int line, BIT_FLAGS mode);
+bool show_file(PlayerType *player_ptr, bool show_version, std::string_view name_with_tag, int initial_line, uint32_t mode, std::string_view what = "");
 void str_tolower(char *str);
index f95335d..c39217c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Special internal key
index cbe6eea..757e8fe 100644 (file)
@@ -1,4 +1,4 @@
-#include "core/speed-table.h"
+#include "core/speed-table.h"
 #include <vector>
 
 /*!
index 2f2ddee..41ad9e4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 49c15f7..506ffce 100644 (file)
@@ -1,23 +1,24 @@
-#include "core/stuff-handler.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "player/player-status.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 
 /*!
  * @brief 全更新処理をチェックして処理していく
- * Handle "player_ptr->update" and "player_ptr->redraw" and "player_ptr->window"
  */
 void handle_stuff(PlayerType *player_ptr)
 {
-    if (player_ptr->update) {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    if (rfu.any_stats()) {
         update_creature(player_ptr);
     }
-    if (player_ptr->redraw) {
+
+    if (rfu.any_main()) {
         redraw_stuff(player_ptr);
     }
-    if (player_ptr->window_flags) {
+
+    if (rfu.any_sub()) {
         window_stuff(player_ptr);
     }
 }
@@ -28,7 +29,7 @@ void handle_stuff(PlayerType *player_ptr)
 void monster_race_track(PlayerType *player_ptr, MonsterRaceId r_idx)
 {
     player_ptr->monster_race_idx = r_idx;
-    player_ptr->window_flags |= (PW_MONSTER_LORE);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
 }
 
 /*
@@ -37,7 +38,7 @@ void monster_race_track(PlayerType *player_ptr, MonsterRaceId r_idx)
 void object_kind_track(PlayerType *player_ptr, short bi_id)
 {
     player_ptr->tracking_bi_id = bi_id;
-    player_ptr->window_flags |= (PW_ITEM_KNOWLEDGTE);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::ITEM_KNOWLEDGE);
 }
 
 /*
@@ -53,13 +54,18 @@ void health_track(PlayerType *player_ptr, MONSTER_IDX m_idx)
     }
 
     player_ptr->health_who = m_idx;
-    player_ptr->redraw |= (PR_HEALTH);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::HEALTH);
 }
 
-bool update_player(PlayerType *player_ptr)
+bool update_player()
 {
-    player_ptr->update |= PU_COMBINATION | PU_REORDER;
-    player_ptr->window_flags |= PW_INVENTORY;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
     return true;
 }
 
@@ -69,8 +75,13 @@ bool redraw_player(PlayerType *player_ptr)
         player_ptr->csp = player_ptr->msp;
     }
 
-    player_ptr->redraw |= PR_MP;
-    player_ptr->update |= PU_COMBINATION | PU_REORDER;
-    player_ptr->window_flags |= PW_INVENTORY;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
     return true;
 }
index 09d1312..59e8dd3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -9,5 +9,5 @@ void monster_race_track(PlayerType *player_ptr, MonsterRaceId r_idx);
 void object_kind_track(PlayerType *player_ptr, short bi_id);
 void health_track(PlayerType *player_ptr, MONSTER_IDX m_idx);
 
-bool update_player(PlayerType *player_ptr);
+bool update_player();
 bool redraw_player(PlayerType *player_ptr);
index 30d3b52..bb65ec6 100644 (file)
@@ -1,10 +1,11 @@
-#include "core/turn-compensator.h"
+#include "core/turn-compensator.h"
 #include "floor/floor-town.h"
 #include "player-info/race-types.h"
 #include "store/store-owners.h"
 #include "store/store-util.h"
 #include "store/store.h"
 #include "system/floor-type-definition.h"
+#include "system/item-entity.h"
 #include "system/player-type-definition.h"
 #include "world/world.h"
 
@@ -65,9 +66,8 @@ void prevent_turn_overflow(PlayerType *player_ptr)
     }
 
     for (size_t i = 1; i < towns_info.size(); i++) {
-        for (auto j = 0; j < MAX_STORES; j++) {
-            store_type *store_ptr = &towns_info[i].store[j];
-
+        for (auto sst : STORE_SALE_TYPE_LIST) {
+            auto *store_ptr = &towns_info[i].stores[sst];
             if (store_ptr->last_visit > -10L * TURNS_PER_TICK * STORE_TICKS) {
                 store_ptr->last_visit -= rollback_turns;
                 if (store_ptr->last_visit < -10L * TURNS_PER_TICK * STORE_TICKS) {
index fdbd40d..e6045ee 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e9eb6d3..bc96df1 100644 (file)
@@ -1,4 +1,4 @@
-#include "core/visuals-reseter.h"
+#include "core/visuals-reseter.h"
 #include "game-option/special-options.h"
 #include "io/read-pref-file.h"
 #include "monster-race/monster-race.h"
  */
 void reset_visuals(PlayerType *player_ptr)
 {
-    for (auto &f_ref : terrains_info) {
+    for (auto &terrain : TerrainList::get_instance()) {
         for (int j = 0; j < F_LIT_MAX; j++) {
-            f_ref.x_attr[j] = f_ref.d_attr[j];
-            f_ref.x_char[j] = f_ref.d_char[j];
+            terrain.x_attr[j] = terrain.d_attr[j];
+            terrain.x_char[j] = terrain.d_char[j];
         }
     }
 
@@ -32,5 +32,5 @@ void reset_visuals(PlayerType *player_ptr)
 
     concptr pref_file = use_graphics ? "graf.prf" : "font.prf";
     process_pref_file(player_ptr, pref_file);
-    process_pref_file(player_ptr, std::string(use_graphics ? "graf-" : "font-").append(player_ptr->base_name).append(".prf").data());
+    process_pref_file(player_ptr, std::string(use_graphics ? "graf-" : "font-").append(player_ptr->base_name).append(".prf"));
 }
index 385f2a7..db60ded 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void reset_visuals(PlayerType *player_ptr);
index b93146a..dfbb106 100644 (file)
@@ -1,10 +1,9 @@
-/*!
+/*!
  * @brief ウィンドウの再描画処理
  * @date 2020/06/27
  * @author Hourier
  */
 #include "core/window-redrawer.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "floor/floor-util.h"
 #include "game-option/option-flags.h"
@@ -12,6 +11,7 @@
 #include "player-base/player-class.h"
 #include "player-info/race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
  * Redraw a term when it is resized
  * @todo ここにPlayerType を追加するとz-termに影響が行くので保留
  */
-void redraw_window(void)
+void redraw_window()
 {
     if (!w_ptr->character_dungeon) {
         return;
     }
 
-    p_ptr->window_flags = PW_ALL;
-
+    RedrawingFlagsUpdater::get_instance().fill_up_sub_flags();
     handle_stuff(p_ptr);
     term_redraw();
 }
@@ -49,17 +48,16 @@ void redraw_window(void)
  */
 static void print_dungeon(PlayerType *player_ptr)
 {
-    TERM_LEN width, height;
-    term_get_size(&width, &height);
+    const auto &[wid, hgt] = term_get_size();
 
-    c_put_str(TERM_WHITE, "             ", height + ROW_DUNGEON, COL_DUNGEON);
-    concptr dungeon_name = map_name(player_ptr);
-    TERM_LEN col = COL_DUNGEON + 6 - strlen(dungeon_name) / 2;
+    c_put_str(TERM_WHITE, "             ", hgt + ROW_DUNGEON, COL_DUNGEON);
+    const auto dungeon_name = map_name(player_ptr);
+    TERM_LEN col = COL_DUNGEON + 6 - dungeon_name.length() / 2;
     if (col < 0) {
         col = 0;
     }
 
-    c_put_str(TERM_L_UMBER, format("%s", dungeon_name), height + ROW_DUNGEON, col);
+    c_put_str(TERM_L_UMBER, dungeon_name, hgt + ROW_DUNGEON, col);
 }
 
 /*!
@@ -68,7 +66,8 @@ static void print_dungeon(PlayerType *player_ptr)
  */
 void redraw_stuff(PlayerType *player_ptr)
 {
-    if (!player_ptr->redraw) {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    if (!rfu.any_main()) {
         return;
     }
 
@@ -80,55 +79,60 @@ void redraw_stuff(PlayerType *player_ptr)
         return;
     }
 
-    if (player_ptr->redraw & (PR_WIPE)) {
-        player_ptr->redraw &= ~(PR_WIPE);
+    if (rfu.has(MainWindowRedrawingFlag::WIPE)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::WIPE);
         msg_print(nullptr);
         term_clear();
     }
 
-    if (player_ptr->redraw & (PR_MAP)) {
-        player_ptr->redraw &= ~(PR_MAP);
+    if (rfu.has(MainWindowRedrawingFlag::MAP)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::MAP);
         print_map(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_BASIC)) {
-        player_ptr->redraw &= ~(PR_BASIC);
-        player_ptr->redraw &= ~(PR_MISC | PR_TITLE | PR_ABILITY_SCORE);
-        player_ptr->redraw &= ~(PR_LEVEL | PR_EXP | PR_GOLD);
-        player_ptr->redraw &= ~(PR_AC | PR_HP | PR_MP);
-        player_ptr->redraw &= ~(PR_DEPTH | PR_HEALTH | PR_UHEALTH);
+    if (rfu.has(MainWindowRedrawingFlag::BASIC)) {
+        static constexpr auto flags = {
+            MainWindowRedrawingFlag::BASIC,
+            MainWindowRedrawingFlag::TITLE,
+            MainWindowRedrawingFlag::ABILITY_SCORE,
+            MainWindowRedrawingFlag::LEVEL,
+            MainWindowRedrawingFlag::EXP,
+            MainWindowRedrawingFlag::GOLD,
+            MainWindowRedrawingFlag::AC,
+            MainWindowRedrawingFlag::HP,
+            MainWindowRedrawingFlag::MP,
+            MainWindowRedrawingFlag::DEPTH,
+            MainWindowRedrawingFlag::HEALTH,
+            MainWindowRedrawingFlag::UHEALTH,
+        };
+        rfu.reset_flags(flags);
         print_frame_basic(player_ptr);
         WorldTurnProcessor(player_ptr).print_time();
         print_dungeon(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_EQUIPPY)) {
-        player_ptr->redraw &= ~(PR_EQUIPPY);
+    if (rfu.has(MainWindowRedrawingFlag::EQUIPPY)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::EQUIPPY);
         display_player_equippy(player_ptr, ROW_EQUIPPY, COL_EQUIPPY, 0);
     }
 
-    if (player_ptr->redraw & (PR_MISC)) {
-        player_ptr->redraw &= ~(PR_MISC);
-        print_field(rp_ptr->title, ROW_RACE, COL_RACE);
-    }
-
-    if (player_ptr->redraw & (PR_TITLE)) {
-        player_ptr->redraw &= ~(PR_TITLE);
+    if (rfu.has(MainWindowRedrawingFlag::TITLE)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::TITLE);
         print_title(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_LEVEL)) {
-        player_ptr->redraw &= ~(PR_LEVEL);
+    if (rfu.has(MainWindowRedrawingFlag::LEVEL)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::LEVEL);
         print_level(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_EXP)) {
-        player_ptr->redraw &= ~(PR_EXP);
+    if (rfu.has(MainWindowRedrawingFlag::EXP)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::EXP);
         print_exp(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_ABILITY_SCORE)) {
-        player_ptr->redraw &= ~(PR_ABILITY_SCORE);
+    if (rfu.has(MainWindowRedrawingFlag::ABILITY_SCORE)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
         print_stat(player_ptr, A_STR);
         print_stat(player_ptr, A_INT);
         print_stat(player_ptr, A_WIS);
@@ -137,172 +141,188 @@ void redraw_stuff(PlayerType *player_ptr)
         print_stat(player_ptr, A_CHR);
     }
 
-    if (player_ptr->redraw & (PR_TIMED_EFFECT)) {
-        player_ptr->redraw &= ~(PR_TIMED_EFFECT);
+    if (rfu.has(MainWindowRedrawingFlag::TIMED_EFFECT)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
         print_status(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_AC)) {
-        player_ptr->redraw &= ~(PR_AC);
+    if (rfu.has(MainWindowRedrawingFlag::AC)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::AC);
         print_ac(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_HP)) {
-        player_ptr->redraw &= ~(PR_HP);
+    if (rfu.has(MainWindowRedrawingFlag::HP)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::HP);
         print_hp(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_MP)) {
-        player_ptr->redraw &= ~(PR_MP);
+    if (rfu.has(MainWindowRedrawingFlag::MP)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::MP);
         print_sp(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_GOLD)) {
-        player_ptr->redraw &= ~(PR_GOLD);
+    if (rfu.has(MainWindowRedrawingFlag::GOLD)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::GOLD);
         print_gold(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_DEPTH)) {
-        player_ptr->redraw &= ~(PR_DEPTH);
+    if (rfu.has(MainWindowRedrawingFlag::DEPTH)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::DEPTH);
         print_depth(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_UHEALTH)) {
-        player_ptr->redraw &= ~(PR_UHEALTH);
+    if (rfu.has(MainWindowRedrawingFlag::UHEALTH)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::UHEALTH);
         print_health(player_ptr, true);
     }
 
-    if (player_ptr->redraw & (PR_HEALTH)) {
-        player_ptr->redraw &= ~(PR_HEALTH);
+    if (rfu.has(MainWindowRedrawingFlag::HEALTH)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::HEALTH);
         print_health(player_ptr, false);
     }
 
-    if (player_ptr->redraw & (PR_EXTRA)) {
-        player_ptr->redraw &= ~(PR_EXTRA);
-        player_ptr->redraw &= ~(PR_CUT | PR_STUN);
-        player_ptr->redraw &= ~(PR_HUNGER);
-        player_ptr->redraw &= ~(PR_ACTION | PR_SPEED | PR_STUDY | PR_IMITATION | PR_TIMED_EFFECT);
+    if (rfu.has(MainWindowRedrawingFlag::EXTRA)) {
+        static constexpr auto flags = {
+            MainWindowRedrawingFlag::EXTRA,
+            MainWindowRedrawingFlag::CUT,
+            MainWindowRedrawingFlag::STUN,
+            MainWindowRedrawingFlag::HUNGER,
+            MainWindowRedrawingFlag::ACTION,
+            MainWindowRedrawingFlag::SPEED,
+            MainWindowRedrawingFlag::STUDY,
+            MainWindowRedrawingFlag::IMITATION,
+            MainWindowRedrawingFlag::TIMED_EFFECT,
+        };
+        rfu.reset_flags(flags);
         print_frame_extra(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_CUT)) {
-        player_ptr->redraw &= ~(PR_CUT);
+    if (rfu.has(MainWindowRedrawingFlag::CUT)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::CUT);
         print_cut(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_STUN)) {
-        player_ptr->redraw &= ~(PR_STUN);
+    if (rfu.has(MainWindowRedrawingFlag::STUN)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::STUN);
         print_stun(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_HUNGER)) {
-        player_ptr->redraw &= ~(PR_HUNGER);
+    if (rfu.has(MainWindowRedrawingFlag::HUNGER)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::HUNGER);
         print_hunger(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_ACTION)) {
-        player_ptr->redraw &= ~(PR_ACTION);
+    if (rfu.has(MainWindowRedrawingFlag::ACTION)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::ACTION);
         print_state(player_ptr);
     }
 
-    if (player_ptr->redraw & (PR_SPEED)) {
-        player_ptr->redraw &= ~(PR_SPEED);
+    if (rfu.has(MainWindowRedrawingFlag::SPEED)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::SPEED);
         print_speed(player_ptr);
     }
 
     if (PlayerClass(player_ptr).equals(PlayerClassType::IMITATOR)) {
-        if (player_ptr->redraw & (PR_IMITATION)) {
-            player_ptr->redraw &= ~(PR_IMITATION);
+        if (rfu.has(MainWindowRedrawingFlag::IMITATION)) {
+            rfu.reset_flag(MainWindowRedrawingFlag::IMITATION);
             print_imitation(player_ptr);
         }
 
         return;
     }
 
-    if (player_ptr->redraw & (PR_STUDY)) {
-        player_ptr->redraw &= ~(PR_STUDY);
+    if (rfu.has(MainWindowRedrawingFlag::STUDY)) {
+        rfu.reset_flag(MainWindowRedrawingFlag::STUDY);
         print_study(player_ptr);
     }
 }
 
 /*!
- * @brief player_ptr->window のフラグに応じた更新をまとめて行う / Handle "player_ptr->window"
+ * @brief SubWindowRedrawingFlag のフラグに応じた更新をまとめて行う
  * @param player_ptr プレイヤーへの参照ポインタ
- * @details 更新処理の対象はサブウィンドウ全
+ * @details 更新処理の対象はサブウィンドウ全
  */
 void window_stuff(PlayerType *player_ptr)
 {
-    if (!player_ptr->window_flags) {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    if (!rfu.any_sub()) {
         return;
     }
 
-    BIT_FLAGS mask = 0L;
+    EnumClassFlagGroup<SubWindowRedrawingFlag> target_flags{};
     for (auto i = 0U; i < angband_terms.size(); ++i) {
-        if (angband_terms[i] && !angband_terms[i]->never_fresh) {
-            mask |= window_flag[i];
+        if ((angband_terms[i] == nullptr) || angband_terms[i]->never_fresh) {
+            continue;
         }
+
+        target_flags.set(g_window_flags[i]);
     }
-    BIT_FLAGS window_flags = player_ptr->window_flags & mask;
 
-    if (window_flags & (PW_INVENTORY)) {
-        player_ptr->window_flags &= ~(PW_INVENTORY);
+    const auto &window_flags = rfu.get_sub_intersection(target_flags);
+    if (window_flags.has(SubWindowRedrawingFlag::INVENTORY)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::INVENTORY);
         fix_inventory(player_ptr);
     }
 
-    if (window_flags & (PW_EQUIPMENT)) {
-        player_ptr->window_flags &= ~(PW_EQUIPMENT);
+    if (window_flags.has(SubWindowRedrawingFlag::EQUIPMENT)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::EQUIPMENT);
         fix_equip(player_ptr);
     }
 
-    if (window_flags & (PW_SPELL)) {
-        player_ptr->window_flags &= ~(PW_SPELL);
+    if (window_flags.has(SubWindowRedrawingFlag::SPELL)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::SPELL);
         fix_spell(player_ptr);
     }
 
-    if (window_flags & (PW_PLAYER)) {
-        player_ptr->window_flags &= ~(PW_PLAYER);
+    if (window_flags.has(SubWindowRedrawingFlag::PLAYER)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::PLAYER);
         fix_player(player_ptr);
     }
 
     // モンスターBGM対応のため、視界内モンスター表示のサブウインドウなし時も処理を行う
-    if (player_ptr->window_flags & (PW_SIGHT_MONSTERS)) {
-        player_ptr->window_flags &= ~(PW_SIGHT_MONSTERS);
+    if (rfu.has(SubWindowRedrawingFlag::SIGHT_MONSTERS)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::SIGHT_MONSTERS);
         fix_monster_list(player_ptr);
     }
 
-    if (window_flags & (PW_MESSAGE)) {
-        player_ptr->window_flags &= ~(PW_MESSAGE);
+    if (window_flags.has(SubWindowRedrawingFlag::PETS)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::PETS);
+        fix_pet_list(player_ptr);
+    }
+
+    if (window_flags.has(SubWindowRedrawingFlag::MESSAGE)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::MESSAGE);
         fix_message();
     }
 
-    if (window_flags & (PW_OVERHEAD)) {
-        player_ptr->window_flags &= ~(PW_OVERHEAD);
+    if (window_flags.has(SubWindowRedrawingFlag::OVERHEAD)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::OVERHEAD);
         fix_overhead(player_ptr);
     }
 
-    if (window_flags & (PW_DUNGEON)) {
-        player_ptr->window_flags &= ~(PW_DUNGEON);
+    if (window_flags.has(SubWindowRedrawingFlag::DUNGEON)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::DUNGEON);
         fix_dungeon(player_ptr);
     }
 
-    if (window_flags & (PW_MONSTER_LORE)) {
-        player_ptr->window_flags &= ~(PW_MONSTER_LORE);
+    if (window_flags.has(SubWindowRedrawingFlag::MONSTER_LORE)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::MONSTER_LORE);
         fix_monster(player_ptr);
     }
 
-    if (window_flags & (PW_ITEM_KNOWLEDGTE)) {
-        player_ptr->window_flags &= ~(PW_ITEM_KNOWLEDGTE);
+    if (window_flags.has(SubWindowRedrawingFlag::ITEM_KNOWLEDGE)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::ITEM_KNOWLEDGE);
         fix_object(player_ptr);
     }
 
-    if (any_bits(window_flags, PW_FLOOR_ITEMS)) {
-        reset_bits(player_ptr->window_flags, PW_FLOOR_ITEMS);
+    if (window_flags.has(SubWindowRedrawingFlag::FLOOR_ITEMS)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::FLOOR_ITEMS);
         // ウィンドウサイズ変更に対応できず。カーソル位置を取る必要がある。
-        fix_floor_item_list(player_ptr, player_ptr->y, player_ptr->x);
+        fix_floor_item_list(player_ptr, player_ptr->get_position());
     }
 
-    if (any_bits(window_flags, PW_FOUND_ITEMS)) {
-        reset_bits(player_ptr->window_flags, PW_FOUND_ITEMS);
+    if (window_flags.has(SubWindowRedrawingFlag::FOUND_ITEMS)) {
+        rfu.reset_flag(SubWindowRedrawingFlag::FOUND_ITEMS);
         fix_found_item_list(player_ptr);
     }
 }
index acad1c0..b8597f3 100644 (file)
@@ -1,31 +1,8 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-// clang-format off
-/*!
- * @brief サブウィンドウ描画フラグ
- */
-enum window_redraw_type {
-    PW_INVENTORY       = 1U <<  0, /*!<サブウィンドウ描画フラグ: 所持品-装備品 / Display inven/equip */
-    PW_EQUIPMENT       = 1U <<  1, /*!<サブウィンドウ描画フラグ: 装備品-所持品 / Display equip/inven */
-    PW_SPELL           = 1U <<  2, /*!<サブウィンドウ描画フラグ: 魔法一覧 / Display spell list */
-    PW_PLAYER          = 1U <<  3, /*!<サブウィンドウ描画フラグ: プレイヤーのステータス / Display character */
-    PW_SIGHT_MONSTERS  = 1U <<  4, /*!<サブウィンドウ描画フラグ: 視界内モンスターの一覧 / Display monster list */
-    PW_MESSAGE         = 1U <<  6, /*!<サブウィンドウ描画フラグ: メッセージログ / Display messages */
-    PW_OVERHEAD        = 1U <<  7, /*!<サブウィンドウ描画フラグ: 周辺の光景 / Display overhead view */
-    PW_MONSTER_LORE    = 1U <<  8, /*!<サブウィンドウ描画フラグ: モンスターの思い出 / Display monster recall */
-    PW_ITEM_KNOWLEDGTE = 1U <<  9, /*!<サブウィンドウ描画フラグ: アイテムの知識 / Display object recall */
-    PW_DUNGEON         = 1U << 10, /*!<サブウィンドウ描画フラグ: ダンジョンの地形 / Display dungeon view */
-    PW_SNAPSHOT        = 1U << 11, /*!<サブウィンドウ描画フラグ: 記念写真 / Display snap-shot */
-    PW_FLOOR_ITEMS     = 1U << 12, /*!<サブウィンドウ描画フラグ: 床上のアイテム一覧 / Display items on grid */
-    PW_FOUND_ITEMS     = 1U << 13, /*!<サブウィンドウ描画フラグ: 発見済みのアイテム一覧 / Display found items*/
-
-    PW_ALL = (PW_INVENTORY | PW_EQUIPMENT | PW_SPELL | PW_PLAYER | PW_SIGHT_MONSTERS | PW_MESSAGE | PW_OVERHEAD | PW_MONSTER_LORE | PW_ITEM_KNOWLEDGTE | PW_DUNGEON | PW_SNAPSHOT | PW_FLOOR_ITEMS | PW_FOUND_ITEMS),
-};
-
-// clang-format on
 class PlayerType;
-void redraw_window(void);
+void redraw_window();
 void window_stuff(PlayerType *player_ptr);
 void redraw_stuff(PlayerType *player_ptr);
index f42b6f9..9d79350 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "dungeon/dungeon-flag-types.h"
 #include "util/flag-group.h"
index 5cfd538..3917013 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class DungeonFeatureType {
     WINNER,
index 4175a6c..c81d399 100644 (file)
@@ -1,11 +1,9 @@
-#include "dungeon/dungeon-processor.h"
+#include "dungeon/dungeon-processor.h"
 #include "cmd-building/cmd-building.h"
 #include "cmd-io/cmd-dump.h"
 #include "core/disturbance.h"
 #include "core/object-compressor.h"
 #include "core/player-processor.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/turn-compensator.h"
 #include "core/window-redrawer.h"
 #include "realm/realm-song-numbers.h"
 #include "realm/realm-song.h"
 #include "spell-realm/spells-song.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include "world/world-turn-processor.h"
 #include "world/world.h"
 
+static void redraw_character_xtra(PlayerType *player_ptr)
+{
+    w_ptr->character_xtra = true;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::SPELL,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::MONSTER_LORE,
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::WIPE,
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::EQUIPPY,
+        MainWindowRedrawingFlag::MAP,
+    };
+    rfu.set_flags(flags_mwrf);
+    auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::TORCH,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+        StatusRecalculatingFlag::DISTANCE,
+        StatusRecalculatingFlag::FLOW,
+    };
+    rfu.set_flags(flags_srf);
+    handle_stuff(player_ptr);
+    w_ptr->character_xtra = false;
+}
+
 /*!
  * process_player()、process_world() をcore.c から移設するのが先.
  * process_upkeep_with_speed() はこの関数と同じところでOK
  */
 void process_dungeon(PlayerType *player_ptr, bool load_game)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    floor_ptr->base_level = floor_ptr->dun_level;
+    auto &floor = *player_ptr->current_floor_ptr;
+    floor.base_level = floor.dun_level;
     w_ptr->is_loading_now = false;
     player_ptr->leaving = false;
 
@@ -77,7 +117,7 @@ void process_dungeon(PlayerType *player_ptr, bool load_game)
     health_track(player_ptr, 0);
 
     disturb(player_ptr, true, true);
-    auto quest_num = quest_number(player_ptr, floor_ptr->dun_level);
+    auto quest_num = floor.get_quest_id();
     const auto &quest_list = QuestList::get_instance();
     auto *questor_ptr = &monraces_info[quest_list[quest_num].r_idx];
     if (inside_quest(quest_num)) {
@@ -88,10 +128,10 @@ void process_dungeon(PlayerType *player_ptr, bool load_game)
         player_ptr->max_plv = player_ptr->lev;
     }
 
-    if ((max_dlv[player_ptr->dungeon_idx] < floor_ptr->dun_level) && !inside_quest(floor_ptr->quest_number)) {
-        max_dlv[player_ptr->dungeon_idx] = floor_ptr->dun_level;
+    if ((max_dlv[floor.dungeon_idx] < floor.dun_level) && !floor.is_in_quest()) {
+        max_dlv[floor.dungeon_idx] = floor.dun_level;
         if (record_maxdepth) {
-            exe_write_diary(player_ptr, DIARY_MAXDEAPTH, floor_ptr->dun_level, nullptr);
+            exe_write_diary(player_ptr, DiaryKind::MAXDEAPTH, floor.dun_level);
         }
     }
 
@@ -100,14 +140,16 @@ void process_dungeon(PlayerType *player_ptr, bool load_game)
     verify_panel(player_ptr);
     msg_erase();
 
-    w_ptr->character_xtra = true;
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_SPELL | PW_PLAYER | PW_MONSTER_LORE | PW_OVERHEAD | PW_DUNGEON);
-    set_bits(player_ptr->redraw, PR_WIPE | PR_BASIC | PR_EXTRA | PR_EQUIPPY | PR_MAP);
-    set_bits(player_ptr->update, PU_BONUS | PU_HP | PU_MP | PU_SPELLS | PU_VIEW | PU_LITE | PU_MONSTER_LITE | PU_TORCH | PU_MONSTER_STATUSES | PU_DISTANCE | PU_FLOW);
-    handle_stuff(player_ptr);
-
-    w_ptr->character_xtra = false;
-    set_bits(player_ptr->update, PU_BONUS | PU_HP | PU_MP | PU_SPELLS | PU_COMBINATION | PU_REORDER);
+    redraw_character_xtra(player_ptr);
+    auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags_srf);
     handle_stuff(player_ptr);
     term_fresh();
 
@@ -118,7 +160,8 @@ void process_dungeon(PlayerType *player_ptr, bool load_game)
         do_cmd_feeling(player_ptr);
     }
 
-    if (player_ptr->phase_out) {
+    const auto is_watching = AngbandSystem::get_instance().is_phase_out();
+    if (is_watching) {
         if (load_game) {
             player_ptr->energy_need = 0;
             update_gambling_monsters(player_ptr);
@@ -136,14 +179,15 @@ void process_dungeon(PlayerType *player_ptr, bool load_game)
         return;
     }
 
-    if (!inside_quest(floor_ptr->quest_number) && (player_ptr->dungeon_idx == DUNGEON_ANGBAND)) {
-        quest_discovery(random_quest_number(player_ptr, floor_ptr->dun_level));
-        floor_ptr->quest_number = random_quest_number(player_ptr, floor_ptr->dun_level);
+    if (!floor.is_in_quest() && (floor.dungeon_idx == DUNGEON_ANGBAND)) {
+        const auto random_quest_id = floor.get_random_quest_id();
+        quest_discovery(random_quest_id);
+        floor.quest_number = random_quest_id;
     }
 
-    const auto &dungeon = dungeons_info[player_ptr->dungeon_idx];
+    const auto &dungeon = floor.get_dungeon_definition();
     const auto guardian = dungeon.final_guardian;
-    if ((floor_ptr->dun_level == dungeon.maxdepth) && MonsterRace(guardian).is_valid()) {
+    if ((floor.dun_level == dungeon.maxdepth) && MonsterRace(guardian).is_valid()) {
         const auto &guardian_ref = monraces_info[guardian];
         if (guardian_ref.max_num) {
 #ifdef JP
@@ -158,30 +202,30 @@ void process_dungeon(PlayerType *player_ptr, bool load_game)
         set_superstealth(player_ptr, false);
     }
 
-    floor_ptr->monster_level = floor_ptr->base_level;
-    floor_ptr->object_level = floor_ptr->base_level;
+    floor.monster_level = floor.base_level;
+    floor.object_level = floor.base_level;
     w_ptr->is_loading_now = true;
-    if (player_ptr->energy_need > 0 && !player_ptr->phase_out && (floor_ptr->dun_level || player_ptr->leaving_dungeon || floor_ptr->inside_arena)) {
+    if (player_ptr->energy_need > 0 && !is_watching && (floor.dun_level || player_ptr->leaving_dungeon || floor.inside_arena)) {
         player_ptr->energy_need = 0;
     }
 
     player_ptr->leaving_dungeon = false;
-    mproc_init(floor_ptr);
+    mproc_init(&floor);
 
     while (true) {
-        if ((floor_ptr->m_cnt + 32 > w_ptr->max_m_idx) && !player_ptr->phase_out) {
+        if ((floor.m_cnt + 32 > w_ptr->max_m_idx) && !is_watching) {
             compact_monsters(player_ptr, 64);
         }
 
-        if ((floor_ptr->m_cnt + 32 < floor_ptr->m_max) && !player_ptr->phase_out) {
+        if ((floor.m_cnt + 32 < floor.m_max) && !is_watching) {
             compact_monsters(player_ptr, 0);
         }
 
-        if (floor_ptr->o_cnt + 32 > w_ptr->max_o_idx) {
+        if (floor.o_cnt + 32 > w_ptr->max_o_idx) {
             compact_objects(player_ptr, 64);
         }
 
-        if (floor_ptr->o_cnt + 32 < floor_ptr->o_max) {
+        if (floor.o_cnt + 32 < floor.o_max) {
             compact_objects(player_ptr, 0);
         }
 
index 83fbdcb..03c094e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void process_dungeon(PlayerType *player_ptr, bool load_game);
index 2cf74f8..3169b7d 100644 (file)
@@ -1,5 +1,4 @@
-#include "dungeon/quest-completion-checker.h"
-#include "core/player-update-types.h"
+#include "dungeon/quest-completion-checker.h"
 #include "dungeon/quest.h"
 #include "effect/effect-characteristics.h"
 #include "floor/cave.h"
@@ -18,6 +17,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include <algorithm>
@@ -25,6 +25,7 @@
 QuestCompletionChecker::QuestCompletionChecker(PlayerType *player_ptr, MonsterEntity *m_ptr)
     : player_ptr(player_ptr)
     , m_ptr(m_ptr)
+    , quest_idx(QuestId::NONE)
 {
 }
 
@@ -240,7 +241,7 @@ Pos2D QuestCompletionChecker::make_stairs(const bool create_stairs)
 
     msg_print(_("魔法の階段が現れた...", "A magical staircase appears..."));
     cave_set_feat(this->player_ptr, y, x, feat_down_stair);
-    set_bits(this->player_ptr->update, PU_FLOW);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
     return Pos2D(y, x);
 }
 
@@ -251,8 +252,8 @@ void QuestCompletionChecker::make_reward(const Pos2D pos)
         ItemEntity item;
         while (true) {
             item.wipe();
-            auto &r_ref = monraces_info[this->m_ptr->r_idx];
-            (void)make_object(this->player_ptr, &item, AM_GOOD | AM_GREAT, r_ref.level);
+            const auto &monrace = this->m_ptr->get_monrace();
+            (void)make_object(this->player_ptr, &item, AM_GOOD | AM_GREAT, monrace.level);
             if (!this->check_quality(item)) {
                 continue;
             }
index 7cf02ea..94b07d6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "dungeon/quest.h"
 #include "system/angband.h"
index 9528e4f..a7a3378 100644 (file)
@@ -1,4 +1,4 @@
-#include "dungeon/quest-monster-placer.h"
+#include "dungeon/quest-monster-placer.h"
 #include "dungeon/quest.h"
 #include "floor/floor-generator-util.h"
 #include "floor/geometry.h"
@@ -30,7 +30,7 @@ bool place_quest_monsters(PlayerType *player_ptr)
         auto no_quest_monsters = quest.status != QuestStatusType::TAKEN;
         no_quest_monsters |= (quest.type != QuestKindType::KILL_LEVEL && quest.type != QuestKindType::RANDOM);
         no_quest_monsters |= quest.level != floor_ptr->dun_level;
-        no_quest_monsters |= player_ptr->dungeon_idx != quest.dungeon;
+        no_quest_monsters |= floor_ptr->dungeon_idx != quest.dungeon;
         no_quest_monsters |= any_bits(quest.flags, QUEST_FLAG_PRESET);
 
         if (no_quest_monsters) {
@@ -54,13 +54,11 @@ bool place_quest_monsters(PlayerType *player_ptr)
                 POSITION y = 0;
                 int l;
                 for (l = SAFE_MAX_ATTEMPTS; l > 0; l--) {
-                    grid_type *g_ptr;
-                    TerrainType *f_ptr;
                     y = randint0(floor_ptr->height);
                     x = randint0(floor_ptr->width);
-                    g_ptr = &floor_ptr->grid_array[y][x];
-                    f_ptr = &terrains_info[g_ptr->feat];
-                    if (f_ptr->flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY })) {
+                    const auto &grid = floor_ptr->get_grid({ y, x });
+                    const auto &terrain = grid.get_terrain();
+                    if (terrain.flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY })) {
                         continue;
                     }
 
@@ -72,7 +70,7 @@ bool place_quest_monsters(PlayerType *player_ptr)
                         continue;
                     }
 
-                    if (g_ptr->is_icky()) {
+                    if (grid.is_icky()) {
                         continue;
                     } else {
                         break;
@@ -83,7 +81,7 @@ bool place_quest_monsters(PlayerType *player_ptr)
                     return false;
                 }
 
-                if (place_monster_aux(player_ptr, 0, y, x, quest.r_idx, mode)) {
+                if (place_specific_monster(player_ptr, 0, y, x, quest.r_idx, mode)) {
                     break;
                 } else {
                     continue;
index 0241423..be29f93 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool place_quest_monsters(PlayerType *player_ptr);
index 46ffece..5d2c7f3 100644 (file)
@@ -1,8 +1,7 @@
-#include "dungeon/quest.h"
+#include "dungeon/quest.h"
 #include "artifact/fixed-art-types.h"
 #include "cmd-io/cmd-dump.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "floor/cave.h"
 #include "floor/floor-events.h"
 #include "floor/floor-mode-changer.h"
@@ -13,6 +12,7 @@
 #include "locale/english.h"
 #include "main/music-definitions-table.h"
 #include "main/sound-of-music.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
@@ -29,7 +29,7 @@
 #include "player/player-status.h"
 #include "system/artifact-type-definition.h"
 #include "system/dungeon-info.h"
-#include "system/floor-type-definition.h"
+#include "system/floor-type-definition.h" // @todo 相互参照、将来的に削除する.
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-race-info.h"
@@ -185,36 +185,37 @@ void determine_random_questor(PlayerType *player_ptr, QuestType *q_ptr)
     get_mon_num_prep(player_ptr, mon_hook_quest, nullptr);
     MonsterRaceId r_idx;
     while (true) {
-        /*
-         * Random monster 5 - 10 levels out of depth
-         * (depending on level)
-         */
-        r_idx = get_mon_num(player_ptr, 0, q_ptr->level + 5 + randint1(q_ptr->level / 10), GMN_ARENA);
-        MonsterRaceInfo *r_ptr;
-        r_ptr = &monraces_info[r_idx];
-
-        if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
+        r_idx = get_mon_num(player_ptr, 0, q_ptr->level + 5 + randint1(q_ptr->level / 10), PM_ARENA);
+        const auto &monrace = monraces_info[r_idx];
+        if (monrace.kind_flags.has_not(MonsterKindType::UNIQUE)) {
             continue;
         }
-        if (r_ptr->flags8 & RF8_NO_QUEST) {
+
+        if (monrace.flags8 & RF8_NO_QUEST) {
             continue;
         }
-        if (r_ptr->flags1 & RF1_QUESTOR) {
+
+        if (monrace.flags1 & RF1_QUESTOR) {
             continue;
         }
-        if (r_ptr->rarity > 100) {
+
+        if (monrace.rarity > 100) {
             continue;
         }
-        if (r_ptr->behavior_flags.has(MonsterBehaviorType::FRIENDLY)) {
+
+        if (monrace.behavior_flags.has(MonsterBehaviorType::FRIENDLY)) {
             continue;
         }
-        if (r_ptr->feature_flags.has(MonsterFeatureType::AQUATIC)) {
+
+        if (monrace.feature_flags.has(MonsterFeatureType::AQUATIC)) {
             continue;
         }
-        if (r_ptr->wilderness_flags.has(MonsterWildernessType::WILD_ONLY)) {
+
+        if (monrace.wilderness_flags.has(MonsterWildernessType::WILD_ONLY)) {
             continue;
         }
-        if (no_questor_or_bounty_uniques(r_idx)) {
+
+        if (MonraceList::get_instance().can_unify_separate(r_idx)) {
             continue;
         }
 
@@ -222,7 +223,7 @@ void determine_random_questor(PlayerType *player_ptr, QuestType *q_ptr)
          * Accept monsters that are 2 - 6 levels
          * out of depth depending on the quest level
          */
-        if (r_ptr->level > (q_ptr->level + (q_ptr->level / 20))) {
+        if (monrace.level > (q_ptr->level + (q_ptr->level / 20))) {
             break;
         }
     }
@@ -240,7 +241,7 @@ void record_quest_final_status(QuestType *q_ptr, PLAYER_LEVEL lev, QuestStatusTy
 {
     q_ptr->status = stat;
     q_ptr->complev = lev;
-    update_playtime();
+    w_ptr->update_playtime();
     q_ptr->comptime = w_ptr->play_time;
 }
 
@@ -257,12 +258,12 @@ void complete_quest(PlayerType *player_ptr, QuestId quest_num)
     switch (q_ptr->type) {
     case QuestKindType::RANDOM:
         if (record_rand_quest) {
-            exe_write_diary_quest(player_ptr, DIARY_RAND_QUEST_C, quest_num);
+            exe_write_diary_quest(player_ptr, DiaryKind::RAND_QUEST_C, quest_num);
         }
         break;
     default:
         if (record_fix_quest) {
-            exe_write_diary_quest(player_ptr, DIARY_FIX_QUEST_C, quest_num);
+            exe_write_diary_quest(player_ptr, DiaryKind::FIX_QUEST_C, quest_num);
         }
         break;
     }
@@ -340,65 +341,6 @@ void quest_discovery(QuestId q_idx)
 }
 
 /*!
- * @brief 新しく入ったダンジョンの階層に固定されている一般のクエストを探し出しIDを返す。
- * / Hack -- Check if a level is a "quest" level
- * @param player_ptr プレイヤーへの参照ポインタ
- * @param level 検索対象になる階
- * @return クエストIDを返す。該当がない場合0を返す。
- */
-QuestId quest_number(PlayerType *player_ptr, DEPTH level)
-{
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    const auto &quest_list = QuestList::get_instance();
-    if (inside_quest(floor_ptr->quest_number)) {
-        return floor_ptr->quest_number;
-    }
-
-    for (const auto &[q_idx, quest] : quest_list) {
-        if (quest.status != QuestStatusType::TAKEN) {
-            continue;
-        }
-
-        auto depth_quest = (quest.type == QuestKindType::KILL_LEVEL);
-        depth_quest &= !(quest.flags & QUEST_FLAG_PRESET);
-        depth_quest &= (quest.level == level);
-        depth_quest &= (quest.dungeon == player_ptr->dungeon_idx);
-        if (depth_quest) {
-            return q_idx;
-        }
-    }
-
-    return random_quest_number(player_ptr, level);
-}
-
-/*!
- * @brief 新しく入ったダンジョンの階層に固定されているランダムクエストを探し出しIDを返す。
- * @param player_ptr プレイヤーへの参照ポインタ
- * @param level 検索対象になる階
- * @return クエストIDを返す。該当がない場合0を返す。
- */
-QuestId random_quest_number(PlayerType *player_ptr, DEPTH level)
-{
-    if (player_ptr->dungeon_idx != DUNGEON_ANGBAND) {
-        return QuestId::NONE;
-    }
-
-    const auto &quest_list = QuestList::get_instance();
-    for (auto q_idx : EnumRange(QuestId::RANDOM_QUEST1, QuestId::RANDOM_QUEST10)) {
-        const auto &quest = quest_list[q_idx];
-        auto is_random_quest = (quest.type == QuestKindType::RANDOM);
-        is_random_quest &= (quest.status == QuestStatusType::TAKEN);
-        is_random_quest &= (quest.level == level);
-        is_random_quest &= (quest.dungeon == DUNGEON_ANGBAND);
-        if (is_random_quest) {
-            return q_idx;
-        }
-    }
-
-    return QuestId::NONE;
-}
-
-/*!
  * @brief クエスト階層から離脱する際の処理
  * @param player_ptr プレイヤーへの参照ポインタ
  */
@@ -438,13 +380,13 @@ void leave_quest_check(PlayerType *player_ptr)
     /* Record finishing a quest */
     if (q_ptr->type == QuestKindType::RANDOM) {
         if (record_rand_quest) {
-            exe_write_diary_quest(player_ptr, DIARY_RAND_QUEST_F, leaving_quest);
+            exe_write_diary_quest(player_ptr, DiaryKind::RAND_QUEST_F, leaving_quest);
         }
         return;
     }
 
     if (record_fix_quest) {
-        exe_write_diary_quest(player_ptr, DIARY_FIX_QUEST_F, leaving_quest);
+        exe_write_diary_quest(player_ptr, DiaryKind::FIX_QUEST_F, leaving_quest);
     }
 }
 
@@ -468,7 +410,7 @@ void leave_tower_check(PlayerType *player_ptr)
     }
     tower1.status = QuestStatusType::FAILED;
     tower1.complev = player_ptr->lev;
-    update_playtime();
+    w_ptr->update_playtime();
     tower1.comptime = w_ptr->play_time;
 }
 
@@ -504,7 +446,7 @@ void do_cmd_quest(PlayerType *player_ptr)
     }
 
     msg_print(_("ここにはクエストへの入口があります。", "There is an entry of a quest."));
-    if (!get_check(_("クエストに入りますか?", "Do you enter? "))) {
+    if (!input_check(_("クエストに入りますか?", "Do you enter? "))) {
         return;
     }
     if (is_echizen(player_ptr)) {
index ae6d3f0..4edd5e8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "util/enum-converter.h"
@@ -11,7 +11,7 @@
 /*
  * Quest constants
  */
-enum class QuestId : int16_t{
+enum class QuestId : short{
        NONE = 0, /* クエストなし */
        THIEF = 1, /*<! 盗賊の隠れ家 */
        SEWER = 2, /*<! 下水道 */
@@ -25,6 +25,7 @@ enum class QuestId : int16_t{
        SORCERER = 10, /*<! 仙術エネルギー特異点 */
        CHAOS = 11, /*<! カオスの特異点 */
        NATURE = 12, /*<! 自然魔術の特異点 */
+       ARCANE = 13, /*<! 秘術の特異点 */
        WARG = 14, /*<! ワーグを殲滅せよ */
        ERIC = 15, /*<! エリックの要塞 */
        MONSALVAT = 16, /*<! モンサルヴァト城への侵攻 */
@@ -100,7 +101,7 @@ class ArtifactType;
 class QuestType {
 public:
     QuestType() = default;
-    virtual ~QuestType() = default;
+
     QuestStatusType status{}; /*!< クエストの進行ステータス / Is the quest taken, completed, finished? */
     QuestKindType type{}; /*!< クエストの種別 / The quest type */
 
@@ -162,6 +163,7 @@ extern char quest_text[10][80];
 extern int quest_text_line;
 extern QuestId leaving_quest;
 
+class FloorType;
 class ItemEntity;
 class PlayerType;
 void determine_random_questor(PlayerType *player_ptr, QuestType *q_ptr);
@@ -169,8 +171,6 @@ void record_quest_final_status(QuestType *q_ptr, PLAYER_LEVEL lev, QuestStatusTy
 void complete_quest(PlayerType *player_ptr, QuestId quest_num);
 void check_find_art_quest_completion(PlayerType *player_ptr, ItemEntity *o_ptr);
 void quest_discovery(QuestId q_idx);
-QuestId quest_number(PlayerType *player_ptr, DEPTH level);
-QuestId random_quest_number(PlayerType *player_ptr, DEPTH level);
 void leave_quest_check(PlayerType *player_ptr);
 void leave_tower_check(PlayerType *player_ptr);
 void exe_enter_quest(PlayerType *player_ptr, QuestId quest_idx);
index 7081ecc..c5b623d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include "util/flag-group.h"
 
 enum class AttributeType : int {
index 608c822..9c0f7ec 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * project()関数に用いられる、遠隔攻撃特性ビットフラグ / Bit flags for the "project()" function
index bf90389..9a4333d 100644 (file)
@@ -1,5 +1,4 @@
-#include "effect/effect-feature.h"
-#include "core/player-update-types.h"
+#include "effect/effect-feature.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h" // 暫定、後で消す.
 #include "player/special-defense-types.h"
 #include "room/door-definition.h"
 #include "spell-class/spells-mirror-master.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
  * Line 2 -- forbid monsters
  * Line 3 -- forbid the player
  */
-static bool cave_naked_bold(PlayerType *player_ptr, POSITION y, POSITION x)
+static bool cave_naked_bold(PlayerType *player_ptr, const Pos2D &pos)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    return cave_clean_bold(floor_ptr, y, x) && (floor_ptr->grid_array[y][x].m_idx == 0) && !player_bold(player_ptr, y, x);
+    return cave_clean_bold(floor_ptr, pos.y, pos.x) && (floor_ptr->get_grid(pos).m_idx == 0) && !player_ptr->is_located_at(pos);
 }
 
 /*!
@@ -68,17 +69,18 @@ static bool cave_naked_bold(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType typ)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    const Pos2D pos(y, x);
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &grid = floor.get_grid(pos);
+    const auto &terrain = grid.get_terrain();
 
-    bool obvious = false;
-    bool known = player_has_los_bold(player_ptr, y, x);
+    auto obvious = false;
+    auto known = grid.has_los();
 
     who = who ? who : 0;
     dam = (dam + r) / (r + 1);
 
-    if (f_ptr->flags.has(TerrainCharacteristics::TREE)) {
+    if (terrain.flags.has(TerrainCharacteristics::TREE)) {
         concptr message;
         switch (typ) {
         case AttributeType::POIS:
@@ -127,7 +129,7 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
             cave_set_feat(player_ptr, y, x, one_in_(3) ? feat_brake : feat_grass);
 
             /* Observe */
-            if (g_ptr->is_mark()) {
+            if (grid.is_mark()) {
                 obvious = true;
             }
         }
@@ -169,14 +171,14 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
         break;
     }
     case AttributeType::KILL_TRAP: {
-        if (is_hidden_door(player_ptr, g_ptr)) {
+        if (is_hidden_door(player_ptr, grid)) {
             disclose_grid(player_ptr, y, x);
             if (known) {
                 obvious = true;
             }
         }
 
-        if (is_trap(player_ptr, g_ptr->feat)) {
+        if (is_trap(player_ptr, grid.feat)) {
             if (known) {
                 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
                 obvious = true;
@@ -185,26 +187,26 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
             cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::DISARM);
         }
 
-        if (is_closed_door(player_ptr, g_ptr->feat) && f_ptr->power && f_ptr->flags.has(TerrainCharacteristics::OPEN)) {
-            FEAT_IDX old_feat = g_ptr->feat;
+        if (is_closed_door(player_ptr, grid.feat) && terrain.power && terrain.flags.has(TerrainCharacteristics::OPEN)) {
+            FEAT_IDX old_feat = grid.feat;
             cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::DISARM);
-            if (known && (old_feat != g_ptr->feat)) {
+            if (known && (old_feat != grid.feat)) {
                 msg_print(_("カチッと音がした!", "Click!"));
                 obvious = true;
             }
         }
 
-        if (player_ptr->effects()->blindness()->is_blind() || !player_has_los_bold(player_ptr, y, x)) {
+        if (player_ptr->effects()->blindness()->is_blind() || !grid.has_los()) {
             break;
         }
 
-        g_ptr->info &= ~(CAVE_UNSAFE);
+        grid.info &= ~(CAVE_UNSAFE);
         lite_spot(player_ptr, y, x);
         obvious = true;
         break;
     }
     case AttributeType::KILL_DOOR: {
-        if (is_trap(player_ptr, g_ptr->feat) || f_ptr->flags.has(TerrainCharacteristics::DOOR)) {
+        if (is_trap(player_ptr, grid.feat) || terrain.flags.has(TerrainCharacteristics::DOOR)) {
             if (known) {
                 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
                 obvious = true;
@@ -213,107 +215,107 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
             cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::TUNNEL);
         }
 
-        if (player_ptr->effects()->blindness()->is_blind() || !player_has_los_bold(player_ptr, y, x)) {
+        if (player_ptr->effects()->blindness()->is_blind() || !grid.has_los()) {
             break;
         }
 
-        g_ptr->info &= ~(CAVE_UNSAFE);
+        grid.info &= ~(CAVE_UNSAFE);
         lite_spot(player_ptr, y, x);
         obvious = true;
         break;
     }
     case AttributeType::JAM_DOOR: {
-        if (f_ptr->flags.has_not(TerrainCharacteristics::SPIKE)) {
+        if (terrain.flags.has_not(TerrainCharacteristics::SPIKE)) {
             break;
         }
 
-        int16_t old_mimic = g_ptr->mimic;
-        TerrainType *mimic_f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
+        int16_t old_mimic = grid.mimic;
+        const auto &terrain_mimic = grid.get_terrain_mimic();
 
         cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::SPIKE);
-        g_ptr->mimic = old_mimic;
+        grid.mimic = old_mimic;
 
         note_spot(player_ptr, y, x);
         lite_spot(player_ptr, y, x);
 
-        if (!known || mimic_f_ptr->flags.has_not(TerrainCharacteristics::OPEN)) {
+        if (!known || terrain_mimic.flags.has_not(TerrainCharacteristics::OPEN)) {
             break;
         }
 
-        msg_format(_("%sに何かがつっかえて開かなくなった。", "The %s seems stuck."), mimic_f_ptr->name.data());
+        msg_format(_("%sに何かがつっかえて開かなくなった。", "The %s seems stuck."), terrain_mimic.name.data());
         obvious = true;
         break;
     }
     case AttributeType::KILL_WALL: {
-        if (f_ptr->flags.has_not(TerrainCharacteristics::HURT_ROCK)) {
+        if (terrain.flags.has_not(TerrainCharacteristics::HURT_ROCK)) {
             break;
         }
 
-        if (known && g_ptr->is_mark()) {
-            msg_format(_("%sが溶けて泥になった!", "The %s turns into mud!"), terrains_info[g_ptr->get_feat_mimic()].name.data());
+        if (known && grid.is_mark()) {
+            msg_format(_("%sが溶けて泥になった!", "The %s turns into mud!"), grid.get_terrain_mimic().name.data());
             obvious = true;
         }
 
         cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_ROCK);
-        player_ptr->update |= (PU_FLOW);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
         break;
     }
     case AttributeType::MAKE_DOOR: {
-        if (!cave_naked_bold(player_ptr, y, x)) {
+        if (!cave_naked_bold(player_ptr, pos)) {
             break;
         }
-        if (player_bold(player_ptr, y, x)) {
+        if (player_ptr->is_located_at(pos)) {
             break;
         }
         cave_set_feat(player_ptr, y, x, feat_door[DOOR_DOOR].closed);
-        if (g_ptr->is_mark()) {
+        if (grid.is_mark()) {
             obvious = true;
         }
         break;
     }
     case AttributeType::MAKE_TRAP: {
-        place_trap(player_ptr, y, x);
+        place_trap(&floor, y, x);
         break;
     }
     case AttributeType::MAKE_TREE: {
-        if (!cave_naked_bold(player_ptr, y, x)) {
+        if (!cave_naked_bold(player_ptr, pos)) {
             break;
         }
-        if (player_bold(player_ptr, y, x)) {
+        if (player_ptr->is_located_at(pos)) {
             break;
         }
         cave_set_feat(player_ptr, y, x, feat_tree);
-        if (g_ptr->is_mark()) {
+        if (grid.is_mark()) {
             obvious = true;
         }
         break;
     }
     case AttributeType::MAKE_RUNE_PROTECTION: {
-        if (!cave_naked_bold(player_ptr, y, x)) {
+        if (!cave_naked_bold(player_ptr, pos)) {
             break;
         }
-        g_ptr->info |= CAVE_OBJECT;
-        g_ptr->mimic = feat_rune_protection;
+        grid.info |= CAVE_OBJECT;
+        grid.mimic = feat_rune_protection;
         note_spot(player_ptr, y, x);
         lite_spot(player_ptr, y, x);
         break;
     }
     case AttributeType::STONE_WALL: {
-        if (!cave_naked_bold(player_ptr, y, x)) {
+        if (!cave_naked_bold(player_ptr, pos)) {
             break;
         }
-        if (player_bold(player_ptr, y, x)) {
+        if (player_ptr->is_located_at(pos)) {
             break;
         }
         cave_set_feat(player_ptr, y, x, feat_granite);
         break;
     }
     case AttributeType::LAVA_FLOW: {
-        if (f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
+        if (terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
             break;
         }
         if (dam == 1) {
-            if (f_ptr->flags.has_not(TerrainCharacteristics::FLOOR)) {
+            if (terrain.flags.has_not(TerrainCharacteristics::FLOOR)) {
                 break;
             }
             cave_set_feat(player_ptr, y, x, feat_shallow_lava);
@@ -324,11 +326,11 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
         break;
     }
     case AttributeType::WATER_FLOW: {
-        if (f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
+        if (terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
             break;
         }
         if (dam == 1) {
-            if (f_ptr->flags.has_not(TerrainCharacteristics::FLOOR)) {
+            if (terrain.flags.has_not(TerrainCharacteristics::FLOOR)) {
                 break;
             }
             cave_set_feat(player_ptr, y, x, feat_shallow_water);
@@ -340,11 +342,11 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
     }
     case AttributeType::LITE_WEAK:
     case AttributeType::LITE: {
-        if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+        if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
             break;
         }
 
-        g_ptr->info |= (CAVE_GLOW);
+        grid.info |= (CAVE_GLOW);
         note_spot(player_ptr, y, x);
         lite_spot(player_ptr, y, x);
         update_local_illumination(player_ptr, y, x);
@@ -352,11 +354,11 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
         if (player_can_see_bold(player_ptr, y, x)) {
             obvious = true;
         }
-        if (g_ptr->m_idx) {
-            update_monster(player_ptr, g_ptr->m_idx, false);
+        if (grid.m_idx) {
+            update_monster(player_ptr, grid.m_idx, false);
         }
 
-        if (player_bold(player_ptr, y, x)) {
+        if (player_ptr->is_located_at(pos)) {
             set_superstealth(player_ptr, false);
         }
 
@@ -365,22 +367,20 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
     case AttributeType::DARK_WEAK:
     case AttributeType::DARK:
     case AttributeType::ABYSS: {
-        bool do_dark = !player_ptr->phase_out && !g_ptr->is_mirror();
+        auto do_dark = !AngbandSystem::get_instance().is_phase_out() && !grid.is_mirror();
         if (!do_dark) {
             break;
         }
 
-        if ((floor_ptr->dun_level > 0) || !is_daytime()) {
+        if ((floor.dun_level > 0) || !w_ptr->is_daytime()) {
             for (int j = 0; j < 9; j++) {
-                int by = y + ddy_ddd[j];
-                int bx = x + ddx_ddd[j];
-
-                if (!in_bounds2(floor_ptr, by, bx)) {
+                const Pos2D pos_neighbor(y + ddy_ddd[j], x + ddx_ddd[j]);
+                if (!in_bounds2(&floor, pos_neighbor.y, pos_neighbor.x)) {
                     continue;
                 }
 
-                grid_type *cc_ptr = &floor_ptr->grid_array[by][bx];
-                if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(TerrainCharacteristics::GLOW)) {
+                const auto &grid_neighbor = floor.get_grid(pos_neighbor);
+                if (grid_neighbor.get_terrain_mimic().flags.has(TerrainCharacteristics::GLOW)) {
                     do_dark = false;
                     break;
                 }
@@ -391,12 +391,12 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
             }
         }
 
-        g_ptr->info &= ~(CAVE_GLOW);
+        grid.info &= ~(CAVE_GLOW);
 
         /* Hack -- Forget "boring" grids */
-        if (f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER) || has_element_resist(player_ptr, ElementRealmType::DARKNESS, 1)) {
+        if (terrain.flags.has_not(TerrainCharacteristics::REMEMBER) || has_element_resist(player_ptr, ElementRealmType::DARKNESS, 1)) {
             /* Forget */
-            g_ptr->info &= ~(CAVE_MARK);
+            grid.info &= ~(CAVE_MARK);
             note_spot(player_ptr, y, x);
         }
 
@@ -407,15 +407,15 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
         if (player_can_see_bold(player_ptr, y, x)) {
             obvious = true;
         }
-        if (g_ptr->m_idx) {
-            update_monster(player_ptr, g_ptr->m_idx, false);
+        if (grid.m_idx) {
+            update_monster(player_ptr, grid.m_idx, false);
         }
 
         break;
     }
     case AttributeType::SHARDS:
     case AttributeType::ROCKET: {
-        if (g_ptr->is_mirror()) {
+        if (grid.is_mirror()) {
             msg_print(_("鏡が割れた!", "The mirror was shattered!"));
             sound(SOUND_GLASS);
             SpellsMirrorMaster(player_ptr).remove_mirror(y, x);
@@ -423,21 +423,21 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI));
         }
 
-        if (f_ptr->flags.has_not(TerrainCharacteristics::GLASS) || f_ptr->flags.has(TerrainCharacteristics::PERMANENT) || (dam < 50)) {
+        if (terrain.flags.has_not(TerrainCharacteristics::GLASS) || terrain.flags.has(TerrainCharacteristics::PERMANENT) || (dam < 50)) {
             break;
         }
 
-        if (known && (g_ptr->is_mark())) {
-            msg_format(_("%sが割れた!", "The %s crumbled!"), terrains_info[g_ptr->get_feat_mimic()].name.data());
+        if (known && (grid.is_mark())) {
+            msg_format(_("%sが割れた!", "The %s crumbled!"), grid.get_terrain_mimic().name.data());
             sound(SOUND_GLASS);
         }
 
         cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_ROCK);
-        player_ptr->update |= (PU_FLOW);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
         break;
     }
     case AttributeType::SOUND: {
-        if (g_ptr->is_mirror() && player_ptr->lev < 40) {
+        if (grid.is_mirror() && player_ptr->lev < 40) {
             msg_print(_("鏡が割れた!", "The mirror was shattered!"));
             sound(SOUND_GLASS);
             SpellsMirrorMaster(player_ptr).remove_mirror(y, x);
@@ -445,30 +445,30 @@ bool affect_feature(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITIO
                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI));
         }
 
-        if (f_ptr->flags.has_not(TerrainCharacteristics::GLASS) || f_ptr->flags.has(TerrainCharacteristics::PERMANENT) || (dam < 200)) {
+        if (terrain.flags.has_not(TerrainCharacteristics::GLASS) || terrain.flags.has(TerrainCharacteristics::PERMANENT) || (dam < 200)) {
             break;
         }
 
-        if (known && (g_ptr->is_mark())) {
-            msg_format(_("%sが割れた!", "The %s crumbled!"), terrains_info[g_ptr->get_feat_mimic()].name.data());
+        if (known && (grid.is_mark())) {
+            msg_format(_("%sが割れた!", "The %s crumbled!"), grid.get_terrain_mimic().name.data());
             sound(SOUND_GLASS);
         }
 
         cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_ROCK);
-        player_ptr->update |= (PU_FLOW);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
         break;
     }
     case AttributeType::DISINTEGRATE: {
-        if (g_ptr->is_mirror() || g_ptr->is_rune_protection() || g_ptr->is_rune_explosion()) {
+        if (grid.is_mirror() || grid.is_rune_protection() || grid.is_rune_explosion()) {
             SpellsMirrorMaster(player_ptr).remove_mirror(y, x);
         }
 
-        if (f_ptr->flags.has_not(TerrainCharacteristics::HURT_DISI) || f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
+        if (terrain.flags.has_not(TerrainCharacteristics::HURT_DISI) || terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
             break;
         }
 
         cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_DISI);
-        player_ptr->update |= (PU_FLOW);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
         break;
     }
     default:
index 57669aa..ccb8245 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index 2fefe3e..08ccd22 100644 (file)
@@ -1,8 +1,7 @@
-#include "effect/effect-item.h"
+#include "effect/effect-item.h"
 #include "autopick/autopick.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
-#include "floor/cave.h"
 #include "floor/floor-object.h"
 #include "grid/grid.h"
 #include "monster-floor/monster-summon.h"
@@ -11,9 +10,7 @@
 #include "object-enchant/tr-types.h"
 #include "object-hook/hook-expendable.h"
 #include "object/object-broken.h"
-#include "object/object-flags.h"
 #include "object/object-mark-types.h"
-#include "perception/object-perception.h"
 #include "spell-kind/spells-perception.h"
 #include "sv-definition/sv-other-types.h"
 #include "sv-definition/sv-scroll-types.h"
  */
 bool affect_item(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType typ)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(y, x);
+    const auto &grid = floor.get_grid(pos);
 
-    bool is_item_affected = false;
-    bool known = player_has_los_bold(player_ptr, y, x);
+    auto is_item_affected = false;
+    const auto known = grid.has_los();
     who = who ? who : 0;
     dam = (dam + r) / (r + 1);
     std::set<OBJECT_IDX> processed_list;
-    for (auto it = g_ptr->o_idx_list.begin(); it != g_ptr->o_idx_list.end();) {
+    for (auto it = grid.o_idx_list.begin(); it != grid.o_idx_list.end();) {
         const OBJECT_IDX this_o_idx = *it++;
 
         if (auto pit = processed_list.find(this_o_idx); pit != processed_list.end()) {
@@ -64,7 +63,7 @@ bool affect_item(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y
 #else
         bool plural = (o_ptr->number > 1);
 #endif
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
         bool is_fixed_or_random_artifact = o_ptr->is_fixed_or_random_artifact();
         switch (typ) {
         case AttributeType::ACID: {
@@ -214,7 +213,7 @@ bool affect_item(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y
             }
 
             o_ptr->pval = (0 - o_ptr->pval);
-            object_known(o_ptr);
+            o_ptr->mark_as_known();
             if (known && o_ptr->marked.has(OmType::FOUND)) {
                 msg_print(_("カチッと音がした!", "Click!"));
                 is_item_affected = true;
@@ -234,7 +233,7 @@ bool affect_item(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y
 
             for (int i = 0; i < o_ptr->number; i++) {
                 auto corpse_r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
-                const auto sval = o_ptr->bi_key.sval().value();
+                const auto sval = *o_ptr->bi_key.sval();
                 if (((sval == SV_CORPSE) && (randint1(100) > 80)) || ((sval == SV_SKELETON) && (randint1(100) > 60))) {
                     if (!note_kill) {
                         note_kill = _("灰になった。", (plural ? " become dust." : " becomes dust."));
@@ -278,15 +277,15 @@ bool affect_item(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y
             msg_format(_("%sは%s", "The %s%s"), item_name.data(), note_kill);
         }
 
-        short bi_id = o_ptr->bi_id;
-        bool is_potion = o_ptr->is_potion();
+        const auto bi_id = o_ptr->bi_id;
+        const auto is_potion = o_ptr->is_potion();
         delete_object_idx(player_ptr, this_o_idx);
         if (is_potion) {
             (void)potion_smash_effect(player_ptr, who, y, x, bi_id);
 
             // 薬の破壊効果によりリストの次のアイテムが破壊された可能性があるのでリストの最初から処理をやり直す
             // 処理済みのアイテムは processed_list に登録されており、スキップされる
-            it = g_ptr->o_idx_list.begin();
+            it = grid.o_idx_list.begin();
         }
 
         lite_spot(player_ptr, y, x);
index 58ca734..9776f98 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index 8113aa9..2bbc19a 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-monster-charm.h"
+#include "effect/effect-monster-charm.h"
 #include "avatar/avatar.h"
 #include "dungeon/quest.h"
 #include "effect/effect-monster-util.h"
@@ -31,7 +31,7 @@
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
-static void effect_monster_charm_resist(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_charm_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr)) {
         em_ptr->note = _("には効果がなかった。", " is unaffected.");
@@ -56,7 +56,7 @@ static void effect_monster_charm_resist(PlayerType *player_ptr, effect_monster_t
     }
 }
 
-ProcessResult effect_monster_charm(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_charm(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     int vir = virtue_number(player_ptr, Virtue::HARMONY);
     if (vir) {
@@ -77,7 +77,7 @@ ProcessResult effect_monster_charm(PlayerType *player_ptr, effect_monster_type *
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_control_undead(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_control_undead(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -113,7 +113,7 @@ ProcessResult effect_monster_control_undead(PlayerType *player_ptr, effect_monst
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_control_demon(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_control_demon(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -149,7 +149,7 @@ ProcessResult effect_monster_control_demon(PlayerType *player_ptr, effect_monste
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_control_animal(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_control_animal(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -188,7 +188,7 @@ ProcessResult effect_monster_control_animal(PlayerType *player_ptr, effect_monst
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_charm_living(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_charm_living(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     int vir = virtue_number(player_ptr, Virtue::UNLIFE);
     if (em_ptr->seen) {
@@ -207,7 +207,7 @@ ProcessResult effect_monster_charm_living(PlayerType *player_ptr, effect_monster
 
     msg_format(_("%sを見つめた。", "You stare at %s."), em_ptr->m_name);
 
-    if (common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr) || !monster_living(em_ptr->m_ptr->r_idx)) {
+    if (common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr) || !em_ptr->m_ptr->has_living_flag()) {
         em_ptr->note = _("には効果がなかった。", " is unaffected.");
         em_ptr->obvious = false;
         if (one_in_(4)) {
@@ -230,7 +230,7 @@ ProcessResult effect_monster_charm_living(PlayerType *player_ptr, effect_monster
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     BadStatusSetter bss(player_ptr);
     switch (randint1(4)) {
@@ -241,7 +241,7 @@ static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr,
         (void)bss.mod_confusion(em_ptr->dam / 2);
         return;
     default:
-        if (any_bits(em_ptr->r_ptr->flags3, RF3_NO_FEAR)) {
+        if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
             em_ptr->note = _("には効果がなかった。", " is unaffected.");
         } else {
             (void)bss.mod_fear(static_cast<TIME_EFFECT>(em_ptr->dam));
@@ -252,7 +252,7 @@ static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr,
 }
 
 // Powerful demons & undead can turn a mindcrafter's attacks back on them.
-static void effect_monster_domination_corrupted(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_domination_corrupted(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     bool is_corrupted = em_ptr->r_ptr->kind_flags.has_any_of(has_corrupted_mind) && (em_ptr->r_ptr->level > player_ptr->lev / 2) && (one_in_(2));
     if (!is_corrupted) {
@@ -261,7 +261,7 @@ static void effect_monster_domination_corrupted(PlayerType *player_ptr, effect_m
         return;
     }
 
-    em_ptr->note = nullptr;
+    em_ptr->note = "";
     msg_format(_("%s^の堕落した精神は攻撃を跳ね返した!",
                    (em_ptr->seen ? "%s^'s corrupted mind backlashes your attack!" : "%s^s corrupted mind backlashes your attack!")),
         em_ptr->m_name);
@@ -273,7 +273,7 @@ static void effect_monster_domination_corrupted(PlayerType *player_ptr, effect_m
     effect_monster_domination_corrupted_addition(player_ptr, em_ptr);
 }
 
-static void effect_monster_domination_addition(effect_monster_type *em_ptr)
+static void effect_monster_domination_addition(EffectMonster *em_ptr)
 {
     switch (randint1(4)) {
     case 1:
@@ -287,7 +287,7 @@ static void effect_monster_domination_addition(effect_monster_type *em_ptr)
     }
 }
 
-ProcessResult effect_monster_domination(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_domination(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (!em_ptr->m_ptr->is_hostile()) {
         return ProcessResult::PROCESS_CONTINUE;
@@ -299,10 +299,10 @@ ProcessResult effect_monster_domination(PlayerType *player_ptr, effect_monster_t
 
     const auto is_unique = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
     const auto is_questor = any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR);
-    const auto is_no_confusion = any_bits(em_ptr->r_ptr->flags3, RF3_NO_CONF);
+    const auto is_no_confusion = em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF);
     if (is_unique || is_questor || is_no_confusion || (em_ptr->r_ptr->level > randint1((em_ptr->dam - 10) < 1 ? 1 : (em_ptr->dam - 10)) + 10)) {
-        if (((em_ptr->r_ptr->flags3 & RF3_NO_CONF) != 0) && is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-            em_ptr->r_ptr->r_flags3 |= (RF3_NO_CONF);
+        if ((em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) && is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
+            em_ptr->r_ptr->resistance_flags.set(MonsterResistanceType::NO_CONF);
         }
 
         em_ptr->do_conf = 0;
@@ -323,13 +323,13 @@ ProcessResult effect_monster_domination(PlayerType *player_ptr, effect_monster_t
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-static bool effect_monster_crusade_domination(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool effect_monster_crusade_domination(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if ((em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::GOOD)) || player_ptr->current_floor_ptr->inside_arena) {
         return false;
     }
 
-    if (em_ptr->r_ptr->flags3 & RF3_NO_CONF) {
+    if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
         em_ptr->dam -= 50;
     }
     if (em_ptr->dam < 1) {
@@ -366,7 +366,7 @@ static bool effect_monster_crusade_domination(PlayerType *player_ptr, effect_mon
     return true;
 }
 
-ProcessResult effect_monster_crusade(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_crusade(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -377,10 +377,10 @@ ProcessResult effect_monster_crusade(PlayerType *player_ptr, effect_monster_type
         return ProcessResult::PROCESS_CONTINUE;
     }
 
-    if ((em_ptr->r_ptr->flags3 & RF3_NO_FEAR) == 0) {
+    if (em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::NO_FEAR)) {
         em_ptr->do_fear = randint1(90) + 10;
     } else if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-        em_ptr->r_ptr->r_flags3 |= RF3_NO_FEAR;
+        em_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_FEAR);
     }
 
     em_ptr->dam = 0;
@@ -400,7 +400,7 @@ static int calcutate_capturable_hp(PlayerType *player_ptr, MonsterEntity *m_ptr,
         return hp * 4L;
     }
 
-    if (PlayerClass(player_ptr).equals(PlayerClassType::BEASTMASTER) && monster_living(m_ptr->r_idx)) {
+    if (PlayerClass(player_ptr).equals(PlayerClassType::BEASTMASTER) && m_ptr->has_living_flag()) {
         return hp * 3 / 10;
     }
 
@@ -412,14 +412,14 @@ static int calcutate_capturable_hp(PlayerType *player_ptr, MonsterEntity *m_ptr,
  * @param player_ptr プレイヤー情報への参照ポインタ
  * @param em_ptr 効果情報への参照ポインタ
  */
-static void effect_monster_captured(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> tmp_cap_mon_ptr)
+static void effect_monster_captured(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> tmp_cap_mon_ptr)
 {
     if (em_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON)) {
         choose_new_monster(player_ptr, em_ptr->g_ptr->m_idx, false, MonsterRaceId::CHAMELEON);
     }
 
     msg_format(_("%sを捕えた!", "You capture %s^!"), em_ptr->m_name);
-    auto cap_mon_ptr = tmp_cap_mon_ptr.value();
+    auto cap_mon_ptr = *tmp_cap_mon_ptr;
     cap_mon_ptr->r_idx = em_ptr->m_ptr->r_idx;
     cap_mon_ptr->speed = em_ptr->m_ptr->mspeed;
     cap_mon_ptr->current_hp = static_cast<short>(em_ptr->m_ptr->hp);
@@ -439,12 +439,12 @@ static void effect_monster_captured(PlayerType *player_ptr, effect_monster_type
  * @param em_ptr 効果情報への参照ポインタ
  * @return 効果発動結果
  */
-ProcessResult effect_monster_capture(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
+ProcessResult effect_monster_capture(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
 {
     const auto &quest_list = QuestList::get_instance();
     auto *floor_ptr = player_ptr->current_floor_ptr;
 
-    auto quest_monster = inside_quest(floor_ptr->quest_number);
+    auto quest_monster = floor_ptr->is_in_quest();
     quest_monster &= (quest_list[floor_ptr->quest_number].type == QuestKindType::KILL_ALL);
     quest_monster &= !em_ptr->m_ptr->is_pet();
 
@@ -452,7 +452,7 @@ ProcessResult effect_monster_capture(PlayerType *player_ptr, effect_monster_type
     cannot_capture |= em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
     cannot_capture |= any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR);
     cannot_capture |= em_ptr->r_ptr->population_flags.has(MonsterPopulationType::NAZGUL);
-    cannot_capture |= any_bits(em_ptr->r_ptr->flags7, RF7_UNIQUE2);
+    cannot_capture |= em_ptr->r_ptr->population_flags.has(MonsterPopulationType::ONLY_ONE);
     cannot_capture |= (em_ptr->m_ptr->parent_m_idx != 0);
     if (cannot_capture) {
         msg_format(_("%sには効果がなかった。", "%s is unaffected."), em_ptr->m_name);
index b050120..77f174b 100644 (file)
@@ -1,17 +1,17 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <optional>
 
 enum class ProcessResult;
-struct effect_monster_type;
+class EffectMonster;
 class CapturedMonsterType;
 class PlayerType;
-ProcessResult effect_monster_charm(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_control_undead(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_control_demon(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_control_animal(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_charm_living(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_domination(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_crusade(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_capture(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr);
+ProcessResult effect_monster_charm(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_control_undead(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_control_demon(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_control_animal(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_charm_living(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_domination(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_crusade(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_capture(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr);
index 61ac898..a69cd78 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-monster-curse.h"
+#include "effect/effect-monster-curse.h"
 #include "effect/effect-monster-util.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-indice-types.h"
@@ -6,7 +6,7 @@
 #include "system/monster-race-info.h"
 #include "view/display-messages.h"
 
-ProcessResult effect_monster_curse_1(effect_monster_type *em_ptr)
+ProcessResult effect_monster_curse_1(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -22,7 +22,7 @@ ProcessResult effect_monster_curse_1(effect_monster_type *em_ptr)
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_curse_2(effect_monster_type *em_ptr)
+ProcessResult effect_monster_curse_2(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -39,7 +39,7 @@ ProcessResult effect_monster_curse_2(effect_monster_type *em_ptr)
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_curse_3(effect_monster_type *em_ptr)
+ProcessResult effect_monster_curse_3(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -56,7 +56,7 @@ ProcessResult effect_monster_curse_3(effect_monster_type *em_ptr)
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_curse_4(effect_monster_type *em_ptr)
+ProcessResult effect_monster_curse_4(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
index 31c46e0..d50f472 100644 (file)
@@ -1,9 +1,9 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-struct effect_monster_type;
-ProcessResult effect_monster_curse_1(effect_monster_type *em_ptr);
-ProcessResult effect_monster_curse_2(effect_monster_type *em_ptr);
-ProcessResult effect_monster_curse_3(effect_monster_type *em_ptr);
-ProcessResult effect_monster_curse_4(effect_monster_type *em_ptr);
+class EffectMonster;
+ProcessResult effect_monster_curse_1(EffectMonster *em_ptr);
+ProcessResult effect_monster_curse_2(EffectMonster *em_ptr);
+ProcessResult effect_monster_curse_3(EffectMonster *em_ptr);
+ProcessResult effect_monster_curse_4(EffectMonster *em_ptr);
index 39b090b..f425478 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-monster-evil.h"
+#include "effect/effect-monster-evil.h"
 #include "effect/effect-monster-util.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
@@ -10,7 +10,7 @@
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 
-static bool effect_monster_away_resist(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool effect_monster_away_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_TELEPORT)) {
         return false;
@@ -35,7 +35,7 @@ static bool effect_monster_away_resist(PlayerType *player_ptr, effect_monster_ty
     return false;
 }
 
-ProcessResult effect_monster_away_undead(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_away_undead(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD)) {
         em_ptr->skipped = true;
@@ -59,7 +59,7 @@ ProcessResult effect_monster_away_undead(PlayerType *player_ptr, effect_monster_
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_away_evil(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_away_evil(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::EVIL)) {
         em_ptr->skipped = true;
@@ -83,7 +83,7 @@ ProcessResult effect_monster_away_evil(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_away_all(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_away_all(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     bool resists_tele = effect_monster_away_resist(player_ptr, em_ptr);
     if (!resists_tele) {
@@ -98,7 +98,7 @@ ProcessResult effect_monster_away_all(PlayerType *player_ptr, effect_monster_typ
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_turn_undead(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_turn_undead(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD)) {
         em_ptr->skipped = true;
@@ -125,7 +125,7 @@ ProcessResult effect_monster_turn_undead(PlayerType *player_ptr, effect_monster_
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_turn_evil(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_turn_evil(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::EVIL)) {
         em_ptr->skipped = true;
@@ -152,7 +152,7 @@ ProcessResult effect_monster_turn_evil(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_turn_all(effect_monster_type *em_ptr)
+ProcessResult effect_monster_turn_all(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -160,7 +160,7 @@ ProcessResult effect_monster_turn_all(effect_monster_type *em_ptr)
 
     em_ptr->do_fear = damroll(3, (em_ptr->dam / 2)) + 1;
     if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) ||
-        (em_ptr->r_ptr->flags3 & (RF3_NO_FEAR)) ||
+        em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR) ||
         (em_ptr->r_ptr->level > randint1((em_ptr->dam - 10) < 1 ? 1 : (em_ptr->dam - 10)) + 10)) {
         em_ptr->note = _("には効果がなかった。", " is unaffected.");
         em_ptr->obvious = false;
@@ -171,7 +171,7 @@ ProcessResult effect_monster_turn_all(effect_monster_type *em_ptr)
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_disp_undead(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_disp_undead(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD)) {
         em_ptr->skipped = true;
@@ -192,7 +192,7 @@ ProcessResult effect_monster_disp_undead(PlayerType *player_ptr, effect_monster_
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_disp_evil(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_disp_evil(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::EVIL)) {
         em_ptr->skipped = true;
@@ -213,7 +213,7 @@ ProcessResult effect_monster_disp_evil(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_disp_good(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_disp_good(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::GOOD)) {
         em_ptr->skipped = true;
@@ -234,9 +234,9 @@ ProcessResult effect_monster_disp_good(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_disp_living(effect_monster_type *em_ptr)
+ProcessResult effect_monster_disp_living(EffectMonster *em_ptr)
 {
-    if (!monster_living(em_ptr->m_ptr->r_idx)) {
+    if (!em_ptr->m_ptr->has_living_flag()) {
         em_ptr->skipped = true;
         em_ptr->dam = 0;
         return ProcessResult::PROCESS_CONTINUE;
@@ -251,7 +251,7 @@ ProcessResult effect_monster_disp_living(effect_monster_type *em_ptr)
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_disp_demon(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_disp_demon(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::DEMON)) {
         em_ptr->skipped = true;
@@ -272,7 +272,7 @@ ProcessResult effect_monster_disp_demon(PlayerType *player_ptr, effect_monster_t
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_disp_all(effect_monster_type *em_ptr)
+ProcessResult effect_monster_disp_all(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
index cff8530..fa380d7 100644 (file)
@@ -1,18 +1,18 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-struct effect_monster_type;
+class EffectMonster;
 class PlayerType;
-ProcessResult effect_monster_away_undead(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_away_evil(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_away_all(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_turn_undead(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_turn_evil(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_turn_all(effect_monster_type *em_ptr);
-ProcessResult effect_monster_disp_undead(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_disp_evil(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_disp_good(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_disp_living(effect_monster_type *em_ptr);
-ProcessResult effect_monster_disp_demon(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_disp_all(effect_monster_type *em_ptr);
+ProcessResult effect_monster_away_undead(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_away_evil(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_away_all(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_turn_undead(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_turn_evil(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_turn_all(EffectMonster *em_ptr);
+ProcessResult effect_monster_disp_undead(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_disp_evil(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_disp_good(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_disp_living(EffectMonster *em_ptr);
+ProcessResult effect_monster_disp_demon(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_disp_all(EffectMonster *em_ptr);
index 61f155f..0955ae5 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-monster-lite-dark.h"
+#include "effect/effect-monster-lite-dark.h"
 #include "effect/effect-monster-util.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags-resistance.h"
@@ -7,7 +7,7 @@
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 
-ProcessResult effect_monster_lite_weak(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_lite_weak(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (!em_ptr->dam) {
         em_ptr->skipped = true;
@@ -32,7 +32,7 @@ ProcessResult effect_monster_lite_weak(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_lite(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_lite(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -58,7 +58,7 @@ ProcessResult effect_monster_lite(PlayerType *player_ptr, effect_monster_type *e
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_dark(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_dark(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
index 6d92803..09d67a9 100644 (file)
@@ -1,9 +1,9 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-struct effect_monster_type;
+class EffectMonster;
 class PlayerType;
-ProcessResult effect_monster_lite_weak(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_lite(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_dark(PlayerType *player_ptr, effect_monster_type *em_ptr);
+ProcessResult effect_monster_lite_weak(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_lite(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_dark(PlayerType *player_ptr, EffectMonster *em_ptr);
index da469b6..e07838d 100644 (file)
@@ -1,6 +1,5 @@
-#include "effect/effect-monster-oldies.h"
+#include "effect/effect-monster-oldies.h"
 #include "avatar/avatar.h"
-#include "core/player-redraw-types.h"
 #include "effect/effect-monster-util.h"
 #include "monster-floor/monster-generator.h"
 #include "monster-race/monster-race.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
 // Powerful monsters can resist.
-ProcessResult effect_monster_old_poly(effect_monster_type *em_ptr)
+ProcessResult effect_monster_old_poly(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -41,18 +41,17 @@ ProcessResult effect_monster_old_poly(effect_monster_type *em_ptr)
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_old_clone(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_old_clone(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
     }
 
-    bool has_resistance = (player_ptr->current_floor_ptr->inside_arena);
+    auto has_resistance = (player_ptr->current_floor_ptr->inside_arena);
     has_resistance |= em_ptr->m_ptr->is_pet();
     has_resistance |= em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
     has_resistance |= any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR);
-    has_resistance |= em_ptr->r_ptr->population_flags.has(MonsterPopulationType::NAZGUL);
-    has_resistance |= any_bits(em_ptr->r_ptr->flags7, RF7_UNIQUE2);
+    has_resistance |= em_ptr->r_ptr->population_flags.has_any_of({ MonsterPopulationType::NAZGUL, MonsterPopulationType::ONLY_ONE });
 
     if (has_resistance) {
         em_ptr->note = _("には効果がなかった。", " is unaffected.");
@@ -69,7 +68,7 @@ ProcessResult effect_monster_old_clone(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_star_heal(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_star_heal(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -84,12 +83,14 @@ ProcessResult effect_monster_star_heal(PlayerType *player_ptr, effect_monster_ty
         em_ptr->m_ptr->maxhp = em_ptr->m_ptr->max_maxhp;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (!em_ptr->dam) {
         if (player_ptr->health_who == em_ptr->g_ptr->m_idx) {
-            player_ptr->redraw |= (PR_HEALTH);
+            rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
         }
+
         if (player_ptr->riding == em_ptr->g_ptr->m_idx) {
-            player_ptr->redraw |= (PR_UHEALTH);
+            rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
         }
 
         return ProcessResult::PROCESS_FALSE;
@@ -100,7 +101,7 @@ ProcessResult effect_monster_star_heal(PlayerType *player_ptr, effect_monster_ty
 }
 
 // who == 0ならばプレイヤーなので、それの判定.
-static void effect_monster_old_heal_check_player(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_old_heal_check_player(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->who != 0) {
         return;
@@ -126,7 +127,7 @@ static void effect_monster_old_heal_check_player(PlayerType *player_ptr, effect_
     }
 }
 
-static void effect_monster_old_heal_recovery(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_old_heal_recovery(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->m_ptr->get_remaining_stun()) {
         if (em_ptr->seen_msg) {
@@ -153,7 +154,7 @@ static void effect_monster_old_heal_recovery(PlayerType *player_ptr, effect_mons
     }
 }
 
-ProcessResult effect_monster_old_heal(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_old_heal(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -177,11 +178,13 @@ ProcessResult effect_monster_old_heal(PlayerType *player_ptr, effect_monster_typ
         }
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == em_ptr->g_ptr->m_idx) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
+
     if (player_ptr->riding == em_ptr->g_ptr->m_idx) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     em_ptr->note = _("は体力を回復したようだ。", " looks healthier.");
@@ -189,7 +192,7 @@ ProcessResult effect_monster_old_heal(PlayerType *player_ptr, effect_monster_typ
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_old_speed(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_old_speed(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -212,7 +215,7 @@ ProcessResult effect_monster_old_speed(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_old_slow(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_old_slow(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -241,20 +244,20 @@ ProcessResult effect_monster_old_slow(PlayerType *player_ptr, effect_monster_typ
  * @todo 「ユニークは (魔法では)常に眠らない」はMonsterRaceDefinitionの趣旨に反すると思われる
  * 眠る確率を半分にするとかしておいた方が良さそう
  */
-ProcessResult effect_monster_old_sleep(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_old_sleep(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
     }
 
     bool has_resistance = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
-    has_resistance |= any_bits(em_ptr->r_ptr->flags3, RF3_NO_SLEEP);
+    has_resistance |= em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_SLEEP);
     has_resistance |= (em_ptr->r_ptr->level > randint1(std::max(1, em_ptr->dam - 10)) + 10);
 
     if (has_resistance) {
-        if (em_ptr->r_ptr->flags3 & RF3_NO_SLEEP) {
+        if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_SLEEP)) {
             if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-                em_ptr->r_ptr->r_flags3 |= (RF3_NO_SLEEP);
+                em_ptr->r_ptr->resistance_flags.set(MonsterResistanceType::NO_SLEEP);
             }
         }
 
@@ -273,7 +276,7 @@ ProcessResult effect_monster_old_sleep(PlayerType *player_ptr, effect_monster_ty
  * @todo 「ユニークは (魔法では)常に混乱しない」はMonsterRaceDefinitionの趣旨に反すると思われる
  * 眠る確率を半分にするとかしておいた方が良さそう
  */
-ProcessResult effect_monster_old_conf(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_old_conf(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -282,12 +285,12 @@ ProcessResult effect_monster_old_conf(PlayerType *player_ptr, effect_monster_typ
     em_ptr->do_conf = damroll(3, (em_ptr->dam / 2)) + 1;
 
     bool has_resistance = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
-    has_resistance |= any_bits(em_ptr->r_ptr->flags3, RF3_NO_CONF);
+    has_resistance |= em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF);
     has_resistance |= (em_ptr->r_ptr->level > randint1(std::max(1, em_ptr->dam - 10)) + 10);
     if (has_resistance) {
-        if (em_ptr->r_ptr->flags3 & (RF3_NO_CONF)) {
+        if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
             if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-                em_ptr->r_ptr->r_flags3 |= (RF3_NO_CONF);
+                em_ptr->r_ptr->resistance_flags.set(MonsterResistanceType::NO_CONF);
             }
         }
 
@@ -300,7 +303,7 @@ ProcessResult effect_monster_old_conf(PlayerType *player_ptr, effect_monster_typ
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_stasis(effect_monster_type *em_ptr, bool to_evil)
+ProcessResult effect_monster_stasis(EffectMonster *em_ptr, bool to_evil)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -325,7 +328,7 @@ ProcessResult effect_monster_stasis(effect_monster_type *em_ptr, bool to_evil)
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_stun(effect_monster_type *em_ptr)
+ProcessResult effect_monster_stun(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
index 718f8d7..b8494c3 100644 (file)
@@ -1,16 +1,16 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-struct effect_monster_type;
+class EffectMonster;
 class PlayerType;
-ProcessResult effect_monster_old_poly(effect_monster_type *em_ptr);
-ProcessResult effect_monster_old_clone(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_star_heal(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_old_heal(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_old_speed(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_old_slow(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_old_sleep(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_old_conf(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_stasis(effect_monster_type *em_ptr, bool to_evil);
-ProcessResult effect_monster_stun(effect_monster_type *em_ptr);
+ProcessResult effect_monster_old_poly(EffectMonster *em_ptr);
+ProcessResult effect_monster_old_clone(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_star_heal(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_old_heal(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_old_speed(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_old_slow(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_old_sleep(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_old_conf(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_stasis(EffectMonster *em_ptr, bool to_evil);
+ProcessResult effect_monster_stun(EffectMonster *em_ptr);
index fe817f5..f63130d 100644 (file)
@@ -1,5 +1,4 @@
-#include "effect/effect-monster-psi.h"
-#include "core/player-redraw-types.h"
+#include "effect/effect-monster-psi.h"
 #include "core/window-redrawer.h"
 #include "effect/effect-monster-util.h"
 #include "floor/line-of-sight.h"
@@ -19,6 +18,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
@@ -30,7 +30,7 @@
  * @param em_ptr モンスター効果への参照ポインタ
  * @return 完全な耐性を発動した場合TRUE、そうでなければFALSE
  */
-static bool resisted_psi_because_empty_mind(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool resisted_psi_because_empty_mind(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (none_bits(em_ptr->r_ptr->flags2, RF2_EMPTY_MIND)) {
         return false;
@@ -55,7 +55,7 @@ static bool resisted_psi_because_empty_mind(PlayerType *player_ptr, effect_monst
  * 2) ANIMALである
  * 3) レベルが d(3*ダメージ) より大きい
  */
-static bool resisted_psi_because_weird_mind_or_powerful(effect_monster_type *em_ptr)
+static bool resisted_psi_because_weird_mind_or_powerful(EffectMonster *em_ptr)
 {
     bool has_resistance = em_ptr->r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID);
     has_resistance |= any_bits(em_ptr->r_ptr->flags2, RF2_WEIRD_MIND);
@@ -80,7 +80,7 @@ static bool resisted_psi_because_weird_mind_or_powerful(effect_monster_type *em_
  * 1) UNDEADまたはDEMONである
  * 2) レベルが詠唱者の レベル/2 より大きい
  */
-static bool reflects_psi_with_currupted_mind(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool reflects_psi_with_currupted_mind(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     bool is_corrupted = em_ptr->r_ptr->kind_flags.has_any_of(has_corrupted_mind);
     is_corrupted &= (em_ptr->r_ptr->level > player_ptr->lev / 2);
@@ -89,7 +89,7 @@ static bool reflects_psi_with_currupted_mind(PlayerType *player_ptr, effect_mons
         return false;
     }
 
-    em_ptr->note = nullptr;
+    em_ptr->note.clear();
     msg_format(_("%s^の堕落した精神は攻撃を跳ね返した!",
                    (em_ptr->seen ? "%s^'s corrupted mind backlashes your attack!" : "%s^s corrupted mind backlashes your attack!")),
         em_ptr->m_name);
@@ -104,7 +104,7 @@ static bool reflects_psi_with_currupted_mind(PlayerType *player_ptr, effect_mons
  * 効果は、混乱、朦朧、恐怖、麻痺
  * 3/4の確率または影分身時はダメージ及び追加効果はない。
  */
-static void effect_monster_psi_reflect_extra_effect(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_psi_reflect_extra_effect(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (!one_in_(4) || check_multishadow(player_ptr)) {
         return;
@@ -119,7 +119,7 @@ static void effect_monster_psi_reflect_extra_effect(PlayerType *player_ptr, effe
         (void)bss.mod_stun(randint1(em_ptr->dam));
         return;
     case 3:
-        if (any_bits(em_ptr->r_ptr->flags3, RF3_NO_FEAR)) {
+        if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
             em_ptr->note = _("には効果がなかった。", " is unaffected.");
         } else {
             (void)bss.mod_fear(3 + randint1(em_ptr->dam));
@@ -142,7 +142,7 @@ static void effect_monster_psi_reflect_extra_effect(PlayerType *player_ptr, effe
  * @details
  * 耐性を発動した精神の堕落したモンスターは効力を跳ね返すことがある。
  */
-static void effect_monster_psi_resist(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_psi_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (resisted_psi_because_empty_mind(player_ptr, em_ptr)) {
         return;
@@ -162,7 +162,7 @@ static void effect_monster_psi_resist(PlayerType *player_ptr, effect_monster_typ
     }
 
     /* Injure +/- confusion */
-    angband_strcpy(em_ptr->killer, monster_desc(player_ptr, em_ptr->m_ptr, MD_WRONGDOER_NAME).data(), sizeof(em_ptr->killer));
+    angband_strcpy(em_ptr->killer, monster_desc(player_ptr, em_ptr->m_ptr, MD_WRONGDOER_NAME), sizeof(em_ptr->killer));
     take_hit(player_ptr, DAMAGE_ATTACK, em_ptr->dam, em_ptr->killer);
     effect_monster_psi_reflect_extra_effect(player_ptr, em_ptr);
     em_ptr->dam = 0;
@@ -176,7 +176,7 @@ static void effect_monster_psi_resist(PlayerType *player_ptr, effect_monster_typ
  * 効果は、混乱、朦朧、恐怖、麻痺(各耐性無効)
  * ダメージがないか3/4の確率で効果なし
  */
-static void effect_monster_psi_extra_effect(effect_monster_type *em_ptr)
+static void effect_monster_psi_extra_effect(EffectMonster *em_ptr)
 {
     if ((em_ptr->dam <= 0) || !one_in_(4)) {
         return;
@@ -208,7 +208,7 @@ static void effect_monster_psi_extra_effect(effect_monster_type *em_ptr)
  * 視界による影響を発動する。
  * モンスターの耐性とそれに不随した効果を発動する。
  */
-ProcessResult effect_monster_psi(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_psi(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -235,7 +235,7 @@ ProcessResult effect_monster_psi(PlayerType *player_ptr, effect_monster_type *em
  * @details
  * 耐性を発動した精神の堕落したモンスターは効力を跳ね返すことがある。
  */
-static void effect_monster_psi_drain_resist(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_psi_drain_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (resisted_psi_because_empty_mind(player_ptr, em_ptr)) {
         return;
@@ -254,7 +254,7 @@ static void effect_monster_psi_drain_resist(PlayerType *player_ptr, effect_monst
         return;
     }
 
-    angband_strcpy(em_ptr->killer, monster_desc(player_ptr, em_ptr->m_ptr, MD_WRONGDOER_NAME).data(), sizeof(em_ptr->killer));
+    angband_strcpy(em_ptr->killer, monster_desc(player_ptr, em_ptr->m_ptr, MD_WRONGDOER_NAME), sizeof(em_ptr->killer));
     if (check_multishadow(player_ptr)) {
         take_hit(player_ptr, DAMAGE_ATTACK, em_ptr->dam, em_ptr->killer);
         em_ptr->dam = 0;
@@ -267,8 +267,9 @@ static void effect_monster_psi_drain_resist(PlayerType *player_ptr, effect_monst
         player_ptr->csp = 0;
     }
 
-    set_bits(player_ptr->redraw, PR_MP);
-    set_bits(player_ptr->window_flags, PW_SPELL);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    rfu.set_flag(SubWindowRedrawingFlag::SPELL);
     take_hit(player_ptr, DAMAGE_ATTACK, em_ptr->dam, em_ptr->killer);
     em_ptr->dam = 0;
 }
@@ -278,7 +279,7 @@ static void effect_monster_psi_drain_resist(PlayerType *player_ptr, effect_monst
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果への参照ポインタ
  */
-static void effect_monster_psi_drain_change_power(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_psi_drain_change_power(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     int b = damroll(5, em_ptr->dam) / 4;
     concptr str = PlayerClass(player_ptr).equals(PlayerClassType::MINDCRAFTER) ? _("超能力パワー", "psychic energy") : _("魔力", "mana");
@@ -287,8 +288,9 @@ static void effect_monster_psi_drain_change_power(PlayerType *player_ptr, effect
 
     b = std::min(player_ptr->msp, player_ptr->csp + b);
     player_ptr->csp = b;
-    set_bits(player_ptr->redraw, PR_MP);
-    set_bits(player_ptr->window_flags, PW_SPELL);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    rfu.set_flag(SubWindowRedrawingFlag::SPELL);
 }
 
 /*!
@@ -299,7 +301,7 @@ static void effect_monster_psi_drain_change_power(PlayerType *player_ptr, effect
  * @details
  * ダメージがないか3/4の確率で追加効果なし
  */
-ProcessResult effect_monster_psi_drain(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_psi_drain(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -322,7 +324,7 @@ ProcessResult effect_monster_psi_drain(PlayerType *player_ptr, effect_monster_ty
  * @details
  * 朦朧+ショートテレポートアウェイ
  */
-ProcessResult effect_monster_telekinesis(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_telekinesis(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
index 07be6cb..fc66b35 100644 (file)
@@ -1,9 +1,9 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-struct effect_monster_type;
+class EffectMonster;
 class PlayerType;
-ProcessResult effect_monster_psi(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_psi_drain(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_telekinesis(PlayerType *player_ptr, effect_monster_type *em_ptr);
+ProcessResult effect_monster_psi(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_psi_drain(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_telekinesis(PlayerType *player_ptr, EffectMonster *em_ptr);
index 48fc693..057276e 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-monster-resist-hurt.h"
+#include "effect/effect-monster-resist-hurt.h"
 #include "effect/effect-monster-util.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-brightness-flags.h"
@@ -22,7 +22,7 @@
  * @param em_ptr 魔法効果情報への参照ポインタ
  * @return 効果処理を続ける
  */
-ProcessResult effect_monster_nothing(effect_monster_type *em_ptr)
+ProcessResult effect_monster_nothing(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -31,7 +31,7 @@ ProcessResult effect_monster_nothing(effect_monster_type *em_ptr)
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_acid(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_acid(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -50,7 +50,7 @@ ProcessResult effect_monster_acid(PlayerType *player_ptr, effect_monster_type *e
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_elec(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_elec(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -69,7 +69,7 @@ ProcessResult effect_monster_elec(PlayerType *player_ptr, effect_monster_type *e
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_fire(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_fire(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -98,7 +98,7 @@ ProcessResult effect_monster_fire(PlayerType *player_ptr, effect_monster_type *e
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_cold(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_cold(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -127,7 +127,7 @@ ProcessResult effect_monster_cold(PlayerType *player_ptr, effect_monster_type *e
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_pois(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_pois(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -146,7 +146,7 @@ ProcessResult effect_monster_pois(PlayerType *player_ptr, effect_monster_type *e
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_nuke(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_nuke(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -170,7 +170,7 @@ ProcessResult effect_monster_nuke(PlayerType *player_ptr, effect_monster_type *e
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_hell_fire(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_hell_fire(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -189,7 +189,7 @@ ProcessResult effect_monster_hell_fire(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_holy_fire(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_holy_fire(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -220,7 +220,7 @@ ProcessResult effect_monster_holy_fire(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_plasma(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_plasma(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -240,7 +240,7 @@ ProcessResult effect_monster_plasma(PlayerType *player_ptr, effect_monster_type
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-static bool effect_monster_nether_resist(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool effect_monster_nether_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_NETHER)) {
         return false;
@@ -265,7 +265,7 @@ static bool effect_monster_nether_resist(PlayerType *player_ptr, effect_monster_
     return true;
 }
 
-ProcessResult effect_monster_nether(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_nether(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -284,7 +284,7 @@ ProcessResult effect_monster_nether(PlayerType *player_ptr, effect_monster_type
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_water(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_water(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -310,7 +310,7 @@ ProcessResult effect_monster_water(PlayerType *player_ptr, effect_monster_type *
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_chaos(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_chaos(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -338,7 +338,7 @@ ProcessResult effect_monster_chaos(PlayerType *player_ptr, effect_monster_type *
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_shards(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_shards(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -358,7 +358,7 @@ ProcessResult effect_monster_shards(PlayerType *player_ptr, effect_monster_type
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_rocket(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_rocket(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -377,7 +377,7 @@ ProcessResult effect_monster_rocket(PlayerType *player_ptr, effect_monster_type
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_sound(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_sound(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -398,13 +398,13 @@ ProcessResult effect_monster_sound(PlayerType *player_ptr, effect_monster_type *
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_confusion(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_confusion(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
     }
 
-    if ((em_ptr->r_ptr->flags3 & RF3_NO_CONF) == 0) {
+    if (em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::NO_CONF)) {
         em_ptr->do_conf = (10 + randint1(15) + em_ptr->r) / (em_ptr->r + 1);
         return ProcessResult::PROCESS_CONTINUE;
     }
@@ -413,13 +413,13 @@ ProcessResult effect_monster_confusion(PlayerType *player_ptr, effect_monster_ty
     em_ptr->dam *= 3;
     em_ptr->dam /= randint1(6) + 6;
     if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-        em_ptr->r_ptr->r_flags3 |= (RF3_NO_CONF);
+        em_ptr->r_ptr->resistance_flags.set(MonsterResistanceType::NO_CONF);
     }
 
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_disenchant(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_disenchant(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -439,7 +439,7 @@ ProcessResult effect_monster_disenchant(PlayerType *player_ptr, effect_monster_t
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_nexus(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_nexus(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -459,7 +459,7 @@ ProcessResult effect_monster_nexus(PlayerType *player_ptr, effect_monster_type *
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_force(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_force(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -481,7 +481,7 @@ ProcessResult effect_monster_force(PlayerType *player_ptr, effect_monster_type *
 }
 
 // Powerful monsters can resists and normal monsters slow down.
-ProcessResult effect_monster_inertial(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_inertial(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -512,7 +512,7 @@ ProcessResult effect_monster_inertial(PlayerType *player_ptr, effect_monster_typ
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_time(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_time(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -533,7 +533,7 @@ ProcessResult effect_monster_time(PlayerType *player_ptr, effect_monster_type *e
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-static bool effect_monster_gravity_resist_teleport(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool effect_monster_gravity_resist_teleport(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_TELEPORT)) {
         em_ptr->obvious = true;
@@ -562,7 +562,7 @@ static bool effect_monster_gravity_resist_teleport(PlayerType *player_ptr, effec
     return true;
 }
 
-static void effect_monster_gravity_slow(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_monster_gravity_slow(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     bool cancel_effect = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
     cancel_effect |= (em_ptr->r_ptr->level > randint1(std::max(1, em_ptr->dam - 10)) + 10);
@@ -577,7 +577,7 @@ static void effect_monster_gravity_slow(PlayerType *player_ptr, effect_monster_t
     em_ptr->obvious = true;
 }
 
-static void effect_monster_gravity_stun(effect_monster_type *em_ptr)
+static void effect_monster_gravity_stun(EffectMonster *em_ptr)
 {
     em_ptr->do_stun = damroll((em_ptr->caster_lev / 20) + 3, (em_ptr->dam)) + 1;
     bool has_resistance = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
@@ -593,7 +593,7 @@ static void effect_monster_gravity_stun(effect_monster_type *em_ptr)
  * Powerful monsters can resist and normal monsters slow down
  * Furthermore, this magic can make non-unique monsters slow/stun.
  */
-ProcessResult effect_monster_gravity(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_gravity(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     em_ptr->do_dist = effect_monster_gravity_resist_teleport(player_ptr, em_ptr) ? 0 : 10;
     if (player_ptr->riding && (em_ptr->g_ptr->m_idx == player_ptr->riding)) {
@@ -618,7 +618,7 @@ ProcessResult effect_monster_gravity(PlayerType *player_ptr, effect_monster_type
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_disintegration(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_disintegration(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -638,7 +638,7 @@ ProcessResult effect_monster_disintegration(PlayerType *player_ptr, effect_monst
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_icee_bolt(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_icee_bolt(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -670,7 +670,7 @@ ProcessResult effect_monster_icee_bolt(PlayerType *player_ptr, effect_monster_ty
  * @details
  * 量子生物に倍打、壁抜けに1.5倍打、テレポート耐性が耐性
  */
-ProcessResult effect_monster_void(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_void(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -722,7 +722,7 @@ ProcessResult effect_monster_void(PlayerType *player_ptr, effect_monster_type *e
  * 飛ばないテレポート耐性に1.25倍打、暗黒耐性が耐性
  * 1/3で追加に混乱か恐怖
  */
-ProcessResult effect_monster_abyss(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_abyss(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -772,3 +772,23 @@ ProcessResult effect_monster_abyss(PlayerType *player_ptr, effect_monster_type *
 
     return ProcessResult::PROCESS_CONTINUE;
 }
+
+ProcessResult effect_monster_meteor(PlayerType *player_ptr, EffectMonster *em_ptr)
+{
+    if (em_ptr->seen) {
+        em_ptr->obvious = true;
+    }
+
+    if (em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_METEOR)) {
+        return ProcessResult::PROCESS_CONTINUE;
+    }
+
+    em_ptr->note = _("には耐性がある!", " resists!");
+    em_ptr->dam *= 3;
+    em_ptr->dam /= randint1(6) + 6;
+    if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
+        em_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_METEOR);
+    }
+
+    return ProcessResult::PROCESS_CONTINUE;
+}
index ac725c5..a20373f 100644 (file)
@@ -1,33 +1,34 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-struct effect_monster_type;
+class EffectMonster;
 class PlayerType;
-ProcessResult effect_monster_nothing(effect_monster_type *em_ptr);
-ProcessResult effect_monster_acid(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_elec(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_fire(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_cold(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_pois(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_nuke(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_hell_fire(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_holy_fire(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_plasma(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_nether(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_water(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_chaos(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_shards(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_rocket(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_sound(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_confusion(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_disenchant(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_nexus(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_force(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_inertial(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_time(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_gravity(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_disintegration(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_icee_bolt(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_void(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_abyss(PlayerType *player_ptr, effect_monster_type *em_ptr);
+ProcessResult effect_monster_nothing(EffectMonster *em_ptr);
+ProcessResult effect_monster_acid(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_elec(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_fire(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_cold(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_pois(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_nuke(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_hell_fire(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_holy_fire(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_plasma(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_nether(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_water(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_chaos(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_shards(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_rocket(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_sound(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_confusion(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_disenchant(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_nexus(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_force(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_inertial(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_time(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_gravity(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_disintegration(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_icee_bolt(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_void(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_abyss(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_meteor(PlayerType *player_ptr, EffectMonster *em_ptr);
index 15634b9..68292e9 100644 (file)
@@ -1,5 +1,4 @@
-#include "effect/effect-monster-spirit.h"
-#include "core/player-redraw-types.h"
+#include "effect/effect-monster-spirit.h"
 #include "effect/effect-monster-util.h"
 #include "hpmp/hp-mp-processor.h"
 #include "monster-race/monster-race.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 
-ProcessResult effect_monster_drain_mana(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_drain_mana(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -52,16 +52,17 @@ ProcessResult effect_monster_drain_mana(PlayerType *player_ptr, effect_monster_t
         em_ptr->m_caster_ptr->hp = em_ptr->m_caster_ptr->maxhp;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == em_ptr->who) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (player_ptr->riding == em_ptr->who) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     if (em_ptr->see_s_msg) {
-        angband_strcpy(em_ptr->killer, monster_desc(player_ptr, em_ptr->m_caster_ptr, 0).data(), sizeof(em_ptr->killer));
+        angband_strcpy(em_ptr->killer, monster_desc(player_ptr, em_ptr->m_caster_ptr, 0), sizeof(em_ptr->killer));
         msg_format(_("%s^は気分が良さそうだ。", "%s^ appears healthier."), em_ptr->killer);
     }
 
@@ -69,7 +70,7 @@ ProcessResult effect_monster_drain_mana(PlayerType *player_ptr, effect_monster_t
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_mind_blast(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_mind_blast(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -79,13 +80,13 @@ ProcessResult effect_monster_mind_blast(PlayerType *player_ptr, effect_monster_t
     }
 
     bool has_immute = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
-    has_immute |= any_bits(em_ptr->r_ptr->flags3, RF3_NO_CONF);
+    has_immute |= em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF);
     has_immute |= (em_ptr->r_ptr->level > randint1(std::max(1, em_ptr->caster_lev - 10)) + 10);
 
     if (has_immute) {
-        if (em_ptr->r_ptr->flags3 & (RF3_NO_CONF)) {
+        if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
             if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-                em_ptr->r_ptr->r_flags3 |= (RF3_NO_CONF);
+                em_ptr->r_ptr->resistance_flags.set(MonsterResistanceType::NO_CONF);
             }
         }
 
@@ -117,7 +118,7 @@ ProcessResult effect_monster_mind_blast(PlayerType *player_ptr, effect_monster_t
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_brain_smash(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_brain_smash(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -127,13 +128,13 @@ ProcessResult effect_monster_brain_smash(PlayerType *player_ptr, effect_monster_
     }
 
     bool has_immute = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
-    has_immute |= any_bits(em_ptr->r_ptr->flags3, RF3_NO_CONF);
+    has_immute |= em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF);
     has_immute |= (em_ptr->r_ptr->level > randint1(std::max(1, em_ptr->caster_lev - 10)) + 10);
 
     if (has_immute) {
-        if (em_ptr->r_ptr->flags3 & (RF3_NO_CONF)) {
+        if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
             if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-                em_ptr->r_ptr->r_flags3 |= (RF3_NO_CONF);
+                em_ptr->r_ptr->resistance_flags.set(MonsterResistanceType::NO_CONF);
             }
         }
 
index 3858101..8716452 100644 (file)
@@ -1,9 +1,9 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-struct effect_monster_type;
+class EffectMonster;
 class PlayerType;
-ProcessResult effect_monster_drain_mana(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_mind_blast(PlayerType *player_ptr, effect_monster_type *em_ptr);
-ProcessResult effect_monster_brain_smash(PlayerType *player_ptr, effect_monster_type *em_ptr);
+ProcessResult effect_monster_drain_mana(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_mind_blast(PlayerType *player_ptr, EffectMonster *em_ptr);
+ProcessResult effect_monster_brain_smash(PlayerType *player_ptr, EffectMonster *em_ptr);
index fc1ef07..af5427d 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * 本ファイル内の行数はまともなレベルに落ち着いているので、一旦ここに留め置くこととする
  * @brief 魔法種別による各種処理切り替え
  * @date 2020/04/29
@@ -9,6 +9,7 @@
 #include "effect/effect-monster-switcher.h"
 #include "avatar/avatar.h"
 #include "cmd-action/cmd-attack.h"
+#include "effect/attribute-types.h"
 #include "effect/effect-monster-charm.h"
 #include "effect/effect-monster-curse.h"
 #include "effect/effect-monster-evil.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
-ProcessResult effect_monster_hypodynamia(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_hypodynamia(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
     }
 
-    if (monster_living(em_ptr->m_ptr->r_idx)) {
+    if (em_ptr->m_ptr->has_living_flag()) {
         em_ptr->do_time = (em_ptr->dam + 7) / 8;
         return ProcessResult::PROCESS_CONTINUE;
     }
@@ -69,13 +70,13 @@ ProcessResult effect_monster_hypodynamia(PlayerType *player_ptr, effect_monster_
 /*!
  * @todo リファクタリング前のコード時点で、単に耐性があるだけでもダメージ0だった.
  */
-ProcessResult effect_monster_death_ray(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_death_ray(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
     }
 
-    if (!monster_living(em_ptr->m_ptr->r_idx)) {
+    if (!em_ptr->m_ptr->has_living_flag()) {
         if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
             if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::DEMON)) {
                 em_ptr->r_ptr->r_kind_flags.set(MonsterKindType::DEMON);
@@ -106,7 +107,7 @@ ProcessResult effect_monster_death_ray(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_kill_wall(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_kill_wall(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::HURT_ROCK)) {
         em_ptr->dam = 0;
@@ -126,7 +127,7 @@ ProcessResult effect_monster_kill_wall(PlayerType *player_ptr, effect_monster_ty
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_hand_doom(effect_monster_type *em_ptr)
+ProcessResult effect_monster_hand_doom(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -162,7 +163,7 @@ ProcessResult effect_monster_hand_doom(effect_monster_type *em_ptr)
  * 寝た場合は試行終了。
  * 与える効果は減速、朦朧、混乱、睡眠。
  */
-ProcessResult effect_monster_engetsu(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_engetsu(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -214,10 +215,10 @@ ProcessResult effect_monster_engetsu(PlayerType *player_ptr, effect_monster_type
             }
             break;
         case 2:
-            if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(em_ptr->r_ptr->flags3, RF3_NO_CONF)) {
-                if (any_bits(em_ptr->r_ptr->flags3, RF3_NO_CONF)) {
+            if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
+                if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
                     if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-                        set_bits(em_ptr->r_ptr->r_flags3, RF3_NO_CONF);
+                        em_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_CONF);
                     }
                 }
                 em_ptr->do_conf = 0;
@@ -229,10 +230,10 @@ ProcessResult effect_monster_engetsu(PlayerType *player_ptr, effect_monster_type
             }
             break;
         default:
-            if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(em_ptr->r_ptr->flags3, RF3_NO_SLEEP)) {
-                if (any_bits(em_ptr->r_ptr->flags3, RF3_NO_SLEEP)) {
+            if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_SLEEP)) {
+                if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_SLEEP)) {
                     if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
-                        set_bits(em_ptr->r_ptr->r_flags3, RF3_NO_SLEEP);
+                        em_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_SLEEP);
                     }
                 }
                 em_ptr->do_sleep = 0;
@@ -259,7 +260,7 @@ ProcessResult effect_monster_engetsu(PlayerType *player_ptr, effect_monster_type
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_genocide(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_genocide(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -278,7 +279,7 @@ ProcessResult effect_monster_genocide(PlayerType *player_ptr, effect_monster_typ
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_photo(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_photo(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (!em_ptr->who) {
         msg_format(_("%sを写真に撮った。", "You take a photograph of %s."), em_ptr->m_name);
@@ -303,7 +304,7 @@ ProcessResult effect_monster_photo(PlayerType *player_ptr, effect_monster_type *
     return ProcessResult::PROCESS_CONTINUE;
 }
 
-ProcessResult effect_monster_wounds(effect_monster_type *em_ptr)
+ProcessResult effect_monster_wounds(EffectMonster *em_ptr)
 {
     if (em_ptr->seen) {
         em_ptr->obvious = true;
@@ -322,14 +323,13 @@ ProcessResult effect_monster_wounds(effect_monster_type *em_ptr)
  * @param em_ptr モンスター効果構造体への参照ポインタ
  * @return ここのスイッチングで終るならTRUEかFALSE、後続処理を実行するならCONTINUE
  */
-ProcessResult switch_effects_monster(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
+ProcessResult switch_effects_monster(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
 {
     switch (em_ptr->attribute) {
     case AttributeType::PSY_SPEAR:
     case AttributeType::MISSILE:
     case AttributeType::DEBUG:
     case AttributeType::MANA:
-    case AttributeType::METEOR:
     case AttributeType::BLOOD_CURSE:
     case AttributeType::SEEKER:
     case AttributeType::SUPER_RAY:
@@ -496,6 +496,8 @@ ProcessResult switch_effects_monster(PlayerType *player_ptr, effect_monster_type
         return effect_monster_void(player_ptr, em_ptr);
     case AttributeType::ABYSS:
         return effect_monster_abyss(player_ptr, em_ptr);
+    case AttributeType::METEOR:
+        return effect_monster_meteor(player_ptr, em_ptr);
     default: {
         em_ptr->skipped = true;
         em_ptr->dam = 0;
index c7b11a2..0dad94b 100644 (file)
@@ -1,9 +1,9 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <optional>
 
-struct effect_monster_type;
+class EffectMonster;
 class CapturedMonsterType;
 class PlayerType;
-ProcessResult switch_effects_monster(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr = std::nullopt);
+ProcessResult switch_effects_monster(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr = std::nullopt);
index eda00c2..ee518c7 100644 (file)
@@ -1,15 +1,17 @@
-/*!
+/*!
  * @brief effect_monster_type構造体の初期化処理
  * @date 2020/04/29
  * @author Hourier
  */
 
 #include "effect/effect-monster-util.h"
+#include "effect/attribute-types.h"
 #include "floor/geometry.h"
 #include "monster-floor/monster-death.h"
 #include "monster-race/monster-race.h"
 #include "monster/monster-info.h"
 #include "monster/monster-status.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
 
 /*!
- * @brief affect_monster() に亘ってきた引数をeffect_monster_type構造体に代入する
- * @param em_ptr モンスター効果構造体への参照ポインタ
- * @param who 魔法を発動したモンスター (0ならばプレイヤー)
- * @param r 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
- * @param y 目標y座標 / Target y location (or location to travel "towards")
- * @param x 目標x座標 / Target x location (or location to travel "towards")
- * @param dam 基本威力 / Base damage roll to apply to affected monsters (or player)
- * @param attribute 効果属性 / Type of damage to apply to monsters (and objects)
- * @param flag 効果フラグ
- * @param see_s_msg TRUEならばメッセージを表示する
- */
-static void substitute_effect_monster(effect_monster_type *em_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType attribute, BIT_FLAGS flag, bool see_s_msg)
-{
-    em_ptr->who = who;
-    em_ptr->r = r;
-    em_ptr->y = y;
-    em_ptr->x = x;
-    em_ptr->dam = dam;
-    em_ptr->attribute = attribute;
-    em_ptr->flag = flag;
-    em_ptr->see_s_msg = see_s_msg;
-}
-
-/*!
- * @brief effect_monster_type構造体を初期化する
+ * @brief EffectMonster構造体のコンストラクタ
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  * @param who 魔法を発動したモンスター (0ならばプレイヤー)
@@ -53,33 +31,25 @@ static void substitute_effect_monster(effect_monster_type *em_ptr, MONSTER_IDX w
  * @param flag 効果フラグ
  * @param see_s_msg TRUEならばメッセージを表示する
  */
-effect_monster_type *initialize_effect_monster(PlayerType *player_ptr, effect_monster_type *em_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType attribute, BIT_FLAGS flag, bool see_s_msg)
+EffectMonster::EffectMonster(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType attribute, BIT_FLAGS flag, bool see_s_msg)
+    : who(who)
+    , r(r)
+    , y(y)
+    , x(x)
+    , dam(dam)
+    , attribute(attribute)
+    , flag(flag)
+    , see_s_msg(see_s_msg)
 {
-    substitute_effect_monster(em_ptr, who, r, y, x, dam, attribute, flag, see_s_msg);
-
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    em_ptr->g_ptr = &floor_ptr->grid_array[em_ptr->y][em_ptr->x];
-    em_ptr->m_ptr = &floor_ptr->m_list[em_ptr->g_ptr->m_idx];
-    em_ptr->m_caster_ptr = (em_ptr->who > 0) ? &floor_ptr->m_list[em_ptr->who] : nullptr;
-    em_ptr->r_ptr = &monraces_info[em_ptr->m_ptr->r_idx];
-    em_ptr->seen = em_ptr->m_ptr->ml;
-    em_ptr->seen_msg = is_seen(player_ptr, em_ptr->m_ptr);
-    em_ptr->slept = em_ptr->m_ptr->is_asleep();
-    em_ptr->obvious = false;
-    em_ptr->known = ((em_ptr->m_ptr->cdis <= MAX_PLAYER_SIGHT) || player_ptr->phase_out);
-    em_ptr->skipped = false;
-    em_ptr->get_angry = false;
-    em_ptr->do_polymorph = false;
-    em_ptr->do_dist = 0;
-    em_ptr->do_conf = 0;
-    em_ptr->do_stun = 0;
-    em_ptr->do_sleep = 0;
-    em_ptr->do_fear = 0;
-    em_ptr->do_time = 0;
-    em_ptr->heal_leper = false;
-    em_ptr->photo = 0;
-    em_ptr->note = nullptr;
-    em_ptr->note_dies = extract_note_dies(em_ptr->m_ptr->get_real_r_idx());
-    em_ptr->caster_lev = (em_ptr->who > 0) ? monraces_info[em_ptr->m_caster_ptr->r_idx].level : (player_ptr->lev * 2);
-    return em_ptr;
+    this->g_ptr = &floor_ptr->grid_array[this->y][this->x];
+    this->m_ptr = &floor_ptr->m_list[this->g_ptr->m_idx];
+    this->m_caster_ptr = (this->who > 0) ? &floor_ptr->m_list[this->who] : nullptr;
+    this->r_ptr = &this->m_ptr->get_monrace();
+    this->seen = this->m_ptr->ml;
+    this->seen_msg = is_seen(player_ptr, this->m_ptr);
+    this->slept = this->m_ptr->is_asleep();
+    this->known = (this->m_ptr->cdis <= MAX_PLAYER_SIGHT) || AngbandSystem::get_instance().is_phase_out();
+    this->note_dies = this->m_ptr->get_died_message();
+    this->caster_lev = (this->who > 0) ? this->m_caster_ptr->get_monrace().level : (player_ptr->lev * 2);
 }
index 44d96ca..738f021 100644 (file)
@@ -1,39 +1,33 @@
-#pragma once
+#pragma once
 
-#include "effect/attribute-types.h"
 #include "system/angband.h"
+#include <string>
 
-struct grid_type;
-;
+enum class AttributeType;
+class Grid;
 class MonsterEntity;
 class MonsterRaceInfo;
-struct effect_monster_type {
-    grid_type *g_ptr;
-    MonsterEntity *m_ptr;
-    MonsterEntity *m_caster_ptr;
-    MonsterRaceInfo *r_ptr;
-    char killer[MAX_MONSTER_NAME];
-    bool seen;
-    bool seen_msg;
-    bool slept;
-    bool obvious;
-    bool known;
-    bool skipped;
-    bool get_angry;
-    bool do_polymorph;
-    int do_dist;
-    int do_conf;
-    int do_stun;
-    int do_sleep;
-    int do_fear;
-    int do_time;
-    bool heal_leper;
-    GAME_TEXT m_name[MAX_NLEN];
-    char m_poss[10];
-    PARAMETER_VALUE photo;
-    concptr note;
-    concptr note_dies;
-    DEPTH caster_lev;
+class PlayerType;
+class EffectMonster {
+public:
+    EffectMonster(PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType attribute, BIT_FLAGS flag, bool see_s_msg);
+
+    char killer[MAX_MONSTER_NAME]{};
+    bool obvious = false;
+    bool skipped = false;
+    bool get_angry = false;
+    bool do_polymorph = false;
+    int do_dist = 0;
+    int do_conf = 0;
+    int do_stun = 0;
+    int do_sleep = 0;
+    int do_fear = 0;
+    int do_time = 0;
+    bool heal_leper = false;
+    GAME_TEXT m_name[MAX_NLEN]{};
+    char m_poss[10]{};
+    short photo = 0;
+    std::string note = "";
 
     MONSTER_IDX who;
     POSITION r;
@@ -43,8 +37,15 @@ struct effect_monster_type {
     AttributeType attribute;
     BIT_FLAGS flag;
     bool see_s_msg;
-};
 
-class PlayerType;
-effect_monster_type *initialize_effect_monster(PlayerType *player_ptr, effect_monster_type *em_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x,
-    int dam, AttributeType attribute, BIT_FLAGS flag, bool see_s_msg);
+    Grid *g_ptr;
+    MonsterEntity *m_ptr;
+    MonsterEntity *m_caster_ptr;
+    MonsterRaceInfo *r_ptr;
+    bool seen;
+    bool seen_msg;
+    bool slept;
+    bool known;
+    std::string note_dies;
+    int caster_lev;
+};
index 4620fbe..84c1968 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 魔法によるモンスターへの効果まとめ
  * @date 2020/04/29
  * @author Hourier
@@ -7,7 +7,6 @@
 #include "effect/effect-monster.h"
 #include "avatar/avatar.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
@@ -15,7 +14,6 @@
 #include "effect/effect-monster-switcher.h"
 #include "effect/effect-monster-util.h"
 #include "effect/spells-effect-util.h"
-#include "floor/cave.h"
 #include "floor/floor-object.h"
 #include "game-option/play-record-options.h"
 #include "grid/grid.h"
@@ -46,6 +44,7 @@
 #include "spell-kind/spells-polymorph.h"
 #include "spell-kind/spells-teleport.h"
 #include "sv-definition/sv-other-types.h"
+#include "system/angband-system.h"
 #include "system/baseitem-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -53,6 +52,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
@@ -64,7 +64,7 @@
  * @param em_ptr モンスター効果構造体への参照ポインタ
  * @return 効果が何もないならFALSE、何かあるならTRUE
  */
-static ProcessResult is_affective(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static ProcessResult is_affective(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (!em_ptr->g_ptr->m_idx) {
         return ProcessResult::PROCESS_FALSE;
@@ -107,11 +107,11 @@ static ProcessResult is_affective(PlayerType *player_ptr, effect_monster_type *e
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void make_description_of_affecred_monster(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void make_description_of_affecred_monster(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     em_ptr->dam = (em_ptr->dam + em_ptr->r) / (em_ptr->r + 1);
-    angband_strcpy(em_ptr->m_name, monster_desc(player_ptr, em_ptr->m_ptr, 0).data(), sizeof(em_ptr->m_name));
-    angband_strcpy(em_ptr->m_poss, monster_desc(player_ptr, em_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE).data(), sizeof(em_ptr->m_poss));
+    angband_strcpy(em_ptr->m_name, monster_desc(player_ptr, em_ptr->m_ptr, 0), sizeof(em_ptr->m_name));
+    angband_strcpy(em_ptr->m_poss, monster_desc(player_ptr, em_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE), sizeof(em_ptr->m_poss));
 }
 
 /*!
@@ -123,7 +123,7 @@ static void make_description_of_affecred_monster(PlayerType *player_ptr, effect_
  * 完全な耐性を持っていたら、一部属性を除いて影響は及ぼさない
  * デバッグ属性、モンスター打撃、モンスター射撃であれば貫通する
  */
-static ProcessResult exe_affect_monster_by_effect(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
+static ProcessResult exe_affect_monster_by_effect(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
 {
     const std::vector<AttributeType> effect_arrtibute = {
         AttributeType::OLD_CLONE,
@@ -179,13 +179,13 @@ static ProcessResult exe_affect_monster_by_effect(PlayerType *player_ptr, effect
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void effect_damage_killed_pet(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_damage_killed_pet(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     bool sad = em_ptr->m_ptr->is_pet() && !(em_ptr->m_ptr->ml);
-    if (em_ptr->known && em_ptr->note) {
-        angband_strcpy(em_ptr->m_name, monster_desc(player_ptr, em_ptr->m_ptr, MD_TRUE_NAME).data(), sizeof(em_ptr->m_name));
+    if (em_ptr->known && !em_ptr->note.empty()) {
+        angband_strcpy(em_ptr->m_name, monster_desc(player_ptr, em_ptr->m_ptr, MD_TRUE_NAME), sizeof(em_ptr->m_name));
         if (em_ptr->see_s_msg) {
-            msg_format("%s^%s", em_ptr->m_name, em_ptr->note);
+            msg_format("%s^%s", em_ptr->m_name, em_ptr->note.data());
         } else {
             player_ptr->current_floor_ptr->monster_noise = true;
         }
@@ -207,10 +207,10 @@ static void effect_damage_killed_pet(PlayerType *player_ptr, effect_monster_type
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void effect_damage_makes_sleep(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_damage_makes_sleep(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
-    if (em_ptr->note && em_ptr->seen_msg) {
-        msg_format("%s^%s", em_ptr->m_name, em_ptr->note);
+    if (!em_ptr->note.empty() && em_ptr->seen_msg) {
+        msg_format("%s^%s", em_ptr->m_name, em_ptr->note.data());
     } else if (em_ptr->see_s_msg) {
         const auto pain_message = MonsterPainDescriber(player_ptr, em_ptr->g_ptr->m_idx).describe(em_ptr->dam);
         if (!pain_message.empty()) {
@@ -233,17 +233,19 @@ static void effect_damage_makes_sleep(PlayerType *player_ptr, effect_monster_typ
  * @details
  * モンスターIDがプレイヤー(0)の場合は処理しない。
  */
-static bool deal_effect_damage_from_monster(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool deal_effect_damage_from_monster(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->who <= 0) {
         return false;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == em_ptr->g_ptr->m_idx) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
+
     if (player_ptr->riding == em_ptr->g_ptr->m_idx) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     (void)set_monster_csleep(player_ptr, em_ptr->g_ptr->m_idx, 0);
@@ -263,7 +265,7 @@ static bool deal_effect_damage_from_monster(PlayerType *player_ptr, effect_monst
  * @param em_ptr モンスター効果構造体への参照ポインタ
  * @return 大賞モンスターが不潔な病人だった場合はTRUE、それ以外はFALSE
  */
-static bool heal_leaper(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool heal_leaper(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (!em_ptr->heal_leper) {
         return false;
@@ -275,7 +277,7 @@ static bool heal_leaper(PlayerType *player_ptr, effect_monster_type *em_ptr)
 
     if (record_named_pet && em_ptr->m_ptr->is_named_pet()) {
         const auto m2_name = monster_desc(player_ptr, em_ptr->m_ptr, MD_INDEF_VISIBLE);
-        exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_HEAL_LEPER, m2_name.data());
+        exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_HEAL_LEPER, m2_name);
     }
 
     delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
@@ -290,7 +292,7 @@ static bool heal_leaper(PlayerType *player_ptr, effect_monster_type *em_ptr)
  * @details
  * em_ptr->do_fearによる恐怖メッセージもここで表示。
  */
-static bool deal_effect_damage_from_player(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static bool deal_effect_damage_from_player(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     bool fear = false;
     MonsterDamageProcessor mdp(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam, &fear, em_ptr->attribute);
@@ -302,8 +304,8 @@ static bool deal_effect_damage_from_player(PlayerType *player_ptr, effect_monste
         anger_monster(player_ptr, em_ptr->m_ptr);
     }
 
-    if (em_ptr->note && em_ptr->seen) {
-        msg_format(_("%s%s", "%s^%s"), em_ptr->m_name, em_ptr->note);
+    if (!em_ptr->note.empty() && em_ptr->seen) {
+        msg_format(_("%s%s", "%s^%s"), em_ptr->m_name, em_ptr->note.data());
     } else if (em_ptr->known && (em_ptr->dam || !em_ptr->do_fear)) {
         const auto pain_message = MonsterPainDescriber(player_ptr, em_ptr->g_ptr->m_idx).describe(em_ptr->dam);
         if (!pain_message.empty()) {
@@ -334,7 +336,7 @@ static bool deal_effect_damage_from_player(PlayerType *player_ptr, effect_monste
  * 3.プレイヤーによる効果ダメージの処理
  * 4.睡眠する処理
  */
-static void deal_effect_damage_to_monster(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void deal_effect_damage_to_monster(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->attribute == AttributeType::DRAIN_MANA) {
         return;
@@ -363,7 +365,7 @@ static void deal_effect_damage_to_monster(PlayerType *player_ptr, effect_monster
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void effect_makes_change_virtues(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_makes_change_virtues(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if ((em_ptr->who > 0) || !em_ptr->slept) {
         return;
@@ -382,13 +384,20 @@ static void effect_makes_change_virtues(PlayerType *player_ptr, effect_monster_t
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void affected_monster_prevents_bad_status(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void affected_monster_prevents_bad_status(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
-    if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR) || (player_ptr->riding && (em_ptr->g_ptr->m_idx == player_ptr->riding))) {
+    const auto *r_ptr = em_ptr->r_ptr;
+    auto can_avoid_polymorph = r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
+    can_avoid_polymorph |= any_bits(r_ptr->flags1, RF1_QUESTOR);
+    can_avoid_polymorph |= (player_ptr->riding != 0) && (em_ptr->g_ptr->m_idx == player_ptr->riding);
+    if (can_avoid_polymorph) {
         em_ptr->do_polymorph = false;
     }
 
-    if ((em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR) || (em_ptr->r_ptr->population_flags.has(MonsterPopulationType::NAZGUL))) && !player_ptr->phase_out && (em_ptr->who > 0) && (em_ptr->dam > em_ptr->m_ptr->hp)) {
+    auto should_alive = r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
+    should_alive |= any_bits(r_ptr->flags1, RF1_QUESTOR);
+    should_alive |= r_ptr->population_flags.has(MonsterPopulationType::NAZGUL);
+    if (should_alive && !AngbandSystem::get_instance().is_phase_out() && (em_ptr->who > 0) && (em_ptr->dam > em_ptr->m_ptr->hp)) {
         em_ptr->dam = em_ptr->m_ptr->hp;
     }
 }
@@ -399,9 +408,13 @@ static void affected_monster_prevents_bad_status(PlayerType *player_ptr, effect_
  * @param em_ptr モンスター効果構造体への参照ポインタ
  * @param stun_damage 朦朧値
  */
-static void effect_damage_piles_stun(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_damage_piles_stun(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
-    if ((em_ptr->do_stun == 0) || em_ptr->r_ptr->resistance_flags.has_any_of({ MonsterResistanceType::RESIST_SOUND, MonsterResistanceType::RESIST_FORCE }) || (em_ptr->r_ptr->flags3 & RF3_NO_STUN)) {
+    const auto *r_ptr = em_ptr->r_ptr;
+    auto can_avoid_stun = em_ptr->do_stun == 0;
+    can_avoid_stun |= r_ptr->resistance_flags.has_any_of({ MonsterResistanceType::RESIST_SOUND, MonsterResistanceType::RESIST_FORCE });
+    can_avoid_stun |= r_ptr->resistance_flags.has(MonsterResistanceType::NO_STUN);
+    if (can_avoid_stun) {
         return;
     }
 
@@ -428,9 +441,9 @@ static void effect_damage_piles_stun(PlayerType *player_ptr, effect_monster_type
  * @param em_ptr モンスター効果構造体への参照ポインタ
  * @param stun_damage 混乱値
  */
-static void effect_damage_piles_confusion(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_damage_piles_confusion(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
-    if ((em_ptr->do_conf == 0) || (em_ptr->r_ptr->flags3 & RF3_NO_CONF) || em_ptr->r_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_CHAOS_MASK)) {
+    if ((em_ptr->do_conf == 0) || (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) || em_ptr->r_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_CHAOS_MASK)) {
         return;
     }
 
@@ -459,9 +472,9 @@ static void effect_damage_piles_confusion(PlayerType *player_ptr, effect_monster
  * @details
  * 打撃ダメージによる恐怖もあるため、メッセージは後で表示。
  */
-static void effect_damage_piles_fear(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_damage_piles_fear(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
-    if (em_ptr->do_fear == 0 || any_bits(em_ptr->r_ptr->flags3, RF3_NO_FEAR)) {
+    if (em_ptr->do_fear == 0 || em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
         return;
     }
 
@@ -473,7 +486,7 @@ static void effect_damage_piles_fear(PlayerType *player_ptr, effect_monster_type
  * @brief モンスターを衰弱させる
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void effect_damage_makes_weak(effect_monster_type *em_ptr)
+static void effect_damage_makes_weak(EffectMonster *em_ptr)
 {
     if (em_ptr->do_time == 0) {
         return;
@@ -503,7 +516,7 @@ static void effect_damage_makes_weak(effect_monster_type *em_ptr)
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void effect_damage_makes_polymorph(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_damage_makes_polymorph(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (!em_ptr->do_polymorph || (randint1(90) <= em_ptr->r_ptr->level)) {
         return;
@@ -519,7 +532,7 @@ static void effect_damage_makes_polymorph(PlayerType *player_ptr, effect_monster
     }
 
     em_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[em_ptr->g_ptr->m_idx];
-    em_ptr->r_ptr = &monraces_info[em_ptr->m_ptr->r_idx];
+    em_ptr->r_ptr = &em_ptr->m_ptr->get_monrace();
 }
 
 /*!
@@ -527,7 +540,7 @@ static void effect_damage_makes_polymorph(PlayerType *player_ptr, effect_monster
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void effect_damage_makes_teleport(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_damage_makes_teleport(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->do_dist == 0) {
         return;
@@ -561,7 +574,7 @@ static void effect_damage_makes_teleport(PlayerType *player_ptr, effect_monster_
  * 2.ダメージ量が現HPを上回る場合
  * 3.通常時(デバフをかける)
  */
-static void effect_damage_gives_bad_status(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void effect_damage_gives_bad_status(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     int tmp_damage = em_ptr->dam;
     em_ptr->dam = mon_damage_mod(player_ptr, em_ptr->m_ptr, em_ptr->dam, (bool)(em_ptr->attribute == AttributeType::PSY_SPEAR));
@@ -593,7 +606,7 @@ static void effect_damage_gives_bad_status(PlayerType *player_ptr, effect_monste
  * 4.ダメージ処理及び恐怖メッセージ
  * 5.悪魔領域血の呪いによる事後処理
  */
-static void exe_affect_monster_by_damage(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void exe_affect_monster_by_damage(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     effect_makes_change_virtues(player_ptr, em_ptr);
     affected_monster_prevents_bad_status(player_ptr, em_ptr);
@@ -609,14 +622,14 @@ static void exe_affect_monster_by_damage(PlayerType *player_ptr, effect_monster_
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void update_phase_out_stat(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void update_phase_out_stat(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
-    if (!player_ptr->phase_out) {
+    if (!AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
     player_ptr->health_who = em_ptr->g_ptr->m_idx;
-    player_ptr->redraw |= (PR_HEALTH);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::HEALTH);
     handle_stuff(player_ptr);
 }
 
@@ -625,7 +638,7 @@ static void update_phase_out_stat(PlayerType *player_ptr, effect_monster_type *e
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void postprocess_by_effected_pet(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void postprocess_by_effected_pet(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     auto *m_ptr = em_ptr->m_ptr;
     if ((em_ptr->dam <= 0) || m_ptr->is_pet() || m_ptr->is_friendly()) {
@@ -641,7 +654,7 @@ static void postprocess_by_effected_pet(PlayerType *player_ptr, effect_monster_t
     }
 
     const auto &m_caster_ref = *em_ptr->m_caster_ptr;
-    if ((em_ptr->who > 0) && m_caster_ref.is_pet() && !player_bold(player_ptr, m_ptr->target_y, m_ptr->target_x)) {
+    if ((em_ptr->who > 0) && m_caster_ref.is_pet() && !player_ptr->is_located_at({ m_ptr->target_y, m_ptr->target_x })) {
         set_target(m_ptr, m_caster_ref.fy, m_caster_ref.fx);
     }
 }
@@ -651,7 +664,7 @@ static void postprocess_by_effected_pet(PlayerType *player_ptr, effect_monster_t
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void postprocess_by_riding_pet_effected(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void postprocess_by_riding_pet_effected(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (!player_ptr->riding || (player_ptr->riding != em_ptr->g_ptr->m_idx) || (em_ptr->dam <= 0)) {
         return;
@@ -670,7 +683,7 @@ static void postprocess_by_riding_pet_effected(PlayerType *player_ptr, effect_mo
  * @param em_ptr モンスター効果構造体への参照ポインタ
  * @details 写真のフラッシュは弱閃光属性
  */
-static void postprocess_by_taking_photo(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void postprocess_by_taking_photo(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     if (em_ptr->photo == 0) {
         return;
@@ -690,7 +703,7 @@ static void postprocess_by_taking_photo(PlayerType *player_ptr, effect_monster_t
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param em_ptr モンスター効果構造体への参照ポインタ
  */
-static void exe_affect_monster_postprocess(PlayerType *player_ptr, effect_monster_type *em_ptr)
+static void exe_affect_monster_postprocess(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     postprocess_by_effected_pet(player_ptr, em_ptr);
     postprocess_by_riding_pet_effected(player_ptr, em_ptr);
@@ -719,10 +732,11 @@ static void exe_affect_monster_postprocess(PlayerType *player_ptr, effect_monste
  * 3.ペット及び撮影による事後効果
  */
 bool affect_monster(
-    PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType attribute, BIT_FLAGS flag, bool see_s_msg, std::optional<CapturedMonsterType *> cap_mon_ptr)
+    PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType attribute, BIT_FLAGS flag, bool see_s_msg,
+    std::optional<CapturedMonsterType *> cap_mon_ptr)
 {
-    effect_monster_type tmp_effect;
-    effect_monster_type *em_ptr = initialize_effect_monster(player_ptr, &tmp_effect, who, r, y, x, dam, attribute, flag, see_s_msg);
+    EffectMonster tmp_effect(player_ptr, who, r, y, x, dam, attribute, flag, see_s_msg);
+    auto *em_ptr = &tmp_effect;
 
     make_description_of_affecred_monster(player_ptr, em_ptr);
 
@@ -749,7 +763,7 @@ bool affect_monster(
 
     lite_spot(player_ptr, em_ptr->y, em_ptr->x);
     if ((player_ptr->monster_race_idx == em_ptr->m_ptr->r_idx) && (em_ptr->seen || !monster_is_valid)) {
-        player_ptr->window_flags |= (PW_MONSTER_LORE);
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
     }
 
     exe_affect_monster_postprocess(player_ptr, em_ptr);
index c2e9fe9..dc295e2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index d30075f..32b8ed8 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-player-curse.h"
+#include "effect/effect-player-curse.h"
 #include "blue-magic/blue-magic-checker.h"
 #include "effect/effect-player.h"
 #include "mind/mind-mirror-master.h"
index 6bda4fd..9431503 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class EffectPlayerType;
 class PlayerType;
index 4bf4fe8..f54bf9d 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-player-oldies.h"
+#include "effect/effect-player-oldies.h"
 #include "effect/effect-player.h"
 #include "game-option/birth-options.h"
 #include "hpmp/hp-mp-processor.h"
index 46efdf5..38ebd1f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class EffectPlayerType;
 class PlayerType;
index e1b8a08..406f410 100644 (file)
@@ -1,8 +1,6 @@
-#include "effect/effect-player-resist-hurt.h"
+#include "effect/effect-player-resist-hurt.h"
 #include "artifact/fixed-art-types.h"
 #include "blue-magic/blue-magic-checker.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "effect/effect-player.h"
 #include "hpmp/hp-mp-processor.h"
@@ -30,6 +28,7 @@
 #include "status/shape-changer.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
@@ -37,7 +36,7 @@
 
 // 毒を除く4元素.
 void effect_player_elements(
-    PlayerType *player_ptr, EffectPlayerType *ep_ptr, concptr attack_message, int (*damage_func)(PlayerType *, int, concptr, bool))
+    PlayerType *player_ptr, EffectPlayerType *ep_ptr, std::string_view attack_message, int (*damage_func)(PlayerType *, int, std::string_view, bool))
 {
     if (player_ptr->effects()->blindness()->is_blind()) {
         msg_print(attack_message);
@@ -432,9 +431,18 @@ void effect_player_lite(PlayerType *player_ptr, EffectPlayerType *ep_ptr)
     player_ptr->wraith_form = 0;
     msg_print(_("閃光のため非物質的な影の存在でいられなくなった。", "The light forces you out of your incorporeal shadow form."));
 
-    player_ptr->redraw |= (PR_MAP | PR_TIMED_EFFECT);
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::TIMED_EFFECT,
+    };
+    rfu.set_flags(flags_mwrf);
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 void effect_player_dark(PlayerType *player_ptr, EffectPlayerType *ep_ptr)
@@ -458,59 +466,6 @@ void effect_player_dark(PlayerType *player_ptr, EffectPlayerType *ep_ptr)
     ep_ptr->get_damage = take_hit(player_ptr, DAMAGE_ATTACK, ep_ptr->dam, ep_ptr->killer);
 }
 
-static void effect_player_time_one_disability(PlayerType *player_ptr)
-{
-    int k = 0;
-    concptr act = nullptr;
-    switch (randint1(6)) {
-    case 1:
-        k = A_STR;
-        act = _("強く", "strong");
-        break;
-    case 2:
-        k = A_INT;
-        act = _("聡明で", "bright");
-        break;
-    case 3:
-        k = A_WIS;
-        act = _("賢明で", "wise");
-        break;
-    case 4:
-        k = A_DEX;
-        act = _("器用で", "agile");
-        break;
-    case 5:
-        k = A_CON;
-        act = _("健康で", "hale");
-        break;
-    case 6:
-        k = A_CHR;
-        act = _("美しく", "beautiful");
-        break;
-    }
-
-    msg_format(_("あなたは以前ほど%sなくなってしまった...。", "You're not as %s as you used to be..."), act);
-    player_ptr->stat_cur[k] = (player_ptr->stat_cur[k] * 3) / 4;
-    if (player_ptr->stat_cur[k] < 3) {
-        player_ptr->stat_cur[k] = 3;
-    }
-
-    player_ptr->update |= (PU_BONUS);
-}
-
-static void effect_player_time_all_disabilities(PlayerType *player_ptr)
-{
-    msg_print(_("あなたは以前ほど力強くなくなってしまった...。", "You're not as powerful as you used to be..."));
-    for (int k = 0; k < A_MAX; k++) {
-        player_ptr->stat_cur[k] = (player_ptr->stat_cur[k] * 7) / 8;
-        if (player_ptr->stat_cur[k] < 3) {
-            player_ptr->stat_cur[k] = 3;
-        }
-    }
-
-    player_ptr->update |= (PU_BONUS);
-}
-
 static void effect_player_time_addition(PlayerType *player_ptr)
 {
     switch (randint1(10)) {
@@ -531,10 +486,10 @@ static void effect_player_time_addition(PlayerType *player_ptr)
     case 7:
     case 8:
     case 9:
-        effect_player_time_one_disability(player_ptr);
+        msg_print(player_ptr->decrease_ability_random());
         break;
     case 10:
-        effect_player_time_all_disabilities(player_ptr);
+        msg_print(player_ptr->decrease_ability_all());
         break;
     }
 }
index f223ddd..5488494 100644 (file)
@@ -1,11 +1,11 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <string_view>
 
 class EffectPlayerType;
 class PlayerType;
 void effect_player_elements(
-    PlayerType *player_ptr, EffectPlayerType *ep_ptr, concptr attack_message, int (*damage_func)(PlayerType *, int, concptr, bool));
+    PlayerType *player_ptr, EffectPlayerType *ep_ptr, std::string_view attack_message, int (*damage_func)(PlayerType *, int, std::string_view, bool));
 void effect_player_poison(PlayerType *player_ptr, EffectPlayerType *ep_ptr);
 void effect_player_nuke(PlayerType *player_ptr, EffectPlayerType *ep_ptr);
 void effect_player_missile(PlayerType *player_ptr, EffectPlayerType *ep_ptr);
index 8818743..b228866 100644 (file)
@@ -1,6 +1,5 @@
-#include "effect/effect-player-spirit.h"
+#include "effect/effect-player-spirit.h"
 #include "blue-magic/blue-magic-checker.h"
-#include "core/player-redraw-types.h"
 #include "core/window-redrawer.h"
 #include "effect/effect-player.h"
 #include "mind/mind-mirror-master.h"
@@ -10,6 +9,7 @@
 #include "status/base-status.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 #include "world/world.h"
 
@@ -40,8 +40,13 @@ void effect_player_drain_mana(PlayerType *player_ptr, EffectPlayerType *ep_ptr)
         player_ptr->csp -= ep_ptr->dam;
     }
 
-    player_ptr->redraw |= (PR_MP);
-    player_ptr->window_flags |= (PW_PLAYER | PW_SPELL);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags);
 
     if ((ep_ptr->who <= 0) || (ep_ptr->m_ptr->hp >= ep_ptr->m_ptr->maxhp)) {
         ep_ptr->dam = 0;
@@ -54,10 +59,10 @@ void effect_player_drain_mana(PlayerType *player_ptr, EffectPlayerType *ep_ptr)
     }
 
     if (player_ptr->health_who == ep_ptr->who) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
     if (player_ptr->riding == ep_ptr->who) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     if (ep_ptr->m_ptr->ml) {
@@ -95,7 +100,7 @@ void effect_player_mind_blast(PlayerType *player_ptr, EffectPlayerType *ep_ptr)
         player_ptr->csp_frac = 0;
     }
 
-    player_ptr->redraw |= PR_MP;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
     ep_ptr->get_damage = take_hit(player_ptr, DAMAGE_ATTACK, ep_ptr->dam, ep_ptr->killer);
 }
 
@@ -108,13 +113,13 @@ void effect_player_brain_smash(PlayerType *player_ptr, EffectPlayerType *ep_ptr)
 
     if (!check_multishadow(player_ptr)) {
         msg_print(_("霊的エネルギーで精神が攻撃された。", "Your mind is blasted by psionic energy."));
-
         player_ptr->csp -= 100;
         if (player_ptr->csp < 0) {
             player_ptr->csp = 0;
             player_ptr->csp_frac = 0;
         }
-        player_ptr->redraw |= PR_MP;
+
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
     }
 
     ep_ptr->get_damage = take_hit(player_ptr, DAMAGE_ATTACK, ep_ptr->dam, ep_ptr->killer);
index 595d574..427faa5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class EffectPlayerType;
 class PlayerType;
index ddd877e..3998001 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-player-switcher.h"
+#include "effect/effect-player-switcher.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-player-curse.h"
 #include "effect/effect-player-oldies.h"
index f8f65af..552309b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class EffectPlayerType;
 class PlayerType;
index 3642f3b..45fae6b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 魔法によるプレイヤーへの効果まとめ
  * @date 2020/04/29
  * @author Hourier
@@ -123,9 +123,9 @@ static bool process_bolt_reflection(PlayerType *player_ptr, EffectPlayerType *ep
  * @param x 目標X座標
  * @return 当たらなかったらFALSE、反射したらTRUE、当たったらCONTINUE
  */
-static ProcessResult check_continue_player_effect(PlayerType *player_ptr, EffectPlayerType *ep_ptr, POSITION y, POSITION x, project_func project)
+static ProcessResult check_continue_player_effect(PlayerType *player_ptr, EffectPlayerType *ep_ptr, const Pos2D &pos, project_func project)
 {
-    if (!player_bold(player_ptr, y, x)) {
+    if (!player_ptr->is_located_at(pos)) {
         return ProcessResult::PROCESS_FALSE;
     }
 
@@ -158,8 +158,8 @@ static void describe_effect_source(PlayerType *player_ptr, EffectPlayerType *ep_
 {
     if (ep_ptr->who > 0) {
         ep_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[ep_ptr->who];
-        ep_ptr->rlev = (&monraces_info[ep_ptr->m_ptr->r_idx])->level >= 1 ? (&monraces_info[ep_ptr->m_ptr->r_idx])->level : 1;
-        angband_strcpy(ep_ptr->m_name, monster_desc(player_ptr, ep_ptr->m_ptr, 0).data(), sizeof(ep_ptr->m_name));
+        ep_ptr->rlev = ep_ptr->m_ptr->get_monrace().level >= 1 ? ep_ptr->m_ptr->get_monrace().level : 1;
+        angband_strcpy(ep_ptr->m_name, monster_desc(player_ptr, ep_ptr->m_ptr, 0), sizeof(ep_ptr->m_name));
         angband_strcpy(ep_ptr->killer, who_name, sizeof(ep_ptr->killer));
         return;
     }
@@ -197,7 +197,7 @@ bool affect_player(MONSTER_IDX who, PlayerType *player_ptr, concptr who_name, in
 {
     EffectPlayerType tmp_effect(who, dam, attribute, flag);
     auto *ep_ptr = &tmp_effect;
-    auto check_result = check_continue_player_effect(player_ptr, ep_ptr, y, x, project);
+    auto check_result = check_continue_player_effect(player_ptr, ep_ptr, { y, x }, project);
     if (check_result != ProcessResult::PROCESS_CONTINUE) {
         return check_result == ProcessResult::PROCESS_TRUE;
     }
index a28b6c1..1fdaf42 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index db79674..7667e92 100644 (file)
@@ -1,4 +1,4 @@
-#include "effect/effect-processor.h"
+#include "effect/effect-processor.h"
 #include "core/stuff-handler.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
@@ -28,6 +28,7 @@
 #include "player/player-status.h"
 #include "spell-class/spells-mirror-master.h"
 #include "spell/range-calc.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
@@ -68,9 +69,9 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
     bool old_hide = false;
     int path_n = 0;
     int grids = 0;
-    POSITION gx[1024];
-    POSITION gy[1024];
-    POSITION gm[32];
+    POSITION gx[1024]{};
+    POSITION gy[1024]{};
+    POSITION gm[32]{};
     rakubadam_p = 0;
     rakubadam_m = 0;
     monster_target_y = player_ptr->y;
@@ -136,27 +137,29 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
     }
 
     /* Calculate the projection path */
-    projection_path path_g(player_ptr, (project_length ? project_length : get_max_range(player_ptr)), y1, x1, y2, x2, flag);
+    const auto &system = AngbandSystem::get_instance();
+    projection_path path_g(player_ptr, (project_length ? project_length : system.get_max_range()), y1, x1, y2, x2, flag);
     handle_stuff(player_ptr);
 
     int k = 0;
     auto oy = y1;
     auto ox = x1;
     auto visual = false;
-    POSITION gm_rad = rad;
     bool see_s_msg = true;
     const auto is_blind = player_ptr->effects()->blindness()->is_blind();
+    auto &floor = *player_ptr->current_floor_ptr;
     for (const auto &[ny, nx] : path_g) {
+        const Pos2D pos(ny, nx);
         if (flag & PROJECT_DISI) {
             if (cave_stop_disintegration(player_ptr->current_floor_ptr, ny, nx) && (rad > 0)) {
                 break;
             }
         } else if (flag & PROJECT_LOS) {
-            if (!cave_los_bold(player_ptr->current_floor_ptr, ny, nx) && (rad > 0)) {
+            if (!cave_los_bold(&floor, ny, nx) && (rad > 0)) {
                 break;
             }
         } else {
-            if (!cave_has_flag_bold(player_ptr->current_floor_ptr, ny, nx, TerrainCharacteristics::PROJECT) && (rad > 0)) {
+            if (!cave_has_flag_bold(&floor, ny, nx, TerrainCharacteristics::PROJECT) && (rad > 0)) {
                 break;
             }
         }
@@ -168,7 +171,7 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
 
         if (delay_factor > 0) {
             if (!is_blind && !(flag & (PROJECT_HIDE | PROJECT_FAST))) {
-                if (panel_contains(ny, nx) && player_has_los_bold(player_ptr, ny, nx)) {
+                if (panel_contains(ny, nx) && floor.has_los(pos)) {
                     print_bolt_pict(player_ptr, oy, ox, ny, nx, typ);
                     move_cursor_relative(ny, nx);
                     term_fresh();
@@ -196,7 +199,6 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
     POSITION bx = ox;
     if (breath && !path_n) {
         breath = false;
-        gm_rad = rad;
         if (!old_hide) {
             flag &= ~(PROJECT_HIDE);
         }
@@ -206,8 +208,9 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
     gm[1] = grids;
     project_length = 0;
 
+    POSITION gm_rad = rad;
     /* If we found a "target", explode there */
-    if (path_n <= get_max_range(player_ptr)) {
+    if (path_n <= system.get_max_range()) {
         if ((flag & (PROJECT_BEAM)) && (grids > 0)) {
             grids--;
         }
@@ -273,11 +276,10 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
         auto drawn = false;
         for (int t = 0; t <= gm_rad; t++) {
             for (int i = gm[t]; i < gm[t + 1]; i++) {
-                auto y = gy[i];
-                auto x = gx[i];
-                if (panel_contains(y, x) && player_has_los_bold(player_ptr, y, x)) {
+                const Pos2D pos(gy[i], gx[i]);
+                if (panel_contains(pos.y, pos.x) && floor.has_los(pos)) {
                     drawn = true;
-                    print_bolt_pict(player_ptr, y, x, y, x, typ);
+                    print_bolt_pict(player_ptr, pos.y, pos.x, pos.y, pos.x, typ);
                 }
             }
 
@@ -290,10 +292,9 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
 
         if (drawn) {
             for (int i = 0; i < grids; i++) {
-                auto y = gy[i];
-                auto x = gx[i];
-                if (panel_contains(y, x) && player_has_los_bold(player_ptr, y, x)) {
-                    lite_spot(player_ptr, y, x);
+                const Pos2D pos(gy[i], gx[i]);
+                if (panel_contains(pos.y, pos.x) && floor.has_los(pos)) {
+                    lite_spot(player_ptr, pos.y, pos.x);
                 }
             }
 
@@ -364,19 +365,19 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
                 dist++;
             }
 
-            auto y = gy[i];
-            auto x = gx[i];
+            const Pos2D pos(gy[i], gx[i]);
+            const auto &grid = floor.get_grid(pos);
             if (grids <= 1) {
-                auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->current_floor_ptr->grid_array[y][x].m_idx];
-                MonsterRaceInfo *ref_ptr = &monraces_info[m_ptr->r_idx];
-                if ((flag & PROJECT_REFLECTABLE) && player_ptr->current_floor_ptr->grid_array[y][x].m_idx && (ref_ptr->flags2 & RF2_REFLECTING) && ((player_ptr->current_floor_ptr->grid_array[y][x].m_idx != player_ptr->riding) || !(flag & PROJECT_PLAYER)) && (!who || path_n > 1) && !one_in_(10)) {
+                auto *m_ptr = &floor.m_list[grid.m_idx];
+                MonsterRaceInfo *ref_ptr = &m_ptr->get_monrace();
+                if ((flag & PROJECT_REFLECTABLE) && grid.m_idx && (ref_ptr->flags2 & RF2_REFLECTING) && ((grid.m_idx != player_ptr->riding) || !(flag & PROJECT_PLAYER)) && (!who || path_n > 1) && !one_in_(10)) {
                     POSITION t_y, t_x;
                     int max_attempts = 10;
                     do {
                         t_y = y1 - 1 + randint1(3);
                         t_x = x1 - 1 + randint1(3);
                         max_attempts--;
-                    } while (max_attempts && in_bounds2u(player_ptr->current_floor_ptr, t_y, t_x) && !projectable(player_ptr, y, x, t_y, t_x));
+                    } while (max_attempts && in_bounds2u(player_ptr->current_floor_ptr, t_y, t_x) && !projectable(player_ptr, pos.y, pos.x, t_y, t_x));
 
                     if (max_attempts < 1) {
                         t_y = y1;
@@ -400,25 +401,25 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
                         ref_ptr->r_flags2 |= RF2_REFLECTING;
                     }
 
-                    if (player_bold(player_ptr, y, x) || one_in_(2)) {
+                    if (player_ptr->is_located_at(pos) || one_in_(2)) {
                         flag &= ~(PROJECT_PLAYER);
                     } else {
                         flag |= PROJECT_PLAYER;
                     }
 
-                    project(player_ptr, player_ptr->current_floor_ptr->grid_array[y][x].m_idx, 0, t_y, t_x, dam, typ, flag);
+                    project(player_ptr, grid.m_idx, 0, t_y, t_x, dam, typ, flag);
                     continue;
                 }
             }
 
             /* Find the closest point in the blast */
             if (breath) {
-                effective_dist = dist_to_line(y, x, y1, x1, by, bx);
+                effective_dist = dist_to_line(pos.y, pos.x, y1, x1, by, bx);
             } else {
                 effective_dist = dist;
             }
 
-            if (player_ptr->riding && player_bold(player_ptr, y, x)) {
+            if (player_ptr->riding && player_ptr->is_located_at(pos)) {
                 if (flag & PROJECT_PLAYER) {
                     if (flag & (PROJECT_BEAM | PROJECT_REFLECTABLE | PROJECT_AIMED)) {
                         /*
@@ -440,7 +441,7 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
                  * This grid is the original target.
                  * Or aimed on your horse.
                  */
-                else if (((y == y2) && (x == x2)) || (flag & PROJECT_AIMED)) {
+                else if (((pos.y == y2) && (pos.x == x2)) || (flag & PROJECT_AIMED)) {
                     /* Hit the mount with full damage */
                 }
 
@@ -473,22 +474,22 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
                 }
             }
 
-            if (affect_monster(player_ptr, who, effective_dist, y, x, dam, typ, flag, see_s_msg, cap_mon_ptr)) {
+            if (affect_monster(player_ptr, who, effective_dist, pos.y, pos.x, dam, typ, flag, see_s_msg, cap_mon_ptr)) {
                 res.notice = true;
             }
         }
         /* Player affected one monster (without "jumping") */
         if (!who && (project_m_n == 1) && none_bits(flag, PROJECT_JUMP)) {
-            auto x = project_m_x;
-            auto y = project_m_y;
-            if (player_ptr->current_floor_ptr->grid_array[y][x].m_idx > 0) {
-                auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->current_floor_ptr->grid_array[y][x].m_idx];
-                if (m_ptr->ml) {
+            const Pos2D pos_project(project_m_y, project_m_x);
+            const auto &grid = floor.get_grid(pos_project);
+            if (grid.m_idx > 0) {
+                auto &monster = floor.m_list[grid.m_idx];
+                if (monster.ml) {
                     if (!player_ptr->effects()->hallucination()->is_hallucinated()) {
-                        monster_race_track(player_ptr, m_ptr->ap_r_idx);
+                        monster_race_track(player_ptr, monster.ap_r_idx);
                     }
 
-                    health_track(player_ptr, player_ptr->current_floor_ptr->grid_array[y][x].m_idx);
+                    health_track(player_ptr, grid.m_idx);
                 }
             }
         }
@@ -502,15 +503,14 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
                 dist++;
             }
 
-            auto y = gy[i];
-            auto x = gx[i];
-            if (!player_bold(player_ptr, y, x)) {
+            const Pos2D pos(gy[i], gx[i]);
+            if (!player_ptr->is_located_at(pos)) {
                 continue;
             }
 
             /* Find the closest point in the blast */
             if (breath) {
-                effective_dist = dist_to_line(y, x, y1, x1, by, bx);
+                effective_dist = dist_to_line(pos.y, pos.x, y1, x1, by, bx);
             } else {
                 effective_dist = dist;
             }
@@ -549,10 +549,10 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
 
             std::string who_name;
             if (who > 0) {
-                who_name = monster_desc(player_ptr, &player_ptr->current_floor_ptr->m_list[who], MD_WRONGDOER_NAME);
+                who_name = monster_desc(player_ptr, &floor.m_list[who], MD_WRONGDOER_NAME);
             }
 
-            if (affect_player(who, player_ptr, who_name.data(), effective_dist, y, x, dam, typ, flag, project)) {
+            if (affect_player(who, player_ptr, who_name.data(), effective_dist, pos.y, pos.x, dam, typ, flag, project)) {
                 res.notice = true;
                 res.affected_player = true;
             }
@@ -560,7 +560,7 @@ ProjectResult project(PlayerType *player_ptr, const MONSTER_IDX who, POSITION ra
     }
 
     if (player_ptr->riding) {
-        const auto m_name = monster_desc(player_ptr, &player_ptr->current_floor_ptr->m_list[player_ptr->riding], 0);
+        const auto m_name = monster_desc(player_ptr, &floor.m_list[player_ptr->riding], 0);
         if (rakubadam_m > 0) {
             if (process_fall_off_horse(player_ptr, rakubadam_m, false)) {
                 msg_format(_("%s^に振り落とされた!", "%s^ has thrown you off!"), m_name.data());
index b5663d0..259baea 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index 11a0c67..b9a23c2 100644 (file)
@@ -1,4 +1,5 @@
-#include "effect/spells-effect-util.h"
+#include "effect/spells-effect-util.h"
+#include "monster-race/race-indice-types.h"
 
 int rakubadam_m;
 int rakubadam_p;
@@ -11,3 +12,8 @@ POSITION project_m_x;
 POSITION project_m_y;
 POSITION monster_target_x;
 POSITION monster_target_y;
+
+CapturedMonsterType::CapturedMonsterType()
+    : r_idx(MonsterRaceId::PLAYER)
+{
+}
index a8f81d9..744138a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
@@ -10,12 +10,12 @@ enum class MonsterRaceId : int16_t;
 
 class CapturedMonsterType {
 public:
-    CapturedMonsterType() = default;
+    CapturedMonsterType();
     MonsterRaceId r_idx;
-    byte speed;
-    short current_hp;
-    short max_hp;
-    std::string nickname;
+    byte speed = STANDARD_SPEED;
+    short current_hp = 0;
+    short max_hp = 0;
+    std::string nickname = "";
 };
 
 extern bool sukekaku;
diff --git a/src/external-lib/include-json.h b/src/external-lib/include-json.h
new file mode 100644 (file)
index 0000000..70b0c2d
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+// MSVCの警告レベルを最大に設定してあるためjson.hppが大量の警告を
+// 出力してしまうのでヘッダのインクルード時のみ警告を抑制しておく
+#if defined(_MSC_VER)
+#pragma warning(push, 0)
+#endif
+
+#include "external-lib/json.hpp"
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
diff --git a/src/external-lib/json.hpp b/src/external-lib/json.hpp
new file mode 100644 (file)
index 0000000..a52d405
--- /dev/null
@@ -0,0 +1,24596 @@
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+/****************************************************************************\
+ * Note on documentation: The source files contain links to the online      *
+ * documentation of the public API at https://json.nlohmann.me. This URL    *
+ * contains the most recent documentation and should also be applicable to  *
+ * previous versions; documentation for deprecated functions is not         *
+ * removed, but marked deprecated. See "Generate documentation" section in  *
+ * file docs/README.md.                                                     *
+\****************************************************************************/
+
+#ifndef INCLUDE_NLOHMANN_JSON_HPP_
+#define INCLUDE_NLOHMANN_JSON_HPP_
+
+#include <algorithm> // all_of, find, for_each
+#include <cstddef> // nullptr_t, ptrdiff_t, size_t
+#include <functional> // hash, less
+#include <initializer_list> // initializer_list
+#ifndef JSON_NO_IO
+    #include <iosfwd> // istream, ostream
+#endif  // JSON_NO_IO
+#include <iterator> // random_access_iterator_tag
+#include <memory> // unique_ptr
+#include <numeric> // accumulate
+#include <string> // string, stoi, to_string
+#include <utility> // declval, forward, move, pair, swap
+#include <vector> // vector
+
+// #include <nlohmann/adl_serializer.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <utility>
+
+// #include <nlohmann/detail/abi_macros.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// This file contains all macro definitions affecting or depending on the ABI
+
+#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
+    #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
+        #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2
+            #warning "Already included a different version of the library!"
+        #endif
+    #endif
+#endif
+
+#define NLOHMANN_JSON_VERSION_MAJOR 3   // NOLINT(modernize-macro-to-enum)
+#define NLOHMANN_JSON_VERSION_MINOR 11  // NOLINT(modernize-macro-to-enum)
+#define NLOHMANN_JSON_VERSION_PATCH 2   // NOLINT(modernize-macro-to-enum)
+
+#ifndef JSON_DIAGNOSTICS
+    #define JSON_DIAGNOSTICS 0
+#endif
+
+#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+    #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
+#endif
+
+#if JSON_DIAGNOSTICS
+    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
+#else
+    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
+#endif
+
+#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+    #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
+#else
+    #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
+#endif
+
+#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
+    #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
+#endif
+
+// Construct the namespace ABI tags component
+#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
+#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
+    NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
+
+#define NLOHMANN_JSON_ABI_TAGS                                       \
+    NLOHMANN_JSON_ABI_TAGS_CONCAT(                                   \
+            NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS,                       \
+            NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
+
+// Construct the namespace version component
+#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
+    _v ## major ## _ ## minor ## _ ## patch
+#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
+    NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
+
+#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
+#define NLOHMANN_JSON_NAMESPACE_VERSION
+#else
+#define NLOHMANN_JSON_NAMESPACE_VERSION                                 \
+    NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
+                                           NLOHMANN_JSON_VERSION_MINOR, \
+                                           NLOHMANN_JSON_VERSION_PATCH)
+#endif
+
+// Combine namespace components
+#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
+#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
+    NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
+
+#ifndef NLOHMANN_JSON_NAMESPACE
+#define NLOHMANN_JSON_NAMESPACE               \
+    nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
+            NLOHMANN_JSON_ABI_TAGS,           \
+            NLOHMANN_JSON_NAMESPACE_VERSION)
+#endif
+
+#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
+#define NLOHMANN_JSON_NAMESPACE_BEGIN                \
+    namespace nlohmann                               \
+    {                                                \
+    inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
+                NLOHMANN_JSON_ABI_TAGS,              \
+                NLOHMANN_JSON_NAMESPACE_VERSION)     \
+    {
+#endif
+
+#ifndef NLOHMANN_JSON_NAMESPACE_END
+#define NLOHMANN_JSON_NAMESPACE_END                                     \
+    }  /* namespace (inline namespace) NOLINT(readability/namespace) */ \
+    }  // namespace nlohmann
+#endif
+
+// #include <nlohmann/detail/conversions/from_json.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <algorithm> // transform
+#include <array> // array
+#include <forward_list> // forward_list
+#include <iterator> // inserter, front_inserter, end
+#include <map> // map
+#include <string> // string
+#include <tuple> // tuple, make_tuple
+#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
+#include <unordered_map> // unordered_map
+#include <utility> // pair, declval
+#include <valarray> // valarray
+
+// #include <nlohmann/detail/exceptions.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstddef> // nullptr_t
+#include <exception> // exception
+#include <stdexcept> // runtime_error
+#include <string> // to_string
+#include <vector> // vector
+
+// #include <nlohmann/detail/value_t.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <array> // array
+#include <cstddef> // size_t
+#include <cstdint> // uint8_t
+#include <string> // string
+
+// #include <nlohmann/detail/macro_scope.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <utility> // declval, pair
+// #include <nlohmann/detail/meta/detected.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <type_traits>
+
+// #include <nlohmann/detail/meta/void_t.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename ...Ts> struct make_void
+{
+    using type = void;
+};
+template<typename ...Ts> using void_t = typename make_void<Ts...>::type;
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// https://en.cppreference.com/w/cpp/experimental/is_detected
+struct nonesuch
+{
+    nonesuch() = delete;
+    ~nonesuch() = delete;
+    nonesuch(nonesuch const&) = delete;
+    nonesuch(nonesuch const&&) = delete;
+    void operator=(nonesuch const&) = delete;
+    void operator=(nonesuch&&) = delete;
+};
+
+template<class Default,
+         class AlwaysVoid,
+         template<class...> class Op,
+         class... Args>
+struct detector
+{
+    using value_t = std::false_type;
+    using type = Default;
+};
+
+template<class Default, template<class...> class Op, class... Args>
+struct detector<Default, void_t<Op<Args...>>, Op, Args...>
+{
+    using value_t = std::true_type;
+    using type = Op<Args...>;
+};
+
+template<template<class...> class Op, class... Args>
+using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
+
+template<template<class...> class Op, class... Args>
+struct is_detected_lazy : is_detected<Op, Args...> { };
+
+template<template<class...> class Op, class... Args>
+using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
+
+template<class Default, template<class...> class Op, class... Args>
+using detected_or = detector<Default, void, Op, Args...>;
+
+template<class Default, template<class...> class Op, class... Args>
+using detected_or_t = typename detected_or<Default, Op, Args...>::type;
+
+template<class Expected, template<class...> class Op, class... Args>
+using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
+
+template<class To, template<class...> class Op, class... Args>
+using is_detected_convertible =
+    std::is_convertible<detected_t<Op, Args...>, To>;
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/thirdparty/hedley/hedley.hpp>
+
+
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson <evan@nemerson.com>
+// SPDX-License-Identifier: MIT
+
+/* Hedley - https://nemequ.github.io/hedley
+ * Created by Evan Nemerson <evan@nemerson.com>
+ */
+
+#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15)
+#if defined(JSON_HEDLEY_VERSION)
+    #undef JSON_HEDLEY_VERSION
+#endif
+#define JSON_HEDLEY_VERSION 15
+
+#if defined(JSON_HEDLEY_STRINGIFY_EX)
+    #undef JSON_HEDLEY_STRINGIFY_EX
+#endif
+#define JSON_HEDLEY_STRINGIFY_EX(x) #x
+
+#if defined(JSON_HEDLEY_STRINGIFY)
+    #undef JSON_HEDLEY_STRINGIFY
+#endif
+#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)
+
+#if defined(JSON_HEDLEY_CONCAT_EX)
+    #undef JSON_HEDLEY_CONCAT_EX
+#endif
+#define JSON_HEDLEY_CONCAT_EX(a,b) a##b
+
+#if defined(JSON_HEDLEY_CONCAT)
+    #undef JSON_HEDLEY_CONCAT
+#endif
+#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)
+
+#if defined(JSON_HEDLEY_CONCAT3_EX)
+    #undef JSON_HEDLEY_CONCAT3_EX
+#endif
+#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c
+
+#if defined(JSON_HEDLEY_CONCAT3)
+    #undef JSON_HEDLEY_CONCAT3
+#endif
+#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c)
+
+#if defined(JSON_HEDLEY_VERSION_ENCODE)
+    #undef JSON_HEDLEY_VERSION_ENCODE
+#endif
+#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)
+    #undef JSON_HEDLEY_VERSION_DECODE_MAJOR
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)
+    #undef JSON_HEDLEY_VERSION_DECODE_MINOR
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)
+
+#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)
+    #undef JSON_HEDLEY_VERSION_DECODE_REVISION
+#endif
+#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)
+
+#if defined(JSON_HEDLEY_GNUC_VERSION)
+    #undef JSON_HEDLEY_GNUC_VERSION
+#endif
+#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
+    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+#elif defined(__GNUC__)
+    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)
+    #undef JSON_HEDLEY_GNUC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_GNUC_VERSION)
+    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_MSVC_VERSION)
+    #undef JSON_HEDLEY_MSVC_VERSION
+#endif
+#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)
+#elif defined(_MSC_FULL_VER) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)
+#elif defined(_MSC_VER) && !defined(__ICL)
+    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)
+    #undef JSON_HEDLEY_MSVC_VERSION_CHECK
+#endif
+#if !defined(JSON_HEDLEY_MSVC_VERSION)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
+#else
+    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_VERSION)
+    #undef JSON_HEDLEY_INTEL_VERSION
+#endif
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)
+    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)
+#elif defined(__INTEL_COMPILER) && !defined(__ICL)
+    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)
+    #undef JSON_HEDLEY_INTEL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_INTEL_VERSION)
+    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
+    #undef JSON_HEDLEY_INTEL_CL_VERSION
+#endif
+#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)
+    #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)
+#endif
+
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)
+    #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
+    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_PGI_VERSION)
+    #undef JSON_HEDLEY_PGI_VERSION
+#endif
+#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
+    #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
+#endif
+
+#if defined(JSON_HEDLEY_PGI_VERSION_CHECK)
+    #undef JSON_HEDLEY_PGI_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_PGI_VERSION)
+    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_SUNPRO_VERSION)
+    #undef JSON_HEDLEY_SUNPRO_VERSION
+#endif
+#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)
+#elif defined(__SUNPRO_C)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)
+#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)
+#elif defined(__SUNPRO_CC)
+    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)
+#endif
+
+#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)
+    #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_SUNPRO_VERSION)
+    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
+    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION
+#endif
+#if defined(__EMSCRIPTEN__)
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)
+#endif
+
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)
+    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_ARM_VERSION)
+    #undef JSON_HEDLEY_ARM_VERSION
+#endif
+#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)
+#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)
+#endif
+
+#if defined(JSON_HEDLEY_ARM_VERSION_CHECK)
+    #undef JSON_HEDLEY_ARM_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_ARM_VERSION)
+    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_IBM_VERSION)
+    #undef JSON_HEDLEY_IBM_VERSION
+#endif
+#if defined(__ibmxl__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)
+#elif defined(__xlC__) && defined(__xlC_ver__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
+#elif defined(__xlC__)
+    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)
+#endif
+
+#if defined(JSON_HEDLEY_IBM_VERSION_CHECK)
+    #undef JSON_HEDLEY_IBM_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_IBM_VERSION)
+    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_VERSION)
+    #undef JSON_HEDLEY_TI_VERSION
+#endif
+#if \
+    defined(__TI_COMPILER_VERSION__) && \
+    ( \
+      defined(__TMS470__) || defined(__TI_ARM__) || \
+      defined(__MSP430__) || \
+      defined(__TMS320C2000__) \
+    )
+#if (__TI_COMPILER_VERSION__ >= 16000000)
+    #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+#endif
+
+#if defined(JSON_HEDLEY_TI_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_VERSION)
+    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
+    #undef JSON_HEDLEY_TI_CL2000_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)
+    #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
+    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL430_VERSION)
+    #undef JSON_HEDLEY_TI_CL430_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)
+    #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL430_VERSION)
+    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
+    #undef JSON_HEDLEY_TI_ARMCL_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))
+    #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
+    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
+    #undef JSON_HEDLEY_TI_CL6X_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)
+    #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
+    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
+    #undef JSON_HEDLEY_TI_CL7X_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)
+    #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
+    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
+    #undef JSON_HEDLEY_TI_CLPRU_VERSION
+#endif
+#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)
+    #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
+#endif
+
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK)
+    #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
+    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_CRAY_VERSION)
+    #undef JSON_HEDLEY_CRAY_VERSION
+#endif
+#if defined(_CRAYC)
+    #if defined(_RELEASE_PATCHLEVEL)
+        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)
+    #else
+        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)
+    #endif
+#endif
+
+#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)
+    #undef JSON_HEDLEY_CRAY_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_CRAY_VERSION)
+    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_IAR_VERSION)
+    #undef JSON_HEDLEY_IAR_VERSION
+#endif
+#if defined(__IAR_SYSTEMS_ICC__)
+    #if __VER__ > 1000
+        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))
+    #else
+        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0)
+    #endif
+#endif
+
+#if defined(JSON_HEDLEY_IAR_VERSION_CHECK)
+    #undef JSON_HEDLEY_IAR_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_IAR_VERSION)
+    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_TINYC_VERSION)
+    #undef JSON_HEDLEY_TINYC_VERSION
+#endif
+#if defined(__TINYC__)
+    #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
+#endif
+
+#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)
+    #undef JSON_HEDLEY_TINYC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_TINYC_VERSION)
+    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_DMC_VERSION)
+    #undef JSON_HEDLEY_DMC_VERSION
+#endif
+#if defined(__DMC__)
+    #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)
+#endif
+
+#if defined(JSON_HEDLEY_DMC_VERSION_CHECK)
+    #undef JSON_HEDLEY_DMC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_DMC_VERSION)
+    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_COMPCERT_VERSION)
+    #undef JSON_HEDLEY_COMPCERT_VERSION
+#endif
+#if defined(__COMPCERT_VERSION__)
+    #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)
+#endif
+
+#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)
+    #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_COMPCERT_VERSION)
+    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_PELLES_VERSION)
+    #undef JSON_HEDLEY_PELLES_VERSION
+#endif
+#if defined(__POCC__)
+    #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)
+#endif
+
+#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)
+    #undef JSON_HEDLEY_PELLES_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_PELLES_VERSION)
+    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #undef JSON_HEDLEY_MCST_LCC_VERSION
+#endif
+#if defined(__LCC__) && defined(__LCC_MINOR__)
+    #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__)
+#endif
+
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK)
+    #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_VERSION)
+    #undef JSON_HEDLEY_GCC_VERSION
+#endif
+#if \
+    defined(JSON_HEDLEY_GNUC_VERSION) && \
+    !defined(__clang__) && \
+    !defined(JSON_HEDLEY_INTEL_VERSION) && \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_ARM_VERSION) && \
+    !defined(JSON_HEDLEY_CRAY_VERSION) && \
+    !defined(JSON_HEDLEY_TI_VERSION) && \
+    !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL430_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \
+    !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \
+    !defined(__COMPCERT__) && \
+    !defined(JSON_HEDLEY_MCST_LCC_VERSION)
+    #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION
+#endif
+
+#if defined(JSON_HEDLEY_GCC_VERSION_CHECK)
+    #undef JSON_HEDLEY_GCC_VERSION_CHECK
+#endif
+#if defined(JSON_HEDLEY_GCC_VERSION)
+    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
+#else
+    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_ATTRIBUTE
+#endif
+#if \
+  defined(__has_attribute) && \
+  ( \
+    (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \
+  )
+#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)
+#else
+#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
+#endif
+#if defined(__has_attribute)
+    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
+#endif
+#if defined(__has_attribute)
+    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
+#endif
+#if \
+    defined(__has_cpp_attribute) && \
+    defined(__cplusplus) && \
+    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0))
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS)
+    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
+#endif
+#if !defined(__cplusplus) || !defined(__has_cpp_attribute)
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
+#elif \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_IAR_VERSION) && \
+    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \
+    (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0))
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute)
+#else
+    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
+#endif
+#if defined(__has_cpp_attribute) && defined(__cplusplus)
+    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
+#endif
+#if defined(__has_cpp_attribute) && defined(__cplusplus)
+    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_BUILTIN)
+    #undef JSON_HEDLEY_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)
+    #undef JSON_HEDLEY_GNUC_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)
+    #undef JSON_HEDLEY_GCC_HAS_BUILTIN
+#endif
+#if defined(__has_builtin)
+    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
+#else
+    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_FEATURE)
+    #undef JSON_HEDLEY_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_HAS_FEATURE(feature) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)
+    #undef JSON_HEDLEY_GNUC_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_FEATURE)
+    #undef JSON_HEDLEY_GCC_HAS_FEATURE
+#endif
+#if defined(__has_feature)
+    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
+#else
+    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_EXTENSION)
+    #undef JSON_HEDLEY_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)
+    #undef JSON_HEDLEY_GNUC_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)
+    #undef JSON_HEDLEY_GCC_HAS_EXTENSION
+#endif
+#if defined(__has_extension)
+    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
+#else
+    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
+#endif
+#if defined(__has_declspec_attribute)
+    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
+#else
+    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_HAS_WARNING)
+    #undef JSON_HEDLEY_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_HAS_WARNING(warning) (0)
+#endif
+
+#if defined(JSON_HEDLEY_GNUC_HAS_WARNING)
+    #undef JSON_HEDLEY_GNUC_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_GCC_HAS_WARNING)
+    #undef JSON_HEDLEY_GCC_HAS_WARNING
+#endif
+#if defined(__has_warning)
+    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
+#else
+    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if \
+    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
+    defined(__clang__) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \
+    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \
+    (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))
+    #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_PRAGMA(value) __pragma(value)
+#else
+    #define JSON_HEDLEY_PRAGMA(value)
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)
+    #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
+#endif
+#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)
+    #undef JSON_HEDLEY_DIAGNOSTIC_POP
+#endif
+#if defined(__clang__)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))
+    #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))
+#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop")
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
+    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_PUSH
+    #define JSON_HEDLEY_DIAGNOSTIC_POP
+#endif
+
+/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for
+   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
+#endif
+#if defined(__cplusplus)
+#  if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat")
+#    if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions")
+#      if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions")
+#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#      else
+#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#      endif
+#    else
+#      define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
+    xpr \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#    endif
+#  endif
+#endif
+#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x
+#endif
+
+#if defined(JSON_HEDLEY_CONST_CAST)
+    #undef JSON_HEDLEY_CONST_CAST
+#endif
+#if defined(__cplusplus)
+#  define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))
+#elif \
+  JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \
+        JSON_HEDLEY_DIAGNOSTIC_PUSH \
+        JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \
+        ((T) (expr)); \
+        JSON_HEDLEY_DIAGNOSTIC_POP \
+    }))
+#else
+#  define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_REINTERPRET_CAST)
+    #undef JSON_HEDLEY_REINTERPRET_CAST
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))
+#else
+    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_STATIC_CAST)
+    #undef JSON_HEDLEY_STATIC_CAST
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))
+#else
+    #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))
+#endif
+
+#if defined(JSON_HEDLEY_CPP_CAST)
+    #undef JSON_HEDLEY_CPP_CAST
+#endif
+#if defined(__cplusplus)
+#  if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast")
+#    define JSON_HEDLEY_CPP_CAST(T, expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
+    ((T) (expr)) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0)
+#    define JSON_HEDLEY_CPP_CAST(T, expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("diag_suppress=Pe137") \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  else
+#    define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))
+#  endif
+#else
+#  define JSON_HEDLEY_CPP_CAST(T, expr) (expr)
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445")
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215")
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161")
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)")
+#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098")
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)")
+#elif \
+    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097")
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
+#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
+#endif
+
+#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION)
+    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunused-function")
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"")
+#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"")
+#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505))
+#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142")
+#else
+    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
+#endif
+
+#if defined(JSON_HEDLEY_DEPRECATED)
+    #undef JSON_HEDLEY_DEPRECATED
+#endif
+#if defined(JSON_HEDLEY_DEPRECATED_FOR)
+    #undef JSON_HEDLEY_DEPRECATED_FOR
+#endif
+#if \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
+#elif \
+    (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
+#elif defined(__cplusplus) && (__cplusplus >= 201402L)
+    #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]])
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated")
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated")
+#else
+    #define JSON_HEDLEY_DEPRECATED(since)
+    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)
+#endif
+
+#if defined(JSON_HEDLEY_UNAVAILABLE)
+    #undef JSON_HEDLEY_UNAVAILABLE
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since)))
+#else
+    #define JSON_HEDLEY_UNAVAILABLE(available_since)
+#endif
+
+#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)
+    #undef JSON_HEDLEY_WARN_UNUSED_RESULT
+#endif
+#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)
+    #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))
+#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
+#elif defined(_Check_return_) /* SAL */
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_
+#else
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT
+    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg)
+#endif
+
+#if defined(JSON_HEDLEY_SENTINEL)
+    #undef JSON_HEDLEY_SENTINEL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))
+#else
+    #define JSON_HEDLEY_SENTINEL(position)
+#endif
+
+#if defined(JSON_HEDLEY_NO_RETURN)
+    #undef JSON_HEDLEY_NO_RETURN
+#endif
+#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_NO_RETURN __noreturn
+#elif \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+    #define JSON_HEDLEY_NO_RETURN _Noreturn
+#elif defined(__cplusplus) && (__cplusplus >= 201103L)
+    #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;")
+#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
+    #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
+    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
+#else
+    #define JSON_HEDLEY_NO_RETURN
+#endif
+
+#if defined(JSON_HEDLEY_NO_ESCAPE)
+    #undef JSON_HEDLEY_NO_ESCAPE
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape)
+    #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__))
+#else
+    #define JSON_HEDLEY_NO_ESCAPE
+#endif
+
+#if defined(JSON_HEDLEY_UNREACHABLE)
+    #undef JSON_HEDLEY_UNREACHABLE
+#endif
+#if defined(JSON_HEDLEY_UNREACHABLE_RETURN)
+    #undef JSON_HEDLEY_UNREACHABLE_RETURN
+#endif
+#if defined(JSON_HEDLEY_ASSUME)
+    #undef JSON_HEDLEY_ASSUME
+#endif
+#if \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_ASSUME(expr) __assume(expr)
+#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)
+    #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)
+#elif \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
+    #if defined(__cplusplus)
+        #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)
+    #else
+        #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)
+    #endif
+#endif
+#if \
+    (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()
+#elif defined(JSON_HEDLEY_ASSUME)
+    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
+#endif
+#if !defined(JSON_HEDLEY_ASSUME)
+    #if defined(JSON_HEDLEY_UNREACHABLE)
+        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1)))
+    #else
+        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr)
+    #endif
+#endif
+#if defined(JSON_HEDLEY_UNREACHABLE)
+    #if  \
+        JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
+        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value))
+    #else
+        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()
+    #endif
+#else
+    #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value)
+#endif
+#if !defined(JSON_HEDLEY_UNREACHABLE)
+    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
+#endif
+
+JSON_HEDLEY_DIAGNOSTIC_PUSH
+#if JSON_HEDLEY_HAS_WARNING("-Wpedantic")
+    #pragma clang diagnostic ignored "-Wpedantic"
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus)
+    #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0)
+    #if defined(__clang__)
+        #pragma clang diagnostic ignored "-Wvariadic-macros"
+    #elif defined(JSON_HEDLEY_GCC_VERSION)
+        #pragma GCC diagnostic ignored "-Wvariadic-macros"
+    #endif
+#endif
+#if defined(JSON_HEDLEY_NON_NULL)
+    #undef JSON_HEDLEY_NON_NULL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
+    #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
+#else
+    #define JSON_HEDLEY_NON_NULL(...)
+#endif
+JSON_HEDLEY_DIAGNOSTIC_POP
+
+#if defined(JSON_HEDLEY_PRINTF_FORMAT)
+    #undef JSON_HEDLEY_PRINTF_FORMAT
+#endif
+#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))
+#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))
+#elif \
+    JSON_HEDLEY_HAS_ATTRIBUTE(format) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))
+#else
+    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)
+#endif
+
+#if defined(JSON_HEDLEY_CONSTEXPR)
+    #undef JSON_HEDLEY_CONSTEXPR
+#endif
+#if defined(__cplusplus)
+    #if __cplusplus >= 201103L
+        #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)
+    #endif
+#endif
+#if !defined(JSON_HEDLEY_CONSTEXPR)
+    #define JSON_HEDLEY_CONSTEXPR
+#endif
+
+#if defined(JSON_HEDLEY_PREDICT)
+    #undef JSON_HEDLEY_PREDICT
+#endif
+#if defined(JSON_HEDLEY_LIKELY)
+    #undef JSON_HEDLEY_LIKELY
+#endif
+#if defined(JSON_HEDLEY_UNLIKELY)
+    #undef JSON_HEDLEY_UNLIKELY
+#endif
+#if defined(JSON_HEDLEY_UNPREDICTABLE)
+    #undef JSON_HEDLEY_UNPREDICTABLE
+#endif
+#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)
+    #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))
+#endif
+#if \
+  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(  (expr), (value), (probability))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability)   __builtin_expect_with_probability(!!(expr),    1   , (probability))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability)  __builtin_expect_with_probability(!!(expr),    0   , (probability))
+#  define JSON_HEDLEY_LIKELY(expr)                      __builtin_expect                 (!!(expr),    1                  )
+#  define JSON_HEDLEY_UNLIKELY(expr)                    __builtin_expect                 (!!(expr),    0                  )
+#elif \
+  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \
+  JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PREDICT(expr, expected, probability) \
+    (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \
+    (__extension__ ({ \
+        double hedley_probability_ = (probability); \
+        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \
+    }))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \
+    (__extension__ ({ \
+        double hedley_probability_ = (probability); \
+        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \
+    }))
+#  define JSON_HEDLEY_LIKELY(expr)   __builtin_expect(!!(expr), 1)
+#  define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
+#else
+#  define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))
+#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))
+#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))
+#  define JSON_HEDLEY_LIKELY(expr) (!!(expr))
+#  define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))
+#endif
+#if !defined(JSON_HEDLEY_UNPREDICTABLE)
+    #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)
+#endif
+
+#if defined(JSON_HEDLEY_MALLOC)
+    #undef JSON_HEDLEY_MALLOC
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory")
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_MALLOC __declspec(restrict)
+#else
+    #define JSON_HEDLEY_MALLOC
+#endif
+
+#if defined(JSON_HEDLEY_PURE)
+    #undef JSON_HEDLEY_PURE
+#endif
+#if \
+  JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#  define JSON_HEDLEY_PURE __attribute__((__pure__))
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+#  define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data")
+#elif defined(__cplusplus) && \
+    ( \
+      JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
+      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \
+      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \
+    )
+#  define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;")
+#else
+#  define JSON_HEDLEY_PURE
+#endif
+
+#if defined(JSON_HEDLEY_CONST)
+    #undef JSON_HEDLEY_CONST
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(const) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_CONST __attribute__((__const__))
+#elif \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
+    #define JSON_HEDLEY_CONST _Pragma("no_side_effect")
+#else
+    #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE
+#endif
+
+#if defined(JSON_HEDLEY_RESTRICT)
+    #undef JSON_HEDLEY_RESTRICT
+#endif
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)
+    #define JSON_HEDLEY_RESTRICT restrict
+#elif \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
+    defined(__clang__) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_RESTRICT __restrict
+#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)
+    #define JSON_HEDLEY_RESTRICT _Restrict
+#else
+    #define JSON_HEDLEY_RESTRICT
+#endif
+
+#if defined(JSON_HEDLEY_INLINE)
+    #undef JSON_HEDLEY_INLINE
+#endif
+#if \
+    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
+    (defined(__cplusplus) && (__cplusplus >= 199711L))
+    #define JSON_HEDLEY_INLINE inline
+#elif \
+    defined(JSON_HEDLEY_GCC_VERSION) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)
+    #define JSON_HEDLEY_INLINE __inline__
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_INLINE __inline
+#else
+    #define JSON_HEDLEY_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_ALWAYS_INLINE)
+    #undef JSON_HEDLEY_ALWAYS_INLINE
+#endif
+#if \
+  JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+  JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE
+#elif \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE __forceinline
+#elif defined(__cplusplus) && \
+    ( \
+      JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+      JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+      JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+      JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \
+    )
+#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced")
+#else
+#  define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_NEVER_INLINE)
+    #undef JSON_HEDLEY_NEVER_INLINE
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
+    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
+    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
+    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
+    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
+    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
+    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
+    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
+    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
+    #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
+#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline")
+#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+    #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never")
+#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
+    #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
+    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
+#else
+    #define JSON_HEDLEY_NEVER_INLINE
+#endif
+
+#if defined(JSON_HEDLEY_PRIVATE)
+    #undef JSON_HEDLEY_PRIVATE
+#endif
+#if defined(JSON_HEDLEY_PUBLIC)
+    #undef JSON_HEDLEY_PUBLIC
+#endif
+#if defined(JSON_HEDLEY_IMPORT)
+    #undef JSON_HEDLEY_IMPORT
+#endif
+#if defined(_WIN32) || defined(__CYGWIN__)
+#  define JSON_HEDLEY_PRIVATE
+#  define JSON_HEDLEY_PUBLIC   __declspec(dllexport)
+#  define JSON_HEDLEY_IMPORT   __declspec(dllimport)
+#else
+#  if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+    ( \
+      defined(__TI_EABI__) && \
+      ( \
+        (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
+        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \
+      ) \
+    ) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+#    define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden")))
+#    define JSON_HEDLEY_PUBLIC  __attribute__((__visibility__("default")))
+#  else
+#    define JSON_HEDLEY_PRIVATE
+#    define JSON_HEDLEY_PUBLIC
+#  endif
+#  define JSON_HEDLEY_IMPORT    extern
+#endif
+
+#if defined(JSON_HEDLEY_NO_THROW)
+    #undef JSON_HEDLEY_NO_THROW
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))
+#elif \
+    JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
+    #define JSON_HEDLEY_NO_THROW __declspec(nothrow)
+#else
+    #define JSON_HEDLEY_NO_THROW
+#endif
+
+#if defined(JSON_HEDLEY_FALL_THROUGH)
+    #undef JSON_HEDLEY_FALL_THROUGH
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)
+    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])
+#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)
+    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])
+#elif defined(__fallthrough) /* SAL */
+    #define JSON_HEDLEY_FALL_THROUGH __fallthrough
+#else
+    #define JSON_HEDLEY_FALL_THROUGH
+#endif
+
+#if defined(JSON_HEDLEY_RETURNS_NON_NULL)
+    #undef JSON_HEDLEY_RETURNS_NON_NULL
+#endif
+#if \
+    JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))
+#elif defined(_Ret_notnull_) /* SAL */
+    #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_
+#else
+    #define JSON_HEDLEY_RETURNS_NON_NULL
+#endif
+
+#if defined(JSON_HEDLEY_ARRAY_PARAM)
+    #undef JSON_HEDLEY_ARRAY_PARAM
+#endif
+#if \
+    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+    !defined(__STDC_NO_VLA__) && \
+    !defined(__cplusplus) && \
+    !defined(JSON_HEDLEY_PGI_VERSION) && \
+    !defined(JSON_HEDLEY_TINYC_VERSION)
+    #define JSON_HEDLEY_ARRAY_PARAM(name) (name)
+#else
+    #define JSON_HEDLEY_ARRAY_PARAM(name)
+#endif
+
+#if defined(JSON_HEDLEY_IS_CONSTANT)
+    #undef JSON_HEDLEY_IS_CONSTANT
+#endif
+#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)
+    #undef JSON_HEDLEY_REQUIRE_CONSTEXPR
+#endif
+/* JSON_HEDLEY_IS_CONSTEXPR_ is for
+   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */
+#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
+    #undef JSON_HEDLEY_IS_CONSTEXPR_
+#endif
+#if \
+    JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \
+    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \
+    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
+    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
+    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \
+    JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
+    #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)
+#endif
+#if !defined(__cplusplus)
+#  if \
+       JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \
+       JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
+       JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+       JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
+       JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
+       JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
+       JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)
+#if defined(__INTPTR_TYPE__)
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)
+#else
+    #include <stdint.h>
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)
+#endif
+#  elif \
+       ( \
+          defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
+          !defined(JSON_HEDLEY_SUNPRO_VERSION) && \
+          !defined(JSON_HEDLEY_PGI_VERSION) && \
+          !defined(JSON_HEDLEY_IAR_VERSION)) || \
+       (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
+       JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
+       JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \
+       JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
+       JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)
+#if defined(__INTPTR_TYPE__)
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)
+#else
+    #include <stdint.h>
+    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)
+#endif
+#  elif \
+       defined(JSON_HEDLEY_GCC_VERSION) || \
+       defined(JSON_HEDLEY_INTEL_VERSION) || \
+       defined(JSON_HEDLEY_TINYC_VERSION) || \
+       defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \
+       JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \
+       defined(JSON_HEDLEY_TI_CL2000_VERSION) || \
+       defined(JSON_HEDLEY_TI_CL6X_VERSION) || \
+       defined(JSON_HEDLEY_TI_CL7X_VERSION) || \
+       defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \
+       defined(__clang__)
+#    define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \
+        sizeof(void) != \
+        sizeof(*( \
+                  1 ? \
+                  ((void*) ((expr) * 0L) ) : \
+((struct { char v[sizeof(void) * 2]; } *) 1) \
+                ) \
+              ) \
+                                            )
+#  endif
+#endif
+#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
+    #if !defined(JSON_HEDLEY_IS_CONSTANT)
+        #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr)
+    #endif
+    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1))
+#else
+    #if !defined(JSON_HEDLEY_IS_CONSTANT)
+        #define JSON_HEDLEY_IS_CONSTANT(expr) (0)
+    #endif
+    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)
+#endif
+
+#if defined(JSON_HEDLEY_BEGIN_C_DECLS)
+    #undef JSON_HEDLEY_BEGIN_C_DECLS
+#endif
+#if defined(JSON_HEDLEY_END_C_DECLS)
+    #undef JSON_HEDLEY_END_C_DECLS
+#endif
+#if defined(JSON_HEDLEY_C_DECL)
+    #undef JSON_HEDLEY_C_DECL
+#endif
+#if defined(__cplusplus)
+    #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" {
+    #define JSON_HEDLEY_END_C_DECLS }
+    #define JSON_HEDLEY_C_DECL extern "C"
+#else
+    #define JSON_HEDLEY_BEGIN_C_DECLS
+    #define JSON_HEDLEY_END_C_DECLS
+    #define JSON_HEDLEY_C_DECL
+#endif
+
+#if defined(JSON_HEDLEY_STATIC_ASSERT)
+    #undef JSON_HEDLEY_STATIC_ASSERT
+#endif
+#if \
+  !defined(__cplusplus) && ( \
+      (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \
+      (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
+      JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \
+      JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
+      defined(_Static_assert) \
+    )
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)
+#elif \
+  (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))
+#else
+#  define JSON_HEDLEY_STATIC_ASSERT(expr, message)
+#endif
+
+#if defined(JSON_HEDLEY_NULL)
+    #undef JSON_HEDLEY_NULL
+#endif
+#if defined(__cplusplus)
+    #if __cplusplus >= 201103L
+        #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)
+    #elif defined(NULL)
+        #define JSON_HEDLEY_NULL NULL
+    #else
+        #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0)
+    #endif
+#elif defined(NULL)
+    #define JSON_HEDLEY_NULL NULL
+#else
+    #define JSON_HEDLEY_NULL ((void*) 0)
+#endif
+
+#if defined(JSON_HEDLEY_MESSAGE)
+    #undef JSON_HEDLEY_MESSAGE
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+#  define JSON_HEDLEY_MESSAGE(msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
+    JSON_HEDLEY_PRAGMA(message msg) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#elif \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)
+#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)
+#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)
+#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#else
+#  define JSON_HEDLEY_MESSAGE(msg)
+#endif
+
+#if defined(JSON_HEDLEY_WARNING)
+    #undef JSON_HEDLEY_WARNING
+#endif
+#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
+#  define JSON_HEDLEY_WARNING(msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
+    JSON_HEDLEY_PRAGMA(clang warning msg) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#elif \
+  JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \
+  JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
+  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)
+#elif \
+  JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
+  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))
+#else
+#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)
+#endif
+
+#if defined(JSON_HEDLEY_REQUIRE)
+    #undef JSON_HEDLEY_REQUIRE
+#endif
+#if defined(JSON_HEDLEY_REQUIRE_MSG)
+    #undef JSON_HEDLEY_REQUIRE_MSG
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)
+#  if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat")
+#    define JSON_HEDLEY_REQUIRE(expr) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
+    __attribute__((diagnose_if(!(expr), #expr, "error"))) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \
+    JSON_HEDLEY_DIAGNOSTIC_PUSH \
+    _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
+    __attribute__((diagnose_if(!(expr), msg, "error"))) \
+    JSON_HEDLEY_DIAGNOSTIC_POP
+#  else
+#    define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error")))
+#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error")))
+#  endif
+#else
+#  define JSON_HEDLEY_REQUIRE(expr)
+#  define JSON_HEDLEY_REQUIRE_MSG(expr,msg)
+#endif
+
+#if defined(JSON_HEDLEY_FLAGS)
+    #undef JSON_HEDLEY_FLAGS
+#endif
+#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion"))
+    #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))
+#else
+    #define JSON_HEDLEY_FLAGS
+#endif
+
+#if defined(JSON_HEDLEY_FLAGS_CAST)
+    #undef JSON_HEDLEY_FLAGS_CAST
+#endif
+#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)
+#  define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \
+        JSON_HEDLEY_DIAGNOSTIC_PUSH \
+        _Pragma("warning(disable:188)") \
+        ((T) (expr)); \
+        JSON_HEDLEY_DIAGNOSTIC_POP \
+    }))
+#else
+#  define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)
+#endif
+
+#if defined(JSON_HEDLEY_EMPTY_BASES)
+    #undef JSON_HEDLEY_EMPTY_BASES
+#endif
+#if \
+    (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \
+    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
+    #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)
+#else
+    #define JSON_HEDLEY_EMPTY_BASES
+#endif
+
+/* Remaining macros are deprecated. */
+
+#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)
+    #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
+#endif
+#if defined(__clang__)
+    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)
+#else
+    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
+#endif
+
+#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)
+    #undef JSON_HEDLEY_CLANG_HAS_BUILTIN
+#endif
+#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)
+    #undef JSON_HEDLEY_CLANG_HAS_FEATURE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)
+    #undef JSON_HEDLEY_CLANG_HAS_EXTENSION
+#endif
+#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)
+    #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
+#endif
+#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)
+
+#if defined(JSON_HEDLEY_CLANG_HAS_WARNING)
+    #undef JSON_HEDLEY_CLANG_HAS_WARNING
+#endif
+#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)
+
+#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */
+
+
+// This file contains all internal macro definitions (except those affecting ABI)
+// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+
+// exclude unsupported compilers
+#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
+    #if defined(__clang__)
+        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
+            #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
+        #endif
+    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
+        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800
+            #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
+        #endif
+    #endif
+#endif
+
+// C++ language standard detection
+// if the user manually specified the used c++ version this is skipped
+#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
+    #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
+        #define JSON_HAS_CPP_20
+        #define JSON_HAS_CPP_17
+        #define JSON_HAS_CPP_14
+    #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
+        #define JSON_HAS_CPP_17
+        #define JSON_HAS_CPP_14
+    #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
+        #define JSON_HAS_CPP_14
+    #endif
+    // the cpp 11 flag is always specified because it is the minimal required version
+    #define JSON_HAS_CPP_11
+#endif
+
+#ifdef __has_include
+    #if __has_include(<version>)
+        #include <version>
+    #endif
+#endif
+
+#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)
+    #ifdef JSON_HAS_CPP_17
+        #if defined(__cpp_lib_filesystem)
+            #define JSON_HAS_FILESYSTEM 1
+        #elif defined(__cpp_lib_experimental_filesystem)
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #elif !defined(__has_include)
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #elif __has_include(<filesystem>)
+            #define JSON_HAS_FILESYSTEM 1
+        #elif __has_include(<experimental/filesystem>)
+            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
+        #endif
+
+        // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/
+        #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(__clang_major__) && __clang_major__ < 7
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support
+        #if defined(_MSC_VER) && _MSC_VER < 1914
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before iOS 13
+        #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+
+        // no filesystem support before macOS Catalina
+        #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
+            #undef JSON_HAS_FILESYSTEM
+            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+        #endif
+    #endif
+#endif
+
+#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+    #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0
+#endif
+
+#ifndef JSON_HAS_FILESYSTEM
+    #define JSON_HAS_FILESYSTEM 0
+#endif
+
+#ifndef JSON_HAS_THREE_WAY_COMPARISON
+    #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \
+        && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
+        #define JSON_HAS_THREE_WAY_COMPARISON 1
+    #else
+        #define JSON_HAS_THREE_WAY_COMPARISON 0
+    #endif
+#endif
+
+#ifndef JSON_HAS_RANGES
+    // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error
+    #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427
+        #define JSON_HAS_RANGES 0
+    #elif defined(__cpp_lib_ranges)
+        #define JSON_HAS_RANGES 1
+    #else
+        #define JSON_HAS_RANGES 0
+    #endif
+#endif
+
+#ifdef JSON_HAS_CPP_17
+    #define JSON_INLINE_VARIABLE inline
+#else
+    #define JSON_INLINE_VARIABLE
+#endif
+
+#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
+    #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
+#else
+    #define JSON_NO_UNIQUE_ADDRESS
+#endif
+
+// disable documentation warnings on clang
+#if defined(__clang__)
+    #pragma clang diagnostic push
+    #pragma clang diagnostic ignored "-Wdocumentation"
+    #pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
+#endif
+
+// allow disabling exceptions
+#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
+    #define JSON_THROW(exception) throw exception
+    #define JSON_TRY try
+    #define JSON_CATCH(exception) catch(exception)
+    #define JSON_INTERNAL_CATCH(exception) catch(exception)
+#else
+    #include <cstdlib>
+    #define JSON_THROW(exception) std::abort()
+    #define JSON_TRY if(true)
+    #define JSON_CATCH(exception) if(false)
+    #define JSON_INTERNAL_CATCH(exception) if(false)
+#endif
+
+// override exception macros
+#if defined(JSON_THROW_USER)
+    #undef JSON_THROW
+    #define JSON_THROW JSON_THROW_USER
+#endif
+#if defined(JSON_TRY_USER)
+    #undef JSON_TRY
+    #define JSON_TRY JSON_TRY_USER
+#endif
+#if defined(JSON_CATCH_USER)
+    #undef JSON_CATCH
+    #define JSON_CATCH JSON_CATCH_USER
+    #undef JSON_INTERNAL_CATCH
+    #define JSON_INTERNAL_CATCH JSON_CATCH_USER
+#endif
+#if defined(JSON_INTERNAL_CATCH_USER)
+    #undef JSON_INTERNAL_CATCH
+    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
+#endif
+
+// allow overriding assert
+#if !defined(JSON_ASSERT)
+    #include <cassert> // assert
+    #define JSON_ASSERT(x) assert(x)
+#endif
+
+// allow to access some private functions (needed by the test suite)
+#if defined(JSON_TESTS_PRIVATE)
+    #define JSON_PRIVATE_UNLESS_TESTED public
+#else
+    #define JSON_PRIVATE_UNLESS_TESTED private
+#endif
+
+/*!
+@brief macro to briefly define a mapping between an enum and JSON
+@def NLOHMANN_JSON_SERIALIZE_ENUM
+@since version 3.4.0
+*/
+#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                            \
+    template<typename BasicJsonType>                                                            \
+    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                   \
+    {                                                                                           \
+        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!");          \
+        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \
+        auto it = std::find_if(std::begin(m), std::end(m),                                      \
+                               [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool  \
+        {                                                                                       \
+            return ej_pair.first == e;                                                          \
+        });                                                                                     \
+        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                 \
+    }                                                                                           \
+    template<typename BasicJsonType>                                                            \
+    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                 \
+    {                                                                                           \
+        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!");          \
+        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \
+        auto it = std::find_if(std::begin(m), std::end(m),                                      \
+                               [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
+        {                                                                                       \
+            return ej_pair.second == j;                                                         \
+        });                                                                                     \
+        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                  \
+    }
+
+// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
+// may be removed in the future once the class is split.
+
+#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \
+    template<template<typename, typename, typename...> class ObjectType,   \
+             template<typename, typename...> class ArrayType,              \
+             class StringType, class BooleanType, class NumberIntegerType, \
+             class NumberUnsignedType, class NumberFloatType,              \
+             template<typename> class AllocatorType,                       \
+             template<typename, typename = void> class JSONSerializer,     \
+             class BinaryType>
+
+#define NLOHMANN_BASIC_JSON_TPL                                            \
+    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \
+    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \
+    AllocatorType, JSONSerializer, BinaryType>
+
+// Macros to simplify conversion from/to types
+
+#define NLOHMANN_JSON_EXPAND( x ) x
+#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
+#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
+        NLOHMANN_JSON_PASTE64, \
+        NLOHMANN_JSON_PASTE63, \
+        NLOHMANN_JSON_PASTE62, \
+        NLOHMANN_JSON_PASTE61, \
+        NLOHMANN_JSON_PASTE60, \
+        NLOHMANN_JSON_PASTE59, \
+        NLOHMANN_JSON_PASTE58, \
+        NLOHMANN_JSON_PASTE57, \
+        NLOHMANN_JSON_PASTE56, \
+        NLOHMANN_JSON_PASTE55, \
+        NLOHMANN_JSON_PASTE54, \
+        NLOHMANN_JSON_PASTE53, \
+        NLOHMANN_JSON_PASTE52, \
+        NLOHMANN_JSON_PASTE51, \
+        NLOHMANN_JSON_PASTE50, \
+        NLOHMANN_JSON_PASTE49, \
+        NLOHMANN_JSON_PASTE48, \
+        NLOHMANN_JSON_PASTE47, \
+        NLOHMANN_JSON_PASTE46, \
+        NLOHMANN_JSON_PASTE45, \
+        NLOHMANN_JSON_PASTE44, \
+        NLOHMANN_JSON_PASTE43, \
+        NLOHMANN_JSON_PASTE42, \
+        NLOHMANN_JSON_PASTE41, \
+        NLOHMANN_JSON_PASTE40, \
+        NLOHMANN_JSON_PASTE39, \
+        NLOHMANN_JSON_PASTE38, \
+        NLOHMANN_JSON_PASTE37, \
+        NLOHMANN_JSON_PASTE36, \
+        NLOHMANN_JSON_PASTE35, \
+        NLOHMANN_JSON_PASTE34, \
+        NLOHMANN_JSON_PASTE33, \
+        NLOHMANN_JSON_PASTE32, \
+        NLOHMANN_JSON_PASTE31, \
+        NLOHMANN_JSON_PASTE30, \
+        NLOHMANN_JSON_PASTE29, \
+        NLOHMANN_JSON_PASTE28, \
+        NLOHMANN_JSON_PASTE27, \
+        NLOHMANN_JSON_PASTE26, \
+        NLOHMANN_JSON_PASTE25, \
+        NLOHMANN_JSON_PASTE24, \
+        NLOHMANN_JSON_PASTE23, \
+        NLOHMANN_JSON_PASTE22, \
+        NLOHMANN_JSON_PASTE21, \
+        NLOHMANN_JSON_PASTE20, \
+        NLOHMANN_JSON_PASTE19, \
+        NLOHMANN_JSON_PASTE18, \
+        NLOHMANN_JSON_PASTE17, \
+        NLOHMANN_JSON_PASTE16, \
+        NLOHMANN_JSON_PASTE15, \
+        NLOHMANN_JSON_PASTE14, \
+        NLOHMANN_JSON_PASTE13, \
+        NLOHMANN_JSON_PASTE12, \
+        NLOHMANN_JSON_PASTE11, \
+        NLOHMANN_JSON_PASTE10, \
+        NLOHMANN_JSON_PASTE9, \
+        NLOHMANN_JSON_PASTE8, \
+        NLOHMANN_JSON_PASTE7, \
+        NLOHMANN_JSON_PASTE6, \
+        NLOHMANN_JSON_PASTE5, \
+        NLOHMANN_JSON_PASTE4, \
+        NLOHMANN_JSON_PASTE3, \
+        NLOHMANN_JSON_PASTE2, \
+        NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
+#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
+#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
+#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
+#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)
+#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)
+#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)
+#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
+#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
+#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)
+#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
+#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
+#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
+#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
+#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
+#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
+#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
+#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
+#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
+#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
+#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
+#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
+#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
+#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
+#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
+#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
+#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
+#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
+#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
+#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
+#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
+#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
+#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
+#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
+#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
+#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
+#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
+#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
+#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
+#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
+#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)
+#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
+#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)
+#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)
+#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)
+#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)
+#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)
+#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)
+#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)
+#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)
+#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)
+#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)
+#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
+#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)
+#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)
+#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)
+#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)
+#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)
+#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)
+#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)
+#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)
+#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)
+#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)
+#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)
+
+#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;
+#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);
+#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1);
+
+/*!
+@brief macro
+@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
+@since version 3.9.0
+*/
+#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)  \
+    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
+
+#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...)  \
+    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
+
+/*!
+@brief macro
+@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
+@since version 3.9.0
+*/
+#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)  \
+    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+    inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
+
+#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...)  \
+    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
+    inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
+
+
+// inspired from https://stackoverflow.com/a/26745591
+// allows to call any std function as if (e.g. with begin):
+// using std::begin; begin(x);
+//
+// it allows using the detected idiom to retrieve the return type
+// of such an expression
+#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name)                                 \
+    namespace detail {                                                            \
+    using std::std_name;                                                          \
+    \
+    template<typename... T>                                                       \
+    using result_of_##std_name = decltype(std_name(std::declval<T>()...));        \
+    }                                                                             \
+    \
+    namespace detail2 {                                                           \
+    struct std_name##_tag                                                         \
+    {                                                                             \
+    };                                                                            \
+    \
+    template<typename... T>                                                       \
+    std_name##_tag std_name(T&&...);                                              \
+    \
+    template<typename... T>                                                       \
+    using result_of_##std_name = decltype(std_name(std::declval<T>()...));        \
+    \
+    template<typename... T>                                                       \
+    struct would_call_std_##std_name                                              \
+    {                                                                             \
+        static constexpr auto const value = ::nlohmann::detail::                  \
+                                            is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
+    };                                                                            \
+    } /* namespace detail2 */ \
+    \
+    template<typename... T>                                                       \
+    struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...>   \
+    {                                                                             \
+    }
+
+#ifndef JSON_USE_IMPLICIT_CONVERSIONS
+    #define JSON_USE_IMPLICIT_CONVERSIONS 1
+#endif
+
+#if JSON_USE_IMPLICIT_CONVERSIONS
+    #define JSON_EXPLICIT
+#else
+    #define JSON_EXPLICIT explicit
+#endif
+
+#ifndef JSON_DISABLE_ENUM_SERIALIZATION
+    #define JSON_DISABLE_ENUM_SERIALIZATION 0
+#endif
+
+#ifndef JSON_USE_GLOBAL_UDLS
+    #define JSON_USE_GLOBAL_UDLS 1
+#endif
+
+#if JSON_HAS_THREE_WAY_COMPARISON
+    #include <compare> // partial_ordering
+#endif
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////////////////////
+// JSON type enumeration //
+///////////////////////////
+
+/*!
+@brief the JSON type enumeration
+
+This enumeration collects the different JSON types. It is internally used to
+distinguish the stored values, and the functions @ref basic_json::is_null(),
+@ref basic_json::is_object(), @ref basic_json::is_array(),
+@ref basic_json::is_string(), @ref basic_json::is_boolean(),
+@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
+@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
+@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
+@ref basic_json::is_structured() rely on it.
+
+@note There are three enumeration entries (number_integer, number_unsigned, and
+number_float), because the library distinguishes these three types for numbers:
+@ref basic_json::number_unsigned_t is used for unsigned integers,
+@ref basic_json::number_integer_t is used for signed integers, and
+@ref basic_json::number_float_t is used for floating-point numbers or to
+approximate integers which do not fit in the limits of their respective type.
+
+@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON
+value with the default value for a given type
+
+@since version 1.0.0
+*/
+enum class value_t : std::uint8_t
+{
+    null,             ///< null value
+    object,           ///< object (unordered set of name/value pairs)
+    array,            ///< array (ordered collection of values)
+    string,           ///< string value
+    boolean,          ///< boolean value
+    number_integer,   ///< number value (signed integer)
+    number_unsigned,  ///< number value (unsigned integer)
+    number_float,     ///< number value (floating-point)
+    binary,           ///< binary array (ordered collection of bytes)
+    discarded         ///< discarded by the parser callback function
+};
+
+/*!
+@brief comparison operator for JSON types
+
+Returns an ordering that is similar to Python:
+- order: null < boolean < number < object < array < string < binary
+- furthermore, each type is not smaller than itself
+- discarded values are not comparable
+- binary is represented as a b"" string in python and directly comparable to a
+  string; however, making a binary array directly comparable with a string would
+  be surprising behavior in a JSON file.
+
+@since version 1.0.0
+*/
+#if JSON_HAS_THREE_WAY_COMPARISON
+    inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD*
+#else
+    inline bool operator<(const value_t lhs, const value_t rhs) noexcept
+#endif
+{
+    static constexpr std::array<std::uint8_t, 9> order = {{
+            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
+            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,
+            6 /* binary */
+        }
+    };
+
+    const auto l_index = static_cast<std::size_t>(lhs);
+    const auto r_index = static_cast<std::size_t>(rhs);
+#if JSON_HAS_THREE_WAY_COMPARISON
+    if (l_index < order.size() && r_index < order.size())
+    {
+        return order[l_index] <=> order[r_index]; // *NOPAD*
+    }
+    return std::partial_ordering::unordered;
+#else
+    return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
+#endif
+}
+
+// GCC selects the built-in operator< over an operator rewritten from
+// a user-defined spaceship operator
+// Clang, MSVC, and ICC select the rewritten candidate
+// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)
+#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)
+inline bool operator<(const value_t lhs, const value_t rhs) noexcept
+{
+    return std::is_lt(lhs <=> rhs); // *NOPAD*
+}
+#endif
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/string_escape.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*!
+@brief replace all occurrences of a substring by another string
+
+@param[in,out] s  the string to manipulate; changed so that all
+               occurrences of @a f are replaced with @a t
+@param[in]     f  the substring to replace with @a t
+@param[in]     t  the string to replace @a f
+
+@pre The search string @a f must not be empty. **This precondition is
+enforced with an assertion.**
+
+@since version 2.0.0
+*/
+template<typename StringType>
+inline void replace_substring(StringType& s, const StringType& f,
+                              const StringType& t)
+{
+    JSON_ASSERT(!f.empty());
+    for (auto pos = s.find(f);                // find first occurrence of f
+            pos != StringType::npos;          // make sure f was found
+            s.replace(pos, f.size(), t),      // replace with t, and
+            pos = s.find(f, pos + t.size()))  // find next occurrence of f
+    {}
+}
+
+/*!
+ * @brief string escaping as described in RFC 6901 (Sect. 4)
+ * @param[in] s string to escape
+ * @return    escaped string
+ *
+ * Note the order of escaping "~" to "~0" and "/" to "~1" is important.
+ */
+template<typename StringType>
+inline StringType escape(StringType s)
+{
+    replace_substring(s, StringType{"~"}, StringType{"~0"});
+    replace_substring(s, StringType{"/"}, StringType{"~1"});
+    return s;
+}
+
+/*!
+ * @brief string unescaping as described in RFC 6901 (Sect. 4)
+ * @param[in] s string to unescape
+ * @return    unescaped string
+ *
+ * Note the order of escaping "~1" to "/" and "~0" to "~" is important.
+ */
+template<typename StringType>
+static void unescape(StringType& s)
+{
+    replace_substring(s, StringType{"~1"}, StringType{"/"});
+    replace_substring(s, StringType{"~0"}, StringType{"~"});
+}
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/input/position_t.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstddef> // size_t
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// struct to capture the start position of the current token
+struct position_t
+{
+    /// the total number of characters read
+    std::size_t chars_read_total = 0;
+    /// the number of characters read in the current line
+    std::size_t chars_read_current_line = 0;
+    /// the number of lines read
+    std::size_t lines_read = 0;
+
+    /// conversion to size_t to preserve SAX interface
+    constexpr operator size_t() const
+    {
+        return chars_read_total;
+    }
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2018 The Abseil Authors
+// SPDX-License-Identifier: MIT
+
+
+
+#include <array> // array
+#include <cstddef> // size_t
+#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
+#include <utility> // index_sequence, make_index_sequence, index_sequence_for
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename T>
+using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+#ifdef JSON_HAS_CPP_14
+
+// the following utilities are natively available in C++14
+using std::enable_if_t;
+using std::index_sequence;
+using std::make_index_sequence;
+using std::index_sequence_for;
+
+#else
+
+// alias templates to reduce boilerplate
+template<bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h
+// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0.
+
+//// START OF CODE FROM GOOGLE ABSEIL
+
+// integer_sequence
+//
+// Class template representing a compile-time integer sequence. An instantiation
+// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its
+// type through its template arguments (which is a common need when
+// working with C++11 variadic templates). `absl::integer_sequence` is designed
+// to be a drop-in replacement for C++14's `std::integer_sequence`.
+//
+// Example:
+//
+//   template< class T, T... Ints >
+//   void user_function(integer_sequence<T, Ints...>);
+//
+//   int main()
+//   {
+//     // user_function's `T` will be deduced to `int` and `Ints...`
+//     // will be deduced to `0, 1, 2, 3, 4`.
+//     user_function(make_integer_sequence<int, 5>());
+//   }
+template <typename T, T... Ints>
+struct integer_sequence
+{
+    using value_type = T;
+    static constexpr std::size_t size() noexcept
+    {
+        return sizeof...(Ints);
+    }
+};
+
+// index_sequence
+//
+// A helper template for an `integer_sequence` of `size_t`,
+// `absl::index_sequence` is designed to be a drop-in replacement for C++14's
+// `std::index_sequence`.
+template <size_t... Ints>
+using index_sequence = integer_sequence<size_t, Ints...>;
+
+namespace utility_internal
+{
+
+template <typename Seq, size_t SeqSize, size_t Rem>
+struct Extend;
+
+// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 0>
+{
+    using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >;
+};
+
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 1>
+{
+    using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >;
+};
+
+// Recursion helper for 'make_integer_sequence<T, N>'.
+// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
+template <typename T, size_t N>
+struct Gen
+{
+    using type =
+        typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type;
+};
+
+template <typename T>
+struct Gen<T, 0>
+{
+    using type = integer_sequence<T>;
+};
+
+}  // namespace utility_internal
+
+// Compile-time sequences of integers
+
+// make_integer_sequence
+//
+// This template alias is equivalent to
+// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
+// replacement for C++14's `std::make_integer_sequence`.
+template <typename T, T N>
+using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
+
+// make_index_sequence
+//
+// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
+// and is designed to be a drop-in replacement for C++14's
+// `std::make_index_sequence`.
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+
+// index_sequence_for
+//
+// Converts a typename pack into an index sequence of the same length, and
+// is designed to be a drop-in replacement for C++14's
+// `std::index_sequence_for()`
+template <typename... Ts>
+using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
+
+//// END OF CODE FROM GOOGLE ABSEIL
+
+#endif
+
+// dispatch utility (taken from ranges-v3)
+template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
+template<> struct priority_tag<0> {};
+
+// taken from ranges-v3
+template<typename T>
+struct static_const
+{
+    static JSON_INLINE_VARIABLE constexpr T value{};
+};
+
+#ifndef JSON_HAS_CPP_17
+    template<typename T>
+    constexpr T static_const<T>::value;
+#endif
+
+template<typename T, typename... Args>
+inline constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args)
+{
+    return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}};
+}
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <limits> // numeric_limits
+#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
+#include <utility> // declval
+#include <tuple> // tuple
+
+// #include <nlohmann/detail/iterators/iterator_traits.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <iterator> // random_access_iterator_tag
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+// #include <nlohmann/detail/meta/void_t.hpp>
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename It, typename = void>
+struct iterator_types {};
+
+template<typename It>
+struct iterator_types <
+    It,
+    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
+    typename It::reference, typename It::iterator_category >>
+{
+    using difference_type = typename It::difference_type;
+    using value_type = typename It::value_type;
+    using pointer = typename It::pointer;
+    using reference = typename It::reference;
+    using iterator_category = typename It::iterator_category;
+};
+
+// This is required as some compilers implement std::iterator_traits in a way that
+// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
+template<typename T, typename = void>
+struct iterator_traits
+{
+};
+
+template<typename T>
+struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
+            : iterator_types<T>
+{
+};
+
+template<typename T>
+struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
+{
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type = T;
+    using difference_type = ptrdiff_t;
+    using pointer = T*;
+    using reference = T&;
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/call_std/begin.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/meta/call_std/end.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+// #include <nlohmann/detail/meta/detected.hpp>
+
+// #include <nlohmann/json_fwd.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
+    #define INCLUDE_NLOHMANN_JSON_FWD_HPP_
+
+    #include <cstdint> // int64_t, uint64_t
+    #include <map> // map
+    #include <memory> // allocator
+    #include <string> // string
+    #include <vector> // vector
+
+    // #include <nlohmann/detail/abi_macros.hpp>
+
+
+    /*!
+    @brief namespace for Niels Lohmann
+    @see https://github.com/nlohmann
+    @since version 1.0.0
+    */
+    NLOHMANN_JSON_NAMESPACE_BEGIN
+
+    /*!
+    @brief default JSONSerializer template argument
+
+    This serializer ignores the template arguments and uses ADL
+    ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
+    for serialization.
+    */
+    template<typename T = void, typename SFINAE = void>
+    struct adl_serializer;
+
+    /// a class to store JSON values
+    /// @sa https://json.nlohmann.me/api/basic_json/
+    template<template<typename U, typename V, typename... Args> class ObjectType =
+    std::map,
+    template<typename U, typename... Args> class ArrayType = std::vector,
+    class StringType = std::string, class BooleanType = bool,
+    class NumberIntegerType = std::int64_t,
+    class NumberUnsignedType = std::uint64_t,
+    class NumberFloatType = double,
+    template<typename U> class AllocatorType = std::allocator,
+    template<typename T, typename SFINAE = void> class JSONSerializer =
+    adl_serializer,
+    class BinaryType = std::vector<std::uint8_t>>
+    class basic_json;
+
+    /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
+    /// @sa https://json.nlohmann.me/api/json_pointer/
+    template<typename RefStringType>
+    class json_pointer;
+
+    /*!
+    @brief default specialization
+    @sa https://json.nlohmann.me/api/json/
+    */
+    using json = basic_json<>;
+
+    /// @brief a minimal map-like container that preserves insertion order
+    /// @sa https://json.nlohmann.me/api/ordered_map/
+    template<class Key, class T, class IgnoredLess, class Allocator>
+    struct ordered_map;
+
+    /// @brief specialization that maintains the insertion order of object keys
+    /// @sa https://json.nlohmann.me/api/ordered_json/
+    using ordered_json = basic_json<nlohmann::ordered_map>;
+
+    NLOHMANN_JSON_NAMESPACE_END
+
+#endif  // INCLUDE_NLOHMANN_JSON_FWD_HPP_
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+/*!
+@brief detail namespace with internal helper functions
+
+This namespace collects functions that should not be exposed,
+implementations of some @ref basic_json methods, and meta-programming helpers.
+
+@since version 2.1.0
+*/
+namespace detail
+{
+
+/////////////
+// helpers //
+/////////////
+
+// Note to maintainers:
+//
+// Every trait in this file expects a non CV-qualified type.
+// The only exceptions are in the 'aliases for detected' section
+// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
+//
+// In this case, T has to be properly CV-qualified to constraint the function arguments
+// (e.g. to_json(BasicJsonType&, const T&))
+
+template<typename> struct is_basic_json : std::false_type {};
+
+NLOHMANN_BASIC_JSON_TPL_DECLARATION
+struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
+
+// used by exceptions create() member functions
+// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
+// false_type otherwise
+template<typename BasicJsonContext>
+struct is_basic_json_context :
+    std::integral_constant < bool,
+    is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value
+    || std::is_same<BasicJsonContext, std::nullptr_t>::value >
+{};
+
+//////////////////////
+// json_ref helpers //
+//////////////////////
+
+template<typename>
+class json_ref;
+
+template<typename>
+struct is_json_ref : std::false_type {};
+
+template<typename T>
+struct is_json_ref<json_ref<T>> : std::true_type {};
+
+//////////////////////////
+// aliases for detected //
+//////////////////////////
+
+template<typename T>
+using mapped_type_t = typename T::mapped_type;
+
+template<typename T>
+using key_type_t = typename T::key_type;
+
+template<typename T>
+using value_type_t = typename T::value_type;
+
+template<typename T>
+using difference_type_t = typename T::difference_type;
+
+template<typename T>
+using pointer_t = typename T::pointer;
+
+template<typename T>
+using reference_t = typename T::reference;
+
+template<typename T>
+using iterator_category_t = typename T::iterator_category;
+
+template<typename T, typename... Args>
+using to_json_function = decltype(T::to_json(std::declval<Args>()...));
+
+template<typename T, typename... Args>
+using from_json_function = decltype(T::from_json(std::declval<Args>()...));
+
+template<typename T, typename U>
+using get_template_function = decltype(std::declval<T>().template get<U>());
+
+// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
+template<typename BasicJsonType, typename T, typename = void>
+struct has_from_json : std::false_type {};
+
+// trait checking if j.get<T> is valid
+// use this trait instead of std::is_constructible or std::is_convertible,
+// both rely on, or make use of implicit conversions, and thus fail when T
+// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
+template <typename BasicJsonType, typename T>
+struct is_getable
+{
+    static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
+};
+
+template<typename BasicJsonType, typename T>
+struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer<T, void>;
+
+    static constexpr bool value =
+        is_detected_exact<void, from_json_function, serializer,
+        const BasicJsonType&, T&>::value;
+};
+
+// This trait checks if JSONSerializer<T>::from_json(json const&) exists
+// this overload is used for non-default-constructible user-defined-types
+template<typename BasicJsonType, typename T, typename = void>
+struct has_non_default_from_json : std::false_type {};
+
+template<typename BasicJsonType, typename T>
+struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer<T, void>;
+
+    static constexpr bool value =
+        is_detected_exact<T, from_json_function, serializer,
+        const BasicJsonType&>::value;
+};
+
+// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
+// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
+template<typename BasicJsonType, typename T, typename = void>
+struct has_to_json : std::false_type {};
+
+template<typename BasicJsonType, typename T>
+struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
+{
+    using serializer = typename BasicJsonType::template json_serializer<T, void>;
+
+    static constexpr bool value =
+        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
+        T>::value;
+};
+
+template<typename T>
+using detect_key_compare = typename T::key_compare;
+
+template<typename T>
+struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
+
+// obtains the actual object key comparator
+template<typename BasicJsonType>
+struct actual_object_comparator
+{
+    using object_t = typename BasicJsonType::object_t;
+    using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
+    using type = typename std::conditional < has_key_compare<object_t>::value,
+          typename object_t::key_compare, object_comparator_t>::type;
+};
+
+template<typename BasicJsonType>
+using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
+
+///////////////////
+// is_ functions //
+///////////////////
+
+// https://en.cppreference.com/w/cpp/types/conjunction
+template<class...> struct conjunction : std::true_type { };
+template<class B> struct conjunction<B> : B { };
+template<class B, class... Bn>
+struct conjunction<B, Bn...>
+: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
+
+// https://en.cppreference.com/w/cpp/types/negation
+template<class B> struct negation : std::integral_constant < bool, !B::value > { };
+
+// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
+// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
+// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
+template <typename T>
+struct is_default_constructible : std::is_default_constructible<T> {};
+
+template <typename T1, typename T2>
+struct is_default_constructible<std::pair<T1, T2>>
+            : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
+
+template <typename T1, typename T2>
+struct is_default_constructible<const std::pair<T1, T2>>
+            : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
+
+template <typename... Ts>
+struct is_default_constructible<std::tuple<Ts...>>
+            : conjunction<is_default_constructible<Ts>...> {};
+
+template <typename... Ts>
+struct is_default_constructible<const std::tuple<Ts...>>
+            : conjunction<is_default_constructible<Ts>...> {};
+
+
+template <typename T, typename... Args>
+struct is_constructible : std::is_constructible<T, Args...> {};
+
+template <typename T1, typename T2>
+struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};
+
+template <typename T1, typename T2>
+struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};
+
+template <typename... Ts>
+struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};
+
+template <typename... Ts>
+struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
+
+
+template<typename T, typename = void>
+struct is_iterator_traits : std::false_type {};
+
+template<typename T>
+struct is_iterator_traits<iterator_traits<T>>
+{
+  private:
+    using traits = iterator_traits<T>;
+
+  public:
+    static constexpr auto value =
+        is_detected<value_type_t, traits>::value &&
+        is_detected<difference_type_t, traits>::value &&
+        is_detected<pointer_t, traits>::value &&
+        is_detected<iterator_category_t, traits>::value &&
+        is_detected<reference_t, traits>::value;
+};
+
+template<typename T>
+struct is_range
+{
+  private:
+    using t_ref = typename std::add_lvalue_reference<T>::type;
+
+    using iterator = detected_t<result_of_begin, t_ref>;
+    using sentinel = detected_t<result_of_end, t_ref>;
+
+    // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
+    // and https://en.cppreference.com/w/cpp/iterator/sentinel_for
+    // but reimplementing these would be too much work, as a lot of other concepts are used underneath
+    static constexpr auto is_iterator_begin =
+        is_iterator_traits<iterator_traits<iterator>>::value;
+
+  public:
+    static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;
+};
+
+template<typename R>
+using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;
+
+template<typename T>
+using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
+
+// The following implementation of is_complete_type is taken from
+// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
+// and is written by Xiang Fan who agreed to using it in this library.
+
+template<typename T, typename = void>
+struct is_complete_type : std::false_type {};
+
+template<typename T>
+struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
+
+template<typename BasicJsonType, typename CompatibleObjectType,
+         typename = void>
+struct is_compatible_object_type_impl : std::false_type {};
+
+template<typename BasicJsonType, typename CompatibleObjectType>
+struct is_compatible_object_type_impl <
+    BasicJsonType, CompatibleObjectType,
+    enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
+    is_detected<key_type_t, CompatibleObjectType>::value >>
+{
+    using object_t = typename BasicJsonType::object_t;
+
+    // macOS's is_constructible does not play well with nonesuch...
+    static constexpr bool value =
+        is_constructible<typename object_t::key_type,
+        typename CompatibleObjectType::key_type>::value &&
+        is_constructible<typename object_t::mapped_type,
+        typename CompatibleObjectType::mapped_type>::value;
+};
+
+template<typename BasicJsonType, typename CompatibleObjectType>
+struct is_compatible_object_type
+    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
+
+template<typename BasicJsonType, typename ConstructibleObjectType,
+         typename = void>
+struct is_constructible_object_type_impl : std::false_type {};
+
+template<typename BasicJsonType, typename ConstructibleObjectType>
+struct is_constructible_object_type_impl <
+    BasicJsonType, ConstructibleObjectType,
+    enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
+    is_detected<key_type_t, ConstructibleObjectType>::value >>
+{
+    using object_t = typename BasicJsonType::object_t;
+
+    static constexpr bool value =
+        (is_default_constructible<ConstructibleObjectType>::value &&
+         (std::is_move_assignable<ConstructibleObjectType>::value ||
+          std::is_copy_assignable<ConstructibleObjectType>::value) &&
+         (is_constructible<typename ConstructibleObjectType::key_type,
+          typename object_t::key_type>::value &&
+          std::is_same <
+          typename object_t::mapped_type,
+          typename ConstructibleObjectType::mapped_type >::value)) ||
+        (has_from_json<BasicJsonType,
+         typename ConstructibleObjectType::mapped_type>::value ||
+         has_non_default_from_json <
+         BasicJsonType,
+         typename ConstructibleObjectType::mapped_type >::value);
+};
+
+template<typename BasicJsonType, typename ConstructibleObjectType>
+struct is_constructible_object_type
+    : is_constructible_object_type_impl<BasicJsonType,
+      ConstructibleObjectType> {};
+
+template<typename BasicJsonType, typename CompatibleStringType>
+struct is_compatible_string_type
+{
+    static constexpr auto value =
+        is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
+};
+
+template<typename BasicJsonType, typename ConstructibleStringType>
+struct is_constructible_string_type
+{
+    // launder type through decltype() to fix compilation failure on ICPC
+#ifdef __INTEL_COMPILER
+    using laundered_type = decltype(std::declval<ConstructibleStringType>());
+#else
+    using laundered_type = ConstructibleStringType;
+#endif
+
+    static constexpr auto value =
+        conjunction <
+        is_constructible<laundered_type, typename BasicJsonType::string_t>,
+        is_detected_exact<typename BasicJsonType::string_t::value_type,
+        value_type_t, laundered_type >>::value;
+};
+
+template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
+struct is_compatible_array_type_impl : std::false_type {};
+
+template<typename BasicJsonType, typename CompatibleArrayType>
+struct is_compatible_array_type_impl <
+    BasicJsonType, CompatibleArrayType,
+    enable_if_t <
+    is_detected<iterator_t, CompatibleArrayType>::value&&
+    is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
+// special case for types like std::filesystem::path whose iterator's value_type are themselves
+// c.f. https://github.com/nlohmann/json/pull/3073
+    !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
+{
+    static constexpr bool value =
+        is_constructible<BasicJsonType,
+        range_value_t<CompatibleArrayType>>::value;
+};
+
+template<typename BasicJsonType, typename CompatibleArrayType>
+struct is_compatible_array_type
+    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
+
+template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
+struct is_constructible_array_type_impl : std::false_type {};
+
+template<typename BasicJsonType, typename ConstructibleArrayType>
+struct is_constructible_array_type_impl <
+    BasicJsonType, ConstructibleArrayType,
+    enable_if_t<std::is_same<ConstructibleArrayType,
+    typename BasicJsonType::value_type>::value >>
+            : std::true_type {};
+
+template<typename BasicJsonType, typename ConstructibleArrayType>
+struct is_constructible_array_type_impl <
+    BasicJsonType, ConstructibleArrayType,
+    enable_if_t < !std::is_same<ConstructibleArrayType,
+    typename BasicJsonType::value_type>::value&&
+    !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
+    is_default_constructible<ConstructibleArrayType>::value&&
+(std::is_move_assignable<ConstructibleArrayType>::value ||
+ std::is_copy_assignable<ConstructibleArrayType>::value)&&
+is_detected<iterator_t, ConstructibleArrayType>::value&&
+is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
+is_detected<range_value_t, ConstructibleArrayType>::value&&
+// special case for types like std::filesystem::path whose iterator's value_type are themselves
+// c.f. https://github.com/nlohmann/json/pull/3073
+!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
+        is_complete_type <
+        detected_t<range_value_t, ConstructibleArrayType >>::value >>
+{
+    using value_type = range_value_t<ConstructibleArrayType>;
+
+    static constexpr bool value =
+        std::is_same<value_type,
+        typename BasicJsonType::array_t::value_type>::value ||
+        has_from_json<BasicJsonType,
+        value_type>::value ||
+        has_non_default_from_json <
+        BasicJsonType,
+        value_type >::value;
+};
+
+template<typename BasicJsonType, typename ConstructibleArrayType>
+struct is_constructible_array_type
+    : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
+
+template<typename RealIntegerType, typename CompatibleNumberIntegerType,
+         typename = void>
+struct is_compatible_integer_type_impl : std::false_type {};
+
+template<typename RealIntegerType, typename CompatibleNumberIntegerType>
+struct is_compatible_integer_type_impl <
+    RealIntegerType, CompatibleNumberIntegerType,
+    enable_if_t < std::is_integral<RealIntegerType>::value&&
+    std::is_integral<CompatibleNumberIntegerType>::value&&
+    !std::is_same<bool, CompatibleNumberIntegerType>::value >>
+{
+    // is there an assert somewhere on overflows?
+    using RealLimits = std::numeric_limits<RealIntegerType>;
+    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
+
+    static constexpr auto value =
+        is_constructible<RealIntegerType,
+        CompatibleNumberIntegerType>::value &&
+        CompatibleLimits::is_integer &&
+        RealLimits::is_signed == CompatibleLimits::is_signed;
+};
+
+template<typename RealIntegerType, typename CompatibleNumberIntegerType>
+struct is_compatible_integer_type
+    : is_compatible_integer_type_impl<RealIntegerType,
+      CompatibleNumberIntegerType> {};
+
+template<typename BasicJsonType, typename CompatibleType, typename = void>
+struct is_compatible_type_impl: std::false_type {};
+
+template<typename BasicJsonType, typename CompatibleType>
+struct is_compatible_type_impl <
+    BasicJsonType, CompatibleType,
+    enable_if_t<is_complete_type<CompatibleType>::value >>
+{
+    static constexpr bool value =
+        has_to_json<BasicJsonType, CompatibleType>::value;
+};
+
+template<typename BasicJsonType, typename CompatibleType>
+struct is_compatible_type
+    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
+
+template<typename T1, typename T2>
+struct is_constructible_tuple : std::false_type {};
+
+template<typename T1, typename... Args>
+struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
+
+template<typename BasicJsonType, typename T>
+struct is_json_iterator_of : std::false_type {};
+
+template<typename BasicJsonType>
+struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
+
+template<typename BasicJsonType>
+struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
+{};
+
+// checks if a given type T is a template specialization of Primary
+template<template <typename...> class Primary, typename T>
+struct is_specialization_of : std::false_type {};
+
+template<template <typename...> class Primary, typename... Args>
+struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
+
+template<typename T>
+using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
+
+// checks if A and B are comparable using Compare functor
+template<typename Compare, typename A, typename B, typename = void>
+struct is_comparable : std::false_type {};
+
+template<typename Compare, typename A, typename B>
+struct is_comparable<Compare, A, B, void_t<
+decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
+decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
+>> : std::true_type {};
+
+template<typename T>
+using detect_is_transparent = typename T::is_transparent;
+
+// type trait to check if KeyType can be used as object key (without a BasicJsonType)
+// see is_usable_as_basic_json_key_type below
+template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
+         bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
+using is_usable_as_key_type = typename std::conditional <
+                              is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value
+                              && !(ExcludeObjectKeyType && std::is_same<KeyType,
+                                   ObjectKeyType>::value)
+                              && (!RequireTransparentComparator
+                                  || is_detected <detect_is_transparent, Comparator>::value)
+                              && !is_json_pointer<KeyType>::value,
+                              std::true_type,
+                              std::false_type >::type;
+
+// type trait to check if KeyType can be used as object key
+// true if:
+//   - KeyType is comparable with BasicJsonType::object_t::key_type
+//   - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
+//   - the comparator is transparent or RequireTransparentComparator is false
+//   - KeyType is not a JSON iterator or json_pointer
+template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
+         bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
+using is_usable_as_basic_json_key_type = typename std::conditional <
+        is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
+        typename BasicJsonType::object_t::key_type, KeyTypeCVRef,
+        RequireTransparentComparator, ExcludeObjectKeyType>::value
+        && !is_json_iterator_of<BasicJsonType, KeyType>::value,
+        std::true_type,
+        std::false_type >::type;
+
+template<typename ObjectType, typename KeyType>
+using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
+
+// type trait to check if object_t has an erase() member functions accepting KeyType
+template<typename BasicJsonType, typename KeyType>
+using has_erase_with_key_type = typename std::conditional <
+                                is_detected <
+                                detect_erase_with_key_type,
+                                typename BasicJsonType::object_t, KeyType >::value,
+                                std::true_type,
+                                std::false_type >::type;
+
+// a naive helper to check if a type is an ordered_map (exploits the fact that
+// ordered_map inherits capacity() from std::vector)
+template <typename T>
+struct is_ordered_map
+{
+    using one = char;
+
+    struct two
+    {
+        char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+    };
+
+    template <typename C> static one test( decltype(&C::capacity) ) ;
+    template <typename C> static two test(...);
+
+    enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+};
+
+// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
+template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
+T conditional_static_cast(U value)
+{
+    return static_cast<T>(value);
+}
+
+template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
+T conditional_static_cast(U value)
+{
+    return value;
+}
+
+template<typename... Types>
+using all_integral = conjunction<std::is_integral<Types>...>;
+
+template<typename... Types>
+using all_signed = conjunction<std::is_signed<Types>...>;
+
+template<typename... Types>
+using all_unsigned = conjunction<std::is_unsigned<Types>...>;
+
+// there's a disjunction trait in another PR; replace when merged
+template<typename... Types>
+using same_sign = std::integral_constant < bool,
+      all_signed<Types...>::value || all_unsigned<Types...>::value >;
+
+template<typename OfType, typename T>
+using never_out_of_range = std::integral_constant < bool,
+      (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))
+      || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
+
+template<typename OfType, typename T,
+         bool OfTypeSigned = std::is_signed<OfType>::value,
+         bool TSigned = std::is_signed<T>::value>
+struct value_in_range_of_impl2;
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl2<OfType, T, false, false>
+{
+    static constexpr bool test(T val)
+    {
+        using CommonType = typename std::common_type<OfType, T>::type;
+        return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
+    }
+};
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl2<OfType, T, true, false>
+{
+    static constexpr bool test(T val)
+    {
+        using CommonType = typename std::common_type<OfType, T>::type;
+        return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
+    }
+};
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl2<OfType, T, false, true>
+{
+    static constexpr bool test(T val)
+    {
+        using CommonType = typename std::common_type<OfType, T>::type;
+        return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
+    }
+};
+
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl2<OfType, T, true, true>
+{
+    static constexpr bool test(T val)
+    {
+        using CommonType = typename std::common_type<OfType, T>::type;
+        return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)())
+               && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
+    }
+};
+
+template<typename OfType, typename T,
+         bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
+         typename = detail::enable_if_t<all_integral<OfType, T>::value>>
+struct value_in_range_of_impl1;
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl1<OfType, T, false>
+{
+    static constexpr bool test(T val)
+    {
+        return value_in_range_of_impl2<OfType, T>::test(val);
+    }
+};
+
+template<typename OfType, typename T>
+struct value_in_range_of_impl1<OfType, T, true>
+{
+    static constexpr bool test(T /*val*/)
+    {
+        return true;
+    }
+};
+
+template<typename OfType, typename T>
+inline constexpr bool value_in_range_of(T val)
+{
+    return value_in_range_of_impl1<OfType, T>::test(val);
+}
+
+template<bool Value>
+using bool_constant = std::integral_constant<bool, Value>;
+
+///////////////////////////////////////////////////////////////////////////////
+// is_c_string
+///////////////////////////////////////////////////////////////////////////////
+
+namespace impl
+{
+
+template<typename T>
+inline constexpr bool is_c_string()
+{
+    using TUnExt = typename std::remove_extent<T>::type;
+    using TUnCVExt = typename std::remove_cv<TUnExt>::type;
+    using TUnPtr = typename std::remove_pointer<T>::type;
+    using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
+    return
+        (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)
+        || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
+}
+
+}  // namespace impl
+
+// checks whether T is a [cv] char */[cv] char[] C string
+template<typename T>
+struct is_c_string : bool_constant<impl::is_c_string<T>()> {};
+
+template<typename T>
+using is_c_string_uncvref = is_c_string<uncvref_t<T>>;
+
+///////////////////////////////////////////////////////////////////////////////
+// is_transparent
+///////////////////////////////////////////////////////////////////////////////
+
+namespace impl
+{
+
+template<typename T>
+inline constexpr bool is_transparent()
+{
+    return is_detected<detect_is_transparent, T>::value;
+}
+
+}  // namespace impl
+
+// checks whether T has a member named is_transparent
+template<typename T>
+struct is_transparent : bool_constant<impl::is_transparent<T>()> {};
+
+///////////////////////////////////////////////////////////////////////////////
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/string_concat.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstring> // strlen
+#include <string> // string
+#include <utility> // forward
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+// #include <nlohmann/detail/meta/detected.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+inline std::size_t concat_length()
+{
+    return 0;
+}
+
+template<typename... Args>
+inline std::size_t concat_length(const char* cstr, const Args& ... rest);
+
+template<typename StringType, typename... Args>
+inline std::size_t concat_length(const StringType& str, const Args& ... rest);
+
+template<typename... Args>
+inline std::size_t concat_length(const char /*c*/, const Args& ... rest)
+{
+    return 1 + concat_length(rest...);
+}
+
+template<typename... Args>
+inline std::size_t concat_length(const char* cstr, const Args& ... rest)
+{
+    // cppcheck-suppress ignoredReturnValue
+    return ::strlen(cstr) + concat_length(rest...);
+}
+
+template<typename StringType, typename... Args>
+inline std::size_t concat_length(const StringType& str, const Args& ... rest)
+{
+    return str.size() + concat_length(rest...);
+}
+
+template<typename OutStringType>
+inline void concat_into(OutStringType& /*out*/)
+{}
+
+template<typename StringType, typename Arg>
+using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ()));
+
+template<typename StringType, typename Arg>
+using detect_string_can_append = is_detected<string_can_append, StringType, Arg>;
+
+template<typename StringType, typename Arg>
+using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ());
+
+template<typename StringType, typename Arg>
+using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;
+
+template<typename StringType, typename Arg>
+using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end()));
+
+template<typename StringType, typename Arg>
+using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>;
+
+template<typename StringType, typename Arg>
+using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size()));
+
+template<typename StringType, typename Arg>
+using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >
+inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && !detect_string_can_append_op<OutStringType, Arg>::value
+                         && detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >
+inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && !detect_string_can_append_op<OutStringType, Arg>::value
+                         && !detect_string_can_append_iter<OutStringType, Arg>::value
+                         && detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >
+inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
+
+template<typename OutStringType, typename Arg, typename... Args,
+         enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>
+inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)
+{
+    out.append(std::forward<Arg>(arg));
+    concat_into(out, std::forward<Args>(rest)...);
+}
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && detect_string_can_append_op<OutStringType, Arg>::value, int > >
+inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)
+{
+    out += std::forward<Arg>(arg);
+    concat_into(out, std::forward<Args>(rest)...);
+}
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && !detect_string_can_append_op<OutStringType, Arg>::value
+                         && detect_string_can_append_iter<OutStringType, Arg>::value, int > >
+inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
+{
+    out.append(arg.begin(), arg.end());
+    concat_into(out, std::forward<Args>(rest)...);
+}
+
+template < typename OutStringType, typename Arg, typename... Args,
+           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
+                         && !detect_string_can_append_op<OutStringType, Arg>::value
+                         && !detect_string_can_append_iter<OutStringType, Arg>::value
+                         && detect_string_can_append_data<OutStringType, Arg>::value, int > >
+inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
+{
+    out.append(arg.data(), arg.size());
+    concat_into(out, std::forward<Args>(rest)...);
+}
+
+template<typename OutStringType = std::string, typename... Args>
+inline OutStringType concat(Args && ... args)
+{
+    OutStringType str;
+    str.reserve(concat_length(args...));
+    concat_into(str, std::forward<Args>(args)...);
+    return str;
+}
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+////////////////
+// exceptions //
+////////////////
+
+/// @brief general exception of the @ref basic_json class
+/// @sa https://json.nlohmann.me/api/basic_json/exception/
+class exception : public std::exception
+{
+  public:
+    /// returns the explanatory string
+    const char* what() const noexcept override
+    {
+        return m.what();
+    }
+
+    /// the id of the exception
+    const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
+
+  protected:
+    JSON_HEDLEY_NON_NULL(3)
+    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
+
+    static std::string name(const std::string& ename, int id_)
+    {
+        return concat("[json.exception.", ename, '.', std::to_string(id_), "] ");
+    }
+
+    static std::string diagnostics(std::nullptr_t /*leaf_element*/)
+    {
+        return "";
+    }
+
+    template<typename BasicJsonType>
+    static std::string diagnostics(const BasicJsonType* leaf_element)
+    {
+#if JSON_DIAGNOSTICS
+        std::vector<std::string> tokens;
+        for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent)
+        {
+            switch (current->m_parent->type())
+            {
+                case value_t::array:
+                {
+                    for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)
+                    {
+                        if (&current->m_parent->m_value.array->operator[](i) == current)
+                        {
+                            tokens.emplace_back(std::to_string(i));
+                            break;
+                        }
+                    }
+                    break;
+                }
+
+                case value_t::object:
+                {
+                    for (const auto& element : *current->m_parent->m_value.object)
+                    {
+                        if (&element.second == current)
+                        {
+                            tokens.emplace_back(element.first.c_str());
+                            break;
+                        }
+                    }
+                    break;
+                }
+
+                case value_t::null: // LCOV_EXCL_LINE
+                case value_t::string: // LCOV_EXCL_LINE
+                case value_t::boolean: // LCOV_EXCL_LINE
+                case value_t::number_integer: // LCOV_EXCL_LINE
+                case value_t::number_unsigned: // LCOV_EXCL_LINE
+                case value_t::number_float: // LCOV_EXCL_LINE
+                case value_t::binary: // LCOV_EXCL_LINE
+                case value_t::discarded: // LCOV_EXCL_LINE
+                default:   // LCOV_EXCL_LINE
+                    break; // LCOV_EXCL_LINE
+            }
+        }
+
+        if (tokens.empty())
+        {
+            return "";
+        }
+
+        auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
+                                   [](const std::string & a, const std::string & b)
+        {
+            return concat(a, '/', detail::escape(b));
+        });
+        return concat('(', str, ") ");
+#else
+        static_cast<void>(leaf_element);
+        return "";
+#endif
+    }
+
+  private:
+    /// an exception object as storage for error messages
+    std::runtime_error m;
+};
+
+/// @brief exception indicating a parse error
+/// @sa https://json.nlohmann.me/api/basic_json/parse_error/
+class parse_error : public exception
+{
+  public:
+    /*!
+    @brief create a parse error exception
+    @param[in] id_       the id of the exception
+    @param[in] pos       the position where the error occurred (or with
+                         chars_read_total=0 if the position cannot be
+                         determined)
+    @param[in] what_arg  the explanatory string
+    @return parse_error object
+    */
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("parse_error", id_), "parse error",
+                               position_string(pos), ": ", exception::diagnostics(context), what_arg);
+        return {id_, pos.chars_read_total, w.c_str()};
+    }
+
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("parse_error", id_), "parse error",
+                               (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
+                               ": ", exception::diagnostics(context), what_arg);
+        return {id_, byte_, w.c_str()};
+    }
+
+    /*!
+    @brief byte index of the parse error
+
+    The byte index of the last read character in the input file.
+
+    @note For an input with n bytes, 1 is the index of the first character and
+          n+1 is the index of the terminating null byte or the end of file.
+          This also holds true when reading a byte vector (CBOR or MessagePack).
+    */
+    const std::size_t byte;
+
+  private:
+    parse_error(int id_, std::size_t byte_, const char* what_arg)
+        : exception(id_, what_arg), byte(byte_) {}
+
+    static std::string position_string(const position_t& pos)
+    {
+        return concat(" at line ", std::to_string(pos.lines_read + 1),
+                      ", column ", std::to_string(pos.chars_read_current_line));
+    }
+};
+
+/// @brief exception indicating errors with iterators
+/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/
+class invalid_iterator : public exception
+{
+  public:
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
+        return {id_, w.c_str()};
+    }
+
+  private:
+    JSON_HEDLEY_NON_NULL(3)
+    invalid_iterator(int id_, const char* what_arg)
+        : exception(id_, what_arg) {}
+};
+
+/// @brief exception indicating executing a member function with a wrong type
+/// @sa https://json.nlohmann.me/api/basic_json/type_error/
+class type_error : public exception
+{
+  public:
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
+        return {id_, w.c_str()};
+    }
+
+  private:
+    JSON_HEDLEY_NON_NULL(3)
+    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
+};
+
+/// @brief exception indicating access out of the defined range
+/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/
+class out_of_range : public exception
+{
+  public:
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
+        return {id_, w.c_str()};
+    }
+
+  private:
+    JSON_HEDLEY_NON_NULL(3)
+    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
+};
+
+/// @brief exception indicating other library errors
+/// @sa https://json.nlohmann.me/api/basic_json/other_error/
+class other_error : public exception
+{
+  public:
+    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
+    static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)
+    {
+        std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
+        return {id_, w.c_str()};
+    }
+
+  private:
+    JSON_HEDLEY_NON_NULL(3)
+    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+// #include <nlohmann/detail/meta/identity_tag.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// dispatching helper struct
+template <class T> struct identity_tag {};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/meta/std_fs.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
+#include <experimental/filesystem>
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+namespace std_fs = std::experimental::filesystem;
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+#elif JSON_HAS_FILESYSTEM
+#include <filesystem>
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+namespace std_fs = std::filesystem;
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+#endif
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+// #include <nlohmann/detail/string_concat.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j));
+    }
+    n = nullptr;
+}
+
+// overloads for basic_json template parameters
+template < typename BasicJsonType, typename ArithmeticType,
+           enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
+                         !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
+                         int > = 0 >
+void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
+{
+    switch (static_cast<value_t>(j))
+    {
+        case value_t::number_unsigned:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
+            break;
+        }
+        case value_t::number_integer:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
+            break;
+        }
+        case value_t::number_float:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
+            break;
+        }
+
+        case value_t::null:
+        case value_t::object:
+        case value_t::array:
+        case value_t::string:
+        case value_t::boolean:
+        case value_t::binary:
+        case value_t::discarded:
+        default:
+            JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
+    }
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j));
+    }
+    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
+    }
+    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
+}
+
+template <
+    typename BasicJsonType, typename StringType,
+    enable_if_t <
+        std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
+        && is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value
+        && !std::is_same<typename BasicJsonType::string_t, StringType>::value
+        && !is_json_ref<StringType>::value, int > = 0 >
+inline void from_json(const BasicJsonType& j, StringType& s)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
+    }
+
+    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
+{
+    get_arithmetic_value(j, val);
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
+{
+    get_arithmetic_value(j, val);
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
+{
+    get_arithmetic_value(j, val);
+}
+
+#if !JSON_DISABLE_ENUM_SERIALIZATION
+template<typename BasicJsonType, typename EnumType,
+         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
+inline void from_json(const BasicJsonType& j, EnumType& e)
+{
+    typename std::underlying_type<EnumType>::type val;
+    get_arithmetic_value(j, val);
+    e = static_cast<EnumType>(val);
+}
+#endif  // JSON_DISABLE_ENUM_SERIALIZATION
+
+// forward_list doesn't have an insert method
+template<typename BasicJsonType, typename T, typename Allocator,
+         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
+inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+    l.clear();
+    std::transform(j.rbegin(), j.rend(),
+                   std::front_inserter(l), [](const BasicJsonType & i)
+    {
+        return i.template get<T>();
+    });
+}
+
+// valarray doesn't have an insert method
+template<typename BasicJsonType, typename T,
+         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
+inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+    l.resize(j.size());
+    std::transform(j.begin(), j.end(), std::begin(l),
+                   [](const BasicJsonType & elem)
+    {
+        return elem.template get<T>();
+    });
+}
+
+template<typename BasicJsonType, typename T, std::size_t N>
+auto from_json(const BasicJsonType& j, T (&arr)[N])  // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+-> decltype(j.template get<T>(), void())
+{
+    for (std::size_t i = 0; i < N; ++i)
+    {
+        arr[i] = j.at(i).template get<T>();
+    }
+}
+
+template<typename BasicJsonType>
+inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
+{
+    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
+}
+
+template<typename BasicJsonType, typename T, std::size_t N>
+auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
+                          priority_tag<2> /*unused*/)
+-> decltype(j.template get<T>(), void())
+{
+    for (std::size_t i = 0; i < N; ++i)
+    {
+        arr[i] = j.at(i).template get<T>();
+    }
+}
+
+template<typename BasicJsonType, typename ConstructibleArrayType,
+         enable_if_t<
+             std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
+             int> = 0>
+auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
+-> decltype(
+    arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
+    j.template get<typename ConstructibleArrayType::value_type>(),
+    void())
+{
+    using std::end;
+
+    ConstructibleArrayType ret;
+    ret.reserve(j.size());
+    std::transform(j.begin(), j.end(),
+                   std::inserter(ret, end(ret)), [](const BasicJsonType & i)
+    {
+        // get<BasicJsonType>() returns *this, this won't call a from_json
+        // method when value_type is BasicJsonType
+        return i.template get<typename ConstructibleArrayType::value_type>();
+    });
+    arr = std::move(ret);
+}
+
+template<typename BasicJsonType, typename ConstructibleArrayType,
+         enable_if_t<
+             std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
+             int> = 0>
+inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
+                                 priority_tag<0> /*unused*/)
+{
+    using std::end;
+
+    ConstructibleArrayType ret;
+    std::transform(
+        j.begin(), j.end(), std::inserter(ret, end(ret)),
+        [](const BasicJsonType & i)
+    {
+        // get<BasicJsonType>() returns *this, this won't call a from_json
+        // method when value_type is BasicJsonType
+        return i.template get<typename ConstructibleArrayType::value_type>();
+    });
+    arr = std::move(ret);
+}
+
+template < typename BasicJsonType, typename ConstructibleArrayType,
+           enable_if_t <
+               is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
+               !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
+               !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
+               !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
+               !is_basic_json<ConstructibleArrayType>::value,
+               int > = 0 >
+auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
+-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
+j.template get<typename ConstructibleArrayType::value_type>(),
+void())
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+
+    from_json_array_impl(j, arr, priority_tag<3> {});
+}
+
+template < typename BasicJsonType, typename T, std::size_t... Idx >
+std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,
+        identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/)
+{
+    return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } };
+}
+
+template < typename BasicJsonType, typename T, std::size_t N >
+auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)
+-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}))
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+
+    return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {});
+}
+
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j));
+    }
+
+    bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
+}
+
+template<typename BasicJsonType, typename ConstructibleObjectType,
+         enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
+inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j));
+    }
+
+    ConstructibleObjectType ret;
+    const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
+    using value_type = typename ConstructibleObjectType::value_type;
+    std::transform(
+        inner_object->begin(), inner_object->end(),
+        std::inserter(ret, ret.begin()),
+        [](typename BasicJsonType::object_t::value_type const & p)
+    {
+        return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
+    });
+    obj = std::move(ret);
+}
+
+// overload for arithmetic types, not chosen for basic_json template arguments
+// (BooleanType, etc..); note: Is it really necessary to provide explicit
+// overloads for boolean_t etc. in case of a custom BooleanType which is not
+// an arithmetic type?
+template < typename BasicJsonType, typename ArithmeticType,
+           enable_if_t <
+               std::is_arithmetic<ArithmeticType>::value&&
+               !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
+               !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
+               !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
+               !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
+               int > = 0 >
+inline void from_json(const BasicJsonType& j, ArithmeticType& val)
+{
+    switch (static_cast<value_t>(j))
+    {
+        case value_t::number_unsigned:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
+            break;
+        }
+        case value_t::number_integer:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
+            break;
+        }
+        case value_t::number_float:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
+            break;
+        }
+        case value_t::boolean:
+        {
+            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
+            break;
+        }
+
+        case value_t::null:
+        case value_t::object:
+        case value_t::array:
+        case value_t::string:
+        case value_t::binary:
+        case value_t::discarded:
+        default:
+            JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
+    }
+}
+
+template<typename BasicJsonType, typename... Args, std::size_t... Idx>
+std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
+{
+    return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
+}
+
+template < typename BasicJsonType, class A1, class A2 >
+std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
+{
+    return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),
+            std::forward<BasicJsonType>(j).at(1).template get<A2>()};
+}
+
+template<typename BasicJsonType, typename A1, typename A2>
+inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
+{
+    p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});
+}
+
+template<typename BasicJsonType, typename... Args>
+std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
+{
+    return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
+}
+
+template<typename BasicJsonType, typename... Args>
+inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
+{
+    t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
+}
+
+template<typename BasicJsonType, typename TupleRelated>
+auto from_json(BasicJsonType&& j, TupleRelated&& t)
+-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}))
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+
+    return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
+}
+
+template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
+           typename = enable_if_t < !std::is_constructible <
+                                        typename BasicJsonType::string_t, Key >::value >>
+inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+    m.clear();
+    for (const auto& p : j)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
+        {
+            JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
+        }
+        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
+    }
+}
+
+template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
+           typename = enable_if_t < !std::is_constructible <
+                                        typename BasicJsonType::string_t, Key >::value >>
+inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
+    }
+    m.clear();
+    for (const auto& p : j)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
+        {
+            JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
+        }
+        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
+    }
+}
+
+#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
+template<typename BasicJsonType>
+inline void from_json(const BasicJsonType& j, std_fs::path& p)
+{
+    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
+    {
+        JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
+    }
+    p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
+}
+#endif
+
+struct from_json_fn
+{
+    template<typename BasicJsonType, typename T>
+    auto operator()(const BasicJsonType& j, T&& val) const
+    noexcept(noexcept(from_json(j, std::forward<T>(val))))
+    -> decltype(from_json(j, std::forward<T>(val)))
+    {
+        return from_json(j, std::forward<T>(val));
+    }
+};
+
+}  // namespace detail
+
+#ifndef JSON_HAS_CPP_17
+/// namespace to hold default `from_json` function
+/// to see why this is required:
+/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
+namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
+{
+#endif
+JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
+    detail::static_const<detail::from_json_fn>::value;
+#ifndef JSON_HAS_CPP_17
+}  // namespace
+#endif
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/conversions/to_json.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <algorithm> // copy
+#include <iterator> // begin, end
+#include <string> // string
+#include <tuple> // tuple, get
+#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
+#include <utility> // move, forward, declval, pair
+#include <valarray> // valarray
+#include <vector> // vector
+
+// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstddef> // size_t
+#include <iterator> // input_iterator_tag
+#include <string> // string, to_string
+#include <tuple> // tuple_size, get, tuple_element
+#include <utility> // move
+
+#if JSON_HAS_RANGES
+    #include <ranges> // enable_borrowed_range
+#endif
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename string_type>
+void int_to_string( string_type& target, std::size_t value )
+{
+    // For ADL
+    using std::to_string;
+    target = to_string(value);
+}
+template<typename IteratorType> class iteration_proxy_value
+{
+  public:
+    using difference_type = std::ptrdiff_t;
+    using value_type = iteration_proxy_value;
+    using pointer = value_type *;
+    using reference = value_type &;
+    using iterator_category = std::input_iterator_tag;
+    using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
+
+  private:
+    /// the iterator
+    IteratorType anchor{};
+    /// an index for arrays (used to create key names)
+    std::size_t array_index = 0;
+    /// last stringified array index
+    mutable std::size_t array_index_last = 0;
+    /// a string representation of the array index
+    mutable string_type array_index_str = "0";
+    /// an empty string (to return a reference for primitive values)
+    string_type empty_str{};
+
+  public:
+    explicit iteration_proxy_value() = default;
+    explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0)
+    noexcept(std::is_nothrow_move_constructible<IteratorType>::value
+             && std::is_nothrow_default_constructible<string_type>::value)
+        : anchor(std::move(it))
+        , array_index(array_index_)
+    {}
+
+    iteration_proxy_value(iteration_proxy_value const&) = default;
+    iteration_proxy_value& operator=(iteration_proxy_value const&) = default;
+    // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
+    iteration_proxy_value(iteration_proxy_value&&)
+    noexcept(std::is_nothrow_move_constructible<IteratorType>::value
+             && std::is_nothrow_move_constructible<string_type>::value) = default;
+    iteration_proxy_value& operator=(iteration_proxy_value&&)
+    noexcept(std::is_nothrow_move_assignable<IteratorType>::value
+             && std::is_nothrow_move_assignable<string_type>::value) = default;
+    ~iteration_proxy_value() = default;
+
+    /// dereference operator (needed for range-based for)
+    const iteration_proxy_value& operator*() const
+    {
+        return *this;
+    }
+
+    /// increment operator (needed for range-based for)
+    iteration_proxy_value& operator++()
+    {
+        ++anchor;
+        ++array_index;
+
+        return *this;
+    }
+
+    iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        auto tmp = iteration_proxy_value(anchor, array_index);
+        ++anchor;
+        ++array_index;
+        return tmp;
+    }
+
+    /// equality operator (needed for InputIterator)
+    bool operator==(const iteration_proxy_value& o) const
+    {
+        return anchor == o.anchor;
+    }
+
+    /// inequality operator (needed for range-based for)
+    bool operator!=(const iteration_proxy_value& o) const
+    {
+        return anchor != o.anchor;
+    }
+
+    /// return key of the iterator
+    const string_type& key() const
+    {
+        JSON_ASSERT(anchor.m_object != nullptr);
+
+        switch (anchor.m_object->type())
+        {
+            // use integer array index as key
+            case value_t::array:
+            {
+                if (array_index != array_index_last)
+                {
+                    int_to_string( array_index_str, array_index );
+                    array_index_last = array_index;
+                }
+                return array_index_str;
+            }
+
+            // use key from the object
+            case value_t::object:
+                return anchor.key();
+
+            // use an empty key for all primitive types
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                return empty_str;
+        }
+    }
+
+    /// return value of the iterator
+    typename IteratorType::reference value() const
+    {
+        return anchor.value();
+    }
+};
+
+/// proxy class for the items() function
+template<typename IteratorType> class iteration_proxy
+{
+  private:
+    /// the container to iterate
+    typename IteratorType::pointer container = nullptr;
+
+  public:
+    explicit iteration_proxy() = default;
+
+    /// construct iteration proxy from a container
+    explicit iteration_proxy(typename IteratorType::reference cont) noexcept
+        : container(&cont) {}
+
+    iteration_proxy(iteration_proxy const&) = default;
+    iteration_proxy& operator=(iteration_proxy const&) = default;
+    iteration_proxy(iteration_proxy&&) noexcept = default;
+    iteration_proxy& operator=(iteration_proxy&&) noexcept = default;
+    ~iteration_proxy() = default;
+
+    /// return iterator begin (needed for range-based for)
+    iteration_proxy_value<IteratorType> begin() const noexcept
+    {
+        return iteration_proxy_value<IteratorType>(container->begin());
+    }
+
+    /// return iterator end (needed for range-based for)
+    iteration_proxy_value<IteratorType> end() const noexcept
+    {
+        return iteration_proxy_value<IteratorType>(container->end());
+    }
+};
+
+// Structured Bindings Support
+// For further reference see https://blog.tartanllama.xyz/structured-bindings/
+// And see https://github.com/nlohmann/json/pull/1391
+template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
+auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
+{
+    return i.key();
+}
+// Structured Bindings Support
+// For further reference see https://blog.tartanllama.xyz/structured-bindings/
+// And see https://github.com/nlohmann/json/pull/1391
+template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
+auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
+{
+    return i.value();
+}
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// The Addition to the STD Namespace is required to add
+// Structured Bindings Support to the iteration_proxy_value class
+// For further reference see https://blog.tartanllama.xyz/structured-bindings/
+// And see https://github.com/nlohmann/json/pull/1391
+namespace std
+{
+
+#if defined(__clang__)
+    // Fix: https://github.com/nlohmann/json/issues/1401
+    #pragma clang diagnostic push
+    #pragma clang diagnostic ignored "-Wmismatched-tags"
+#endif
+template<typename IteratorType>
+class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
+            : public std::integral_constant<std::size_t, 2> {};
+
+template<std::size_t N, typename IteratorType>
+class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
+{
+  public:
+    using type = decltype(
+                     get<N>(std::declval <
+                            ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
+};
+#if defined(__clang__)
+    #pragma clang diagnostic pop
+#endif
+
+}  // namespace std
+
+#if JSON_HAS_RANGES
+    template <typename IteratorType>
+    inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true;
+#endif
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+// #include <nlohmann/detail/meta/std_fs.hpp>
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+//////////////////
+// constructors //
+//////////////////
+
+/*
+ * Note all external_constructor<>::construct functions need to call
+ * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an
+ * allocated value (e.g., a string). See bug issue
+ * https://github.com/nlohmann/json/issues/2865 for more information.
+ */
+
+template<value_t> struct external_constructor;
+
+template<>
+struct external_constructor<value_t::boolean>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::boolean;
+        j.m_value = b;
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::string>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::string;
+        j.m_value = s;
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::string;
+        j.m_value = std::move(s);
+        j.assert_invariant();
+    }
+
+    template < typename BasicJsonType, typename CompatibleStringType,
+               enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
+                             int > = 0 >
+    static void construct(BasicJsonType& j, const CompatibleStringType& str)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::string;
+        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::binary>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::binary;
+        j.m_value = typename BasicJsonType::binary_t(b);
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::binary;
+        j.m_value = typename BasicJsonType::binary_t(std::move(b));
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::number_float>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::number_float;
+        j.m_value = val;
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::number_unsigned>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::number_unsigned;
+        j.m_value = val;
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::number_integer>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::number_integer;
+        j.m_value = val;
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::array>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value = arr;
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value = std::move(arr);
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template < typename BasicJsonType, typename CompatibleArrayType,
+               enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
+                             int > = 0 >
+    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
+    {
+        using std::begin;
+        using std::end;
+
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const std::vector<bool>& arr)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value = value_t::array;
+        j.m_value.array->reserve(arr.size());
+        for (const bool x : arr)
+        {
+            j.m_value.array->push_back(x);
+            j.set_parent(j.m_value.array->back());
+        }
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType, typename T,
+             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
+    static void construct(BasicJsonType& j, const std::valarray<T>& arr)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::array;
+        j.m_value = value_t::array;
+        j.m_value.array->resize(arr.size());
+        if (arr.size() > 0)
+        {
+            std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
+        }
+        j.set_parents();
+        j.assert_invariant();
+    }
+};
+
+template<>
+struct external_constructor<value_t::object>
+{
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::object;
+        j.m_value = obj;
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template<typename BasicJsonType>
+    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
+    {
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::object;
+        j.m_value = std::move(obj);
+        j.set_parents();
+        j.assert_invariant();
+    }
+
+    template < typename BasicJsonType, typename CompatibleObjectType,
+               enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
+    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
+    {
+        using std::begin;
+        using std::end;
+
+        j.m_value.destroy(j.m_type);
+        j.m_type = value_t::object;
+        j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
+        j.set_parents();
+        j.assert_invariant();
+    }
+};
+
+/////////////
+// to_json //
+/////////////
+
+template<typename BasicJsonType, typename T,
+         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
+inline void to_json(BasicJsonType& j, T b) noexcept
+{
+    external_constructor<value_t::boolean>::construct(j, b);
+}
+
+template < typename BasicJsonType, typename BoolRef,
+           enable_if_t <
+               ((std::is_same<std::vector<bool>::reference, BoolRef>::value
+                 && !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value)
+                || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value
+                    && !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>,
+                                      typename BasicJsonType::boolean_t >::value))
+               && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 >
+inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept
+{
+    external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b));
+}
+
+template<typename BasicJsonType, typename CompatibleString,
+         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
+inline void to_json(BasicJsonType& j, const CompatibleString& s)
+{
+    external_constructor<value_t::string>::construct(j, s);
+}
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
+{
+    external_constructor<value_t::string>::construct(j, std::move(s));
+}
+
+template<typename BasicJsonType, typename FloatType,
+         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, FloatType val) noexcept
+{
+    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
+}
+
+template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
+         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
+{
+    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
+}
+
+template<typename BasicJsonType, typename CompatibleNumberIntegerType,
+         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
+{
+    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
+}
+
+#if !JSON_DISABLE_ENUM_SERIALIZATION
+template<typename BasicJsonType, typename EnumType,
+         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, EnumType e) noexcept
+{
+    using underlying_type = typename std::underlying_type<EnumType>::type;
+    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
+}
+#endif  // JSON_DISABLE_ENUM_SERIALIZATION
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, const std::vector<bool>& e)
+{
+    external_constructor<value_t::array>::construct(j, e);
+}
+
+template < typename BasicJsonType, typename CompatibleArrayType,
+           enable_if_t < is_compatible_array_type<BasicJsonType,
+                         CompatibleArrayType>::value&&
+                         !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
+                         !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
+                         !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
+                         !is_basic_json<CompatibleArrayType>::value,
+                         int > = 0 >
+inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
+{
+    external_constructor<value_t::array>::construct(j, arr);
+}
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
+{
+    external_constructor<value_t::binary>::construct(j, bin);
+}
+
+template<typename BasicJsonType, typename T,
+         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
+inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
+{
+    external_constructor<value_t::array>::construct(j, std::move(arr));
+}
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
+{
+    external_constructor<value_t::array>::construct(j, std::move(arr));
+}
+
+template < typename BasicJsonType, typename CompatibleObjectType,
+           enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
+inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
+{
+    external_constructor<value_t::object>::construct(j, obj);
+}
+
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
+{
+    external_constructor<value_t::object>::construct(j, std::move(obj));
+}
+
+template <
+    typename BasicJsonType, typename T, std::size_t N,
+    enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
+                  const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+                  int > = 0 >
+inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+{
+    external_constructor<value_t::array>::construct(j, arr);
+}
+
+template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >
+inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
+{
+    j = { p.first, p.second };
+}
+
+// for https://github.com/nlohmann/json/pull/1134
+template<typename BasicJsonType, typename T,
+         enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
+inline void to_json(BasicJsonType& j, const T& b)
+{
+    j = { {b.key(), b.value()} };
+}
+
+template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
+inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
+{
+    j = { std::get<Idx>(t)... };
+}
+
+template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
+inline void to_json(BasicJsonType& j, const T& t)
+{
+    to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
+}
+
+#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
+template<typename BasicJsonType>
+inline void to_json(BasicJsonType& j, const std_fs::path& p)
+{
+    j = p.string();
+}
+#endif
+
+struct to_json_fn
+{
+    template<typename BasicJsonType, typename T>
+    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
+    -> decltype(to_json(j, std::forward<T>(val)), void())
+    {
+        return to_json(j, std::forward<T>(val));
+    }
+};
+}  // namespace detail
+
+#ifndef JSON_HAS_CPP_17
+/// namespace to hold default `to_json` function
+/// to see why this is required:
+/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
+namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
+{
+#endif
+JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
+    detail::static_const<detail::to_json_fn>::value;
+#ifndef JSON_HAS_CPP_17
+}  // namespace
+#endif
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/meta/identity_tag.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+/// @sa https://json.nlohmann.me/api/adl_serializer/
+template<typename ValueType, typename>
+struct adl_serializer
+{
+    /// @brief convert a JSON value to any value type
+    /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
+    template<typename BasicJsonType, typename TargetType = ValueType>
+    static auto from_json(BasicJsonType && j, TargetType& val) noexcept(
+        noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
+    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())
+    {
+        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
+    }
+
+    /// @brief convert a JSON value to any value type
+    /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
+    template<typename BasicJsonType, typename TargetType = ValueType>
+    static auto from_json(BasicJsonType && j) noexcept(
+    noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})))
+    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))
+    {
+        return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {});
+    }
+
+    /// @brief convert any value type to a JSON value
+    /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/
+    template<typename BasicJsonType, typename TargetType = ValueType>
+    static auto to_json(BasicJsonType& j, TargetType && val) noexcept(
+        noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val))))
+    -> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void())
+    {
+        ::nlohmann::to_json(j, std::forward<TargetType>(val));
+    }
+};
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/byte_container_with_subtype.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstdint> // uint8_t, uint64_t
+#include <tuple> // tie
+#include <utility> // move
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+/// @brief an internal type for a backed binary type
+/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/
+template<typename BinaryType>
+class byte_container_with_subtype : public BinaryType
+{
+  public:
+    using container_type = BinaryType;
+    using subtype_type = std::uint64_t;
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype() noexcept(noexcept(container_type()))
+        : container_type()
+    {}
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))
+        : container_type(b)
+    {}
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))
+        : container_type(std::move(b))
+    {}
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b)))
+        : container_type(b)
+        , m_subtype(subtype_)
+        , m_has_subtype(true)
+    {}
+
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
+    byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))
+        : container_type(std::move(b))
+        , m_subtype(subtype_)
+        , m_has_subtype(true)
+    {}
+
+    bool operator==(const byte_container_with_subtype& rhs) const
+    {
+        return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
+               std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
+    }
+
+    bool operator!=(const byte_container_with_subtype& rhs) const
+    {
+        return !(rhs == *this);
+    }
+
+    /// @brief sets the binary subtype
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/
+    void set_subtype(subtype_type subtype_) noexcept
+    {
+        m_subtype = subtype_;
+        m_has_subtype = true;
+    }
+
+    /// @brief return the binary subtype
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/
+    constexpr subtype_type subtype() const noexcept
+    {
+        return m_has_subtype ? m_subtype : static_cast<subtype_type>(-1);
+    }
+
+    /// @brief return whether the value has a subtype
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/
+    constexpr bool has_subtype() const noexcept
+    {
+        return m_has_subtype;
+    }
+
+    /// @brief clears the binary subtype
+    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/
+    void clear_subtype() noexcept
+    {
+        m_subtype = 0;
+        m_has_subtype = false;
+    }
+
+  private:
+    subtype_type m_subtype = 0;
+    bool m_has_subtype = false;
+};
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/conversions/from_json.hpp>
+
+// #include <nlohmann/detail/conversions/to_json.hpp>
+
+// #include <nlohmann/detail/exceptions.hpp>
+
+// #include <nlohmann/detail/hash.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstdint> // uint8_t
+#include <cstddef> // size_t
+#include <functional> // hash
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// boost::hash_combine
+inline std::size_t combine(std::size_t seed, std::size_t h) noexcept
+{
+    seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
+    return seed;
+}
+
+/*!
+@brief hash a JSON value
+
+The hash function tries to rely on std::hash where possible. Furthermore, the
+type of the JSON value is taken into account to have different hash values for
+null, 0, 0U, and false, etc.
+
+@tparam BasicJsonType basic_json specialization
+@param j JSON value to hash
+@return hash value of j
+*/
+template<typename BasicJsonType>
+std::size_t hash(const BasicJsonType& j)
+{
+    using string_t = typename BasicJsonType::string_t;
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+
+    const auto type = static_cast<std::size_t>(j.type());
+    switch (j.type())
+    {
+        case BasicJsonType::value_t::null:
+        case BasicJsonType::value_t::discarded:
+        {
+            return combine(type, 0);
+        }
+
+        case BasicJsonType::value_t::object:
+        {
+            auto seed = combine(type, j.size());
+            for (const auto& element : j.items())
+            {
+                const auto h = std::hash<string_t> {}(element.key());
+                seed = combine(seed, h);
+                seed = combine(seed, hash(element.value()));
+            }
+            return seed;
+        }
+
+        case BasicJsonType::value_t::array:
+        {
+            auto seed = combine(type, j.size());
+            for (const auto& element : j)
+            {
+                seed = combine(seed, hash(element));
+            }
+            return seed;
+        }
+
+        case BasicJsonType::value_t::string:
+        {
+            const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::boolean:
+        {
+            const auto h = std::hash<bool> {}(j.template get<bool>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::number_integer:
+        {
+            const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::number_unsigned:
+        {
+            const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::number_float:
+        {
+            const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
+            return combine(type, h);
+        }
+
+        case BasicJsonType::value_t::binary:
+        {
+            auto seed = combine(type, j.get_binary().size());
+            const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
+            seed = combine(seed, h);
+            seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
+            for (const auto byte : j.get_binary())
+            {
+                seed = combine(seed, std::hash<std::uint8_t> {}(byte));
+            }
+            return seed;
+        }
+
+        default:                   // LCOV_EXCL_LINE
+            JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+            return 0;              // LCOV_EXCL_LINE
+    }
+}
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/input/binary_reader.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <algorithm> // generate_n
+#include <array> // array
+#include <cmath> // ldexp
+#include <cstddef> // size_t
+#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
+#include <cstdio> // snprintf
+#include <cstring> // memcpy
+#include <iterator> // back_inserter
+#include <limits> // numeric_limits
+#include <string> // char_traits, string
+#include <utility> // make_pair, move
+#include <vector> // vector
+
+// #include <nlohmann/detail/exceptions.hpp>
+
+// #include <nlohmann/detail/input/input_adapters.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <array> // array
+#include <cstddef> // size_t
+#include <cstring> // strlen
+#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
+#include <memory> // shared_ptr, make_shared, addressof
+#include <numeric> // accumulate
+#include <string> // string, char_traits
+#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
+#include <utility> // pair, declval
+
+#ifndef JSON_NO_IO
+    #include <cstdio>   // FILE *
+    #include <istream>  // istream
+#endif                  // JSON_NO_IO
+
+// #include <nlohmann/detail/iterators/iterator_traits.hpp>
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// the supported input formats
+enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata };
+
+////////////////////
+// input adapters //
+////////////////////
+
+#ifndef JSON_NO_IO
+/*!
+Input adapter for stdio file access. This adapter read only 1 byte and do not use any
+ buffer. This adapter is a very low level adapter.
+*/
+class file_input_adapter
+{
+  public:
+    using char_type = char;
+
+    JSON_HEDLEY_NON_NULL(2)
+    explicit file_input_adapter(std::FILE* f) noexcept
+        : m_file(f)
+    {
+        JSON_ASSERT(m_file != nullptr);
+    }
+
+    // make class move-only
+    file_input_adapter(const file_input_adapter&) = delete;
+    file_input_adapter(file_input_adapter&&) noexcept = default;
+    file_input_adapter& operator=(const file_input_adapter&) = delete;
+    file_input_adapter& operator=(file_input_adapter&&) = delete;
+    ~file_input_adapter() = default;
+
+    std::char_traits<char>::int_type get_character() noexcept
+    {
+        return std::fgetc(m_file);
+    }
+
+  private:
+    /// the file pointer to read from
+    std::FILE* m_file;
+};
+
+
+/*!
+Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
+beginning of input. Does not support changing the underlying std::streambuf
+in mid-input. Maintains underlying std::istream and std::streambuf to support
+subsequent use of standard std::istream operations to process any input
+characters following those used in parsing the JSON input.  Clears the
+std::istream flags; any input errors (e.g., EOF) will be detected by the first
+subsequent call for input from the std::istream.
+*/
+class input_stream_adapter
+{
+  public:
+    using char_type = char;
+
+    ~input_stream_adapter()
+    {
+        // clear stream flags; we use underlying streambuf I/O, do not
+        // maintain ifstream flags, except eof
+        if (is != nullptr)
+        {
+            is->clear(is->rdstate() & std::ios::eofbit);
+        }
+    }
+
+    explicit input_stream_adapter(std::istream& i)
+        : is(&i), sb(i.rdbuf())
+    {}
+
+    // delete because of pointer members
+    input_stream_adapter(const input_stream_adapter&) = delete;
+    input_stream_adapter& operator=(input_stream_adapter&) = delete;
+    input_stream_adapter& operator=(input_stream_adapter&&) = delete;
+
+    input_stream_adapter(input_stream_adapter&& rhs) noexcept
+        : is(rhs.is), sb(rhs.sb)
+    {
+        rhs.is = nullptr;
+        rhs.sb = nullptr;
+    }
+
+    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
+    // ensure that std::char_traits<char>::eof() and the character 0xFF do not
+    // end up as the same value, e.g. 0xFFFFFFFF.
+    std::char_traits<char>::int_type get_character()
+    {
+        auto res = sb->sbumpc();
+        // set eof manually, as we don't use the istream interface.
+        if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
+        {
+            is->clear(is->rdstate() | std::ios::eofbit);
+        }
+        return res;
+    }
+
+  private:
+    /// the associated input stream
+    std::istream* is = nullptr;
+    std::streambuf* sb = nullptr;
+};
+#endif  // JSON_NO_IO
+
+// General-purpose iterator-based adapter. It might not be as fast as
+// theoretically possible for some containers, but it is extremely versatile.
+template<typename IteratorType>
+class iterator_input_adapter
+{
+  public:
+    using char_type = typename std::iterator_traits<IteratorType>::value_type;
+
+    iterator_input_adapter(IteratorType first, IteratorType last)
+        : current(std::move(first)), end(std::move(last))
+    {}
+
+    typename std::char_traits<char_type>::int_type get_character()
+    {
+        if (JSON_HEDLEY_LIKELY(current != end))
+        {
+            auto result = std::char_traits<char_type>::to_int_type(*current);
+            std::advance(current, 1);
+            return result;
+        }
+
+        return std::char_traits<char_type>::eof();
+    }
+
+  private:
+    IteratorType current;
+    IteratorType end;
+
+    template<typename BaseInputAdapter, size_t T>
+    friend struct wide_string_input_helper;
+
+    bool empty() const
+    {
+        return current == end;
+    }
+};
+
+
+template<typename BaseInputAdapter, size_t T>
+struct wide_string_input_helper;
+
+template<typename BaseInputAdapter>
+struct wide_string_input_helper<BaseInputAdapter, 4>
+{
+    // UTF-32
+    static void fill_buffer(BaseInputAdapter& input,
+                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
+                            size_t& utf8_bytes_index,
+                            size_t& utf8_bytes_filled)
+    {
+        utf8_bytes_index = 0;
+
+        if (JSON_HEDLEY_UNLIKELY(input.empty()))
+        {
+            utf8_bytes[0] = std::char_traits<char>::eof();
+            utf8_bytes_filled = 1;
+        }
+        else
+        {
+            // get the current character
+            const auto wc = input.get_character();
+
+            // UTF-32 to UTF-8 encoding
+            if (wc < 0x80)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
+                utf8_bytes_filled = 1;
+            }
+            else if (wc <= 0x7FF)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 2;
+            }
+            else if (wc <= 0xFFFF)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
+                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 3;
+            }
+            else if (wc <= 0x10FFFF)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));
+                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
+                utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 4;
+            }
+            else
+            {
+                // unknown character
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
+                utf8_bytes_filled = 1;
+            }
+        }
+    }
+};
+
+template<typename BaseInputAdapter>
+struct wide_string_input_helper<BaseInputAdapter, 2>
+{
+    // UTF-16
+    static void fill_buffer(BaseInputAdapter& input,
+                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
+                            size_t& utf8_bytes_index,
+                            size_t& utf8_bytes_filled)
+    {
+        utf8_bytes_index = 0;
+
+        if (JSON_HEDLEY_UNLIKELY(input.empty()))
+        {
+            utf8_bytes[0] = std::char_traits<char>::eof();
+            utf8_bytes_filled = 1;
+        }
+        else
+        {
+            // get the current character
+            const auto wc = input.get_character();
+
+            // UTF-16 to UTF-8 encoding
+            if (wc < 0x80)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
+                utf8_bytes_filled = 1;
+            }
+            else if (wc <= 0x7FF)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 2;
+            }
+            else if (0xD800 > wc || wc >= 0xE000)
+            {
+                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
+                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
+                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
+                utf8_bytes_filled = 3;
+            }
+            else
+            {
+                if (JSON_HEDLEY_UNLIKELY(!input.empty()))
+                {
+                    const auto wc2 = static_cast<unsigned int>(input.get_character());
+                    const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
+                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
+                    utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
+                    utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
+                    utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
+                    utf8_bytes_filled = 4;
+                }
+                else
+                {
+                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
+                    utf8_bytes_filled = 1;
+                }
+            }
+        }
+    }
+};
+
+// Wraps another input apdater to convert wide character types into individual bytes.
+template<typename BaseInputAdapter, typename WideCharType>
+class wide_string_input_adapter
+{
+  public:
+    using char_type = char;
+
+    wide_string_input_adapter(BaseInputAdapter base)
+        : base_adapter(base) {}
+
+    typename std::char_traits<char>::int_type get_character() noexcept
+    {
+        // check if buffer needs to be filled
+        if (utf8_bytes_index == utf8_bytes_filled)
+        {
+            fill_buffer<sizeof(WideCharType)>();
+
+            JSON_ASSERT(utf8_bytes_filled > 0);
+            JSON_ASSERT(utf8_bytes_index == 0);
+        }
+
+        // use buffer
+        JSON_ASSERT(utf8_bytes_filled > 0);
+        JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
+        return utf8_bytes[utf8_bytes_index++];
+    }
+
+  private:
+    BaseInputAdapter base_adapter;
+
+    template<size_t T>
+    void fill_buffer()
+    {
+        wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
+    }
+
+    /// a buffer for UTF-8 bytes
+    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
+
+    /// index to the utf8_codes array for the next valid byte
+    std::size_t utf8_bytes_index = 0;
+    /// number of valid bytes in the utf8_codes array
+    std::size_t utf8_bytes_filled = 0;
+};
+
+
+template<typename IteratorType, typename Enable = void>
+struct iterator_input_adapter_factory
+{
+    using iterator_type = IteratorType;
+    using char_type = typename std::iterator_traits<iterator_type>::value_type;
+    using adapter_type = iterator_input_adapter<iterator_type>;
+
+    static adapter_type create(IteratorType first, IteratorType last)
+    {
+        return adapter_type(std::move(first), std::move(last));
+    }
+};
+
+template<typename T>
+struct is_iterator_of_multibyte
+{
+    using value_type = typename std::iterator_traits<T>::value_type;
+    enum
+    {
+        value = sizeof(value_type) > 1
+    };
+};
+
+template<typename IteratorType>
+struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
+{
+    using iterator_type = IteratorType;
+    using char_type = typename std::iterator_traits<iterator_type>::value_type;
+    using base_adapter_type = iterator_input_adapter<iterator_type>;
+    using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
+
+    static adapter_type create(IteratorType first, IteratorType last)
+    {
+        return adapter_type(base_adapter_type(std::move(first), std::move(last)));
+    }
+};
+
+// General purpose iterator-based input
+template<typename IteratorType>
+typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
+{
+    using factory_type = iterator_input_adapter_factory<IteratorType>;
+    return factory_type::create(first, last);
+}
+
+// Convenience shorthand from container to iterator
+// Enables ADL on begin(container) and end(container)
+// Encloses the using declarations in namespace for not to leak them to outside scope
+
+namespace container_input_adapter_factory_impl
+{
+
+using std::begin;
+using std::end;
+
+template<typename ContainerType, typename Enable = void>
+struct container_input_adapter_factory {};
+
+template<typename ContainerType>
+struct container_input_adapter_factory< ContainerType,
+       void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>
+       {
+           using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
+
+           static adapter_type create(const ContainerType& container)
+{
+    return input_adapter(begin(container), end(container));
+}
+       };
+
+}  // namespace container_input_adapter_factory_impl
+
+template<typename ContainerType>
+typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
+{
+    return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
+}
+
+#ifndef JSON_NO_IO
+// Special cases with fast paths
+inline file_input_adapter input_adapter(std::FILE* file)
+{
+    return file_input_adapter(file);
+}
+
+inline input_stream_adapter input_adapter(std::istream& stream)
+{
+    return input_stream_adapter(stream);
+}
+
+inline input_stream_adapter input_adapter(std::istream&& stream)
+{
+    return input_stream_adapter(stream);
+}
+#endif  // JSON_NO_IO
+
+using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
+
+// Null-delimited strings, and the like.
+template < typename CharT,
+           typename std::enable_if <
+               std::is_pointer<CharT>::value&&
+               !std::is_array<CharT>::value&&
+               std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
+               sizeof(typename std::remove_pointer<CharT>::type) == 1,
+               int >::type = 0 >
+contiguous_bytes_input_adapter input_adapter(CharT b)
+{
+    auto length = std::strlen(reinterpret_cast<const char*>(b));
+    const auto* ptr = reinterpret_cast<const char*>(b);
+    return input_adapter(ptr, ptr + length);
+}
+
+template<typename T, std::size_t N>
+auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+{
+    return input_adapter(array, array + N);
+}
+
+// This class only handles inputs of input_buffer_adapter type.
+// It's required so that expressions like {ptr, len} can be implicitly cast
+// to the correct adapter.
+class span_input_adapter
+{
+  public:
+    template < typename CharT,
+               typename std::enable_if <
+                   std::is_pointer<CharT>::value&&
+                   std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
+                   sizeof(typename std::remove_pointer<CharT>::type) == 1,
+                   int >::type = 0 >
+    span_input_adapter(CharT b, std::size_t l)
+        : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}
+
+    template<class IteratorType,
+             typename std::enable_if<
+                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
+                 int>::type = 0>
+    span_input_adapter(IteratorType first, IteratorType last)
+        : ia(input_adapter(first, last)) {}
+
+    contiguous_bytes_input_adapter&& get()
+    {
+        return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
+    }
+
+  private:
+    contiguous_bytes_input_adapter ia;
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/input/json_sax.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstddef>
+#include <string> // string
+#include <utility> // move
+#include <vector> // vector
+
+// #include <nlohmann/detail/exceptions.hpp>
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/string_concat.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+/*!
+@brief SAX interface
+
+This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
+Each function is called in different situations while the input is parsed. The
+boolean return value informs the parser whether to continue processing the
+input.
+*/
+template<typename BasicJsonType>
+struct json_sax
+{
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+
+    /*!
+    @brief a null value was read
+    @return whether parsing should proceed
+    */
+    virtual bool null() = 0;
+
+    /*!
+    @brief a boolean value was read
+    @param[in] val  boolean value
+    @return whether parsing should proceed
+    */
+    virtual bool boolean(bool val) = 0;
+
+    /*!
+    @brief an integer number was read
+    @param[in] val  integer value
+    @return whether parsing should proceed
+    */
+    virtual bool number_integer(number_integer_t val) = 0;
+
+    /*!
+    @brief an unsigned integer number was read
+    @param[in] val  unsigned integer value
+    @return whether parsing should proceed
+    */
+    virtual bool number_unsigned(number_unsigned_t val) = 0;
+
+    /*!
+    @brief a floating-point number was read
+    @param[in] val  floating-point value
+    @param[in] s    raw token value
+    @return whether parsing should proceed
+    */
+    virtual bool number_float(number_float_t val, const string_t& s) = 0;
+
+    /*!
+    @brief a string value was read
+    @param[in] val  string value
+    @return whether parsing should proceed
+    @note It is safe to move the passed string value.
+    */
+    virtual bool string(string_t& val) = 0;
+
+    /*!
+    @brief a binary value was read
+    @param[in] val  binary value
+    @return whether parsing should proceed
+    @note It is safe to move the passed binary value.
+    */
+    virtual bool binary(binary_t& val) = 0;
+
+    /*!
+    @brief the beginning of an object was read
+    @param[in] elements  number of object elements or -1 if unknown
+    @return whether parsing should proceed
+    @note binary formats may report the number of elements
+    */
+    virtual bool start_object(std::size_t elements) = 0;
+
+    /*!
+    @brief an object key was read
+    @param[in] val  object key
+    @return whether parsing should proceed
+    @note It is safe to move the passed string.
+    */
+    virtual bool key(string_t& val) = 0;
+
+    /*!
+    @brief the end of an object was read
+    @return whether parsing should proceed
+    */
+    virtual bool end_object() = 0;
+
+    /*!
+    @brief the beginning of an array was read
+    @param[in] elements  number of array elements or -1 if unknown
+    @return whether parsing should proceed
+    @note binary formats may report the number of elements
+    */
+    virtual bool start_array(std::size_t elements) = 0;
+
+    /*!
+    @brief the end of an array was read
+    @return whether parsing should proceed
+    */
+    virtual bool end_array() = 0;
+
+    /*!
+    @brief a parse error occurred
+    @param[in] position    the position in the input where the error occurs
+    @param[in] last_token  the last read token
+    @param[in] ex          an exception object describing the error
+    @return whether parsing should proceed (must return false)
+    */
+    virtual bool parse_error(std::size_t position,
+                             const std::string& last_token,
+                             const detail::exception& ex) = 0;
+
+    json_sax() = default;
+    json_sax(const json_sax&) = default;
+    json_sax(json_sax&&) noexcept = default;
+    json_sax& operator=(const json_sax&) = default;
+    json_sax& operator=(json_sax&&) noexcept = default;
+    virtual ~json_sax() = default;
+};
+
+
+namespace detail
+{
+/*!
+@brief SAX implementation to create a JSON value from SAX events
+
+This class implements the @ref json_sax interface and processes the SAX events
+to create a JSON value which makes it basically a DOM parser. The structure or
+hierarchy of the JSON value is managed by the stack `ref_stack` which contains
+a pointer to the respective array or object for each recursion depth.
+
+After successful parsing, the value that is passed by reference to the
+constructor contains the parsed value.
+
+@tparam BasicJsonType  the JSON type
+*/
+template<typename BasicJsonType>
+class json_sax_dom_parser
+{
+  public:
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+
+    /*!
+    @param[in,out] r  reference to a JSON value that is manipulated while
+                       parsing
+    @param[in] allow_exceptions_  whether parse errors yield exceptions
+    */
+    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
+        : root(r), allow_exceptions(allow_exceptions_)
+    {}
+
+    // make class move-only
+    json_sax_dom_parser(const json_sax_dom_parser&) = delete;
+    json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
+    json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    ~json_sax_dom_parser() = default;
+
+    bool null()
+    {
+        handle_value(nullptr);
+        return true;
+    }
+
+    bool boolean(bool val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_integer(number_integer_t val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_unsigned(number_unsigned_t val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_float(number_float_t val, const string_t& /*unused*/)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool string(string_t& val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool binary(binary_t& val)
+    {
+        handle_value(std::move(val));
+        return true;
+    }
+
+    bool start_object(std::size_t len)
+    {
+        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
+
+        if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
+        {
+            JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
+        }
+
+        return true;
+    }
+
+    bool key(string_t& val)
+    {
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(ref_stack.back()->is_object());
+
+        // add null at given key and store the reference for later
+        object_element = &(ref_stack.back()->m_value.object->operator[](val));
+        return true;
+    }
+
+    bool end_object()
+    {
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(ref_stack.back()->is_object());
+
+        ref_stack.back()->set_parents();
+        ref_stack.pop_back();
+        return true;
+    }
+
+    bool start_array(std::size_t len)
+    {
+        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
+
+        if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
+        {
+            JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
+        }
+
+        return true;
+    }
+
+    bool end_array()
+    {
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(ref_stack.back()->is_array());
+
+        ref_stack.back()->set_parents();
+        ref_stack.pop_back();
+        return true;
+    }
+
+    template<class Exception>
+    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
+                     const Exception& ex)
+    {
+        errored = true;
+        static_cast<void>(ex);
+        if (allow_exceptions)
+        {
+            JSON_THROW(ex);
+        }
+        return false;
+    }
+
+    constexpr bool is_errored() const
+    {
+        return errored;
+    }
+
+  private:
+    /*!
+    @invariant If the ref stack is empty, then the passed value will be the new
+               root.
+    @invariant If the ref stack contains a value, then it is an array or an
+               object to which we can add elements
+    */
+    template<typename Value>
+    JSON_HEDLEY_RETURNS_NON_NULL
+    BasicJsonType* handle_value(Value&& v)
+    {
+        if (ref_stack.empty())
+        {
+            root = BasicJsonType(std::forward<Value>(v));
+            return &root;
+        }
+
+        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
+
+        if (ref_stack.back()->is_array())
+        {
+            ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
+            return &(ref_stack.back()->m_value.array->back());
+        }
+
+        JSON_ASSERT(ref_stack.back()->is_object());
+        JSON_ASSERT(object_element);
+        *object_element = BasicJsonType(std::forward<Value>(v));
+        return object_element;
+    }
+
+    /// the parsed JSON value
+    BasicJsonType& root;
+    /// stack to model hierarchy of values
+    std::vector<BasicJsonType*> ref_stack {};
+    /// helper to hold the reference for the next object element
+    BasicJsonType* object_element = nullptr;
+    /// whether a syntax error occurred
+    bool errored = false;
+    /// whether to throw exceptions in case of errors
+    const bool allow_exceptions = true;
+};
+
+template<typename BasicJsonType>
+class json_sax_dom_callback_parser
+{
+  public:
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using parser_callback_t = typename BasicJsonType::parser_callback_t;
+    using parse_event_t = typename BasicJsonType::parse_event_t;
+
+    json_sax_dom_callback_parser(BasicJsonType& r,
+                                 const parser_callback_t cb,
+                                 const bool allow_exceptions_ = true)
+        : root(r), callback(cb), allow_exceptions(allow_exceptions_)
+    {
+        keep_stack.push_back(true);
+    }
+
+    // make class move-only
+    json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
+    json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
+    json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    ~json_sax_dom_callback_parser() = default;
+
+    bool null()
+    {
+        handle_value(nullptr);
+        return true;
+    }
+
+    bool boolean(bool val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_integer(number_integer_t val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_unsigned(number_unsigned_t val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool number_float(number_float_t val, const string_t& /*unused*/)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool string(string_t& val)
+    {
+        handle_value(val);
+        return true;
+    }
+
+    bool binary(binary_t& val)
+    {
+        handle_value(std::move(val));
+        return true;
+    }
+
+    bool start_object(std::size_t len)
+    {
+        // check callback for object start
+        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
+        keep_stack.push_back(keep);
+
+        auto val = handle_value(BasicJsonType::value_t::object, true);
+        ref_stack.push_back(val.second);
+
+        // check object limit
+        if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
+        {
+            JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
+        }
+
+        return true;
+    }
+
+    bool key(string_t& val)
+    {
+        BasicJsonType k = BasicJsonType(val);
+
+        // check callback for key
+        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
+        key_keep_stack.push_back(keep);
+
+        // add discarded value at given key and store the reference for later
+        if (keep && ref_stack.back())
+        {
+            object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
+        }
+
+        return true;
+    }
+
+    bool end_object()
+    {
+        if (ref_stack.back())
+        {
+            if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
+            {
+                // discard object
+                *ref_stack.back() = discarded;
+            }
+            else
+            {
+                ref_stack.back()->set_parents();
+            }
+        }
+
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(!keep_stack.empty());
+        ref_stack.pop_back();
+        keep_stack.pop_back();
+
+        if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
+        {
+            // remove discarded value
+            for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
+            {
+                if (it->is_discarded())
+                {
+                    ref_stack.back()->erase(it);
+                    break;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    bool start_array(std::size_t len)
+    {
+        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
+        keep_stack.push_back(keep);
+
+        auto val = handle_value(BasicJsonType::value_t::array, true);
+        ref_stack.push_back(val.second);
+
+        // check array limit
+        if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
+        {
+            JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
+        }
+
+        return true;
+    }
+
+    bool end_array()
+    {
+        bool keep = true;
+
+        if (ref_stack.back())
+        {
+            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
+            if (keep)
+            {
+                ref_stack.back()->set_parents();
+            }
+            else
+            {
+                // discard array
+                *ref_stack.back() = discarded;
+            }
+        }
+
+        JSON_ASSERT(!ref_stack.empty());
+        JSON_ASSERT(!keep_stack.empty());
+        ref_stack.pop_back();
+        keep_stack.pop_back();
+
+        // remove discarded value
+        if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
+        {
+            ref_stack.back()->m_value.array->pop_back();
+        }
+
+        return true;
+    }
+
+    template<class Exception>
+    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
+                     const Exception& ex)
+    {
+        errored = true;
+        static_cast<void>(ex);
+        if (allow_exceptions)
+        {
+            JSON_THROW(ex);
+        }
+        return false;
+    }
+
+    constexpr bool is_errored() const
+    {
+        return errored;
+    }
+
+  private:
+    /*!
+    @param[in] v  value to add to the JSON value we build during parsing
+    @param[in] skip_callback  whether we should skip calling the callback
+               function; this is required after start_array() and
+               start_object() SAX events, because otherwise we would call the
+               callback function with an empty array or object, respectively.
+
+    @invariant If the ref stack is empty, then the passed value will be the new
+               root.
+    @invariant If the ref stack contains a value, then it is an array or an
+               object to which we can add elements
+
+    @return pair of boolean (whether value should be kept) and pointer (to the
+            passed value in the ref_stack hierarchy; nullptr if not kept)
+    */
+    template<typename Value>
+    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
+    {
+        JSON_ASSERT(!keep_stack.empty());
+
+        // do not handle this value if we know it would be added to a discarded
+        // container
+        if (!keep_stack.back())
+        {
+            return {false, nullptr};
+        }
+
+        // create value
+        auto value = BasicJsonType(std::forward<Value>(v));
+
+        // check callback
+        const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
+
+        // do not handle this value if we just learnt it shall be discarded
+        if (!keep)
+        {
+            return {false, nullptr};
+        }
+
+        if (ref_stack.empty())
+        {
+            root = std::move(value);
+            return {true, &root};
+        }
+
+        // skip this value if we already decided to skip the parent
+        // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
+        if (!ref_stack.back())
+        {
+            return {false, nullptr};
+        }
+
+        // we now only expect arrays and objects
+        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
+
+        // array
+        if (ref_stack.back()->is_array())
+        {
+            ref_stack.back()->m_value.array->emplace_back(std::move(value));
+            return {true, &(ref_stack.back()->m_value.array->back())};
+        }
+
+        // object
+        JSON_ASSERT(ref_stack.back()->is_object());
+        // check if we should store an element for the current key
+        JSON_ASSERT(!key_keep_stack.empty());
+        const bool store_element = key_keep_stack.back();
+        key_keep_stack.pop_back();
+
+        if (!store_element)
+        {
+            return {false, nullptr};
+        }
+
+        JSON_ASSERT(object_element);
+        *object_element = std::move(value);
+        return {true, object_element};
+    }
+
+    /// the parsed JSON value
+    BasicJsonType& root;
+    /// stack to model hierarchy of values
+    std::vector<BasicJsonType*> ref_stack {};
+    /// stack to manage which values to keep
+    std::vector<bool> keep_stack {};
+    /// stack to manage which object keys to keep
+    std::vector<bool> key_keep_stack {};
+    /// helper to hold the reference for the next object element
+    BasicJsonType* object_element = nullptr;
+    /// whether a syntax error occurred
+    bool errored = false;
+    /// callback function
+    const parser_callback_t callback = nullptr;
+    /// whether to throw exceptions in case of errors
+    const bool allow_exceptions = true;
+    /// a discarded value for the callback
+    BasicJsonType discarded = BasicJsonType::value_t::discarded;
+};
+
+template<typename BasicJsonType>
+class json_sax_acceptor
+{
+  public:
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+
+    bool null()
+    {
+        return true;
+    }
+
+    bool boolean(bool /*unused*/)
+    {
+        return true;
+    }
+
+    bool number_integer(number_integer_t /*unused*/)
+    {
+        return true;
+    }
+
+    bool number_unsigned(number_unsigned_t /*unused*/)
+    {
+        return true;
+    }
+
+    bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
+    {
+        return true;
+    }
+
+    bool string(string_t& /*unused*/)
+    {
+        return true;
+    }
+
+    bool binary(binary_t& /*unused*/)
+    {
+        return true;
+    }
+
+    bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
+    {
+        return true;
+    }
+
+    bool key(string_t& /*unused*/)
+    {
+        return true;
+    }
+
+    bool end_object()
+    {
+        return true;
+    }
+
+    bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
+    {
+        return true;
+    }
+
+    bool end_array()
+    {
+        return true;
+    }
+
+    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
+    {
+        return false;
+    }
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/input/lexer.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <array> // array
+#include <clocale> // localeconv
+#include <cstddef> // size_t
+#include <cstdio> // snprintf
+#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
+#include <initializer_list> // initializer_list
+#include <string> // char_traits, string
+#include <utility> // move
+#include <vector> // vector
+
+// #include <nlohmann/detail/input/input_adapters.hpp>
+
+// #include <nlohmann/detail/input/position_t.hpp>
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////
+// lexer //
+///////////
+
+template<typename BasicJsonType>
+class lexer_base
+{
+  public:
+    /// token types for the parser
+    enum class token_type
+    {
+        uninitialized,    ///< indicating the scanner is uninitialized
+        literal_true,     ///< the `true` literal
+        literal_false,    ///< the `false` literal
+        literal_null,     ///< the `null` literal
+        value_string,     ///< a string -- use get_string() for actual value
+        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value
+        value_integer,    ///< a signed integer -- use get_number_integer() for actual value
+        value_float,      ///< an floating point number -- use get_number_float() for actual value
+        begin_array,      ///< the character for array begin `[`
+        begin_object,     ///< the character for object begin `{`
+        end_array,        ///< the character for array end `]`
+        end_object,       ///< the character for object end `}`
+        name_separator,   ///< the name separator `:`
+        value_separator,  ///< the value separator `,`
+        parse_error,      ///< indicating a parse error
+        end_of_input,     ///< indicating the end of the input buffer
+        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)
+    };
+
+    /// return name of values of type token_type (only used for errors)
+    JSON_HEDLEY_RETURNS_NON_NULL
+    JSON_HEDLEY_CONST
+    static const char* token_type_name(const token_type t) noexcept
+    {
+        switch (t)
+        {
+            case token_type::uninitialized:
+                return "<uninitialized>";
+            case token_type::literal_true:
+                return "true literal";
+            case token_type::literal_false:
+                return "false literal";
+            case token_type::literal_null:
+                return "null literal";
+            case token_type::value_string:
+                return "string literal";
+            case token_type::value_unsigned:
+            case token_type::value_integer:
+            case token_type::value_float:
+                return "number literal";
+            case token_type::begin_array:
+                return "'['";
+            case token_type::begin_object:
+                return "'{'";
+            case token_type::end_array:
+                return "']'";
+            case token_type::end_object:
+                return "'}'";
+            case token_type::name_separator:
+                return "':'";
+            case token_type::value_separator:
+                return "','";
+            case token_type::parse_error:
+                return "<parse error>";
+            case token_type::end_of_input:
+                return "end of input";
+            case token_type::literal_or_value:
+                return "'[', '{', or a literal";
+            // LCOV_EXCL_START
+            default: // catch non-enum values
+                return "unknown token";
+                // LCOV_EXCL_STOP
+        }
+    }
+};
+/*!
+@brief lexical analysis
+
+This class organizes the lexical analysis during JSON deserialization.
+*/
+template<typename BasicJsonType, typename InputAdapterType>
+class lexer : public lexer_base<BasicJsonType>
+{
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using char_type = typename InputAdapterType::char_type;
+    using char_int_type = typename std::char_traits<char_type>::int_type;
+
+  public:
+    using token_type = typename lexer_base<BasicJsonType>::token_type;
+
+    explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
+        : ia(std::move(adapter))
+        , ignore_comments(ignore_comments_)
+        , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
+    {}
+
+    // delete because of pointer members
+    lexer(const lexer&) = delete;
+    lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    lexer& operator=(lexer&) = delete;
+    lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    ~lexer() = default;
+
+  private:
+    /////////////////////
+    // locales
+    /////////////////////
+
+    /// return the locale-dependent decimal point
+    JSON_HEDLEY_PURE
+    static char get_decimal_point() noexcept
+    {
+        const auto* loc = localeconv();
+        JSON_ASSERT(loc != nullptr);
+        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
+    }
+
+    /////////////////////
+    // scan functions
+    /////////////////////
+
+    /*!
+    @brief get codepoint from 4 hex characters following `\u`
+
+    For input "\u c1 c2 c3 c4" the codepoint is:
+      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
+    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
+
+    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'
+    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The
+    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)
+    between the ASCII value of the character and the desired integer value.
+
+    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or
+            non-hex character)
+    */
+    int get_codepoint()
+    {
+        // this function only makes sense after reading `\u`
+        JSON_ASSERT(current == 'u');
+        int codepoint = 0;
+
+        const auto factors = { 12u, 8u, 4u, 0u };
+        for (const auto factor : factors)
+        {
+            get();
+
+            if (current >= '0' && current <= '9')
+            {
+                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
+            }
+            else if (current >= 'A' && current <= 'F')
+            {
+                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
+            }
+            else if (current >= 'a' && current <= 'f')
+            {
+                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);
+        return codepoint;
+    }
+
+    /*!
+    @brief check if the next byte(s) are inside a given range
+
+    Adds the current byte and, for each passed range, reads a new byte and
+    checks if it is inside the range. If a violation was detected, set up an
+    error message and return false. Otherwise, return true.
+
+    @param[in] ranges  list of integers; interpreted as list of pairs of
+                       inclusive lower and upper bound, respectively
+
+    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,
+         1, 2, or 3 pairs. This precondition is enforced by an assertion.
+
+    @return true if and only if no range violation was detected
+    */
+    bool next_byte_in_range(std::initializer_list<char_int_type> ranges)
+    {
+        JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
+        add(current);
+
+        for (auto range = ranges.begin(); range != ranges.end(); ++range)
+        {
+            get();
+            if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range)))
+            {
+                add(current);
+            }
+            else
+            {
+                error_message = "invalid string: ill-formed UTF-8 byte";
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /*!
+    @brief scan a string literal
+
+    This function scans a string according to Sect. 7 of RFC 8259. While
+    scanning, bytes are escaped and copied into buffer token_buffer. Then the
+    function returns successfully, token_buffer is *not* null-terminated (as it
+    may contain \0 bytes), and token_buffer.size() is the number of bytes in the
+    string.
+
+    @return token_type::value_string if string could be successfully scanned,
+            token_type::parse_error otherwise
+
+    @note In case of errors, variable error_message contains a textual
+          description.
+    */
+    token_type scan_string()
+    {
+        // reset token_buffer (ignore opening quote)
+        reset();
+
+        // we entered the function by reading an open quote
+        JSON_ASSERT(current == '\"');
+
+        while (true)
+        {
+            // get next character
+            switch (get())
+            {
+                // end of file while parsing string
+                case std::char_traits<char_type>::eof():
+                {
+                    error_message = "invalid string: missing closing quote";
+                    return token_type::parse_error;
+                }
+
+                // closing quote
+                case '\"':
+                {
+                    return token_type::value_string;
+                }
+
+                // escapes
+                case '\\':
+                {
+                    switch (get())
+                    {
+                        // quotation mark
+                        case '\"':
+                            add('\"');
+                            break;
+                        // reverse solidus
+                        case '\\':
+                            add('\\');
+                            break;
+                        // solidus
+                        case '/':
+                            add('/');
+                            break;
+                        // backspace
+                        case 'b':
+                            add('\b');
+                            break;
+                        // form feed
+                        case 'f':
+                            add('\f');
+                            break;
+                        // line feed
+                        case 'n':
+                            add('\n');
+                            break;
+                        // carriage return
+                        case 'r':
+                            add('\r');
+                            break;
+                        // tab
+                        case 't':
+                            add('\t');
+                            break;
+
+                        // unicode escapes
+                        case 'u':
+                        {
+                            const int codepoint1 = get_codepoint();
+                            int codepoint = codepoint1; // start with codepoint1
+
+                            if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))
+                            {
+                                error_message = "invalid string: '\\u' must be followed by 4 hex digits";
+                                return token_type::parse_error;
+                            }
+
+                            // check if code point is a high surrogate
+                            if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)
+                            {
+                                // expect next \uxxxx entry
+                                if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u'))
+                                {
+                                    const int codepoint2 = get_codepoint();
+
+                                    if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))
+                                    {
+                                        error_message = "invalid string: '\\u' must be followed by 4 hex digits";
+                                        return token_type::parse_error;
+                                    }
+
+                                    // check if codepoint2 is a low surrogate
+                                    if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))
+                                    {
+                                        // overwrite codepoint
+                                        codepoint = static_cast<int>(
+                                                        // high surrogate occupies the most significant 22 bits
+                                                        (static_cast<unsigned int>(codepoint1) << 10u)
+                                                        // low surrogate occupies the least significant 15 bits
+                                                        + static_cast<unsigned int>(codepoint2)
+                                                        // there is still the 0xD800, 0xDC00 and 0x10000 noise
+                                                        // in the result, so we have to subtract with:
+                                                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
+                                                        - 0x35FDC00u);
+                                    }
+                                    else
+                                    {
+                                        error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF";
+                                        return token_type::parse_error;
+                                    }
+                                }
+                                else
+                                {
+                                    error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF";
+                                    return token_type::parse_error;
+                                }
+                            }
+                            else
+                            {
+                                if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))
+                                {
+                                    error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
+                                    return token_type::parse_error;
+                                }
+                            }
+
+                            // result of the above calculation yields a proper codepoint
+                            JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);
+
+                            // translate codepoint into bytes
+                            if (codepoint < 0x80)
+                            {
+                                // 1-byte characters: 0xxxxxxx (ASCII)
+                                add(static_cast<char_int_type>(codepoint));
+                            }
+                            else if (codepoint <= 0x7FF)
+                            {
+                                // 2-byte characters: 110xxxxx 10xxxxxx
+                                add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));
+                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
+                            }
+                            else if (codepoint <= 0xFFFF)
+                            {
+                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
+                                add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));
+                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
+                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
+                            }
+                            else
+                            {
+                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+                                add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));
+                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));
+                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
+                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
+                            }
+
+                            break;
+                        }
+
+                        // other characters after escape
+                        default:
+                            error_message = "invalid string: forbidden character after backslash";
+                            return token_type::parse_error;
+                    }
+
+                    break;
+                }
+
+                // invalid control characters
+                case 0x00:
+                {
+                    error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000";
+                    return token_type::parse_error;
+                }
+
+                case 0x01:
+                {
+                    error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001";
+                    return token_type::parse_error;
+                }
+
+                case 0x02:
+                {
+                    error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002";
+                    return token_type::parse_error;
+                }
+
+                case 0x03:
+                {
+                    error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003";
+                    return token_type::parse_error;
+                }
+
+                case 0x04:
+                {
+                    error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004";
+                    return token_type::parse_error;
+                }
+
+                case 0x05:
+                {
+                    error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005";
+                    return token_type::parse_error;
+                }
+
+                case 0x06:
+                {
+                    error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006";
+                    return token_type::parse_error;
+                }
+
+                case 0x07:
+                {
+                    error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007";
+                    return token_type::parse_error;
+                }
+
+                case 0x08:
+                {
+                    error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b";
+                    return token_type::parse_error;
+                }
+
+                case 0x09:
+                {
+                    error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t";
+                    return token_type::parse_error;
+                }
+
+                case 0x0A:
+                {
+                    error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n";
+                    return token_type::parse_error;
+                }
+
+                case 0x0B:
+                {
+                    error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B";
+                    return token_type::parse_error;
+                }
+
+                case 0x0C:
+                {
+                    error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f";
+                    return token_type::parse_error;
+                }
+
+                case 0x0D:
+                {
+                    error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r";
+                    return token_type::parse_error;
+                }
+
+                case 0x0E:
+                {
+                    error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E";
+                    return token_type::parse_error;
+                }
+
+                case 0x0F:
+                {
+                    error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F";
+                    return token_type::parse_error;
+                }
+
+                case 0x10:
+                {
+                    error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010";
+                    return token_type::parse_error;
+                }
+
+                case 0x11:
+                {
+                    error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011";
+                    return token_type::parse_error;
+                }
+
+                case 0x12:
+                {
+                    error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012";
+                    return token_type::parse_error;
+                }
+
+                case 0x13:
+                {
+                    error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013";
+                    return token_type::parse_error;
+                }
+
+                case 0x14:
+                {
+                    error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014";
+                    return token_type::parse_error;
+                }
+
+                case 0x15:
+                {
+                    error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015";
+                    return token_type::parse_error;
+                }
+
+                case 0x16:
+                {
+                    error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016";
+                    return token_type::parse_error;
+                }
+
+                case 0x17:
+                {
+                    error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017";
+                    return token_type::parse_error;
+                }
+
+                case 0x18:
+                {
+                    error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018";
+                    return token_type::parse_error;
+                }
+
+                case 0x19:
+                {
+                    error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019";
+                    return token_type::parse_error;
+                }
+
+                case 0x1A:
+                {
+                    error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A";
+                    return token_type::parse_error;
+                }
+
+                case 0x1B:
+                {
+                    error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B";
+                    return token_type::parse_error;
+                }
+
+                case 0x1C:
+                {
+                    error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C";
+                    return token_type::parse_error;
+                }
+
+                case 0x1D:
+                {
+                    error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D";
+                    return token_type::parse_error;
+                }
+
+                case 0x1E:
+                {
+                    error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E";
+                    return token_type::parse_error;
+                }
+
+                case 0x1F:
+                {
+                    error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F";
+                    return token_type::parse_error;
+                }
+
+                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
+                case 0x20:
+                case 0x21:
+                case 0x23:
+                case 0x24:
+                case 0x25:
+                case 0x26:
+                case 0x27:
+                case 0x28:
+                case 0x29:
+                case 0x2A:
+                case 0x2B:
+                case 0x2C:
+                case 0x2D:
+                case 0x2E:
+                case 0x2F:
+                case 0x30:
+                case 0x31:
+                case 0x32:
+                case 0x33:
+                case 0x34:
+                case 0x35:
+                case 0x36:
+                case 0x37:
+                case 0x38:
+                case 0x39:
+                case 0x3A:
+                case 0x3B:
+                case 0x3C:
+                case 0x3D:
+                case 0x3E:
+                case 0x3F:
+                case 0x40:
+                case 0x41:
+                case 0x42:
+                case 0x43:
+                case 0x44:
+                case 0x45:
+                case 0x46:
+                case 0x47:
+                case 0x48:
+                case 0x49:
+                case 0x4A:
+                case 0x4B:
+                case 0x4C:
+                case 0x4D:
+                case 0x4E:
+                case 0x4F:
+                case 0x50:
+                case 0x51:
+                case 0x52:
+                case 0x53:
+                case 0x54:
+                case 0x55:
+                case 0x56:
+                case 0x57:
+                case 0x58:
+                case 0x59:
+                case 0x5A:
+                case 0x5B:
+                case 0x5D:
+                case 0x5E:
+                case 0x5F:
+                case 0x60:
+                case 0x61:
+                case 0x62:
+                case 0x63:
+                case 0x64:
+                case 0x65:
+                case 0x66:
+                case 0x67:
+                case 0x68:
+                case 0x69:
+                case 0x6A:
+                case 0x6B:
+                case 0x6C:
+                case 0x6D:
+                case 0x6E:
+                case 0x6F:
+                case 0x70:
+                case 0x71:
+                case 0x72:
+                case 0x73:
+                case 0x74:
+                case 0x75:
+                case 0x76:
+                case 0x77:
+                case 0x78:
+                case 0x79:
+                case 0x7A:
+                case 0x7B:
+                case 0x7C:
+                case 0x7D:
+                case 0x7E:
+                case 0x7F:
+                {
+                    add(current);
+                    break;
+                }
+
+                // U+0080..U+07FF: bytes C2..DF 80..BF
+                case 0xC2:
+                case 0xC3:
+                case 0xC4:
+                case 0xC5:
+                case 0xC6:
+                case 0xC7:
+                case 0xC8:
+                case 0xC9:
+                case 0xCA:
+                case 0xCB:
+                case 0xCC:
+                case 0xCD:
+                case 0xCE:
+                case 0xCF:
+                case 0xD0:
+                case 0xD1:
+                case 0xD2:
+                case 0xD3:
+                case 0xD4:
+                case 0xD5:
+                case 0xD6:
+                case 0xD7:
+                case 0xD8:
+                case 0xD9:
+                case 0xDA:
+                case 0xDB:
+                case 0xDC:
+                case 0xDD:
+                case 0xDE:
+                case 0xDF:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
+                case 0xE0:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
+                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
+                case 0xE1:
+                case 0xE2:
+                case 0xE3:
+                case 0xE4:
+                case 0xE5:
+                case 0xE6:
+                case 0xE7:
+                case 0xE8:
+                case 0xE9:
+                case 0xEA:
+                case 0xEB:
+                case 0xEC:
+                case 0xEE:
+                case 0xEF:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+D000..U+D7FF: bytes ED 80..9F 80..BF
+                case 0xED:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
+                case 0xF0:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
+                case 0xF1:
+                case 0xF2:
+                case 0xF3:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
+                case 0xF4:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
+                    {
+                        return token_type::parse_error;
+                    }
+                    break;
+                }
+
+                // remaining bytes (80..C1 and F5..FF) are ill-formed
+                default:
+                {
+                    error_message = "invalid string: ill-formed UTF-8 byte";
+                    return token_type::parse_error;
+                }
+            }
+        }
+    }
+
+    /*!
+     * @brief scan a comment
+     * @return whether comment could be scanned successfully
+     */
+    bool scan_comment()
+    {
+        switch (get())
+        {
+            // single-line comments skip input until a newline or EOF is read
+            case '/':
+            {
+                while (true)
+                {
+                    switch (get())
+                    {
+                        case '\n':
+                        case '\r':
+                        case std::char_traits<char_type>::eof():
+                        case '\0':
+                            return true;
+
+                        default:
+                            break;
+                    }
+                }
+            }
+
+            // multi-line comments skip input until */ is read
+            case '*':
+            {
+                while (true)
+                {
+                    switch (get())
+                    {
+                        case std::char_traits<char_type>::eof():
+                        case '\0':
+                        {
+                            error_message = "invalid comment; missing closing '*/'";
+                            return false;
+                        }
+
+                        case '*':
+                        {
+                            switch (get())
+                            {
+                                case '/':
+                                    return true;
+
+                                default:
+                                {
+                                    unget();
+                                    continue;
+                                }
+                            }
+                        }
+
+                        default:
+                            continue;
+                    }
+                }
+            }
+
+            // unexpected character after reading '/'
+            default:
+            {
+                error_message = "invalid comment; expecting '/' or '*' after '/'";
+                return false;
+            }
+        }
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    static void strtof(float& f, const char* str, char** endptr) noexcept
+    {
+        f = std::strtof(str, endptr);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    static void strtof(double& f, const char* str, char** endptr) noexcept
+    {
+        f = std::strtod(str, endptr);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    static void strtof(long double& f, const char* str, char** endptr) noexcept
+    {
+        f = std::strtold(str, endptr);
+    }
+
+    /*!
+    @brief scan a number literal
+
+    This function scans a string according to Sect. 6 of RFC 8259.
+
+    The function is realized with a deterministic finite state machine derived
+    from the grammar described in RFC 8259. Starting in state "init", the
+    input is read and used to determined the next state. Only state "done"
+    accepts the number. State "error" is a trap state to model errors. In the
+    table below, "anything" means any character but the ones listed before.
+
+    state    | 0        | 1-9      | e E      | +       | -       | .        | anything
+    ---------|----------|----------|----------|---------|---------|----------|-----------
+    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]
+    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]
+    zero     | done     | done     | exponent | done    | done    | decimal1 | done
+    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done
+    decimal1 | decimal2 | decimal2 | [error]  | [error] | [error] | [error]  | [error]
+    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done
+    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]
+    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]
+    any2     | any2     | any2     | done     | done    | done    | done     | done
+
+    The state machine is realized with one label per state (prefixed with
+    "scan_number_") and `goto` statements between them. The state machine
+    contains cycles, but any cycle can be left when EOF is read. Therefore,
+    the function is guaranteed to terminate.
+
+    During scanning, the read bytes are stored in token_buffer. This string is
+    then converted to a signed integer, an unsigned integer, or a
+    floating-point number.
+
+    @return token_type::value_unsigned, token_type::value_integer, or
+            token_type::value_float if number could be successfully scanned,
+            token_type::parse_error otherwise
+
+    @note The scanner is independent of the current locale. Internally, the
+          locale's decimal point is used instead of `.` to work with the
+          locale-dependent converters.
+    */
+    token_type scan_number()  // lgtm [cpp/use-of-goto]
+    {
+        // reset token_buffer to store the number's bytes
+        reset();
+
+        // the type of the parsed number; initially set to unsigned; will be
+        // changed if minus sign, decimal point or exponent is read
+        token_type number_type = token_type::value_unsigned;
+
+        // state (init): we just found out we need to scan a number
+        switch (current)
+        {
+            case '-':
+            {
+                add(current);
+                goto scan_number_minus;
+            }
+
+            case '0':
+            {
+                add(current);
+                goto scan_number_zero;
+            }
+
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any1;
+            }
+
+            // all other characters are rejected outside scan_number()
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+
+scan_number_minus:
+        // state: we just parsed a leading minus sign
+        number_type = token_type::value_integer;
+        switch (get())
+        {
+            case '0':
+            {
+                add(current);
+                goto scan_number_zero;
+            }
+
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any1;
+            }
+
+            default:
+            {
+                error_message = "invalid number; expected digit after '-'";
+                return token_type::parse_error;
+            }
+        }
+
+scan_number_zero:
+        // state: we just parse a zero (maybe with a leading minus sign)
+        switch (get())
+        {
+            case '.':
+            {
+                add(decimal_point_char);
+                goto scan_number_decimal1;
+            }
+
+            case 'e':
+            case 'E':
+            {
+                add(current);
+                goto scan_number_exponent;
+            }
+
+            default:
+                goto scan_number_done;
+        }
+
+scan_number_any1:
+        // state: we just parsed a number 0-9 (maybe with a leading minus sign)
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any1;
+            }
+
+            case '.':
+            {
+                add(decimal_point_char);
+                goto scan_number_decimal1;
+            }
+
+            case 'e':
+            case 'E':
+            {
+                add(current);
+                goto scan_number_exponent;
+            }
+
+            default:
+                goto scan_number_done;
+        }
+
+scan_number_decimal1:
+        // state: we just parsed a decimal point
+        number_type = token_type::value_float;
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_decimal2;
+            }
+
+            default:
+            {
+                error_message = "invalid number; expected digit after '.'";
+                return token_type::parse_error;
+            }
+        }
+
+scan_number_decimal2:
+        // we just parsed at least one number after a decimal point
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_decimal2;
+            }
+
+            case 'e':
+            case 'E':
+            {
+                add(current);
+                goto scan_number_exponent;
+            }
+
+            default:
+                goto scan_number_done;
+        }
+
+scan_number_exponent:
+        // we just parsed an exponent
+        number_type = token_type::value_float;
+        switch (get())
+        {
+            case '+':
+            case '-':
+            {
+                add(current);
+                goto scan_number_sign;
+            }
+
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any2;
+            }
+
+            default:
+            {
+                error_message =
+                    "invalid number; expected '+', '-', or digit after exponent";
+                return token_type::parse_error;
+            }
+        }
+
+scan_number_sign:
+        // we just parsed an exponent sign
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any2;
+            }
+
+            default:
+            {
+                error_message = "invalid number; expected digit after exponent sign";
+                return token_type::parse_error;
+            }
+        }
+
+scan_number_any2:
+        // we just parsed a number after the exponent or exponent sign
+        switch (get())
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            {
+                add(current);
+                goto scan_number_any2;
+            }
+
+            default:
+                goto scan_number_done;
+        }
+
+scan_number_done:
+        // unget the character after the number (we only read it to know that
+        // we are done scanning a number)
+        unget();
+
+        char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+        errno = 0;
+
+        // try to parse integers first and fall back to floats
+        if (number_type == token_type::value_unsigned)
+        {
+            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
+
+            // we checked the number format before
+            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
+
+            if (errno == 0)
+            {
+                value_unsigned = static_cast<number_unsigned_t>(x);
+                if (value_unsigned == x)
+                {
+                    return token_type::value_unsigned;
+                }
+            }
+        }
+        else if (number_type == token_type::value_integer)
+        {
+            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
+
+            // we checked the number format before
+            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
+
+            if (errno == 0)
+            {
+                value_integer = static_cast<number_integer_t>(x);
+                if (value_integer == x)
+                {
+                    return token_type::value_integer;
+                }
+            }
+        }
+
+        // this code is reached if we parse a floating-point number or if an
+        // integer conversion above failed
+        strtof(value_float, token_buffer.data(), &endptr);
+
+        // we checked the number format before
+        JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
+
+        return token_type::value_float;
+    }
+
+    /*!
+    @param[in] literal_text  the literal text to expect
+    @param[in] length        the length of the passed literal text
+    @param[in] return_type   the token type to return on success
+    */
+    JSON_HEDLEY_NON_NULL(2)
+    token_type scan_literal(const char_type* literal_text, const std::size_t length,
+                            token_type return_type)
+    {
+        JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
+        for (std::size_t i = 1; i < length; ++i)
+        {
+            if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))
+            {
+                error_message = "invalid literal";
+                return token_type::parse_error;
+            }
+        }
+        return return_type;
+    }
+
+    /////////////////////
+    // input management
+    /////////////////////
+
+    /// reset token_buffer; current character is beginning of token
+    void reset() noexcept
+    {
+        token_buffer.clear();
+        token_string.clear();
+        token_string.push_back(std::char_traits<char_type>::to_char_type(current));
+    }
+
+    /*
+    @brief get next character from the input
+
+    This function provides the interface to the used input adapter. It does
+    not throw in case the input reached EOF, but returns a
+    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters
+    for use in error messages.
+
+    @return character read from the input
+    */
+    char_int_type get()
+    {
+        ++position.chars_read_total;
+        ++position.chars_read_current_line;
+
+        if (next_unget)
+        {
+            // just reset the next_unget variable and work with current
+            next_unget = false;
+        }
+        else
+        {
+            current = ia.get_character();
+        }
+
+        if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
+        {
+            token_string.push_back(std::char_traits<char_type>::to_char_type(current));
+        }
+
+        if (current == '\n')
+        {
+            ++position.lines_read;
+            position.chars_read_current_line = 0;
+        }
+
+        return current;
+    }
+
+    /*!
+    @brief unget current character (read it again on next get)
+
+    We implement unget by setting variable next_unget to true. The input is not
+    changed - we just simulate ungetting by modifying chars_read_total,
+    chars_read_current_line, and token_string. The next call to get() will
+    behave as if the unget character is read again.
+    */
+    void unget()
+    {
+        next_unget = true;
+
+        --position.chars_read_total;
+
+        // in case we "unget" a newline, we have to also decrement the lines_read
+        if (position.chars_read_current_line == 0)
+        {
+            if (position.lines_read > 0)
+            {
+                --position.lines_read;
+            }
+        }
+        else
+        {
+            --position.chars_read_current_line;
+        }
+
+        if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
+        {
+            JSON_ASSERT(!token_string.empty());
+            token_string.pop_back();
+        }
+    }
+
+    /// add a character to token_buffer
+    void add(char_int_type c)
+    {
+        token_buffer.push_back(static_cast<typename string_t::value_type>(c));
+    }
+
+  public:
+    /////////////////////
+    // value getters
+    /////////////////////
+
+    /// return integer value
+    constexpr number_integer_t get_number_integer() const noexcept
+    {
+        return value_integer;
+    }
+
+    /// return unsigned integer value
+    constexpr number_unsigned_t get_number_unsigned() const noexcept
+    {
+        return value_unsigned;
+    }
+
+    /// return floating-point value
+    constexpr number_float_t get_number_float() const noexcept
+    {
+        return value_float;
+    }
+
+    /// return current string value (implicitly resets the token; useful only once)
+    string_t& get_string()
+    {
+        return token_buffer;
+    }
+
+    /////////////////////
+    // diagnostics
+    /////////////////////
+
+    /// return position of last read token
+    constexpr position_t get_position() const noexcept
+    {
+        return position;
+    }
+
+    /// return the last read token (for errors only).  Will never contain EOF
+    /// (an arbitrary value that is not a valid char value, often -1), because
+    /// 255 may legitimately occur.  May contain NUL, which should be escaped.
+    std::string get_token_string() const
+    {
+        // escape control characters
+        std::string result;
+        for (const auto c : token_string)
+        {
+            if (static_cast<unsigned char>(c) <= '\x1F')
+            {
+                // escape control characters
+                std::array<char, 9> cs{{}};
+                static_cast<void>((std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+                result += cs.data();
+            }
+            else
+            {
+                // add character as is
+                result.push_back(static_cast<std::string::value_type>(c));
+            }
+        }
+
+        return result;
+    }
+
+    /// return syntax error message
+    JSON_HEDLEY_RETURNS_NON_NULL
+    constexpr const char* get_error_message() const noexcept
+    {
+        return error_message;
+    }
+
+    /////////////////////
+    // actual scanner
+    /////////////////////
+
+    /*!
+    @brief skip the UTF-8 byte order mark
+    @return true iff there is no BOM or the correct BOM has been skipped
+    */
+    bool skip_bom()
+    {
+        if (get() == 0xEF)
+        {
+            // check if we completely parse the BOM
+            return get() == 0xBB && get() == 0xBF;
+        }
+
+        // the first character is not the beginning of the BOM; unget it to
+        // process is later
+        unget();
+        return true;
+    }
+
+    void skip_whitespace()
+    {
+        do
+        {
+            get();
+        }
+        while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
+    }
+
+    token_type scan()
+    {
+        // initially, skip the BOM
+        if (position.chars_read_total == 0 && !skip_bom())
+        {
+            error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
+            return token_type::parse_error;
+        }
+
+        // read next character and ignore whitespace
+        skip_whitespace();
+
+        // ignore comments
+        while (ignore_comments && current == '/')
+        {
+            if (!scan_comment())
+            {
+                return token_type::parse_error;
+            }
+
+            // skip following whitespace
+            skip_whitespace();
+        }
+
+        switch (current)
+        {
+            // structural characters
+            case '[':
+                return token_type::begin_array;
+            case ']':
+                return token_type::end_array;
+            case '{':
+                return token_type::begin_object;
+            case '}':
+                return token_type::end_object;
+            case ':':
+                return token_type::name_separator;
+            case ',':
+                return token_type::value_separator;
+
+            // literals
+            case 't':
+            {
+                std::array<char_type, 4> true_literal = {{static_cast<char_type>('t'), static_cast<char_type>('r'), static_cast<char_type>('u'), static_cast<char_type>('e')}};
+                return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true);
+            }
+            case 'f':
+            {
+                std::array<char_type, 5> false_literal = {{static_cast<char_type>('f'), static_cast<char_type>('a'), static_cast<char_type>('l'), static_cast<char_type>('s'), static_cast<char_type>('e')}};
+                return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false);
+            }
+            case 'n':
+            {
+                std::array<char_type, 4> null_literal = {{static_cast<char_type>('n'), static_cast<char_type>('u'), static_cast<char_type>('l'), static_cast<char_type>('l')}};
+                return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null);
+            }
+
+            // string
+            case '\"':
+                return scan_string();
+
+            // number
+            case '-':
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                return scan_number();
+
+            // end of input (the null byte is needed when parsing from
+            // string literals)
+            case '\0':
+            case std::char_traits<char_type>::eof():
+                return token_type::end_of_input;
+
+            // error
+            default:
+                error_message = "invalid literal";
+                return token_type::parse_error;
+        }
+    }
+
+  private:
+    /// input adapter
+    InputAdapterType ia;
+
+    /// whether comments should be ignored (true) or signaled as errors (false)
+    const bool ignore_comments = false;
+
+    /// the current character
+    char_int_type current = std::char_traits<char_type>::eof();
+
+    /// whether the next get() call should just return current
+    bool next_unget = false;
+
+    /// the start position of the current token
+    position_t position {};
+
+    /// raw input token string (for error messages)
+    std::vector<char_type> token_string {};
+
+    /// buffer for variable-length tokens (numbers, strings)
+    string_t token_buffer {};
+
+    /// a description of occurred lexer errors
+    const char* error_message = "";
+
+    // number values
+    number_integer_t value_integer = 0;
+    number_unsigned_t value_unsigned = 0;
+    number_float_t value_float = 0;
+
+    /// the decimal point
+    const char_int_type decimal_point_char = '.';
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/is_sax.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstdint> // size_t
+#include <utility> // declval
+#include <string> // string
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+// #include <nlohmann/detail/meta/detected.hpp>
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename T>
+using null_function_t = decltype(std::declval<T&>().null());
+
+template<typename T>
+using boolean_function_t =
+    decltype(std::declval<T&>().boolean(std::declval<bool>()));
+
+template<typename T, typename Integer>
+using number_integer_function_t =
+    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
+
+template<typename T, typename Unsigned>
+using number_unsigned_function_t =
+    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
+
+template<typename T, typename Float, typename String>
+using number_float_function_t = decltype(std::declval<T&>().number_float(
+                                    std::declval<Float>(), std::declval<const String&>()));
+
+template<typename T, typename String>
+using string_function_t =
+    decltype(std::declval<T&>().string(std::declval<String&>()));
+
+template<typename T, typename Binary>
+using binary_function_t =
+    decltype(std::declval<T&>().binary(std::declval<Binary&>()));
+
+template<typename T>
+using start_object_function_t =
+    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
+
+template<typename T, typename String>
+using key_function_t =
+    decltype(std::declval<T&>().key(std::declval<String&>()));
+
+template<typename T>
+using end_object_function_t = decltype(std::declval<T&>().end_object());
+
+template<typename T>
+using start_array_function_t =
+    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
+
+template<typename T>
+using end_array_function_t = decltype(std::declval<T&>().end_array());
+
+template<typename T, typename Exception>
+using parse_error_function_t = decltype(std::declval<T&>().parse_error(
+        std::declval<std::size_t>(), std::declval<const std::string&>(),
+        std::declval<const Exception&>()));
+
+template<typename SAX, typename BasicJsonType>
+struct is_sax
+{
+  private:
+    static_assert(is_basic_json<BasicJsonType>::value,
+                  "BasicJsonType must be of type basic_json<...>");
+
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using exception_t = typename BasicJsonType::exception;
+
+  public:
+    static constexpr bool value =
+        is_detected_exact<bool, null_function_t, SAX>::value &&
+        is_detected_exact<bool, boolean_function_t, SAX>::value &&
+        is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
+        is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
+        is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
+        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
+        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
+        is_detected_exact<bool, start_object_function_t, SAX>::value &&
+        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
+        is_detected_exact<bool, end_object_function_t, SAX>::value &&
+        is_detected_exact<bool, start_array_function_t, SAX>::value &&
+        is_detected_exact<bool, end_array_function_t, SAX>::value &&
+        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
+};
+
+template<typename SAX, typename BasicJsonType>
+struct is_sax_static_asserts
+{
+  private:
+    static_assert(is_basic_json<BasicJsonType>::value,
+                  "BasicJsonType must be of type basic_json<...>");
+
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using exception_t = typename BasicJsonType::exception;
+
+  public:
+    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
+                  "Missing/invalid function: bool null()");
+    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
+                  "Missing/invalid function: bool boolean(bool)");
+    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
+                  "Missing/invalid function: bool boolean(bool)");
+    static_assert(
+        is_detected_exact<bool, number_integer_function_t, SAX,
+        number_integer_t>::value,
+        "Missing/invalid function: bool number_integer(number_integer_t)");
+    static_assert(
+        is_detected_exact<bool, number_unsigned_function_t, SAX,
+        number_unsigned_t>::value,
+        "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
+    static_assert(is_detected_exact<bool, number_float_function_t, SAX,
+                  number_float_t, string_t>::value,
+                  "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
+    static_assert(
+        is_detected_exact<bool, string_function_t, SAX, string_t>::value,
+        "Missing/invalid function: bool string(string_t&)");
+    static_assert(
+        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,
+        "Missing/invalid function: bool binary(binary_t&)");
+    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
+                  "Missing/invalid function: bool start_object(std::size_t)");
+    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
+                  "Missing/invalid function: bool key(string_t&)");
+    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
+                  "Missing/invalid function: bool end_object()");
+    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
+                  "Missing/invalid function: bool start_array(std::size_t)");
+    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
+                  "Missing/invalid function: bool end_array()");
+    static_assert(
+        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
+        "Missing/invalid function: bool parse_error(std::size_t, const "
+        "std::string&, const exception&)");
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+// #include <nlohmann/detail/string_concat.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// how to treat CBOR tags
+enum class cbor_tag_handler_t
+{
+    error,   ///< throw a parse_error exception in case of a tag
+    ignore,  ///< ignore tags
+    store    ///< store tags as binary type
+};
+
+/*!
+@brief determine system byte order
+
+@return true if and only if system's byte order is little endian
+
+@note from https://stackoverflow.com/a/1001328/266378
+*/
+static inline bool little_endianness(int num = 1) noexcept
+{
+    return *reinterpret_cast<char*>(&num) == 1;
+}
+
+
+///////////////////
+// binary reader //
+///////////////////
+
+/*!
+@brief deserialization of CBOR, MessagePack, and UBJSON values
+*/
+template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>
+class binary_reader
+{
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using json_sax_t = SAX;
+    using char_type = typename InputAdapterType::char_type;
+    using char_int_type = typename std::char_traits<char_type>::int_type;
+
+  public:
+    /*!
+    @brief create a binary reader
+
+    @param[in] adapter  input adapter to read from
+    */
+    explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format)
+    {
+        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
+    }
+
+    // make class move-only
+    binary_reader(const binary_reader&) = delete;
+    binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    binary_reader& operator=(const binary_reader&) = delete;
+    binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
+    ~binary_reader() = default;
+
+    /*!
+    @param[in] format  the binary format to parse
+    @param[in] sax_    a SAX event processor
+    @param[in] strict  whether to expect the input to be consumed completed
+    @param[in] tag_handler  how to treat CBOR tags
+
+    @return whether parsing was successful
+    */
+    JSON_HEDLEY_NON_NULL(3)
+    bool sax_parse(const input_format_t format,
+                   json_sax_t* sax_,
+                   const bool strict = true,
+                   const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        sax = sax_;
+        bool result = false;
+
+        switch (format)
+        {
+            case input_format_t::bson:
+                result = parse_bson_internal();
+                break;
+
+            case input_format_t::cbor:
+                result = parse_cbor_internal(true, tag_handler);
+                break;
+
+            case input_format_t::msgpack:
+                result = parse_msgpack_internal();
+                break;
+
+            case input_format_t::ubjson:
+            case input_format_t::bjdata:
+                result = parse_ubjson_internal();
+                break;
+
+            case input_format_t::json: // LCOV_EXCL_LINE
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+
+        // strict mode: next byte must be EOF
+        if (result && strict)
+        {
+            if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata)
+            {
+                get_ignore_noop();
+            }
+            else
+            {
+                get();
+            }
+
+            if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))
+            {
+                return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
+                                        exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
+            }
+        }
+
+        return result;
+    }
+
+  private:
+    //////////
+    // BSON //
+    //////////
+
+    /*!
+    @brief Reads in a BSON-object and passes it to the SAX-parser.
+    @return whether a valid BSON-value was passed to the SAX parser
+    */
+    bool parse_bson_internal()
+    {
+        std::int32_t document_size{};
+        get_number<std::int32_t, true>(input_format_t::bson, document_size);
+
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
+        {
+            return false;
+        }
+
+        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))
+        {
+            return false;
+        }
+
+        return sax->end_object();
+    }
+
+    /*!
+    @brief Parses a C-style string from the BSON input.
+    @param[in,out] result  A reference to the string variable where the read
+                            string is to be stored.
+    @return `true` if the \x00-byte indicating the end of the string was
+             encountered before the EOF; false` indicates an unexpected EOF.
+    */
+    bool get_bson_cstr(string_t& result)
+    {
+        auto out = std::back_inserter(result);
+        while (true)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring")))
+            {
+                return false;
+            }
+            if (current == 0x00)
+            {
+                return true;
+            }
+            *out++ = static_cast<typename string_t::value_type>(current);
+        }
+    }
+
+    /*!
+    @brief Parses a zero-terminated string of length @a len from the BSON
+           input.
+    @param[in] len  The length (including the zero-byte at the end) of the
+                    string to be read.
+    @param[in,out] result  A reference to the string variable where the read
+                            string is to be stored.
+    @tparam NumberType The type of the length @a len
+    @pre len >= 1
+    @return `true` if the string was successfully parsed
+    */
+    template<typename NumberType>
+    bool get_bson_string(const NumberType len, string_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(len < 1))
+        {
+            auto last_token = get_token_string();
+            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                    exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
+        }
+
+        return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof();
+    }
+
+    /*!
+    @brief Parses a byte array input of length @a len from the BSON input.
+    @param[in] len  The length of the byte array to be read.
+    @param[in,out] result  A reference to the binary variable where the read
+                            array is to be stored.
+    @tparam NumberType The type of the length @a len
+    @pre len >= 0
+    @return `true` if the byte array was successfully parsed
+    */
+    template<typename NumberType>
+    bool get_bson_binary(const NumberType len, binary_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(len < 0))
+        {
+            auto last_token = get_token_string();
+            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                    exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr));
+        }
+
+        // All BSON binary values have a subtype
+        std::uint8_t subtype{};
+        get_number<std::uint8_t>(input_format_t::bson, subtype);
+        result.set_subtype(subtype);
+
+        return get_binary(input_format_t::bson, len, result);
+    }
+
+    /*!
+    @brief Read a BSON document element of the given @a element_type.
+    @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html
+    @param[in] element_type_parse_position The position in the input stream,
+               where the `element_type` was read.
+    @warning Not all BSON element types are supported yet. An unsupported
+             @a element_type will give rise to a parse_error.114:
+             Unsupported BSON record type 0x...
+    @return whether a valid BSON-object/array was passed to the SAX parser
+    */
+    bool parse_bson_element_internal(const char_int_type element_type,
+                                     const std::size_t element_type_parse_position)
+    {
+        switch (element_type)
+        {
+            case 0x01: // double
+            {
+                double number{};
+                return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 0x02: // string
+            {
+                std::int32_t len{};
+                string_t value;
+                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);
+            }
+
+            case 0x03: // object
+            {
+                return parse_bson_internal();
+            }
+
+            case 0x04: // array
+            {
+                return parse_bson_array();
+            }
+
+            case 0x05: // binary
+            {
+                std::int32_t len{};
+                binary_t value;
+                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);
+            }
+
+            case 0x08: // boolean
+            {
+                return sax->boolean(get() != 0);
+            }
+
+            case 0x0A: // null
+            {
+                return sax->null();
+            }
+
+            case 0x10: // int32
+            {
+                std::int32_t value{};
+                return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
+            }
+
+            case 0x12: // int64
+            {
+                std::int64_t value{};
+                return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
+            }
+
+            default: // anything else not supported (yet)
+            {
+                std::array<char, 3> cr{{}};
+                static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+                std::string cr_str{cr.data()};
+                return sax->parse_error(element_type_parse_position, cr_str,
+                                        parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief Read a BSON element list (as specified in the BSON-spec)
+
+    The same binary layout is used for objects and arrays, hence it must be
+    indicated with the argument @a is_array which one is expected
+    (true --> array, false --> object).
+
+    @param[in] is_array Determines if the element list being read is to be
+                        treated as an object (@a is_array == false), or as an
+                        array (@a is_array == true).
+    @return whether a valid BSON-object/array was passed to the SAX parser
+    */
+    bool parse_bson_element_list(const bool is_array)
+    {
+        string_t key;
+
+        while (auto element_type = get())
+        {
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list")))
+            {
+                return false;
+            }
+
+            const std::size_t element_type_parse_position = chars_read;
+            if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
+            {
+                return false;
+            }
+
+            if (!is_array && !sax->key(key))
+            {
+                return false;
+            }
+
+            if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))
+            {
+                return false;
+            }
+
+            // get_bson_cstr only appends
+            key.clear();
+        }
+
+        return true;
+    }
+
+    /*!
+    @brief Reads an array from the BSON input and passes it to the SAX-parser.
+    @return whether a valid BSON-array was passed to the SAX parser
+    */
+    bool parse_bson_array()
+    {
+        std::int32_t document_size{};
+        get_number<std::int32_t, true>(input_format_t::bson, document_size);
+
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
+        {
+            return false;
+        }
+
+        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))
+        {
+            return false;
+        }
+
+        return sax->end_array();
+    }
+
+    //////////
+    // CBOR //
+    //////////
+
+    /*!
+    @param[in] get_char  whether a new character should be retrieved from the
+                         input (true) or whether the last read character should
+                         be considered instead (false)
+    @param[in] tag_handler how CBOR tags should be treated
+
+    @return whether a valid CBOR value was passed to the SAX parser
+    */
+    bool parse_cbor_internal(const bool get_char,
+                             const cbor_tag_handler_t tag_handler)
+    {
+        switch (get_char ? get() : current)
+        {
+            // EOF
+            case std::char_traits<char_type>::eof():
+                return unexpect_eof(input_format_t::cbor, "value");
+
+            // Integer 0x00..0x17 (0..23)
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+            case 0x0A:
+            case 0x0B:
+            case 0x0C:
+            case 0x0D:
+            case 0x0E:
+            case 0x0F:
+            case 0x10:
+            case 0x11:
+            case 0x12:
+            case 0x13:
+            case 0x14:
+            case 0x15:
+            case 0x16:
+            case 0x17:
+                return sax->number_unsigned(static_cast<number_unsigned_t>(current));
+
+            case 0x18: // Unsigned integer (one-byte uint8_t follows)
+            {
+                std::uint8_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+            }
+
+            case 0x19: // Unsigned integer (two-byte uint16_t follows)
+            {
+                std::uint16_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+            }
+
+            case 0x1A: // Unsigned integer (four-byte uint32_t follows)
+            {
+                std::uint32_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+            }
+
+            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
+            {
+                std::uint64_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
+            }
+
+            // Negative integer -1-0x00..-1-0x17 (-1..-24)
+            case 0x20:
+            case 0x21:
+            case 0x22:
+            case 0x23:
+            case 0x24:
+            case 0x25:
+            case 0x26:
+            case 0x27:
+            case 0x28:
+            case 0x29:
+            case 0x2A:
+            case 0x2B:
+            case 0x2C:
+            case 0x2D:
+            case 0x2E:
+            case 0x2F:
+            case 0x30:
+            case 0x31:
+            case 0x32:
+            case 0x33:
+            case 0x34:
+            case 0x35:
+            case 0x36:
+            case 0x37:
+                return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
+
+            case 0x38: // Negative integer (one-byte uint8_t follows)
+            {
+                std::uint8_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+            }
+
+            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
+            {
+                std::uint16_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+            }
+
+            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
+            {
+                std::uint32_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
+            }
+
+            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
+            {
+                std::uint64_t number{};
+                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
+                        - static_cast<number_integer_t>(number));
+            }
+
+            // Binary data (0x00..0x17 bytes follow)
+            case 0x40:
+            case 0x41:
+            case 0x42:
+            case 0x43:
+            case 0x44:
+            case 0x45:
+            case 0x46:
+            case 0x47:
+            case 0x48:
+            case 0x49:
+            case 0x4A:
+            case 0x4B:
+            case 0x4C:
+            case 0x4D:
+            case 0x4E:
+            case 0x4F:
+            case 0x50:
+            case 0x51:
+            case 0x52:
+            case 0x53:
+            case 0x54:
+            case 0x55:
+            case 0x56:
+            case 0x57:
+            case 0x58: // Binary data (one-byte uint8_t for n follows)
+            case 0x59: // Binary data (two-byte uint16_t for n follow)
+            case 0x5A: // Binary data (four-byte uint32_t for n follow)
+            case 0x5B: // Binary data (eight-byte uint64_t for n follow)
+            case 0x5F: // Binary data (indefinite length)
+            {
+                binary_t b;
+                return get_cbor_binary(b) && sax->binary(b);
+            }
+
+            // UTF-8 string (0x00..0x17 bytes follow)
+            case 0x60:
+            case 0x61:
+            case 0x62:
+            case 0x63:
+            case 0x64:
+            case 0x65:
+            case 0x66:
+            case 0x67:
+            case 0x68:
+            case 0x69:
+            case 0x6A:
+            case 0x6B:
+            case 0x6C:
+            case 0x6D:
+            case 0x6E:
+            case 0x6F:
+            case 0x70:
+            case 0x71:
+            case 0x72:
+            case 0x73:
+            case 0x74:
+            case 0x75:
+            case 0x76:
+            case 0x77:
+            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
+            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
+            case 0x7F: // UTF-8 string (indefinite length)
+            {
+                string_t s;
+                return get_cbor_string(s) && sax->string(s);
+            }
+
+            // array (0x00..0x17 data items follow)
+            case 0x80:
+            case 0x81:
+            case 0x82:
+            case 0x83:
+            case 0x84:
+            case 0x85:
+            case 0x86:
+            case 0x87:
+            case 0x88:
+            case 0x89:
+            case 0x8A:
+            case 0x8B:
+            case 0x8C:
+            case 0x8D:
+            case 0x8E:
+            case 0x8F:
+            case 0x90:
+            case 0x91:
+            case 0x92:
+            case 0x93:
+            case 0x94:
+            case 0x95:
+            case 0x96:
+            case 0x97:
+                return get_cbor_array(
+                           conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
+
+            case 0x98: // array (one-byte uint8_t for n follows)
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0x99: // array (two-byte uint16_t for n follow)
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0x9A: // array (four-byte uint32_t for n follow)
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0x9B: // array (eight-byte uint64_t for n follow)
+            {
+                std::uint64_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0x9F: // array (indefinite length)
+                return get_cbor_array(static_cast<std::size_t>(-1), tag_handler);
+
+            // map (0x00..0x17 pairs of data items follow)
+            case 0xA0:
+            case 0xA1:
+            case 0xA2:
+            case 0xA3:
+            case 0xA4:
+            case 0xA5:
+            case 0xA6:
+            case 0xA7:
+            case 0xA8:
+            case 0xA9:
+            case 0xAA:
+            case 0xAB:
+            case 0xAC:
+            case 0xAD:
+            case 0xAE:
+            case 0xAF:
+            case 0xB0:
+            case 0xB1:
+            case 0xB2:
+            case 0xB3:
+            case 0xB4:
+            case 0xB5:
+            case 0xB6:
+            case 0xB7:
+                return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
+
+            case 0xB8: // map (one-byte uint8_t for n follows)
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0xB9: // map (two-byte uint16_t for n follow)
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0xBA: // map (four-byte uint32_t for n follow)
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0xBB: // map (eight-byte uint64_t for n follow)
+            {
+                std::uint64_t len{};
+                return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
+            }
+
+            case 0xBF: // map (indefinite length)
+                return get_cbor_object(static_cast<std::size_t>(-1), tag_handler);
+
+            case 0xC6: // tagged item
+            case 0xC7:
+            case 0xC8:
+            case 0xC9:
+            case 0xCA:
+            case 0xCB:
+            case 0xCC:
+            case 0xCD:
+            case 0xCE:
+            case 0xCF:
+            case 0xD0:
+            case 0xD1:
+            case 0xD2:
+            case 0xD3:
+            case 0xD4:
+            case 0xD8: // tagged item (1 bytes follow)
+            case 0xD9: // tagged item (2 bytes follow)
+            case 0xDA: // tagged item (4 bytes follow)
+            case 0xDB: // tagged item (8 bytes follow)
+            {
+                switch (tag_handler)
+                {
+                    case cbor_tag_handler_t::error:
+                    {
+                        auto last_token = get_token_string();
+                        return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                                exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
+                    }
+
+                    case cbor_tag_handler_t::ignore:
+                    {
+                        // ignore binary subtype
+                        switch (current)
+                        {
+                            case 0xD8:
+                            {
+                                std::uint8_t subtype_to_ignore{};
+                                get_number(input_format_t::cbor, subtype_to_ignore);
+                                break;
+                            }
+                            case 0xD9:
+                            {
+                                std::uint16_t subtype_to_ignore{};
+                                get_number(input_format_t::cbor, subtype_to_ignore);
+                                break;
+                            }
+                            case 0xDA:
+                            {
+                                std::uint32_t subtype_to_ignore{};
+                                get_number(input_format_t::cbor, subtype_to_ignore);
+                                break;
+                            }
+                            case 0xDB:
+                            {
+                                std::uint64_t subtype_to_ignore{};
+                                get_number(input_format_t::cbor, subtype_to_ignore);
+                                break;
+                            }
+                            default:
+                                break;
+                        }
+                        return parse_cbor_internal(true, tag_handler);
+                    }
+
+                    case cbor_tag_handler_t::store:
+                    {
+                        binary_t b;
+                        // use binary subtype and store in binary container
+                        switch (current)
+                        {
+                            case 0xD8:
+                            {
+                                std::uint8_t subtype{};
+                                get_number(input_format_t::cbor, subtype);
+                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
+                                break;
+                            }
+                            case 0xD9:
+                            {
+                                std::uint16_t subtype{};
+                                get_number(input_format_t::cbor, subtype);
+                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
+                                break;
+                            }
+                            case 0xDA:
+                            {
+                                std::uint32_t subtype{};
+                                get_number(input_format_t::cbor, subtype);
+                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
+                                break;
+                            }
+                            case 0xDB:
+                            {
+                                std::uint64_t subtype{};
+                                get_number(input_format_t::cbor, subtype);
+                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
+                                break;
+                            }
+                            default:
+                                return parse_cbor_internal(true, tag_handler);
+                        }
+                        get();
+                        return get_cbor_binary(b) && sax->binary(b);
+                    }
+
+                    default:                 // LCOV_EXCL_LINE
+                        JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+                        return false;        // LCOV_EXCL_LINE
+                }
+            }
+
+            case 0xF4: // false
+                return sax->boolean(false);
+
+            case 0xF5: // true
+                return sax->boolean(true);
+
+            case 0xF6: // null
+                return sax->null();
+
+            case 0xF9: // Half-Precision Float (two-byte IEEE 754)
+            {
+                const auto byte1_raw = get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
+                {
+                    return false;
+                }
+                const auto byte2_raw = get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
+                {
+                    return false;
+                }
+
+                const auto byte1 = static_cast<unsigned char>(byte1_raw);
+                const auto byte2 = static_cast<unsigned char>(byte2_raw);
+
+                // code from RFC 7049, Appendix D, Figure 3:
+                // As half-precision floating-point numbers were only added
+                // to IEEE 754 in 2008, today's programming platforms often
+                // still only have limited support for them. It is very
+                // easy to include at least decoding support for them even
+                // without such support. An example of a small decoder for
+                // half-precision floating-point numbers in the C language
+                // is shown in Fig. 3.
+                const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
+                const double val = [&half]
+                {
+                    const int exp = (half >> 10u) & 0x1Fu;
+                    const unsigned int mant = half & 0x3FFu;
+                    JSON_ASSERT(0 <= exp&& exp <= 32);
+                    JSON_ASSERT(mant <= 1024);
+                    switch (exp)
+                    {
+                        case 0:
+                            return std::ldexp(mant, -24);
+                        case 31:
+                            return (mant == 0)
+                            ? std::numeric_limits<double>::infinity()
+                            : std::numeric_limits<double>::quiet_NaN();
+                        default:
+                            return std::ldexp(mant + 1024, exp - 25);
+                    }
+                }();
+                return sax->number_float((half & 0x8000u) != 0
+                                         ? static_cast<number_float_t>(-val)
+                                         : static_cast<number_float_t>(val), "");
+            }
+
+            case 0xFA: // Single-Precision Float (four-byte IEEE 754)
+            {
+                float number{};
+                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
+            {
+                double number{};
+                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            default: // anything else (0xFF is handled inside the other types)
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief reads a CBOR string
+
+    This function first reads starting bytes to determine the expected
+    string length and then copies this number of bytes into a string.
+    Additionally, CBOR's strings with indefinite lengths are supported.
+
+    @param[out] result  created string
+
+    @return whether string creation completed
+    */
+    bool get_cbor_string(string_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
+        {
+            return false;
+        }
+
+        switch (current)
+        {
+            // UTF-8 string (0x00..0x17 bytes follow)
+            case 0x60:
+            case 0x61:
+            case 0x62:
+            case 0x63:
+            case 0x64:
+            case 0x65:
+            case 0x66:
+            case 0x67:
+            case 0x68:
+            case 0x69:
+            case 0x6A:
+            case 0x6B:
+            case 0x6C:
+            case 0x6D:
+            case 0x6E:
+            case 0x6F:
+            case 0x70:
+            case 0x71:
+            case 0x72:
+            case 0x73:
+            case 0x74:
+            case 0x75:
+            case 0x76:
+            case 0x77:
+            {
+                return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
+            }
+
+            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+            }
+
+            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+            }
+
+            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+            }
+
+            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
+            {
+                std::uint64_t len{};
+                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
+            }
+
+            case 0x7F: // UTF-8 string (indefinite length)
+            {
+                while (get() != 0xFF)
+                {
+                    string_t chunk;
+                    if (!get_cbor_string(chunk))
+                    {
+                        return false;
+                    }
+                    result.append(chunk);
+                }
+                return true;
+            }
+
+            default:
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                        exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief reads a CBOR byte array
+
+    This function first reads starting bytes to determine the expected
+    byte array length and then copies this number of bytes into the byte array.
+    Additionally, CBOR's byte arrays with indefinite lengths are supported.
+
+    @param[out] result  created byte array
+
+    @return whether byte array creation completed
+    */
+    bool get_cbor_binary(binary_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
+        {
+            return false;
+        }
+
+        switch (current)
+        {
+            // Binary data (0x00..0x17 bytes follow)
+            case 0x40:
+            case 0x41:
+            case 0x42:
+            case 0x43:
+            case 0x44:
+            case 0x45:
+            case 0x46:
+            case 0x47:
+            case 0x48:
+            case 0x49:
+            case 0x4A:
+            case 0x4B:
+            case 0x4C:
+            case 0x4D:
+            case 0x4E:
+            case 0x4F:
+            case 0x50:
+            case 0x51:
+            case 0x52:
+            case 0x53:
+            case 0x54:
+            case 0x55:
+            case 0x56:
+            case 0x57:
+            {
+                return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
+            }
+
+            case 0x58: // Binary data (one-byte uint8_t for n follows)
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::cbor, len) &&
+                       get_binary(input_format_t::cbor, len, result);
+            }
+
+            case 0x59: // Binary data (two-byte uint16_t for n follow)
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::cbor, len) &&
+                       get_binary(input_format_t::cbor, len, result);
+            }
+
+            case 0x5A: // Binary data (four-byte uint32_t for n follow)
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::cbor, len) &&
+                       get_binary(input_format_t::cbor, len, result);
+            }
+
+            case 0x5B: // Binary data (eight-byte uint64_t for n follow)
+            {
+                std::uint64_t len{};
+                return get_number(input_format_t::cbor, len) &&
+                       get_binary(input_format_t::cbor, len, result);
+            }
+
+            case 0x5F: // Binary data (indefinite length)
+            {
+                while (get() != 0xFF)
+                {
+                    binary_t chunk;
+                    if (!get_cbor_binary(chunk))
+                    {
+                        return false;
+                    }
+                    result.insert(result.end(), chunk.begin(), chunk.end());
+                }
+                return true;
+            }
+
+            default:
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                        exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @param[in] len  the length of the array or static_cast<std::size_t>(-1) for an
+                    array of indefinite size
+    @param[in] tag_handler how CBOR tags should be treated
+    @return whether array creation completed
+    */
+    bool get_cbor_array(const std::size_t len,
+                        const cbor_tag_handler_t tag_handler)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
+        {
+            return false;
+        }
+
+        if (len != static_cast<std::size_t>(-1))
+        {
+            for (std::size_t i = 0; i < len; ++i)
+            {
+                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            while (get() != 0xFF)
+            {
+                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))
+                {
+                    return false;
+                }
+            }
+        }
+
+        return sax->end_array();
+    }
+
+    /*!
+    @param[in] len  the length of the object or static_cast<std::size_t>(-1) for an
+                    object of indefinite size
+    @param[in] tag_handler how CBOR tags should be treated
+    @return whether object creation completed
+    */
+    bool get_cbor_object(const std::size_t len,
+                         const cbor_tag_handler_t tag_handler)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
+        {
+            return false;
+        }
+
+        if (len != 0)
+        {
+            string_t key;
+            if (len != static_cast<std::size_t>(-1))
+            {
+                for (std::size_t i = 0; i < len; ++i)
+                {
+                    get();
+                    if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
+                    {
+                        return false;
+                    }
+
+                    if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+                    {
+                        return false;
+                    }
+                    key.clear();
+                }
+            }
+            else
+            {
+                while (get() != 0xFF)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
+                    {
+                        return false;
+                    }
+
+                    if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
+                    {
+                        return false;
+                    }
+                    key.clear();
+                }
+            }
+        }
+
+        return sax->end_object();
+    }
+
+    /////////////
+    // MsgPack //
+    /////////////
+
+    /*!
+    @return whether a valid MessagePack value was passed to the SAX parser
+    */
+    bool parse_msgpack_internal()
+    {
+        switch (get())
+        {
+            // EOF
+            case std::char_traits<char_type>::eof():
+                return unexpect_eof(input_format_t::msgpack, "value");
+
+            // positive fixint
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+            case 0x0A:
+            case 0x0B:
+            case 0x0C:
+            case 0x0D:
+            case 0x0E:
+            case 0x0F:
+            case 0x10:
+            case 0x11:
+            case 0x12:
+            case 0x13:
+            case 0x14:
+            case 0x15:
+            case 0x16:
+            case 0x17:
+            case 0x18:
+            case 0x19:
+            case 0x1A:
+            case 0x1B:
+            case 0x1C:
+            case 0x1D:
+            case 0x1E:
+            case 0x1F:
+            case 0x20:
+            case 0x21:
+            case 0x22:
+            case 0x23:
+            case 0x24:
+            case 0x25:
+            case 0x26:
+            case 0x27:
+            case 0x28:
+            case 0x29:
+            case 0x2A:
+            case 0x2B:
+            case 0x2C:
+            case 0x2D:
+            case 0x2E:
+            case 0x2F:
+            case 0x30:
+            case 0x31:
+            case 0x32:
+            case 0x33:
+            case 0x34:
+            case 0x35:
+            case 0x36:
+            case 0x37:
+            case 0x38:
+            case 0x39:
+            case 0x3A:
+            case 0x3B:
+            case 0x3C:
+            case 0x3D:
+            case 0x3E:
+            case 0x3F:
+            case 0x40:
+            case 0x41:
+            case 0x42:
+            case 0x43:
+            case 0x44:
+            case 0x45:
+            case 0x46:
+            case 0x47:
+            case 0x48:
+            case 0x49:
+            case 0x4A:
+            case 0x4B:
+            case 0x4C:
+            case 0x4D:
+            case 0x4E:
+            case 0x4F:
+            case 0x50:
+            case 0x51:
+            case 0x52:
+            case 0x53:
+            case 0x54:
+            case 0x55:
+            case 0x56:
+            case 0x57:
+            case 0x58:
+            case 0x59:
+            case 0x5A:
+            case 0x5B:
+            case 0x5C:
+            case 0x5D:
+            case 0x5E:
+            case 0x5F:
+            case 0x60:
+            case 0x61:
+            case 0x62:
+            case 0x63:
+            case 0x64:
+            case 0x65:
+            case 0x66:
+            case 0x67:
+            case 0x68:
+            case 0x69:
+            case 0x6A:
+            case 0x6B:
+            case 0x6C:
+            case 0x6D:
+            case 0x6E:
+            case 0x6F:
+            case 0x70:
+            case 0x71:
+            case 0x72:
+            case 0x73:
+            case 0x74:
+            case 0x75:
+            case 0x76:
+            case 0x77:
+            case 0x78:
+            case 0x79:
+            case 0x7A:
+            case 0x7B:
+            case 0x7C:
+            case 0x7D:
+            case 0x7E:
+            case 0x7F:
+                return sax->number_unsigned(static_cast<number_unsigned_t>(current));
+
+            // fixmap
+            case 0x80:
+            case 0x81:
+            case 0x82:
+            case 0x83:
+            case 0x84:
+            case 0x85:
+            case 0x86:
+            case 0x87:
+            case 0x88:
+            case 0x89:
+            case 0x8A:
+            case 0x8B:
+            case 0x8C:
+            case 0x8D:
+            case 0x8E:
+            case 0x8F:
+                return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
+
+            // fixarray
+            case 0x90:
+            case 0x91:
+            case 0x92:
+            case 0x93:
+            case 0x94:
+            case 0x95:
+            case 0x96:
+            case 0x97:
+            case 0x98:
+            case 0x99:
+            case 0x9A:
+            case 0x9B:
+            case 0x9C:
+            case 0x9D:
+            case 0x9E:
+            case 0x9F:
+                return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
+
+            // fixstr
+            case 0xA0:
+            case 0xA1:
+            case 0xA2:
+            case 0xA3:
+            case 0xA4:
+            case 0xA5:
+            case 0xA6:
+            case 0xA7:
+            case 0xA8:
+            case 0xA9:
+            case 0xAA:
+            case 0xAB:
+            case 0xAC:
+            case 0xAD:
+            case 0xAE:
+            case 0xAF:
+            case 0xB0:
+            case 0xB1:
+            case 0xB2:
+            case 0xB3:
+            case 0xB4:
+            case 0xB5:
+            case 0xB6:
+            case 0xB7:
+            case 0xB8:
+            case 0xB9:
+            case 0xBA:
+            case 0xBB:
+            case 0xBC:
+            case 0xBD:
+            case 0xBE:
+            case 0xBF:
+            case 0xD9: // str 8
+            case 0xDA: // str 16
+            case 0xDB: // str 32
+            {
+                string_t s;
+                return get_msgpack_string(s) && sax->string(s);
+            }
+
+            case 0xC0: // nil
+                return sax->null();
+
+            case 0xC2: // false
+                return sax->boolean(false);
+
+            case 0xC3: // true
+                return sax->boolean(true);
+
+            case 0xC4: // bin 8
+            case 0xC5: // bin 16
+            case 0xC6: // bin 32
+            case 0xC7: // ext 8
+            case 0xC8: // ext 16
+            case 0xC9: // ext 32
+            case 0xD4: // fixext 1
+            case 0xD5: // fixext 2
+            case 0xD6: // fixext 4
+            case 0xD7: // fixext 8
+            case 0xD8: // fixext 16
+            {
+                binary_t b;
+                return get_msgpack_binary(b) && sax->binary(b);
+            }
+
+            case 0xCA: // float 32
+            {
+                float number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 0xCB: // float 64
+            {
+                double number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 0xCC: // uint 8
+            {
+                std::uint8_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+            }
+
+            case 0xCD: // uint 16
+            {
+                std::uint16_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+            }
+
+            case 0xCE: // uint 32
+            {
+                std::uint32_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+            }
+
+            case 0xCF: // uint 64
+            {
+                std::uint64_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
+            }
+
+            case 0xD0: // int 8
+            {
+                std::int8_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+            }
+
+            case 0xD1: // int 16
+            {
+                std::int16_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+            }
+
+            case 0xD2: // int 32
+            {
+                std::int32_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+            }
+
+            case 0xD3: // int 64
+            {
+                std::int64_t number{};
+                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+            }
+
+            case 0xDC: // array 16
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
+            }
+
+            case 0xDD: // array 32
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));
+            }
+
+            case 0xDE: // map 16
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
+            }
+
+            case 0xDF: // map 32
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));
+            }
+
+            // negative fixint
+            case 0xE0:
+            case 0xE1:
+            case 0xE2:
+            case 0xE3:
+            case 0xE4:
+            case 0xE5:
+            case 0xE6:
+            case 0xE7:
+            case 0xE8:
+            case 0xE9:
+            case 0xEA:
+            case 0xEB:
+            case 0xEC:
+            case 0xED:
+            case 0xEE:
+            case 0xEF:
+            case 0xF0:
+            case 0xF1:
+            case 0xF2:
+            case 0xF3:
+            case 0xF4:
+            case 0xF5:
+            case 0xF6:
+            case 0xF7:
+            case 0xF8:
+            case 0xF9:
+            case 0xFA:
+            case 0xFB:
+            case 0xFC:
+            case 0xFD:
+            case 0xFE:
+            case 0xFF:
+                return sax->number_integer(static_cast<std::int8_t>(current));
+
+            default: // anything else
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief reads a MessagePack string
+
+    This function first reads starting bytes to determine the expected
+    string length and then copies this number of bytes into a string.
+
+    @param[out] result  created string
+
+    @return whether string creation completed
+    */
+    bool get_msgpack_string(string_t& result)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string")))
+        {
+            return false;
+        }
+
+        switch (current)
+        {
+            // fixstr
+            case 0xA0:
+            case 0xA1:
+            case 0xA2:
+            case 0xA3:
+            case 0xA4:
+            case 0xA5:
+            case 0xA6:
+            case 0xA7:
+            case 0xA8:
+            case 0xA9:
+            case 0xAA:
+            case 0xAB:
+            case 0xAC:
+            case 0xAD:
+            case 0xAE:
+            case 0xAF:
+            case 0xB0:
+            case 0xB1:
+            case 0xB2:
+            case 0xB3:
+            case 0xB4:
+            case 0xB5:
+            case 0xB6:
+            case 0xB7:
+            case 0xB8:
+            case 0xB9:
+            case 0xBA:
+            case 0xBB:
+            case 0xBC:
+            case 0xBD:
+            case 0xBE:
+            case 0xBF:
+            {
+                return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
+            }
+
+            case 0xD9: // str 8
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+            }
+
+            case 0xDA: // str 16
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+            }
+
+            case 0xDB: // str 32
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
+            }
+
+            default:
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                        exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr));
+            }
+        }
+    }
+
+    /*!
+    @brief reads a MessagePack byte array
+
+    This function first reads starting bytes to determine the expected
+    byte array length and then copies this number of bytes into a byte array.
+
+    @param[out] result  created byte array
+
+    @return whether byte array creation completed
+    */
+    bool get_msgpack_binary(binary_t& result)
+    {
+        // helper function to set the subtype
+        auto assign_and_return_true = [&result](std::int8_t subtype)
+        {
+            result.set_subtype(static_cast<std::uint8_t>(subtype));
+            return true;
+        };
+
+        switch (current)
+        {
+            case 0xC4: // bin 8
+            {
+                std::uint8_t len{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_binary(input_format_t::msgpack, len, result);
+            }
+
+            case 0xC5: // bin 16
+            {
+                std::uint16_t len{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_binary(input_format_t::msgpack, len, result);
+            }
+
+            case 0xC6: // bin 32
+            {
+                std::uint32_t len{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_binary(input_format_t::msgpack, len, result);
+            }
+
+            case 0xC7: // ext 8
+            {
+                std::uint8_t len{};
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, len, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xC8: // ext 16
+            {
+                std::uint16_t len{};
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, len, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xC9: // ext 32
+            {
+                std::uint32_t len{};
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, len) &&
+                       get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, len, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD4: // fixext 1
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 1, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD5: // fixext 2
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 2, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD6: // fixext 4
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 4, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD7: // fixext 8
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 8, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            case 0xD8: // fixext 16
+            {
+                std::int8_t subtype{};
+                return get_number(input_format_t::msgpack, subtype) &&
+                       get_binary(input_format_t::msgpack, 16, result) &&
+                       assign_and_return_true(subtype);
+            }
+
+            default:           // LCOV_EXCL_LINE
+                return false;  // LCOV_EXCL_LINE
+        }
+    }
+
+    /*!
+    @param[in] len  the length of the array
+    @return whether array creation completed
+    */
+    bool get_msgpack_array(const std::size_t len)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
+        {
+            return false;
+        }
+
+        for (std::size_t i = 0; i < len; ++i)
+        {
+            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
+            {
+                return false;
+            }
+        }
+
+        return sax->end_array();
+    }
+
+    /*!
+    @param[in] len  the length of the object
+    @return whether object creation completed
+    */
+    bool get_msgpack_object(const std::size_t len)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
+        {
+            return false;
+        }
+
+        string_t key;
+        for (std::size_t i = 0; i < len; ++i)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
+            {
+                return false;
+            }
+
+            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
+            {
+                return false;
+            }
+            key.clear();
+        }
+
+        return sax->end_object();
+    }
+
+    ////////////
+    // UBJSON //
+    ////////////
+
+    /*!
+    @param[in] get_char  whether a new character should be retrieved from the
+                         input (true, default) or whether the last read
+                         character should be considered instead
+
+    @return whether a valid UBJSON value was passed to the SAX parser
+    */
+    bool parse_ubjson_internal(const bool get_char = true)
+    {
+        return get_ubjson_value(get_char ? get_ignore_noop() : current);
+    }
+
+    /*!
+    @brief reads a UBJSON string
+
+    This function is either called after reading the 'S' byte explicitly
+    indicating a string, or in case of an object key where the 'S' byte can be
+    left out.
+
+    @param[out] result   created string
+    @param[in] get_char  whether a new character should be retrieved from the
+                         input (true, default) or whether the last read
+                         character should be considered instead
+
+    @return whether string creation completed
+    */
+    bool get_ubjson_string(string_t& result, const bool get_char = true)
+    {
+        if (get_char)
+        {
+            get();  // TODO(niels): may we ignore N here?
+        }
+
+        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
+        {
+            return false;
+        }
+
+        switch (current)
+        {
+            case 'U':
+            {
+                std::uint8_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'i':
+            {
+                std::int8_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'I':
+            {
+                std::int16_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'l':
+            {
+                std::int32_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'L':
+            {
+                std::int64_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'u':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint16_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'm':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint32_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            case 'M':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint64_t len{};
+                return get_number(input_format, len) && get_string(input_format, len, result);
+            }
+
+            default:
+                break;
+        }
+        auto last_token = get_token_string();
+        std::string message;
+
+        if (input_format != input_format_t::bjdata)
+        {
+            message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
+        }
+        else
+        {
+            message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
+        }
+        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
+    }
+
+    /*!
+    @param[out] dim  an integer vector storing the ND array dimensions
+    @return whether reading ND array size vector is successful
+    */
+    bool get_ubjson_ndarray_size(std::vector<size_t>& dim)
+    {
+        std::pair<std::size_t, char_int_type> size_and_type;
+        size_t dimlen = 0;
+        bool no_ndarray = true;
+
+        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray)))
+        {
+            return false;
+        }
+
+        if (size_and_type.first != npos)
+        {
+            if (size_and_type.second != 0)
+            {
+                if (size_and_type.second != 'N')
+                {
+                    for (std::size_t i = 0; i < size_and_type.first; ++i)
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second)))
+                        {
+                            return false;
+                        }
+                        dim.push_back(dimlen);
+                    }
+                }
+            }
+            else
+            {
+                for (std::size_t i = 0; i < size_and_type.first; ++i)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray)))
+                    {
+                        return false;
+                    }
+                    dim.push_back(dimlen);
+                }
+            }
+        }
+        else
+        {
+            while (current != ']')
+            {
+                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current)))
+                {
+                    return false;
+                }
+                dim.push_back(dimlen);
+                get_ignore_noop();
+            }
+        }
+        return true;
+    }
+
+    /*!
+    @param[out] result  determined size
+    @param[in,out] is_ndarray  for input, `true` means already inside an ndarray vector
+                               or ndarray dimension is not allowed; `false` means ndarray
+                               is allowed; for output, `true` means an ndarray is found;
+                               is_ndarray can only return `true` when its initial value
+                               is `false`
+    @param[in] prefix  type marker if already read, otherwise set to 0
+
+    @return whether size determination completed
+    */
+    bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0)
+    {
+        if (prefix == 0)
+        {
+            prefix = get_ignore_noop();
+        }
+
+        switch (prefix)
+        {
+            case 'U':
+            {
+                std::uint8_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'i':
+            {
+                std::int8_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (number < 0)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
+                                            exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
+                }
+                result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
+                return true;
+            }
+
+            case 'I':
+            {
+                std::int16_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (number < 0)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
+                                            exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'l':
+            {
+                std::int32_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (number < 0)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
+                                            exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'L':
+            {
+                std::int64_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (number < 0)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
+                                            exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
+                }
+                if (!value_in_range_of<std::size_t>(number))
+                {
+                    return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
+                                            exception_message(input_format, "integer value overflow", "size"), nullptr));
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'u':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint16_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                result = static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'm':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint32_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                result = conditional_static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case 'M':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint64_t number{};
+                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
+                {
+                    return false;
+                }
+                if (!value_in_range_of<std::size_t>(number))
+                {
+                    return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
+                                            exception_message(input_format, "integer value overflow", "size"), nullptr));
+                }
+                result = detail::conditional_static_cast<std::size_t>(number);
+                return true;
+            }
+
+            case '[':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimentional vector is not allowed", "size"), nullptr));
+                }
+                std::vector<size_t> dim;
+                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
+                {
+                    return false;
+                }
+                if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector
+                {
+                    result = dim.at(dim.size() - 1);
+                    return true;
+                }
+                if (!dim.empty())  // if ndarray, convert to an object in JData annotated array format
+                {
+                    for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container
+                    {
+                        if ( i == 0 )
+                        {
+                            result = 0;
+                            return true;
+                        }
+                    }
+
+                    string_t key = "_ArraySize_";
+                    if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size())))
+                    {
+                        return false;
+                    }
+                    result = 1;
+                    for (auto i : dim)
+                    {
+                        result *= i;
+                        if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type()
+                        {
+                            return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
+                        }
+                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(i))))
+                        {
+                            return false;
+                        }
+                    }
+                    is_ndarray = true;
+                    return sax->end_array();
+                }
+                result = 0;
+                return true;
+            }
+
+            default:
+                break;
+        }
+        auto last_token = get_token_string();
+        std::string message;
+
+        if (input_format != input_format_t::bjdata)
+        {
+            message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
+        }
+        else
+        {
+            message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
+        }
+        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
+    }
+
+    /*!
+    @brief determine the type and size for a container
+
+    In the optimized UBJSON format, a type and a size can be provided to allow
+    for a more compact representation.
+
+    @param[out] result  pair of the size and the type
+    @param[in] inside_ndarray  whether the parser is parsing an ND array dimensional vector
+
+    @return whether pair creation completed
+    */
+    bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result, bool inside_ndarray = false)
+    {
+        result.first = npos; // size
+        result.second = 0; // type
+        bool is_ndarray = false;
+
+        get_ignore_noop();
+
+        if (current == '$')
+        {
+            result.second = get();  // must not ignore 'N', because 'N' maybe the type
+            if (input_format == input_format_t::bjdata
+                    && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second)))
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr));
+            }
+
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type")))
+            {
+                return false;
+            }
+
+            get_ignore_noop();
+            if (JSON_HEDLEY_UNLIKELY(current != '#'))
+            {
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
+                {
+                    return false;
+                }
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
+            }
+
+            bool is_error = get_ubjson_size_value(result.first, is_ndarray);
+            if (input_format == input_format_t::bjdata && is_ndarray)
+            {
+                if (inside_ndarray)
+                {
+                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
+                                            exception_message(input_format, "ndarray can not be recursive", "size"), nullptr));
+                }
+                result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
+            }
+            return is_error;
+        }
+
+        if (current == '#')
+        {
+            bool is_error = get_ubjson_size_value(result.first, is_ndarray);
+            if (input_format == input_format_t::bjdata && is_ndarray)
+            {
+                return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
+                                        exception_message(input_format, "ndarray requires both type and size", "size"), nullptr));
+            }
+            return is_error;
+        }
+
+        return true;
+    }
+
+    /*!
+    @param prefix  the previously read or set type prefix
+    @return whether value creation completed
+    */
+    bool get_ubjson_value(const char_int_type prefix)
+    {
+        switch (prefix)
+        {
+            case std::char_traits<char_type>::eof():  // EOF
+                return unexpect_eof(input_format, "value");
+
+            case 'T':  // true
+                return sax->boolean(true);
+            case 'F':  // false
+                return sax->boolean(false);
+
+            case 'Z':  // null
+                return sax->null();
+
+            case 'U':
+            {
+                std::uint8_t number{};
+                return get_number(input_format, number) && sax->number_unsigned(number);
+            }
+
+            case 'i':
+            {
+                std::int8_t number{};
+                return get_number(input_format, number) && sax->number_integer(number);
+            }
+
+            case 'I':
+            {
+                std::int16_t number{};
+                return get_number(input_format, number) && sax->number_integer(number);
+            }
+
+            case 'l':
+            {
+                std::int32_t number{};
+                return get_number(input_format, number) && sax->number_integer(number);
+            }
+
+            case 'L':
+            {
+                std::int64_t number{};
+                return get_number(input_format, number) && sax->number_integer(number);
+            }
+
+            case 'u':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint16_t number{};
+                return get_number(input_format, number) && sax->number_unsigned(number);
+            }
+
+            case 'm':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint32_t number{};
+                return get_number(input_format, number) && sax->number_unsigned(number);
+            }
+
+            case 'M':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                std::uint64_t number{};
+                return get_number(input_format, number) && sax->number_unsigned(number);
+            }
+
+            case 'h':
+            {
+                if (input_format != input_format_t::bjdata)
+                {
+                    break;
+                }
+                const auto byte1_raw = get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
+                {
+                    return false;
+                }
+                const auto byte2_raw = get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
+                {
+                    return false;
+                }
+
+                const auto byte1 = static_cast<unsigned char>(byte1_raw);
+                const auto byte2 = static_cast<unsigned char>(byte2_raw);
+
+                // code from RFC 7049, Appendix D, Figure 3:
+                // As half-precision floating-point numbers were only added
+                // to IEEE 754 in 2008, today's programming platforms often
+                // still only have limited support for them. It is very
+                // easy to include at least decoding support for them even
+                // without such support. An example of a small decoder for
+                // half-precision floating-point numbers in the C language
+                // is shown in Fig. 3.
+                const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1);
+                const double val = [&half]
+                {
+                    const int exp = (half >> 10u) & 0x1Fu;
+                    const unsigned int mant = half & 0x3FFu;
+                    JSON_ASSERT(0 <= exp&& exp <= 32);
+                    JSON_ASSERT(mant <= 1024);
+                    switch (exp)
+                    {
+                        case 0:
+                            return std::ldexp(mant, -24);
+                        case 31:
+                            return (mant == 0)
+                            ? std::numeric_limits<double>::infinity()
+                            : std::numeric_limits<double>::quiet_NaN();
+                        default:
+                            return std::ldexp(mant + 1024, exp - 25);
+                    }
+                }();
+                return sax->number_float((half & 0x8000u) != 0
+                                         ? static_cast<number_float_t>(-val)
+                                         : static_cast<number_float_t>(val), "");
+            }
+
+            case 'd':
+            {
+                float number{};
+                return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 'D':
+            {
+                double number{};
+                return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
+            }
+
+            case 'H':
+            {
+                return get_ubjson_high_precision_number();
+            }
+
+            case 'C':  // char
+            {
+                get();
+                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char")))
+                {
+                    return false;
+                }
+                if (JSON_HEDLEY_UNLIKELY(current > 127))
+                {
+                    auto last_token = get_token_string();
+                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                            exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr));
+                }
+                string_t s(1, static_cast<typename string_t::value_type>(current));
+                return sax->string(s);
+            }
+
+            case 'S':  // string
+            {
+                string_t s;
+                return get_ubjson_string(s) && sax->string(s);
+            }
+
+            case '[':  // array
+                return get_ubjson_array();
+
+            case '{':  // object
+                return get_ubjson_object();
+
+            default: // anything else
+                break;
+        }
+        auto last_token = get_token_string();
+        return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr));
+    }
+
+    /*!
+    @return whether array creation completed
+    */
+    bool get_ubjson_array()
+    {
+        std::pair<std::size_t, char_int_type> size_and_type;
+        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
+        {
+            return false;
+        }
+
+        // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
+        // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
+
+        if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
+        {
+            size_and_type.second &= ~(static_cast<char_int_type>(1) << 8);  // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker
+            auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t)
+            {
+                return p.first < t;
+            });
+            string_t key = "_ArrayType_";
+            if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second))
+            {
+                auto last_token = get_token_string();
+                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                        exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
+            }
+
+            string_t type = it->second; // sax->string() takes a reference
+            if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
+            {
+                return false;
+            }
+
+            if (size_and_type.second == 'C')
+            {
+                size_and_type.second = 'U';
+            }
+
+            key = "_ArrayData_";
+            if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) ))
+            {
+                return false;
+            }
+
+            for (std::size_t i = 0; i < size_and_type.first; ++i)
+            {
+                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
+                {
+                    return false;
+                }
+            }
+
+            return (sax->end_array() && sax->end_object());
+        }
+
+        if (size_and_type.first != npos)
+        {
+            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
+            {
+                return false;
+            }
+
+            if (size_and_type.second != 0)
+            {
+                if (size_and_type.second != 'N')
+                {
+                    for (std::size_t i = 0; i < size_and_type.first; ++i)
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
+                        {
+                            return false;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                for (std::size_t i = 0; i < size_and_type.first; ++i)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+                    {
+                        return false;
+                    }
+                }
+            }
+        }
+        else
+        {
+            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
+            {
+                return false;
+            }
+
+            while (current != ']')
+            {
+                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))
+                {
+                    return false;
+                }
+                get_ignore_noop();
+            }
+        }
+
+        return sax->end_array();
+    }
+
+    /*!
+    @return whether object creation completed
+    */
+    bool get_ubjson_object()
+    {
+        std::pair<std::size_t, char_int_type> size_and_type;
+        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
+        {
+            return false;
+        }
+
+        // do not accept ND-array size in objects in BJData
+        if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
+        {
+            auto last_token = get_token_string();
+            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
+                                    exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr));
+        }
+
+        string_t key;
+        if (size_and_type.first != npos)
+        {
+            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))
+            {
+                return false;
+            }
+
+            if (size_and_type.second != 0)
+            {
+                for (std::size_t i = 0; i < size_and_type.first; ++i)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
+                    {
+                        return false;
+                    }
+                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
+                    {
+                        return false;
+                    }
+                    key.clear();
+                }
+            }
+            else
+            {
+                for (std::size_t i = 0; i < size_and_type.first; ++i)
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
+                    {
+                        return false;
+                    }
+                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+                    {
+                        return false;
+                    }
+                    key.clear();
+                }
+            }
+        }
+        else
+        {
+            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
+            {
+                return false;
+            }
+
+            while (current != '}')
+            {
+                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))
+                {
+                    return false;
+                }
+                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
+                {
+                    return false;
+                }
+                get_ignore_noop();
+                key.clear();
+            }
+        }
+
+        return sax->end_object();
+    }
+
+    // Note, no reader for UBJSON binary types is implemented because they do
+    // not exist
+
+    bool get_ubjson_high_precision_number()
+    {
+        // get size of following number string
+        std::size_t size{};
+        bool no_ndarray = true;
+        auto res = get_ubjson_size_value(size, no_ndarray);
+        if (JSON_HEDLEY_UNLIKELY(!res))
+        {
+            return res;
+        }
+
+        // get number string
+        std::vector<char> number_vector;
+        for (std::size_t i = 0; i < size; ++i)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
+            {
+                return false;
+            }
+            number_vector.push_back(static_cast<char>(current));
+        }
+
+        // parse number string
+        using ia_type = decltype(detail::input_adapter(number_vector));
+        auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false);
+        const auto result_number = number_lexer.scan();
+        const auto number_string = number_lexer.get_token_string();
+        const auto result_remainder = number_lexer.scan();
+
+        using token_type = typename detail::lexer_base<BasicJsonType>::token_type;
+
+        if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
+        {
+            return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
+                                    exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
+        }
+
+        switch (result_number)
+        {
+            case token_type::value_integer:
+                return sax->number_integer(number_lexer.get_number_integer());
+            case token_type::value_unsigned:
+                return sax->number_unsigned(number_lexer.get_number_unsigned());
+            case token_type::value_float:
+                return sax->number_float(number_lexer.get_number_float(), std::move(number_string));
+            case token_type::uninitialized:
+            case token_type::literal_true:
+            case token_type::literal_false:
+            case token_type::literal_null:
+            case token_type::value_string:
+            case token_type::begin_array:
+            case token_type::begin_object:
+            case token_type::end_array:
+            case token_type::end_object:
+            case token_type::name_separator:
+            case token_type::value_separator:
+            case token_type::parse_error:
+            case token_type::end_of_input:
+            case token_type::literal_or_value:
+            default:
+                return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
+                                        exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
+        }
+    }
+
+    ///////////////////////
+    // Utility functions //
+    ///////////////////////
+
+    /*!
+    @brief get next character from the input
+
+    This function provides the interface to the used input adapter. It does
+    not throw in case the input reached EOF, but returns a -'ve valued
+    `std::char_traits<char_type>::eof()` in that case.
+
+    @return character read from the input
+    */
+    char_int_type get()
+    {
+        ++chars_read;
+        return current = ia.get_character();
+    }
+
+    /*!
+    @return character read from the input after ignoring all 'N' entries
+    */
+    char_int_type get_ignore_noop()
+    {
+        do
+        {
+            get();
+        }
+        while (current == 'N');
+
+        return current;
+    }
+
+    /*
+    @brief read a number from the input
+
+    @tparam NumberType the type of the number
+    @param[in] format   the current format (for diagnostics)
+    @param[out] result  number of type @a NumberType
+
+    @return whether conversion completed
+
+    @note This function needs to respect the system's endianness, because
+          bytes in CBOR, MessagePack, and UBJSON are stored in network order
+          (big endian) and therefore need reordering on little endian systems.
+          On the other hand, BSON and BJData use little endian and should reorder
+          on big endian systems.
+    */
+    template<typename NumberType, bool InputIsLittleEndian = false>
+    bool get_number(const input_format_t format, NumberType& result)
+    {
+        // step 1: read input into array with system's byte order
+        std::array<std::uint8_t, sizeof(NumberType)> vec{};
+        for (std::size_t i = 0; i < sizeof(NumberType); ++i)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
+            {
+                return false;
+            }
+
+            // reverse byte order prior to conversion if necessary
+            if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
+            {
+                vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
+            }
+            else
+            {
+                vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
+            }
+        }
+
+        // step 2: convert array into number of type T and return
+        std::memcpy(&result, vec.data(), sizeof(NumberType));
+        return true;
+    }
+
+    /*!
+    @brief create a string by reading characters from the input
+
+    @tparam NumberType the type of the number
+    @param[in] format the current format (for diagnostics)
+    @param[in] len number of characters to read
+    @param[out] result string created by reading @a len bytes
+
+    @return whether string creation completed
+
+    @note We can not reserve @a len bytes for the result, because @a len
+          may be too large. Usually, @ref unexpect_eof() detects the end of
+          the input before we run out of string memory.
+    */
+    template<typename NumberType>
+    bool get_string(const input_format_t format,
+                    const NumberType len,
+                    string_t& result)
+    {
+        bool success = true;
+        for (NumberType i = 0; i < len; i++)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string")))
+            {
+                success = false;
+                break;
+            }
+            result.push_back(static_cast<typename string_t::value_type>(current));
+        }
+        return success;
+    }
+
+    /*!
+    @brief create a byte array by reading bytes from the input
+
+    @tparam NumberType the type of the number
+    @param[in] format the current format (for diagnostics)
+    @param[in] len number of bytes to read
+    @param[out] result byte array created by reading @a len bytes
+
+    @return whether byte array creation completed
+
+    @note We can not reserve @a len bytes for the result, because @a len
+          may be too large. Usually, @ref unexpect_eof() detects the end of
+          the input before we run out of memory.
+    */
+    template<typename NumberType>
+    bool get_binary(const input_format_t format,
+                    const NumberType len,
+                    binary_t& result)
+    {
+        bool success = true;
+        for (NumberType i = 0; i < len; i++)
+        {
+            get();
+            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary")))
+            {
+                success = false;
+                break;
+            }
+            result.push_back(static_cast<std::uint8_t>(current));
+        }
+        return success;
+    }
+
+    /*!
+    @param[in] format   the current format (for diagnostics)
+    @param[in] context  further context information (for diagnostics)
+    @return whether the last read character is not EOF
+    */
+    JSON_HEDLEY_NON_NULL(3)
+    bool unexpect_eof(const input_format_t format, const char* context) const
+    {
+        if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))
+        {
+            return sax->parse_error(chars_read, "<end of file>",
+                                    parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
+        }
+        return true;
+    }
+
+    /*!
+    @return a string representation of the last read byte
+    */
+    std::string get_token_string() const
+    {
+        std::array<char, 3> cr{{}};
+        static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+        return std::string{cr.data()};
+    }
+
+    /*!
+    @param[in] format   the current format
+    @param[in] detail   a detailed error message
+    @param[in] context  further context information
+    @return a message string to use in the parse_error exceptions
+    */
+    std::string exception_message(const input_format_t format,
+                                  const std::string& detail,
+                                  const std::string& context) const
+    {
+        std::string error_msg = "syntax error while parsing ";
+
+        switch (format)
+        {
+            case input_format_t::cbor:
+                error_msg += "CBOR";
+                break;
+
+            case input_format_t::msgpack:
+                error_msg += "MessagePack";
+                break;
+
+            case input_format_t::ubjson:
+                error_msg += "UBJSON";
+                break;
+
+            case input_format_t::bson:
+                error_msg += "BSON";
+                break;
+
+            case input_format_t::bjdata:
+                error_msg += "BJData";
+                break;
+
+            case input_format_t::json: // LCOV_EXCL_LINE
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+
+        return concat(error_msg, ' ', context, ": ", detail);
+    }
+
+  private:
+    static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast<std::size_t>(-1);
+
+    /// input adapter
+    InputAdapterType ia;
+
+    /// the current character
+    char_int_type current = std::char_traits<char_type>::eof();
+
+    /// the number of characters read
+    std::size_t chars_read = 0;
+
+    /// whether we can assume little endianness
+    const bool is_little_endian = little_endianness();
+
+    /// input format
+    const input_format_t input_format = input_format_t::json;
+
+    /// the SAX parser
+    json_sax_t* sax = nullptr;
+
+    // excluded markers in bjdata optimized type
+#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \
+    make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{')
+
+#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \
+    make_array<bjd_type>(                      \
+    bjd_type{'C', "char"},                     \
+    bjd_type{'D', "double"},                   \
+    bjd_type{'I', "int16"},                    \
+    bjd_type{'L', "int64"},                    \
+    bjd_type{'M', "uint64"},                   \
+    bjd_type{'U', "uint8"},                    \
+    bjd_type{'d', "single"},                   \
+    bjd_type{'i', "int8"},                     \
+    bjd_type{'l', "int32"},                    \
+    bjd_type{'m', "uint32"},                   \
+    bjd_type{'u', "uint16"})
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    // lookup tables
+    // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
+    const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers =
+        JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_;
+
+    using bjd_type = std::pair<char_int_type, string_t>;
+    // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
+    const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map =
+        JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_;
+
+#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_
+#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_
+};
+
+#ifndef JSON_HAS_CPP_17
+    template<typename BasicJsonType, typename InputAdapterType, typename SAX>
+    constexpr std::size_t binary_reader<BasicJsonType, InputAdapterType, SAX>::npos;
+#endif
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/input/input_adapters.hpp>
+
+// #include <nlohmann/detail/input/lexer.hpp>
+
+// #include <nlohmann/detail/input/parser.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cmath> // isfinite
+#include <cstdint> // uint8_t
+#include <functional> // function
+#include <string> // string
+#include <utility> // move
+#include <vector> // vector
+
+// #include <nlohmann/detail/exceptions.hpp>
+
+// #include <nlohmann/detail/input/input_adapters.hpp>
+
+// #include <nlohmann/detail/input/json_sax.hpp>
+
+// #include <nlohmann/detail/input/lexer.hpp>
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/is_sax.hpp>
+
+// #include <nlohmann/detail/string_concat.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+////////////
+// parser //
+////////////
+
+enum class parse_event_t : std::uint8_t
+{
+    /// the parser read `{` and started to process a JSON object
+    object_start,
+    /// the parser read `}` and finished processing a JSON object
+    object_end,
+    /// the parser read `[` and started to process a JSON array
+    array_start,
+    /// the parser read `]` and finished processing a JSON array
+    array_end,
+    /// the parser read a key of a value in an object
+    key,
+    /// the parser finished reading a JSON value
+    value
+};
+
+template<typename BasicJsonType>
+using parser_callback_t =
+    std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;
+
+/*!
+@brief syntax analysis
+
+This class implements a recursive descent parser.
+*/
+template<typename BasicJsonType, typename InputAdapterType>
+class parser
+{
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using string_t = typename BasicJsonType::string_t;
+    using lexer_t = lexer<BasicJsonType, InputAdapterType>;
+    using token_type = typename lexer_t::token_type;
+
+  public:
+    /// a parser reading from an input adapter
+    explicit parser(InputAdapterType&& adapter,
+                    const parser_callback_t<BasicJsonType> cb = nullptr,
+                    const bool allow_exceptions_ = true,
+                    const bool skip_comments = false)
+        : callback(cb)
+        , m_lexer(std::move(adapter), skip_comments)
+        , allow_exceptions(allow_exceptions_)
+    {
+        // read first token
+        get_token();
+    }
+
+    /*!
+    @brief public parser interface
+
+    @param[in] strict      whether to expect the last token to be EOF
+    @param[in,out] result  parsed JSON value
+
+    @throw parse_error.101 in case of an unexpected token
+    @throw parse_error.102 if to_unicode fails or surrogate error
+    @throw parse_error.103 if to_unicode fails
+    */
+    void parse(const bool strict, BasicJsonType& result)
+    {
+        if (callback)
+        {
+            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
+            sax_parse_internal(&sdp);
+
+            // in strict mode, input must be completely read
+            if (strict && (get_token() != token_type::end_of_input))
+            {
+                sdp.parse_error(m_lexer.get_position(),
+                                m_lexer.get_token_string(),
+                                parse_error::create(101, m_lexer.get_position(),
+                                                    exception_message(token_type::end_of_input, "value"), nullptr));
+            }
+
+            // in case of an error, return discarded value
+            if (sdp.is_errored())
+            {
+                result = value_t::discarded;
+                return;
+            }
+
+            // set top-level value to null if it was discarded by the callback
+            // function
+            if (result.is_discarded())
+            {
+                result = nullptr;
+            }
+        }
+        else
+        {
+            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
+            sax_parse_internal(&sdp);
+
+            // in strict mode, input must be completely read
+            if (strict && (get_token() != token_type::end_of_input))
+            {
+                sdp.parse_error(m_lexer.get_position(),
+                                m_lexer.get_token_string(),
+                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
+            }
+
+            // in case of an error, return discarded value
+            if (sdp.is_errored())
+            {
+                result = value_t::discarded;
+                return;
+            }
+        }
+
+        result.assert_invariant();
+    }
+
+    /*!
+    @brief public accept interface
+
+    @param[in] strict  whether to expect the last token to be EOF
+    @return whether the input is a proper JSON text
+    */
+    bool accept(const bool strict = true)
+    {
+        json_sax_acceptor<BasicJsonType> sax_acceptor;
+        return sax_parse(&sax_acceptor, strict);
+    }
+
+    template<typename SAX>
+    JSON_HEDLEY_NON_NULL(2)
+    bool sax_parse(SAX* sax, const bool strict = true)
+    {
+        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
+        const bool result = sax_parse_internal(sax);
+
+        // strict mode: next byte must be EOF
+        if (result && strict && (get_token() != token_type::end_of_input))
+        {
+            return sax->parse_error(m_lexer.get_position(),
+                                    m_lexer.get_token_string(),
+                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
+        }
+
+        return result;
+    }
+
+  private:
+    template<typename SAX>
+    JSON_HEDLEY_NON_NULL(2)
+    bool sax_parse_internal(SAX* sax)
+    {
+        // stack to remember the hierarchy of structured values we are parsing
+        // true = array; false = object
+        std::vector<bool> states;
+        // value to avoid a goto (see comment where set to true)
+        bool skip_to_state_evaluation = false;
+
+        while (true)
+        {
+            if (!skip_to_state_evaluation)
+            {
+                // invariant: get_token() was called before each iteration
+                switch (last_token)
+                {
+                    case token_type::begin_object:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
+                        {
+                            return false;
+                        }
+
+                        // closing } -> we are done
+                        if (get_token() == token_type::end_object)
+                        {
+                            if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
+                            {
+                                return false;
+                            }
+                            break;
+                        }
+
+                        // parse key
+                        if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
+                        {
+                            return sax->parse_error(m_lexer.get_position(),
+                                                    m_lexer.get_token_string(),
+                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
+                        }
+                        if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
+                        {
+                            return false;
+                        }
+
+                        // parse separator (:)
+                        if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
+                        {
+                            return sax->parse_error(m_lexer.get_position(),
+                                                    m_lexer.get_token_string(),
+                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
+                        }
+
+                        // remember we are now inside an object
+                        states.push_back(false);
+
+                        // parse values
+                        get_token();
+                        continue;
+                    }
+
+                    case token_type::begin_array:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
+                        {
+                            return false;
+                        }
+
+                        // closing ] -> we are done
+                        if (get_token() == token_type::end_array)
+                        {
+                            if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
+                            {
+                                return false;
+                            }
+                            break;
+                        }
+
+                        // remember we are now inside an array
+                        states.push_back(true);
+
+                        // parse values (no need to call get_token)
+                        continue;
+                    }
+
+                    case token_type::value_float:
+                    {
+                        const auto res = m_lexer.get_number_float();
+
+                        if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))
+                        {
+                            return sax->parse_error(m_lexer.get_position(),
+                                                    m_lexer.get_token_string(),
+                                                    out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr));
+                        }
+
+                        if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
+                        {
+                            return false;
+                        }
+
+                        break;
+                    }
+
+                    case token_type::literal_false:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::literal_null:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->null()))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::literal_true:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::value_integer:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::value_string:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::value_unsigned:
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+
+                    case token_type::parse_error:
+                    {
+                        // using "uninitialized" to avoid "expected" message
+                        return sax->parse_error(m_lexer.get_position(),
+                                                m_lexer.get_token_string(),
+                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
+                    }
+
+                    case token_type::uninitialized:
+                    case token_type::end_array:
+                    case token_type::end_object:
+                    case token_type::name_separator:
+                    case token_type::value_separator:
+                    case token_type::end_of_input:
+                    case token_type::literal_or_value:
+                    default: // the last token was unexpected
+                    {
+                        return sax->parse_error(m_lexer.get_position(),
+                                                m_lexer.get_token_string(),
+                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
+                    }
+                }
+            }
+            else
+            {
+                skip_to_state_evaluation = false;
+            }
+
+            // we reached this line after we successfully parsed a value
+            if (states.empty())
+            {
+                // empty stack: we reached the end of the hierarchy: done
+                return true;
+            }
+
+            if (states.back())  // array
+            {
+                // comma -> next value
+                if (get_token() == token_type::value_separator)
+                {
+                    // parse a new value
+                    get_token();
+                    continue;
+                }
+
+                // closing ]
+                if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
+                {
+                    if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
+                    {
+                        return false;
+                    }
+
+                    // We are done with this array. Before we can parse a
+                    // new value, we need to evaluate the new state first.
+                    // By setting skip_to_state_evaluation to false, we
+                    // are effectively jumping to the beginning of this if.
+                    JSON_ASSERT(!states.empty());
+                    states.pop_back();
+                    skip_to_state_evaluation = true;
+                    continue;
+                }
+
+                return sax->parse_error(m_lexer.get_position(),
+                                        m_lexer.get_token_string(),
+                                        parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr));
+            }
+
+            // states.back() is false -> object
+
+            // comma -> next value
+            if (get_token() == token_type::value_separator)
+            {
+                // parse key
+                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
+                {
+                    return sax->parse_error(m_lexer.get_position(),
+                                            m_lexer.get_token_string(),
+                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
+                }
+
+                if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
+                {
+                    return false;
+                }
+
+                // parse separator (:)
+                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
+                {
+                    return sax->parse_error(m_lexer.get_position(),
+                                            m_lexer.get_token_string(),
+                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
+                }
+
+                // parse values
+                get_token();
+                continue;
+            }
+
+            // closing }
+            if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
+            {
+                if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
+                {
+                    return false;
+                }
+
+                // We are done with this object. Before we can parse a
+                // new value, we need to evaluate the new state first.
+                // By setting skip_to_state_evaluation to false, we
+                // are effectively jumping to the beginning of this if.
+                JSON_ASSERT(!states.empty());
+                states.pop_back();
+                skip_to_state_evaluation = true;
+                continue;
+            }
+
+            return sax->parse_error(m_lexer.get_position(),
+                                    m_lexer.get_token_string(),
+                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr));
+        }
+    }
+
+    /// get next token from lexer
+    token_type get_token()
+    {
+        return last_token = m_lexer.scan();
+    }
+
+    std::string exception_message(const token_type expected, const std::string& context)
+    {
+        std::string error_msg = "syntax error ";
+
+        if (!context.empty())
+        {
+            error_msg += concat("while parsing ", context, ' ');
+        }
+
+        error_msg += "- ";
+
+        if (last_token == token_type::parse_error)
+        {
+            error_msg += concat(m_lexer.get_error_message(), "; last read: '",
+                                m_lexer.get_token_string(), '\'');
+        }
+        else
+        {
+            error_msg += concat("unexpected ", lexer_t::token_type_name(last_token));
+        }
+
+        if (expected != token_type::uninitialized)
+        {
+            error_msg += concat("; expected ", lexer_t::token_type_name(expected));
+        }
+
+        return error_msg;
+    }
+
+  private:
+    /// callback function
+    const parser_callback_t<BasicJsonType> callback = nullptr;
+    /// the type of the last read token
+    token_type last_token = token_type::uninitialized;
+    /// the lexer
+    lexer_t m_lexer;
+    /// whether to throw exceptions in case of errors
+    const bool allow_exceptions = true;
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/iterators/internal_iterator.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstddef> // ptrdiff_t
+#include <limits>  // numeric_limits
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*
+@brief an iterator for primitive JSON types
+
+This class models an iterator for primitive JSON types (boolean, number,
+string). It's only purpose is to allow the iterator/const_iterator classes
+to "iterate" over primitive values. Internally, the iterator is modeled by
+a `difference_type` variable. Value begin_value (`0`) models the begin,
+end_value (`1`) models past the end.
+*/
+class primitive_iterator_t
+{
+  private:
+    using difference_type = std::ptrdiff_t;
+    static constexpr difference_type begin_value = 0;
+    static constexpr difference_type end_value = begin_value + 1;
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    /// iterator as signed integer type
+    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
+
+  public:
+    constexpr difference_type get_value() const noexcept
+    {
+        return m_it;
+    }
+
+    /// set iterator to a defined beginning
+    void set_begin() noexcept
+    {
+        m_it = begin_value;
+    }
+
+    /// set iterator to a defined past the end
+    void set_end() noexcept
+    {
+        m_it = end_value;
+    }
+
+    /// return whether the iterator can be dereferenced
+    constexpr bool is_begin() const noexcept
+    {
+        return m_it == begin_value;
+    }
+
+    /// return whether the iterator is at end
+    constexpr bool is_end() const noexcept
+    {
+        return m_it == end_value;
+    }
+
+    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+    {
+        return lhs.m_it == rhs.m_it;
+    }
+
+    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+    {
+        return lhs.m_it < rhs.m_it;
+    }
+
+    primitive_iterator_t operator+(difference_type n) noexcept
+    {
+        auto result = *this;
+        result += n;
+        return result;
+    }
+
+    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
+    {
+        return lhs.m_it - rhs.m_it;
+    }
+
+    primitive_iterator_t& operator++() noexcept
+    {
+        ++m_it;
+        return *this;
+    }
+
+    primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp)
+    {
+        auto result = *this;
+        ++m_it;
+        return result;
+    }
+
+    primitive_iterator_t& operator--() noexcept
+    {
+        --m_it;
+        return *this;
+    }
+
+    primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp)
+    {
+        auto result = *this;
+        --m_it;
+        return result;
+    }
+
+    primitive_iterator_t& operator+=(difference_type n) noexcept
+    {
+        m_it += n;
+        return *this;
+    }
+
+    primitive_iterator_t& operator-=(difference_type n) noexcept
+    {
+        m_it -= n;
+        return *this;
+    }
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*!
+@brief an iterator value
+
+@note This structure could easily be a union, but MSVC currently does not allow
+unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
+*/
+template<typename BasicJsonType> struct internal_iterator
+{
+    /// iterator for JSON objects
+    typename BasicJsonType::object_t::iterator object_iterator {};
+    /// iterator for JSON arrays
+    typename BasicJsonType::array_t::iterator array_iterator {};
+    /// generic iterator for all other types
+    primitive_iterator_t primitive_iterator {};
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/iterators/iter_impl.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
+#include <type_traits> // conditional, is_const, remove_const
+
+// #include <nlohmann/detail/exceptions.hpp>
+
+// #include <nlohmann/detail/iterators/internal_iterator.hpp>
+
+// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+// forward declare, to be able to friend it later on
+template<typename IteratorType> class iteration_proxy;
+template<typename IteratorType> class iteration_proxy_value;
+
+/*!
+@brief a template for a bidirectional iterator for the @ref basic_json class
+This class implements a both iterators (iterator and const_iterator) for the
+@ref basic_json class.
+@note An iterator is called *initialized* when a pointer to a JSON value has
+      been set (e.g., by a constructor or a copy assignment). If the iterator is
+      default-constructed, it is *uninitialized* and most methods are undefined.
+      **The library uses assertions to detect calls on uninitialized iterators.**
+@requirement The class satisfies the following concept requirements:
+-
+[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
+  The iterator that can be moved can be moved in both directions (i.e.
+  incremented and decremented).
+@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
+       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
+*/
+template<typename BasicJsonType>
+class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
+{
+    /// the iterator with BasicJsonType of different const-ness
+    using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
+    /// allow basic_json to access private members
+    friend other_iter_impl;
+    friend BasicJsonType;
+    friend iteration_proxy<iter_impl>;
+    friend iteration_proxy_value<iter_impl>;
+
+    using object_t = typename BasicJsonType::object_t;
+    using array_t = typename BasicJsonType::array_t;
+    // make sure BasicJsonType is basic_json or const basic_json
+    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
+                  "iter_impl only accepts (const) basic_json");
+    // superficial check for the LegacyBidirectionalIterator named requirement
+    static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
+                  &&  std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
+                  "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
+
+  public:
+    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
+    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
+    /// A user-defined iterator should provide publicly accessible typedefs named
+    /// iterator_category, value_type, difference_type, pointer, and reference.
+    /// Note that value_type is required to be non-const, even for constant iterators.
+    using iterator_category = std::bidirectional_iterator_tag;
+
+    /// the type of the values when the iterator is dereferenced
+    using value_type = typename BasicJsonType::value_type;
+    /// a type to represent differences between iterators
+    using difference_type = typename BasicJsonType::difference_type;
+    /// defines a pointer to the type iterated over (value_type)
+    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
+          typename BasicJsonType::const_pointer,
+          typename BasicJsonType::pointer>::type;
+    /// defines a reference to the type iterated over (value_type)
+    using reference =
+        typename std::conditional<std::is_const<BasicJsonType>::value,
+        typename BasicJsonType::const_reference,
+        typename BasicJsonType::reference>::type;
+
+    iter_impl() = default;
+    ~iter_impl() = default;
+    iter_impl(iter_impl&&) noexcept = default;
+    iter_impl& operator=(iter_impl&&) noexcept = default;
+
+    /*!
+    @brief constructor for a given JSON instance
+    @param[in] object  pointer to a JSON object for this iterator
+    @pre object != nullptr
+    @post The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    explicit iter_impl(pointer object) noexcept : m_object(object)
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                m_it.object_iterator = typename object_t::iterator();
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_it.array_iterator = typename array_t::iterator();
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                m_it.primitive_iterator = primitive_iterator_t();
+                break;
+            }
+        }
+    }
+
+    /*!
+    @note The conventional copy constructor and copy assignment are implicitly
+          defined. Combined with the following converting constructor and
+          assignment, they support: (1) copy from iterator to iterator, (2)
+          copy from const iterator to const iterator, and (3) conversion from
+          iterator to const iterator. However conversion from const iterator
+          to iterator is not defined.
+    */
+
+    /*!
+    @brief const copy constructor
+    @param[in] other const iterator to copy from
+    @note This copy constructor had to be defined explicitly to circumvent a bug
+          occurring on msvc v19.0 compiler (VS 2015) debug build. For more
+          information refer to: https://github.com/nlohmann/json/issues/1608
+    */
+    iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
+        : m_object(other.m_object), m_it(other.m_it)
+    {}
+
+    /*!
+    @brief converting assignment
+    @param[in] other const iterator to copy from
+    @return const/non-const iterator
+    @note It is not checked whether @a other is initialized.
+    */
+    iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept
+    {
+        if (&other != this)
+        {
+            m_object = other.m_object;
+            m_it = other.m_it;
+        }
+        return *this;
+    }
+
+    /*!
+    @brief converting constructor
+    @param[in] other  non-const iterator to copy from
+    @note It is not checked whether @a other is initialized.
+    */
+    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
+        : m_object(other.m_object), m_it(other.m_it)
+    {}
+
+    /*!
+    @brief converting assignment
+    @param[in] other  non-const iterator to copy from
+    @return const/non-const iterator
+    @note It is not checked whether @a other is initialized.
+    */
+    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)
+    {
+        m_object = other.m_object;
+        m_it = other.m_it;
+        return *this;
+    }
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    /*!
+    @brief set the iterator to the first value
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    void set_begin() noexcept
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                m_it.object_iterator = m_object->m_value.object->begin();
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_it.array_iterator = m_object->m_value.array->begin();
+                break;
+            }
+
+            case value_t::null:
+            {
+                // set to end so begin()==end() is true: null is empty
+                m_it.primitive_iterator.set_end();
+                break;
+            }
+
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                m_it.primitive_iterator.set_begin();
+                break;
+            }
+        }
+    }
+
+    /*!
+    @brief set the iterator past the last value
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    void set_end() noexcept
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                m_it.object_iterator = m_object->m_value.object->end();
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_it.array_iterator = m_object->m_value.array->end();
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                m_it.primitive_iterator.set_end();
+                break;
+            }
+        }
+    }
+
+  public:
+    /*!
+    @brief return a reference to the value pointed to by the iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    reference operator*() const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
+                return m_it.object_iterator->second;
+            }
+
+            case value_t::array:
+            {
+                JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
+                return *m_it.array_iterator;
+            }
+
+            case value_t::null:
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
+                {
+                    return *m_object;
+                }
+
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+            }
+        }
+    }
+
+    /*!
+    @brief dereference the iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    pointer operator->() const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
+                return &(m_it.object_iterator->second);
+            }
+
+            case value_t::array:
+            {
+                JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
+                return &*m_it.array_iterator;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
+                {
+                    return m_object;
+                }
+
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+            }
+        }
+    }
+
+    /*!
+    @brief post-increment (it++)
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        auto result = *this;
+        ++(*this);
+        return result;
+    }
+
+    /*!
+    @brief pre-increment (++it)
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl& operator++()
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                std::advance(m_it.object_iterator, 1);
+                break;
+            }
+
+            case value_t::array:
+            {
+                std::advance(m_it.array_iterator, 1);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                ++m_it.primitive_iterator;
+                break;
+            }
+        }
+
+        return *this;
+    }
+
+    /*!
+    @brief post-decrement (it--)
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        auto result = *this;
+        --(*this);
+        return result;
+    }
+
+    /*!
+    @brief pre-decrement (--it)
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl& operator--()
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+            {
+                std::advance(m_it.object_iterator, -1);
+                break;
+            }
+
+            case value_t::array:
+            {
+                std::advance(m_it.array_iterator, -1);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                --m_it.primitive_iterator;
+                break;
+            }
+        }
+
+        return *this;
+    }
+
+    /*!
+    @brief comparison: equal
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
+    bool operator==(const IterImpl& other) const
+    {
+        // if objects are not the same, the comparison is undefined
+        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
+        }
+
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                return (m_it.object_iterator == other.m_it.object_iterator);
+
+            case value_t::array:
+                return (m_it.array_iterator == other.m_it.array_iterator);
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                return (m_it.primitive_iterator == other.m_it.primitive_iterator);
+        }
+    }
+
+    /*!
+    @brief comparison: not equal
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
+    bool operator!=(const IterImpl& other) const
+    {
+        return !operator==(other);
+    }
+
+    /*!
+    @brief comparison: smaller
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    bool operator<(const iter_impl& other) const
+    {
+        // if objects are not the same, the comparison is undefined
+        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
+        }
+
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
+
+            case value_t::array:
+                return (m_it.array_iterator < other.m_it.array_iterator);
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                return (m_it.primitive_iterator < other.m_it.primitive_iterator);
+        }
+    }
+
+    /*!
+    @brief comparison: less than or equal
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    bool operator<=(const iter_impl& other) const
+    {
+        return !other.operator < (*this);
+    }
+
+    /*!
+    @brief comparison: greater than
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    bool operator>(const iter_impl& other) const
+    {
+        return !operator<=(other);
+    }
+
+    /*!
+    @brief comparison: greater than or equal
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    bool operator>=(const iter_impl& other) const
+    {
+        return !operator<(other);
+    }
+
+    /*!
+    @brief add to iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl& operator+=(difference_type i)
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
+
+            case value_t::array:
+            {
+                std::advance(m_it.array_iterator, i);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                m_it.primitive_iterator += i;
+                break;
+            }
+        }
+
+        return *this;
+    }
+
+    /*!
+    @brief subtract from iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl& operator-=(difference_type i)
+    {
+        return operator+=(-i);
+    }
+
+    /*!
+    @brief add to iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl operator+(difference_type i) const
+    {
+        auto result = *this;
+        result += i;
+        return result;
+    }
+
+    /*!
+    @brief addition of distance and iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    friend iter_impl operator+(difference_type i, const iter_impl& it)
+    {
+        auto result = it;
+        result += i;
+        return result;
+    }
+
+    /*!
+    @brief subtract from iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    iter_impl operator-(difference_type i) const
+    {
+        auto result = *this;
+        result -= i;
+        return result;
+    }
+
+    /*!
+    @brief return difference
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    difference_type operator-(const iter_impl& other) const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
+
+            case value_t::array:
+                return m_it.array_iterator - other.m_it.array_iterator;
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                return m_it.primitive_iterator - other.m_it.primitive_iterator;
+        }
+    }
+
+    /*!
+    @brief access to successor
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    reference operator[](difference_type n) const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        switch (m_object->m_type)
+        {
+            case value_t::object:
+                JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
+
+            case value_t::array:
+                return *std::next(m_it.array_iterator, n);
+
+            case value_t::null:
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
+                {
+                    return *m_object;
+                }
+
+                JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
+            }
+        }
+    }
+
+    /*!
+    @brief return the key of an object iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    const typename object_t::key_type& key() const
+    {
+        JSON_ASSERT(m_object != nullptr);
+
+        if (JSON_HEDLEY_LIKELY(m_object->is_object()))
+        {
+            return m_it.object_iterator->first;
+        }
+
+        JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object));
+    }
+
+    /*!
+    @brief return the value of an iterator
+    @pre The iterator is initialized; i.e. `m_object != nullptr`.
+    */
+    reference value() const
+    {
+        return operator*();
+    }
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    /// associated JSON instance
+    pointer m_object = nullptr;
+    /// the actual iterator of the associated instance
+    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
+
+// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <cstddef> // ptrdiff_t
+#include <iterator> // reverse_iterator
+#include <utility> // declval
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+//////////////////////
+// reverse_iterator //
+//////////////////////
+
+/*!
+@brief a template for a reverse iterator class
+
+@tparam Base the base iterator type to reverse. Valid types are @ref
+iterator (to create @ref reverse_iterator) and @ref const_iterator (to
+create @ref const_reverse_iterator).
+
+@requirement The class satisfies the following concept requirements:
+-
+[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
+  The iterator that can be moved can be moved in both directions (i.e.
+  incremented and decremented).
+- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
+  It is possible to write to the pointed-to element (only if @a Base is
+  @ref iterator).
+
+@since version 1.0.0
+*/
+template<typename Base>
+class json_reverse_iterator : public std::reverse_iterator<Base>
+{
+  public:
+    using difference_type = std::ptrdiff_t;
+    /// shortcut to the reverse iterator adapter
+    using base_iterator = std::reverse_iterator<Base>;
+    /// the reference type for the pointed-to element
+    using reference = typename Base::reference;
+
+    /// create reverse iterator from iterator
+    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
+        : base_iterator(it) {}
+
+    /// create reverse iterator from base class
+    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
+
+    /// post-increment (it++)
+    json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
+    }
+
+    /// pre-increment (++it)
+    json_reverse_iterator& operator++()
+    {
+        return static_cast<json_reverse_iterator&>(base_iterator::operator++());
+    }
+
+    /// post-decrement (it--)
+    json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp)
+    {
+        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
+    }
+
+    /// pre-decrement (--it)
+    json_reverse_iterator& operator--()
+    {
+        return static_cast<json_reverse_iterator&>(base_iterator::operator--());
+    }
+
+    /// add to iterator
+    json_reverse_iterator& operator+=(difference_type i)
+    {
+        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
+    }
+
+    /// add to iterator
+    json_reverse_iterator operator+(difference_type i) const
+    {
+        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
+    }
+
+    /// subtract from iterator
+    json_reverse_iterator operator-(difference_type i) const
+    {
+        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
+    }
+
+    /// return difference
+    difference_type operator-(const json_reverse_iterator& other) const
+    {
+        return base_iterator(*this) - base_iterator(other);
+    }
+
+    /// access to successor
+    reference operator[](difference_type n) const
+    {
+        return *(this->operator+(n));
+    }
+
+    /// return the key of an object iterator
+    auto key() const -> decltype(std::declval<Base>().key())
+    {
+        auto it = --this->base();
+        return it.key();
+    }
+
+    /// return the value of an iterator
+    reference value() const
+    {
+        auto it = --this->base();
+        return it.operator * ();
+    }
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
+
+// #include <nlohmann/detail/json_pointer.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <algorithm> // all_of
+#include <cctype> // isdigit
+#include <cerrno> // errno, ERANGE
+#include <cstdlib> // strtoull
+#ifndef JSON_NO_IO
+    #include <iosfwd> // ostream
+#endif  // JSON_NO_IO
+#include <limits> // max
+#include <numeric> // accumulate
+#include <string> // string
+#include <utility> // move
+#include <vector> // vector
+
+// #include <nlohmann/detail/exceptions.hpp>
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/string_concat.hpp>
+
+// #include <nlohmann/detail/string_escape.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
+/// @sa https://json.nlohmann.me/api/json_pointer/
+template<typename RefStringType>
+class json_pointer
+{
+    // allow basic_json to access private members
+    NLOHMANN_BASIC_JSON_TPL_DECLARATION
+    friend class basic_json;
+
+    template<typename>
+    friend class json_pointer;
+
+    template<typename T>
+    struct string_t_helper
+    {
+        using type = T;
+    };
+
+    NLOHMANN_BASIC_JSON_TPL_DECLARATION
+    struct string_t_helper<NLOHMANN_BASIC_JSON_TPL>
+    {
+        using type = StringType;
+    };
+
+  public:
+    // for backwards compatibility accept BasicJsonType
+    using string_t = typename string_t_helper<RefStringType>::type;
+
+    /// @brief create JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/
+    explicit json_pointer(const string_t& s = "")
+        : reference_tokens(split(s))
+    {}
+
+    /// @brief return a string representation of the JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/to_string/
+    string_t to_string() const
+    {
+        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
+                               string_t{},
+                               [](const string_t& a, const string_t& b)
+        {
+            return detail::concat(a, '/', detail::escape(b));
+        });
+    }
+
+    /// @brief return a string representation of the JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
+    operator string_t() const
+    {
+        return to_string();
+    }
+
+#ifndef JSON_NO_IO
+    /// @brief write string representation of the JSON pointer to stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+    friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
+    {
+        o << ptr.to_string();
+        return o;
+    }
+#endif
+
+    /// @brief append another JSON pointer at the end of this JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
+    json_pointer& operator/=(const json_pointer& ptr)
+    {
+        reference_tokens.insert(reference_tokens.end(),
+                                ptr.reference_tokens.begin(),
+                                ptr.reference_tokens.end());
+        return *this;
+    }
+
+    /// @brief append an unescaped reference token at the end of this JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
+    json_pointer& operator/=(string_t token)
+    {
+        push_back(std::move(token));
+        return *this;
+    }
+
+    /// @brief append an array index at the end of this JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
+    json_pointer& operator/=(std::size_t array_idx)
+    {
+        return *this /= std::to_string(array_idx);
+    }
+
+    /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
+    friend json_pointer operator/(const json_pointer& lhs,
+                                  const json_pointer& rhs)
+    {
+        return json_pointer(lhs) /= rhs;
+    }
+
+    /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
+    friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)
+    {
+        return json_pointer(lhs) /= std::move(token);
+    }
+
+    /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
+    friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)
+    {
+        return json_pointer(lhs) /= array_idx;
+    }
+
+    /// @brief returns the parent of this JSON pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/
+    json_pointer parent_pointer() const
+    {
+        if (empty())
+        {
+            return *this;
+        }
+
+        json_pointer res = *this;
+        res.pop_back();
+        return res;
+    }
+
+    /// @brief remove last reference token
+    /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/
+    void pop_back()
+    {
+        if (JSON_HEDLEY_UNLIKELY(empty()))
+        {
+            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
+        }
+
+        reference_tokens.pop_back();
+    }
+
+    /// @brief return last reference token
+    /// @sa https://json.nlohmann.me/api/json_pointer/back/
+    const string_t& back() const
+    {
+        if (JSON_HEDLEY_UNLIKELY(empty()))
+        {
+            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
+        }
+
+        return reference_tokens.back();
+    }
+
+    /// @brief append an unescaped token at the end of the reference pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
+    void push_back(const string_t& token)
+    {
+        reference_tokens.push_back(token);
+    }
+
+    /// @brief append an unescaped token at the end of the reference pointer
+    /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
+    void push_back(string_t&& token)
+    {
+        reference_tokens.push_back(std::move(token));
+    }
+
+    /// @brief return whether pointer points to the root document
+    /// @sa https://json.nlohmann.me/api/json_pointer/empty/
+    bool empty() const noexcept
+    {
+        return reference_tokens.empty();
+    }
+
+  private:
+    /*!
+    @param[in] s  reference token to be converted into an array index
+
+    @return integer representation of @a s
+
+    @throw parse_error.106  if an array index begins with '0'
+    @throw parse_error.109  if an array index begins not with a digit
+    @throw out_of_range.404 if string @a s could not be converted to an integer
+    @throw out_of_range.410 if an array index exceeds size_type
+    */
+    template<typename BasicJsonType>
+    static typename BasicJsonType::size_type array_index(const string_t& s)
+    {
+        using size_type = typename BasicJsonType::size_type;
+
+        // error condition (cf. RFC 6901, Sect. 4)
+        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
+        {
+            JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
+        }
+
+        // error condition (cf. RFC 6901, Sect. 4)
+        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
+        {
+            JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
+        }
+
+        const char* p = s.c_str();
+        char* p_end = nullptr;
+        errno = 0; // strtoull doesn't reset errno
+        unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
+        if (p == p_end // invalid input or empty string
+                || errno == ERANGE // out of range
+                || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
+        {
+            JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
+        }
+
+        // only triggered on special platforms (like 32bit), see also
+        // https://github.com/nlohmann/json/pull/2203
+        if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))  // NOLINT(runtime/int)
+        {
+            JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr));   // LCOV_EXCL_LINE
+        }
+
+        return static_cast<size_type>(res);
+    }
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    json_pointer top() const
+    {
+        if (JSON_HEDLEY_UNLIKELY(empty()))
+        {
+            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
+        }
+
+        json_pointer result = *this;
+        result.reference_tokens = {reference_tokens[0]};
+        return result;
+    }
+
+  private:
+    /*!
+    @brief create and return a reference to the pointed to value
+
+    @complexity Linear in the number of reference tokens.
+
+    @throw parse_error.109 if array index is not a number
+    @throw type_error.313 if value cannot be unflattened
+    */
+    template<typename BasicJsonType>
+    BasicJsonType& get_and_create(BasicJsonType& j) const
+    {
+        auto* result = &j;
+
+        // in case no reference tokens exist, return a reference to the JSON value
+        // j which will be overwritten by a primitive value
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (result->type())
+            {
+                case detail::value_t::null:
+                {
+                    if (reference_token == "0")
+                    {
+                        // start a new array if reference token is 0
+                        result = &result->operator[](0);
+                    }
+                    else
+                    {
+                        // start a new object otherwise
+                        result = &result->operator[](reference_token);
+                    }
+                    break;
+                }
+
+                case detail::value_t::object:
+                {
+                    // create an entry in the object
+                    result = &result->operator[](reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    // create an entry in the array
+                    result = &result->operator[](array_index<BasicJsonType>(reference_token));
+                    break;
+                }
+
+                /*
+                The following code is only reached if there exists a reference
+                token _and_ the current value is primitive. In this case, we have
+                an error situation, because primitive values may only occur as
+                single value; that is, with an empty list of reference tokens.
+                */
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
+            }
+        }
+
+        return *result;
+    }
+
+    /*!
+    @brief return a reference to the pointed to value
+
+    @note This version does not throw if a value is not present, but tries to
+          create nested values instead. For instance, calling this function
+          with pointer `"/this/that"` on a null value is equivalent to calling
+          `operator[]("this").operator[]("that")` on that value, effectively
+          changing the null value to an object.
+
+    @param[in] ptr  a JSON value
+
+    @return reference to the JSON value pointed to by the JSON pointer
+
+    @complexity Linear in the length of the JSON pointer.
+
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    @throw out_of_range.404  if the JSON pointer can not be resolved
+    */
+    template<typename BasicJsonType>
+    BasicJsonType& get_unchecked(BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            // convert null values to arrays or objects before continuing
+            if (ptr->is_null())
+            {
+                // check if reference token is a number
+                const bool nums =
+                    std::all_of(reference_token.begin(), reference_token.end(),
+                                [](const unsigned char x)
+                {
+                    return std::isdigit(x);
+                });
+
+                // change value to array for numbers or "-" or to object otherwise
+                *ptr = (nums || reference_token == "-")
+                       ? detail::value_t::array
+                       : detail::value_t::object;
+            }
+
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    // use unchecked object access
+                    ptr = &ptr->operator[](reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (reference_token == "-")
+                    {
+                        // explicitly treat "-" as index beyond the end
+                        ptr = &ptr->operator[](ptr->m_value.array->size());
+                    }
+                    else
+                    {
+                        // convert array index to number; unchecked access
+                        ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
+                    }
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
+            }
+        }
+
+        return *ptr;
+    }
+
+    /*!
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    @throw out_of_range.402  if the array index '-' is used
+    @throw out_of_range.404  if the JSON pointer can not be resolved
+    */
+    template<typename BasicJsonType>
+    BasicJsonType& get_checked(BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    // note: at performs range check
+                    ptr = &ptr->at(reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
+                    {
+                        // "-" always fails the range check
+                        JSON_THROW(detail::out_of_range::create(402, detail::concat(
+                                "array index '-' (", std::to_string(ptr->m_value.array->size()),
+                                ") is out of range"), ptr));
+                    }
+
+                    // note: at performs range check
+                    ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
+            }
+        }
+
+        return *ptr;
+    }
+
+    /*!
+    @brief return a const reference to the pointed to value
+
+    @param[in] ptr  a JSON value
+
+    @return const reference to the JSON value pointed to by the JSON
+    pointer
+
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    @throw out_of_range.402  if the array index '-' is used
+    @throw out_of_range.404  if the JSON pointer can not be resolved
+    */
+    template<typename BasicJsonType>
+    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    // use unchecked object access
+                    ptr = &ptr->operator[](reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
+                    {
+                        // "-" cannot be used for const access
+                        JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_value.array->size()), ") is out of range"), ptr));
+                    }
+
+                    // use unchecked array access
+                    ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
+            }
+        }
+
+        return *ptr;
+    }
+
+    /*!
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    @throw out_of_range.402  if the array index '-' is used
+    @throw out_of_range.404  if the JSON pointer can not be resolved
+    */
+    template<typename BasicJsonType>
+    const BasicJsonType& get_checked(const BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    // note: at performs range check
+                    ptr = &ptr->at(reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
+                    {
+                        // "-" always fails the range check
+                        JSON_THROW(detail::out_of_range::create(402, detail::concat(
+                                "array index '-' (", std::to_string(ptr->m_value.array->size()),
+                                ") is out of range"), ptr));
+                    }
+
+                    // note: at performs range check
+                    ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                    JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
+            }
+        }
+
+        return *ptr;
+    }
+
+    /*!
+    @throw parse_error.106   if an array index begins with '0'
+    @throw parse_error.109   if an array index was not a number
+    */
+    template<typename BasicJsonType>
+    bool contains(const BasicJsonType* ptr) const
+    {
+        for (const auto& reference_token : reference_tokens)
+        {
+            switch (ptr->type())
+            {
+                case detail::value_t::object:
+                {
+                    if (!ptr->contains(reference_token))
+                    {
+                        // we did not find the key in the object
+                        return false;
+                    }
+
+                    ptr = &ptr->operator[](reference_token);
+                    break;
+                }
+
+                case detail::value_t::array:
+                {
+                    if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
+                    {
+                        // "-" always fails the range check
+                        return false;
+                    }
+                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
+                    {
+                        // invalid char
+                        return false;
+                    }
+                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
+                    {
+                        if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
+                        {
+                            // first char should be between '1' and '9'
+                            return false;
+                        }
+                        for (std::size_t i = 1; i < reference_token.size(); i++)
+                        {
+                            if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
+                            {
+                                // other char should be between '0' and '9'
+                                return false;
+                            }
+                        }
+                    }
+
+                    const auto idx = array_index<BasicJsonType>(reference_token);
+                    if (idx >= ptr->size())
+                    {
+                        // index out of range
+                        return false;
+                    }
+
+                    ptr = &ptr->operator[](idx);
+                    break;
+                }
+
+                case detail::value_t::null:
+                case detail::value_t::string:
+                case detail::value_t::boolean:
+                case detail::value_t::number_integer:
+                case detail::value_t::number_unsigned:
+                case detail::value_t::number_float:
+                case detail::value_t::binary:
+                case detail::value_t::discarded:
+                default:
+                {
+                    // we do not expect primitive values if there is still a
+                    // reference token to process
+                    return false;
+                }
+            }
+        }
+
+        // no reference token left means we found a primitive value
+        return true;
+    }
+
+    /*!
+    @brief split the string input to reference tokens
+
+    @note This function is only called by the json_pointer constructor.
+          All exceptions below are documented there.
+
+    @throw parse_error.107  if the pointer is not empty or begins with '/'
+    @throw parse_error.108  if character '~' is not followed by '0' or '1'
+    */
+    static std::vector<string_t> split(const string_t& reference_string)
+    {
+        std::vector<string_t> result;
+
+        // special case: empty reference string -> no reference tokens
+        if (reference_string.empty())
+        {
+            return result;
+        }
+
+        // check if nonempty reference string begins with slash
+        if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
+        {
+            JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
+        }
+
+        // extract the reference tokens:
+        // - slash: position of the last read slash (or end of string)
+        // - start: position after the previous slash
+        for (
+            // search for the first slash after the first character
+            std::size_t slash = reference_string.find_first_of('/', 1),
+            // set the beginning of the first reference token
+            start = 1;
+            // we can stop if start == 0 (if slash == string_t::npos)
+            start != 0;
+            // set the beginning of the next reference token
+            // (will eventually be 0 if slash == string_t::npos)
+            start = (slash == string_t::npos) ? 0 : slash + 1,
+            // find next slash
+            slash = reference_string.find_first_of('/', start))
+        {
+            // use the text between the beginning of the reference token
+            // (start) and the last slash (slash).
+            auto reference_token = reference_string.substr(start, slash - start);
+
+            // check reference tokens are properly escaped
+            for (std::size_t pos = reference_token.find_first_of('~');
+                    pos != string_t::npos;
+                    pos = reference_token.find_first_of('~', pos + 1))
+            {
+                JSON_ASSERT(reference_token[pos] == '~');
+
+                // ~ must be followed by 0 or 1
+                if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
+                                         (reference_token[pos + 1] != '0' &&
+                                          reference_token[pos + 1] != '1')))
+                {
+                    JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
+                }
+            }
+
+            // finally, store the reference token
+            detail::unescape(reference_token);
+            result.push_back(reference_token);
+        }
+
+        return result;
+    }
+
+  private:
+    /*!
+    @param[in] reference_string  the reference string to the current value
+    @param[in] value             the value to consider
+    @param[in,out] result        the result object to insert values to
+
+    @note Empty objects or arrays are flattened to `null`.
+    */
+    template<typename BasicJsonType>
+    static void flatten(const string_t& reference_string,
+                        const BasicJsonType& value,
+                        BasicJsonType& result)
+    {
+        switch (value.type())
+        {
+            case detail::value_t::array:
+            {
+                if (value.m_value.array->empty())
+                {
+                    // flatten empty array as null
+                    result[reference_string] = nullptr;
+                }
+                else
+                {
+                    // iterate array and use index as reference string
+                    for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
+                    {
+                        flatten(detail::concat(reference_string, '/', std::to_string(i)),
+                                value.m_value.array->operator[](i), result);
+                    }
+                }
+                break;
+            }
+
+            case detail::value_t::object:
+            {
+                if (value.m_value.object->empty())
+                {
+                    // flatten empty object as null
+                    result[reference_string] = nullptr;
+                }
+                else
+                {
+                    // iterate object and use keys as reference string
+                    for (const auto& element : *value.m_value.object)
+                    {
+                        flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
+                    }
+                }
+                break;
+            }
+
+            case detail::value_t::null:
+            case detail::value_t::string:
+            case detail::value_t::boolean:
+            case detail::value_t::number_integer:
+            case detail::value_t::number_unsigned:
+            case detail::value_t::number_float:
+            case detail::value_t::binary:
+            case detail::value_t::discarded:
+            default:
+            {
+                // add primitive value with its reference string
+                result[reference_string] = value;
+                break;
+            }
+        }
+    }
+
+    /*!
+    @param[in] value  flattened JSON
+
+    @return unflattened JSON
+
+    @throw parse_error.109 if array index is not a number
+    @throw type_error.314  if value is not an object
+    @throw type_error.315  if object values are not primitive
+    @throw type_error.313  if value cannot be unflattened
+    */
+    template<typename BasicJsonType>
+    static BasicJsonType
+    unflatten(const BasicJsonType& value)
+    {
+        if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
+        {
+            JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
+        }
+
+        BasicJsonType result;
+
+        // iterate the JSON object values
+        for (const auto& element : *value.m_value.object)
+        {
+            if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
+            {
+                JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
+            }
+
+            // assign value to reference pointed to by JSON pointer; Note that if
+            // the JSON pointer is "" (i.e., points to the whole value), function
+            // get_and_create returns a reference to result itself. An assignment
+            // will then create a primitive value.
+            json_pointer(element.first).get_and_create(result) = element.second;
+        }
+
+        return result;
+    }
+
+    // can't use conversion operator because of ambiguity
+    json_pointer<string_t> convert() const&
+    {
+        json_pointer<string_t> result;
+        result.reference_tokens = reference_tokens;
+        return result;
+    }
+
+    json_pointer<string_t> convert()&&
+    {
+        json_pointer<string_t> result;
+        result.reference_tokens = std::move(reference_tokens);
+        return result;
+    }
+
+  public:
+#if JSON_HAS_THREE_WAY_COMPARISON
+    /// @brief compares two JSON pointers for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    template<typename RefStringTypeRhs>
+    bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
+    {
+        return reference_tokens == rhs.reference_tokens;
+    }
+
+    /// @brief compares JSON pointer and string for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
+    bool operator==(const string_t& rhs) const
+    {
+        return *this == json_pointer(rhs);
+    }
+
+    /// @brief 3-way compares two JSON pointers
+    template<typename RefStringTypeRhs>
+    std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
+    {
+        return  reference_tokens <=> rhs.reference_tokens; // *NOPAD*
+    }
+#else
+    /// @brief compares two JSON pointers for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
+                           const json_pointer<RefStringTypeRhs>& rhs) noexcept;
+
+    /// @brief compares JSON pointer and string for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    template<typename RefStringTypeLhs, typename StringType>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
+                           const StringType& rhs);
+
+    /// @brief compares string and JSON pointer for equality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
+    template<typename RefStringTypeRhs, typename StringType>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator==(const StringType& lhs,
+                           const json_pointer<RefStringTypeRhs>& rhs);
+
+    /// @brief compares two JSON pointers for inequality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
+    template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
+                           const json_pointer<RefStringTypeRhs>& rhs) noexcept;
+
+    /// @brief compares JSON pointer and string for inequality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
+    template<typename RefStringTypeLhs, typename StringType>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
+                           const StringType& rhs);
+
+    /// @brief compares string and JSON pointer for inequality
+    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
+    template<typename RefStringTypeRhs, typename StringType>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator!=(const StringType& lhs,
+                           const json_pointer<RefStringTypeRhs>& rhs);
+
+    /// @brief compares two JSON pointer for less-than
+    template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+    // NOLINTNEXTLINE(readability-redundant-declaration)
+    friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
+                          const json_pointer<RefStringTypeRhs>& rhs) noexcept;
+#endif
+
+  private:
+    /// the reference tokens
+    std::vector<string_t> reference_tokens;
+};
+
+#if !JSON_HAS_THREE_WAY_COMPARISON
+// functions cannot be defined inside class due to ODR violations
+template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
+                       const json_pointer<RefStringTypeRhs>& rhs) noexcept
+{
+    return lhs.reference_tokens == rhs.reference_tokens;
+}
+
+template<typename RefStringTypeLhs,
+         typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
+JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
+inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
+                       const StringType& rhs)
+{
+    return lhs == json_pointer<RefStringTypeLhs>(rhs);
+}
+
+template<typename RefStringTypeRhs,
+         typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
+JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
+inline bool operator==(const StringType& lhs,
+                       const json_pointer<RefStringTypeRhs>& rhs)
+{
+    return json_pointer<RefStringTypeRhs>(lhs) == rhs;
+}
+
+template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
+                       const json_pointer<RefStringTypeRhs>& rhs) noexcept
+{
+    return !(lhs == rhs);
+}
+
+template<typename RefStringTypeLhs,
+         typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
+JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
+inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
+                       const StringType& rhs)
+{
+    return !(lhs == rhs);
+}
+
+template<typename RefStringTypeRhs,
+         typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
+JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
+inline bool operator!=(const StringType& lhs,
+                       const json_pointer<RefStringTypeRhs>& rhs)
+{
+    return !(lhs == rhs);
+}
+
+template<typename RefStringTypeLhs, typename RefStringTypeRhs>
+inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
+                      const json_pointer<RefStringTypeRhs>& rhs) noexcept
+{
+    return lhs.reference_tokens < rhs.reference_tokens;
+}
+#endif
+
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/json_ref.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <initializer_list>
+#include <utility>
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+template<typename BasicJsonType>
+class json_ref
+{
+  public:
+    using value_type = BasicJsonType;
+
+    json_ref(value_type&& value)
+        : owned_value(std::move(value))
+    {}
+
+    json_ref(const value_type& value)
+        : value_ref(&value)
+    {}
+
+    json_ref(std::initializer_list<json_ref> init)
+        : owned_value(init)
+    {}
+
+    template <
+        class... Args,
+        enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
+    json_ref(Args && ... args)
+        : owned_value(std::forward<Args>(args)...)
+    {}
+
+    // class should be movable only
+    json_ref(json_ref&&) noexcept = default;
+    json_ref(const json_ref&) = delete;
+    json_ref& operator=(const json_ref&) = delete;
+    json_ref& operator=(json_ref&&) = delete;
+    ~json_ref() = default;
+
+    value_type moved_or_copied() const
+    {
+        if (value_ref == nullptr)
+        {
+            return std::move(owned_value);
+        }
+        return *value_ref;
+    }
+
+    value_type const& operator*() const
+    {
+        return value_ref ? *value_ref : owned_value;
+    }
+
+    value_type const* operator->() const
+    {
+        return &** this;
+    }
+
+  private:
+    mutable value_type owned_value = nullptr;
+    value_type const* value_ref = nullptr;
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/string_concat.hpp>
+
+// #include <nlohmann/detail/string_escape.hpp>
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+// #include <nlohmann/detail/output/binary_writer.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <algorithm> // reverse
+#include <array> // array
+#include <map> // map
+#include <cmath> // isnan, isinf
+#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
+#include <cstring> // memcpy
+#include <limits> // numeric_limits
+#include <string> // string
+#include <utility> // move
+#include <vector> // vector
+
+// #include <nlohmann/detail/input/binary_reader.hpp>
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/output/output_adapters.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <algorithm> // copy
+#include <cstddef> // size_t
+#include <iterator> // back_inserter
+#include <memory> // shared_ptr, make_shared
+#include <string> // basic_string
+#include <vector> // vector
+
+#ifndef JSON_NO_IO
+    #include <ios>      // streamsize
+    #include <ostream>  // basic_ostream
+#endif  // JSON_NO_IO
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/// abstract output adapter interface
+template<typename CharType> struct output_adapter_protocol
+{
+    virtual void write_character(CharType c) = 0;
+    virtual void write_characters(const CharType* s, std::size_t length) = 0;
+    virtual ~output_adapter_protocol() = default;
+
+    output_adapter_protocol() = default;
+    output_adapter_protocol(const output_adapter_protocol&) = default;
+    output_adapter_protocol(output_adapter_protocol&&) noexcept = default;
+    output_adapter_protocol& operator=(const output_adapter_protocol&) = default;
+    output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default;
+};
+
+/// a type to simplify interfaces
+template<typename CharType>
+using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
+
+/// output adapter for byte vectors
+template<typename CharType, typename AllocatorType = std::allocator<CharType>>
+class output_vector_adapter : public output_adapter_protocol<CharType>
+{
+  public:
+    explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept
+        : v(vec)
+    {}
+
+    void write_character(CharType c) override
+    {
+        v.push_back(c);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    void write_characters(const CharType* s, std::size_t length) override
+    {
+        v.insert(v.end(), s, s + length);
+    }
+
+  private:
+    std::vector<CharType, AllocatorType>& v;
+};
+
+#ifndef JSON_NO_IO
+/// output adapter for output streams
+template<typename CharType>
+class output_stream_adapter : public output_adapter_protocol<CharType>
+{
+  public:
+    explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
+        : stream(s)
+    {}
+
+    void write_character(CharType c) override
+    {
+        stream.put(c);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    void write_characters(const CharType* s, std::size_t length) override
+    {
+        stream.write(s, static_cast<std::streamsize>(length));
+    }
+
+  private:
+    std::basic_ostream<CharType>& stream;
+};
+#endif  // JSON_NO_IO
+
+/// output adapter for basic_string
+template<typename CharType, typename StringType = std::basic_string<CharType>>
+class output_string_adapter : public output_adapter_protocol<CharType>
+{
+  public:
+    explicit output_string_adapter(StringType& s) noexcept
+        : str(s)
+    {}
+
+    void write_character(CharType c) override
+    {
+        str.push_back(c);
+    }
+
+    JSON_HEDLEY_NON_NULL(2)
+    void write_characters(const CharType* s, std::size_t length) override
+    {
+        str.append(s, length);
+    }
+
+  private:
+    StringType& str;
+};
+
+template<typename CharType, typename StringType = std::basic_string<CharType>>
+class output_adapter
+{
+  public:
+    template<typename AllocatorType = std::allocator<CharType>>
+    output_adapter(std::vector<CharType, AllocatorType>& vec)
+        : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {}
+
+#ifndef JSON_NO_IO
+    output_adapter(std::basic_ostream<CharType>& s)
+        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
+#endif  // JSON_NO_IO
+
+    output_adapter(StringType& s)
+        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
+
+    operator output_adapter_t<CharType>()
+    {
+        return oa;
+    }
+
+  private:
+    output_adapter_t<CharType> oa = nullptr;
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/string_concat.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////////////
+// binary writer //
+///////////////////
+
+/*!
+@brief serialization to CBOR and MessagePack values
+*/
+template<typename BasicJsonType, typename CharType>
+class binary_writer
+{
+    using string_t = typename BasicJsonType::string_t;
+    using binary_t = typename BasicJsonType::binary_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+
+  public:
+    /*!
+    @brief create a binary writer
+
+    @param[in] adapter  output adapter to write to
+    */
+    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter))
+    {
+        JSON_ASSERT(oa);
+    }
+
+    /*!
+    @param[in] j  JSON value to serialize
+    @pre       j.type() == value_t::object
+    */
+    void write_bson(const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            case value_t::object:
+            {
+                write_bson_object(*j.m_value.object);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::array:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
+            }
+        }
+    }
+
+    /*!
+    @param[in] j  JSON value to serialize
+    */
+    void write_cbor(const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            case value_t::null:
+            {
+                oa->write_character(to_char_type(0xF6));
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                oa->write_character(j.m_value.boolean
+                                    ? to_char_type(0xF5)
+                                    : to_char_type(0xF4));
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                if (j.m_value.number_integer >= 0)
+                {
+                    // CBOR does not differentiate between positive signed
+                    // integers and unsigned integers. Therefore, we used the
+                    // code from the value_t::number_unsigned case here.
+                    if (j.m_value.number_integer <= 0x17)
+                    {
+                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x18));
+                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x19));
+                        write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x1A));
+                        write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+                    }
+                    else
+                    {
+                        oa->write_character(to_char_type(0x1B));
+                        write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+                    }
+                }
+                else
+                {
+                    // The conversions below encode the sign in the first
+                    // byte, and the value is converted to a positive number.
+                    const auto positive_number = -1 - j.m_value.number_integer;
+                    if (j.m_value.number_integer >= -24)
+                    {
+                        write_number(static_cast<std::uint8_t>(0x20 + positive_number));
+                    }
+                    else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x38));
+                        write_number(static_cast<std::uint8_t>(positive_number));
+                    }
+                    else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x39));
+                        write_number(static_cast<std::uint16_t>(positive_number));
+                    }
+                    else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
+                    {
+                        oa->write_character(to_char_type(0x3A));
+                        write_number(static_cast<std::uint32_t>(positive_number));
+                    }
+                    else
+                    {
+                        oa->write_character(to_char_type(0x3B));
+                        write_number(static_cast<std::uint64_t>(positive_number));
+                    }
+                }
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                if (j.m_value.number_unsigned <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x18));
+                    write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x19));
+                    write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x1A));
+                    write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
+                }
+                else
+                {
+                    oa->write_character(to_char_type(0x1B));
+                    write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
+                }
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                if (std::isnan(j.m_value.number_float))
+                {
+                    // NaN is 0xf97e00 in CBOR
+                    oa->write_character(to_char_type(0xF9));
+                    oa->write_character(to_char_type(0x7E));
+                    oa->write_character(to_char_type(0x00));
+                }
+                else if (std::isinf(j.m_value.number_float))
+                {
+                    // Infinity is 0xf97c00, -Infinity is 0xf9fc00
+                    oa->write_character(to_char_type(0xf9));
+                    oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
+                    oa->write_character(to_char_type(0x00));
+                }
+                else
+                {
+                    write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);
+                }
+                break;
+            }
+
+            case value_t::string:
+            {
+                // step 1: write control byte and the string length
+                const auto N = j.m_value.string->size();
+                if (N <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(0x60 + N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x78));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x79));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x7A));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+                // LCOV_EXCL_START
+                else if (N <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x7B));
+                    write_number(static_cast<std::uint64_t>(N));
+                }
+                // LCOV_EXCL_STOP
+
+                // step 2: write the string
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
+                    j.m_value.string->size());
+                break;
+            }
+
+            case value_t::array:
+            {
+                // step 1: write control byte and the array size
+                const auto N = j.m_value.array->size();
+                if (N <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(0x80 + N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x98));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x99));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x9A));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+                // LCOV_EXCL_START
+                else if (N <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x9B));
+                    write_number(static_cast<std::uint64_t>(N));
+                }
+                // LCOV_EXCL_STOP
+
+                // step 2: write each element
+                for (const auto& el : *j.m_value.array)
+                {
+                    write_cbor(el);
+                }
+                break;
+            }
+
+            case value_t::binary:
+            {
+                if (j.m_value.binary->has_subtype())
+                {
+                    if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())
+                    {
+                        write_number(static_cast<std::uint8_t>(0xd8));
+                        write_number(static_cast<std::uint8_t>(j.m_value.binary->subtype()));
+                    }
+                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())
+                    {
+                        write_number(static_cast<std::uint8_t>(0xd9));
+                        write_number(static_cast<std::uint16_t>(j.m_value.binary->subtype()));
+                    }
+                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())
+                    {
+                        write_number(static_cast<std::uint8_t>(0xda));
+                        write_number(static_cast<std::uint32_t>(j.m_value.binary->subtype()));
+                    }
+                    else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
+                    {
+                        write_number(static_cast<std::uint8_t>(0xdb));
+                        write_number(static_cast<std::uint64_t>(j.m_value.binary->subtype()));
+                    }
+                }
+
+                // step 1: write control byte and the binary array size
+                const auto N = j.m_value.binary->size();
+                if (N <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(0x40 + N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x58));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x59));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x5A));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+                // LCOV_EXCL_START
+                else if (N <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    oa->write_character(to_char_type(0x5B));
+                    write_number(static_cast<std::uint64_t>(N));
+                }
+                // LCOV_EXCL_STOP
+
+                // step 2: write each element
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.binary->data()),
+                    N);
+
+                break;
+            }
+
+            case value_t::object:
+            {
+                // step 1: write control byte and the object size
+                const auto N = j.m_value.object->size();
+                if (N <= 0x17)
+                {
+                    write_number(static_cast<std::uint8_t>(0xA0 + N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    oa->write_character(to_char_type(0xB8));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    oa->write_character(to_char_type(0xB9));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    oa->write_character(to_char_type(0xBA));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+                // LCOV_EXCL_START
+                else if (N <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    oa->write_character(to_char_type(0xBB));
+                    write_number(static_cast<std::uint64_t>(N));
+                }
+                // LCOV_EXCL_STOP
+
+                // step 2: write each element
+                for (const auto& el : *j.m_value.object)
+                {
+                    write_cbor(el.first);
+                    write_cbor(el.second);
+                }
+                break;
+            }
+
+            case value_t::discarded:
+            default:
+                break;
+        }
+    }
+
+    /*!
+    @param[in] j  JSON value to serialize
+    */
+    void write_msgpack(const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            case value_t::null: // nil
+            {
+                oa->write_character(to_char_type(0xC0));
+                break;
+            }
+
+            case value_t::boolean: // true and false
+            {
+                oa->write_character(j.m_value.boolean
+                                    ? to_char_type(0xC3)
+                                    : to_char_type(0xC2));
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                if (j.m_value.number_integer >= 0)
+                {
+                    // MessagePack does not differentiate between positive
+                    // signed integers and unsigned integers. Therefore, we used
+                    // the code from the value_t::number_unsigned case here.
+                    if (j.m_value.number_unsigned < 128)
+                    {
+                        // positive fixnum
+                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+                    {
+                        // uint 8
+                        oa->write_character(to_char_type(0xCC));
+                        write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+                    {
+                        // uint 16
+                        oa->write_character(to_char_type(0xCD));
+                        write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+                    {
+                        // uint 32
+                        oa->write_character(to_char_type(0xCE));
+                        write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+                    {
+                        // uint 64
+                        oa->write_character(to_char_type(0xCF));
+                        write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+                    }
+                }
+                else
+                {
+                    if (j.m_value.number_integer >= -32)
+                    {
+                        // negative fixnum
+                        write_number(static_cast<std::int8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
+                             j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
+                    {
+                        // int 8
+                        oa->write_character(to_char_type(0xD0));
+                        write_number(static_cast<std::int8_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
+                             j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
+                    {
+                        // int 16
+                        oa->write_character(to_char_type(0xD1));
+                        write_number(static_cast<std::int16_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
+                             j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
+                    {
+                        // int 32
+                        oa->write_character(to_char_type(0xD2));
+                        write_number(static_cast<std::int32_t>(j.m_value.number_integer));
+                    }
+                    else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
+                             j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
+                    {
+                        // int 64
+                        oa->write_character(to_char_type(0xD3));
+                        write_number(static_cast<std::int64_t>(j.m_value.number_integer));
+                    }
+                }
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                if (j.m_value.number_unsigned < 128)
+                {
+                    // positive fixnum
+                    write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    // uint 8
+                    oa->write_character(to_char_type(0xCC));
+                    write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    // uint 16
+                    oa->write_character(to_char_type(0xCD));
+                    write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    // uint 32
+                    oa->write_character(to_char_type(0xCE));
+                    write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+                }
+                else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    // uint 64
+                    oa->write_character(to_char_type(0xCF));
+                    write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+                }
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);
+                break;
+            }
+
+            case value_t::string:
+            {
+                // step 1: write control byte and the string length
+                const auto N = j.m_value.string->size();
+                if (N <= 31)
+                {
+                    // fixstr
+                    write_number(static_cast<std::uint8_t>(0xA0 | N));
+                }
+                else if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    // str 8
+                    oa->write_character(to_char_type(0xD9));
+                    write_number(static_cast<std::uint8_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    // str 16
+                    oa->write_character(to_char_type(0xDA));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    // str 32
+                    oa->write_character(to_char_type(0xDB));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+
+                // step 2: write the string
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
+                    j.m_value.string->size());
+                break;
+            }
+
+            case value_t::array:
+            {
+                // step 1: write control byte and the array size
+                const auto N = j.m_value.array->size();
+                if (N <= 15)
+                {
+                    // fixarray
+                    write_number(static_cast<std::uint8_t>(0x90 | N));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    // array 16
+                    oa->write_character(to_char_type(0xDC));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    // array 32
+                    oa->write_character(to_char_type(0xDD));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+
+                // step 2: write each element
+                for (const auto& el : *j.m_value.array)
+                {
+                    write_msgpack(el);
+                }
+                break;
+            }
+
+            case value_t::binary:
+            {
+                // step 0: determine if the binary type has a set subtype to
+                // determine whether or not to use the ext or fixext types
+                const bool use_ext = j.m_value.binary->has_subtype();
+
+                // step 1: write control byte and the byte string length
+                const auto N = j.m_value.binary->size();
+                if (N <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    std::uint8_t output_type{};
+                    bool fixed = true;
+                    if (use_ext)
+                    {
+                        switch (N)
+                        {
+                            case 1:
+                                output_type = 0xD4; // fixext 1
+                                break;
+                            case 2:
+                                output_type = 0xD5; // fixext 2
+                                break;
+                            case 4:
+                                output_type = 0xD6; // fixext 4
+                                break;
+                            case 8:
+                                output_type = 0xD7; // fixext 8
+                                break;
+                            case 16:
+                                output_type = 0xD8; // fixext 16
+                                break;
+                            default:
+                                output_type = 0xC7; // ext 8
+                                fixed = false;
+                                break;
+                        }
+
+                    }
+                    else
+                    {
+                        output_type = 0xC4; // bin 8
+                        fixed = false;
+                    }
+
+                    oa->write_character(to_char_type(output_type));
+                    if (!fixed)
+                    {
+                        write_number(static_cast<std::uint8_t>(N));
+                    }
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    std::uint8_t output_type = use_ext
+                                               ? 0xC8 // ext 16
+                                               : 0xC5; // bin 16
+
+                    oa->write_character(to_char_type(output_type));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    std::uint8_t output_type = use_ext
+                                               ? 0xC9 // ext 32
+                                               : 0xC6; // bin 32
+
+                    oa->write_character(to_char_type(output_type));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+
+                // step 1.5: if this is an ext type, write the subtype
+                if (use_ext)
+                {
+                    write_number(static_cast<std::int8_t>(j.m_value.binary->subtype()));
+                }
+
+                // step 2: write the byte string
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.binary->data()),
+                    N);
+
+                break;
+            }
+
+            case value_t::object:
+            {
+                // step 1: write control byte and the object size
+                const auto N = j.m_value.object->size();
+                if (N <= 15)
+                {
+                    // fixmap
+                    write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
+                }
+                else if (N <= (std::numeric_limits<std::uint16_t>::max)())
+                {
+                    // map 16
+                    oa->write_character(to_char_type(0xDE));
+                    write_number(static_cast<std::uint16_t>(N));
+                }
+                else if (N <= (std::numeric_limits<std::uint32_t>::max)())
+                {
+                    // map 32
+                    oa->write_character(to_char_type(0xDF));
+                    write_number(static_cast<std::uint32_t>(N));
+                }
+
+                // step 2: write each element
+                for (const auto& el : *j.m_value.object)
+                {
+                    write_msgpack(el.first);
+                    write_msgpack(el.second);
+                }
+                break;
+            }
+
+            case value_t::discarded:
+            default:
+                break;
+        }
+    }
+
+    /*!
+    @param[in] j  JSON value to serialize
+    @param[in] use_count   whether to use '#' prefixes (optimized format)
+    @param[in] use_type    whether to use '$' prefixes (optimized format)
+    @param[in] add_prefix  whether prefixes need to be used for this value
+    @param[in] use_bjdata  whether write in BJData format, default is false
+    */
+    void write_ubjson(const BasicJsonType& j, const bool use_count,
+                      const bool use_type, const bool add_prefix = true,
+                      const bool use_bjdata = false)
+    {
+        switch (j.type())
+        {
+            case value_t::null:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('Z'));
+                }
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(j.m_value.boolean
+                                        ? to_char_type('T')
+                                        : to_char_type('F'));
+                }
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix, use_bjdata);
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix, use_bjdata);
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix, use_bjdata);
+                break;
+            }
+
+            case value_t::string:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('S'));
+                }
+                write_number_with_ubjson_prefix(j.m_value.string->size(), true, use_bjdata);
+                oa->write_characters(
+                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
+                    j.m_value.string->size());
+                break;
+            }
+
+            case value_t::array:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('['));
+                }
+
+                bool prefix_required = true;
+                if (use_type && !j.m_value.array->empty())
+                {
+                    JSON_ASSERT(use_count);
+                    const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
+                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
+                                                         [this, first_prefix, use_bjdata](const BasicJsonType & v)
+                    {
+                        return ubjson_prefix(v, use_bjdata) == first_prefix;
+                    });
+
+                    std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
+
+                    if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
+                    {
+                        prefix_required = false;
+                        oa->write_character(to_char_type('$'));
+                        oa->write_character(first_prefix);
+                    }
+                }
+
+                if (use_count)
+                {
+                    oa->write_character(to_char_type('#'));
+                    write_number_with_ubjson_prefix(j.m_value.array->size(), true, use_bjdata);
+                }
+
+                for (const auto& el : *j.m_value.array)
+                {
+                    write_ubjson(el, use_count, use_type, prefix_required, use_bjdata);
+                }
+
+                if (!use_count)
+                {
+                    oa->write_character(to_char_type(']'));
+                }
+
+                break;
+            }
+
+            case value_t::binary:
+            {
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('['));
+                }
+
+                if (use_type && !j.m_value.binary->empty())
+                {
+                    JSON_ASSERT(use_count);
+                    oa->write_character(to_char_type('$'));
+                    oa->write_character('U');
+                }
+
+                if (use_count)
+                {
+                    oa->write_character(to_char_type('#'));
+                    write_number_with_ubjson_prefix(j.m_value.binary->size(), true, use_bjdata);
+                }
+
+                if (use_type)
+                {
+                    oa->write_characters(
+                        reinterpret_cast<const CharType*>(j.m_value.binary->data()),
+                        j.m_value.binary->size());
+                }
+                else
+                {
+                    for (size_t i = 0; i < j.m_value.binary->size(); ++i)
+                    {
+                        oa->write_character(to_char_type('U'));
+                        oa->write_character(j.m_value.binary->data()[i]);
+                    }
+                }
+
+                if (!use_count)
+                {
+                    oa->write_character(to_char_type(']'));
+                }
+
+                break;
+            }
+
+            case value_t::object:
+            {
+                if (use_bjdata && j.m_value.object->size() == 3 && j.m_value.object->find("_ArrayType_") != j.m_value.object->end() && j.m_value.object->find("_ArraySize_") != j.m_value.object->end() && j.m_value.object->find("_ArrayData_") != j.m_value.object->end())
+                {
+                    if (!write_bjdata_ndarray(*j.m_value.object, use_count, use_type))  // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata)
+                    {
+                        break;
+                    }
+                }
+
+                if (add_prefix)
+                {
+                    oa->write_character(to_char_type('{'));
+                }
+
+                bool prefix_required = true;
+                if (use_type && !j.m_value.object->empty())
+                {
+                    JSON_ASSERT(use_count);
+                    const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
+                    const bool same_prefix = std::all_of(j.begin(), j.end(),
+                                                         [this, first_prefix, use_bjdata](const BasicJsonType & v)
+                    {
+                        return ubjson_prefix(v, use_bjdata) == first_prefix;
+                    });
+
+                    std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
+
+                    if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
+                    {
+                        prefix_required = false;
+                        oa->write_character(to_char_type('$'));
+                        oa->write_character(first_prefix);
+                    }
+                }
+
+                if (use_count)
+                {
+                    oa->write_character(to_char_type('#'));
+                    write_number_with_ubjson_prefix(j.m_value.object->size(), true, use_bjdata);
+                }
+
+                for (const auto& el : *j.m_value.object)
+                {
+                    write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
+                    oa->write_characters(
+                        reinterpret_cast<const CharType*>(el.first.c_str()),
+                        el.first.size());
+                    write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata);
+                }
+
+                if (!use_count)
+                {
+                    oa->write_character(to_char_type('}'));
+                }
+
+                break;
+            }
+
+            case value_t::discarded:
+            default:
+                break;
+        }
+    }
+
+  private:
+    //////////
+    // BSON //
+    //////////
+
+    /*!
+    @return The size of a BSON document entry header, including the id marker
+            and the entry name size (and its null-terminator).
+    */
+    static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j)
+    {
+        const auto it = name.find(static_cast<typename string_t::value_type>(0));
+        if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
+        {
+            JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
+            static_cast<void>(j);
+        }
+
+        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
+    }
+
+    /*!
+    @brief Writes the given @a element_type and @a name to the output adapter
+    */
+    void write_bson_entry_header(const string_t& name,
+                                 const std::uint8_t element_type)
+    {
+        oa->write_character(to_char_type(element_type)); // boolean
+        oa->write_characters(
+            reinterpret_cast<const CharType*>(name.c_str()),
+            name.size() + 1u);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and boolean value @a value
+    */
+    void write_bson_boolean(const string_t& name,
+                            const bool value)
+    {
+        write_bson_entry_header(name, 0x08);
+        oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and double value @a value
+    */
+    void write_bson_double(const string_t& name,
+                           const double value)
+    {
+        write_bson_entry_header(name, 0x01);
+        write_number<double>(value, true);
+    }
+
+    /*!
+    @return The size of the BSON-encoded string in @a value
+    */
+    static std::size_t calc_bson_string_size(const string_t& value)
+    {
+        return sizeof(std::int32_t) + value.size() + 1ul;
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and string value @a value
+    */
+    void write_bson_string(const string_t& name,
+                           const string_t& value)
+    {
+        write_bson_entry_header(name, 0x02);
+
+        write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true);
+        oa->write_characters(
+            reinterpret_cast<const CharType*>(value.c_str()),
+            value.size() + 1);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and null value
+    */
+    void write_bson_null(const string_t& name)
+    {
+        write_bson_entry_header(name, 0x0A);
+    }
+
+    /*!
+    @return The size of the BSON-encoded integer @a value
+    */
+    static std::size_t calc_bson_integer_size(const std::int64_t value)
+    {
+        return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
+               ? sizeof(std::int32_t)
+               : sizeof(std::int64_t);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and integer @a value
+    */
+    void write_bson_integer(const string_t& name,
+                            const std::int64_t value)
+    {
+        if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
+        {
+            write_bson_entry_header(name, 0x10); // int32
+            write_number<std::int32_t>(static_cast<std::int32_t>(value), true);
+        }
+        else
+        {
+            write_bson_entry_header(name, 0x12); // int64
+            write_number<std::int64_t>(static_cast<std::int64_t>(value), true);
+        }
+    }
+
+    /*!
+    @return The size of the BSON-encoded unsigned integer in @a j
+    */
+    static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
+    {
+        return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+               ? sizeof(std::int32_t)
+               : sizeof(std::int64_t);
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and unsigned @a value
+    */
+    void write_bson_unsigned(const string_t& name,
+                             const BasicJsonType& j)
+    {
+        if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+        {
+            write_bson_entry_header(name, 0x10 /* int32 */);
+            write_number<std::int32_t>(static_cast<std::int32_t>(j.m_value.number_unsigned), true);
+        }
+        else if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+        {
+            write_bson_entry_header(name, 0x12 /* int64 */);
+            write_number<std::int64_t>(static_cast<std::int64_t>(j.m_value.number_unsigned), true);
+        }
+        else
+        {
+            JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j));
+        }
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and object @a value
+    */
+    void write_bson_object_entry(const string_t& name,
+                                 const typename BasicJsonType::object_t& value)
+    {
+        write_bson_entry_header(name, 0x03); // object
+        write_bson_object(value);
+    }
+
+    /*!
+    @return The size of the BSON-encoded array @a value
+    */
+    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
+    {
+        std::size_t array_index = 0ul;
+
+        const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
+        {
+            return result + calc_bson_element_size(std::to_string(array_index++), el);
+        });
+
+        return sizeof(std::int32_t) + embedded_document_size + 1ul;
+    }
+
+    /*!
+    @return The size of the BSON-encoded binary array @a value
+    */
+    static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)
+    {
+        return sizeof(std::int32_t) + value.size() + 1ul;
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and array @a value
+    */
+    void write_bson_array(const string_t& name,
+                          const typename BasicJsonType::array_t& value)
+    {
+        write_bson_entry_header(name, 0x04); // array
+        write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true);
+
+        std::size_t array_index = 0ul;
+
+        for (const auto& el : value)
+        {
+            write_bson_element(std::to_string(array_index++), el);
+        }
+
+        oa->write_character(to_char_type(0x00));
+    }
+
+    /*!
+    @brief Writes a BSON element with key @a name and binary value @a value
+    */
+    void write_bson_binary(const string_t& name,
+                           const binary_t& value)
+    {
+        write_bson_entry_header(name, 0x05);
+
+        write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true);
+        write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));
+
+        oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
+    }
+
+    /*!
+    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name
+    @return The calculated size for the BSON document entry for @a j with the given @a name.
+    */
+    static std::size_t calc_bson_element_size(const string_t& name,
+            const BasicJsonType& j)
+    {
+        const auto header_size = calc_bson_entry_header_size(name, j);
+        switch (j.type())
+        {
+            case value_t::object:
+                return header_size + calc_bson_object_size(*j.m_value.object);
+
+            case value_t::array:
+                return header_size + calc_bson_array_size(*j.m_value.array);
+
+            case value_t::binary:
+                return header_size + calc_bson_binary_size(*j.m_value.binary);
+
+            case value_t::boolean:
+                return header_size + 1ul;
+
+            case value_t::number_float:
+                return header_size + 8ul;
+
+            case value_t::number_integer:
+                return header_size + calc_bson_integer_size(j.m_value.number_integer);
+
+            case value_t::number_unsigned:
+                return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);
+
+            case value_t::string:
+                return header_size + calc_bson_string_size(*j.m_value.string);
+
+            case value_t::null:
+                return header_size + 0ul;
+
+            // LCOV_EXCL_START
+            case value_t::discarded:
+            default:
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
+                return 0ul;
+                // LCOV_EXCL_STOP
+        }
+    }
+
+    /*!
+    @brief Serializes the JSON value @a j to BSON and associates it with the
+           key @a name.
+    @param name The name to associate with the JSON entity @a j within the
+                current BSON document
+    */
+    void write_bson_element(const string_t& name,
+                            const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            case value_t::object:
+                return write_bson_object_entry(name, *j.m_value.object);
+
+            case value_t::array:
+                return write_bson_array(name, *j.m_value.array);
+
+            case value_t::binary:
+                return write_bson_binary(name, *j.m_value.binary);
+
+            case value_t::boolean:
+                return write_bson_boolean(name, j.m_value.boolean);
+
+            case value_t::number_float:
+                return write_bson_double(name, j.m_value.number_float);
+
+            case value_t::number_integer:
+                return write_bson_integer(name, j.m_value.number_integer);
+
+            case value_t::number_unsigned:
+                return write_bson_unsigned(name, j);
+
+            case value_t::string:
+                return write_bson_string(name, *j.m_value.string);
+
+            case value_t::null:
+                return write_bson_null(name);
+
+            // LCOV_EXCL_START
+            case value_t::discarded:
+            default:
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
+                return;
+                // LCOV_EXCL_STOP
+        }
+    }
+
+    /*!
+    @brief Calculates the size of the BSON serialization of the given
+           JSON-object @a j.
+    @param[in] value  JSON value to serialize
+    @pre       value.type() == value_t::object
+    */
+    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
+    {
+        std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0),
+                                    [](size_t result, const typename BasicJsonType::object_t::value_type & el)
+        {
+            return result += calc_bson_element_size(el.first, el.second);
+        });
+
+        return sizeof(std::int32_t) + document_size + 1ul;
+    }
+
+    /*!
+    @param[in] value  JSON value to serialize
+    @pre       value.type() == value_t::object
+    */
+    void write_bson_object(const typename BasicJsonType::object_t& value)
+    {
+        write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_object_size(value)), true);
+
+        for (const auto& el : value)
+        {
+            write_bson_element(el.first, el.second);
+        }
+
+        oa->write_character(to_char_type(0x00));
+    }
+
+    //////////
+    // CBOR //
+    //////////
+
+    static constexpr CharType get_cbor_float_prefix(float /*unused*/)
+    {
+        return to_char_type(0xFA);  // Single-Precision Float
+    }
+
+    static constexpr CharType get_cbor_float_prefix(double /*unused*/)
+    {
+        return to_char_type(0xFB);  // Double-Precision Float
+    }
+
+    /////////////
+    // MsgPack //
+    /////////////
+
+    static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
+    {
+        return to_char_type(0xCA);  // float 32
+    }
+
+    static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
+    {
+        return to_char_type(0xCB);  // float 64
+    }
+
+    ////////////
+    // UBJSON //
+    ////////////
+
+    // UBJSON: write number (floating point)
+    template<typename NumberType, typename std::enable_if<
+                 std::is_floating_point<NumberType>::value, int>::type = 0>
+    void write_number_with_ubjson_prefix(const NumberType n,
+                                         const bool add_prefix,
+                                         const bool use_bjdata)
+    {
+        if (add_prefix)
+        {
+            oa->write_character(get_ubjson_float_prefix(n));
+        }
+        write_number(n, use_bjdata);
+    }
+
+    // UBJSON: write number (unsigned integer)
+    template<typename NumberType, typename std::enable_if<
+                 std::is_unsigned<NumberType>::value, int>::type = 0>
+    void write_number_with_ubjson_prefix(const NumberType n,
+                                         const bool add_prefix,
+                                         const bool use_bjdata)
+    {
+        if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('i'));  // int8
+            }
+            write_number(static_cast<std::uint8_t>(n), use_bjdata);
+        }
+        else if (n <= (std::numeric_limits<std::uint8_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('U'));  // uint8
+            }
+            write_number(static_cast<std::uint8_t>(n), use_bjdata);
+        }
+        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('I'));  // int16
+            }
+            write_number(static_cast<std::int16_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint16_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('u'));  // uint16 - bjdata only
+            }
+            write_number(static_cast<std::uint16_t>(n), use_bjdata);
+        }
+        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('l'));  // int32
+            }
+            write_number(static_cast<std::int32_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('m'));  // uint32 - bjdata only
+            }
+            write_number(static_cast<std::uint32_t>(n), use_bjdata);
+        }
+        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('L'));  // int64
+            }
+            write_number(static_cast<std::int64_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('M'));  // uint64 - bjdata only
+            }
+            write_number(static_cast<std::uint64_t>(n), use_bjdata);
+        }
+        else
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('H'));  // high-precision number
+            }
+
+            const auto number = BasicJsonType(n).dump();
+            write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
+            for (std::size_t i = 0; i < number.size(); ++i)
+            {
+                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
+            }
+        }
+    }
+
+    // UBJSON: write number (signed integer)
+    template < typename NumberType, typename std::enable_if <
+                   std::is_signed<NumberType>::value&&
+                   !std::is_floating_point<NumberType>::value, int >::type = 0 >
+    void write_number_with_ubjson_prefix(const NumberType n,
+                                         const bool add_prefix,
+                                         const bool use_bjdata)
+    {
+        if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('i'));  // int8
+            }
+            write_number(static_cast<std::int8_t>(n), use_bjdata);
+        }
+        else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('U'));  // uint8
+            }
+            write_number(static_cast<std::uint8_t>(n), use_bjdata);
+        }
+        else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('I'));  // int16
+            }
+            write_number(static_cast<std::int16_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::max)())))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('u'));  // uint16 - bjdata only
+            }
+            write_number(static_cast<uint16_t>(n), use_bjdata);
+        }
+        else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('l'));  // int32
+            }
+            write_number(static_cast<std::int32_t>(n), use_bjdata);
+        }
+        else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::max)())))
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('m'));  // uint32 - bjdata only
+            }
+            write_number(static_cast<uint32_t>(n), use_bjdata);
+        }
+        else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('L'));  // int64
+            }
+            write_number(static_cast<std::int64_t>(n), use_bjdata);
+        }
+        // LCOV_EXCL_START
+        else
+        {
+            if (add_prefix)
+            {
+                oa->write_character(to_char_type('H'));  // high-precision number
+            }
+
+            const auto number = BasicJsonType(n).dump();
+            write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
+            for (std::size_t i = 0; i < number.size(); ++i)
+            {
+                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
+            }
+        }
+        // LCOV_EXCL_STOP
+    }
+
+    /*!
+    @brief determine the type prefix of container values
+    */
+    CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept
+    {
+        switch (j.type())
+        {
+            case value_t::null:
+                return 'Z';
+
+            case value_t::boolean:
+                return j.m_value.boolean ? 'T' : 'F';
+
+            case value_t::number_integer:
+            {
+                if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
+                {
+                    return 'i';
+                }
+                if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
+                {
+                    return 'U';
+                }
+                if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
+                {
+                    return 'I';
+                }
+                if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()))
+                {
+                    return 'u';
+                }
+                if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
+                {
+                    return 'l';
+                }
+                if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()))
+                {
+                    return 'm';
+                }
+                if ((std::numeric_limits<std::int64_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
+                {
+                    return 'L';
+                }
+                // anything else is treated as high-precision number
+                return 'H'; // LCOV_EXCL_LINE
+            }
+
+            case value_t::number_unsigned:
+            {
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
+                {
+                    return 'i';
+                }
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
+                {
+                    return 'U';
+                }
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
+                {
+                    return 'I';
+                }
+                if (use_bjdata && j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)()))
+                {
+                    return 'u';
+                }
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+                {
+                    return 'l';
+                }
+                if (use_bjdata && j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)()))
+                {
+                    return 'm';
+                }
+                if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+                {
+                    return 'L';
+                }
+                if (use_bjdata && j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+                {
+                    return 'M';
+                }
+                // anything else is treated as high-precision number
+                return 'H'; // LCOV_EXCL_LINE
+            }
+
+            case value_t::number_float:
+                return get_ubjson_float_prefix(j.m_value.number_float);
+
+            case value_t::string:
+                return 'S';
+
+            case value_t::array: // fallthrough
+            case value_t::binary:
+                return '[';
+
+            case value_t::object:
+                return '{';
+
+            case value_t::discarded:
+            default:  // discarded values
+                return 'N';
+        }
+    }
+
+    static constexpr CharType get_ubjson_float_prefix(float /*unused*/)
+    {
+        return 'd';  // float 32
+    }
+
+    static constexpr CharType get_ubjson_float_prefix(double /*unused*/)
+    {
+        return 'D';  // float 64
+    }
+
+    /*!
+    @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid
+    */
+    bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type)
+    {
+        std::map<string_t, CharType> bjdtype = {{"uint8", 'U'},  {"int8", 'i'},  {"uint16", 'u'}, {"int16", 'I'},
+            {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'}
+        };
+
+        string_t key = "_ArrayType_";
+        auto it = bjdtype.find(static_cast<string_t>(value.at(key)));
+        if (it == bjdtype.end())
+        {
+            return true;
+        }
+        CharType dtype = it->second;
+
+        key = "_ArraySize_";
+        std::size_t len = (value.at(key).empty() ? 0 : 1);
+        for (const auto& el : value.at(key))
+        {
+            len *= static_cast<std::size_t>(el.m_value.number_unsigned);
+        }
+
+        key = "_ArrayData_";
+        if (value.at(key).size() != len)
+        {
+            return true;
+        }
+
+        oa->write_character('[');
+        oa->write_character('$');
+        oa->write_character(dtype);
+        oa->write_character('#');
+
+        key = "_ArraySize_";
+        write_ubjson(value.at(key), use_count, use_type, true,  true);
+
+        key = "_ArrayData_";
+        if (dtype == 'U' || dtype == 'C')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::uint8_t>(el.m_value.number_unsigned), true);
+            }
+        }
+        else if (dtype == 'i')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::int8_t>(el.m_value.number_integer), true);
+            }
+        }
+        else if (dtype == 'u')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::uint16_t>(el.m_value.number_unsigned), true);
+            }
+        }
+        else if (dtype == 'I')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::int16_t>(el.m_value.number_integer), true);
+            }
+        }
+        else if (dtype == 'm')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::uint32_t>(el.m_value.number_unsigned), true);
+            }
+        }
+        else if (dtype == 'l')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::int32_t>(el.m_value.number_integer), true);
+            }
+        }
+        else if (dtype == 'M')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::uint64_t>(el.m_value.number_unsigned), true);
+            }
+        }
+        else if (dtype == 'L')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<std::int64_t>(el.m_value.number_integer), true);
+            }
+        }
+        else if (dtype == 'd')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<float>(el.m_value.number_float), true);
+            }
+        }
+        else if (dtype == 'D')
+        {
+            for (const auto& el : value.at(key))
+            {
+                write_number(static_cast<double>(el.m_value.number_float), true);
+            }
+        }
+        return false;
+    }
+
+    ///////////////////////
+    // Utility functions //
+    ///////////////////////
+
+    /*
+    @brief write a number to output input
+    @param[in] n number of type @a NumberType
+    @param[in] OutputIsLittleEndian Set to true if output data is
+                                 required to be little endian
+    @tparam NumberType the type of the number
+
+    @note This function needs to respect the system's endianness, because bytes
+          in CBOR, MessagePack, and UBJSON are stored in network order (big
+          endian) and therefore need reordering on little endian systems.
+          On the other hand, BSON and BJData use little endian and should reorder
+          on big endian systems.
+    */
+    template<typename NumberType>
+    void write_number(const NumberType n, const bool OutputIsLittleEndian = false)
+    {
+        // step 1: write number to array of length NumberType
+        std::array<CharType, sizeof(NumberType)> vec{};
+        std::memcpy(vec.data(), &n, sizeof(NumberType));
+
+        // step 2: write array to output (with possible reordering)
+        if (is_little_endian != OutputIsLittleEndian)
+        {
+            // reverse byte order prior to conversion if necessary
+            std::reverse(vec.begin(), vec.end());
+        }
+
+        oa->write_characters(vec.data(), sizeof(NumberType));
+    }
+
+    void write_compact_float(const number_float_t n, detail::input_format_t format)
+    {
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+        if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
+                static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
+                static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
+        {
+            oa->write_character(format == detail::input_format_t::cbor
+                                ? get_cbor_float_prefix(static_cast<float>(n))
+                                : get_msgpack_float_prefix(static_cast<float>(n)));
+            write_number(static_cast<float>(n));
+        }
+        else
+        {
+            oa->write_character(format == detail::input_format_t::cbor
+                                ? get_cbor_float_prefix(n)
+                                : get_msgpack_float_prefix(n));
+            write_number(n);
+        }
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+    }
+
+  public:
+    // The following to_char_type functions are implement the conversion
+    // between uint8_t and CharType. In case CharType is not unsigned,
+    // such a conversion is required to allow values greater than 128.
+    // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
+    template < typename C = CharType,
+               enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
+    static constexpr CharType to_char_type(std::uint8_t x) noexcept
+    {
+        return *reinterpret_cast<char*>(&x);
+    }
+
+    template < typename C = CharType,
+               enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
+    static CharType to_char_type(std::uint8_t x) noexcept
+    {
+        static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
+        static_assert(std::is_trivial<CharType>::value, "CharType must be trivial");
+        CharType result;
+        std::memcpy(&result, &x, sizeof(x));
+        return result;
+    }
+
+    template<typename C = CharType,
+             enable_if_t<std::is_unsigned<C>::value>* = nullptr>
+    static constexpr CharType to_char_type(std::uint8_t x) noexcept
+    {
+        return x;
+    }
+
+    template < typename InputCharType, typename C = CharType,
+               enable_if_t <
+                   std::is_signed<C>::value &&
+                   std::is_signed<char>::value &&
+                   std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
+                   > * = nullptr >
+    static constexpr CharType to_char_type(InputCharType x) noexcept
+    {
+        return x;
+    }
+
+  private:
+    /// whether we can assume little endianness
+    const bool is_little_endian = little_endianness();
+
+    /// the output
+    output_adapter_t<CharType> oa = nullptr;
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/output/output_adapters.hpp>
+
+// #include <nlohmann/detail/output/serializer.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de>
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <algorithm> // reverse, remove, fill, find, none_of
+#include <array> // array
+#include <clocale> // localeconv, lconv
+#include <cmath> // labs, isfinite, isnan, signbit
+#include <cstddef> // size_t, ptrdiff_t
+#include <cstdint> // uint8_t
+#include <cstdio> // snprintf
+#include <limits> // numeric_limits
+#include <string> // string, char_traits
+#include <iomanip> // setfill, setw
+#include <type_traits> // is_same
+#include <utility> // move
+
+// #include <nlohmann/detail/conversions/to_chars.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/>
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <array> // array
+#include <cmath>   // signbit, isfinite
+#include <cstdint> // intN_t, uintN_t
+#include <cstring> // memcpy, memmove
+#include <limits> // numeric_limits
+#include <type_traits> // conditional
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*!
+@brief implements the Grisu2 algorithm for binary to decimal floating-point
+conversion.
+
+This implementation is a slightly modified version of the reference
+implementation which may be obtained from
+http://florian.loitsch.com/publications (bench.tar.gz).
+
+The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
+
+For a detailed description of the algorithm see:
+
+[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
+    Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
+    Language Design and Implementation, PLDI 2010
+[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
+    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
+    Design and Implementation, PLDI 1996
+*/
+namespace dtoa_impl
+{
+
+template<typename Target, typename Source>
+Target reinterpret_bits(const Source source)
+{
+    static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
+
+    Target target;
+    std::memcpy(&target, &source, sizeof(Source));
+    return target;
+}
+
+struct diyfp // f * 2^e
+{
+    static constexpr int kPrecision = 64; // = q
+
+    std::uint64_t f = 0;
+    int e = 0;
+
+    constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
+
+    /*!
+    @brief returns x - y
+    @pre x.e == y.e and x.f >= y.f
+    */
+    static diyfp sub(const diyfp& x, const diyfp& y) noexcept
+    {
+        JSON_ASSERT(x.e == y.e);
+        JSON_ASSERT(x.f >= y.f);
+
+        return {x.f - y.f, x.e};
+    }
+
+    /*!
+    @brief returns x * y
+    @note The result is rounded. (Only the upper q bits are returned.)
+    */
+    static diyfp mul(const diyfp& x, const diyfp& y) noexcept
+    {
+        static_assert(kPrecision == 64, "internal error");
+
+        // Computes:
+        //  f = round((x.f * y.f) / 2^q)
+        //  e = x.e + y.e + q
+
+        // Emulate the 64-bit * 64-bit multiplication:
+        //
+        // p = u * v
+        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
+        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )
+        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )
+        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )
+        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)
+        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )
+        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )
+        //
+        // (Since Q might be larger than 2^32 - 1)
+        //
+        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
+        //
+        // (Q_hi + H does not overflow a 64-bit int)
+        //
+        //   = p_lo + 2^64 p_hi
+
+        const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;
+        const std::uint64_t u_hi = x.f >> 32u;
+        const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;
+        const std::uint64_t v_hi = y.f >> 32u;
+
+        const std::uint64_t p0 = u_lo * v_lo;
+        const std::uint64_t p1 = u_lo * v_hi;
+        const std::uint64_t p2 = u_hi * v_lo;
+        const std::uint64_t p3 = u_hi * v_hi;
+
+        const std::uint64_t p0_hi = p0 >> 32u;
+        const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;
+        const std::uint64_t p1_hi = p1 >> 32u;
+        const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;
+        const std::uint64_t p2_hi = p2 >> 32u;
+
+        std::uint64_t Q = p0_hi + p1_lo + p2_lo;
+
+        // The full product might now be computed as
+        //
+        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
+        // p_lo = p0_lo + (Q << 32)
+        //
+        // But in this particular case here, the full p_lo is not required.
+        // Effectively we only need to add the highest bit in p_lo to p_hi (and
+        // Q_hi + 1 does not overflow).
+
+        Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up
+
+        const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);
+
+        return {h, x.e + y.e + 64};
+    }
+
+    /*!
+    @brief normalize x such that the significand is >= 2^(q-1)
+    @pre x.f != 0
+    */
+    static diyfp normalize(diyfp x) noexcept
+    {
+        JSON_ASSERT(x.f != 0);
+
+        while ((x.f >> 63u) == 0)
+        {
+            x.f <<= 1u;
+            x.e--;
+        }
+
+        return x;
+    }
+
+    /*!
+    @brief normalize x such that the result has the exponent E
+    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.
+    */
+    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
+    {
+        const int delta = x.e - target_exponent;
+
+        JSON_ASSERT(delta >= 0);
+        JSON_ASSERT(((x.f << delta) >> delta) == x.f);
+
+        return {x.f << delta, target_exponent};
+    }
+};
+
+struct boundaries
+{
+    diyfp w;
+    diyfp minus;
+    diyfp plus;
+};
+
+/*!
+Compute the (normalized) diyfp representing the input number 'value' and its
+boundaries.
+
+@pre value must be finite and positive
+*/
+template<typename FloatType>
+boundaries compute_boundaries(FloatType value)
+{
+    JSON_ASSERT(std::isfinite(value));
+    JSON_ASSERT(value > 0);
+
+    // Convert the IEEE representation into a diyfp.
+    //
+    // If v is denormal:
+    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))
+    // If v is normalized:
+    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
+
+    static_assert(std::numeric_limits<FloatType>::is_iec559,
+                  "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
+
+    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
+    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
+    constexpr int      kMinExp    = 1 - kBias;
+    constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
+
+    using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;
+
+    const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value));
+    const std::uint64_t E = bits >> (kPrecision - 1);
+    const std::uint64_t F = bits & (kHiddenBit - 1);
+
+    const bool is_denormal = E == 0;
+    const diyfp v = is_denormal
+                    ? diyfp(F, kMinExp)
+                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
+
+    // Compute the boundaries m- and m+ of the floating-point value
+    // v = f * 2^e.
+    //
+    // Determine v- and v+, the floating-point predecessor and successor if v,
+    // respectively.
+    //
+    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)
+    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)
+    //
+    //      v+ = v + 2^e
+    //
+    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
+    // between m- and m+ round to v, regardless of how the input rounding
+    // algorithm breaks ties.
+    //
+    //      ---+-------------+-------------+-------------+-------------+---  (A)
+    //         v-            m-            v             m+            v+
+    //
+    //      -----------------+------+------+-------------+-------------+---  (B)
+    //                       v-     m-     v             m+            v+
+
+    const bool lower_boundary_is_closer = F == 0 && E > 1;
+    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
+    const diyfp m_minus = lower_boundary_is_closer
+                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)
+                          : diyfp(2 * v.f - 1, v.e - 1); // (A)
+
+    // Determine the normalized w+ = m+.
+    const diyfp w_plus = diyfp::normalize(m_plus);
+
+    // Determine w- = m- such that e_(w-) = e_(w+).
+    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);
+
+    return {diyfp::normalize(v), w_minus, w_plus};
+}
+
+// Given normalized diyfp w, Grisu needs to find a (normalized) cached
+// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
+// within a certain range [alpha, gamma] (Definition 3.2 from [1])
+//
+//      alpha <= e = e_c + e_w + q <= gamma
+//
+// or
+//
+//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
+//                          <= f_c * f_w * 2^gamma
+//
+// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
+//
+//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
+//
+// or
+//
+//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
+//
+// The choice of (alpha,gamma) determines the size of the table and the form of
+// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
+// in practice:
+//
+// The idea is to cut the number c * w = f * 2^e into two parts, which can be
+// processed independently: An integral part p1, and a fractional part p2:
+//
+//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
+//              = (f div 2^-e) + (f mod 2^-e) * 2^e
+//              = p1 + p2 * 2^e
+//
+// The conversion of p1 into decimal form requires a series of divisions and
+// modulos by (a power of) 10. These operations are faster for 32-bit than for
+// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
+// achieved by choosing
+//
+//      -e >= 32   or   e <= -32 := gamma
+//
+// In order to convert the fractional part
+//
+//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
+//
+// into decimal form, the fraction is repeatedly multiplied by 10 and the digits
+// d[-i] are extracted in order:
+//
+//      (10 * p2) div 2^-e = d[-1]
+//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
+//
+// The multiplication by 10 must not overflow. It is sufficient to choose
+//
+//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
+//
+// Since p2 = f mod 2^-e < 2^-e,
+//
+//      -e <= 60   or   e >= -60 := alpha
+
+constexpr int kAlpha = -60;
+constexpr int kGamma = -32;
+
+struct cached_power // c = f * 2^e ~= 10^k
+{
+    std::uint64_t f;
+    int e;
+    int k;
+};
+
+/*!
+For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
+power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
+satisfies (Definition 3.2 from [1])
+
+     alpha <= e_c + e + q <= gamma.
+*/
+inline cached_power get_cached_power_for_binary_exponent(int e)
+{
+    // Now
+    //
+    //      alpha <= e_c + e + q <= gamma                                    (1)
+    //      ==> f_c * 2^alpha <= c * 2^e * 2^q
+    //
+    // and since the c's are normalized, 2^(q-1) <= f_c,
+    //
+    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
+    //      ==> 2^(alpha - e - 1) <= c
+    //
+    // If c were an exact power of ten, i.e. c = 10^k, one may determine k as
+    //
+    //      k = ceil( log_10( 2^(alpha - e - 1) ) )
+    //        = ceil( (alpha - e - 1) * log_10(2) )
+    //
+    // From the paper:
+    // "In theory the result of the procedure could be wrong since c is rounded,
+    //  and the computation itself is approximated [...]. In practice, however,
+    //  this simple function is sufficient."
+    //
+    // For IEEE double precision floating-point numbers converted into
+    // normalized diyfp's w = f * 2^e, with q = 64,
+    //
+    //      e >= -1022      (min IEEE exponent)
+    //           -52        (p - 1)
+    //           -52        (p - 1, possibly normalize denormal IEEE numbers)
+    //           -11        (normalize the diyfp)
+    //         = -1137
+    //
+    // and
+    //
+    //      e <= +1023      (max IEEE exponent)
+    //           -52        (p - 1)
+    //           -11        (normalize the diyfp)
+    //         = 960
+    //
+    // This binary exponent range [-1137,960] results in a decimal exponent
+    // range [-307,324]. One does not need to store a cached power for each
+    // k in this range. For each such k it suffices to find a cached power
+    // such that the exponent of the product lies in [alpha,gamma].
+    // This implies that the difference of the decimal exponents of adjacent
+    // table entries must be less than or equal to
+    //
+    //      floor( (gamma - alpha) * log_10(2) ) = 8.
+    //
+    // (A smaller distance gamma-alpha would require a larger table.)
+
+    // NB:
+    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
+
+    constexpr int kCachedPowersMinDecExp = -300;
+    constexpr int kCachedPowersDecStep = 8;
+
+    static constexpr std::array<cached_power, 79> kCachedPowers =
+    {
+        {
+            { 0xAB70FE17C79AC6CA, -1060, -300 },
+            { 0xFF77B1FCBEBCDC4F, -1034, -292 },
+            { 0xBE5691EF416BD60C, -1007, -284 },
+            { 0x8DD01FAD907FFC3C,  -980, -276 },
+            { 0xD3515C2831559A83,  -954, -268 },
+            { 0x9D71AC8FADA6C9B5,  -927, -260 },
+            { 0xEA9C227723EE8BCB,  -901, -252 },
+            { 0xAECC49914078536D,  -874, -244 },
+            { 0x823C12795DB6CE57,  -847, -236 },
+            { 0xC21094364DFB5637,  -821, -228 },
+            { 0x9096EA6F3848984F,  -794, -220 },
+            { 0xD77485CB25823AC7,  -768, -212 },
+            { 0xA086CFCD97BF97F4,  -741, -204 },
+            { 0xEF340A98172AACE5,  -715, -196 },
+            { 0xB23867FB2A35B28E,  -688, -188 },
+            { 0x84C8D4DFD2C63F3B,  -661, -180 },
+            { 0xC5DD44271AD3CDBA,  -635, -172 },
+            { 0x936B9FCEBB25C996,  -608, -164 },
+            { 0xDBAC6C247D62A584,  -582, -156 },
+            { 0xA3AB66580D5FDAF6,  -555, -148 },
+            { 0xF3E2F893DEC3F126,  -529, -140 },
+            { 0xB5B5ADA8AAFF80B8,  -502, -132 },
+            { 0x87625F056C7C4A8B,  -475, -124 },
+            { 0xC9BCFF6034C13053,  -449, -116 },
+            { 0x964E858C91BA2655,  -422, -108 },
+            { 0xDFF9772470297EBD,  -396, -100 },
+            { 0xA6DFBD9FB8E5B88F,  -369,  -92 },
+            { 0xF8A95FCF88747D94,  -343,  -84 },
+            { 0xB94470938FA89BCF,  -316,  -76 },
+            { 0x8A08F0F8BF0F156B,  -289,  -68 },
+            { 0xCDB02555653131B6,  -263,  -60 },
+            { 0x993FE2C6D07B7FAC,  -236,  -52 },
+            { 0xE45C10C42A2B3B06,  -210,  -44 },
+            { 0xAA242499697392D3,  -183,  -36 },
+            { 0xFD87B5F28300CA0E,  -157,  -28 },
+            { 0xBCE5086492111AEB,  -130,  -20 },
+            { 0x8CBCCC096F5088CC,  -103,  -12 },
+            { 0xD1B71758E219652C,   -77,   -4 },
+            { 0x9C40000000000000,   -50,    4 },
+            { 0xE8D4A51000000000,   -24,   12 },
+            { 0xAD78EBC5AC620000,     3,   20 },
+            { 0x813F3978F8940984,    30,   28 },
+            { 0xC097CE7BC90715B3,    56,   36 },
+            { 0x8F7E32CE7BEA5C70,    83,   44 },
+            { 0xD5D238A4ABE98068,   109,   52 },
+            { 0x9F4F2726179A2245,   136,   60 },
+            { 0xED63A231D4C4FB27,   162,   68 },
+            { 0xB0DE65388CC8ADA8,   189,   76 },
+            { 0x83C7088E1AAB65DB,   216,   84 },
+            { 0xC45D1DF942711D9A,   242,   92 },
+            { 0x924D692CA61BE758,   269,  100 },
+            { 0xDA01EE641A708DEA,   295,  108 },
+            { 0xA26DA3999AEF774A,   322,  116 },
+            { 0xF209787BB47D6B85,   348,  124 },
+            { 0xB454E4A179DD1877,   375,  132 },
+            { 0x865B86925B9BC5C2,   402,  140 },
+            { 0xC83553C5C8965D3D,   428,  148 },
+            { 0x952AB45CFA97A0B3,   455,  156 },
+            { 0xDE469FBD99A05FE3,   481,  164 },
+            { 0xA59BC234DB398C25,   508,  172 },
+            { 0xF6C69A72A3989F5C,   534,  180 },
+            { 0xB7DCBF5354E9BECE,   561,  188 },
+            { 0x88FCF317F22241E2,   588,  196 },
+            { 0xCC20CE9BD35C78A5,   614,  204 },
+            { 0x98165AF37B2153DF,   641,  212 },
+            { 0xE2A0B5DC971F303A,   667,  220 },
+            { 0xA8D9D1535CE3B396,   694,  228 },
+            { 0xFB9B7CD9A4A7443C,   720,  236 },
+            { 0xBB764C4CA7A44410,   747,  244 },
+            { 0x8BAB8EEFB6409C1A,   774,  252 },
+            { 0xD01FEF10A657842C,   800,  260 },
+            { 0x9B10A4E5E9913129,   827,  268 },
+            { 0xE7109BFBA19C0C9D,   853,  276 },
+            { 0xAC2820D9623BF429,   880,  284 },
+            { 0x80444B5E7AA7CF85,   907,  292 },
+            { 0xBF21E44003ACDD2D,   933,  300 },
+            { 0x8E679C2F5E44FF8F,   960,  308 },
+            { 0xD433179D9C8CB841,   986,  316 },
+            { 0x9E19DB92B4E31BA9,  1013,  324 },
+        }
+    };
+
+    // This computation gives exactly the same results for k as
+    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)
+    // for |e| <= 1500, but doesn't require floating-point operations.
+    // NB: log_10(2) ~= 78913 / 2^18
+    JSON_ASSERT(e >= -1500);
+    JSON_ASSERT(e <=  1500);
+    const int f = kAlpha - e - 1;
+    const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
+
+    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
+    JSON_ASSERT(index >= 0);
+    JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());
+
+    const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
+    JSON_ASSERT(kAlpha <= cached.e + e + 64);
+    JSON_ASSERT(kGamma >= cached.e + e + 64);
+
+    return cached;
+}
+
+/*!
+For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
+For n == 0, returns 1 and sets pow10 := 1.
+*/
+inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
+{
+    // LCOV_EXCL_START
+    if (n >= 1000000000)
+    {
+        pow10 = 1000000000;
+        return 10;
+    }
+    // LCOV_EXCL_STOP
+    if (n >= 100000000)
+    {
+        pow10 = 100000000;
+        return  9;
+    }
+    if (n >= 10000000)
+    {
+        pow10 = 10000000;
+        return  8;
+    }
+    if (n >= 1000000)
+    {
+        pow10 = 1000000;
+        return  7;
+    }
+    if (n >= 100000)
+    {
+        pow10 = 100000;
+        return  6;
+    }
+    if (n >= 10000)
+    {
+        pow10 = 10000;
+        return  5;
+    }
+    if (n >= 1000)
+    {
+        pow10 = 1000;
+        return  4;
+    }
+    if (n >= 100)
+    {
+        pow10 = 100;
+        return  3;
+    }
+    if (n >= 10)
+    {
+        pow10 = 10;
+        return  2;
+    }
+
+    pow10 = 1;
+    return 1;
+}
+
+inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
+                         std::uint64_t rest, std::uint64_t ten_k)
+{
+    JSON_ASSERT(len >= 1);
+    JSON_ASSERT(dist <= delta);
+    JSON_ASSERT(rest <= delta);
+    JSON_ASSERT(ten_k > 0);
+
+    //               <--------------------------- delta ---->
+    //                                  <---- dist --------->
+    // --------------[------------------+-------------------]--------------
+    //               M-                 w                   M+
+    //
+    //                                  ten_k
+    //                                <------>
+    //                                       <---- rest ---->
+    // --------------[------------------+----+--------------]--------------
+    //                                  w    V
+    //                                       = buf * 10^k
+    //
+    // ten_k represents a unit-in-the-last-place in the decimal representation
+    // stored in buf.
+    // Decrement buf by ten_k while this takes buf closer to w.
+
+    // The tests are written in this order to avoid overflow in unsigned
+    // integer arithmetic.
+
+    while (rest < dist
+            && delta - rest >= ten_k
+            && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
+    {
+        JSON_ASSERT(buf[len - 1] != '0');
+        buf[len - 1]--;
+        rest += ten_k;
+    }
+}
+
+/*!
+Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
+M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
+*/
+inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
+                             diyfp M_minus, diyfp w, diyfp M_plus)
+{
+    static_assert(kAlpha >= -60, "internal error");
+    static_assert(kGamma <= -32, "internal error");
+
+    // Generates the digits (and the exponent) of a decimal floating-point
+    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
+    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
+    //
+    //               <--------------------------- delta ---->
+    //                                  <---- dist --------->
+    // --------------[------------------+-------------------]--------------
+    //               M-                 w                   M+
+    //
+    // Grisu2 generates the digits of M+ from left to right and stops as soon as
+    // V is in [M-,M+].
+
+    JSON_ASSERT(M_plus.e >= kAlpha);
+    JSON_ASSERT(M_plus.e <= kGamma);
+
+    std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
+    std::uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)
+
+    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
+    //
+    //      M+ = f * 2^e
+    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
+    //         = ((p1        ) * 2^-e + (p2        )) * 2^e
+    //         = p1 + p2 * 2^e
+
+    const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);
+
+    auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
+    std::uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e
+
+    // 1)
+    //
+    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
+
+    JSON_ASSERT(p1 > 0);
+
+    std::uint32_t pow10{};
+    const int k = find_largest_pow10(p1, pow10);
+
+    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
+    //
+    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
+    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))
+    //
+    //      M+ = p1                                             + p2 * 2^e
+    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e
+    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
+    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e
+    //
+    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
+    //
+    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
+    //
+    // but stop as soon as
+    //
+    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
+
+    int n = k;
+    while (n > 0)
+    {
+        // Invariants:
+        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)
+        //      pow10 = 10^(n-1) <= p1 < 10^n
+        //
+        const std::uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)
+        const std::uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)
+        //
+        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
+        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
+        //
+        JSON_ASSERT(d <= 9);
+        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
+        //
+        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
+        //
+        p1 = r;
+        n--;
+        //
+        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)
+        //      pow10 = 10^n
+        //
+
+        // Now check if enough digits have been generated.
+        // Compute
+        //
+        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
+        //
+        // Note:
+        // Since rest and delta share the same exponent e, it suffices to
+        // compare the significands.
+        const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;
+        if (rest <= delta)
+        {
+            // V = buffer * 10^n, with M- <= V <= M+.
+
+            decimal_exponent += n;
+
+            // We may now just stop. But instead look if the buffer could be
+            // decremented to bring V closer to w.
+            //
+            // pow10 = 10^n is now 1 ulp in the decimal representation V.
+            // The rounding procedure works with diyfp's with an implicit
+            // exponent of e.
+            //
+            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
+            //
+            const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;
+            grisu2_round(buffer, length, dist, delta, rest, ten_n);
+
+            return;
+        }
+
+        pow10 /= 10;
+        //
+        //      pow10 = 10^(n-1) <= p1 < 10^n
+        // Invariants restored.
+    }
+
+    // 2)
+    //
+    // The digits of the integral part have been generated:
+    //
+    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e
+    //         = buffer            + p2 * 2^e
+    //
+    // Now generate the digits of the fractional part p2 * 2^e.
+    //
+    // Note:
+    // No decimal point is generated: the exponent is adjusted instead.
+    //
+    // p2 actually represents the fraction
+    //
+    //      p2 * 2^e
+    //          = p2 / 2^-e
+    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...
+    //
+    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
+    //
+    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
+    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
+    //
+    // using
+    //
+    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
+    //                = (                   d) * 2^-e + (                   r)
+    //
+    // or
+    //      10^m * p2 * 2^e = d + r * 2^e
+    //
+    // i.e.
+    //
+    //      M+ = buffer + p2 * 2^e
+    //         = buffer + 10^-m * (d + r * 2^e)
+    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
+    //
+    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
+
+    JSON_ASSERT(p2 > delta);
+
+    int m = 0;
+    for (;;)
+    {
+        // Invariant:
+        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
+        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e
+        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e
+        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
+        //
+        JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
+        p2 *= 10;
+        const std::uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e
+        const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
+        //
+        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
+        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
+        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
+        //
+        JSON_ASSERT(d <= 9);
+        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
+        //
+        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
+        //
+        p2 = r;
+        m++;
+        //
+        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e
+        // Invariant restored.
+
+        // Check if enough digits have been generated.
+        //
+        //      10^-m * p2 * 2^e <= delta * 2^e
+        //              p2 * 2^e <= 10^m * delta * 2^e
+        //                    p2 <= 10^m * delta
+        delta *= 10;
+        dist  *= 10;
+        if (p2 <= delta)
+        {
+            break;
+        }
+    }
+
+    // V = buffer * 10^-m, with M- <= V <= M+.
+
+    decimal_exponent -= m;
+
+    // 1 ulp in the decimal representation is now 10^-m.
+    // Since delta and dist are now scaled by 10^m, we need to do the
+    // same with ulp in order to keep the units in sync.
+    //
+    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
+    //
+    const std::uint64_t ten_m = one.f;
+    grisu2_round(buffer, length, dist, delta, p2, ten_m);
+
+    // By construction this algorithm generates the shortest possible decimal
+    // number (Loitsch, Theorem 6.2) which rounds back to w.
+    // For an input number of precision p, at least
+    //
+    //      N = 1 + ceil(p * log_10(2))
+    //
+    // decimal digits are sufficient to identify all binary floating-point
+    // numbers (Matula, "In-and-Out conversions").
+    // This implies that the algorithm does not produce more than N decimal
+    // digits.
+    //
+    //      N = 17 for p = 53 (IEEE double precision)
+    //      N = 9  for p = 24 (IEEE single precision)
+}
+
+/*!
+v = buf * 10^decimal_exponent
+len is the length of the buffer (number of decimal digits)
+The buffer must be large enough, i.e. >= max_digits10.
+*/
+JSON_HEDLEY_NON_NULL(1)
+inline void grisu2(char* buf, int& len, int& decimal_exponent,
+                   diyfp m_minus, diyfp v, diyfp m_plus)
+{
+    JSON_ASSERT(m_plus.e == m_minus.e);
+    JSON_ASSERT(m_plus.e == v.e);
+
+    //  --------(-----------------------+-----------------------)--------    (A)
+    //          m-                      v                       m+
+    //
+    //  --------------------(-----------+-----------------------)--------    (B)
+    //                      m-          v                       m+
+    //
+    // First scale v (and m- and m+) such that the exponent is in the range
+    // [alpha, gamma].
+
+    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
+
+    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
+
+    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
+    const diyfp w       = diyfp::mul(v,       c_minus_k);
+    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
+    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);
+
+    //  ----(---+---)---------------(---+---)---------------(---+---)----
+    //          w-                      w                       w+
+    //          = c*m-                  = c*v                   = c*m+
+    //
+    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
+    // w+ are now off by a small amount.
+    // In fact:
+    //
+    //      w - v * 10^k < 1 ulp
+    //
+    // To account for this inaccuracy, add resp. subtract 1 ulp.
+    //
+    //  --------+---[---------------(---+---)---------------]---+--------
+    //          w-  M-                  w                   M+  w+
+    //
+    // Now any number in [M-, M+] (bounds included) will round to w when input,
+    // regardless of how the input rounding algorithm breaks ties.
+    //
+    // And digit_gen generates the shortest possible such number in [M-, M+].
+    // Note that this does not mean that Grisu2 always generates the shortest
+    // possible number in the interval (m-, m+).
+    const diyfp M_minus(w_minus.f + 1, w_minus.e);
+    const diyfp M_plus (w_plus.f  - 1, w_plus.e );
+
+    decimal_exponent = -cached.k; // = -(-k) = k
+
+    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
+}
+
+/*!
+v = buf * 10^decimal_exponent
+len is the length of the buffer (number of decimal digits)
+The buffer must be large enough, i.e. >= max_digits10.
+*/
+template<typename FloatType>
+JSON_HEDLEY_NON_NULL(1)
+void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
+{
+    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
+                  "internal error: not enough precision");
+
+    JSON_ASSERT(std::isfinite(value));
+    JSON_ASSERT(value > 0);
+
+    // If the neighbors (and boundaries) of 'value' are always computed for double-precision
+    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
+    // decimal representations are not exactly "short".
+    //
+    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
+    // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
+    // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars'
+    // does.
+    // On the other hand, the documentation for 'std::to_chars' requires that "parsing the
+    // representation using the corresponding std::from_chars function recovers value exactly". That
+    // indicates that single precision floating-point numbers should be recovered using
+    // 'std::strtof'.
+    //
+    // NB: If the neighbors are computed for single-precision numbers, there is a single float
+    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
+    //     value is off by 1 ulp.
+#if 0
+    const boundaries w = compute_boundaries(static_cast<double>(value));
+#else
+    const boundaries w = compute_boundaries(value);
+#endif
+
+    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
+}
+
+/*!
+@brief appends a decimal representation of e to buf
+@return a pointer to the element following the exponent.
+@pre -1000 < e < 1000
+*/
+JSON_HEDLEY_NON_NULL(1)
+JSON_HEDLEY_RETURNS_NON_NULL
+inline char* append_exponent(char* buf, int e)
+{
+    JSON_ASSERT(e > -1000);
+    JSON_ASSERT(e <  1000);
+
+    if (e < 0)
+    {
+        e = -e;
+        *buf++ = '-';
+    }
+    else
+    {
+        *buf++ = '+';
+    }
+
+    auto k = static_cast<std::uint32_t>(e);
+    if (k < 10)
+    {
+        // Always print at least two digits in the exponent.
+        // This is for compatibility with printf("%g").
+        *buf++ = '0';
+        *buf++ = static_cast<char>('0' + k);
+    }
+    else if (k < 100)
+    {
+        *buf++ = static_cast<char>('0' + k / 10);
+        k %= 10;
+        *buf++ = static_cast<char>('0' + k);
+    }
+    else
+    {
+        *buf++ = static_cast<char>('0' + k / 100);
+        k %= 100;
+        *buf++ = static_cast<char>('0' + k / 10);
+        k %= 10;
+        *buf++ = static_cast<char>('0' + k);
+    }
+
+    return buf;
+}
+
+/*!
+@brief prettify v = buf * 10^decimal_exponent
+
+If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
+notation. Otherwise it will be printed in exponential notation.
+
+@pre min_exp < 0
+@pre max_exp > 0
+*/
+JSON_HEDLEY_NON_NULL(1)
+JSON_HEDLEY_RETURNS_NON_NULL
+inline char* format_buffer(char* buf, int len, int decimal_exponent,
+                           int min_exp, int max_exp)
+{
+    JSON_ASSERT(min_exp < 0);
+    JSON_ASSERT(max_exp > 0);
+
+    const int k = len;
+    const int n = len + decimal_exponent;
+
+    // v = buf * 10^(n-k)
+    // k is the length of the buffer (number of decimal digits)
+    // n is the position of the decimal point relative to the start of the buffer.
+
+    if (k <= n && n <= max_exp)
+    {
+        // digits[000]
+        // len <= max_exp + 2
+
+        std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));
+        // Make it look like a floating-point number (#362, #378)
+        buf[n + 0] = '.';
+        buf[n + 1] = '0';
+        return buf + (static_cast<size_t>(n) + 2);
+    }
+
+    if (0 < n && n <= max_exp)
+    {
+        // dig.its
+        // len <= max_digits10 + 1
+
+        JSON_ASSERT(k > n);
+
+        std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
+        buf[n] = '.';
+        return buf + (static_cast<size_t>(k) + 1U);
+    }
+
+    if (min_exp < n && n <= 0)
+    {
+        // 0.[000]digits
+        // len <= 2 + (-min_exp - 1) + max_digits10
+
+        std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k));
+        buf[0] = '0';
+        buf[1] = '.';
+        std::memset(buf + 2, '0', static_cast<size_t>(-n));
+        return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));
+    }
+
+    if (k == 1)
+    {
+        // dE+123
+        // len <= 1 + 5
+
+        buf += 1;
+    }
+    else
+    {
+        // d.igitsE+123
+        // len <= max_digits10 + 1 + 5
+
+        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);
+        buf[1] = '.';
+        buf += 1 + static_cast<size_t>(k);
+    }
+
+    *buf++ = 'e';
+    return append_exponent(buf, n - 1);
+}
+
+}  // namespace dtoa_impl
+
+/*!
+@brief generates a decimal representation of the floating-point number value in [first, last).
+
+The format of the resulting decimal representation is similar to printf's %g
+format. Returns an iterator pointing past-the-end of the decimal representation.
+
+@note The input number must be finite, i.e. NaN's and Inf's are not supported.
+@note The buffer must be large enough.
+@note The result is NOT null-terminated.
+*/
+template<typename FloatType>
+JSON_HEDLEY_NON_NULL(1, 2)
+JSON_HEDLEY_RETURNS_NON_NULL
+char* to_chars(char* first, const char* last, FloatType value)
+{
+    static_cast<void>(last); // maybe unused - fix warning
+    JSON_ASSERT(std::isfinite(value));
+
+    // Use signbit(value) instead of (value < 0) since signbit works for -0.
+    if (std::signbit(value))
+    {
+        value = -value;
+        *first++ = '-';
+    }
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+    if (value == 0) // +-0
+    {
+        *first++ = '0';
+        // Make it look like a floating-point number (#362, #378)
+        *first++ = '.';
+        *first++ = '0';
+        return first;
+    }
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
+
+    // Compute v = buffer * 10^decimal_exponent.
+    // The decimal digits are stored in the buffer, which needs to be interpreted
+    // as an unsigned decimal integer.
+    // len is the length of the buffer, i.e. the number of decimal digits.
+    int len = 0;
+    int decimal_exponent = 0;
+    dtoa_impl::grisu2(first, len, decimal_exponent, value);
+
+    JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);
+
+    // Format the buffer like printf("%.*g", prec, value)
+    constexpr int kMinExp = -4;
+    // Use digits10 here to increase compatibility with version 2.
+    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
+
+    JSON_ASSERT(last - first >= kMaxExp + 2);
+    JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
+    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
+
+    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
+}
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/exceptions.hpp>
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/cpp_future.hpp>
+
+// #include <nlohmann/detail/output/binary_writer.hpp>
+
+// #include <nlohmann/detail/output/output_adapters.hpp>
+
+// #include <nlohmann/detail/string_concat.hpp>
+
+// #include <nlohmann/detail/value_t.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+///////////////////
+// serialization //
+///////////////////
+
+/// how to treat decoding errors
+enum class error_handler_t
+{
+    strict,  ///< throw a type_error exception in case of invalid UTF-8
+    replace, ///< replace invalid UTF-8 sequences with U+FFFD
+    ignore   ///< ignore invalid UTF-8 sequences
+};
+
+template<typename BasicJsonType>
+class serializer
+{
+    using string_t = typename BasicJsonType::string_t;
+    using number_float_t = typename BasicJsonType::number_float_t;
+    using number_integer_t = typename BasicJsonType::number_integer_t;
+    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+    using binary_char_t = typename BasicJsonType::binary_t::value_type;
+    static constexpr std::uint8_t UTF8_ACCEPT = 0;
+    static constexpr std::uint8_t UTF8_REJECT = 1;
+
+  public:
+    /*!
+    @param[in] s  output stream to serialize to
+    @param[in] ichar  indentation character to use
+    @param[in] error_handler_  how to react on decoding errors
+    */
+    serializer(output_adapter_t<char> s, const char ichar,
+               error_handler_t error_handler_ = error_handler_t::strict)
+        : o(std::move(s))
+        , loc(std::localeconv())
+        , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
+        , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
+        , indent_char(ichar)
+        , indent_string(512, indent_char)
+        , error_handler(error_handler_)
+    {}
+
+    // delete because of pointer members
+    serializer(const serializer&) = delete;
+    serializer& operator=(const serializer&) = delete;
+    serializer(serializer&&) = delete;
+    serializer& operator=(serializer&&) = delete;
+    ~serializer() = default;
+
+    /*!
+    @brief internal implementation of the serialization function
+
+    This function is called by the public member function dump and organizes
+    the serialization internally. The indentation level is propagated as
+    additional parameter. In case of arrays and objects, the function is
+    called recursively.
+
+    - strings and object keys are escaped using `escape_string()`
+    - integer numbers are converted implicitly via `operator<<`
+    - floating-point numbers are converted to a string using `"%g"` format
+    - binary values are serialized as objects containing the subtype and the
+      byte array
+
+    @param[in] val               value to serialize
+    @param[in] pretty_print      whether the output shall be pretty-printed
+    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
+    in the output are escaped with `\uXXXX` sequences, and the result consists
+    of ASCII characters only.
+    @param[in] indent_step       the indent level
+    @param[in] current_indent    the current indent level (only used internally)
+    */
+    void dump(const BasicJsonType& val,
+              const bool pretty_print,
+              const bool ensure_ascii,
+              const unsigned int indent_step,
+              const unsigned int current_indent = 0)
+    {
+        switch (val.m_type)
+        {
+            case value_t::object:
+            {
+                if (val.m_value.object->empty())
+                {
+                    o->write_characters("{}", 2);
+                    return;
+                }
+
+                if (pretty_print)
+                {
+                    o->write_characters("{\n", 2);
+
+                    // variable to hold indentation for recursive calls
+                    const auto new_indent = current_indent + indent_step;
+                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
+                    {
+                        indent_string.resize(indent_string.size() * 2, ' ');
+                    }
+
+                    // first n-1 elements
+                    auto i = val.m_value.object->cbegin();
+                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
+                    {
+                        o->write_characters(indent_string.c_str(), new_indent);
+                        o->write_character('\"');
+                        dump_escaped(i->first, ensure_ascii);
+                        o->write_characters("\": ", 3);
+                        dump(i->second, true, ensure_ascii, indent_step, new_indent);
+                        o->write_characters(",\n", 2);
+                    }
+
+                    // last element
+                    JSON_ASSERT(i != val.m_value.object->cend());
+                    JSON_ASSERT(std::next(i) == val.m_value.object->cend());
+                    o->write_characters(indent_string.c_str(), new_indent);
+                    o->write_character('\"');
+                    dump_escaped(i->first, ensure_ascii);
+                    o->write_characters("\": ", 3);
+                    dump(i->second, true, ensure_ascii, indent_step, new_indent);
+
+                    o->write_character('\n');
+                    o->write_characters(indent_string.c_str(), current_indent);
+                    o->write_character('}');
+                }
+                else
+                {
+                    o->write_character('{');
+
+                    // first n-1 elements
+                    auto i = val.m_value.object->cbegin();
+                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
+                    {
+                        o->write_character('\"');
+                        dump_escaped(i->first, ensure_ascii);
+                        o->write_characters("\":", 2);
+                        dump(i->second, false, ensure_ascii, indent_step, current_indent);
+                        o->write_character(',');
+                    }
+
+                    // last element
+                    JSON_ASSERT(i != val.m_value.object->cend());
+                    JSON_ASSERT(std::next(i) == val.m_value.object->cend());
+                    o->write_character('\"');
+                    dump_escaped(i->first, ensure_ascii);
+                    o->write_characters("\":", 2);
+                    dump(i->second, false, ensure_ascii, indent_step, current_indent);
+
+                    o->write_character('}');
+                }
+
+                return;
+            }
+
+            case value_t::array:
+            {
+                if (val.m_value.array->empty())
+                {
+                    o->write_characters("[]", 2);
+                    return;
+                }
+
+                if (pretty_print)
+                {
+                    o->write_characters("[\n", 2);
+
+                    // variable to hold indentation for recursive calls
+                    const auto new_indent = current_indent + indent_step;
+                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
+                    {
+                        indent_string.resize(indent_string.size() * 2, ' ');
+                    }
+
+                    // first n-1 elements
+                    for (auto i = val.m_value.array->cbegin();
+                            i != val.m_value.array->cend() - 1; ++i)
+                    {
+                        o->write_characters(indent_string.c_str(), new_indent);
+                        dump(*i, true, ensure_ascii, indent_step, new_indent);
+                        o->write_characters(",\n", 2);
+                    }
+
+                    // last element
+                    JSON_ASSERT(!val.m_value.array->empty());
+                    o->write_characters(indent_string.c_str(), new_indent);
+                    dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
+
+                    o->write_character('\n');
+                    o->write_characters(indent_string.c_str(), current_indent);
+                    o->write_character(']');
+                }
+                else
+                {
+                    o->write_character('[');
+
+                    // first n-1 elements
+                    for (auto i = val.m_value.array->cbegin();
+                            i != val.m_value.array->cend() - 1; ++i)
+                    {
+                        dump(*i, false, ensure_ascii, indent_step, current_indent);
+                        o->write_character(',');
+                    }
+
+                    // last element
+                    JSON_ASSERT(!val.m_value.array->empty());
+                    dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
+
+                    o->write_character(']');
+                }
+
+                return;
+            }
+
+            case value_t::string:
+            {
+                o->write_character('\"');
+                dump_escaped(*val.m_value.string, ensure_ascii);
+                o->write_character('\"');
+                return;
+            }
+
+            case value_t::binary:
+            {
+                if (pretty_print)
+                {
+                    o->write_characters("{\n", 2);
+
+                    // variable to hold indentation for recursive calls
+                    const auto new_indent = current_indent + indent_step;
+                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
+                    {
+                        indent_string.resize(indent_string.size() * 2, ' ');
+                    }
+
+                    o->write_characters(indent_string.c_str(), new_indent);
+
+                    o->write_characters("\"bytes\": [", 10);
+
+                    if (!val.m_value.binary->empty())
+                    {
+                        for (auto i = val.m_value.binary->cbegin();
+                                i != val.m_value.binary->cend() - 1; ++i)
+                        {
+                            dump_integer(*i);
+                            o->write_characters(", ", 2);
+                        }
+                        dump_integer(val.m_value.binary->back());
+                    }
+
+                    o->write_characters("],\n", 3);
+                    o->write_characters(indent_string.c_str(), new_indent);
+
+                    o->write_characters("\"subtype\": ", 11);
+                    if (val.m_value.binary->has_subtype())
+                    {
+                        dump_integer(val.m_value.binary->subtype());
+                    }
+                    else
+                    {
+                        o->write_characters("null", 4);
+                    }
+                    o->write_character('\n');
+                    o->write_characters(indent_string.c_str(), current_indent);
+                    o->write_character('}');
+                }
+                else
+                {
+                    o->write_characters("{\"bytes\":[", 10);
+
+                    if (!val.m_value.binary->empty())
+                    {
+                        for (auto i = val.m_value.binary->cbegin();
+                                i != val.m_value.binary->cend() - 1; ++i)
+                        {
+                            dump_integer(*i);
+                            o->write_character(',');
+                        }
+                        dump_integer(val.m_value.binary->back());
+                    }
+
+                    o->write_characters("],\"subtype\":", 12);
+                    if (val.m_value.binary->has_subtype())
+                    {
+                        dump_integer(val.m_value.binary->subtype());
+                        o->write_character('}');
+                    }
+                    else
+                    {
+                        o->write_characters("null}", 5);
+                    }
+                }
+                return;
+            }
+
+            case value_t::boolean:
+            {
+                if (val.m_value.boolean)
+                {
+                    o->write_characters("true", 4);
+                }
+                else
+                {
+                    o->write_characters("false", 5);
+                }
+                return;
+            }
+
+            case value_t::number_integer:
+            {
+                dump_integer(val.m_value.number_integer);
+                return;
+            }
+
+            case value_t::number_unsigned:
+            {
+                dump_integer(val.m_value.number_unsigned);
+                return;
+            }
+
+            case value_t::number_float:
+            {
+                dump_float(val.m_value.number_float);
+                return;
+            }
+
+            case value_t::discarded:
+            {
+                o->write_characters("<discarded>", 11);
+                return;
+            }
+
+            case value_t::null:
+            {
+                o->write_characters("null", 4);
+                return;
+            }
+
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+    }
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    /*!
+    @brief dump escaped string
+
+    Escape a string by replacing certain special characters by a sequence of an
+    escape character (backslash) and another character and other control
+    characters by a sequence of "\u" followed by a four-digit hex
+    representation. The escaped string is written to output stream @a o.
+
+    @param[in] s  the string to escape
+    @param[in] ensure_ascii  whether to escape non-ASCII characters with
+                             \uXXXX sequences
+
+    @complexity Linear in the length of string @a s.
+    */
+    void dump_escaped(const string_t& s, const bool ensure_ascii)
+    {
+        std::uint32_t codepoint{};
+        std::uint8_t state = UTF8_ACCEPT;
+        std::size_t bytes = 0;  // number of bytes written to string_buffer
+
+        // number of bytes written at the point of the last valid byte
+        std::size_t bytes_after_last_accept = 0;
+        std::size_t undumped_chars = 0;
+
+        for (std::size_t i = 0; i < s.size(); ++i)
+        {
+            const auto byte = static_cast<std::uint8_t>(s[i]);
+
+            switch (decode(state, codepoint, byte))
+            {
+                case UTF8_ACCEPT:  // decode found a new code point
+                {
+                    switch (codepoint)
+                    {
+                        case 0x08: // backspace
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 'b';
+                            break;
+                        }
+
+                        case 0x09: // horizontal tab
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 't';
+                            break;
+                        }
+
+                        case 0x0A: // newline
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 'n';
+                            break;
+                        }
+
+                        case 0x0C: // formfeed
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 'f';
+                            break;
+                        }
+
+                        case 0x0D: // carriage return
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = 'r';
+                            break;
+                        }
+
+                        case 0x22: // quotation mark
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = '\"';
+                            break;
+                        }
+
+                        case 0x5C: // reverse solidus
+                        {
+                            string_buffer[bytes++] = '\\';
+                            string_buffer[bytes++] = '\\';
+                            break;
+                        }
+
+                        default:
+                        {
+                            // escape control characters (0x00..0x1F) or, if
+                            // ensure_ascii parameter is used, non-ASCII characters
+                            if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
+                            {
+                                if (codepoint <= 0xFFFF)
+                                {
+                                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+                                    static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
+                                                                      static_cast<std::uint16_t>(codepoint)));
+                                    bytes += 6;
+                                }
+                                else
+                                {
+                                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+                                    static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
+                                                                      static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
+                                                                      static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
+                                    bytes += 12;
+                                }
+                            }
+                            else
+                            {
+                                // copy byte to buffer (all previous bytes
+                                // been copied have in default case above)
+                                string_buffer[bytes++] = s[i];
+                            }
+                            break;
+                        }
+                    }
+
+                    // write buffer and reset index; there must be 13 bytes
+                    // left, as this is the maximal number of bytes to be
+                    // written ("\uxxxx\uxxxx\0") for one code point
+                    if (string_buffer.size() - bytes < 13)
+                    {
+                        o->write_characters(string_buffer.data(), bytes);
+                        bytes = 0;
+                    }
+
+                    // remember the byte position of this accept
+                    bytes_after_last_accept = bytes;
+                    undumped_chars = 0;
+                    break;
+                }
+
+                case UTF8_REJECT:  // decode found invalid UTF-8 byte
+                {
+                    switch (error_handler)
+                    {
+                        case error_handler_t::strict:
+                        {
+                            JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr));
+                        }
+
+                        case error_handler_t::ignore:
+                        case error_handler_t::replace:
+                        {
+                            // in case we saw this character the first time, we
+                            // would like to read it again, because the byte
+                            // may be OK for itself, but just not OK for the
+                            // previous sequence
+                            if (undumped_chars > 0)
+                            {
+                                --i;
+                            }
+
+                            // reset length buffer to the last accepted index;
+                            // thus removing/ignoring the invalid characters
+                            bytes = bytes_after_last_accept;
+
+                            if (error_handler == error_handler_t::replace)
+                            {
+                                // add a replacement character
+                                if (ensure_ascii)
+                                {
+                                    string_buffer[bytes++] = '\\';
+                                    string_buffer[bytes++] = 'u';
+                                    string_buffer[bytes++] = 'f';
+                                    string_buffer[bytes++] = 'f';
+                                    string_buffer[bytes++] = 'f';
+                                    string_buffer[bytes++] = 'd';
+                                }
+                                else
+                                {
+                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF');
+                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
+                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
+                                }
+
+                                // write buffer and reset index; there must be 13 bytes
+                                // left, as this is the maximal number of bytes to be
+                                // written ("\uxxxx\uxxxx\0") for one code point
+                                if (string_buffer.size() - bytes < 13)
+                                {
+                                    o->write_characters(string_buffer.data(), bytes);
+                                    bytes = 0;
+                                }
+
+                                bytes_after_last_accept = bytes;
+                            }
+
+                            undumped_chars = 0;
+
+                            // continue processing the string
+                            state = UTF8_ACCEPT;
+                            break;
+                        }
+
+                        default:            // LCOV_EXCL_LINE
+                            JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+                    }
+                    break;
+                }
+
+                default:  // decode found yet incomplete multi-byte code point
+                {
+                    if (!ensure_ascii)
+                    {
+                        // code point will not be escaped - copy byte to buffer
+                        string_buffer[bytes++] = s[i];
+                    }
+                    ++undumped_chars;
+                    break;
+                }
+            }
+        }
+
+        // we finished processing the string
+        if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
+        {
+            // write buffer
+            if (bytes > 0)
+            {
+                o->write_characters(string_buffer.data(), bytes);
+            }
+        }
+        else
+        {
+            // we finish reading, but do not accept: string was incomplete
+            switch (error_handler)
+            {
+                case error_handler_t::strict:
+                {
+                    JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr));
+                }
+
+                case error_handler_t::ignore:
+                {
+                    // write all accepted bytes
+                    o->write_characters(string_buffer.data(), bytes_after_last_accept);
+                    break;
+                }
+
+                case error_handler_t::replace:
+                {
+                    // write all accepted bytes
+                    o->write_characters(string_buffer.data(), bytes_after_last_accept);
+                    // add a replacement character
+                    if (ensure_ascii)
+                    {
+                        o->write_characters("\\ufffd", 6);
+                    }
+                    else
+                    {
+                        o->write_characters("\xEF\xBF\xBD", 3);
+                    }
+                    break;
+                }
+
+                default:            // LCOV_EXCL_LINE
+                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+            }
+        }
+    }
+
+  private:
+    /*!
+    @brief count digits
+
+    Count the number of decimal (base 10) digits for an input unsigned integer.
+
+    @param[in] x  unsigned integer number to count its digits
+    @return    number of decimal digits
+    */
+    inline unsigned int count_digits(number_unsigned_t x) noexcept
+    {
+        unsigned int n_digits = 1;
+        for (;;)
+        {
+            if (x < 10)
+            {
+                return n_digits;
+            }
+            if (x < 100)
+            {
+                return n_digits + 1;
+            }
+            if (x < 1000)
+            {
+                return n_digits + 2;
+            }
+            if (x < 10000)
+            {
+                return n_digits + 3;
+            }
+            x = x / 10000u;
+            n_digits += 4;
+        }
+    }
+
+    /*!
+     * @brief convert a byte to a uppercase hex representation
+     * @param[in] byte byte to represent
+     * @return representation ("00".."FF")
+     */
+    static std::string hex_bytes(std::uint8_t byte)
+    {
+        std::string result = "FF";
+        constexpr const char* nibble_to_hex = "0123456789ABCDEF";
+        result[0] = nibble_to_hex[byte / 16];
+        result[1] = nibble_to_hex[byte % 16];
+        return result;
+    }
+
+    // templates to avoid warnings about useless casts
+    template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
+    bool is_negative_number(NumberType x)
+    {
+        return x < 0;
+    }
+
+    template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >
+    bool is_negative_number(NumberType /*unused*/)
+    {
+        return false;
+    }
+
+    /*!
+    @brief dump an integer
+
+    Dump a given integer to output stream @a o. Works internally with
+    @a number_buffer.
+
+    @param[in] x  integer number (signed or unsigned) to dump
+    @tparam NumberType either @a number_integer_t or @a number_unsigned_t
+    */
+    template < typename NumberType, detail::enable_if_t <
+                   std::is_integral<NumberType>::value ||
+                   std::is_same<NumberType, number_unsigned_t>::value ||
+                   std::is_same<NumberType, number_integer_t>::value ||
+                   std::is_same<NumberType, binary_char_t>::value,
+                   int > = 0 >
+    void dump_integer(NumberType x)
+    {
+        static constexpr std::array<std::array<char, 2>, 100> digits_to_99
+        {
+            {
+                {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
+                {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
+                {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
+                {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
+                {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
+                {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
+                {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
+                {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
+                {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
+                {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
+            }
+        };
+
+        // special case for "0"
+        if (x == 0)
+        {
+            o->write_character('0');
+            return;
+        }
+
+        // use a pointer to fill the buffer
+        auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+
+        number_unsigned_t abs_value;
+
+        unsigned int n_chars{};
+
+        if (is_negative_number(x))
+        {
+            *buffer_ptr = '-';
+            abs_value = remove_sign(static_cast<number_integer_t>(x));
+
+            // account one more byte for the minus sign
+            n_chars = 1 + count_digits(abs_value);
+        }
+        else
+        {
+            abs_value = static_cast<number_unsigned_t>(x);
+            n_chars = count_digits(abs_value);
+        }
+
+        // spare 1 byte for '\0'
+        JSON_ASSERT(n_chars < number_buffer.size() - 1);
+
+        // jump to the end to generate the string from backward,
+        // so we later avoid reversing the result
+        buffer_ptr += n_chars;
+
+        // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
+        // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
+        while (abs_value >= 100)
+        {
+            const auto digits_index = static_cast<unsigned>((abs_value % 100));
+            abs_value /= 100;
+            *(--buffer_ptr) = digits_to_99[digits_index][1];
+            *(--buffer_ptr) = digits_to_99[digits_index][0];
+        }
+
+        if (abs_value >= 10)
+        {
+            const auto digits_index = static_cast<unsigned>(abs_value);
+            *(--buffer_ptr) = digits_to_99[digits_index][1];
+            *(--buffer_ptr) = digits_to_99[digits_index][0];
+        }
+        else
+        {
+            *(--buffer_ptr) = static_cast<char>('0' + abs_value);
+        }
+
+        o->write_characters(number_buffer.data(), n_chars);
+    }
+
+    /*!
+    @brief dump a floating-point number
+
+    Dump a given floating-point number to output stream @a o. Works internally
+    with @a number_buffer.
+
+    @param[in] x  floating-point number to dump
+    */
+    void dump_float(number_float_t x)
+    {
+        // NaN / inf
+        if (!std::isfinite(x))
+        {
+            o->write_characters("null", 4);
+            return;
+        }
+
+        // If number_float_t is an IEEE-754 single or double precision number,
+        // use the Grisu2 algorithm to produce short numbers which are
+        // guaranteed to round-trip, using strtof and strtod, resp.
+        //
+        // NB: The test below works if <long double> == <double>.
+        static constexpr bool is_ieee_single_or_double
+            = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
+              (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
+
+        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
+    }
+
+    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
+    {
+        auto* begin = number_buffer.data();
+        auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
+
+        o->write_characters(begin, static_cast<size_t>(end - begin));
+    }
+
+    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
+    {
+        // get number of digits for a float -> text -> float round-trip
+        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
+
+        // the actual conversion
+        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
+        std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
+
+        // negative value indicates an error
+        JSON_ASSERT(len > 0);
+        // check if buffer was large enough
+        JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
+
+        // erase thousands separator
+        if (thousands_sep != '\0')
+        {
+            // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081
+            const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);
+            std::fill(end, number_buffer.end(), '\0');
+            JSON_ASSERT((end - number_buffer.begin()) <= len);
+            len = (end - number_buffer.begin());
+        }
+
+        // convert decimal point to '.'
+        if (decimal_point != '\0' && decimal_point != '.')
+        {
+            // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081
+            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
+            if (dec_pos != number_buffer.end())
+            {
+                *dec_pos = '.';
+            }
+        }
+
+        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
+
+        // determine if we need to append ".0"
+        const bool value_is_int_like =
+            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
+                         [](char c)
+        {
+            return c == '.' || c == 'e';
+        });
+
+        if (value_is_int_like)
+        {
+            o->write_characters(".0", 2);
+        }
+    }
+
+    /*!
+    @brief check whether a string is UTF-8 encoded
+
+    The function checks each byte of a string whether it is UTF-8 encoded. The
+    result of the check is stored in the @a state parameter. The function must
+    be called initially with state 0 (accept). State 1 means the string must
+    be rejected, because the current byte is not allowed. If the string is
+    completely processed, but the state is non-zero, the string ended
+    prematurely; that is, the last byte indicated more bytes should have
+    followed.
+
+    @param[in,out] state  the state of the decoding
+    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)
+    @param[in] byte       next byte to decode
+    @return               new state
+
+    @note The function has been edited: a std::array is used.
+
+    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+    */
+    static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
+    {
+        static const std::array<std::uint8_t, 400> utf8d =
+        {
+            {
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
+                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
+                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
+                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
+                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
+                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
+                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
+                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
+                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
+                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
+                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
+            }
+        };
+
+        JSON_ASSERT(byte < utf8d.size());
+        const std::uint8_t type = utf8d.at(byte);
+
+        codep = (state != UTF8_ACCEPT)
+                ? (byte & 0x3fu) | (codep << 6u)
+                : (0xFFu >> type) & (byte);
+
+        std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
+        JSON_ASSERT(index < 400);
+        state = utf8d[index];
+        return state;
+    }
+
+    /*
+     * Overload to make the compiler happy while it is instantiating
+     * dump_integer for number_unsigned_t.
+     * Must never be called.
+     */
+    number_unsigned_t remove_sign(number_unsigned_t x)
+    {
+        JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        return x; // LCOV_EXCL_LINE
+    }
+
+    /*
+     * Helper function for dump_integer
+     *
+     * This function takes a negative signed integer and returns its absolute
+     * value as unsigned integer. The plus/minus shuffling is necessary as we can
+     * not directly remove the sign of an arbitrary signed integer as the
+     * absolute values of INT_MIN and INT_MAX are usually not the same. See
+     * #1708 for details.
+     */
+    inline number_unsigned_t remove_sign(number_integer_t x) noexcept
+    {
+        JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)
+        return static_cast<number_unsigned_t>(-(x + 1)) + 1;
+    }
+
+  private:
+    /// the output of the serializer
+    output_adapter_t<char> o = nullptr;
+
+    /// a (hopefully) large enough character buffer
+    std::array<char, 64> number_buffer{{}};
+
+    /// the locale
+    const std::lconv* loc = nullptr;
+    /// the locale's thousand separator character
+    const char thousands_sep = '\0';
+    /// the locale's decimal point character
+    const char decimal_point = '\0';
+
+    /// string buffer
+    std::array<char, 512> string_buffer{{}};
+
+    /// the indentation character
+    const char indent_char;
+    /// the indentation string
+    string_t indent_string;
+
+    /// error_handler how to react on decoding errors
+    const error_handler_t error_handler;
+};
+
+}  // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
+// #include <nlohmann/detail/value_t.hpp>
+
+// #include <nlohmann/json_fwd.hpp>
+
+// #include <nlohmann/ordered_map.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <functional> // equal_to, less
+#include <initializer_list> // initializer_list
+#include <iterator> // input_iterator_tag, iterator_traits
+#include <memory> // allocator
+#include <stdexcept> // for out_of_range
+#include <type_traits> // enable_if, is_convertible
+#include <utility> // pair
+#include <vector> // vector
+
+// #include <nlohmann/detail/macro_scope.hpp>
+
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+/// ordered_map: a minimal map-like container that preserves insertion order
+/// for use within nlohmann::basic_json<ordered_map>
+template <class Key, class T, class IgnoredLess = std::less<Key>,
+          class Allocator = std::allocator<std::pair<const Key, T>>>
+                  struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
+{
+    using key_type = Key;
+    using mapped_type = T;
+    using Container = std::vector<std::pair<const Key, T>, Allocator>;
+    using iterator = typename Container::iterator;
+    using const_iterator = typename Container::const_iterator;
+    using size_type = typename Container::size_type;
+    using value_type = typename Container::value_type;
+#ifdef JSON_HAS_CPP_14
+    using key_compare = std::equal_to<>;
+#else
+    using key_compare = std::equal_to<Key>;
+#endif
+
+    // Explicit constructors instead of `using Container::Container`
+    // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
+    ordered_map() noexcept(noexcept(Container())) : Container{} {}
+    explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
+    template <class It>
+    ordered_map(It first, It last, const Allocator& alloc = Allocator())
+        : Container{first, last, alloc} {}
+    ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
+        : Container{init, alloc} {}
+
+    std::pair<iterator, bool> emplace(const key_type& key, T&& t)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return {it, false};
+            }
+        }
+        Container::emplace_back(key, std::forward<T>(t));
+        return {std::prev(this->end()), true};
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    std::pair<iterator, bool> emplace(KeyType && key, T && t)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return {it, false};
+            }
+        }
+        Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t));
+        return {std::prev(this->end()), true};
+    }
+
+    T& operator[](const key_type& key)
+    {
+        return emplace(key, T{}).first->second;
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    T & operator[](KeyType && key)
+    {
+        return emplace(std::forward<KeyType>(key), T{}).first->second;
+    }
+
+    const T& operator[](const key_type& key) const
+    {
+        return at(key);
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    const T & operator[](KeyType && key) const
+    {
+        return at(std::forward<KeyType>(key));
+    }
+
+    T& at(const key_type& key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it->second;
+            }
+        }
+
+        JSON_THROW(std::out_of_range("key not found"));
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    T & at(KeyType && key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it->second;
+            }
+        }
+
+        JSON_THROW(std::out_of_range("key not found"));
+    }
+
+    const T& at(const key_type& key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it->second;
+            }
+        }
+
+        JSON_THROW(std::out_of_range("key not found"));
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    const T & at(KeyType && key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it->second;
+            }
+        }
+
+        JSON_THROW(std::out_of_range("key not found"));
+    }
+
+    size_type erase(const key_type& key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                // Since we cannot move const Keys, re-construct them in place
+                for (auto next = it; ++next != this->end(); ++it)
+                {
+                    it->~value_type(); // Destroy but keep allocation
+                    new (&*it) value_type{std::move(*next)};
+                }
+                Container::pop_back();
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    size_type erase(KeyType && key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                // Since we cannot move const Keys, re-construct them in place
+                for (auto next = it; ++next != this->end(); ++it)
+                {
+                    it->~value_type(); // Destroy but keep allocation
+                    new (&*it) value_type{std::move(*next)};
+                }
+                Container::pop_back();
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    iterator erase(iterator pos)
+    {
+        return erase(pos, std::next(pos));
+    }
+
+    iterator erase(iterator first, iterator last)
+    {
+        if (first == last)
+        {
+            return first;
+        }
+
+        const auto elements_affected = std::distance(first, last);
+        const auto offset = std::distance(Container::begin(), first);
+
+        // This is the start situation. We need to delete elements_affected
+        // elements (3 in this example: e, f, g), and need to return an
+        // iterator past the last deleted element (h in this example).
+        // Note that offset is the distance from the start of the vector
+        // to first. We will need this later.
+
+        // [ a, b, c, d, e, f, g, h, i, j ]
+        //               ^        ^
+        //             first    last
+
+        // Since we cannot move const Keys, we re-construct them in place.
+        // We start at first and re-construct (viz. copy) the elements from
+        // the back of the vector. Example for first iteration:
+
+        //               ,--------.
+        //               v        |   destroy e and re-construct with h
+        // [ a, b, c, d, e, f, g, h, i, j ]
+        //               ^        ^
+        //               it       it + elements_affected
+
+        for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
+        {
+            it->~value_type(); // destroy but keep allocation
+            new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
+        }
+
+        // [ a, b, c, d, h, i, j, h, i, j ]
+        //               ^        ^
+        //             first    last
+
+        // remove the unneeded elements at the end of the vector
+        Container::resize(this->size() - static_cast<size_type>(elements_affected));
+
+        // [ a, b, c, d, h, i, j ]
+        //               ^        ^
+        //             first    last
+
+        // first is now pointing past the last deleted element, but we cannot
+        // use this iterator, because it may have been invalidated by the
+        // resize call. Instead, we can return begin() + offset.
+        return Container::begin() + offset;
+    }
+
+    size_type count(const key_type& key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    size_type count(KeyType && key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    iterator find(const key_type& key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it;
+            }
+        }
+        return Container::end();
+    }
+
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
+    iterator find(KeyType && key)
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it;
+            }
+        }
+        return Container::end();
+    }
+
+    const_iterator find(const key_type& key) const
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, key))
+            {
+                return it;
+            }
+        }
+        return Container::end();
+    }
+
+    std::pair<iterator, bool> insert( value_type&& value )
+    {
+        return emplace(value.first, std::move(value.second));
+    }
+
+    std::pair<iterator, bool> insert( const value_type& value )
+    {
+        for (auto it = this->begin(); it != this->end(); ++it)
+        {
+            if (m_compare(it->first, value.first))
+            {
+                return {it, false};
+            }
+        }
+        Container::push_back(value);
+        return {--this->end(), true};
+    }
+
+    template<typename InputIt>
+    using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
+            std::input_iterator_tag>::value>::type;
+
+    template<typename InputIt, typename = require_input_iter<InputIt>>
+    void insert(InputIt first, InputIt last)
+    {
+        for (auto it = first; it != last; ++it)
+        {
+            insert(*it);
+        }
+    }
+
+private:
+    JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();
+};
+
+NLOHMANN_JSON_NAMESPACE_END
+
+
+#if defined(JSON_HAS_CPP_17)
+    #include <any>
+    #include <string_view>
+#endif
+
+/*!
+@brief namespace for Niels Lohmann
+@see https://github.com/nlohmann
+@since version 1.0.0
+*/
+NLOHMANN_JSON_NAMESPACE_BEGIN
+
+/*!
+@brief a class to store JSON values
+
+@internal
+@invariant The member variables @a m_value and @a m_type have the following
+relationship:
+- If `m_type == value_t::object`, then `m_value.object != nullptr`.
+- If `m_type == value_t::array`, then `m_value.array != nullptr`.
+- If `m_type == value_t::string`, then `m_value.string != nullptr`.
+The invariants are checked by member function assert_invariant().
+
+@note ObjectType trick from https://stackoverflow.com/a/9860911
+@endinternal
+
+@since version 1.0.0
+
+@nosubgrouping
+*/
+NLOHMANN_BASIC_JSON_TPL_DECLARATION
+class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
+{
+  private:
+    template<detail::value_t> friend struct detail::external_constructor;
+
+    template<typename>
+    friend class ::nlohmann::json_pointer;
+    // can be restored when json_pointer backwards compatibility is removed
+    // friend ::nlohmann::json_pointer<StringType>;
+
+    template<typename BasicJsonType, typename InputType>
+    friend class ::nlohmann::detail::parser;
+    friend ::nlohmann::detail::serializer<basic_json>;
+    template<typename BasicJsonType>
+    friend class ::nlohmann::detail::iter_impl;
+    template<typename BasicJsonType, typename CharType>
+    friend class ::nlohmann::detail::binary_writer;
+    template<typename BasicJsonType, typename InputType, typename SAX>
+    friend class ::nlohmann::detail::binary_reader;
+    template<typename BasicJsonType>
+    friend class ::nlohmann::detail::json_sax_dom_parser;
+    template<typename BasicJsonType>
+    friend class ::nlohmann::detail::json_sax_dom_callback_parser;
+    friend class ::nlohmann::detail::exception;
+
+    /// workaround type for MSVC
+    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    // convenience aliases for types residing in namespace detail;
+    using lexer = ::nlohmann::detail::lexer_base<basic_json>;
+
+    template<typename InputAdapterType>
+    static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(
+        InputAdapterType adapter,
+        detail::parser_callback_t<basic_json>cb = nullptr,
+        const bool allow_exceptions = true,
+        const bool ignore_comments = false
+                                 )
+    {
+        return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
+                std::move(cb), allow_exceptions, ignore_comments);
+    }
+
+  private:
+    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
+    template<typename BasicJsonType>
+    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
+    template<typename BasicJsonType>
+    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
+    template<typename Iterator>
+    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
+    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
+
+    template<typename CharType>
+    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
+
+    template<typename InputType>
+    using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;
+    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    using serializer = ::nlohmann::detail::serializer<basic_json>;
+
+  public:
+    using value_t = detail::value_t;
+    /// JSON Pointer, see @ref nlohmann::json_pointer
+    using json_pointer = ::nlohmann::json_pointer<StringType>;
+    template<typename T, typename SFINAE>
+    using json_serializer = JSONSerializer<T, SFINAE>;
+    /// how to treat decoding errors
+    using error_handler_t = detail::error_handler_t;
+    /// how to treat CBOR tags
+    using cbor_tag_handler_t = detail::cbor_tag_handler_t;
+    /// helper type for initializer lists of basic_json values
+    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
+
+    using input_format_t = detail::input_format_t;
+    /// SAX interface type, see @ref nlohmann::json_sax
+    using json_sax_t = json_sax<basic_json>;
+
+    ////////////////
+    // exceptions //
+    ////////////////
+
+    /// @name exceptions
+    /// Classes to implement user-defined exceptions.
+    /// @{
+
+    using exception = detail::exception;
+    using parse_error = detail::parse_error;
+    using invalid_iterator = detail::invalid_iterator;
+    using type_error = detail::type_error;
+    using out_of_range = detail::out_of_range;
+    using other_error = detail::other_error;
+
+    /// @}
+
+
+    /////////////////////
+    // container types //
+    /////////////////////
+
+    /// @name container types
+    /// The canonic container types to use @ref basic_json like any other STL
+    /// container.
+    /// @{
+
+    /// the type of elements in a basic_json container
+    using value_type = basic_json;
+
+    /// the type of an element reference
+    using reference = value_type&;
+    /// the type of an element const reference
+    using const_reference = const value_type&;
+
+    /// a type to represent differences between iterators
+    using difference_type = std::ptrdiff_t;
+    /// a type to represent container sizes
+    using size_type = std::size_t;
+
+    /// the allocator type
+    using allocator_type = AllocatorType<basic_json>;
+
+    /// the type of an element pointer
+    using pointer = typename std::allocator_traits<allocator_type>::pointer;
+    /// the type of an element const pointer
+    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
+
+    /// an iterator for a basic_json container
+    using iterator = iter_impl<basic_json>;
+    /// a const iterator for a basic_json container
+    using const_iterator = iter_impl<const basic_json>;
+    /// a reverse iterator for a basic_json container
+    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
+    /// a const reverse iterator for a basic_json container
+    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
+
+    /// @}
+
+
+    /// @brief returns the allocator associated with the container
+    /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/
+    static allocator_type get_allocator()
+    {
+        return allocator_type();
+    }
+
+    /// @brief returns version information on the library
+    /// @sa https://json.nlohmann.me/api/basic_json/meta/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json meta()
+    {
+        basic_json result;
+
+        result["copyright"] = "(C) 2013-2022 Niels Lohmann";
+        result["name"] = "JSON for Modern C++";
+        result["url"] = "https://github.com/nlohmann/json";
+        result["version"]["string"] =
+            detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.',
+                           std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.',
+                           std::to_string(NLOHMANN_JSON_VERSION_PATCH));
+        result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
+        result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
+        result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
+
+#ifdef _WIN32
+        result["platform"] = "win32";
+#elif defined __linux__
+        result["platform"] = "linux";
+#elif defined __APPLE__
+        result["platform"] = "apple";
+#elif defined __unix__
+        result["platform"] = "unix";
+#else
+        result["platform"] = "unknown";
+#endif
+
+#if defined(__ICC) || defined(__INTEL_COMPILER)
+        result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
+#elif defined(__clang__)
+        result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
+#elif defined(__GNUC__) || defined(__GNUG__)
+        result["compiler"] = {{"family", "gcc"}, {"version", detail::concat(
+                    std::to_string(__GNUC__), '.',
+                    std::to_string(__GNUC_MINOR__), '.',
+                    std::to_string(__GNUC_PATCHLEVEL__))
+            }
+        };
+#elif defined(__HP_cc) || defined(__HP_aCC)
+        result["compiler"] = "hp"
+#elif defined(__IBMCPP__)
+        result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
+#elif defined(_MSC_VER)
+        result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
+#elif defined(__PGI)
+        result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
+#elif defined(__SUNPRO_CC)
+        result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
+#else
+        result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
+#endif
+
+
+#if defined(_MSVC_LANG)
+        result["compiler"]["c++"] = std::to_string(_MSVC_LANG);
+#elif defined(__cplusplus)
+        result["compiler"]["c++"] = std::to_string(__cplusplus);
+#else
+        result["compiler"]["c++"] = "unknown";
+#endif
+        return result;
+    }
+
+
+    ///////////////////////////
+    // JSON value data types //
+    ///////////////////////////
+
+    /// @name JSON value data types
+    /// The data types to store a JSON value. These types are derived from
+    /// the template arguments passed to class @ref basic_json.
+    /// @{
+
+    /// @brief default object key comparator type
+    /// The actual object key comparator type (@ref object_comparator_t) may be
+    /// different.
+    /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
+#if defined(JSON_HAS_CPP_14)
+    // use of transparent comparator avoids unnecessary repeated construction of temporaries
+    // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
+    using default_object_comparator_t = std::less<>;
+#else
+    using default_object_comparator_t = std::less<StringType>;
+#endif
+
+    /// @brief a type for an object
+    /// @sa https://json.nlohmann.me/api/basic_json/object_t/
+    using object_t = ObjectType<StringType,
+          basic_json,
+          default_object_comparator_t,
+          AllocatorType<std::pair<const StringType,
+          basic_json>>>;
+
+    /// @brief a type for an array
+    /// @sa https://json.nlohmann.me/api/basic_json/array_t/
+    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
+
+    /// @brief a type for a string
+    /// @sa https://json.nlohmann.me/api/basic_json/string_t/
+    using string_t = StringType;
+
+    /// @brief a type for a boolean
+    /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/
+    using boolean_t = BooleanType;
+
+    /// @brief a type for a number (integer)
+    /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/
+    using number_integer_t = NumberIntegerType;
+
+    /// @brief a type for a number (unsigned)
+    /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/
+    using number_unsigned_t = NumberUnsignedType;
+
+    /// @brief a type for a number (floating-point)
+    /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/
+    using number_float_t = NumberFloatType;
+
+    /// @brief a type for a packed binary type
+    /// @sa https://json.nlohmann.me/api/basic_json/binary_t/
+    using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
+
+    /// @brief object key comparator type
+    /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
+    using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
+
+    /// @}
+
+  private:
+
+    /// helper for exception-safe object creation
+    template<typename T, typename... Args>
+    JSON_HEDLEY_RETURNS_NON_NULL
+    static T* create(Args&& ... args)
+    {
+        AllocatorType<T> alloc;
+        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
+
+        auto deleter = [&](T * obj)
+        {
+            AllocatorTraits::deallocate(alloc, obj, 1);
+        };
+        std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);
+        AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);
+        JSON_ASSERT(obj != nullptr);
+        return obj.release();
+    }
+
+    ////////////////////////
+    // JSON value storage //
+    ////////////////////////
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    /*!
+    @brief a JSON value
+
+    The actual storage for a JSON value of the @ref basic_json class. This
+    union combines the different storage types for the JSON value types
+    defined in @ref value_t.
+
+    JSON type | value_t type    | used type
+    --------- | --------------- | ------------------------
+    object    | object          | pointer to @ref object_t
+    array     | array           | pointer to @ref array_t
+    string    | string          | pointer to @ref string_t
+    boolean   | boolean         | @ref boolean_t
+    number    | number_integer  | @ref number_integer_t
+    number    | number_unsigned | @ref number_unsigned_t
+    number    | number_float    | @ref number_float_t
+    binary    | binary          | pointer to @ref binary_t
+    null      | null            | *no value is stored*
+
+    @note Variable-length types (objects, arrays, and strings) are stored as
+    pointers. The size of the union should not exceed 64 bits if the default
+    value types are used.
+
+    @since version 1.0.0
+    */
+    union json_value
+    {
+        /// object (stored with pointer to save storage)
+        object_t* object;
+        /// array (stored with pointer to save storage)
+        array_t* array;
+        /// string (stored with pointer to save storage)
+        string_t* string;
+        /// binary (stored with pointer to save storage)
+        binary_t* binary;
+        /// boolean
+        boolean_t boolean;
+        /// number (integer)
+        number_integer_t number_integer;
+        /// number (unsigned integer)
+        number_unsigned_t number_unsigned;
+        /// number (floating-point)
+        number_float_t number_float;
+
+        /// default constructor (for null values)
+        json_value() = default;
+        /// constructor for booleans
+        json_value(boolean_t v) noexcept : boolean(v) {}
+        /// constructor for numbers (integer)
+        json_value(number_integer_t v) noexcept : number_integer(v) {}
+        /// constructor for numbers (unsigned)
+        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
+        /// constructor for numbers (floating-point)
+        json_value(number_float_t v) noexcept : number_float(v) {}
+        /// constructor for empty values of a given type
+        json_value(value_t t)
+        {
+            switch (t)
+            {
+                case value_t::object:
+                {
+                    object = create<object_t>();
+                    break;
+                }
+
+                case value_t::array:
+                {
+                    array = create<array_t>();
+                    break;
+                }
+
+                case value_t::string:
+                {
+                    string = create<string_t>("");
+                    break;
+                }
+
+                case value_t::binary:
+                {
+                    binary = create<binary_t>();
+                    break;
+                }
+
+                case value_t::boolean:
+                {
+                    boolean = static_cast<boolean_t>(false);
+                    break;
+                }
+
+                case value_t::number_integer:
+                {
+                    number_integer = static_cast<number_integer_t>(0);
+                    break;
+                }
+
+                case value_t::number_unsigned:
+                {
+                    number_unsigned = static_cast<number_unsigned_t>(0);
+                    break;
+                }
+
+                case value_t::number_float:
+                {
+                    number_float = static_cast<number_float_t>(0.0);
+                    break;
+                }
+
+                case value_t::null:
+                {
+                    object = nullptr;  // silence warning, see #821
+                    break;
+                }
+
+                case value_t::discarded:
+                default:
+                {
+                    object = nullptr;  // silence warning, see #821
+                    if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
+                    {
+                        JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.2", nullptr)); // LCOV_EXCL_LINE
+                    }
+                    break;
+                }
+            }
+        }
+
+        /// constructor for strings
+        json_value(const string_t& value) : string(create<string_t>(value)) {}
+
+        /// constructor for rvalue strings
+        json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
+
+        /// constructor for objects
+        json_value(const object_t& value) : object(create<object_t>(value)) {}
+
+        /// constructor for rvalue objects
+        json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
+
+        /// constructor for arrays
+        json_value(const array_t& value) : array(create<array_t>(value)) {}
+
+        /// constructor for rvalue arrays
+        json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
+
+        /// constructor for binary arrays
+        json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
+
+        /// constructor for rvalue binary arrays
+        json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
+
+        /// constructor for binary arrays (internal type)
+        json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
+
+        /// constructor for rvalue binary arrays (internal type)
+        json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
+
+        void destroy(value_t t)
+        {
+            if (t == value_t::array || t == value_t::object)
+            {
+                // flatten the current json_value to a heap-allocated stack
+                std::vector<basic_json> stack;
+
+                // move the top-level items to stack
+                if (t == value_t::array)
+                {
+                    stack.reserve(array->size());
+                    std::move(array->begin(), array->end(), std::back_inserter(stack));
+                }
+                else
+                {
+                    stack.reserve(object->size());
+                    for (auto&& it : *object)
+                    {
+                        stack.push_back(std::move(it.second));
+                    }
+                }
+
+                while (!stack.empty())
+                {
+                    // move the last item to local variable to be processed
+                    basic_json current_item(std::move(stack.back()));
+                    stack.pop_back();
+
+                    // if current_item is array/object, move
+                    // its children to the stack to be processed later
+                    if (current_item.is_array())
+                    {
+                        std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack));
+
+                        current_item.m_value.array->clear();
+                    }
+                    else if (current_item.is_object())
+                    {
+                        for (auto&& it : *current_item.m_value.object)
+                        {
+                            stack.push_back(std::move(it.second));
+                        }
+
+                        current_item.m_value.object->clear();
+                    }
+
+                    // it's now safe that current_item get destructed
+                    // since it doesn't have any children
+                }
+            }
+
+            switch (t)
+            {
+                case value_t::object:
+                {
+                    AllocatorType<object_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
+                    break;
+                }
+
+                case value_t::array:
+                {
+                    AllocatorType<array_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
+                    break;
+                }
+
+                case value_t::string:
+                {
+                    AllocatorType<string_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
+                    break;
+                }
+
+                case value_t::binary:
+                {
+                    AllocatorType<binary_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
+                    break;
+                }
+
+                case value_t::null:
+                case value_t::boolean:
+                case value_t::number_integer:
+                case value_t::number_unsigned:
+                case value_t::number_float:
+                case value_t::discarded:
+                default:
+                {
+                    break;
+                }
+            }
+        }
+    };
+
+  private:
+    /*!
+    @brief checks the class invariants
+
+    This function asserts the class invariants. It needs to be called at the
+    end of every constructor to make sure that created objects respect the
+    invariant. Furthermore, it has to be called each time the type of a JSON
+    value is changed, because the invariant expresses a relationship between
+    @a m_type and @a m_value.
+
+    Furthermore, the parent relation is checked for arrays and objects: If
+    @a check_parents true and the value is an array or object, then the
+    container's elements must have the current value as parent.
+
+    @param[in] check_parents  whether the parent relation should be checked.
+               The value is true by default and should only be set to false
+               during destruction of objects when the invariant does not
+               need to hold.
+    */
+    void assert_invariant(bool check_parents = true) const noexcept
+    {
+        JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);
+        JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);
+        JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);
+        JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);
+
+#if JSON_DIAGNOSTICS
+        JSON_TRY
+        {
+            // cppcheck-suppress assertWithSideEffect
+            JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)
+            {
+                return j.m_parent == this;
+            }));
+        }
+        JSON_CATCH(...) {} // LCOV_EXCL_LINE
+#endif
+        static_cast<void>(check_parents);
+    }
+
+    void set_parents()
+    {
+#if JSON_DIAGNOSTICS
+        switch (m_type)
+        {
+            case value_t::array:
+            {
+                for (auto& element : *m_value.array)
+                {
+                    element.m_parent = this;
+                }
+                break;
+            }
+
+            case value_t::object:
+            {
+                for (auto& element : *m_value.object)
+                {
+                    element.second.m_parent = this;
+                }
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                break;
+        }
+#endif
+    }
+
+    iterator set_parents(iterator it, typename iterator::difference_type count_set_parents)
+    {
+#if JSON_DIAGNOSTICS
+        for (typename iterator::difference_type i = 0; i < count_set_parents; ++i)
+        {
+            (it + i)->m_parent = this;
+        }
+#else
+        static_cast<void>(count_set_parents);
+#endif
+        return it;
+    }
+
+    reference set_parent(reference j, std::size_t old_capacity = static_cast<std::size_t>(-1))
+    {
+#if JSON_DIAGNOSTICS
+        if (old_capacity != static_cast<std::size_t>(-1))
+        {
+            // see https://github.com/nlohmann/json/issues/2838
+            JSON_ASSERT(type() == value_t::array);
+            if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
+            {
+                // capacity has changed: update all parents
+                set_parents();
+                return j;
+            }
+        }
+
+        // ordered_json uses a vector internally, so pointers could have
+        // been invalidated; see https://github.com/nlohmann/json/issues/2962
+#ifdef JSON_HEDLEY_MSVC_VERSION
+#pragma warning(push )
+#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr
+#endif
+        if (detail::is_ordered_map<object_t>::value)
+        {
+            set_parents();
+            return j;
+        }
+#ifdef JSON_HEDLEY_MSVC_VERSION
+#pragma warning( pop )
+#endif
+
+        j.m_parent = this;
+#else
+        static_cast<void>(j);
+        static_cast<void>(old_capacity);
+#endif
+        return j;
+    }
+
+  public:
+    //////////////////////////
+    // JSON parser callback //
+    //////////////////////////
+
+    /// @brief parser event types
+    /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/
+    using parse_event_t = detail::parse_event_t;
+
+    /// @brief per-element parser callback type
+    /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/
+    using parser_callback_t = detail::parser_callback_t<basic_json>;
+
+    //////////////////
+    // constructors //
+    //////////////////
+
+    /// @name constructors and destructors
+    /// Constructors of class @ref basic_json, copy/move constructor, copy
+    /// assignment, static functions creating objects, and the destructor.
+    /// @{
+
+    /// @brief create an empty value with a given type
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(const value_t v)
+        : m_type(v), m_value(v)
+    {
+        assert_invariant();
+    }
+
+    /// @brief create a null object
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape)
+        : basic_json(value_t::null)
+    {
+        assert_invariant();
+    }
+
+    /// @brief create a JSON value from compatible types
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    template < typename CompatibleType,
+               typename U = detail::uncvref_t<CompatibleType>,
+               detail::enable_if_t <
+                   !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
+    basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
+                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
+                                           std::forward<CompatibleType>(val))))
+    {
+        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
+        set_parents();
+        assert_invariant();
+    }
+
+    /// @brief create a JSON value from an existing one
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    template < typename BasicJsonType,
+               detail::enable_if_t <
+                   detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
+    basic_json(const BasicJsonType& val)
+    {
+        using other_boolean_t = typename BasicJsonType::boolean_t;
+        using other_number_float_t = typename BasicJsonType::number_float_t;
+        using other_number_integer_t = typename BasicJsonType::number_integer_t;
+        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+        using other_string_t = typename BasicJsonType::string_t;
+        using other_object_t = typename BasicJsonType::object_t;
+        using other_array_t = typename BasicJsonType::array_t;
+        using other_binary_t = typename BasicJsonType::binary_t;
+
+        switch (val.type())
+        {
+            case value_t::boolean:
+                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
+                break;
+            case value_t::number_float:
+                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
+                break;
+            case value_t::number_integer:
+                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
+                break;
+            case value_t::number_unsigned:
+                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
+                break;
+            case value_t::string:
+                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
+                break;
+            case value_t::object:
+                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
+                break;
+            case value_t::array:
+                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
+                break;
+            case value_t::binary:
+                JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
+                break;
+            case value_t::null:
+                *this = nullptr;
+                break;
+            case value_t::discarded:
+                m_type = value_t::discarded;
+                break;
+            default:            // LCOV_EXCL_LINE
+                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+        }
+        JSON_ASSERT(m_type == val.type());
+        set_parents();
+        assert_invariant();
+    }
+
+    /// @brief create a container (array or object) from an initializer list
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(initializer_list_t init,
+               bool type_deduction = true,
+               value_t manual_type = value_t::array)
+    {
+        // check if each element is an array with two elements whose first
+        // element is a string
+        bool is_an_object = std::all_of(init.begin(), init.end(),
+                                        [](const detail::json_ref<basic_json>& element_ref)
+        {
+            return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string();
+        });
+
+        // adjust type if type deduction is not wanted
+        if (!type_deduction)
+        {
+            // if array is wanted, do not create an object though possible
+            if (manual_type == value_t::array)
+            {
+                is_an_object = false;
+            }
+
+            // if object is wanted but impossible, throw an exception
+            if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
+            {
+                JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
+            }
+        }
+
+        if (is_an_object)
+        {
+            // the initializer list is a list of pairs -> create object
+            m_type = value_t::object;
+            m_value = value_t::object;
+
+            for (auto& element_ref : init)
+            {
+                auto element = element_ref.moved_or_copied();
+                m_value.object->emplace(
+                    std::move(*((*element.m_value.array)[0].m_value.string)),
+                    std::move((*element.m_value.array)[1]));
+            }
+        }
+        else
+        {
+            // the initializer list describes an array -> create array
+            m_type = value_t::array;
+            m_value.array = create<array_t>(init.begin(), init.end());
+        }
+
+        set_parents();
+        assert_invariant();
+    }
+
+    /// @brief explicitly create a binary array (without subtype)
+    /// @sa https://json.nlohmann.me/api/basic_json/binary/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json binary(const typename binary_t::container_type& init)
+    {
+        auto res = basic_json();
+        res.m_type = value_t::binary;
+        res.m_value = init;
+        return res;
+    }
+
+    /// @brief explicitly create a binary array (with subtype)
+    /// @sa https://json.nlohmann.me/api/basic_json/binary/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
+    {
+        auto res = basic_json();
+        res.m_type = value_t::binary;
+        res.m_value = binary_t(init, subtype);
+        return res;
+    }
+
+    /// @brief explicitly create a binary array
+    /// @sa https://json.nlohmann.me/api/basic_json/binary/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json binary(typename binary_t::container_type&& init)
+    {
+        auto res = basic_json();
+        res.m_type = value_t::binary;
+        res.m_value = std::move(init);
+        return res;
+    }
+
+    /// @brief explicitly create a binary array (with subtype)
+    /// @sa https://json.nlohmann.me/api/basic_json/binary/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
+    {
+        auto res = basic_json();
+        res.m_type = value_t::binary;
+        res.m_value = binary_t(std::move(init), subtype);
+        return res;
+    }
+
+    /// @brief explicitly create an array from an initializer list
+    /// @sa https://json.nlohmann.me/api/basic_json/array/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json array(initializer_list_t init = {})
+    {
+        return basic_json(init, false, value_t::array);
+    }
+
+    /// @brief explicitly create an object from an initializer list
+    /// @sa https://json.nlohmann.me/api/basic_json/object/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json object(initializer_list_t init = {})
+    {
+        return basic_json(init, false, value_t::object);
+    }
+
+    /// @brief construct an array with count copies of given value
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(size_type cnt, const basic_json& val)
+        : m_type(value_t::array)
+    {
+        m_value.array = create<array_t>(cnt, val);
+        set_parents();
+        assert_invariant();
+    }
+
+    /// @brief construct a JSON container given an iterator range
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    template < class InputIT, typename std::enable_if <
+                   std::is_same<InputIT, typename basic_json_t::iterator>::value ||
+                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
+    basic_json(InputIT first, InputIT last)
+    {
+        JSON_ASSERT(first.m_object != nullptr);
+        JSON_ASSERT(last.m_object != nullptr);
+
+        // make sure iterator fits the current value
+        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
+        }
+
+        // copy type from first iterator
+        m_type = first.m_object->m_type;
+
+        // check if iterator range is complete for primitive values
+        switch (m_type)
+        {
+            case value_t::boolean:
+            case value_t::number_float:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::string:
+            {
+                if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
+                                         || !last.m_it.primitive_iterator.is_end()))
+                {
+                    JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
+                }
+                break;
+            }
+
+            case value_t::null:
+            case value_t::object:
+            case value_t::array:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+                break;
+        }
+
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            {
+                m_value.number_integer = first.m_object->m_value.number_integer;
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                m_value.number_unsigned = first.m_object->m_value.number_unsigned;
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                m_value.number_float = first.m_object->m_value.number_float;
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                m_value.boolean = first.m_object->m_value.boolean;
+                break;
+            }
+
+            case value_t::string:
+            {
+                m_value = *first.m_object->m_value.string;
+                break;
+            }
+
+            case value_t::object:
+            {
+                m_value.object = create<object_t>(first.m_it.object_iterator,
+                                                  last.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_value.array = create<array_t>(first.m_it.array_iterator,
+                                                last.m_it.array_iterator);
+                break;
+            }
+
+            case value_t::binary:
+            {
+                m_value = *first.m_object->m_value.binary;
+                break;
+            }
+
+            case value_t::null:
+            case value_t::discarded:
+            default:
+                JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
+        }
+
+        set_parents();
+        assert_invariant();
+    }
+
+
+    ///////////////////////////////////////
+    // other constructors and destructor //
+    ///////////////////////////////////////
+
+    template<typename JsonRef,
+             detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
+                                 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
+    basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}
+
+    /// @brief copy constructor
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(const basic_json& other)
+        : m_type(other.m_type)
+    {
+        // check of passed value is valid
+        other.assert_invariant();
+
+        switch (m_type)
+        {
+            case value_t::object:
+            {
+                m_value = *other.m_value.object;
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_value = *other.m_value.array;
+                break;
+            }
+
+            case value_t::string:
+            {
+                m_value = *other.m_value.string;
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                m_value = other.m_value.boolean;
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                m_value = other.m_value.number_integer;
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                m_value = other.m_value.number_unsigned;
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                m_value = other.m_value.number_float;
+                break;
+            }
+
+            case value_t::binary:
+            {
+                m_value = *other.m_value.binary;
+                break;
+            }
+
+            case value_t::null:
+            case value_t::discarded:
+            default:
+                break;
+        }
+
+        set_parents();
+        assert_invariant();
+    }
+
+    /// @brief move constructor
+    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
+    basic_json(basic_json&& other) noexcept
+        : m_type(std::move(other.m_type)),
+          m_value(std::move(other.m_value))
+    {
+        // check that passed value is valid
+        other.assert_invariant(false);
+
+        // invalidate payload
+        other.m_type = value_t::null;
+        other.m_value = {};
+
+        set_parents();
+        assert_invariant();
+    }
+
+    /// @brief copy assignment
+    /// @sa https://json.nlohmann.me/api/basic_json/operator=/
+    basic_json& operator=(basic_json other) noexcept (
+        std::is_nothrow_move_constructible<value_t>::value&&
+        std::is_nothrow_move_assignable<value_t>::value&&
+        std::is_nothrow_move_constructible<json_value>::value&&
+        std::is_nothrow_move_assignable<json_value>::value
+    )
+    {
+        // check that passed value is valid
+        other.assert_invariant();
+
+        using std::swap;
+        swap(m_type, other.m_type);
+        swap(m_value, other.m_value);
+
+        set_parents();
+        assert_invariant();
+        return *this;
+    }
+
+    /// @brief destructor
+    /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/
+    ~basic_json() noexcept
+    {
+        assert_invariant(false);
+        m_value.destroy(m_type);
+    }
+
+    /// @}
+
+  public:
+    ///////////////////////
+    // object inspection //
+    ///////////////////////
+
+    /// @name object inspection
+    /// Functions to inspect the type of a JSON value.
+    /// @{
+
+    /// @brief serialization
+    /// @sa https://json.nlohmann.me/api/basic_json/dump/
+    string_t dump(const int indent = -1,
+                  const char indent_char = ' ',
+                  const bool ensure_ascii = false,
+                  const error_handler_t error_handler = error_handler_t::strict) const
+    {
+        string_t result;
+        serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
+
+        if (indent >= 0)
+        {
+            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
+        }
+        else
+        {
+            s.dump(*this, false, ensure_ascii, 0);
+        }
+
+        return result;
+    }
+
+    /// @brief return the type of the JSON value (explicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/type/
+    constexpr value_t type() const noexcept
+    {
+        return m_type;
+    }
+
+    /// @brief return whether type is primitive
+    /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
+    constexpr bool is_primitive() const noexcept
+    {
+        return is_null() || is_string() || is_boolean() || is_number() || is_binary();
+    }
+
+    /// @brief return whether type is structured
+    /// @sa https://json.nlohmann.me/api/basic_json/is_structured/
+    constexpr bool is_structured() const noexcept
+    {
+        return is_array() || is_object();
+    }
+
+    /// @brief return whether value is null
+    /// @sa https://json.nlohmann.me/api/basic_json/is_null/
+    constexpr bool is_null() const noexcept
+    {
+        return m_type == value_t::null;
+    }
+
+    /// @brief return whether value is a boolean
+    /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
+    constexpr bool is_boolean() const noexcept
+    {
+        return m_type == value_t::boolean;
+    }
+
+    /// @brief return whether value is a number
+    /// @sa https://json.nlohmann.me/api/basic_json/is_number/
+    constexpr bool is_number() const noexcept
+    {
+        return is_number_integer() || is_number_float();
+    }
+
+    /// @brief return whether value is an integer number
+    /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
+    constexpr bool is_number_integer() const noexcept
+    {
+        return m_type == value_t::number_integer || m_type == value_t::number_unsigned;
+    }
+
+    /// @brief return whether value is an unsigned integer number
+    /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
+    constexpr bool is_number_unsigned() const noexcept
+    {
+        return m_type == value_t::number_unsigned;
+    }
+
+    /// @brief return whether value is a floating-point number
+    /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
+    constexpr bool is_number_float() const noexcept
+    {
+        return m_type == value_t::number_float;
+    }
+
+    /// @brief return whether value is an object
+    /// @sa https://json.nlohmann.me/api/basic_json/is_object/
+    constexpr bool is_object() const noexcept
+    {
+        return m_type == value_t::object;
+    }
+
+    /// @brief return whether value is an array
+    /// @sa https://json.nlohmann.me/api/basic_json/is_array/
+    constexpr bool is_array() const noexcept
+    {
+        return m_type == value_t::array;
+    }
+
+    /// @brief return whether value is a string
+    /// @sa https://json.nlohmann.me/api/basic_json/is_string/
+    constexpr bool is_string() const noexcept
+    {
+        return m_type == value_t::string;
+    }
+
+    /// @brief return whether value is a binary array
+    /// @sa https://json.nlohmann.me/api/basic_json/is_binary/
+    constexpr bool is_binary() const noexcept
+    {
+        return m_type == value_t::binary;
+    }
+
+    /// @brief return whether value is discarded
+    /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
+    constexpr bool is_discarded() const noexcept
+    {
+        return m_type == value_t::discarded;
+    }
+
+    /// @brief return the type of the JSON value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/
+    constexpr operator value_t() const noexcept
+    {
+        return m_type;
+    }
+
+    /// @}
+
+  private:
+    //////////////////
+    // value access //
+    //////////////////
+
+    /// get a boolean (explicit)
+    boolean_t get_impl(boolean_t* /*unused*/) const
+    {
+        if (JSON_HEDLEY_LIKELY(is_boolean()))
+        {
+            return m_value.boolean;
+        }
+
+        JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
+    }
+
+    /// get a pointer to the value (object)
+    object_t* get_impl_ptr(object_t* /*unused*/) noexcept
+    {
+        return is_object() ? m_value.object : nullptr;
+    }
+
+    /// get a pointer to the value (object)
+    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
+    {
+        return is_object() ? m_value.object : nullptr;
+    }
+
+    /// get a pointer to the value (array)
+    array_t* get_impl_ptr(array_t* /*unused*/) noexcept
+    {
+        return is_array() ? m_value.array : nullptr;
+    }
+
+    /// get a pointer to the value (array)
+    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
+    {
+        return is_array() ? m_value.array : nullptr;
+    }
+
+    /// get a pointer to the value (string)
+    string_t* get_impl_ptr(string_t* /*unused*/) noexcept
+    {
+        return is_string() ? m_value.string : nullptr;
+    }
+
+    /// get a pointer to the value (string)
+    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
+    {
+        return is_string() ? m_value.string : nullptr;
+    }
+
+    /// get a pointer to the value (boolean)
+    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
+    {
+        return is_boolean() ? &m_value.boolean : nullptr;
+    }
+
+    /// get a pointer to the value (boolean)
+    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
+    {
+        return is_boolean() ? &m_value.boolean : nullptr;
+    }
+
+    /// get a pointer to the value (integer number)
+    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
+    {
+        return is_number_integer() ? &m_value.number_integer : nullptr;
+    }
+
+    /// get a pointer to the value (integer number)
+    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
+    {
+        return is_number_integer() ? &m_value.number_integer : nullptr;
+    }
+
+    /// get a pointer to the value (unsigned number)
+    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
+    {
+        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
+    }
+
+    /// get a pointer to the value (unsigned number)
+    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
+    {
+        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
+    }
+
+    /// get a pointer to the value (floating-point number)
+    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
+    {
+        return is_number_float() ? &m_value.number_float : nullptr;
+    }
+
+    /// get a pointer to the value (floating-point number)
+    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
+    {
+        return is_number_float() ? &m_value.number_float : nullptr;
+    }
+
+    /// get a pointer to the value (binary)
+    binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
+    {
+        return is_binary() ? m_value.binary : nullptr;
+    }
+
+    /// get a pointer to the value (binary)
+    constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
+    {
+        return is_binary() ? m_value.binary : nullptr;
+    }
+
+    /*!
+    @brief helper function to implement get_ref()
+
+    This function helps to implement get_ref() without code duplication for
+    const and non-const overloads
+
+    @tparam ThisType will be deduced as `basic_json` or `const basic_json`
+
+    @throw type_error.303 if ReferenceType does not match underlying value
+    type of the current JSON
+    */
+    template<typename ReferenceType, typename ThisType>
+    static ReferenceType get_ref_impl(ThisType& obj)
+    {
+        // delegate the call to get_ptr<>()
+        auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
+
+        if (JSON_HEDLEY_LIKELY(ptr != nullptr))
+        {
+            return *ptr;
+        }
+
+        JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
+    }
+
+  public:
+    /// @name value access
+    /// Direct access to the stored value of a JSON value.
+    /// @{
+
+    /// @brief get a pointer value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
+    auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
+    {
+        // delegate the call to get_impl_ptr<>()
+        return get_impl_ptr(static_cast<PointerType>(nullptr));
+    }
+
+    /// @brief get a pointer value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
+    template < typename PointerType, typename std::enable_if <
+                   std::is_pointer<PointerType>::value&&
+                   std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
+    constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
+    {
+        // delegate the call to get_impl_ptr<>() const
+        return get_impl_ptr(static_cast<PointerType>(nullptr));
+    }
+
+  private:
+    /*!
+    @brief get a value (explicit)
+
+    Explicit type conversion between the JSON value and a compatible value
+    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
+    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
+    The value is converted by calling the @ref json_serializer<ValueType>
+    `from_json()` method.
+
+    The function is equivalent to executing
+    @code {.cpp}
+    ValueType ret;
+    JSONSerializer<ValueType>::from_json(*this, ret);
+    return ret;
+    @endcode
+
+    This overloads is chosen if:
+    - @a ValueType is not @ref basic_json,
+    - @ref json_serializer<ValueType> has a `from_json()` method of the form
+      `void from_json(const basic_json&, ValueType&)`, and
+    - @ref json_serializer<ValueType> does not have a `from_json()` method of
+      the form `ValueType from_json(const basic_json&)`
+
+    @tparam ValueType the returned value type
+
+    @return copy of the JSON value, converted to @a ValueType
+
+    @throw what @ref json_serializer<ValueType> `from_json()` method throws
+
+    @liveexample{The example below shows several conversions from JSON values
+    to other types. There a few things to note: (1) Floating-point numbers can
+    be converted to integers\, (2) A JSON array can be converted to a standard
+    `std::vector<short>`\, (3) A JSON object can be converted to C++
+    associative containers such as `std::unordered_map<std::string\,
+    json>`.,get__ValueType_const}
+
+    @since version 2.1.0
+    */
+    template < typename ValueType,
+               detail::enable_if_t <
+                   detail::is_default_constructible<ValueType>::value&&
+                   detail::has_from_json<basic_json_t, ValueType>::value,
+                   int > = 0 >
+    ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(
+                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
+    {
+        auto ret = ValueType();
+        JSONSerializer<ValueType>::from_json(*this, ret);
+        return ret;
+    }
+
+    /*!
+    @brief get a value (explicit); special case
+
+    Explicit type conversion between the JSON value and a compatible value
+    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
+    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
+    The value is converted by calling the @ref json_serializer<ValueType>
+    `from_json()` method.
+
+    The function is equivalent to executing
+    @code {.cpp}
+    return JSONSerializer<ValueType>::from_json(*this);
+    @endcode
+
+    This overloads is chosen if:
+    - @a ValueType is not @ref basic_json and
+    - @ref json_serializer<ValueType> has a `from_json()` method of the form
+      `ValueType from_json(const basic_json&)`
+
+    @note If @ref json_serializer<ValueType> has both overloads of
+    `from_json()`, this one is chosen.
+
+    @tparam ValueType the returned value type
+
+    @return copy of the JSON value, converted to @a ValueType
+
+    @throw what @ref json_serializer<ValueType> `from_json()` method throws
+
+    @since version 2.1.0
+    */
+    template < typename ValueType,
+               detail::enable_if_t <
+                   detail::has_non_default_from_json<basic_json_t, ValueType>::value,
+                   int > = 0 >
+    ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(
+                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
+    {
+        return JSONSerializer<ValueType>::from_json(*this);
+    }
+
+    /*!
+    @brief get special-case overload
+
+    This overloads converts the current @ref basic_json in a different
+    @ref basic_json type
+
+    @tparam BasicJsonType == @ref basic_json
+
+    @return a copy of *this, converted into @a BasicJsonType
+
+    @complexity Depending on the implementation of the called `from_json()`
+                method.
+
+    @since version 3.2.0
+    */
+    template < typename BasicJsonType,
+               detail::enable_if_t <
+                   detail::is_basic_json<BasicJsonType>::value,
+                   int > = 0 >
+    BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
+    {
+        return *this;
+    }
+
+    /*!
+    @brief get special-case overload
+
+    This overloads avoids a lot of template boilerplate, it can be seen as the
+    identity method
+
+    @tparam BasicJsonType == @ref basic_json
+
+    @return a copy of *this
+
+    @complexity Constant.
+
+    @since version 2.1.0
+    */
+    template<typename BasicJsonType,
+             detail::enable_if_t<
+                 std::is_same<BasicJsonType, basic_json_t>::value,
+                 int> = 0>
+    basic_json get_impl(detail::priority_tag<3> /*unused*/) const
+    {
+        return *this;
+    }
+
+    /*!
+    @brief get a pointer value (explicit)
+    @copydoc get()
+    */
+    template<typename PointerType,
+             detail::enable_if_t<
+                 std::is_pointer<PointerType>::value,
+                 int> = 0>
+    constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept
+    -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
+    {
+        // delegate the call to get_ptr
+        return get_ptr<PointerType>();
+    }
+
+  public:
+    /*!
+    @brief get a (pointer) value (explicit)
+
+    Performs explicit type conversion between the JSON value and a compatible value if required.
+
+    - If the requested type is a pointer to the internally stored JSON value that pointer is returned.
+    No copies are made.
+
+    - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible
+    from the current @ref basic_json.
+
+    - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()`
+    method.
+
+    @tparam ValueTypeCV the provided value type
+    @tparam ValueType the returned value type
+
+    @return copy of the JSON value, converted to @tparam ValueType if necessary
+
+    @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
+
+    @since version 2.1.0
+    */
+    template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
+#if defined(JSON_HAS_CPP_14)
+    constexpr
+#endif
+    auto get() const noexcept(
+    noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))
+    -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))
+    {
+        // we cannot static_assert on ValueTypeCV being non-const, because
+        // there is support for get<const basic_json_t>(), which is why we
+        // still need the uncvref
+        static_assert(!std::is_reference<ValueTypeCV>::value,
+                      "get() cannot be used with reference types, you might want to use get_ref()");
+        return get_impl<ValueType>(detail::priority_tag<4> {});
+    }
+
+    /*!
+    @brief get a pointer value (explicit)
+
+    Explicit pointer access to the internally stored JSON value. No copies are
+    made.
+
+    @warning The pointer becomes invalid if the underlying JSON object
+    changes.
+
+    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
+    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
+    @ref number_unsigned_t, or @ref number_float_t.
+
+    @return pointer to the internally stored JSON value if the requested
+    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how pointers to internal values of a
+    JSON value can be requested. Note that no type conversions are made and a
+    `nullptr` is returned if the value and the requested pointer type does not
+    match.,get__PointerType}
+
+    @sa see @ref get_ptr() for explicit pointer-member access
+
+    @since version 1.0.0
+    */
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
+    auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
+    {
+        // delegate the call to get_ptr
+        return get_ptr<PointerType>();
+    }
+
+    /// @brief get a value (explicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_to/
+    template < typename ValueType,
+               detail::enable_if_t <
+                   !detail::is_basic_json<ValueType>::value&&
+                   detail::has_from_json<basic_json_t, ValueType>::value,
+                   int > = 0 >
+    ValueType & get_to(ValueType& v) const noexcept(noexcept(
+                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
+    {
+        JSONSerializer<ValueType>::from_json(*this, v);
+        return v;
+    }
+
+    // specialization to allow calling get_to with a basic_json value
+    // see https://github.com/nlohmann/json/issues/2175
+    template<typename ValueType,
+             detail::enable_if_t <
+                 detail::is_basic_json<ValueType>::value,
+                 int> = 0>
+    ValueType & get_to(ValueType& v) const
+    {
+        v = *this;
+        return v;
+    }
+
+    template <
+        typename T, std::size_t N,
+        typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+        detail::enable_if_t <
+            detail::has_from_json<basic_json_t, Array>::value, int > = 0 >
+    Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
+    noexcept(noexcept(JSONSerializer<Array>::from_json(
+                          std::declval<const basic_json_t&>(), v)))
+    {
+        JSONSerializer<Array>::from_json(*this, v);
+        return v;
+    }
+
+    /// @brief get a reference value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
+    template<typename ReferenceType, typename std::enable_if<
+                 std::is_reference<ReferenceType>::value, int>::type = 0>
+    ReferenceType get_ref()
+    {
+        // delegate call to get_ref_impl
+        return get_ref_impl<ReferenceType>(*this);
+    }
+
+    /// @brief get a reference value (implicit)
+    /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
+    template < typename ReferenceType, typename std::enable_if <
+                   std::is_reference<ReferenceType>::value&&
+                   std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
+    ReferenceType get_ref() const
+    {
+        // delegate call to get_ref_impl
+        return get_ref_impl<ReferenceType>(*this);
+    }
+
+    /*!
+    @brief get a value (implicit)
+
+    Implicit type conversion between the JSON value and a compatible value.
+    The call is realized by calling @ref get() const.
+
+    @tparam ValueType non-pointer type compatible to the JSON value, for
+    instance `int` for JSON integer numbers, `bool` for JSON booleans, or
+    `std::vector` types for JSON arrays. The character type of @ref string_t
+    as well as an initializer list of this type is excluded to avoid
+    ambiguities as these types implicitly convert to `std::string`.
+
+    @return copy of the JSON value, converted to type @a ValueType
+
+    @throw type_error.302 in case passed type @a ValueType is incompatible
+    to the JSON value type (e.g., the JSON value is of type boolean, but a
+    string is requested); see example below
+
+    @complexity Linear in the size of the JSON value.
+
+    @liveexample{The example below shows several conversions from JSON values
+    to other types. There a few things to note: (1) Floating-point numbers can
+    be converted to integers\, (2) A JSON array can be converted to a standard
+    `std::vector<short>`\, (3) A JSON object can be converted to C++
+    associative containers such as `std::unordered_map<std::string\,
+    json>`.,operator__ValueType}
+
+    @since version 1.0.0
+    */
+    template < typename ValueType, typename std::enable_if <
+                   detail::conjunction <
+                       detail::negation<std::is_pointer<ValueType>>,
+                       detail::negation<std::is_same<ValueType, std::nullptr_t>>,
+                       detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,
+                                        detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
+                                        detail::negation<detail::is_basic_json<ValueType>>,
+                                        detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,
+#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
+                                                detail::negation<std::is_same<ValueType, std::string_view>>,
+#endif
+#if defined(JSON_HAS_CPP_17)
+                                                detail::negation<std::is_same<ValueType, std::any>>,
+#endif
+                                                detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
+                                                >::value, int >::type = 0 >
+                                        JSON_EXPLICIT operator ValueType() const
+    {
+        // delegate the call to get<>() const
+        return get<ValueType>();
+    }
+
+    /// @brief get a binary value
+    /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
+    binary_t& get_binary()
+    {
+        if (!is_binary())
+        {
+            JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
+        }
+
+        return *get_ptr<binary_t*>();
+    }
+
+    /// @brief get a binary value
+    /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
+    const binary_t& get_binary() const
+    {
+        if (!is_binary())
+        {
+            JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
+        }
+
+        return *get_ptr<const binary_t*>();
+    }
+
+    /// @}
+
+
+    ////////////////////
+    // element access //
+    ////////////////////
+
+    /// @name element access
+    /// Access to the JSON value.
+    /// @{
+
+    /// @brief access specified array element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    reference at(size_type idx)
+    {
+        // at only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            JSON_TRY
+            {
+                return set_parent(m_value.array->at(idx));
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                // create better exception explanation
+                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
+            }
+        }
+        else
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+    }
+
+    /// @brief access specified array element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    const_reference at(size_type idx) const
+    {
+        // at only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            JSON_TRY
+            {
+                return m_value.array->at(idx);
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                // create better exception explanation
+                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
+            }
+        }
+        else
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+    }
+
+    /// @brief access specified object element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    reference at(const typename object_t::key_type& key)
+    {
+        // at only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+
+        auto it = m_value.object->find(key);
+        if (it == m_value.object->end())
+        {
+            JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
+        }
+        return set_parent(it->second);
+    }
+
+    /// @brief access specified object element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    reference at(KeyType && key)
+    {
+        // at only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+
+        auto it = m_value.object->find(std::forward<KeyType>(key));
+        if (it == m_value.object->end())
+        {
+            JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
+        }
+        return set_parent(it->second);
+    }
+
+    /// @brief access specified object element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    const_reference at(const typename object_t::key_type& key) const
+    {
+        // at only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+
+        auto it = m_value.object->find(key);
+        if (it == m_value.object->end())
+        {
+            JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
+        }
+        return it->second;
+    }
+
+    /// @brief access specified object element with bounds checking
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    const_reference at(KeyType && key) const
+    {
+        // at only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
+        }
+
+        auto it = m_value.object->find(std::forward<KeyType>(key));
+        if (it == m_value.object->end())
+        {
+            JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
+        }
+        return it->second;
+    }
+
+    /// @brief access specified array element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    reference operator[](size_type idx)
+    {
+        // implicitly convert null value to an empty array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value.array = create<array_t>();
+            assert_invariant();
+        }
+
+        // operator[] only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            // fill up array with null values if given idx is outside range
+            if (idx >= m_value.array->size())
+            {
+#if JSON_DIAGNOSTICS
+                // remember array size & capacity before resizing
+                const auto old_size = m_value.array->size();
+                const auto old_capacity = m_value.array->capacity();
+#endif
+                m_value.array->resize(idx + 1);
+
+#if JSON_DIAGNOSTICS
+                if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
+                {
+                    // capacity has changed: update all parents
+                    set_parents();
+                }
+                else
+                {
+                    // set parent for values added above
+                    set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size));
+                }
+#endif
+                assert_invariant();
+            }
+
+            return m_value.array->operator[](idx);
+        }
+
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
+    }
+
+    /// @brief access specified array element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    const_reference operator[](size_type idx) const
+    {
+        // const operator[] only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            return m_value.array->operator[](idx);
+        }
+
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
+    }
+
+    /// @brief access specified object element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    reference operator[](typename object_t::key_type key)
+    {
+        // implicitly convert null value to an empty object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value.object = create<object_t>();
+            assert_invariant();
+        }
+
+        // operator[] only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            auto result = m_value.object->emplace(std::move(key), nullptr);
+            return set_parent(result.first->second);
+        }
+
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
+    }
+
+    /// @brief access specified object element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    const_reference operator[](const typename object_t::key_type& key) const
+    {
+        // const operator[] only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            auto it = m_value.object->find(key);
+            JSON_ASSERT(it != m_value.object->end());
+            return it->second;
+        }
+
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
+    }
+
+    // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
+    // (they seemingly cannot be constrained to resolve the ambiguity)
+    template<typename T>
+    reference operator[](T* key)
+    {
+        return operator[](typename object_t::key_type(key));
+    }
+
+    template<typename T>
+    const_reference operator[](T* key) const
+    {
+        return operator[](typename object_t::key_type(key));
+    }
+
+    /// @brief access specified object element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
+    reference operator[](KeyType && key)
+    {
+        // implicitly convert null value to an empty object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value.object = create<object_t>();
+            assert_invariant();
+        }
+
+        // operator[] only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            auto result = m_value.object->emplace(std::forward<KeyType>(key), nullptr);
+            return set_parent(result.first->second);
+        }
+
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
+    }
+
+    /// @brief access specified object element
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
+    const_reference operator[](KeyType && key) const
+    {
+        // const operator[] only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            auto it = m_value.object->find(std::forward<KeyType>(key));
+            JSON_ASSERT(it != m_value.object->end());
+            return it->second;
+        }
+
+        JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
+    }
+
+  private:
+    template<typename KeyType>
+    using is_comparable_with_object_key = detail::is_comparable <
+        object_comparator_t, const typename object_t::key_type&, KeyType >;
+
+    template<typename ValueType>
+    using value_return_type = std::conditional <
+        detail::is_c_string_uncvref<ValueType>::value,
+        string_t, typename std::decay<ValueType>::type >;
+
+  public:
+    /// @brief access specified object element with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, detail::enable_if_t <
+                   !detail::is_transparent<object_comparator_t>::value
+                   && detail::is_getable<basic_json_t, ValueType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if key is found, return value and given default value otherwise
+            const auto it = find(key);
+            if (it != end())
+            {
+                return it->template get<ValueType>();
+            }
+
+            return default_value;
+        }
+
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
+    }
+
+    /// @brief access specified object element with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
+               detail::enable_if_t <
+                   !detail::is_transparent<object_comparator_t>::value
+                   && detail::is_getable<basic_json_t, ReturnType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if key is found, return value and given default value otherwise
+            const auto it = find(key);
+            if (it != end())
+            {
+                return it->template get<ReturnType>();
+            }
+
+            return std::forward<ValueType>(default_value);
+        }
+
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
+    }
+
+    /// @brief access specified object element with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, class KeyType, detail::enable_if_t <
+                   detail::is_transparent<object_comparator_t>::value
+                   && !detail::is_json_pointer<KeyType>::value
+                   && is_comparable_with_object_key<KeyType>::value
+                   && detail::is_getable<basic_json_t, ValueType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ValueType value(KeyType && key, const ValueType& default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if key is found, return value and given default value otherwise
+            const auto it = find(std::forward<KeyType>(key));
+            if (it != end())
+            {
+                return it->template get<ValueType>();
+            }
+
+            return default_value;
+        }
+
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
+    }
+
+    /// @brief access specified object element via JSON Pointer with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
+               detail::enable_if_t <
+                   detail::is_transparent<object_comparator_t>::value
+                   && !detail::is_json_pointer<KeyType>::value
+                   && is_comparable_with_object_key<KeyType>::value
+                   && detail::is_getable<basic_json_t, ReturnType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ReturnType value(KeyType && key, ValueType && default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if key is found, return value and given default value otherwise
+            const auto it = find(std::forward<KeyType>(key));
+            if (it != end())
+            {
+                return it->template get<ReturnType>();
+            }
+
+            return std::forward<ValueType>(default_value);
+        }
+
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
+    }
+
+    /// @brief access specified object element via JSON Pointer with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, detail::enable_if_t <
+                   detail::is_getable<basic_json_t, ValueType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ValueType value(const json_pointer& ptr, const ValueType& default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if pointer resolves a value, return it or use default value
+            JSON_TRY
+            {
+                return ptr.get_checked(this).template get<ValueType>();
+            }
+            JSON_INTERNAL_CATCH (out_of_range&)
+            {
+                return default_value;
+            }
+        }
+
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
+    }
+
+    /// @brief access specified object element via JSON Pointer with default value
+    /// @sa https://json.nlohmann.me/api/basic_json/value/
+    template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
+               detail::enable_if_t <
+                   detail::is_getable<basic_json_t, ReturnType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    ReturnType value(const json_pointer& ptr, ValueType && default_value) const
+    {
+        // value only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            // if pointer resolves a value, return it or use default value
+            JSON_TRY
+            {
+                return ptr.get_checked(this).template get<ReturnType>();
+            }
+            JSON_INTERNAL_CATCH (out_of_range&)
+            {
+                return std::forward<ValueType>(default_value);
+            }
+        }
+
+        JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
+    }
+
+    template < class ValueType, class BasicJsonType, detail::enable_if_t <
+                   detail::is_basic_json<BasicJsonType>::value
+                   && detail::is_getable<basic_json_t, ValueType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
+    {
+        return value(ptr.convert(), default_value);
+    }
+
+    template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
+               detail::enable_if_t <
+                   detail::is_basic_json<BasicJsonType>::value
+                   && detail::is_getable<basic_json_t, ReturnType>::value
+                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
+    {
+        return value(ptr.convert(), std::forward<ValueType>(default_value));
+    }
+
+    /// @brief access the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/front/
+    reference front()
+    {
+        return *begin();
+    }
+
+    /// @brief access the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/front/
+    const_reference front() const
+    {
+        return *cbegin();
+    }
+
+    /// @brief access the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/back/
+    reference back()
+    {
+        auto tmp = end();
+        --tmp;
+        return *tmp;
+    }
+
+    /// @brief access the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/back/
+    const_reference back() const
+    {
+        auto tmp = cend();
+        --tmp;
+        return *tmp;
+    }
+
+    /// @brief remove element given an iterator
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    template < class IteratorType, detail::enable_if_t <
+                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
+                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
+    IteratorType erase(IteratorType pos)
+    {
+        // make sure iterator fits the current value
+        if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+        }
+
+        IteratorType result = end();
+
+        switch (m_type)
+        {
+            case value_t::boolean:
+            case value_t::number_float:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::string:
+            case value_t::binary:
+            {
+                if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
+                {
+                    JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
+                }
+
+                if (is_string())
+                {
+                    AllocatorType<string_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
+                    m_value.string = nullptr;
+                }
+                else if (is_binary())
+                {
+                    AllocatorType<binary_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);
+                    m_value.binary = nullptr;
+                }
+
+                m_type = value_t::null;
+                assert_invariant();
+                break;
+            }
+
+            case value_t::object:
+            {
+                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::discarded:
+            default:
+                JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
+
+        return result;
+    }
+
+    /// @brief remove elements given an iterator range
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    template < class IteratorType, detail::enable_if_t <
+                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
+                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
+    IteratorType erase(IteratorType first, IteratorType last)
+    {
+        // make sure iterator fits the current value
+        if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
+        }
+
+        IteratorType result = end();
+
+        switch (m_type)
+        {
+            case value_t::boolean:
+            case value_t::number_float:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::string:
+            case value_t::binary:
+            {
+                if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
+                                       || !last.m_it.primitive_iterator.is_end()))
+                {
+                    JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
+                }
+
+                if (is_string())
+                {
+                    AllocatorType<string_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
+                    m_value.string = nullptr;
+                }
+                else if (is_binary())
+                {
+                    AllocatorType<binary_t> alloc;
+                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);
+                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);
+                    m_value.binary = nullptr;
+                }
+
+                m_type = value_t::null;
+                assert_invariant();
+                break;
+            }
+
+            case value_t::object:
+            {
+                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
+                                              last.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
+                                             last.m_it.array_iterator);
+                break;
+            }
+
+            case value_t::null:
+            case value_t::discarded:
+            default:
+                JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
+
+        return result;
+    }
+
+  private:
+    template < typename KeyType, detail::enable_if_t <
+                   detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
+    size_type erase_internal(KeyType && key)
+    {
+        // this erase only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
+
+        return m_value.object->erase(std::forward<KeyType>(key));
+    }
+
+    template < typename KeyType, detail::enable_if_t <
+                   !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
+    size_type erase_internal(KeyType && key)
+    {
+        // this erase only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
+
+        const auto it = m_value.object->find(std::forward<KeyType>(key));
+        if (it != m_value.object->end())
+        {
+            m_value.object->erase(it);
+            return 1;
+        }
+        return 0;
+    }
+
+  public:
+
+    /// @brief remove element from a JSON object given a key
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    size_type erase(const typename object_t::key_type& key)
+    {
+        // the indirection via erase_internal() is added to avoid making this
+        // function a template and thus de-rank it during overload resolution
+        return erase_internal(key);
+    }
+
+    /// @brief remove element from a JSON object given a key
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    size_type erase(KeyType && key)
+    {
+        return erase_internal(std::forward<KeyType>(key));
+    }
+
+    /// @brief remove element from a JSON array given an index
+    /// @sa https://json.nlohmann.me/api/basic_json/erase/
+    void erase(const size_type idx)
+    {
+        // this erase only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            if (JSON_HEDLEY_UNLIKELY(idx >= size()))
+            {
+                JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
+            }
+
+            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
+        }
+        else
+        {
+            JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
+        }
+    }
+
+    /// @}
+
+
+    ////////////
+    // lookup //
+    ////////////
+
+    /// @name lookup
+    /// @{
+
+    /// @brief find an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/find/
+    iterator find(const typename object_t::key_type& key)
+    {
+        auto result = end();
+
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(key);
+        }
+
+        return result;
+    }
+
+    /// @brief find an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/find/
+    const_iterator find(const typename object_t::key_type& key) const
+    {
+        auto result = cend();
+
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(key);
+        }
+
+        return result;
+    }
+
+    /// @brief find an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/find/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    iterator find(KeyType && key)
+    {
+        auto result = end();
+
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
+        }
+
+        return result;
+    }
+
+    /// @brief find an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/find/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    const_iterator find(KeyType && key) const
+    {
+        auto result = cend();
+
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
+        }
+
+        return result;
+    }
+
+    /// @brief returns the number of occurrences of a key in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/count/
+    size_type count(const typename object_t::key_type& key) const
+    {
+        // return 0 for all nonobject types
+        return is_object() ? m_value.object->count(key) : 0;
+    }
+
+    /// @brief returns the number of occurrences of a key in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/count/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    size_type count(KeyType && key) const
+    {
+        // return 0 for all nonobject types
+        return is_object() ? m_value.object->count(std::forward<KeyType>(key)) : 0;
+    }
+
+    /// @brief check the existence of an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/contains/
+    bool contains(const typename object_t::key_type& key) const
+    {
+        return is_object() && m_value.object->find(key) != m_value.object->end();
+    }
+
+    /// @brief check the existence of an element in a JSON object
+    /// @sa https://json.nlohmann.me/api/basic_json/contains/
+    template<class KeyType, detail::enable_if_t<
+                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
+    bool contains(KeyType && key) const
+    {
+        return is_object() && m_value.object->find(std::forward<KeyType>(key)) != m_value.object->end();
+    }
+
+    /// @brief check the existence of an element in a JSON object given a JSON pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/contains/
+    bool contains(const json_pointer& ptr) const
+    {
+        return ptr.contains(this);
+    }
+
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
+    {
+        return ptr.contains(this);
+    }
+
+    /// @}
+
+
+    ///////////////
+    // iterators //
+    ///////////////
+
+    /// @name iterators
+    /// @{
+
+    /// @brief returns an iterator to the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/begin/
+    iterator begin() noexcept
+    {
+        iterator result(this);
+        result.set_begin();
+        return result;
+    }
+
+    /// @brief returns an iterator to the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/begin/
+    const_iterator begin() const noexcept
+    {
+        return cbegin();
+    }
+
+    /// @brief returns a const iterator to the first element
+    /// @sa https://json.nlohmann.me/api/basic_json/cbegin/
+    const_iterator cbegin() const noexcept
+    {
+        const_iterator result(this);
+        result.set_begin();
+        return result;
+    }
+
+    /// @brief returns an iterator to one past the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/end/
+    iterator end() noexcept
+    {
+        iterator result(this);
+        result.set_end();
+        return result;
+    }
+
+    /// @brief returns an iterator to one past the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/end/
+    const_iterator end() const noexcept
+    {
+        return cend();
+    }
+
+    /// @brief returns an iterator to one past the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/cend/
+    const_iterator cend() const noexcept
+    {
+        const_iterator result(this);
+        result.set_end();
+        return result;
+    }
+
+    /// @brief returns an iterator to the reverse-beginning
+    /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
+    reverse_iterator rbegin() noexcept
+    {
+        return reverse_iterator(end());
+    }
+
+    /// @brief returns an iterator to the reverse-beginning
+    /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
+    const_reverse_iterator rbegin() const noexcept
+    {
+        return crbegin();
+    }
+
+    /// @brief returns an iterator to the reverse-end
+    /// @sa https://json.nlohmann.me/api/basic_json/rend/
+    reverse_iterator rend() noexcept
+    {
+        return reverse_iterator(begin());
+    }
+
+    /// @brief returns an iterator to the reverse-end
+    /// @sa https://json.nlohmann.me/api/basic_json/rend/
+    const_reverse_iterator rend() const noexcept
+    {
+        return crend();
+    }
+
+    /// @brief returns a const reverse iterator to the last element
+    /// @sa https://json.nlohmann.me/api/basic_json/crbegin/
+    const_reverse_iterator crbegin() const noexcept
+    {
+        return const_reverse_iterator(cend());
+    }
+
+    /// @brief returns a const reverse iterator to one before the first
+    /// @sa https://json.nlohmann.me/api/basic_json/crend/
+    const_reverse_iterator crend() const noexcept
+    {
+        return const_reverse_iterator(cbegin());
+    }
+
+  public:
+    /// @brief wrapper to access iterator member functions in range-based for
+    /// @sa https://json.nlohmann.me/api/basic_json/items/
+    /// @deprecated This function is deprecated since 3.1.0 and will be removed in
+    ///             version 4.0.0 of the library. Please use @ref items() instead;
+    ///             that is, replace `json::iterator_wrapper(j)` with `j.items()`.
+    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
+    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
+    {
+        return ref.items();
+    }
+
+    /// @brief wrapper to access iterator member functions in range-based for
+    /// @sa https://json.nlohmann.me/api/basic_json/items/
+    /// @deprecated This function is deprecated since 3.1.0 and will be removed in
+    ///         version 4.0.0 of the library. Please use @ref items() instead;
+    ///         that is, replace `json::iterator_wrapper(j)` with `j.items()`.
+    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
+    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
+    {
+        return ref.items();
+    }
+
+    /// @brief helper to access iterator member functions in range-based for
+    /// @sa https://json.nlohmann.me/api/basic_json/items/
+    iteration_proxy<iterator> items() noexcept
+    {
+        return iteration_proxy<iterator>(*this);
+    }
+
+    /// @brief helper to access iterator member functions in range-based for
+    /// @sa https://json.nlohmann.me/api/basic_json/items/
+    iteration_proxy<const_iterator> items() const noexcept
+    {
+        return iteration_proxy<const_iterator>(*this);
+    }
+
+    /// @}
+
+
+    //////////////
+    // capacity //
+    //////////////
+
+    /// @name capacity
+    /// @{
+
+    /// @brief checks whether the container is empty.
+    /// @sa https://json.nlohmann.me/api/basic_json/empty/
+    bool empty() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+            {
+                // null values are empty
+                return true;
+            }
+
+            case value_t::array:
+            {
+                // delegate call to array_t::empty()
+                return m_value.array->empty();
+            }
+
+            case value_t::object:
+            {
+                // delegate call to object_t::empty()
+                return m_value.object->empty();
+            }
+
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                // all other types are nonempty
+                return false;
+            }
+        }
+    }
+
+    /// @brief returns the number of elements
+    /// @sa https://json.nlohmann.me/api/basic_json/size/
+    size_type size() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+            {
+                // null values are empty
+                return 0;
+            }
+
+            case value_t::array:
+            {
+                // delegate call to array_t::size()
+                return m_value.array->size();
+            }
+
+            case value_t::object:
+            {
+                // delegate call to object_t::size()
+                return m_value.object->size();
+            }
+
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                // all other types have size 1
+                return 1;
+            }
+        }
+    }
+
+    /// @brief returns the maximum possible number of elements
+    /// @sa https://json.nlohmann.me/api/basic_json/max_size/
+    size_type max_size() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::array:
+            {
+                // delegate call to array_t::max_size()
+                return m_value.array->max_size();
+            }
+
+            case value_t::object:
+            {
+                // delegate call to object_t::max_size()
+                return m_value.object->max_size();
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                // all other types have max_size() == size()
+                return size();
+            }
+        }
+    }
+
+    /// @}
+
+
+    ///////////////
+    // modifiers //
+    ///////////////
+
+    /// @name modifiers
+    /// @{
+
+    /// @brief clears the contents
+    /// @sa https://json.nlohmann.me/api/basic_json/clear/
+    void clear() noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            {
+                m_value.number_integer = 0;
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                m_value.number_unsigned = 0;
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                m_value.number_float = 0.0;
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                m_value.boolean = false;
+                break;
+            }
+
+            case value_t::string:
+            {
+                m_value.string->clear();
+                break;
+            }
+
+            case value_t::binary:
+            {
+                m_value.binary->clear();
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_value.array->clear();
+                break;
+            }
+
+            case value_t::object:
+            {
+                m_value.object->clear();
+                break;
+            }
+
+            case value_t::null:
+            case value_t::discarded:
+            default:
+                break;
+        }
+    }
+
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
+    void push_back(basic_json&& val)
+    {
+        // push_back only works for null objects or arrays
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
+        {
+            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
+        }
+
+        // transform null object into an array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value = value_t::array;
+            assert_invariant();
+        }
+
+        // add element to array (move semantics)
+        const auto old_capacity = m_value.array->capacity();
+        m_value.array->push_back(std::move(val));
+        set_parent(m_value.array->back(), old_capacity);
+        // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
+    }
+
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
+    reference operator+=(basic_json&& val)
+    {
+        push_back(std::move(val));
+        return *this;
+    }
+
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
+    void push_back(const basic_json& val)
+    {
+        // push_back only works for null objects or arrays
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
+        {
+            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
+        }
+
+        // transform null object into an array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value = value_t::array;
+            assert_invariant();
+        }
+
+        // add element to array
+        const auto old_capacity = m_value.array->capacity();
+        m_value.array->push_back(val);
+        set_parent(m_value.array->back(), old_capacity);
+    }
+
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
+    reference operator+=(const basic_json& val)
+    {
+        push_back(val);
+        return *this;
+    }
+
+    /// @brief add an object to an object
+    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
+    void push_back(const typename object_t::value_type& val)
+    {
+        // push_back only works for null objects or objects
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
+        {
+            JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
+        }
+
+        // transform null object into an object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value = value_t::object;
+            assert_invariant();
+        }
+
+        // add element to object
+        auto res = m_value.object->insert(val);
+        set_parent(res.first->second);
+    }
+
+    /// @brief add an object to an object
+    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
+    reference operator+=(const typename object_t::value_type& val)
+    {
+        push_back(val);
+        return *this;
+    }
+
+    /// @brief add an object to an object
+    /// @sa https://json.nlohmann.me/api/basic_json/push_back/
+    void push_back(initializer_list_t init)
+    {
+        if (is_object() && init.size() == 2 && (*init.begin())->is_string())
+        {
+            basic_json&& key = init.begin()->moved_or_copied();
+            push_back(typename object_t::value_type(
+                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
+        }
+        else
+        {
+            push_back(basic_json(init));
+        }
+    }
+
+    /// @brief add an object to an object
+    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
+    reference operator+=(initializer_list_t init)
+    {
+        push_back(init);
+        return *this;
+    }
+
+    /// @brief add an object to an array
+    /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/
+    template<class... Args>
+    reference emplace_back(Args&& ... args)
+    {
+        // emplace_back only works for null objects or arrays
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
+        {
+            JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
+        }
+
+        // transform null object into an array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value = value_t::array;
+            assert_invariant();
+        }
+
+        // add element to array (perfect forwarding)
+        const auto old_capacity = m_value.array->capacity();
+        m_value.array->emplace_back(std::forward<Args>(args)...);
+        return set_parent(m_value.array->back(), old_capacity);
+    }
+
+    /// @brief add an object to an object if key does not exist
+    /// @sa https://json.nlohmann.me/api/basic_json/emplace/
+    template<class... Args>
+    std::pair<iterator, bool> emplace(Args&& ... args)
+    {
+        // emplace only works for null objects or arrays
+        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
+        {
+            JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
+        }
+
+        // transform null object into an object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value = value_t::object;
+            assert_invariant();
+        }
+
+        // add element to array (perfect forwarding)
+        auto res = m_value.object->emplace(std::forward<Args>(args)...);
+        set_parent(res.first->second);
+
+        // create result iterator and set iterator to the result of emplace
+        auto it = begin();
+        it.m_it.object_iterator = res.first;
+
+        // return pair of iterator and boolean
+        return {it, res.second};
+    }
+
+    /// Helper for insertion of an iterator
+    /// @note: This uses std::distance to support GCC 4.8,
+    ///        see https://github.com/nlohmann/json/pull/1257
+    template<typename... Args>
+    iterator insert_iterator(const_iterator pos, Args&& ... args)
+    {
+        iterator result(this);
+        JSON_ASSERT(m_value.array != nullptr);
+
+        auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);
+        m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
+        result.m_it.array_iterator = m_value.array->begin() + insert_pos;
+
+        // This could have been written as:
+        // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
+        // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
+
+        set_parents();
+        return result;
+    }
+
+    /// @brief inserts element into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, const basic_json& val)
+    {
+        // insert only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            // check if iterator pos fits to this JSON value
+            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
+            {
+                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+            }
+
+            // insert to array and return iterator
+            return insert_iterator(pos, val);
+        }
+
+        JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+    }
+
+    /// @brief inserts element into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, basic_json&& val)
+    {
+        return insert(pos, val);
+    }
+
+    /// @brief inserts copies of element into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
+    {
+        // insert only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            // check if iterator pos fits to this JSON value
+            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
+            {
+                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+            }
+
+            // insert to array and return iterator
+            return insert_iterator(pos, cnt, val);
+        }
+
+        JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+    }
+
+    /// @brief inserts range of elements into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, const_iterator first, const_iterator last)
+    {
+        // insert only works for arrays
+        if (JSON_HEDLEY_UNLIKELY(!is_array()))
+        {
+            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+        }
+
+        // check if iterator pos fits to this JSON value
+        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
+        {
+            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+        }
+
+        // check if range iterators belong to the same JSON object
+        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
+        }
+
+        if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
+        {
+            JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
+        }
+
+        // insert to array and return iterator
+        return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
+    }
+
+    /// @brief inserts elements from initializer list into array
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    iterator insert(const_iterator pos, initializer_list_t ilist)
+    {
+        // insert only works for arrays
+        if (JSON_HEDLEY_UNLIKELY(!is_array()))
+        {
+            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+        }
+
+        // check if iterator pos fits to this JSON value
+        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
+        {
+            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
+        }
+
+        // insert to array and return iterator
+        return insert_iterator(pos, ilist.begin(), ilist.end());
+    }
+
+    /// @brief inserts range of elements into object
+    /// @sa https://json.nlohmann.me/api/basic_json/insert/
+    void insert(const_iterator first, const_iterator last)
+    {
+        // insert only works for objects
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
+        }
+
+        // check if range iterators belong to the same JSON object
+        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
+        }
+
+        // passed iterators must belong to objects
+        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
+        {
+            JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
+        }
+
+        m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
+    }
+
+    /// @brief updates a JSON object from another object, overwriting existing keys
+    /// @sa https://json.nlohmann.me/api/basic_json/update/
+    void update(const_reference j, bool merge_objects = false)
+    {
+        update(j.begin(), j.end(), merge_objects);
+    }
+
+    /// @brief updates a JSON object from another object, overwriting existing keys
+    /// @sa https://json.nlohmann.me/api/basic_json/update/
+    void update(const_iterator first, const_iterator last, bool merge_objects = false)
+    {
+        // implicitly convert null value to an empty object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value.object = create<object_t>();
+            assert_invariant();
+        }
+
+        if (JSON_HEDLEY_UNLIKELY(!is_object()))
+        {
+            JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
+        }
+
+        // check if range iterators belong to the same JSON object
+        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
+        {
+            JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
+        }
+
+        // passed iterators must belong to objects
+        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
+        {
+            JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
+        }
+
+        for (auto it = first; it != last; ++it)
+        {
+            if (merge_objects && it.value().is_object())
+            {
+                auto it2 = m_value.object->find(it.key());
+                if (it2 != m_value.object->end())
+                {
+                    it2->second.update(it.value(), true);
+                    continue;
+                }
+            }
+            m_value.object->operator[](it.key()) = it.value();
+#if JSON_DIAGNOSTICS
+            m_value.object->operator[](it.key()).m_parent = this;
+#endif
+        }
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(reference other) noexcept (
+        std::is_nothrow_move_constructible<value_t>::value&&
+        std::is_nothrow_move_assignable<value_t>::value&&
+        std::is_nothrow_move_constructible<json_value>::value&&
+        std::is_nothrow_move_assignable<json_value>::value
+    )
+    {
+        std::swap(m_type, other.m_type);
+        std::swap(m_value, other.m_value);
+
+        set_parents();
+        other.set_parents();
+        assert_invariant();
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    friend void swap(reference left, reference right) noexcept (
+        std::is_nothrow_move_constructible<value_t>::value&&
+        std::is_nothrow_move_assignable<value_t>::value&&
+        std::is_nothrow_move_constructible<json_value>::value&&
+        std::is_nothrow_move_assignable<json_value>::value
+    )
+    {
+        left.swap(right);
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(array_t& other) // NOLINT(bugprone-exception-escape)
+    {
+        // swap only works for arrays
+        if (JSON_HEDLEY_LIKELY(is_array()))
+        {
+            using std::swap;
+            swap(*(m_value.array), other);
+        }
+        else
+        {
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
+        }
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(object_t& other) // NOLINT(bugprone-exception-escape)
+    {
+        // swap only works for objects
+        if (JSON_HEDLEY_LIKELY(is_object()))
+        {
+            using std::swap;
+            swap(*(m_value.object), other);
+        }
+        else
+        {
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
+        }
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(string_t& other) // NOLINT(bugprone-exception-escape)
+    {
+        // swap only works for strings
+        if (JSON_HEDLEY_LIKELY(is_string()))
+        {
+            using std::swap;
+            swap(*(m_value.string), other);
+        }
+        else
+        {
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
+        }
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(binary_t& other) // NOLINT(bugprone-exception-escape)
+    {
+        // swap only works for strings
+        if (JSON_HEDLEY_LIKELY(is_binary()))
+        {
+            using std::swap;
+            swap(*(m_value.binary), other);
+        }
+        else
+        {
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
+        }
+    }
+
+    /// @brief exchanges the values
+    /// @sa https://json.nlohmann.me/api/basic_json/swap/
+    void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)
+    {
+        // swap only works for strings
+        if (JSON_HEDLEY_LIKELY(is_binary()))
+        {
+            using std::swap;
+            swap(*(m_value.binary), other);
+        }
+        else
+        {
+            JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
+        }
+    }
+
+    /// @}
+
+    //////////////////////////////////////////
+    // lexicographical comparison operators //
+    //////////////////////////////////////////
+
+    /// @name lexicographical comparison operators
+    /// @{
+
+    // note parentheses around operands are necessary; see
+    // https://github.com/nlohmann/json/issues/1530
+#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result)                       \
+    const auto lhs_type = lhs.type();                                                                    \
+    const auto rhs_type = rhs.type();                                                                    \
+    \
+    if (lhs_type == rhs_type) /* NOLINT(readability/braces) */                                           \
+    {                                                                                                    \
+        switch (lhs_type)                                                                                \
+        {                                                                                                \
+            case value_t::array:                                                                         \
+                return (*lhs.m_value.array) op (*rhs.m_value.array);                                     \
+                \
+            case value_t::object:                                                                        \
+                return (*lhs.m_value.object) op (*rhs.m_value.object);                                   \
+                \
+            case value_t::null:                                                                          \
+                return (null_result);                                                                    \
+                \
+            case value_t::string:                                                                        \
+                return (*lhs.m_value.string) op (*rhs.m_value.string);                                   \
+                \
+            case value_t::boolean:                                                                       \
+                return (lhs.m_value.boolean) op (rhs.m_value.boolean);                                   \
+                \
+            case value_t::number_integer:                                                                \
+                return (lhs.m_value.number_integer) op (rhs.m_value.number_integer);                     \
+                \
+            case value_t::number_unsigned:                                                               \
+                return (lhs.m_value.number_unsigned) op (rhs.m_value.number_unsigned);                   \
+                \
+            case value_t::number_float:                                                                  \
+                return (lhs.m_value.number_float) op (rhs.m_value.number_float);                         \
+                \
+            case value_t::binary:                                                                        \
+                return (*lhs.m_value.binary) op (*rhs.m_value.binary);                                   \
+                \
+            case value_t::discarded:                                                                     \
+            default:                                                                                     \
+                return (unordered_result);                                                               \
+        }                                                                                                \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)                   \
+    {                                                                                                    \
+        return static_cast<number_float_t>(lhs.m_value.number_integer) op rhs.m_value.number_float;      \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)                   \
+    {                                                                                                    \
+        return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_integer);      \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)                  \
+    {                                                                                                    \
+        return static_cast<number_float_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_float;     \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)                  \
+    {                                                                                                    \
+        return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_unsigned);     \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)                \
+    {                                                                                                    \
+        return static_cast<number_integer_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_integer; \
+    }                                                                                                    \
+    else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)                \
+    {                                                                                                    \
+        return lhs.m_value.number_integer op static_cast<number_integer_t>(rhs.m_value.number_unsigned); \
+    }                                                                                                    \
+    else if(compares_unordered(lhs, rhs))\
+    {\
+        return (unordered_result);\
+    }\
+    \
+    return (default_result);
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    // returns true if:
+    // - any operand is NaN and the other operand is of number type
+    // - any operand is discarded
+    // in legacy mode, discarded values are considered ordered if
+    // an operation is computed as an odd number of inverses of others
+    static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
+    {
+        if ((lhs.is_number_float() && std::isnan(lhs.m_value.number_float) && rhs.is_number())
+                || (rhs.is_number_float() && std::isnan(rhs.m_value.number_float) && lhs.is_number()))
+        {
+            return true;
+        }
+#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+        return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;
+#else
+        static_cast<void>(inverse);
+        return lhs.is_discarded() || rhs.is_discarded();
+#endif
+    }
+
+  private:
+    bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept
+    {
+        return compares_unordered(*this, rhs, inverse);
+    }
+
+  public:
+#if JSON_HAS_THREE_WAY_COMPARISON
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
+    bool operator==(const_reference rhs) const noexcept
+    {
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+        const_reference lhs = *this;
+        JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+    }
+
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
+    template<typename ScalarType>
+    requires std::is_scalar_v<ScalarType>
+    bool operator==(ScalarType rhs) const noexcept
+    {
+        return *this == basic_json(rhs);
+    }
+
+    /// @brief comparison: not equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
+    bool operator!=(const_reference rhs) const noexcept
+    {
+        if (compares_unordered(rhs, true))
+        {
+            return false;
+        }
+        return !operator==(rhs);
+    }
+
+    /// @brief comparison: 3-way
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
+    std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
+    {
+        const_reference lhs = *this;
+        // default_result is used if we cannot compare values. In that case,
+        // we compare types.
+        JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
+                                std::partial_ordering::equivalent,
+                                std::partial_ordering::unordered,
+                                lhs_type <=> rhs_type) // *NOPAD*
+    }
+
+    /// @brief comparison: 3-way
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
+    template<typename ScalarType>
+    requires std::is_scalar_v<ScalarType>
+    std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*
+    {
+        return *this <=> basic_json(rhs); // *NOPAD*
+    }
+
+#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+    // all operators that are computed as an odd number of inverses of others
+    // need to be overloaded to emulate the legacy comparison behavior
+
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
+    bool operator<=(const_reference rhs) const noexcept
+    {
+        if (compares_unordered(rhs, true))
+        {
+            return false;
+        }
+        return !(rhs < *this);
+    }
+
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
+    template<typename ScalarType>
+    requires std::is_scalar_v<ScalarType>
+    bool operator<=(ScalarType rhs) const noexcept
+    {
+        return *this <= basic_json(rhs);
+    }
+
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
+    bool operator>=(const_reference rhs) const noexcept
+    {
+        if (compares_unordered(rhs, true))
+        {
+            return false;
+        }
+        return !(*this < rhs);
+    }
+
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
+    template<typename ScalarType>
+    requires std::is_scalar_v<ScalarType>
+    bool operator>=(ScalarType rhs) const noexcept
+    {
+        return *this >= basic_json(rhs);
+    }
+#endif
+#else
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
+    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
+    {
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+        JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+    }
+
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator==(const_reference lhs, ScalarType rhs) noexcept
+    {
+        return lhs == basic_json(rhs);
+    }
+
+    /// @brief comparison: equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator==(ScalarType lhs, const_reference rhs) noexcept
+    {
+        return basic_json(lhs) == rhs;
+    }
+
+    /// @brief comparison: not equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
+    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
+    {
+        if (compares_unordered(lhs, rhs, true))
+        {
+            return false;
+        }
+        return !(lhs == rhs);
+    }
+
+    /// @brief comparison: not equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept
+    {
+        return lhs != basic_json(rhs);
+    }
+
+    /// @brief comparison: not equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept
+    {
+        return basic_json(lhs) != rhs;
+    }
+
+    /// @brief comparison: less than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
+    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
+    {
+        // default_result is used if we cannot compare values. In that case,
+        // we compare types. Note we have to call the operator explicitly,
+        // because MSVC has problems otherwise.
+        JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))
+    }
+
+    /// @brief comparison: less than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator<(const_reference lhs, ScalarType rhs) noexcept
+    {
+        return lhs < basic_json(rhs);
+    }
+
+    /// @brief comparison: less than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator<(ScalarType lhs, const_reference rhs) noexcept
+    {
+        return basic_json(lhs) < rhs;
+    }
+
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
+    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
+    {
+        if (compares_unordered(lhs, rhs, true))
+        {
+            return false;
+        }
+        return !(rhs < lhs);
+    }
+
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept
+    {
+        return lhs <= basic_json(rhs);
+    }
+
+    /// @brief comparison: less than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
+    {
+        return basic_json(lhs) <= rhs;
+    }
+
+    /// @brief comparison: greater than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
+    friend bool operator>(const_reference lhs, const_reference rhs) noexcept
+    {
+        // double inverse
+        if (compares_unordered(lhs, rhs))
+        {
+            return false;
+        }
+        return !(lhs <= rhs);
+    }
+
+    /// @brief comparison: greater than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator>(const_reference lhs, ScalarType rhs) noexcept
+    {
+        return lhs > basic_json(rhs);
+    }
+
+    /// @brief comparison: greater than
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator>(ScalarType lhs, const_reference rhs) noexcept
+    {
+        return basic_json(lhs) > rhs;
+    }
+
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
+    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
+    {
+        if (compares_unordered(lhs, rhs, true))
+        {
+            return false;
+        }
+        return !(lhs < rhs);
+    }
+
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept
+    {
+        return lhs >= basic_json(rhs);
+    }
+
+    /// @brief comparison: greater than or equal
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
+    template<typename ScalarType, typename std::enable_if<
+                 std::is_scalar<ScalarType>::value, int>::type = 0>
+    friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
+    {
+        return basic_json(lhs) >= rhs;
+    }
+#endif
+
+#undef JSON_IMPLEMENT_OPERATOR
+
+    /// @}
+
+    ///////////////////
+    // serialization //
+    ///////////////////
+
+    /// @name serialization
+    /// @{
+#ifndef JSON_NO_IO
+    /// @brief serialize to stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
+    {
+        // read width member and use it as indentation parameter if nonzero
+        const bool pretty_print = o.width() > 0;
+        const auto indentation = pretty_print ? o.width() : 0;
+
+        // reset width to 0 for subsequent calls to this stream
+        o.width(0);
+
+        // do the actual serialization
+        serializer s(detail::output_adapter<char>(o), o.fill());
+        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
+        return o;
+    }
+
+    /// @brief serialize to stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+    /// @deprecated This function is deprecated since 3.0.0 and will be removed in
+    ///             version 4.0.0 of the library. Please use
+    ///             operator<<(std::ostream&, const basic_json&) instead; that is,
+    ///             replace calls like `j >> o;` with `o << j;`.
+    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
+    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
+    {
+        return o << j;
+    }
+#endif  // JSON_NO_IO
+    /// @}
+
+
+    /////////////////////
+    // deserialization //
+    /////////////////////
+
+    /// @name deserialization
+    /// @{
+
+    /// @brief deserialize from a compatible input
+    /// @sa https://json.nlohmann.me/api/basic_json/parse/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json parse(InputType&& i,
+                            const parser_callback_t cb = nullptr,
+                            const bool allow_exceptions = true,
+                            const bool ignore_comments = false)
+    {
+        basic_json result;
+        parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
+        return result;
+    }
+
+    /// @brief deserialize from a pair of character iterators
+    /// @sa https://json.nlohmann.me/api/basic_json/parse/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json parse(IteratorType first,
+                            IteratorType last,
+                            const parser_callback_t cb = nullptr,
+                            const bool allow_exceptions = true,
+                            const bool ignore_comments = false)
+    {
+        basic_json result;
+        parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);
+        return result;
+    }
+
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
+    static basic_json parse(detail::span_input_adapter&& i,
+                            const parser_callback_t cb = nullptr,
+                            const bool allow_exceptions = true,
+                            const bool ignore_comments = false)
+    {
+        basic_json result;
+        parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);
+        return result;
+    }
+
+    /// @brief check if the input is valid JSON
+    /// @sa https://json.nlohmann.me/api/basic_json/accept/
+    template<typename InputType>
+    static bool accept(InputType&& i,
+                       const bool ignore_comments = false)
+    {
+        return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
+    }
+
+    /// @brief check if the input is valid JSON
+    /// @sa https://json.nlohmann.me/api/basic_json/accept/
+    template<typename IteratorType>
+    static bool accept(IteratorType first, IteratorType last,
+                       const bool ignore_comments = false)
+    {
+        return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
+    }
+
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
+    static bool accept(detail::span_input_adapter&& i,
+                       const bool ignore_comments = false)
+    {
+        return parser(i.get(), nullptr, false, ignore_comments).accept(true);
+    }
+
+    /// @brief generate SAX events
+    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
+    template <typename InputType, typename SAX>
+    JSON_HEDLEY_NON_NULL(2)
+    static bool sax_parse(InputType&& i, SAX* sax,
+                          input_format_t format = input_format_t::json,
+                          const bool strict = true,
+                          const bool ignore_comments = false)
+    {
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        return format == input_format_t::json
+               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
+               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
+    }
+
+    /// @brief generate SAX events
+    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
+    template<class IteratorType, class SAX>
+    JSON_HEDLEY_NON_NULL(3)
+    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
+                          input_format_t format = input_format_t::json,
+                          const bool strict = true,
+                          const bool ignore_comments = false)
+    {
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        return format == input_format_t::json
+               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
+               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
+    }
+
+    /// @brief generate SAX events
+    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
+    /// @deprecated This function is deprecated since 3.8.0 and will be removed in
+    ///             version 4.0.0 of the library. Please use
+    ///             sax_parse(ptr, ptr + len) instead.
+    template <typename SAX>
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
+    JSON_HEDLEY_NON_NULL(2)
+    static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
+                          input_format_t format = input_format_t::json,
+                          const bool strict = true,
+                          const bool ignore_comments = false)
+    {
+        auto ia = i.get();
+        return format == input_format_t::json
+               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
+               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
+    }
+#ifndef JSON_NO_IO
+    /// @brief deserialize from stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
+    /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
+    ///             version 4.0.0 of the library. Please use
+    ///             operator>>(std::istream&, basic_json&) instead; that is,
+    ///             replace calls like `j << i;` with `i >> j;`.
+    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
+    friend std::istream& operator<<(basic_json& j, std::istream& i)
+    {
+        return operator>>(i, j);
+    }
+
+    /// @brief deserialize from stream
+    /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
+    friend std::istream& operator>>(std::istream& i, basic_json& j)
+    {
+        parser(detail::input_adapter(i)).parse(false, j);
+        return i;
+    }
+#endif  // JSON_NO_IO
+    /// @}
+
+    ///////////////////////////
+    // convenience functions //
+    ///////////////////////////
+
+    /// @brief return the type as string
+    /// @sa https://json.nlohmann.me/api/basic_json/type_name/
+    JSON_HEDLEY_RETURNS_NON_NULL
+    const char* type_name() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+                return "null";
+            case value_t::object:
+                return "object";
+            case value_t::array:
+                return "array";
+            case value_t::string:
+                return "string";
+            case value_t::boolean:
+                return "boolean";
+            case value_t::binary:
+                return "binary";
+            case value_t::discarded:
+                return "discarded";
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            default:
+                return "number";
+        }
+    }
+
+
+  JSON_PRIVATE_UNLESS_TESTED:
+    //////////////////////
+    // member variables //
+    //////////////////////
+
+    /// the type of the current element
+    value_t m_type = value_t::null;
+
+    /// the value of the current element
+    json_value m_value = {};
+
+#if JSON_DIAGNOSTICS
+    /// a pointer to a parent value (for debugging purposes)
+    basic_json* m_parent = nullptr;
+#endif
+
+    //////////////////////////////////////////
+    // binary serialization/deserialization //
+    //////////////////////////////////////////
+
+    /// @name binary serialization/deserialization support
+    /// @{
+
+  public:
+    /// @brief create a CBOR serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
+    static std::vector<std::uint8_t> to_cbor(const basic_json& j)
+    {
+        std::vector<std::uint8_t> result;
+        to_cbor(j, result);
+        return result;
+    }
+
+    /// @brief create a CBOR serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
+    static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o)
+    {
+        binary_writer<std::uint8_t>(o).write_cbor(j);
+    }
+
+    /// @brief create a CBOR serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
+    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
+    {
+        binary_writer<char>(o).write_cbor(j);
+    }
+
+    /// @brief create a MessagePack serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
+    static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
+    {
+        std::vector<std::uint8_t> result;
+        to_msgpack(j, result);
+        return result;
+    }
+
+    /// @brief create a MessagePack serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
+    static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o)
+    {
+        binary_writer<std::uint8_t>(o).write_msgpack(j);
+    }
+
+    /// @brief create a MessagePack serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
+    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
+    {
+        binary_writer<char>(o).write_msgpack(j);
+    }
+
+    /// @brief create a UBJSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
+    static std::vector<std::uint8_t> to_ubjson(const basic_json& j,
+            const bool use_size = false,
+            const bool use_type = false)
+    {
+        std::vector<std::uint8_t> result;
+        to_ubjson(j, result, use_size, use_type);
+        return result;
+    }
+
+    /// @brief create a UBJSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
+    static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o,
+                          const bool use_size = false, const bool use_type = false)
+    {
+        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);
+    }
+
+    /// @brief create a UBJSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
+    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
+                          const bool use_size = false, const bool use_type = false)
+    {
+        binary_writer<char>(o).write_ubjson(j, use_size, use_type);
+    }
+
+    /// @brief create a BJData serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
+    static std::vector<std::uint8_t> to_bjdata(const basic_json& j,
+            const bool use_size = false,
+            const bool use_type = false)
+    {
+        std::vector<std::uint8_t> result;
+        to_bjdata(j, result, use_size, use_type);
+        return result;
+    }
+
+    /// @brief create a BJData serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
+    static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o,
+                          const bool use_size = false, const bool use_type = false)
+    {
+        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true);
+    }
+
+    /// @brief create a BJData serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
+    static void to_bjdata(const basic_json& j, detail::output_adapter<char> o,
+                          const bool use_size = false, const bool use_type = false)
+    {
+        binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true);
+    }
+
+    /// @brief create a BSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
+    static std::vector<std::uint8_t> to_bson(const basic_json& j)
+    {
+        std::vector<std::uint8_t> result;
+        to_bson(j, result);
+        return result;
+    }
+
+    /// @brief create a BSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
+    static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o)
+    {
+        binary_writer<std::uint8_t>(o).write_bson(j);
+    }
+
+    /// @brief create a BSON serialization of a given JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
+    static void to_bson(const basic_json& j, detail::output_adapter<char> o)
+    {
+        binary_writer<char>(o).write_bson(j);
+    }
+
+    /// @brief create a JSON value from an input in CBOR format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_cbor(InputType&& i,
+                                const bool strict = true,
+                                const bool allow_exceptions = true,
+                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    /// @brief create a JSON value from an input in CBOR format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_cbor(IteratorType first, IteratorType last,
+                                const bool strict = true,
+                                const bool allow_exceptions = true,
+                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    template<typename T>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
+    static basic_json from_cbor(const T* ptr, std::size_t len,
+                                const bool strict = true,
+                                const bool allow_exceptions = true,
+                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
+    }
+
+
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
+    static basic_json from_cbor(detail::span_input_adapter&& i,
+                                const bool strict = true,
+                                const bool allow_exceptions = true,
+                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = i.get();
+        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    /// @brief create a JSON value from an input in MessagePack format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_msgpack(InputType&& i,
+                                   const bool strict = true,
+                                   const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    /// @brief create a JSON value from an input in MessagePack format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_msgpack(IteratorType first, IteratorType last,
+                                   const bool strict = true,
+                                   const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    template<typename T>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
+    static basic_json from_msgpack(const T* ptr, std::size_t len,
+                                   const bool strict = true,
+                                   const bool allow_exceptions = true)
+    {
+        return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
+    }
+
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
+    static basic_json from_msgpack(detail::span_input_adapter&& i,
+                                   const bool strict = true,
+                                   const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = i.get();
+        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    /// @brief create a JSON value from an input in UBJSON format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_ubjson(InputType&& i,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    /// @brief create a JSON value from an input in UBJSON format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_ubjson(IteratorType first, IteratorType last,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    template<typename T>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
+    static basic_json from_ubjson(const T* ptr, std::size_t len,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
+    }
+
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
+    static basic_json from_ubjson(detail::span_input_adapter&& i,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = i.get();
+        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+
+    /// @brief create a JSON value from an input in BJData format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_bjdata(InputType&& i,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    /// @brief create a JSON value from an input in BJData format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_bjdata(IteratorType first, IteratorType last,
+                                  const bool strict = true,
+                                  const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    /// @brief create a JSON value from an input in BSON format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
+    template<typename InputType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_bson(InputType&& i,
+                                const bool strict = true,
+                                const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::forward<InputType>(i));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    /// @brief create a JSON value from an input in BSON format
+    /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
+    template<typename IteratorType>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json from_bson(IteratorType first, IteratorType last,
+                                const bool strict = true,
+                                const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = detail::input_adapter(std::move(first), std::move(last));
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+
+    template<typename T>
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
+    static basic_json from_bson(const T* ptr, std::size_t len,
+                                const bool strict = true,
+                                const bool allow_exceptions = true)
+    {
+        return from_bson(ptr, ptr + len, strict, allow_exceptions);
+    }
+
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
+    static basic_json from_bson(detail::span_input_adapter&& i,
+                                const bool strict = true,
+                                const bool allow_exceptions = true)
+    {
+        basic_json result;
+        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
+        auto ia = i.get();
+        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
+        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
+        return res ? result : basic_json(value_t::discarded);
+    }
+    /// @}
+
+    //////////////////////////
+    // JSON Pointer support //
+    //////////////////////////
+
+    /// @name JSON Pointer functions
+    /// @{
+
+    /// @brief access specified element via JSON Pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    reference operator[](const json_pointer& ptr)
+    {
+        return ptr.get_unchecked(this);
+    }
+
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
+    {
+        return ptr.get_unchecked(this);
+    }
+
+    /// @brief access specified element via JSON Pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
+    const_reference operator[](const json_pointer& ptr) const
+    {
+        return ptr.get_unchecked(this);
+    }
+
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
+    {
+        return ptr.get_unchecked(this);
+    }
+
+    /// @brief access specified element via JSON Pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    reference at(const json_pointer& ptr)
+    {
+        return ptr.get_checked(this);
+    }
+
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
+    {
+        return ptr.get_checked(this);
+    }
+
+    /// @brief access specified element via JSON Pointer
+    /// @sa https://json.nlohmann.me/api/basic_json/at/
+    const_reference at(const json_pointer& ptr) const
+    {
+        return ptr.get_checked(this);
+    }
+
+    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
+    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
+    const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
+    {
+        return ptr.get_checked(this);
+    }
+
+    /// @brief return flattened JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/flatten/
+    basic_json flatten() const
+    {
+        basic_json result(value_t::object);
+        json_pointer::flatten("", *this, result);
+        return result;
+    }
+
+    /// @brief unflatten a previously flattened JSON value
+    /// @sa https://json.nlohmann.me/api/basic_json/unflatten/
+    basic_json unflatten() const
+    {
+        return json_pointer::unflatten(*this);
+    }
+
+    /// @}
+
+    //////////////////////////
+    // JSON Patch functions //
+    //////////////////////////
+
+    /// @name JSON Patch functions
+    /// @{
+
+    /// @brief applies a JSON patch in-place without copying the object
+    /// @sa https://json.nlohmann.me/api/basic_json/patch/
+    void patch_inplace(const basic_json& json_patch)
+    {
+        basic_json& result = *this;
+        // the valid JSON Patch operations
+        enum class patch_operations {add, remove, replace, move, copy, test, invalid};
+
+        const auto get_op = [](const std::string & op)
+        {
+            if (op == "add")
+            {
+                return patch_operations::add;
+            }
+            if (op == "remove")
+            {
+                return patch_operations::remove;
+            }
+            if (op == "replace")
+            {
+                return patch_operations::replace;
+            }
+            if (op == "move")
+            {
+                return patch_operations::move;
+            }
+            if (op == "copy")
+            {
+                return patch_operations::copy;
+            }
+            if (op == "test")
+            {
+                return patch_operations::test;
+            }
+
+            return patch_operations::invalid;
+        };
+
+        // wrapper for "add" operation; add value at ptr
+        const auto operation_add = [&result](json_pointer & ptr, basic_json val)
+        {
+            // adding to the root of the target document means replacing it
+            if (ptr.empty())
+            {
+                result = val;
+                return;
+            }
+
+            // make sure the top element of the pointer exists
+            json_pointer top_pointer = ptr.top();
+            if (top_pointer != ptr)
+            {
+                result.at(top_pointer);
+            }
+
+            // get reference to parent of JSON pointer ptr
+            const auto last_path = ptr.back();
+            ptr.pop_back();
+            // parent must exist when performing patch add per RFC6902 specs
+            basic_json& parent = result.at(ptr);
+
+            switch (parent.m_type)
+            {
+                case value_t::null:
+                case value_t::object:
+                {
+                    // use operator[] to add value
+                    parent[last_path] = val;
+                    break;
+                }
+
+                case value_t::array:
+                {
+                    if (last_path == "-")
+                    {
+                        // special case: append to back
+                        parent.push_back(val);
+                    }
+                    else
+                    {
+                        const auto idx = json_pointer::template array_index<basic_json_t>(last_path);
+                        if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
+                        {
+                            // avoid undefined behavior
+                            JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
+                        }
+
+                        // default case: insert add offset
+                        parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
+                    }
+                    break;
+                }
+
+                // if there exists a parent it cannot be primitive
+                case value_t::string: // LCOV_EXCL_LINE
+                case value_t::boolean: // LCOV_EXCL_LINE
+                case value_t::number_integer: // LCOV_EXCL_LINE
+                case value_t::number_unsigned: // LCOV_EXCL_LINE
+                case value_t::number_float: // LCOV_EXCL_LINE
+                case value_t::binary: // LCOV_EXCL_LINE
+                case value_t::discarded: // LCOV_EXCL_LINE
+                default:            // LCOV_EXCL_LINE
+                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
+            }
+        };
+
+        // wrapper for "remove" operation; remove value at ptr
+        const auto operation_remove = [this, &result](json_pointer & ptr)
+        {
+            // get reference to parent of JSON pointer ptr
+            const auto last_path = ptr.back();
+            ptr.pop_back();
+            basic_json& parent = result.at(ptr);
+
+            // remove child
+            if (parent.is_object())
+            {
+                // perform range check
+                auto it = parent.find(last_path);
+                if (JSON_HEDLEY_LIKELY(it != parent.end()))
+                {
+                    parent.erase(it);
+                }
+                else
+                {
+                    JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
+                }
+            }
+            else if (parent.is_array())
+            {
+                // note erase performs range check
+                parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
+            }
+        };
+
+        // type check: top level value must be an array
+        if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
+        {
+            JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
+        }
+
+        // iterate and apply the operations
+        for (const auto& val : json_patch)
+        {
+            // wrapper to get a value for an operation
+            const auto get_value = [&val](const std::string & op,
+                                          const std::string & member,
+                                          bool string_type) -> basic_json &
+            {
+                // find value
+                auto it = val.m_value.object->find(member);
+
+                // context-sensitive error message
+                const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\'');
+
+                // check if desired value is present
+                if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end()))
+                {
+                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
+                    JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
+                }
+
+                // check if result is of type string
+                if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
+                {
+                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
+                    JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
+                }
+
+                // no error: return value
+                return it->second;
+            };
+
+            // type check: every element of the array must be an object
+            if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
+            {
+                JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
+            }
+
+            // collect mandatory members
+            const auto op = get_value("op", "op", true).template get<std::string>();
+            const auto path = get_value(op, "path", true).template get<std::string>();
+            json_pointer ptr(path);
+
+            switch (get_op(op))
+            {
+                case patch_operations::add:
+                {
+                    operation_add(ptr, get_value("add", "value", false));
+                    break;
+                }
+
+                case patch_operations::remove:
+                {
+                    operation_remove(ptr);
+                    break;
+                }
+
+                case patch_operations::replace:
+                {
+                    // the "path" location must exist - use at()
+                    result.at(ptr) = get_value("replace", "value", false);
+                    break;
+                }
+
+                case patch_operations::move:
+                {
+                    const auto from_path = get_value("move", "from", true).template get<std::string>();
+                    json_pointer from_ptr(from_path);
+
+                    // the "from" location must exist - use at()
+                    basic_json v = result.at(from_ptr);
+
+                    // The move operation is functionally identical to a
+                    // "remove" operation on the "from" location, followed
+                    // immediately by an "add" operation at the target
+                    // location with the value that was just removed.
+                    operation_remove(from_ptr);
+                    operation_add(ptr, v);
+                    break;
+                }
+
+                case patch_operations::copy:
+                {
+                    const auto from_path = get_value("copy", "from", true).template get<std::string>();
+                    const json_pointer from_ptr(from_path);
+
+                    // the "from" location must exist - use at()
+                    basic_json v = result.at(from_ptr);
+
+                    // The copy is functionally identical to an "add"
+                    // operation at the target location using the value
+                    // specified in the "from" member.
+                    operation_add(ptr, v);
+                    break;
+                }
+
+                case patch_operations::test:
+                {
+                    bool success = false;
+                    JSON_TRY
+                    {
+                        // check if "value" matches the one at "path"
+                        // the "path" location must exist - use at()
+                        success = (result.at(ptr) == get_value("test", "value", false));
+                    }
+                    JSON_INTERNAL_CATCH (out_of_range&)
+                    {
+                        // ignore out of range errors: success remains false
+                    }
+
+                    // throw an exception if test fails
+                    if (JSON_HEDLEY_UNLIKELY(!success))
+                    {
+                        JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
+                    }
+
+                    break;
+                }
+
+                case patch_operations::invalid:
+                default:
+                {
+                    // op must be "add", "remove", "replace", "move", "copy", or
+                    // "test"
+                    JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
+                }
+            }
+        }
+    }
+
+    /// @brief applies a JSON patch to a copy of the current object
+    /// @sa https://json.nlohmann.me/api/basic_json/patch/
+    basic_json patch(const basic_json& json_patch) const
+    {
+        basic_json result = *this;
+        result.patch_inplace(json_patch);
+        return result;
+    }
+
+    /// @brief creates a diff as a JSON patch
+    /// @sa https://json.nlohmann.me/api/basic_json/diff/
+    JSON_HEDLEY_WARN_UNUSED_RESULT
+    static basic_json diff(const basic_json& source, const basic_json& target,
+                           const std::string& path = "")
+    {
+        // the patch
+        basic_json result(value_t::array);
+
+        // if the values are the same, return empty patch
+        if (source == target)
+        {
+            return result;
+        }
+
+        if (source.type() != target.type())
+        {
+            // different types: replace value
+            result.push_back(
+            {
+                {"op", "replace"}, {"path", path}, {"value", target}
+            });
+            return result;
+        }
+
+        switch (source.type())
+        {
+            case value_t::array:
+            {
+                // first pass: traverse common elements
+                std::size_t i = 0;
+                while (i < source.size() && i < target.size())
+                {
+                    // recursive call to compare array values at index i
+                    auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i)));
+                    result.insert(result.end(), temp_diff.begin(), temp_diff.end());
+                    ++i;
+                }
+
+                // We now reached the end of at least one array
+                // in a second pass, traverse the remaining elements
+
+                // remove my remaining elements
+                const auto end_index = static_cast<difference_type>(result.size());
+                while (i < source.size())
+                {
+                    // add operations in reverse order to avoid invalid
+                    // indices
+                    result.insert(result.begin() + end_index, object(
+                    {
+                        {"op", "remove"},
+                        {"path", detail::concat(path, '/', std::to_string(i))}
+                    }));
+                    ++i;
+                }
+
+                // add other remaining elements
+                while (i < target.size())
+                {
+                    result.push_back(
+                    {
+                        {"op", "add"},
+                        {"path", detail::concat(path, "/-")},
+                        {"value", target[i]}
+                    });
+                    ++i;
+                }
+
+                break;
+            }
+
+            case value_t::object:
+            {
+                // first pass: traverse this object's elements
+                for (auto it = source.cbegin(); it != source.cend(); ++it)
+                {
+                    // escape the key name to be used in a JSON patch
+                    const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
+
+                    if (target.find(it.key()) != target.end())
+                    {
+                        // recursive call to compare object values at key it
+                        auto temp_diff = diff(it.value(), target[it.key()], path_key);
+                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
+                    }
+                    else
+                    {
+                        // found a key that is not in o -> remove it
+                        result.push_back(object(
+                        {
+                            {"op", "remove"}, {"path", path_key}
+                        }));
+                    }
+                }
+
+                // second pass: traverse other object's elements
+                for (auto it = target.cbegin(); it != target.cend(); ++it)
+                {
+                    if (source.find(it.key()) == source.end())
+                    {
+                        // found a key that is not in this -> add it
+                        const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
+                        result.push_back(
+                        {
+                            {"op", "add"}, {"path", path_key},
+                            {"value", it.value()}
+                        });
+                    }
+                }
+
+                break;
+            }
+
+            case value_t::null:
+            case value_t::string:
+            case value_t::boolean:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::number_float:
+            case value_t::binary:
+            case value_t::discarded:
+            default:
+            {
+                // both primitive type: replace value
+                result.push_back(
+                {
+                    {"op", "replace"}, {"path", path}, {"value", target}
+                });
+                break;
+            }
+        }
+
+        return result;
+    }
+    /// @}
+
+    ////////////////////////////////
+    // JSON Merge Patch functions //
+    ////////////////////////////////
+
+    /// @name JSON Merge Patch functions
+    /// @{
+
+    /// @brief applies a JSON Merge Patch
+    /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/
+    void merge_patch(const basic_json& apply_patch)
+    {
+        if (apply_patch.is_object())
+        {
+            if (!is_object())
+            {
+                *this = object();
+            }
+            for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
+            {
+                if (it.value().is_null())
+                {
+                    erase(it.key());
+                }
+                else
+                {
+                    operator[](it.key()).merge_patch(it.value());
+                }
+            }
+        }
+        else
+        {
+            *this = apply_patch;
+        }
+    }
+
+    /// @}
+};
+
+/// @brief user-defined to_string function for JSON values
+/// @sa https://json.nlohmann.me/api/basic_json/to_string/
+NLOHMANN_BASIC_JSON_TPL_DECLARATION
+std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
+{
+    return j.dump();
+}
+
+inline namespace literals
+{
+inline namespace json_literals
+{
+
+/// @brief user-defined string literal for JSON values
+/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/
+JSON_HEDLEY_NON_NULL(1)
+inline nlohmann::json operator "" _json(const char* s, std::size_t n)
+{
+    return nlohmann::json::parse(s, s + n);
+}
+
+/// @brief user-defined string literal for JSON pointer
+/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/
+JSON_HEDLEY_NON_NULL(1)
+inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
+{
+    return nlohmann::json::json_pointer(std::string(s, n));
+}
+
+}  // namespace json_literals
+}  // namespace literals
+NLOHMANN_JSON_NAMESPACE_END
+
+///////////////////////
+// nonmember support //
+///////////////////////
+
+namespace std // NOLINT(cert-dcl58-cpp)
+{
+
+/// @brief hash value for JSON objects
+/// @sa https://json.nlohmann.me/api/basic_json/std_hash/
+NLOHMANN_BASIC_JSON_TPL_DECLARATION
+struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL>
+{
+    std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
+    {
+        return nlohmann::detail::hash(j);
+    }
+};
+
+// specialization for std::less<value_t>
+template<>
+struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679
+{
+    /*!
+    @brief compare two value_t enum values
+    @since version 3.0.0
+    */
+    bool operator()(::nlohmann::detail::value_t lhs,
+                    ::nlohmann::detail::value_t rhs) const noexcept
+    {
+#if JSON_HAS_THREE_WAY_COMPARISON
+        return std::is_lt(lhs <=> rhs); // *NOPAD*
+#else
+        return ::nlohmann::detail::operator<(lhs, rhs);
+#endif
+    }
+};
+
+// C++20 prohibit function specialization in the std namespace.
+#ifndef JSON_HAS_CPP_20
+
+/// @brief exchanges the values of two JSON objects
+/// @sa https://json.nlohmann.me/api/basic_json/std_swap/
+NLOHMANN_BASIC_JSON_TPL_DECLARATION
+inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept(  // NOLINT(readability-inconsistent-declaration-parameter-name)
+    is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&&                          // NOLINT(misc-redundant-expression)
+    is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
+{
+    j1.swap(j2);
+}
+
+#endif
+
+}  // namespace std
+
+#if JSON_USE_GLOBAL_UDLS
+    using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
+    using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
+#endif
+
+// #include <nlohmann/detail/macro_unscope.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+// restore clang diagnostic settings
+#if defined(__clang__)
+    #pragma clang diagnostic pop
+#endif
+
+// clean up
+#undef JSON_ASSERT
+#undef JSON_INTERNAL_CATCH
+#undef JSON_THROW
+#undef JSON_PRIVATE_UNLESS_TESTED
+#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
+#undef NLOHMANN_BASIC_JSON_TPL
+#undef JSON_EXPLICIT
+#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL
+#undef JSON_INLINE_VARIABLE
+#undef JSON_NO_UNIQUE_ADDRESS
+#undef JSON_DISABLE_ENUM_SERIALIZATION
+#undef JSON_USE_GLOBAL_UDLS
+
+#ifndef JSON_TEST_KEEP_MACROS
+    #undef JSON_CATCH
+    #undef JSON_TRY
+    #undef JSON_HAS_CPP_11
+    #undef JSON_HAS_CPP_14
+    #undef JSON_HAS_CPP_17
+    #undef JSON_HAS_CPP_20
+    #undef JSON_HAS_FILESYSTEM
+    #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
+    #undef JSON_HAS_THREE_WAY_COMPARISON
+    #undef JSON_HAS_RANGES
+    #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
+#endif
+
+// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
+//     __ _____ _____ _____
+//  __|  |   __|     |   | |  JSON for Modern C++
+// |  |  |__   |  |  | | | |  version 3.11.2
+// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#undef JSON_HEDLEY_ALWAYS_INLINE
+#undef JSON_HEDLEY_ARM_VERSION
+#undef JSON_HEDLEY_ARM_VERSION_CHECK
+#undef JSON_HEDLEY_ARRAY_PARAM
+#undef JSON_HEDLEY_ASSUME
+#undef JSON_HEDLEY_BEGIN_C_DECLS
+#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
+#undef JSON_HEDLEY_CLANG_HAS_BUILTIN
+#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
+#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
+#undef JSON_HEDLEY_CLANG_HAS_EXTENSION
+#undef JSON_HEDLEY_CLANG_HAS_FEATURE
+#undef JSON_HEDLEY_CLANG_HAS_WARNING
+#undef JSON_HEDLEY_COMPCERT_VERSION
+#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
+#undef JSON_HEDLEY_CONCAT
+#undef JSON_HEDLEY_CONCAT3
+#undef JSON_HEDLEY_CONCAT3_EX
+#undef JSON_HEDLEY_CONCAT_EX
+#undef JSON_HEDLEY_CONST
+#undef JSON_HEDLEY_CONSTEXPR
+#undef JSON_HEDLEY_CONST_CAST
+#undef JSON_HEDLEY_CPP_CAST
+#undef JSON_HEDLEY_CRAY_VERSION
+#undef JSON_HEDLEY_CRAY_VERSION_CHECK
+#undef JSON_HEDLEY_C_DECL
+#undef JSON_HEDLEY_DEPRECATED
+#undef JSON_HEDLEY_DEPRECATED_FOR
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
+#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
+#undef JSON_HEDLEY_DIAGNOSTIC_POP
+#undef JSON_HEDLEY_DIAGNOSTIC_PUSH
+#undef JSON_HEDLEY_DMC_VERSION
+#undef JSON_HEDLEY_DMC_VERSION_CHECK
+#undef JSON_HEDLEY_EMPTY_BASES
+#undef JSON_HEDLEY_EMSCRIPTEN_VERSION
+#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
+#undef JSON_HEDLEY_END_C_DECLS
+#undef JSON_HEDLEY_FLAGS
+#undef JSON_HEDLEY_FLAGS_CAST
+#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
+#undef JSON_HEDLEY_GCC_HAS_BUILTIN
+#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
+#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
+#undef JSON_HEDLEY_GCC_HAS_EXTENSION
+#undef JSON_HEDLEY_GCC_HAS_FEATURE
+#undef JSON_HEDLEY_GCC_HAS_WARNING
+#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
+#undef JSON_HEDLEY_GCC_VERSION
+#undef JSON_HEDLEY_GCC_VERSION_CHECK
+#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
+#undef JSON_HEDLEY_GNUC_HAS_BUILTIN
+#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
+#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
+#undef JSON_HEDLEY_GNUC_HAS_EXTENSION
+#undef JSON_HEDLEY_GNUC_HAS_FEATURE
+#undef JSON_HEDLEY_GNUC_HAS_WARNING
+#undef JSON_HEDLEY_GNUC_VERSION
+#undef JSON_HEDLEY_GNUC_VERSION_CHECK
+#undef JSON_HEDLEY_HAS_ATTRIBUTE
+#undef JSON_HEDLEY_HAS_BUILTIN
+#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
+#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
+#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
+#undef JSON_HEDLEY_HAS_EXTENSION
+#undef JSON_HEDLEY_HAS_FEATURE
+#undef JSON_HEDLEY_HAS_WARNING
+#undef JSON_HEDLEY_IAR_VERSION
+#undef JSON_HEDLEY_IAR_VERSION_CHECK
+#undef JSON_HEDLEY_IBM_VERSION
+#undef JSON_HEDLEY_IBM_VERSION_CHECK
+#undef JSON_HEDLEY_IMPORT
+#undef JSON_HEDLEY_INLINE
+#undef JSON_HEDLEY_INTEL_CL_VERSION
+#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
+#undef JSON_HEDLEY_INTEL_VERSION
+#undef JSON_HEDLEY_INTEL_VERSION_CHECK
+#undef JSON_HEDLEY_IS_CONSTANT
+#undef JSON_HEDLEY_IS_CONSTEXPR_
+#undef JSON_HEDLEY_LIKELY
+#undef JSON_HEDLEY_MALLOC
+#undef JSON_HEDLEY_MCST_LCC_VERSION
+#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
+#undef JSON_HEDLEY_MESSAGE
+#undef JSON_HEDLEY_MSVC_VERSION
+#undef JSON_HEDLEY_MSVC_VERSION_CHECK
+#undef JSON_HEDLEY_NEVER_INLINE
+#undef JSON_HEDLEY_NON_NULL
+#undef JSON_HEDLEY_NO_ESCAPE
+#undef JSON_HEDLEY_NO_RETURN
+#undef JSON_HEDLEY_NO_THROW
+#undef JSON_HEDLEY_NULL
+#undef JSON_HEDLEY_PELLES_VERSION
+#undef JSON_HEDLEY_PELLES_VERSION_CHECK
+#undef JSON_HEDLEY_PGI_VERSION
+#undef JSON_HEDLEY_PGI_VERSION_CHECK
+#undef JSON_HEDLEY_PREDICT
+#undef JSON_HEDLEY_PRINTF_FORMAT
+#undef JSON_HEDLEY_PRIVATE
+#undef JSON_HEDLEY_PUBLIC
+#undef JSON_HEDLEY_PURE
+#undef JSON_HEDLEY_REINTERPRET_CAST
+#undef JSON_HEDLEY_REQUIRE
+#undef JSON_HEDLEY_REQUIRE_CONSTEXPR
+#undef JSON_HEDLEY_REQUIRE_MSG
+#undef JSON_HEDLEY_RESTRICT
+#undef JSON_HEDLEY_RETURNS_NON_NULL
+#undef JSON_HEDLEY_SENTINEL
+#undef JSON_HEDLEY_STATIC_ASSERT
+#undef JSON_HEDLEY_STATIC_CAST
+#undef JSON_HEDLEY_STRINGIFY
+#undef JSON_HEDLEY_STRINGIFY_EX
+#undef JSON_HEDLEY_SUNPRO_VERSION
+#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
+#undef JSON_HEDLEY_TINYC_VERSION
+#undef JSON_HEDLEY_TINYC_VERSION_CHECK
+#undef JSON_HEDLEY_TI_ARMCL_VERSION
+#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CL2000_VERSION
+#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CL430_VERSION
+#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CL6X_VERSION
+#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CL7X_VERSION
+#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
+#undef JSON_HEDLEY_TI_CLPRU_VERSION
+#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
+#undef JSON_HEDLEY_TI_VERSION
+#undef JSON_HEDLEY_TI_VERSION_CHECK
+#undef JSON_HEDLEY_UNAVAILABLE
+#undef JSON_HEDLEY_UNLIKELY
+#undef JSON_HEDLEY_UNPREDICTABLE
+#undef JSON_HEDLEY_UNREACHABLE
+#undef JSON_HEDLEY_UNREACHABLE_RETURN
+#undef JSON_HEDLEY_VERSION
+#undef JSON_HEDLEY_VERSION_DECODE_MAJOR
+#undef JSON_HEDLEY_VERSION_DECODE_MINOR
+#undef JSON_HEDLEY_VERSION_DECODE_REVISION
+#undef JSON_HEDLEY_VERSION_ENCODE
+#undef JSON_HEDLEY_WARNING
+#undef JSON_HEDLEY_WARN_UNUSED_RESULT
+#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
+#undef JSON_HEDLEY_FALL_THROUGH
+
+
+
+#endif  // INCLUDE_NLOHMANN_JSON_HPP_
index 147c354..54ce980 100644 (file)
@@ -1,4 +1,4 @@
-#include "flavor/flag-inscriptions-table.h"
+#include "flavor/flag-inscriptions-table.h"
 #include "object-enchant/tr-types.h"
 
 #ifdef JP
index 7d75329..4348dce 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <optional>
 #include <vector>
index 846efd2..bb7fbfd 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 武器/防具/アクセサリアイテムにおける、耐性やスレイ等の表記
  * @date 2020/07/06
  * @author Hourier
@@ -20,7 +20,6 @@
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trg-types.h"
 #include "object-hook/hook-quest.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "perception/object-perception.h"
 #include "player-base/player-class.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include <sstream>
 
 static std::string describe_chest_trap(const ItemEntity &item)
 {
-    auto trap_kinds = chest_traps[item.pval];
+    auto &trap_kinds = chest_traps[item.pval];
     if (trap_kinds.count() >= 2) {
         return _("(マルチ・トラップ)", " (Multiple Traps)");
     }
 
     auto trap_kind = trap_kinds.first();
-    if (!trap_kind.has_value()) {
+    if (!trap_kind) {
         return _("(施錠)", " (Locked)");
     }
 
-    switch (trap_kind.value()) {
+    switch (*trap_kind) {
     case ChestTrapType::LOSE_STR:
         return _("(毒針)", " (Poison Needle)");
     case ChestTrapType::LOSE_CON:
@@ -113,7 +111,7 @@ static bool should_show_ac_bonus(const ItemEntity &item)
 
 static bool should_show_slaying_bonus(const ItemEntity &item)
 {
-    if (object_flags(&item).has(TR_SHOW_MODS)) {
+    if (item.get_flags().has(TR_SHOW_MODS)) {
         return true;
     }
 
@@ -155,7 +153,7 @@ static std::string describe_weapon_dice(PlayerType *player_ptr, const ItemEntity
 static std::string describe_bow_power(PlayerType *player_ptr, const ItemEntity &item, const describe_option_type &opt)
 {
     auto power = item.get_arrow_magnification();
-    const auto tr_flags = object_flags(&item);
+    const auto tr_flags = item.get_flags();
     if (tr_flags.has(TR_XTRA_MIGHT)) {
         power++;
     }
@@ -356,7 +354,7 @@ static std::string describe_charges_rod(const ItemEntity &item)
 
 static std::string describe_pval_type(const ItemEntity &item)
 {
-    const auto tr_flags = object_flags(&item);
+    const auto tr_flags = item.get_flags();
     if (tr_flags.has(TR_HIDE_TYPE)) {
         return "";
     }
@@ -386,7 +384,7 @@ static std::string describe_pval_type(const ItemEntity &item)
 
 static std::string describe_pval(const ItemEntity &item)
 {
-    const auto tr_flags = object_flags(&item);
+    const auto tr_flags = item.get_flags();
     if (tr_flags.has_none_of(TR_PVAL_FLAG_MASK)) {
         return "";
     }
@@ -577,7 +575,7 @@ static describe_option_type decide_describe_option(const ItemEntity &item, BIT_F
  * @param mode 表記に関するオプション指定
  * @return modeに応じたオブジェクトの表記
  */
-std::string describe_flavor(PlayerType *player_ptr, const ItemEntity *o_ptr, BIT_FLAGS mode)
+std::string describe_flavor(PlayerType *player_ptr, const ItemEntity *o_ptr, BIT_FLAGS mode, const size_t max_length)
 {
     const auto &item = *o_ptr;
     const auto opt = decide_describe_option(item, mode);
@@ -585,7 +583,7 @@ std::string describe_flavor(PlayerType *player_ptr, const ItemEntity *o_ptr, BIT
     ss << describe_named_item(player_ptr, item, opt);
 
     if (any_bits(mode, OD_NAME_ONLY) || !o_ptr->is_valid()) {
-        return ss.str();
+        return str_substr(ss.str(), 0, max_length);
     }
 
     ss << describe_chest(item, opt)
@@ -604,14 +602,14 @@ std::string describe_flavor(PlayerType *player_ptr, const ItemEntity *o_ptr, BIT
 
     ss << describe_ac(item, opt);
     if (any_bits(mode, OD_NAME_AND_ENCHANT)) {
-        return ss.str();
+        return str_substr(ss.str(), 0, max_length);
     }
 
     ss << describe_remaining(item, opt);
     if (any_bits(mode, OD_OMIT_INSCRIPTION)) {
-        return ss.str();
+        return str_substr(ss.str(), 0, max_length);
     }
 
     ss << describe_inscription(item, opt);
-    return ss.str();
+    return str_substr(ss.str(), 0, max_length);
 }
index 633fce6..8b2ae47 100644 (file)
@@ -1,8 +1,8 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
-#include <string>
+#include <string_view>
 
 class ItemEntity;
 class PlayerType;
-std::string describe_flavor(PlayerType *player_ptr, const ItemEntity *o_ptr, const BIT_FLAGS mode);
+std::string describe_flavor(PlayerType *player_ptr, const ItemEntity *o_ptr, const BIT_FLAGS mode, const size_t max_length = std::string_view::npos);
index 06473ef..076f762 100644 (file)
@@ -1,13 +1,11 @@
-#include "flavor/flavor-util.h"
+#include "flavor/flavor-util.h"
 #include "flavor/flag-inscriptions-table.h"
 #include "object-enchant/tr-flags.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "sv-definition/sv-food-types.h"
 #include "system/artifact-type-definition.h"
 #include "system/item-entity.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include <sstream>
 
@@ -33,7 +31,7 @@ static std::string inscribe_flags_aux(const std::vector<flag_insc_table> &fi_vec
     std::stringstream ss;
 
     for (const auto &fi : fi_vec) {
-        if (flags.has(fi.flag) && (!fi.except_flag.has_value() || flags.has_not(fi.except_flag.value()))) {
+        if (flags.has(fi.flag) && (!fi.except_flag || flags.has_not(*fi.except_flag))) {
             const auto flag_str = _(is_kanji ? fi.japanese : fi.english, fi.english);
             ss << flag_str;
         }
@@ -52,7 +50,7 @@ static std::string inscribe_flags_aux(const std::vector<flag_insc_table> &fi_vec
 static bool has_flag_of(const std::vector<flag_insc_table> &fi_vec, const TrFlags &flags)
 {
     for (const auto &fi : fi_vec) {
-        if (flags.has(fi.flag) && (!fi.except_flag.has_value() || flags.has_not(fi.except_flag.value()))) {
+        if (flags.has(fi.flag) && (!fi.except_flag || flags.has_not(*fi.except_flag))) {
             return true;
         }
     }
@@ -69,7 +67,7 @@ static bool has_flag_of(const std::vector<flag_insc_table> &fi_vec, const TrFlag
  */
 std::string get_ability_abbreviation(const ItemEntity &item, bool is_kanji, bool all)
 {
-    auto flags = object_flags(&item);
+    auto flags = item.get_flags();
     if (!all) {
         const auto &baseitem = item.get_baseitem();
         flags.reset(baseitem.flags);
@@ -225,7 +223,7 @@ std::string get_inscription(const ItemEntity &item)
     std::stringstream ss;
 
     if (!item.is_fully_known()) {
-        for (std::string_view sv = item.inscription.value(); !sv.empty(); sv.remove_prefix(1)) {
+        for (std::string_view sv = *item.inscription; !sv.empty(); sv.remove_prefix(1)) {
             if (sv.front() == '#') {
                 break;
             }
@@ -244,7 +242,7 @@ std::string get_inscription(const ItemEntity &item)
         return ss.str();
     }
 
-    for (std::string_view sv = item.inscription.value(); !sv.empty(); sv.remove_prefix(1)) {
+    for (std::string_view sv = *item.inscription; !sv.empty(); sv.remove_prefix(1)) {
         switch (sv.front()) {
         case '#':
             return ss.str();
@@ -346,7 +344,7 @@ std::string describe_count_with_counter_suffix(const ItemEntity &item)
         break;
 
     case ItemKindType::FOOD:
-        if (item.bi_key.sval().value() == SV_FOOD_JERKY) {
+        if (item.bi_key.sval() == SV_FOOD_JERKY) {
             ss << "切れ";
             break;
         }
index b0a644c..de9cd0f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 96bddf0..2fc8b56 100644 (file)
@@ -1,4 +1,4 @@
-#include "flavor/named-item-describer.h"
+#include "flavor/named-item-describer.h"
 #include "artifact/fixed-art-types.h"
 #include "flavor/flavor-util.h"
 #include "flavor/object-flavor-types.h"
@@ -9,13 +9,11 @@
 #include "object-enchant/object-ego.h"
 #include "object-enchant/special-object-flags.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "perception/object-perception.h"
 #include "system/artifact-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #ifdef JP
 #else
@@ -28,7 +26,7 @@
 
 static std::string get_fullname_if_set(const ItemEntity &item, const describe_option_type &opt)
 {
-    if (!opt.aware || object_flags(&item).has_not(TR_FULL_NAME)) {
+    if (!opt.aware || item.get_flags().has_not(TR_FULL_NAME)) {
         return "";
     }
 
@@ -95,7 +93,7 @@ static std::string describe_unique_name_before_body_ja(const ItemEntity &item, c
     }
 
     if (item.is_random_artifact()) {
-        const std::string_view name_sv = item.randart_name.value();
+        const std::string_view name_sv = *item.randart_name;
 
         /* '『' から始まらない伝説のアイテムの名前は最初に付加する */
         /* 英語版のセーブファイルから来た 'of XXX' は,「XXXの」と表示する */
@@ -104,11 +102,11 @@ static std::string describe_unique_name_before_body_ja(const ItemEntity &item, c
             ss << name_sv.substr(3) << "の";
             return ss.str();
         } else if (!name_sv.starts_with("『") && !name_sv.starts_with("《") && !name_sv.starts_with('\'')) {
-            return item.randart_name.value();
+            return *item.randart_name;
         }
     }
 
-    if (item.is_fixed_artifact() && object_flags(&item).has_not(TR_FULL_NAME)) {
+    if (item.is_fixed_artifact() && item.get_flags().has_not(TR_FULL_NAME)) {
         const auto &artifact = item.get_fixed_artifact();
         /* '『' から始まらない伝説のアイテムの名前は最初に付加する */
         if (artifact.name.find("『", 0, 2) != 0) {
@@ -131,7 +129,7 @@ static std::optional<std::string> describe_random_artifact_name_after_body_ja(co
         return std::nullopt;
     }
 
-    const std::string_view name_sv = item.randart_name.value();
+    const std::string_view name_sv = *item.randart_name;
     if (name_sv.starts_with("『") || name_sv.starts_with("《")) {
         return item.randart_name;
     }
@@ -194,8 +192,8 @@ static std::string describe_unique_name_after_body_ja(const ItemEntity &item, co
         return "";
     }
 
-    if (auto body = describe_random_artifact_name_after_body_ja(item); body.has_value()) {
-        return body.value();
+    if (auto body = describe_random_artifact_name_after_body_ja(item); body) {
+        return *body;
     }
 
     if (item.is_fixed_artifact()) {
@@ -281,14 +279,14 @@ static std::string describe_item_count_or_definite_article_en(const ItemEntity &
 
 static std::string describe_unique_name_after_body_en(const ItemEntity &item, const describe_option_type &opt)
 {
-    if (!opt.known || object_flags(&item).has(TR_FULL_NAME) || any_bits(opt.mode, OD_BASE_NAME)) {
+    if (!opt.known || item.get_flags().has(TR_FULL_NAME) || any_bits(opt.mode, OD_BASE_NAME)) {
         return "";
     }
 
     std::stringstream ss;
 
     if (item.is_random_artifact()) {
-        ss << ' ' << item.randart_name.value();
+        ss << ' ' << *item.randart_name;
         return ss.str();
     }
 
@@ -429,7 +427,7 @@ std::string describe_named_item(PlayerType *player_ptr, const ItemEntity &item,
 #endif
     if (item.is_spell_book()) {
         // svalは0から数えているので表示用に+1している
-        ss << format("Lv%d ", item.bi_key.sval().value() + 1);
+        ss << format("Lv%d ", *item.bi_key.sval() + 1);
     }
 
     ss << describe_body(item, opt, basename_sv, modstr);
index 343fe1b..9d4dae5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 
index bedac2a..41879de 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum object_description_type {
     OD_NAME_ONLY = 0x00000001, /* Omit values, pval, inscription */
index a645aa6..910d4a3 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  *  @brief オブジェクトの記述処理 / Mbject flavor code
  *  @date 2014/01/03
  *  @author
@@ -29,7 +29,6 @@
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trg-types.h"
 #include "object-hook/hook-quest.h"
-#include "object/object-flags.h"
 #include "object/object-info.h"
 #include "perception/object-perception.h"
 #include "player-info/class-info.h"
@@ -38,7 +37,6 @@
 #include "sv-definition/sv-lite-types.h"
 #include "system/baseitem-info.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include <functional>
 #include <sstream>
@@ -54,8 +52,8 @@ std::string get_table_name_aux()
 {
     std::stringstream ss;
 #ifdef JP
-    ss << get_random_line("aname_j.txt", 1).value();
-    ss << get_random_line("aname_j.txt", 2).value();
+    ss << *get_random_line("aname_j.txt", 1);
+    ss << *get_random_line("aname_j.txt", 2);
     return ss.str();
 #else
     static const std::vector<std::string_view> syllables = {
@@ -72,12 +70,12 @@ std::string get_table_name_aux()
     int testcounter = randint1(3) + 1;
     if (randint1(3) == 2) {
         while (testcounter--) {
-            ss << syllables[randint0(syllables.size())];
+            ss << rand_choice(syllables);
         }
     } else {
         testcounter = randint1(2) + 1;
         while (testcounter--) {
-            ss << get_random_line("elvish.txt", 0).value();
+            ss << *get_random_line("elvish.txt", 0);
         }
     }
 
@@ -105,8 +103,8 @@ std::string get_table_name()
 std::string get_table_sindarin_aux()
 {
     std::stringstream ss;
-    ss << get_random_line("sname.txt", 1).value();
-    ss << get_random_line("sname.txt", 2).value();
+    ss << *get_random_line("sname.txt", 1);
+    ss << *get_random_line("sname.txt", 2);
     auto name = ss.str();
     return _(sindarin_to_kana(name), name);
 }
index f0308e8..aabba8b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 
index 16d4acc..ab417d0 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 個々のアイテム種別について、未鑑定名/鑑定後の正式な名前を取得する処理
  * @date 2020/07/07
  * @author Hourier
@@ -36,7 +36,7 @@ static std::pair<std::string, std::string> describe_monster_ball(const ItemEntit
     }
 
 #ifdef JP
-    std::string modstr = format(" (%s)", r_ptr->name.data());
+    const auto modstr = format(" (%s)", r_ptr->name.data());
 #else
     std::string modstr;
     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
index 213de7b..c9b73d3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 #include <utility>
index 41ace4f..2e80f60 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/cave-generator.h"
+#include "floor/cave-generator.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest-monster-placer.h"
 #include "floor/dungeon-tunnel-util.h"
@@ -129,16 +129,14 @@ static bool decide_tunnel_planned_site(PlayerType *player_ptr, dun_data_type *dd
 
 static void make_tunnels(PlayerType *player_ptr, dun_data_type *dd_ptr)
 {
-    for (int j = 0; j < dd_ptr->tunn_n; j++) {
-        grid_type *g_ptr;
-        TerrainType *f_ptr;
-        dd_ptr->tunnel_y = dd_ptr->tunn[j].y;
-        dd_ptr->tunnel_x = dd_ptr->tunn[j].x;
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[dd_ptr->tunnel_y][dd_ptr->tunnel_x];
-        f_ptr = &terrains_info[g_ptr->feat];
-        if (f_ptr->flags.has_not(TerrainCharacteristics::MOVE) || f_ptr->flags.has_none_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::LAVA })) {
-            g_ptr->mimic = 0;
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
+    for (auto i = 0; i < dd_ptr->tunn_n; i++) {
+        dd_ptr->tunnel_y = dd_ptr->tunn[i].y;
+        dd_ptr->tunnel_x = dd_ptr->tunn[i].x;
+        auto &grid = player_ptr->current_floor_ptr->grid_array[dd_ptr->tunnel_y][dd_ptr->tunnel_x];
+        const auto &terrain = grid.get_terrain();
+        if (terrain.flags.has_not(TerrainCharacteristics::MOVE) || terrain.flags.has_none_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::LAVA })) {
+            grid.mimic = 0;
+            place_grid(player_ptr, &grid, GB_FLOOR);
         }
     }
 }
@@ -146,7 +144,7 @@ static void make_tunnels(PlayerType *player_ptr, dun_data_type *dd_ptr)
 static void make_walls(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr, dt_type *dt_ptr)
 {
     for (int j = 0; j < dd_ptr->wall_n; j++) {
-        grid_type *g_ptr;
+        Grid *g_ptr;
         dd_ptr->tunnel_y = dd_ptr->wall[j].y;
         dd_ptr->tunnel_x = dd_ptr->wall[j].x;
         g_ptr = &player_ptr->current_floor_ptr->grid_array[dd_ptr->tunnel_y][dd_ptr->tunnel_x];
@@ -204,7 +202,7 @@ static bool make_one_floor(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeo
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
 
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_ROOM)) {
+    if (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::NO_ROOM)) {
         make_only_tunnel_points(floor_ptr, dd_ptr);
     } else {
         if (!generate_rooms(player_ptr, dd_ptr)) {
@@ -286,34 +284,34 @@ static void make_aqua_streams(PlayerType *player_ptr, dun_data_type *dd_ptr, dun
  * @brief マスにフロア端用の永久壁を配置する / Set boundary mimic and add "solid" perma-wall
  * @param g_ptr 永久壁を配置したいマス構造体の参照ポインタ
  */
-static void place_bound_perm_wall(PlayerType *player_ptr, grid_type *g_ptr)
+static void place_bound_perm_wall(PlayerType *player_ptr, Grid &grid)
 {
     if (bound_walls_perm) {
-        g_ptr->mimic = 0;
-        place_grid(player_ptr, g_ptr, GB_SOLID_PERM);
+        grid.mimic = 0;
+        place_grid(player_ptr, &grid, GB_SOLID_PERM);
         return;
     }
 
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    if (f_ptr->flags.has_any_of({ TerrainCharacteristics::HAS_GOLD, TerrainCharacteristics::HAS_ITEM }) && f_ptr->flags.has_not(TerrainCharacteristics::SECRET)) {
-        g_ptr->feat = feat_state(player_ptr->current_floor_ptr, g_ptr->feat, TerrainCharacteristics::ENSECRET);
+    const auto &terrain = grid.get_terrain();
+    if (terrain.flags.has_any_of({ TerrainCharacteristics::HAS_GOLD, TerrainCharacteristics::HAS_ITEM }) && terrain.flags.has_not(TerrainCharacteristics::SECRET)) {
+        grid.feat = feat_state(player_ptr->current_floor_ptr, grid.feat, TerrainCharacteristics::ENSECRET);
     }
 
-    g_ptr->mimic = g_ptr->feat;
-    place_grid(player_ptr, g_ptr, GB_SOLID_PERM);
+    grid.mimic = grid.feat;
+    place_grid(player_ptr, &grid, GB_SOLID_PERM);
 }
 
 static void make_perm_walls(PlayerType *player_ptr)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    for (POSITION x = 0; x < floor_ptr->width; x++) {
-        place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[0][x]);
-        place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[floor_ptr->height - 1][x]);
+    auto &floor = *player_ptr->current_floor_ptr;
+    for (POSITION x = 0; x < floor.width; x++) {
+        place_bound_perm_wall(player_ptr, floor.get_grid({ 0, x }));
+        place_bound_perm_wall(player_ptr, floor.get_grid({ floor.height - 1, x }));
     }
 
-    for (POSITION y = 1; y < (floor_ptr->height - 1); y++) {
-        place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[y][0]);
-        place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[y][floor_ptr->width - 1]);
+    for (POSITION y = 1; y < (floor.height - 1); y++) {
+        place_bound_perm_wall(player_ptr, floor.get_grid({ y, 0 }));
+        place_bound_perm_wall(player_ptr, floor.get_grid({ y, floor.width - 1 }));
     }
 }
 
@@ -435,7 +433,7 @@ bool cave_gen(PlayerType *player_ptr, concptr *why)
     }
 
     dd_ptr->cent_n = 0;
-    auto *d_ptr = &dungeons_info[floor_ptr->dungeon_idx];
+    auto *d_ptr = &floor_ptr->get_dungeon_definition();
     constexpr auto chance_empty_floor = 24;
     if (ironman_empty_levels || (d_ptr->flags.has(DungeonFeatureType::ARENA) && (empty_levels && one_in_(chance_empty_floor)))) {
         dd_ptr->empty_level = true;
index e54bd77..5af3fdc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3ceb963..cfbd262 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ダンジョンの壁等に関する判定関数の集合
  * @date 2020/07/18
  * @author Hourier
@@ -8,6 +8,7 @@
 
 #include "floor/cave.h"
 #include "grid/grid.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
@@ -18,7 +19,7 @@
 /*
  * Determines if a map location is fully inside the outer walls
  */
-bool in_bounds(FloorType *floor_ptr, POSITION y, POSITION x)
+bool in_bounds(FloorType *floor_ptr, int y, int x)
 {
     return (y > 0) && (x > 0) && (y < floor_ptr->height - 1) && (x < floor_ptr->width - 1);
 }
@@ -26,7 +27,7 @@ bool in_bounds(FloorType *floor_ptr, POSITION y, POSITION x)
 /*
  * Determines if a map location is on or inside the outer walls
  */
-bool in_bounds2(FloorType *floor_ptr, POSITION y, POSITION x)
+bool in_bounds2(FloorType *floor_ptr, int y, int x)
 {
     return (y >= 0) && (x >= 0) && (y < floor_ptr->height) && (x < floor_ptr->width);
 }
@@ -35,7 +36,7 @@ bool in_bounds2(FloorType *floor_ptr, POSITION y, POSITION x)
  * Determines if a map location is on or inside the outer walls
  * (unsigned version)
  */
-bool in_bounds2u(FloorType *floor_ptr, POSITION y, POSITION x)
+bool in_bounds2u(FloorType *floor_ptr, int y, int x)
 {
     return (y < floor_ptr->height) && (x < floor_ptr->width);
 }
@@ -48,12 +49,12 @@ bool in_bounds2u(FloorType *floor_ptr, POSITION y, POSITION x)
  * Line 2 -- forbid normal monsters
  * Line 3 -- forbid the player
  */
-bool is_cave_empty_bold(PlayerType *player_ptr, POSITION y, POSITION x)
+bool is_cave_empty_bold(PlayerType *player_ptr, int y, int x)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     bool is_empty_grid = cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PLACE);
     is_empty_grid &= !(floor_ptr->grid_array[y][x].m_idx);
-    is_empty_grid &= !player_bold(player_ptr, y, x);
+    is_empty_grid &= !player_ptr->is_located_at({ y, x });
     return is_empty_grid;
 }
 
@@ -64,40 +65,28 @@ bool is_cave_empty_bold(PlayerType *player_ptr, POSITION y, POSITION x)
  * Line 1 -- forbid non-empty grids
  * Line 2 -- forbid trees while dungeon generation
  */
-bool is_cave_empty_bold2(PlayerType *player_ptr, POSITION y, POSITION x)
+bool is_cave_empty_bold2(PlayerType *player_ptr, int y, int x)
 {
     bool is_empty_grid = is_cave_empty_bold(player_ptr, y, x);
     is_empty_grid &= w_ptr->character_dungeon || !cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::TREE);
     return is_empty_grid;
 }
 
-bool cave_has_flag_bold(FloorType *floor_ptr, POSITION y, POSITION x, TerrainCharacteristics f_idx)
+bool cave_has_flag_bold(const FloorType *floor_ptr, int y, int x, TerrainCharacteristics f_idx)
 {
-    return terrains_info[floor_ptr->grid_array[y][x].feat].flags.has(f_idx);
-}
-
-/*
- * Determine if a "legal" grid is within "los" of the player
- */
-bool player_has_los_bold(PlayerType *player_ptr, POSITION y, POSITION x)
-{
-    return ((player_ptr->current_floor_ptr->grid_array[y][x].info & CAVE_VIEW) != 0) || player_ptr->phase_out;
-}
-
-/*
- * Determine if player is on this grid
- */
-bool player_bold(PlayerType *player_ptr, POSITION y, POSITION x)
-{
-    return (y == player_ptr->y) && (x == player_ptr->x);
+    const Pos2D pos(y, x);
+    return floor_ptr->get_grid(pos).get_terrain().flags.has(f_idx);
 }
 
 /*
  * Does the grid stop disintegration?
  */
-bool cave_stop_disintegration(FloorType *floor_ptr, POSITION y, POSITION x)
+bool cave_stop_disintegration(FloorType *floor_ptr, int y, int x)
 {
-    return !cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PROJECT) && (!cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::HURT_DISI) || cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PERMANENT));
+    const auto can_stop = !cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PROJECT);
+    auto is_bold = !cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::HURT_DISI);
+    is_bold |= cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PERMANENT);
+    return can_stop && is_bold;
 }
 
 /*
@@ -107,7 +96,7 @@ bool cave_stop_disintegration(FloorType *floor_ptr, POSITION y, POSITION x)
  * @param x 指定X座標
  * @return 光を通すならばtrueを返す。
  */
-bool cave_los_bold(FloorType *floor_ptr, POSITION y, POSITION x)
+bool cave_los_bold(FloorType *floor_ptr, int y, int x)
 {
     return feat_supports_los(floor_ptr->grid_array[y][x].feat);
 }
@@ -115,9 +104,9 @@ bool cave_los_bold(FloorType *floor_ptr, POSITION y, POSITION x)
 /*
  * Determine if a "feature" supports "los"
  */
-bool feat_supports_los(FEAT_IDX f_idx)
+bool feat_supports_los(short f_idx)
 {
-    return terrains_info[f_idx].flags.has(TerrainCharacteristics::LOS);
+    return TerrainList::get_instance()[f_idx].flags.has(TerrainCharacteristics::LOS);
 }
 
 /*
@@ -128,7 +117,7 @@ bool feat_supports_los(FEAT_IDX f_idx)
  * Line 2 -- forbid object terrains
  * Line 3 -- forbid normal objects
  */
-bool cave_clean_bold(FloorType *floor_ptr, POSITION y, POSITION x)
+bool cave_clean_bold(FloorType *floor_ptr, int y, int x)
 {
     return cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::FLOOR) && ((floor_ptr->grid_array[y][x].is_object()) == 0) && floor_ptr->grid_array[y][x].o_idx_list.empty();
 }
@@ -139,12 +128,12 @@ bool cave_clean_bold(FloorType *floor_ptr, POSITION y, POSITION x)
  * Line 1 -- forbid non-drops
  * Line 2 -- forbid object terrains
  */
-bool cave_drop_bold(FloorType *floor_ptr, POSITION y, POSITION x)
+bool cave_drop_bold(FloorType *floor_ptr, int y, int x)
 {
     return cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::DROP) && ((floor_ptr->grid_array[y][x].is_object()) == 0);
 }
 
-bool pattern_tile(FloorType *floor_ptr, POSITION y, POSITION x)
+bool pattern_tile(FloorType *floor_ptr, int y, int x)
 {
     return cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PATTERN);
 }
index 1f056d5..2495c24 100644 (file)
@@ -1,22 +1,17 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 class FloorType;
-struct grid_type;
 class PlayerType;
 enum class TerrainCharacteristics;
-bool in_bounds(FloorType *floor_ptr, POSITION y, POSITION x);
-bool in_bounds2(FloorType *floor_ptr, POSITION y, POSITION x);
-bool in_bounds2u(FloorType *floor_ptr, POSITION y, POSITION x);
-bool is_cave_empty_bold(PlayerType *player_ptr, POSITION x, POSITION y);
-bool is_cave_empty_bold2(PlayerType *player_ptr, POSITION x, POSITION y);
-bool cave_has_flag_bold(FloorType *floor_ptr, POSITION y, POSITION x, TerrainCharacteristics f_idx);
-bool player_has_los_bold(PlayerType *player_ptr, POSITION y, POSITION x);
-bool player_bold(PlayerType *player_ptr, POSITION y, POSITION x);
-bool cave_stop_disintegration(FloorType *floor_ptr, POSITION y, POSITION x);
-bool cave_los_bold(FloorType *floor_ptr, POSITION y, POSITION x);
-bool feat_supports_los(FEAT_IDX f_idx);
-bool cave_clean_bold(FloorType *floor_ptr, POSITION y, POSITION x);
-bool cave_drop_bold(FloorType *floor_ptr, POSITION y, POSITION x);
-bool pattern_tile(FloorType *floor_ptr, POSITION y, POSITION x);
+bool in_bounds(FloorType *floor_ptr, int y, int x);
+bool in_bounds2(FloorType *floor_ptr, int y, int x);
+bool in_bounds2u(FloorType *floor_ptr, int y, int x);
+bool is_cave_empty_bold(PlayerType *player_ptr, int x, int y);
+bool is_cave_empty_bold2(PlayerType *player_ptr, int x, int y);
+bool cave_has_flag_bold(const FloorType *floor_ptr, int y, int x, TerrainCharacteristics f_idx);
+bool cave_stop_disintegration(FloorType *floor_ptr, int y, int x);
+bool cave_los_bold(FloorType *floor_ptr, int y, int x);
+bool feat_supports_los(short f_idx);
+bool cave_clean_bold(FloorType *floor_ptr, int y, int x);
+bool cave_drop_bold(FloorType *floor_ptr, int y, int x);
+bool pattern_tile(FloorType *floor_ptr, int y, int x);
index ec17e25..f82d1fa 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/dungeon-tunnel-util.h"
+#include "floor/dungeon-tunnel-util.h"
 #include "system/angband.h"
 
 /*
index 3359f01..87a82c8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct dt_type {
     int dun_tun_rnd; /*!< ダンジョンの通路方向を掻き回す頻度(一回の試行ごとに%で判定している) */
index 06c6364..2017859 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/fixed-map-generator.h"
+#include "floor/fixed-map-generator.h"
 #include "artifact/fixed-art-generator.h"
 #include "artifact/fixed-art-types.h"
 #include "dungeon/quest.h"
@@ -115,7 +115,7 @@ static void parse_qtw_D(PlayerType *player_ptr, qtwg_type *qtwg_ptr, char *s)
         if (random & RANDOM_MONSTER) {
             floor_ptr->monster_level = floor_ptr->base_level + monster_index;
 
-            place_monster(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP | PM_NO_QUEST));
+            place_random_monster(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP | PM_NO_QUEST));
 
             floor_ptr->monster_level = floor_ptr->base_level;
         } else if (monster_index) {
@@ -135,14 +135,14 @@ static void parse_qtw_D(PlayerType *player_ptr, qtwg_type *qtwg_ptr, char *s)
 
             if (r_ref.kind_flags.has(MonsterKindType::UNIQUE)) {
                 r_ref.cur_num = 0;
-                r_ref.max_num = 1;
+                r_ref.max_num = MAX_UNIQUE_NUM;
             } else if (r_ref.population_flags.has(MonsterPopulationType::NAZGUL)) {
                 if (r_ref.cur_num == r_ref.max_num) {
                     r_ref.max_num++;
                 }
             }
 
-            place_monster_aux(player_ptr, 0, *qtwg_ptr->y, *qtwg_ptr->x, r_idx, (PM_ALLOW_SLEEP | PM_NO_KAGE));
+            place_specific_monster(player_ptr, 0, *qtwg_ptr->y, *qtwg_ptr->x, r_idx, (PM_ALLOW_SLEEP | PM_NO_KAGE));
             if (clone) {
                 floor_ptr->m_list[hack_m_idx_ii].mflag2.set(MonsterConstantFlagType::CLONED);
                 r_ref.cur_num = old_cur_num;
@@ -160,7 +160,7 @@ static void parse_qtw_D(PlayerType *player_ptr, qtwg_type *qtwg_ptr, char *s)
             if (randint0(100) < 75) {
                 place_object(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x, 0L);
             } else {
-                place_trap(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x);
+                place_trap(floor_ptr, *qtwg_ptr->y, *qtwg_ptr->x);
             }
 
             floor_ptr->object_level = floor_ptr->base_level;
@@ -176,7 +176,7 @@ static void parse_qtw_D(PlayerType *player_ptr, qtwg_type *qtwg_ptr, char *s)
 
             floor_ptr->object_level = floor_ptr->base_level;
         } else if (random & RANDOM_TRAP) {
-            place_trap(player_ptr, *qtwg_ptr->y, *qtwg_ptr->x);
+            place_trap(floor_ptr, *qtwg_ptr->y, *qtwg_ptr->x);
         } else if (letter[idx].trap) {
             g_ptr->mimic = g_ptr->feat;
             g_ptr->feat = conv_dungeon_feat(floor_ptr, letter[idx].trap);
@@ -369,7 +369,7 @@ static bool parse_qtw_P(PlayerType *player_ptr, qtwg_type *qtwg_ptr, char **zz)
     floor_ptr->width = panels_x * SCREEN_WID;
     panel_row_min = floor_ptr->height;
     panel_col_min = floor_ptr->width;
-    if (inside_quest(floor_ptr->quest_number)) {
+    if (floor_ptr->is_in_quest()) {
         POSITION py = atoi(zz[0]);
         POSITION px = atoi(zz[1]);
         player_ptr->y = py;
index 11f7e9b..72f8347 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d6b429c..d624b0e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* Dungeon allocation "places" */
 enum dap_type : int {
index 633a7f2..6e1df18 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @brief ダンジョンの最深層 / Maximum dungeon level.
index 0f2473c..5b0c18d 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/floor-changer.h"
+#include "floor/floor-changer.h"
 #include "action/travel-execution.h"
 #include "dungeon/quest-monster-placer.h"
 #include "dungeon/quest.h"
@@ -118,7 +118,7 @@ static MonsterRaceInfo &set_pet_params(PlayerType *player_ptr, const int current
     m_ptr->mtimed[MTIMED_CSLEEP] = 0;
     m_ptr->hold_o_idx_list.clear();
     m_ptr->target_y = 0;
-    auto &r_ref = m_ptr->get_real_r_ref();
+    auto &r_ref = m_ptr->get_real_monrace();
     if (r_ref.behavior_flags.has(MonsterBehaviorType::PREVENT_SUDDEN_MAGIC) && !ironman_nightmare) {
         m_ptr->mflag.set(MonsterTemporaryFlagType::PREVENT_MAGIC);
     }
@@ -150,10 +150,10 @@ static void place_pet(PlayerType *player_ptr)
             }
         } else {
             auto *m_ptr = &party_mon[current_monster];
-            auto &r_ref = m_ptr->get_real_r_ref();
+            auto &r_ref = m_ptr->get_real_monrace();
             msg_format(_("%sとはぐれてしまった。", "You have lost sight of %s."), monster_desc(player_ptr, m_ptr, 0).data());
             if (record_named_pet && m_ptr->is_named()) {
-                exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_LOST_SIGHT, monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE).data());
+                exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_LOST_SIGHT, monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE));
             }
 
             if (r_ref.cur_num) {
@@ -182,7 +182,7 @@ static void update_unique_artifact(FloorType *floor_ptr, int16_t cur_floor_id)
             continue;
         }
 
-        auto &r_ref = m_ref.get_real_r_ref();
+        auto &r_ref = m_ref.get_real_monrace();
         if (r_ref.kind_flags.has(MonsterKindType::UNIQUE) || (r_ref.population_flags.has(MonsterPopulationType::NAZGUL))) {
             r_ref.floor_id = cur_floor_id;
         }
@@ -217,7 +217,7 @@ static void check_visited_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr
     }
 
     if (player_ptr->change_floor_mode & (CFM_DOWN | CFM_UP)) {
-        g_ptr->feat = feat_ground_type[randint0(100)];
+        g_ptr->feat = rand_choice(feat_ground_type);
     }
 
     g_ptr->special = 0;
@@ -268,7 +268,7 @@ static void reset_unique_by_floor_change(PlayerType *player_ptr)
             (void)set_monster_invulner(player_ptr, i, 0, false);
         }
 
-        const auto &r_ref = m_ptr->get_real_r_ref();
+        const auto &r_ref = m_ptr->get_real_monrace();
         if (r_ref.kind_flags.has_not(MonsterKindType::UNIQUE) && r_ref.population_flags.has_not(MonsterPopulationType::NAZGUL)) {
             continue;
         }
@@ -282,15 +282,16 @@ static void reset_unique_by_floor_change(PlayerType *player_ptr)
 static void new_floor_allocation(PlayerType *player_ptr, saved_floor_type *sf_ptr)
 {
     GAME_TURN tmp_last_visit = sf_ptr->last_visit;
-    int alloc_chance = dungeons_info[player_ptr->dungeon_idx].max_m_alloc_chance;
+    const auto &floor = *player_ptr->current_floor_ptr;
+    auto alloc_chance = floor.get_dungeon_definition().max_m_alloc_chance;
     while (tmp_last_visit > w_ptr->game_turn) {
         tmp_last_visit -= TURNS_PER_TICK * TOWN_DAWN;
     }
 
     GAME_TURN absence_ticks = (w_ptr->game_turn - tmp_last_visit) / TURNS_PER_TICK;
     reset_unique_by_floor_change(player_ptr);
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->o_max; i++) {
-        auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i];
+    for (MONSTER_IDX i = 1; i < floor.o_max; i++) {
+        const auto *o_ptr = &floor.o_list[i];
         if (!o_ptr->is_valid() || !o_ptr->is_fixed_artifact()) {
             continue;
         }
@@ -339,16 +340,17 @@ static void update_new_floor_feature(PlayerType *player_ptr, saved_floor_type *s
 
     check_dead_end(player_ptr, sf_ptr);
     sf_ptr->last_visit = w_ptr->game_turn;
-    sf_ptr->dun_level = player_ptr->current_floor_ptr->dun_level;
+    auto &floor = *player_ptr->current_floor_ptr;
+    sf_ptr->dun_level = floor.dun_level;
     if ((player_ptr->change_floor_mode & CFM_NO_RETURN) != 0) {
         return;
     }
 
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
-    if ((player_ptr->change_floor_mode & CFM_UP) && !inside_quest(quest_number(player_ptr, player_ptr->current_floor_ptr->dun_level))) {
-        g_ptr->feat = (player_ptr->change_floor_mode & CFM_SHAFT) ? feat_state(player_ptr->current_floor_ptr, feat_down_stair, TerrainCharacteristics::SHAFT) : feat_down_stair;
+    auto *g_ptr = &floor.grid_array[player_ptr->y][player_ptr->x];
+    if ((player_ptr->change_floor_mode & CFM_UP) && !inside_quest(floor.get_quest_id())) {
+        g_ptr->feat = (player_ptr->change_floor_mode & CFM_SHAFT) ? feat_state(&floor, feat_down_stair, TerrainCharacteristics::SHAFT) : feat_down_stair;
     } else if ((player_ptr->change_floor_mode & CFM_DOWN) && !ironman_downward) {
-        g_ptr->feat = (player_ptr->change_floor_mode & CFM_SHAFT) ? feat_state(player_ptr->current_floor_ptr, feat_up_stair, TerrainCharacteristics::SHAFT) : feat_up_stair;
+        g_ptr->feat = (player_ptr->change_floor_mode & CFM_SHAFT) ? feat_state(&floor, feat_up_stair, TerrainCharacteristics::SHAFT) : feat_up_stair;
     }
 
     g_ptr->mimic = 0;
index 21ea1a6..ce6483a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void change_floor(PlayerType *player_ptr);
index 055315d..f40861c 100644 (file)
@@ -1,8 +1,6 @@
-#include "floor/floor-events.h"
+#include "floor/floor-events.h"
 #include "cmd-io/cmd-dump.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h"
@@ -31,6 +29,7 @@
 #include "sv-definition/sv-amulet-types.h"
 #include "sv-definition/sv-protector-types.h"
 #include "sv-definition/sv-ring-types.h"
+#include "system/angband-system.h"
 #include "system/baseitem-info.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include "world/world.h"
 
+static void update_sun_light(PlayerType *player_ptr)
+{
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+        StatusRecalculatingFlag::MONSTER_LITE,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags);
+    if ((player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) != 0) {
+        set_superstealth(player_ptr, false);
+    }
+}
+
 void day_break(PlayerType *player_ptr)
 {
     msg_print(_("夜が明けた。", "The sun has risen."));
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!player_ptr->wild_mode) {
-        for (POSITION y = 0; y < floor_ptr->height; y++) {
-            for (POSITION x = 0; x < floor_ptr->width; x++) {
-                auto *g_ptr = &floor_ptr->grid_array[y][x];
-                g_ptr->info |= CAVE_GLOW;
-                if (view_perma_grids) {
-                    g_ptr->info |= CAVE_MARK;
-                }
+    if (player_ptr->wild_mode) {
+        update_sun_light(player_ptr);
+        return;
+    }
 
-                note_spot(player_ptr, y, x);
+    for (auto y = 0; y < floor_ptr->height; y++) {
+        for (auto x = 0; x < floor_ptr->width; x++) {
+            auto *g_ptr = &floor_ptr->grid_array[y][x];
+            g_ptr->info |= CAVE_GLOW;
+            if (view_perma_grids) {
+                g_ptr->info |= CAVE_MARK;
             }
+
+            note_spot(player_ptr, y, x);
         }
     }
 
-    player_ptr->update |= PU_MONSTER_STATUSES | PU_MONSTER_LITE;
-    player_ptr->redraw |= PR_MAP;
-    player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
-    if ((floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) != 0) {
-        set_superstealth(player_ptr, false);
-    }
+    update_sun_light(player_ptr);
 }
 
 void night_falls(PlayerType *player_ptr)
 {
     msg_print(_("日が沈んだ。", "The sun has fallen."));
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!player_ptr->wild_mode) {
-        for (POSITION y = 0; y < floor_ptr->height; y++) {
-            for (POSITION x = 0; x < floor_ptr->width; x++) {
-                auto *g_ptr = &floor_ptr->grid_array[y][x];
-                auto *f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
-                if (g_ptr->is_mirror() || f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER) || f_ptr->flags.has(TerrainCharacteristics::ENTRANCE)) {
-                    continue;
-                }
+    if (player_ptr->wild_mode) {
+        update_sun_light(player_ptr);
+        return;
+    }
 
-                g_ptr->info &= ~(CAVE_GLOW);
-                if (f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
-                    g_ptr->info &= ~(CAVE_MARK);
-                    note_spot(player_ptr, y, x);
-                }
+    auto &floor = *player_ptr->current_floor_ptr;
+    for (auto y = 0; y < floor.height; y++) {
+        for (auto x = 0; x < floor.width; x++) {
+            const Pos2D pos(y, x);
+            auto &grid = floor.get_grid(pos);
+            const auto &terrain = grid.get_terrain_mimic();
+            using Tc = TerrainCharacteristics;
+            if (grid.is_mirror() || terrain.flags.has(Tc::QUEST_ENTER) || terrain.flags.has(Tc::ENTRANCE)) {
+                continue;
             }
 
-            glow_deep_lava_and_bldg(player_ptr);
+            grid.info &= ~(CAVE_GLOW);
+            if (terrain.flags.has_not(Tc::REMEMBER)) {
+                grid.info &= ~(CAVE_MARK);
+                note_spot(player_ptr, y, x);
+            }
         }
-    }
-
-    player_ptr->update |= PU_MONSTER_STATUSES | PU_MONSTER_LITE;
-    player_ptr->redraw |= PR_MAP;
-    player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
 
-    if ((floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) != 0) {
-        set_superstealth(player_ptr, false);
+        glow_deep_lava_and_bldg(player_ptr);
     }
+
+    update_sun_light(player_ptr);
 }
 
 /*!
@@ -133,7 +149,7 @@ static byte get_dungeon_feeling(PlayerType *player_ptr)
             continue;
         }
 
-        r_ptr = &monraces_info[m_ptr->r_idx];
+        r_ptr = &m_ptr->get_monrace();
         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
             if (r_ptr->level + 10 > floor_ptr->dun_level) {
                 delta += (r_ptr->level + 10 - floor_ptr->dun_level) * 2 * base;
@@ -266,21 +282,21 @@ static byte get_dungeon_feeling(PlayerType *player_ptr)
  */
 void update_dungeon_feeling(PlayerType *player_ptr)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!floor_ptr->dun_level) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if (!floor.dun_level) {
         return;
     }
 
-    if (player_ptr->phase_out) {
+    if (AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
-    int delay = std::max(10, 150 - player_ptr->skill_fos) * (150 - floor_ptr->dun_level) * TURNS_PER_TICK / 100;
+    int delay = std::max(10, 150 - player_ptr->skill_fos) * (150 - floor.dun_level) * TURNS_PER_TICK / 100;
     if (w_ptr->game_turn < player_ptr->feeling_turn + delay && !cheat_xtra) {
         return;
     }
 
-    auto quest_num = quest_number(player_ptr, floor_ptr->dun_level);
+    auto quest_num = floor.get_quest_id();
     const auto &quest_list = QuestList::get_instance();
 
     auto dungeon_quest = (quest_num == QuestId::OBERON);
@@ -302,7 +318,7 @@ void update_dungeon_feeling(PlayerType *player_ptr)
     player_ptr->feeling = new_feeling;
     do_cmd_feeling(player_ptr);
     select_floor_music(player_ptr);
-    player_ptr->redraw |= PR_DEPTH;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::DEPTH);
     if (disturb_minor) {
         disturb(player_ptr, false, false);
     }
@@ -313,33 +329,37 @@ void update_dungeon_feeling(PlayerType *player_ptr)
  */
 void glow_deep_lava_and_bldg(PlayerType *player_ptr)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         return;
     }
 
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    for (POSITION y = 0; y < floor_ptr->height; y++) {
-        for (POSITION x = 0; x < floor_ptr->width; x++) {
-            grid_type *g_ptr;
-            g_ptr = &floor_ptr->grid_array[y][x];
-            if (terrains_info[g_ptr->get_feat_mimic()].flags.has_not(TerrainCharacteristics::GLOW)) {
+    for (auto y = 0; y < floor.height; y++) {
+        for (auto x = 0; x < floor.width; x++) {
+            const auto &grid = floor.get_grid({ y, x });
+            if (grid.get_terrain_mimic().flags.has_not(TerrainCharacteristics::GLOW)) {
                 continue;
             }
 
-            for (DIRECTION i = 0; i < 9; i++) {
-                POSITION yy = y + ddy_ddd[i];
-                POSITION xx = x + ddx_ddd[i];
-                if (!in_bounds2(floor_ptr, yy, xx)) {
+            for (auto i = 0; i < 9; i++) {
+                const Pos2D pos(y + ddy_ddd[i], x + ddx_ddd[i]);
+                if (!in_bounds2(&floor, pos.y, pos.x)) {
                     continue;
                 }
 
-                floor_ptr->grid_array[yy][xx].info |= CAVE_GLOW;
+                floor.get_grid(pos).info |= CAVE_GLOW;
             }
         }
     }
 
-    player_ptr->update |= PU_VIEW | PU_LITE | PU_MONSTER_LITE;
-    player_ptr->redraw |= PR_MAP;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
 }
 
 /*
@@ -372,7 +392,7 @@ void forget_view(FloorType *floor_ptr)
     for (int i = 0; i < floor_ptr->view_n; i++) {
         POSITION y = floor_ptr->view_y[i];
         POSITION x = floor_ptr->view_x[i];
-        grid_type *g_ptr;
+        Grid *g_ptr;
         g_ptr = &floor_ptr->grid_array[y][x];
         g_ptr->info &= ~(CAVE_VIEW);
     }
index 213b345..21e5478 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 class FloorType;
index c251fa0..5179610 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 #define SAFE_MAX_ATTEMPTS 5000 /*!< 生成処理基本試行回数 */
index 60f3f31..156f45c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ダンジョンの生成 / Dungeon generation
  * @date 2014/01/04
  * @author
@@ -38,6 +38,7 @@
 #include "monster/monster-update.h"
 #include "monster/monster-util.h"
 #include "player/player-status.h"
+#include "system/angband-system.h"
 #include "system/building-type-definition.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
@@ -139,11 +140,11 @@ static void generate_challenge_arena(PlayerType *player_ptr)
 
     build_arena(player_ptr, &y, &x);
     player_place(player_ptr, y, x);
-    if (place_monster_aux(player_ptr, 0, player_ptr->y + 5, player_ptr->x, arena_info[player_ptr->arena_number].r_idx, PM_NO_KAGE | PM_NO_PET)) {
+    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)) {
         return;
     }
 
-    player_ptr->exit_bldg = true;
+    w_ptr->set_arena(true);
     player_ptr->arena_number++;
     msg_print(_("相手は欠場した。あなたの不戦勝だ。", "The enemy is unable to appear. You won by default."));
 }
@@ -238,7 +239,7 @@ static void generate_gambling_arena(PlayerType *player_ptr)
     build_battle(player_ptr, &y, &x);
     player_place(player_ptr, y, x);
     for (MONSTER_IDX i = 0; i < 4; i++) {
-        place_monster_aux(player_ptr, 0, player_ptr->y + 8 + (i / 2) * 4, player_ptr->x - 2 + (i % 2) * 4, battle_mon_list[i], (PM_NO_KAGE | PM_NO_PET));
+        place_specific_monster(player_ptr, 0, player_ptr->y + 8 + (i / 2) * 4, player_ptr->x - 2 + (i % 2) * 4, battle_mon_list[i], (PM_NO_KAGE | PM_NO_PET));
         set_friendly(&floor_ptr->m_list[floor_ptr->grid_array[player_ptr->y + 8 + (i / 2) * 4][player_ptr->x - 2 + (i % 2) * 4].m_idx]);
     }
 
@@ -272,7 +273,7 @@ static void generate_fixed_floor(PlayerType *player_ptr)
     floor_ptr->object_level = floor_ptr->base_level;
     floor_ptr->monster_level = floor_ptr->base_level;
     if (record_stair) {
-        exe_write_diary_quest(player_ptr, DIARY_TO_QUEST, floor_ptr->quest_number);
+        exe_write_diary_quest(player_ptr, DiaryKind::TO_QUEST, floor_ptr->quest_number);
     }
     get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), nullptr);
     init_flags = INIT_CREATE_DUNGEON;
@@ -386,8 +387,8 @@ void clear_cave(PlayerType *player_ptr)
             g_ptr->m_idx = 0;
             g_ptr->special = 0;
             g_ptr->mimic = 0;
-            memset(g_ptr->costs, 0, sizeof(g_ptr->costs));
-            memset(g_ptr->costs, 0, sizeof(g_ptr->dists));
+            g_ptr->reset_costs();
+            g_ptr->reset_dists();
             g_ptr->when = 0;
         }
     }
@@ -402,8 +403,7 @@ typedef bool (*IsWallFunc)(const FloorType *, int, int);
 // (y,x) がプレイヤーが通れない永久地形かどうかを返す。
 static bool is_permanent_blocker(const FloorType *const floor_ptr, const int y, const int x)
 {
-    const FEAT_IDX feat = floor_ptr->grid_array[y][x].feat;
-    const auto &flags = terrains_info[feat].flags;
+    const auto &flags = floor_ptr->get_grid({ y, x }).get_terrain().flags;
     return flags.has(TerrainCharacteristics::PERMANENT) && flags.has_not(TerrainCharacteristics::MOVE);
 }
 
@@ -494,7 +494,6 @@ static bool floor_is_connected(const FloorType *const floor_ptr, const IsWallFun
 void generate_floor(PlayerType *player_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    floor_ptr->dungeon_idx = player_ptr->dungeon_idx;
     set_floor_and_wall(floor_ptr->dungeon_idx);
     for (int num = 0; true; num++) {
         bool okay = true;
@@ -503,9 +502,9 @@ void generate_floor(PlayerType *player_ptr)
         player_ptr->x = player_ptr->y = 0;
         if (floor_ptr->inside_arena) {
             generate_challenge_arena(player_ptr);
-        } else if (player_ptr->phase_out) {
+        } else if (AngbandSystem::get_instance().is_phase_out()) {
             generate_gambling_arena(player_ptr);
-        } else if (inside_quest(floor_ptr->quest_number)) {
+        } else if (floor_ptr->is_in_quest()) {
             generate_fixed_floor(player_ptr);
         } else if (!floor_ptr->dun_level) {
             if (player_ptr->wild_mode) {
@@ -529,7 +528,7 @@ void generate_floor(PlayerType *player_ptr)
         // 狂戦士でのプレイに支障をきたしうるので再生成する。
         // 地上、荒野マップ、クエストでは連結性判定は行わない。
         // TODO: 本来はダンジョン生成アルゴリズム自身で連結性を保証するのが理想ではある。
-        const bool check_conn = okay && floor_ptr->dun_level > 0 && !inside_quest(floor_ptr->quest_number);
+        const bool check_conn = okay && floor_ptr->dun_level > 0 && !floor_ptr->is_in_quest();
         if (check_conn && !floor_is_connected(floor_ptr, is_permanent_blocker)) {
             // 一定回数試しても連結にならないなら諦める。
             if (num >= 1000) {
index 0ec2e8d..6504876 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class FloorType;
 class PlayerType;
index 0c3dc1e..6537a78 100644 (file)
@@ -1,5 +1,6 @@
-#include "floor/floor-leaver.h"
+#include "floor/floor-leaver.h"
 #include "cmd-building/cmd-building.h"
+#include "dungeon/quest.h"
 #include "floor/cave.h"
 #include "floor/floor-events.h"
 #include "floor/floor-mode-changer.h"
@@ -21,6 +22,7 @@
 #include "pet/pet-util.h"
 #include "save/floor-writer.h"
 #include "spell-class/spells-mirror-master.h"
+#include "system/angband-system.h"
 #include "system/artifact-type-definition.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
@@ -57,25 +59,26 @@ static bool check_pet_preservation_conditions(PlayerType *player_ptr, MonsterEnt
         return false;
     }
 
-    POSITION dis = distance(player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx);
+    auto dis = distance(player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx);
     if (m_ptr->is_confused() || m_ptr->is_stunned() || m_ptr->is_asleep() || (m_ptr->parent_m_idx != 0)) {
         return true;
     }
 
-    if (m_ptr->is_named() && ((player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx) && projectable(player_ptr, player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx)) || (los(player_ptr, m_ptr->fy, m_ptr->fx, player_ptr->y, player_ptr->x) && projectable(player_ptr, m_ptr->fy, m_ptr->fx, player_ptr->y, player_ptr->x)))) {
-        if (dis > 3) {
-            return true;
-        }
-    } else if (dis > 1) {
-        return true;
+    const auto should_preserve = m_ptr->is_named();
+    auto sight_from_player = player_ptr->current_floor_ptr->has_los({ m_ptr->fy, m_ptr->fx });
+    sight_from_player &= projectable(player_ptr, player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx);
+    auto sight_from_monster = los(player_ptr, m_ptr->fy, m_ptr->fx, player_ptr->y, player_ptr->x);
+    sight_from_monster &= projectable(player_ptr, m_ptr->fy, m_ptr->fx, player_ptr->y, player_ptr->x);
+    if (should_preserve && (sight_from_player || sight_from_monster)) {
+        return dis > 3;
     }
 
-    return false;
+    return dis > 1;
 }
 
 static void sweep_preserving_pet(PlayerType *player_ptr)
 {
-    if (player_ptr->wild_mode || player_ptr->current_floor_ptr->inside_arena || player_ptr->phase_out) {
+    if (player_ptr->wild_mode || player_ptr->current_floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -103,7 +106,7 @@ static void record_pet_diary(PlayerType *player_ptr)
             continue;
         }
 
-        exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_MOVED, monster_desc(player_ptr, m_ptr, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE).data());
+        exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_MOVED, monster_desc(player_ptr, m_ptr, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE));
     }
 }
 
@@ -142,34 +145,34 @@ static void preserve_pet(PlayerType *player_ptr)
  */
 static void locate_connected_stairs(PlayerType *player_ptr, FloorType *floor_ptr, saved_floor_type *sf_ptr, BIT_FLAGS floor_mode)
 {
-    POSITION sx = 0;
-    POSITION sy = 0;
-    POSITION x_table[20];
-    POSITION y_table[20];
-    int num = 0;
+    auto sx = 0;
+    auto sy = 0;
+    int x_table[20]{};
+    int y_table[20]{};
+    auto num = 0;
     for (POSITION y = 0; y < floor_ptr->height; y++) {
         for (POSITION x = 0; x < floor_ptr->width; x++) {
-            auto *g_ptr = &floor_ptr->grid_array[y][x];
-            auto *f_ptr = &terrains_info[g_ptr->feat];
-            bool ok = false;
+            const auto &grid = floor_ptr->get_grid({ y, x });
+            const auto &terrain = grid.get_terrain();
+            auto ok = false;
             if (floor_mode & CFM_UP) {
-                if (f_ptr->flags.has_all_of({ TerrainCharacteristics::LESS, TerrainCharacteristics::STAIRS }) && f_ptr->flags.has_not(TerrainCharacteristics::SPECIAL)) {
+                if (terrain.flags.has_all_of({ TerrainCharacteristics::LESS, TerrainCharacteristics::STAIRS }) && terrain.flags.has_not(TerrainCharacteristics::SPECIAL)) {
                     ok = true;
-                    if (g_ptr->special && g_ptr->special == sf_ptr->upper_floor_id) {
+                    if (grid.special && grid.special == sf_ptr->upper_floor_id) {
                         sx = x;
                         sy = y;
                     }
                 }
             } else if (floor_mode & CFM_DOWN) {
-                if (f_ptr->flags.has_all_of({ TerrainCharacteristics::MORE, TerrainCharacteristics::STAIRS }) && f_ptr->flags.has_not(TerrainCharacteristics::SPECIAL)) {
+                if (terrain.flags.has_all_of({ TerrainCharacteristics::MORE, TerrainCharacteristics::STAIRS }) && terrain.flags.has_not(TerrainCharacteristics::SPECIAL)) {
                     ok = true;
-                    if (g_ptr->special && g_ptr->special == sf_ptr->lower_floor_id) {
+                    if (grid.special && grid.special == sf_ptr->lower_floor_id) {
                         sx = x;
                         sy = y;
                     }
                 }
             } else {
-                if (f_ptr->flags.has(TerrainCharacteristics::BLDG)) {
+                if (terrain.flags.has(TerrainCharacteristics::BLDG)) {
                     ok = true;
                 }
             }
@@ -251,24 +254,25 @@ static void preserve_info(PlayerType *player_ptr)
 {
     auto quest_r_idx = MonsterRace::empty_id();
     const auto &quest_list = QuestList::get_instance();
+    const auto &floor = *player_ptr->current_floor_ptr;
     for (const auto &[q_idx, quest] : quest_list) {
         auto quest_relating_monster = (quest.status == QuestStatusType::TAKEN);
         quest_relating_monster &= ((quest.type == QuestKindType::KILL_LEVEL) || (quest.type == QuestKindType::RANDOM));
-        quest_relating_monster &= (quest.level == player_ptr->current_floor_ptr->dun_level);
-        quest_relating_monster &= (player_ptr->dungeon_idx == quest.dungeon);
+        quest_relating_monster &= (quest.level == floor.dun_level);
+        quest_relating_monster &= (floor.dungeon_idx == quest.dungeon);
         quest_relating_monster &= !(quest.flags & QUEST_FLAG_PRESET);
         if (quest_relating_monster) {
             quest_r_idx = quest.r_idx;
         }
     }
 
-    for (DUNGEON_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
+    for (DUNGEON_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
         if (!m_ptr->is_valid() || (quest_r_idx != m_ptr->r_idx)) {
             continue;
         }
 
-        const auto &r_ref = m_ptr->get_real_r_ref();
+        const auto &r_ref = m_ptr->get_real_monrace();
         if (r_ref.kind_flags.has(MonsterKindType::UNIQUE) || (r_ref.population_flags.has(MonsterPopulationType::NAZGUL))) {
             continue;
         }
@@ -288,21 +292,23 @@ static void preserve_info(PlayerType *player_ptr)
     }
 }
 
-static void set_grid_by_leaving_floor(PlayerType *player_ptr, grid_type **g_ptr)
+static Grid *set_grid_by_leaving_floor(PlayerType *player_ptr)
 {
     if ((player_ptr->change_floor_mode & CFM_SAVE_FLOORS) == 0) {
-        return;
+        return nullptr;
     }
 
-    *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
-    auto *f_ptr = &terrains_info[(*g_ptr)->feat];
-    if ((*g_ptr)->special && f_ptr->flags.has_not(TerrainCharacteristics::SPECIAL) && get_sf_ptr((*g_ptr)->special)) {
-        new_floor_id = (*g_ptr)->special;
+    auto *g_ptr = &player_ptr->current_floor_ptr->get_grid(player_ptr->get_position());
+    const auto &terrain = g_ptr->get_terrain();
+    if (g_ptr->special && terrain.flags.has_not(TerrainCharacteristics::SPECIAL) && get_sf_ptr(g_ptr->special)) {
+        new_floor_id = g_ptr->special;
     }
 
-    if (f_ptr->flags.has_all_of({ TerrainCharacteristics::STAIRS, TerrainCharacteristics::SHAFT })) {
+    if (terrain.flags.has_all_of({ TerrainCharacteristics::STAIRS, TerrainCharacteristics::SHAFT })) {
         prepare_change_floor_mode(player_ptr, CFM_SHAFT);
     }
+
+    return g_ptr;
 }
 
 static void jump_floors(PlayerType *player_ptr)
@@ -323,35 +329,38 @@ static void jump_floors(PlayerType *player_ptr)
         move_num *= 2;
     }
 
-    auto &floor_ref = *player_ptr->current_floor_ptr;
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &dungeon = floor.get_dungeon_definition();
     if (any_bits(mode, CFM_DOWN)) {
-        if (!floor_ref.is_in_dungeon()) {
-            move_num = dungeons_info[player_ptr->dungeon_idx].mindepth;
+        if (!floor.is_in_dungeon()) {
+            move_num = dungeon.mindepth;
         }
     } else if (any_bits(mode, CFM_UP)) {
-        if (floor_ref.dun_level + move_num < dungeons_info[player_ptr->dungeon_idx].mindepth) {
-            move_num = -floor_ref.dun_level;
+        if (floor.dun_level + move_num < dungeon.mindepth) {
+            move_num = -floor.dun_level;
         }
     }
 
-    floor_ref.dun_level += move_num;
+    floor.dun_level += move_num;
 }
 
 static void exit_to_wilderness(PlayerType *player_ptr)
 {
-    if (player_ptr->current_floor_ptr->is_in_dungeon() || (player_ptr->dungeon_idx == 0)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.is_in_dungeon() || (floor.dungeon_idx == 0)) {
         return;
     }
 
     player_ptr->leaving_dungeon = true;
     if (!vanilla_town && !lite_town) {
-        player_ptr->wilderness_y = dungeons_info[player_ptr->dungeon_idx].dy;
-        player_ptr->wilderness_x = dungeons_info[player_ptr->dungeon_idx].dx;
+        const auto &dungeon = floor.get_dungeon_definition();
+        player_ptr->wilderness_y = dungeon.dy;
+        player_ptr->wilderness_x = dungeon.dx;
     }
 
-    player_ptr->recall_dungeon = player_ptr->dungeon_idx;
+    player_ptr->recall_dungeon = floor.dungeon_idx;
     player_ptr->word_recall = 0;
-    player_ptr->dungeon_idx = 0;
+    floor.reset_dungeon_index();
     player_ptr->change_floor_mode &= ~CFM_SAVE_FLOORS; // TODO
 }
 
@@ -370,7 +379,7 @@ static void kill_saved_floors(PlayerType *player_ptr, saved_floor_type *sf_ptr)
     }
 }
 
-static void refresh_new_floor_id(PlayerType *player_ptr, grid_type *g_ptr)
+static void refresh_new_floor_id(PlayerType *player_ptr, Grid *g_ptr)
 {
     if (new_floor_id != 0) {
         return;
@@ -397,8 +406,7 @@ static void update_upper_lower_or_floor_id(PlayerType *player_ptr, saved_floor_t
 
 static void exe_leave_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr)
 {
-    grid_type *g_ptr = nullptr;
-    set_grid_by_leaving_floor(player_ptr, &g_ptr);
+    auto g_ptr = set_grid_by_leaving_floor(player_ptr);
     jump_floors(player_ptr);
     exit_to_wilderness(player_ptr);
     kill_saved_floors(player_ptr, sf_ptr);
index 77c454c..d679040 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void leave_floor(PlayerType *player_ptr);
index e1bc0fd..dd1f21c 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/floor-mode-changer.h"
+#include "floor/floor-mode-changer.h"
 #include "system/player-type-definition.h"
 
 /*!
index fccaebb..2980cef 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 2045eec..cfd0f86 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief フロア生成時にアイテムを配置する
  * @date 2020/06/01
  * @author Hourier
@@ -35,6 +35,7 @@
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/system-variables.h"
 #include "target/projection-path-calculator.h"
 #include "util/bit-flags-calculator.h"
@@ -73,7 +74,7 @@ static errr get_obj_index_prep(void)
 static void object_mention(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
     object_aware(player_ptr, o_ptr);
-    object_known(o_ptr);
+    o_ptr->mark_as_known();
 
     o_ptr->ident |= (IDENT_FULL_KNOWN);
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
@@ -83,11 +84,11 @@ static void object_mention(PlayerType *player_ptr, ItemEntity *o_ptr)
 static int get_base_floor(FloorType *floor_ptr, BIT_FLAGS mode, std::optional<int> rq_mon_level)
 {
     if (any_bits(mode, AM_GREAT)) {
-        if (rq_mon_level.has_value()) {
-            return rq_mon_level.value() + 10 + randint1(10);
-        } else {
-            return floor_ptr->object_level + 15;
+        if (rq_mon_level) {
+            return *rq_mon_level + 10 + randint1(10);
         }
+
+        return floor_ptr->object_level + 15;
     }
 
     if (any_bits(mode, AM_GOOD)) {
@@ -129,7 +130,7 @@ bool make_object(PlayerType *player_ptr, ItemEntity *j_ptr, BIT_FLAGS mode, std:
             get_obj_index_prep();
         }
 
-        auto bi_id = get_obj_index(player_ptr, base, mode);
+        auto bi_id = get_obj_index(floor_ptr, base, mode);
         if (get_obj_index_hook) {
             get_obj_index_hook = nullptr;
             get_obj_index_prep();
@@ -191,7 +192,7 @@ bool make_gold(PlayerType *player_ptr, ItemEntity *j_ptr)
  */
 void delete_all_items_from_floor(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    grid_type *g_ptr;
+    Grid *g_ptr;
     auto *floor_ptr = player_ptr->current_floor_ptr;
     if (!in_bounds(floor_ptr, y, x)) {
         return;
@@ -213,14 +214,14 @@ void delete_all_items_from_floor(PlayerType *player_ptr, POSITION y, POSITION x)
  * @brief 床上のアイテムの数を増やす /
  * Increase the "number" of an item on the floor
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 増やしたいアイテムの所持スロット
+ * @param i_idx 増やしたいアイテムの所持スロット
  * @param num 増やしたいアイテムの数
  */
-void floor_item_increase(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
+void floor_item_increase(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER num)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
 
-    auto *o_ptr = &floor_ptr->o_list[item];
+    auto *o_ptr = &floor_ptr->o_list[i_idx];
     num += o_ptr->number;
     if (num > 255) {
         num = 255;
@@ -230,19 +231,22 @@ void floor_item_increase(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER
 
     num -= o_ptr->number;
     o_ptr->number += num;
-
-    set_bits(player_ptr->window_flags, PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
 }
 
 /*!
  * @brief 床上の数の無くなったアイテムスロットを消去する /
  * Optimize an item on the floor (destroy "empty" items)
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 消去したいアイテムの所持スロット
+ * @param i_idx 消去したいアイテムの所持スロット
  */
-void floor_item_optimize(PlayerType *player_ptr, INVENTORY_IDX item)
+void floor_item_optimize(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
-    auto *o_ptr = &player_ptr->current_floor_ptr->o_list[item];
+    auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i_idx];
     if (!o_ptr->is_valid()) {
         return;
     }
@@ -250,9 +254,12 @@ void floor_item_optimize(PlayerType *player_ptr, INVENTORY_IDX item)
         return;
     }
 
-    delete_object_idx(player_ptr, item);
-
-    set_bits(player_ptr->window_flags, PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    delete_object_idx(player_ptr, i_idx);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
 }
 
 /*!
@@ -278,8 +285,11 @@ void delete_object_idx(PlayerType *player_ptr, OBJECT_IDX o_idx)
 
     j_ptr->wipe();
     floor_ptr->o_cnt--;
-
-    set_bits(player_ptr->window_flags, PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
 }
 
 /*!
@@ -339,7 +349,7 @@ OBJECT_IDX drop_near(PlayerType *player_ptr, ItemEntity *j_ptr, PERCENTAGE chanc
     POSITION dy, dx;
     POSITION ty, tx = 0;
     OBJECT_IDX o_idx = 0;
-    grid_type *g_ptr;
+    Grid *g_ptr;
     bool flag = false;
     bool done = false;
 #ifdef JP
@@ -559,11 +569,16 @@ OBJECT_IDX drop_near(PlayerType *player_ptr, ItemEntity *j_ptr, PERCENTAGE chanc
     lite_spot(player_ptr, by, bx);
     sound(SOUND_DROP);
 
-    if (player_bold(player_ptr, by, bx)) {
-        set_bits(player_ptr->window_flags, PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    const auto is_located = player_ptr->is_located_at({ by, bx });
+    if (is_located) {
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::FLOOR_ITEMS,
+            SubWindowRedrawingFlag::FOUND_ITEMS,
+        };
+        RedrawingFlagsUpdater::get_instance().set_flags(flags);
     }
 
-    if (chance && player_bold(player_ptr, by, bx)) {
+    if (chance && is_located) {
         msg_print(_("何かが足下に転がってきた。", "You feel something roll beneath your feet."));
     }
 
@@ -571,14 +586,13 @@ OBJECT_IDX drop_near(PlayerType *player_ptr, ItemEntity *j_ptr, PERCENTAGE chanc
 }
 
 /*!
- * @brief 床上の魔道具の残り残量メッセージを表示する /
- * Describe the charges on an item on the floor.
+ * @brief 床上の魔道具の残り残量メッセージを表示する
  * @param floo_ptr 現在フロアへの参照ポインタ
- * @param item メッセージの対象にしたいアイテム所持スロット
+ * @param i_idx メッセージの対象にしたいアイテム所持スロット
  */
-void floor_item_charges(FloorType *floor_ptr, INVENTORY_IDX inventory)
+void floor_item_charges(FloorType *floor_ptr, INVENTORY_IDX i_idx)
 {
-    const auto &item = floor_ptr->o_list[inventory];
+    const auto &item = floor_ptr->o_list[i_idx];
     if (!item.is_wand_staff() || !item.is_known()) {
         return;
     }
@@ -602,11 +616,11 @@ void floor_item_charges(FloorType *floor_ptr, INVENTORY_IDX inventory)
  * @brief 床上のアイテムの残り数メッセージを表示する /
  * Describe the charges on an item on the floor.
  * @param floo_ptr 現在フロアへの参照ポインタ
- * @param item メッセージの対象にしたいアイテム所持スロット
+ * @param i_idx メッセージの対象にしたいアイテム所持スロット
  */
-void floor_item_describe(PlayerType *player_ptr, INVENTORY_IDX item)
+void floor_item_describe(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
-    auto *o_ptr = &player_ptr->current_floor_ptr->o_list[item];
+    auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i_idx];
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
 #ifdef JP
     if (o_ptr->number <= 0) {
@@ -620,29 +634,28 @@ void floor_item_describe(PlayerType *player_ptr, INVENTORY_IDX item)
 }
 
 /*
- * Choose an item and get auto-picker entry from it.
+ * @brief Choose an item and get auto-picker entry from it.
+ * @todo initial_i_idx をポインタではなく値に変え、戻り値をstd::pairに変える
  */
-ItemEntity *choose_object(PlayerType *player_ptr, OBJECT_IDX *idx, concptr q, concptr s, BIT_FLAGS option, const ItemTester &item_tester)
+ItemEntity *choose_object(PlayerType *player_ptr, short *initial_i_idx, concptr q, concptr s, BIT_FLAGS option, const ItemTester &item_tester)
 {
-    OBJECT_IDX item;
-
-    if (idx) {
-        *idx = INVEN_NONE;
+    if (initial_i_idx) {
+        *initial_i_idx = INVEN_NONE;
     }
 
     FixItemTesterSetter setter(item_tester);
-
-    if (!get_item(player_ptr, &item, q, s, option, item_tester)) {
+    short i_idx;
+    if (!get_item(player_ptr, &i_idx, q, s, option, item_tester)) {
         return nullptr;
     }
 
-    if (idx) {
-        *idx = item;
+    if (initial_i_idx) {
+        *initial_i_idx = i_idx;
     }
 
-    if (item == INVEN_FORCE) {
+    if (i_idx == INVEN_FORCE) {
         return nullptr;
     }
 
-    return ref_item(player_ptr, item);
+    return ref_item(player_ptr, i_idx);
 }
index 2a78aac..85985a1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/item-tester-hooker.h"
 #include "system/angband.h"
@@ -13,12 +13,12 @@ class ItemTester;
 bool make_object(PlayerType *player_ptr, ItemEntity *j_ptr, BIT_FLAGS mode, std::optional<int> rq_mon_level = std::nullopt);
 bool make_gold(PlayerType *player_ptr, ItemEntity *j_ptr);
 void delete_all_items_from_floor(PlayerType *player_ptr, POSITION y, POSITION x);
-void floor_item_increase(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER num);
-void floor_item_optimize(PlayerType *player_ptr, INVENTORY_IDX item);
+void floor_item_increase(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER num);
+void floor_item_optimize(PlayerType *player_ptr, INVENTORY_IDX i_idx);
 void delete_object_idx(PlayerType *player_ptr, OBJECT_IDX o_idx);
 void excise_object_idx(FloorType *floor_ptr, OBJECT_IDX o_idx);
 ObjectIndexList &get_o_idx_list_contains(FloorType *floor_ptr, OBJECT_IDX o_idx);
 OBJECT_IDX drop_near(PlayerType *player_ptr, ItemEntity *o_ptr, PERCENTAGE chance, POSITION y, POSITION x);
-void floor_item_charges(FloorType *player_ptr, INVENTORY_IDX item);
-void floor_item_describe(PlayerType *player_ptr, INVENTORY_IDX item);
-ItemEntity *choose_object(PlayerType *player_ptr, OBJECT_IDX *idx, concptr q, concptr s, BIT_FLAGS option, const ItemTester &item_tester = AllMatchItemTester());
+void floor_item_charges(FloorType *player_ptr, INVENTORY_IDX i_idx);
+void floor_item_describe(PlayerType *player_ptr, INVENTORY_IDX i_idx);
+ItemEntity *choose_object(PlayerType *player_ptr, short *initial_i_idx, concptr q, concptr s, BIT_FLAGS option, const ItemTester &item_tester = AllMatchItemTester());
index 09996ab..d2c6c82 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/floor-save-util.h"
+#include "floor/floor-save-util.h"
 
 /*
  * Sign for current process used in temporary files.
index 60f3f99..d0bca0b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "system/monster-entity.h"
index 364313c..decf7dc 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 保存された階の管理 / management of the saved floor
  * @date 2014/01/04
  * @author
@@ -29,7 +29,7 @@ static std::string get_saved_floor_name(int level)
 {
     char ext[32];
     strnfmt(ext, sizeof(ext), ".F%02d", level);
-    return std::string(savefile).append(ext);
+    return savefile.string().append(ext);
 }
 
 static void check_saved_tmp_files(const int fd, bool *force)
@@ -47,7 +47,7 @@ static void check_saved_tmp_files(const int fd, bool *force)
     msg_print(_("変愚蛮怒を二重に起動していないか確認してください。", "Make sure you are not running two game processes simultaneously."));
     msg_print(_("過去に変愚蛮怒がクラッシュした場合は一時ファイルを", "If the temporary files are garbage from an old crashed process, "));
     msg_print(_("強制的に削除して実行を続けられます。", "you can delete them safely."));
-    if (!get_check(_("強制的に削除してもよろしいですか?", "Do you delete the old temporary files? "))) {
+    if (!input_check(_("強制的に削除してもよろしいですか?", "Do you delete the old temporary files? "))) {
         quit(_("実行中止", "Aborted."));
     }
 
@@ -63,16 +63,16 @@ static void check_saved_tmp_files(const int fd, bool *force)
 void init_saved_floors(PlayerType *player_ptr, bool force)
 {
     auto fd = -1;
-    if (savefile[0]) {
+    if (!savefile.empty()) {
         for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
             saved_floor_type *sf_ptr = &saved_floors[i];
-            std::string floor_savefile = get_saved_floor_name(i);
-            safe_setuid_grab(player_ptr);
-            fd = fd_make(floor_savefile.data());
+            auto floor_savefile = get_saved_floor_name(i);
+            safe_setuid_grab();
+            fd = fd_make(floor_savefile);
             safe_setuid_drop();
             check_saved_tmp_files(fd, &force);
-            safe_setuid_grab(player_ptr);
-            (void)fd_kill(floor_savefile.data());
+            safe_setuid_grab();
+            (void)fd_kill(floor_savefile);
             safe_setuid_drop();
             sf_ptr->floor_id = 0;
         }
@@ -98,8 +98,8 @@ void clear_saved_floor_files(PlayerType *player_ptr)
             continue;
         }
 
-        safe_setuid_grab(player_ptr);
-        (void)fd_kill(get_saved_floor_name(i).data());
+        safe_setuid_grab();
+        (void)fd_kill(get_saved_floor_name(i));
         safe_setuid_drop();
     }
 }
@@ -142,8 +142,8 @@ void kill_saved_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr)
         return;
     }
 
-    safe_setuid_grab(player_ptr);
-    (void)fd_kill(get_saved_floor_name((int)sf_ptr->savefile_id).data());
+    safe_setuid_grab();
+    (void)fd_kill(get_saved_floor_name((int)sf_ptr->savefile_id));
     safe_setuid_drop();
     sf_ptr->floor_id = 0;
 }
@@ -222,6 +222,6 @@ void precalc_cur_num_of_pet(PlayerType *player_ptr)
             continue;
         }
 
-        m_ptr->get_real_r_ref().cur_num++;
+        m_ptr->get_real_monrace().cur_num++;
     }
 }
index 3df5223..85c2961 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 1289de5..5fe95d8 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ダンジョン生成に利用する関数群 / Used by dungeon generation.
  * @date 2014/07/15
  * @author
@@ -61,7 +61,7 @@ static void recursive_river(FloorType *floor_ptr, POSITION x1, POSITION y1, POSI
     POSITION changex, changey;
     POSITION ty, tx;
     bool done;
-    grid_type *g_ptr;
+    Grid *g_ptr;
 
     length = distance(x1, y1, x2, y2);
 
@@ -103,6 +103,7 @@ static void recursive_river(FloorType *floor_ptr, POSITION x1, POSITION y1, POSI
         }
     } else {
         /* Actually build the river */
+        const auto &terrains = TerrainList::get_instance();
         for (l = 0; l < length; l++) {
             x = x1 + l * (x2 - x1) / length;
             y = y1 + l * (y2 - y1) / length;
@@ -148,8 +149,8 @@ static void recursive_river(FloorType *floor_ptr, POSITION x1, POSITION y1, POSI
                         g_ptr->mimic = 0;
 
                         /* Lava terrain glows */
-                        if (terrains_info[feat1].flags.has(TerrainCharacteristics::LAVA)) {
-                            if (dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS)) {
+                        if (terrains[feat1].flags.has(TerrainCharacteristics::LAVA)) {
+                            if (floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS)) {
                                 g_ptr->info |= CAVE_GLOW;
                             }
                         }
@@ -173,42 +174,38 @@ static void recursive_river(FloorType *floor_ptr, POSITION x1, POSITION y1, POSI
  */
 void add_river(FloorType *floor_ptr, dun_data_type *dd_ptr)
 {
-    dungeon_type *dungeon_ptr;
-    POSITION y2, x2;
-    POSITION y1 = 0, x1 = 0;
-    POSITION wid;
-    FEAT_IDX feat1 = 0, feat2 = 0;
+    short feat1 = 0;
+    short feat2 = 0;
 
-    dungeon_ptr = &dungeons_info[floor_ptr->dungeon_idx];
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
 
     /* Choose water mainly */
-    if ((randint1(MAX_DEPTH * 2) - 1 > floor_ptr->dun_level) && dungeon_ptr->flags.has(DungeonFeatureType::WATER_RIVER)) {
+    if ((randint1(MAX_DEPTH * 2) - 1 > floor_ptr->dun_level) && dungeon.flags.has(DungeonFeatureType::WATER_RIVER)) {
         feat1 = feat_deep_water;
         feat2 = feat_shallow_water;
     } else /* others */
     {
-        FEAT_IDX select_deep_feat[10];
-        FEAT_IDX select_shallow_feat[10];
-        int select_id_max = 0, selected;
-
-        if (dungeon_ptr->flags.has(DungeonFeatureType::LAVA_RIVER)) {
+        short select_deep_feat[10]{};
+        short select_shallow_feat[10]{};
+        auto select_id_max = 0;
+        if (dungeon.flags.has(DungeonFeatureType::LAVA_RIVER)) {
             select_deep_feat[select_id_max] = feat_deep_lava;
             select_shallow_feat[select_id_max] = feat_shallow_lava;
             select_id_max++;
         }
-        if (dungeon_ptr->flags.has(DungeonFeatureType::POISONOUS_RIVER)) {
+        if (dungeon.flags.has(DungeonFeatureType::POISONOUS_RIVER)) {
             select_deep_feat[select_id_max] = feat_deep_poisonous_puddle;
             select_shallow_feat[select_id_max] = feat_shallow_poisonous_puddle;
             select_id_max++;
         }
-        if (dungeon_ptr->flags.has(DungeonFeatureType::ACID_RIVER)) {
+        if (dungeon.flags.has(DungeonFeatureType::ACID_RIVER)) {
             select_deep_feat[select_id_max] = feat_deep_acid_puddle;
             select_shallow_feat[select_id_max] = feat_shallow_acid_puddle;
             select_id_max++;
         }
 
         if (select_id_max > 0) {
-            selected = randint0(select_id_max);
+            const auto selected = randint0(select_id_max);
             feat1 = select_deep_feat[selected];
             feat2 = select_shallow_feat[selected];
         } else {
@@ -217,11 +214,11 @@ void add_river(FloorType *floor_ptr, dun_data_type *dd_ptr)
     }
 
     if (feat1) {
-        auto *f_ptr = &terrains_info[feat1];
+        const auto &terrain = TerrainList::get_instance()[feat1];
         auto is_lava = dd_ptr->laketype == LAKE_T_LAVA;
-        is_lava &= f_ptr->flags.has(TerrainCharacteristics::LAVA);
+        is_lava &= terrain.flags.has(TerrainCharacteristics::LAVA);
         auto is_water = dd_ptr->laketype == LAKE_T_WATER;
-        is_water &= f_ptr->flags.has(TerrainCharacteristics::WATER);
+        is_water &= terrain.flags.has(TerrainCharacteristics::WATER);
         const auto should_add_river = !is_lava && !is_water && (dd_ptr->laketype != 0);
         if (should_add_river) {
             return;
@@ -229,10 +226,12 @@ void add_river(FloorType *floor_ptr, dun_data_type *dd_ptr)
     }
 
     /* Hack -- Choose starting point */
-    y2 = randint1(floor_ptr->height / 2 - 2) + floor_ptr->height / 2;
-    x2 = randint1(floor_ptr->width / 2 - 2) + floor_ptr->width / 2;
+    const auto y2 = randint1(floor_ptr->height / 2 - 2) + floor_ptr->height / 2;
+    const auto x2 = randint1(floor_ptr->width / 2 - 2) + floor_ptr->width / 2;
 
     /* Hack -- Choose ending point somewhere on boundary */
+    auto y1 = 0;
+    auto x1 = 0;
     switch (randint1(4)) {
     case 1: {
         /* top boundary */
@@ -261,7 +260,7 @@ void add_river(FloorType *floor_ptr, dun_data_type *dd_ptr)
     }
 
     constexpr auto width_rivers = 2;
-    wid = randint1(width_rivers);
+    const auto wid = randint1(width_rivers);
     recursive_river(floor_ptr, x1, y1, x2, y2, feat1, feat2, wid);
 
     /* Hack - Save the location as a "room" */
@@ -288,78 +287,72 @@ void add_river(FloorType *floor_ptr, dun_data_type *dd_ptr)
  */
 void build_streamer(PlayerType *player_ptr, FEAT_IDX feat, int chance)
 {
-    int i;
-    POSITION y, x, tx, ty;
-    DIRECTION dir;
-    int dummy = 0;
-
-    grid_type *g_ptr;
-    TerrainType *f_ptr;
-
-    TerrainType *streamer_ptr = &terrains_info[feat];
-    bool streamer_is_wall = streamer_ptr->flags.has(TerrainCharacteristics::WALL) && streamer_ptr->flags.has_not(TerrainCharacteristics::PERMANENT);
-    bool streamer_may_have_gold = streamer_ptr->flags.has(TerrainCharacteristics::MAY_HAVE_GOLD);
+    const auto &streamer = TerrainList::get_instance()[feat];
+    bool streamer_is_wall = streamer.flags.has(TerrainCharacteristics::WALL) && streamer.flags.has_not(TerrainCharacteristics::PERMANENT);
+    bool streamer_may_have_gold = streamer.flags.has(TerrainCharacteristics::MAY_HAVE_GOLD);
 
     /* Hack -- Choose starting point */
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    y = rand_spread(floor_ptr->height / 2, floor_ptr->height / 6);
-    x = rand_spread(floor_ptr->width / 2, floor_ptr->width / 6);
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto y = rand_spread(floor.height / 2, floor.height / 6);
+    auto x = rand_spread(floor.width / 2, floor.width / 6);
 
     /* Choose a random compass direction */
-    dir = randint0(8);
+    auto dir = randint0(8);
 
     /* Place streamer into dungeon */
+    auto dummy = 0;
     while (dummy < SAFE_MAX_ATTEMPTS) {
         dummy++;
 
         /* One grid per density */
         constexpr auto stream_density = 5;
-        for (i = 0; i < stream_density; i++) {
+        for (auto i = 0; i < stream_density; i++) {
             constexpr auto stream_width = 5;
             int d = stream_width;
 
             /* Pick a nearby grid */
+            Pos2D pos(y, x);
             while (true) {
-                ty = rand_spread(y, d);
-                tx = rand_spread(x, d);
-                if (!in_bounds2(floor_ptr, ty, tx)) {
+                pos.y = rand_spread(y, d);
+                pos.x = rand_spread(x, d);
+                if (!in_bounds2(&floor, pos.y, pos.x)) {
                     continue;
                 }
                 break;
             }
-            g_ptr = &floor_ptr->grid_array[ty][tx];
-            f_ptr = &terrains_info[g_ptr->feat];
 
-            if (f_ptr->flags.has(TerrainCharacteristics::MOVE) && f_ptr->flags.has_any_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::LAVA })) {
+            auto &grid = floor.get_grid(pos);
+            const auto &terrain = grid.get_terrain();
+            if (terrain.flags.has(TerrainCharacteristics::MOVE) && terrain.flags.has_any_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::LAVA })) {
                 continue;
             }
 
             /* Do not convert permanent features */
-            if (f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
+            if (terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
                 continue;
             }
 
             /* Only convert "granite" walls */
             if (streamer_is_wall) {
-                if (!g_ptr->is_extra() && !g_ptr->is_inner() && !g_ptr->is_outer() && !g_ptr->is_solid()) {
+                if (!grid.is_extra() && !grid.is_inner() && !grid.is_outer() && !grid.is_solid()) {
                     continue;
                 }
-                if (is_closed_door(player_ptr, g_ptr->feat)) {
+                if (is_closed_door(player_ptr, grid.feat)) {
                     continue;
                 }
             }
 
-            auto *r_ptr = &monraces_info[floor_ptr->m_list[g_ptr->m_idx].r_idx];
-            if (g_ptr->m_idx && !(streamer_ptr->flags.has(TerrainCharacteristics::PLACE) && monster_can_cross_terrain(player_ptr, feat, r_ptr, 0))) {
+            auto *r_ptr = &monraces_info[floor.m_list[grid.m_idx].r_idx];
+            if (grid.m_idx && !(streamer.flags.has(TerrainCharacteristics::PLACE) && monster_can_cross_terrain(player_ptr, feat, r_ptr, 0))) {
                 /* Delete the monster (if any) */
-                delete_monster(player_ptr, ty, tx);
+                delete_monster(player_ptr, pos.y, pos.x);
             }
 
-            if (!g_ptr->o_idx_list.empty() && streamer_ptr->flags.has_not(TerrainCharacteristics::DROP)) {
+            if (!grid.o_idx_list.empty() && streamer.flags.has_not(TerrainCharacteristics::DROP)) {
 
                 /* Scan all objects in the grid */
-                for (const auto this_o_idx : g_ptr->o_idx_list) {
-                    auto *o_ptr = &floor_ptr->o_list[this_o_idx];
+                for (const auto this_o_idx : grid.o_idx_list) {
+                    auto *o_ptr = &floor.o_list[this_o_idx];
 
                     /* Hack -- Preserve unknown artifacts */
                     if (o_ptr->is_fixed_artifact()) {
@@ -373,25 +366,25 @@ void build_streamer(PlayerType *player_ptr, FEAT_IDX feat, int chance)
                     }
                 }
 
-                delete_all_items_from_floor(player_ptr, ty, tx);
+                delete_all_items_from_floor(player_ptr, pos.y, pos.x);
             }
 
             /* Clear previous contents, add proper vein type */
-            g_ptr->feat = feat;
+            grid.feat = feat;
 
             /* Paranoia: Clear mimic field */
-            g_ptr->mimic = 0;
+            grid.mimic = 0;
 
             if (streamer_may_have_gold) {
                 /* Hack -- Add some known treasure */
                 if (one_in_(chance)) {
-                    cave_alter_feat(player_ptr, ty, tx, TerrainCharacteristics::MAY_HAVE_GOLD);
+                    cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::MAY_HAVE_GOLD);
                 }
 
                 /* Hack -- Add some hidden treasure */
                 else if (one_in_(chance / 4)) {
-                    cave_alter_feat(player_ptr, ty, tx, TerrainCharacteristics::MAY_HAVE_GOLD);
-                    cave_alter_feat(player_ptr, ty, tx, TerrainCharacteristics::ENSECRET);
+                    cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::MAY_HAVE_GOLD);
+                    cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::ENSECRET);
                 }
             }
         }
@@ -414,7 +407,7 @@ void build_streamer(PlayerType *player_ptr, FEAT_IDX feat, int chance)
         }
 
         /* Quit before leaving the dungeon */
-        if (!in_bounds(floor_ptr, y, x)) {
+        if (!in_bounds(&floor, y, x)) {
             break;
         }
     }
@@ -434,7 +427,7 @@ void build_streamer(PlayerType *player_ptr, FEAT_IDX feat, int chance)
 void place_trees(PlayerType *player_ptr, POSITION x, POSITION y)
 {
     int i, j;
-    grid_type *g_ptr;
+    Grid *g_ptr;
 
     /* place trees/ rubble in ovalish distribution */
     auto *floor_ptr = player_ptr->current_floor_ptr;
@@ -470,7 +463,7 @@ void place_trees(PlayerType *player_ptr, POSITION x, POSITION y)
                 g_ptr->mimic = 0;
 
                 /* Light area since is open above */
-                if (dungeons_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS)) {
+                if (floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS)) {
                     floor_ptr->grid_array[j][i].info |= (CAVE_GLOW | CAVE_ROOM);
                 }
             }
index f81c864..48eaee0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index bc54036..e039f91 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/floor-town.h"
+#include "floor/floor-town.h"
 #include "system/item-entity.h"
 
 /* The towns [towns_info.size()] */
index f912e1b..22ed7a7 100644 (file)
@@ -1,18 +1,19 @@
-#pragma once
+#pragma once
 
 #include "store/store-util.h"
 #include "system/angband.h"
+#include <map>
+#include <string>
 #include <vector>
 
 /*
  * A structure describing a town with
  * stores and buildings
  */
+enum class StoreSaleType : int;
 struct town_type {
-    GAME_TEXT name[32];
-    uint32_t seed; /* Seed for RNG */
-    std::vector<store_type> store; /* The stores [MAX_STORES] */
-    byte numstores;
+    std::string name;
+    std::map<StoreSaleType, store_type> stores; /* The stores [MAX_STORES] */
 };
 
 constexpr short VALID_TOWNS = 6; // @details 旧海底都市クエストのマップを除外する. 有効な町に差し替え完了したら不要になるので注意.
index 0496d10..01d5983 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief フロア全体の処理に関するユーティリティ
  * @date 2019/04/24
  * @author deskull
@@ -14,6 +14,7 @@
 #include "game-option/birth-options.h"
 #include "grid/feature.h"
 #include "perception/object-perception.h"
+#include "system/angband-system.h"
 #include "system/artifact-type-definition.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
@@ -63,8 +64,8 @@ void update_smell(FloorType *floor_ptr, PlayerType *player_ptr)
     };
 
     if (++scent_when == 254) {
-        for (POSITION y = 0; y < floor_ptr->height; y++) {
-            for (POSITION x = 0; x < floor_ptr->width; x++) {
+        for (auto y = 0; y < floor_ptr->height; y++) {
+            for (auto x = 0; x < floor_ptr->width; x++) {
                 int w = floor_ptr->grid_array[y][x].when;
                 floor_ptr->grid_array[y][x].when = (w > 128) ? (w - 128) : 0;
             }
@@ -73,27 +74,22 @@ void update_smell(FloorType *floor_ptr, PlayerType *player_ptr)
         scent_when = 126;
     }
 
-    for (POSITION i = 0; i < 5; i++) {
-        for (POSITION j = 0; j < 5; j++) {
-            grid_type *g_ptr;
-            POSITION y = i + player_ptr->y - 2;
-            POSITION x = j + player_ptr->x - 2;
-            if (!in_bounds(floor_ptr, y, x)) {
+    for (auto i = 0; i < 5; i++) {
+        for (auto j = 0; j < 5; j++) {
+            const Pos2D pos(i + player_ptr->y - 2, j + player_ptr->x - 2);
+            if (!in_bounds(floor_ptr, pos.y, pos.x)) {
                 continue;
             }
 
-            g_ptr = &floor_ptr->grid_array[y][x];
-            if (!g_ptr->cave_has_flag(TerrainCharacteristics::MOVE) && !is_closed_door(player_ptr, g_ptr->feat)) {
-                continue;
-            }
-            if (!player_has_los_bold(player_ptr, y, x)) {
-                continue;
-            }
-            if (scent_adjust[i][j] == -1) {
+            auto &grid = floor_ptr->get_grid(pos);
+            auto update_when = !grid.cave_has_flag(TerrainCharacteristics::MOVE) && !is_closed_door(player_ptr, grid.feat);
+            update_when |= !grid.has_los();
+            update_when |= scent_adjust[i][j] == -1;
+            if (update_when) {
                 continue;
             }
 
-            g_ptr->when = scent_when + scent_adjust[i][j];
+            grid.when = scent_when + scent_adjust[i][j];
         }
     }
 }
@@ -105,8 +101,9 @@ void forget_flow(FloorType *floor_ptr)
 {
     for (POSITION y = 0; y < floor_ptr->height; y++) {
         for (POSITION x = 0; x < floor_ptr->width; x++) {
-            memset(&floor_ptr->grid_array[y][x].costs, 0, sizeof(floor_ptr->grid_array[y][x].costs));
-            memset(&floor_ptr->grid_array[y][x].dists, 0, sizeof(floor_ptr->grid_array[y][x].dists));
+            auto &grid = floor_ptr->grid_array[y][x];
+            grid.reset_costs();
+            grid.reset_dists();
             floor_ptr->grid_array[y][x].when = 0;
         }
     }
@@ -192,11 +189,11 @@ void scatter(PlayerType *player_ptr, POSITION *yp, POSITION *xp, POSITION y, POS
  * @param player_ptr プレイヤーへの参照ポインタ
  * @return マップ名の文字列参照ポインタ
  */
-concptr map_name(PlayerType *player_ptr)
+std::string map_name(PlayerType *player_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     const auto &quest_list = QuestList::get_instance();
-    auto is_fixed_quest = inside_quest(floor_ptr->quest_number);
+    auto is_fixed_quest = floor_ptr->is_in_quest();
     is_fixed_quest &= QuestType::is_fixed(floor_ptr->quest_number);
     is_fixed_quest &= any_bits(quest_list[floor_ptr->quest_number].flags, QUEST_FLAG_PRESET);
     if (is_fixed_quest) {
@@ -205,11 +202,11 @@ concptr map_name(PlayerType *player_ptr)
         return _("地上", "Surface");
     } else if (floor_ptr->inside_arena) {
         return _("アリーナ", "Arena");
-    } else if (player_ptr->phase_out) {
+    } else if (AngbandSystem::get_instance().is_phase_out()) {
         return _("闘技場", "Monster Arena");
     } else if (!floor_ptr->dun_level && player_ptr->town_num) {
         return towns_info[player_ptr->town_num].name;
     } else {
-        return dungeons_info[player_ptr->dungeon_idx].name.data();
+        return floor_ptr->get_dungeon_definition().name;
     }
 }
index 2ff48d8..1345b1b 100644 (file)
@@ -1,6 +1,7 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
+#include <string>
 
 class FloorType;
 extern FloorType floor_info;
@@ -10,4 +11,4 @@ void update_smell(FloorType *floor_ptr, PlayerType *player_ptr);
 void forget_flow(FloorType *floor_ptr);
 void wipe_o_list(FloorType *floor_ptr);
 void scatter(PlayerType *player_ptr, POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION d, BIT_FLAGS mode);
-concptr map_name(PlayerType *player_ptr);
+std::string map_name(PlayerType *player_ptr);
index d9b9ada..502a1ca 100644 (file)
@@ -1,8 +1,9 @@
-#include "floor/geometry.h"
+#include "floor/geometry.h"
 #include "floor/cave.h"
 #include "game-option/text-display-options.h"
 #include "grid/feature.h"
 #include "grid/grid.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 /*!
  * キーパッドの方向を南から反時計回り順に列挙 / Global array for looping through the "keypad directions"
  */
-const POSITION ddd[9] = { 2, 8, 6, 4, 3, 1, 9, 7, 5 };
+const int ddd[9] = { 2, 8, 6, 4, 3, 1, 9, 7, 5 };
 
 /*!
  * dddで定義した順にベクトルのX軸成分を定義 / Global arrays for converting "keypad direction" into offsets
  */
-const POSITION ddx[10] = { 0, -1, 0, 1, -1, 0, 1, -1, 0, 1 };
+const int ddx[10] = { 0, -1, 0, 1, -1, 0, 1, -1, 0, 1 };
 
 /*!
  * dddで定義した順にベクトルのY軸成分を定義 / Global arrays for converting "keypad direction" into offsets
  */
-const POSITION ddy[10] = { 0, 1, 1, 1, 0, 0, 0, -1, -1, -1 };
+const int ddy[10] = { 0, 1, 1, 1, 0, 0, 0, -1, -1, -1 };
 
 /*!
  * ddd越しにベクトルのX軸成分を定義 / Global arrays for optimizing "ddx[ddd[i]]" and "ddy[ddd[i]]"
  */
-const POSITION ddx_ddd[9] = { 0, 0, 1, -1, 1, -1, 1, -1, 0 };
+const int ddx_ddd[9] = { 0, 0, 1, -1, 1, -1, 1, -1, 0 };
 
 /*!
  * ddd越しにベクトルのY軸成分を定義 / Global arrays for optimizing "ddx[ddd[i]]" and "ddy[ddd[i]]"
  */
-const POSITION ddy_ddd[9] = { 1, -1, 0, 0, 1, 1, -1, -1, 0 };
+const int ddy_ddd[9] = { 1, -1, 0, 0, 1, 1, -1, -1, 0 };
 
 /*!
  * キーパッドの円環状方向配列 / Circular keypad direction array
  */
-const POSITION cdd[8] = { 2, 3, 6, 9, 8, 7, 4, 1 };
+const int cdd[8] = { 2, 3, 6, 9, 8, 7, 4, 1 };
 
 /*!
  * cdd越しにベクトルのX軸成分を定義 / Global arrays for optimizing "ddx[cdd[i]]" and "ddy[cdd[i]]"
  */
-const POSITION ddx_cdd[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
+const int ddx_cdd[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
 
 /*!
  * cdd越しにベクトルのY軸成分を定義 / Global arrays for optimizing "ddx[cdd[i]]" and "ddy[cdd[i]]"
  */
-const POSITION ddy_cdd[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
+const int ddy_cdd[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
 
 /*!
  * @brief 2点間の距離をニュートン・ラプソン法で算出する / Distance between two points via Newton-Raphson technique
@@ -152,22 +153,21 @@ DIRECTION coords_to_dir(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 bool player_can_see_bold(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    grid_type *g_ptr;
-
     /* Blind players see nothing */
     if (player_ptr->effects()->blindness()->is_blind()) {
         return false;
     }
 
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
 
     /* Note that "torch-lite" yields "illumination" */
-    if (g_ptr->info & (CAVE_LITE | CAVE_MNLT)) {
+    if (grid.info & (CAVE_LITE | CAVE_MNLT)) {
         return true;
     }
 
     /* Require line of sight to the grid */
-    if (!player_has_los_bold(player_ptr, y, x)) {
+    if (!grid.has_los()) {
         return false;
     }
 
@@ -177,13 +177,13 @@ bool player_can_see_bold(PlayerType *player_ptr, POSITION y, POSITION x)
     }
 
     /* Require "perma-lite" of the grid */
-    if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
+    if ((grid.info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
         return false;
     }
 
     /* Feature code (applying "mimic" field) */
     /* Floors are simple */
-    if (feat_supports_los(g_ptr->get_feat_mimic())) {
+    if (feat_supports_los(grid.get_feat_mimic())) {
         return true;
     }
 
@@ -195,52 +195,43 @@ bool player_can_see_bold(PlayerType *player_ptr, POSITION y, POSITION x)
  * Calculate "incremental motion". Used by project() and shoot().
  * Assumes that (*y,*x) lies on the path from (y1,x1) to (y2,x2).
  */
-void mmove2(POSITION *y, POSITION *x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
+Pos2D mmove2(const Pos2D &pos_orig, const Pos2D &pos1, const Pos2D &pos2)
 {
-    POSITION dy, dx, dist, shift;
-
     /* Extract the distance travelled */
-    dy = (*y < y1) ? y1 - *y : *y - y1;
-    dx = (*x < x1) ? x1 - *x : *x - x1;
+    auto dy = (pos_orig.y < pos1.y) ? pos1.y - pos_orig.y : pos_orig.y - pos1.y;
+    auto dx = (pos_orig.x < pos1.x) ? pos1.x - pos_orig.x : pos_orig.x - pos1.x;
 
     /* Number of steps */
-    dist = (dy > dx) ? dy : dx;
+    auto dist = (dy > dx) ? dy : dx;
 
     /* We are calculating the next location */
     dist++;
 
     /* Calculate the total distance along each axis */
-    dy = (y2 < y1) ? (y1 - y2) : (y2 - y1);
-    dx = (x2 < x1) ? (x1 - x2) : (x2 - x1);
+    dy = (pos2.y < pos1.y) ? (pos1.y - pos2.y) : (pos2.y - pos1.y);
+    dx = (pos2.x < pos1.x) ? (pos1.x - pos2.x) : (pos2.x - pos1.x);
 
     /* Paranoia -- Hack -- no motion */
     if (!dy && !dx) {
-        return;
+        return pos_orig;
     }
 
     /* Move mostly vertically */
     if (dy > dx) {
         /* Extract a shift factor */
-        shift = (dist * dx + (dy - 1) / 2) / dy;
+        auto shift = (dist * dx + (dy - 1) / 2) / dy;
 
-        /* Sometimes move along the minor axis */
-        (*x) = (x2 < x1) ? (x1 - shift) : (x1 + shift);
-
-        /* Always move along major axis */
-        (*y) = (y2 < y1) ? (y1 - dist) : (y1 + dist);
+        /* Sometimes move along the minor axis, Always move along major axis */
+        const auto y = (pos2.y < pos1.y) ? (pos1.y - dist) : (pos1.y + dist);
+        const auto x = (pos2.x < pos1.x) ? (pos1.x - shift) : (pos1.x + shift);
+        return { y, x };
     }
 
     /* Move mostly horizontally */
-    else {
-        /* Extract a shift factor */
-        shift = (dist * dy + (dx - 1) / 2) / dx;
-
-        /* Sometimes move along the minor axis */
-        (*y) = (y2 < y1) ? (y1 - shift) : (y1 + shift);
-
-        /* Always move along major axis */
-        (*x) = (x2 < x1) ? (x1 - dist) : (x1 + dist);
-    }
+    auto shift = (dist * dy + (dx - 1) / 2) / dx;
+    const auto y = (pos2.y < pos1.y) ? (pos1.y - shift) : (pos1.y + shift);
+    const auto x = (pos2.x < pos1.x) ? (pos1.x - dist) : (pos1.x + dist);
+    return { y, x };
 }
 
 /*!
@@ -253,7 +244,7 @@ void mmove2(POSITION *y, POSITION *x, POSITION y1, POSITION x1, POSITION y2, POS
 bool is_seen(PlayerType *player_ptr, MonsterEntity *m_ptr)
 {
     bool is_inside_view = !ignore_unview;
-    is_inside_view |= player_ptr->phase_out;
+    is_inside_view |= AngbandSystem::get_instance().is_phase_out();
     is_inside_view |= player_can_see_bold(player_ptr, m_ptr->fy, m_ptr->fx) && projectable(player_ptr, player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx);
     return m_ptr->ml && is_inside_view;
 }
index c4cc8ae..6ddbd4f 100644 (file)
@@ -1,6 +1,7 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
+#include "util/point-2d.h"
 
 /*!
  * @brief 視界及び光源の過渡処理配列サイズ / Maximum size of the "temp" array
@@ -19,19 +20,19 @@ struct pos_list {
     POSITION x[TEMP_MAX];
 };
 
-extern const POSITION ddd[9];
-extern const POSITION ddx[10];
-extern const POSITION ddy[10];
-extern const POSITION ddx_ddd[9];
-extern const POSITION ddy_ddd[9];
-extern const POSITION cdd[8];
-extern const POSITION ddx_cdd[8];
-extern const POSITION ddy_cdd[8];
+extern const int ddd[9];
+extern const int ddx[10];
+extern const int ddy[10];
+extern const int ddx_ddd[9];
+extern const int ddy_ddd[9];
+extern const int cdd[8];
+extern const int ddx_cdd[8];
+extern const int ddy_cdd[8];
 
 class PlayerType;
 DIRECTION coords_to_dir(PlayerType *player_ptr, POSITION y, POSITION x);
 POSITION distance(POSITION y1, POSITION x1, POSITION y2, POSITION x2);
-void mmove2(POSITION *y, POSITION *x, POSITION y1, POSITION x1, POSITION y2, POSITION x2);
+Pos2D mmove2(const Pos2D &pos_orig, const Pos2D &pos1, const Pos2D &pos2);
 bool player_can_see_bold(PlayerType *player_ptr, POSITION y, POSITION x);
 
 class MonsterEntity;
index 7f66758..f2d3b8c 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/line-of-sight.h"
+#include "floor/line-of-sight.h"
 #include "floor/cave.h"
 #include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
index cd5b537..5a77a79 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index ea6b6f8..8748294 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/object-allocator.h"
+#include "floor/object-allocator.h"
 #include "dungeon/quest.h"
 #include "floor/cave.h"
 #include "floor/dungeon-tunnel-util.h"
@@ -81,31 +81,32 @@ static bool alloc_stairs_aux(PlayerType *player_ptr, POSITION y, POSITION x, int
 bool alloc_stairs(PlayerType *player_ptr, FEAT_IDX feat, int num, int walls)
 {
     int shaft_num = 0;
-    auto *f_ptr = &terrains_info[feat];
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (f_ptr->flags.has(TerrainCharacteristics::LESS)) {
-        if (ironman_downward || !floor_ptr->dun_level) {
+    const auto &terrain = TerrainList::get_instance()[feat];
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &dungeon = floor.get_dungeon_definition();
+    if (terrain.flags.has(TerrainCharacteristics::LESS)) {
+        if (ironman_downward || !floor.dun_level) {
             return true;
         }
 
-        if (floor_ptr->dun_level > dungeons_info[floor_ptr->dungeon_idx].mindepth) {
+        if (floor.dun_level > dungeon.mindepth) {
             shaft_num = (randint1(num + 1)) / 2;
         }
-    } else if (f_ptr->flags.has(TerrainCharacteristics::MORE)) {
-        auto q_idx = quest_number(player_ptr, floor_ptr->dun_level);
+    } else if (terrain.flags.has(TerrainCharacteristics::MORE)) {
+        auto q_idx = floor.get_quest_id();
         const auto &quest_list = QuestList::get_instance();
-        if (floor_ptr->dun_level > 1 && inside_quest(q_idx)) {
+        if (floor.dun_level > 1 && inside_quest(q_idx)) {
             auto *r_ptr = &monraces_info[quest_list[q_idx].r_idx];
             if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) || 0 < r_ptr->max_num) {
                 return true;
             }
         }
 
-        if (floor_ptr->dun_level >= dungeons_info[floor_ptr->dungeon_idx].maxdepth) {
+        if (floor.dun_level >= dungeon.maxdepth) {
             return true;
         }
 
-        if ((floor_ptr->dun_level < dungeons_info[floor_ptr->dungeon_idx].maxdepth - 1) && !inside_quest(quest_number(player_ptr, floor_ptr->dun_level + 1))) {
+        if ((floor.dun_level < dungeon.maxdepth - 1) && !inside_quest(floor.get_quest_id(1))) {
             shaft_num = (randint1(num) + 1) / 2;
         }
     } else {
@@ -114,10 +115,10 @@ bool alloc_stairs(PlayerType *player_ptr, FEAT_IDX feat, int num, int walls)
 
     for (int i = 0; i < num; i++) {
         while (true) {
-            grid_type *g_ptr;
+            Grid *g_ptr;
             int candidates = 0;
-            const POSITION max_x = floor_ptr->width - 1;
-            for (POSITION y = 1; y < floor_ptr->height - 1; y++) {
+            const POSITION max_x = floor.width - 1;
+            for (POSITION y = 1; y < floor.height - 1; y++) {
                 for (POSITION x = 1; x < max_x; x++) {
                     if (alloc_stairs_aux(player_ptr, y, x, walls)) {
                         candidates++;
@@ -137,8 +138,8 @@ bool alloc_stairs(PlayerType *player_ptr, FEAT_IDX feat, int num, int walls)
             int pick = randint1(candidates);
             POSITION y;
             POSITION x = max_x;
-            for (y = 1; y < floor_ptr->height - 1; y++) {
-                for (x = 1; x < floor_ptr->width - 1; x++) {
+            for (y = 1; y < floor.height - 1; y++) {
+                for (x = 1; x < floor.width - 1; x++) {
                     if (alloc_stairs_aux(player_ptr, y, x, walls)) {
                         pick--;
                         if (pick == 0) {
@@ -152,9 +153,9 @@ bool alloc_stairs(PlayerType *player_ptr, FEAT_IDX feat, int num, int walls)
                 }
             }
 
-            g_ptr = &floor_ptr->grid_array[y][x];
+            g_ptr = &floor.grid_array[y][x];
             g_ptr->mimic = 0;
-            g_ptr->feat = (i < shaft_num) ? feat_state(player_ptr->current_floor_ptr, feat, TerrainCharacteristics::SHAFT) : feat;
+            g_ptr->feat = (i < shaft_num) ? feat_state(&floor, feat, TerrainCharacteristics::SHAFT) : feat;
             g_ptr->info &= ~(CAVE_FLOOR);
             break;
         }
@@ -185,7 +186,6 @@ void alloc_object(PlayerType *player_ptr, dap_type set, dungeon_allocation_type
     POSITION y = 0;
     POSITION x = 0;
     int dummy = 0;
-    grid_type *g_ptr;
     auto *floor_ptr = player_ptr->current_floor_ptr;
     num = num * floor_ptr->height * floor_ptr->width / (MAX_HGT * MAX_WID) + 1;
     for (int k = 0; k < num; k++) {
@@ -193,16 +193,17 @@ void alloc_object(PlayerType *player_ptr, dap_type set, dungeon_allocation_type
             dummy++;
             y = randint0(floor_ptr->height);
             x = randint0(floor_ptr->width);
-            g_ptr = &floor_ptr->grid_array[y][x];
-            if (!g_ptr->is_floor() || !g_ptr->o_idx_list.empty() || g_ptr->m_idx) {
+            const Pos2D pos(y, x);
+            const auto &grid = floor_ptr->get_grid(pos);
+            if (!grid.is_floor() || !grid.o_idx_list.empty() || grid.m_idx) {
                 continue;
             }
 
-            if (player_bold(player_ptr, y, x)) {
+            if (player_ptr->is_located_at(pos)) {
                 continue;
             }
 
-            auto is_room = floor_ptr->grid_array[y][x].is_room();
+            auto is_room = grid.is_room();
             if (((set == ALLOC_SET_CORR) && is_room) || ((set == ALLOC_SET_ROOM) && !is_room)) {
                 continue;
             }
@@ -221,7 +222,7 @@ void alloc_object(PlayerType *player_ptr, dap_type set, dungeon_allocation_type
             floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
             break;
         case ALLOC_TYP_TRAP:
-            place_trap(player_ptr, y, x);
+            place_trap(floor_ptr, y, x);
             floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
             break;
         case ALLOC_TYP_GOLD:
index c8af760..00422b4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "floor/floor-allocation-types.h"
 #include "system/angband.h"
index d0c9393..31dbc7c 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/object-scanner.h"
+#include "floor/object-scanner.h"
 #include "flavor/flavor-describer.h"
 #include "floor/cave.h"
 #include "game-option/text-display-options.h"
@@ -106,18 +106,17 @@ COMMAND_CODE show_floor_items(PlayerType *player_ptr, int target_item, POSITION
     COMMAND_CODE i, m;
     int j, k, l;
     ItemEntity *o_ptr;
-    char tmp_val[80];
-    COMMAND_CODE out_index[23];
-    TERM_COLOR out_color[23];
+    char tmp_val[80]{};
+    COMMAND_CODE out_index[23]{};
+    TERM_COLOR out_color[23]{};
     std::array<std::string, 23> descriptions{};
     COMMAND_CODE target_item_label = 0;
-    OBJECT_IDX floor_list[23];
+    OBJECT_IDX floor_list[23]{};
     ITEM_NUMBER floor_num;
-    TERM_LEN wid, hgt;
-    char floor_label[52 + 1];
-    bool dont_need_to_show_weights = true;
-    term_get_size(&wid, &hgt);
-    int len = std::max((*min_width), 20);
+    char floor_label[52 + 1]{};
+    auto dont_need_to_show_weights = true;
+    const auto &[wid, hgt] = term_get_size();
+    auto len = std::max((*min_width), 20);
     floor_num = scan_floor_items(player_ptr, floor_list, y, x, SCAN_FLOOR_ITEM_TESTER | SCAN_FLOOR_ONLY_MARKED, item_tester);
     auto *floor_ptr = player_ptr->current_floor_ptr;
     for (k = 0, i = 0; i < floor_num && i < 23; i++) {
index 1e50c92..af341a6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 #include "system/angband.h"
index 793643a..b20135e 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/pattern-walk.h"
+#include "floor/pattern-walk.h"
 #include "cmd-io/cmd-save.h"
 #include "core/asking-player.h"
 #include "dungeon/quest.h"
@@ -34,6 +34,7 @@
 #include "view/display-messages.h"
 #include "world/world-movement-processor.h"
 #include "world/world.h"
+#include <algorithm>
 
 /*!
  * @brief パターン終点到達時のテレポート処理を行う
  */
 void pattern_teleport(PlayerType *player_ptr)
 {
-    DEPTH min_level = 0;
-    DEPTH max_level = 99;
-
-    if (get_check(_("他の階にテレポートしますか?", "Teleport level? "))) {
-        char ppp[80];
-        char tmp_val[160];
-
+    auto min_level = 0;
+    auto max_level = 99;
+    auto current_level = static_cast<short>(player_ptr->current_floor_ptr->dun_level);
+    if (input_check(_("他の階にテレポートしますか?", "Teleport level? "))) {
         if (ironman_downward) {
-            min_level = player_ptr->current_floor_ptr->dun_level;
+            min_level = current_level;
         }
 
-        if (player_ptr->dungeon_idx == DUNGEON_ANGBAND) {
-            if (player_ptr->current_floor_ptr->dun_level > 100) {
+        const auto &floor = *player_ptr->current_floor_ptr;
+        if (floor.dungeon_idx == DUNGEON_ANGBAND) {
+            if (floor.dun_level > 100) {
                 max_level = MAX_DEPTH - 1;
-            } else if (player_ptr->current_floor_ptr->dun_level == 100) {
+            } else if (current_level == 100) {
                 max_level = 100;
             }
         } else {
-            max_level = dungeons_info[player_ptr->dungeon_idx].maxdepth;
-            min_level = dungeons_info[player_ptr->dungeon_idx].mindepth;
+            const auto &dungeon = floor.get_dungeon_definition();
+            max_level = dungeon.maxdepth;
+            min_level = dungeon.mindepth;
         }
 
-        strnfmt(ppp, sizeof(ppp), _("テレポート先:(%d-%d)", "Teleport to level (%d-%d): "), (int)min_level, (int)max_level);
-        strnfmt(tmp_val, sizeof(tmp_val), "%d", (int)player_ptr->current_floor_ptr->dun_level);
-        if (!get_string(ppp, tmp_val, 10)) {
+        constexpr auto prompt = _("テレポート先", "Teleport to level");
+        const auto input_level = input_numerics(prompt, min_level, max_level, current_level);
+        if (!input_level) {
             return;
         }
 
-        command_arg = (COMMAND_ARG)atoi(tmp_val);
-    } else if (get_check(_("通常テレポート?", "Normal teleport? "))) {
+        command_arg = *input_level;
+    } else if (input_check(_("通常テレポート?", "Normal teleport? "))) {
         teleport_player(player_ptr, 200, TELEPORT_SPONTANEOUS);
         return;
     } else {
         return;
     }
 
-    if (command_arg < min_level) {
-        command_arg = (COMMAND_ARG)min_level;
-    }
-    if (command_arg > max_level) {
-        command_arg = (COMMAND_ARG)max_level;
-    }
-
     msg_format(_("%d 階にテレポートしました。", "You teleport to dungeon level %d."), command_arg);
     if (autosave_l) {
         do_cmd_save_game(player_ptr, true);
@@ -92,7 +85,7 @@ void pattern_teleport(PlayerType *player_ptr)
     player_ptr->current_floor_ptr->dun_level = command_arg;
     leave_quest_check(player_ptr);
     if (record_stair) {
-        exe_write_diary(player_ptr, DIARY_PAT_TELE, 0, nullptr);
+        exe_write_diary(player_ptr, DiaryKind::PAT_TELE, 0);
     }
 
     player_ptr->current_floor_ptr->quest_number = QuestId::NONE;
@@ -116,7 +109,8 @@ void pattern_teleport(PlayerType *player_ptr)
 bool pattern_effect(PlayerType *player_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!pattern_tile(floor_ptr, player_ptr->y, player_ptr->x)) {
+    const auto p_pos = player_ptr->get_position();
+    if (!pattern_tile(floor_ptr, p_pos.y, p_pos.x)) {
         return false;
     }
 
@@ -125,7 +119,7 @@ bool pattern_effect(PlayerType *player_ptr)
         wreck_the_pattern(player_ptr);
     }
 
-    int pattern_type = terrains_info[floor_ptr->grid_array[player_ptr->y][player_ptr->x].feat].subtype;
+    int pattern_type = floor_ptr->get_grid(p_pos).get_terrain().subtype;
     switch (pattern_type) {
     case PATTERN_TILE_END:
         (void)BadStatusSetter(player_ptr).hallucination(0);
@@ -173,48 +167,44 @@ bool pattern_effect(PlayerType *player_ptr)
 /*!
  * @brief パターンによる移動制限処理
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param c_y プレイヤーの移動元Y座標
- * @param c_x プレイヤーの移動元X座標
- * @param n_y プレイヤーの移動先Y座標
- * @param n_x プレイヤーの移動先X座標
+ * @param pos プレイヤーの移動先座標
  * @return 移動処理が可能である場合(可能な場合に選択した場合)TRUEを返す。
  */
-bool pattern_seq(PlayerType *player_ptr, POSITION c_y, POSITION c_x, POSITION n_y, POSITION n_x)
+bool pattern_seq(PlayerType *player_ptr, const Pos2D &pos)
 {
-    TerrainType *cur_f_ptr = &terrains_info[player_ptr->current_floor_ptr->grid_array[c_y][c_x].feat];
-    TerrainType *new_f_ptr = &terrains_info[player_ptr->current_floor_ptr->grid_array[n_y][n_x].feat];
-    bool is_pattern_tile_cur = cur_f_ptr->flags.has(TerrainCharacteristics::PATTERN);
-    bool is_pattern_tile_new = new_f_ptr->flags.has(TerrainCharacteristics::PATTERN);
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid_current = floor.get_grid(player_ptr->get_position());
+    const auto &grid_new = floor.get_grid(pos);
+    const auto &terrain_current = grid_current.get_terrain();
+    const auto &terrain_new = grid_new.get_terrain();
+    const auto is_pattern_tile_cur = terrain_current.flags.has(TerrainCharacteristics::PATTERN);
+    const auto is_pattern_tile_new = terrain_new.flags.has(TerrainCharacteristics::PATTERN);
     if (!is_pattern_tile_cur && !is_pattern_tile_new) {
         return true;
     }
 
-    int pattern_type_cur = is_pattern_tile_cur ? cur_f_ptr->subtype : NOT_PATTERN_TILE;
-    int pattern_type_new = is_pattern_tile_new ? new_f_ptr->subtype : NOT_PATTERN_TILE;
+    int pattern_type_cur = is_pattern_tile_cur ? terrain_current.subtype : NOT_PATTERN_TILE;
+    int pattern_type_new = is_pattern_tile_new ? terrain_new.subtype : NOT_PATTERN_TILE;
     if (pattern_type_new == PATTERN_TILE_START) {
-        auto effects = player_ptr->effects();
-        auto is_stunned = effects->stun()->is_stunned();
-        auto is_confused = effects->confusion()->is_confused();
-        auto is_hallucinated = effects->hallucination()->is_hallucinated();
-        if (!is_pattern_tile_cur && !is_confused && !is_stunned && !is_hallucinated) {
-            if (get_check(_("パターンの上を歩き始めると、全てを歩かなければなりません。いいですか?",
-                    "If you start walking the Pattern, you must walk the whole way. Ok? "))) {
-                return true;
-            } else {
-                return false;
-            }
-        } else {
+        const auto effects = player_ptr->effects();
+        const auto is_stunned = effects->stun()->is_stunned();
+        const auto is_confused = effects->confusion()->is_confused();
+        const auto is_hallucinated = effects->hallucination()->is_hallucinated();
+        if (is_pattern_tile_cur || is_confused || is_stunned || is_hallucinated) {
             return true;
         }
+
+        return input_check(_("パターンの上を歩き始めると、全てを歩かなければなりません。いいですか?",
+            "If you start walking the Pattern, you must walk the whole way. Ok? "));
     }
 
     if ((pattern_type_new == PATTERN_TILE_OLD) || (pattern_type_new == PATTERN_TILE_END) || (pattern_type_new == PATTERN_TILE_WRECKED)) {
         if (is_pattern_tile_cur) {
             return true;
-        } else {
-            msg_print(_("パターンの上を歩くにはスタート地点から歩き始めなくてはなりません。", "You must start walking the Pattern from the startpoint."));
-            return false;
         }
+
+        msg_print(_("パターンの上を歩くにはスタート地点から歩き始めなくてはなりません。", "You must start walking the Pattern from the startpoint."));
+        return false;
     }
 
     if ((pattern_type_new == PATTERN_TILE_TELEPORT) || (pattern_type_cur == PATTERN_TILE_TELEPORT)) {
@@ -224,24 +214,23 @@ bool pattern_seq(PlayerType *player_ptr, POSITION c_y, POSITION c_x, POSITION n_
     if (pattern_type_cur == PATTERN_TILE_START) {
         if (is_pattern_tile_new) {
             return true;
-        } else {
-            msg_print(_("パターンの上は正しい順序で歩かねばなりません。", "You must walk the Pattern in correct order."));
-            return false;
         }
+
+        msg_print(_("パターンの上は正しい順序で歩かねばなりません。", "You must walk the Pattern in correct order."));
+        return false;
     }
 
     if ((pattern_type_cur == PATTERN_TILE_OLD) || (pattern_type_cur == PATTERN_TILE_END) || (pattern_type_cur == PATTERN_TILE_WRECKED)) {
-        if (!is_pattern_tile_new) {
-            msg_print(_("パターンを踏み外してはいけません。", "You may not step off from the Pattern."));
-            return false;
-        } else {
+        if (is_pattern_tile_new) {
             return true;
         }
+
+        msg_print(_("パターンを踏み外してはいけません。", "You may not step off from the Pattern."));
+        return false;
     }
 
     if (!is_pattern_tile_cur) {
         msg_print(_("パターンの上を歩くにはスタート地点から歩き始めなくてはなりません。", "You must start walking the Pattern from the startpoint."));
-
         return false;
     }
 
index 1c798eb..c3ef745 100644 (file)
@@ -1,8 +1,8 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include "util/point-2d.h"
 
 class PlayerType;
 bool pattern_effect(PlayerType *player_ptr);
-bool pattern_seq(PlayerType *player_ptr, POSITION c_y, POSITION c_x, POSITION n_y, POSITION n_x);
+bool pattern_seq(PlayerType *player_ptr, const Pos2D &pos);
 void pattern_teleport(PlayerType *player_ptr);
index 5062662..23ca8e9 100644 (file)
@@ -1,4 +1,4 @@
-#include "floor/tunnel-generator.h"
+#include "floor/tunnel-generator.h"
 #include "floor/cave.h"
 #include "floor/dungeon-tunnel-util.h"
 #include "floor/geometry.h"
@@ -376,7 +376,7 @@ bool build_tunnel2(PlayerType *player_ptr, dun_data_type *dd_ptr, POSITION x1, P
     POSITION x3, y3, dx, dy;
     POSITION changex, changey;
     bool retval, firstsuccede;
-    grid_type *g_ptr;
+    Grid *g_ptr;
 
     int length = distance(x1, y1, x2, y2);
     auto *floor_ptr = player_ptr->current_floor_ptr;
index 65ed31f..2b25460 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3766b9d..fef6bb4 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 荒野マップの生成とルール管理 / Wilderness generation
  * @date 2014/02/13
  * @author
@@ -89,7 +89,7 @@ static int16_t conv_terrain2feat[MAX_WILDERNESS];
  */
 static void set_floor_and_wall_aux(int16_t feat_type[100], const std::array<feat_prob, DUNGEON_FEAT_PROB_NUM> &prob)
 {
-    int lim[DUNGEON_FEAT_PROB_NUM];
+    std::array<int, DUNGEON_FEAT_PROB_NUM> lim{};
     lim[0] = prob[0].percent;
     for (int i = 1; i < DUNGEON_FEAT_PROB_NUM; i++) {
         lim[i] = lim[i - 1] + prob[i].percent;
@@ -122,14 +122,12 @@ void set_floor_and_wall(DUNGEON_IDX type)
     }
 
     cur_type = type;
-    dungeon_type *d_ptr = &dungeons_info[type];
-
-    set_floor_and_wall_aux(feat_ground_type, d_ptr->floor);
-    set_floor_and_wall_aux(feat_wall_type, d_ptr->fill);
-
-    feat_wall_outer = d_ptr->outer_wall;
-    feat_wall_inner = d_ptr->inner_wall;
-    feat_wall_solid = d_ptr->outer_wall;
+    const auto &dungeon = dungeons_info[type];
+    set_floor_and_wall_aux(feat_ground_type, dungeon.floor);
+    set_floor_and_wall_aux(feat_wall_type, dungeon.fill);
+    feat_wall_outer = dungeon.outer_wall;
+    feat_wall_inner = dungeon.inner_wall;
+    feat_wall_solid = dungeon.outer_wall;
 }
 
 /*!
@@ -257,7 +255,7 @@ static void generate_wilderness_area(FloorType *floor_ptr, int terrain, uint32_t
         return;
     }
 
-    const auto state_backup = w_ptr->rng.get_state();
+    const auto rng_backup = w_ptr->rng;
     w_ptr->rng.set_state(seed);
     int table_size = sizeof(terrain_table[0]) / sizeof(int16_t);
     if (!corner) {
@@ -277,7 +275,7 @@ static void generate_wilderness_area(FloorType *floor_ptr, int terrain, uint32_t
         floor_ptr->grid_array[MAX_HGT - 2][1].feat = terrain_table[terrain][floor_ptr->grid_array[MAX_HGT - 2][1].feat];
         floor_ptr->grid_array[1][MAX_WID - 2].feat = terrain_table[terrain][floor_ptr->grid_array[1][MAX_WID - 2].feat];
         floor_ptr->grid_array[MAX_HGT - 2][MAX_WID - 2].feat = terrain_table[terrain][floor_ptr->grid_array[MAX_HGT - 2][MAX_WID - 2].feat];
-        w_ptr->rng.set_state(state_backup);
+        w_ptr->rng = rng_backup;
         return;
     }
 
@@ -297,7 +295,7 @@ static void generate_wilderness_area(FloorType *floor_ptr, int terrain, uint32_t
         }
     }
 
-    w_ptr->rng.set_state(state_backup);
+    w_ptr->rng = rng_backup;
 }
 
 /*!
@@ -381,13 +379,13 @@ static void generate_area(PlayerType *player_ptr, POSITION y, POSITION x, bool i
         return;
     }
 
-    const auto state_backup = w_ptr->rng.get_state();
+    const auto rng_backup = w_ptr->rng;
     w_ptr->rng.set_state(wilderness[y][x].seed);
     int dy = rand_range(6, floor_ptr->height - 6);
     int dx = rand_range(6, floor_ptr->width - 6);
     floor_ptr->grid_array[dy][dx].feat = feat_entrance;
     floor_ptr->grid_array[dy][dx].special = wilderness[y][x].entrance;
-    w_ptr->rng.set_state(state_backup);
+    w_ptr->rng = rng_backup;
 }
 
 /*!
@@ -420,141 +418,141 @@ static void generate_wild_monsters(PlayerType *player_ptr)
  */
 void wilderness_gen(PlayerType *player_ptr)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    floor_ptr->height = MAX_HGT;
-    floor_ptr->width = MAX_WID;
-    panel_row_min = floor_ptr->height;
-    panel_col_min = floor_ptr->width;
+    auto &floor = *player_ptr->current_floor_ptr;
+    floor.height = MAX_HGT;
+    floor.width = MAX_WID;
+    panel_row_min = floor.height;
+    panel_col_min = floor.width;
     parse_fixed_map(player_ptr, WILDERNESS_DEFINITION, 0, 0, w_ptr->max_wild_y, w_ptr->max_wild_x);
-    POSITION x = player_ptr->wilderness_x;
-    POSITION y = player_ptr->wilderness_y;
+    const auto wild_y = player_ptr->wilderness_y;
+    const auto wild_x = player_ptr->wilderness_x;
     get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), nullptr);
 
     /* North border */
-    generate_area(player_ptr, y - 1, x, true, false);
+    generate_area(player_ptr, wild_y - 1, wild_x, true, false);
     for (int i = 1; i < MAX_WID - 1; i++) {
-        border.north[i] = floor_ptr->grid_array[MAX_HGT - 2][i].feat;
+        border.north[i] = floor.grid_array[MAX_HGT - 2][i].feat;
     }
 
     /* South border */
-    generate_area(player_ptr, y + 1, x, true, false);
+    generate_area(player_ptr, wild_y + 1, wild_x, true, false);
     for (int i = 1; i < MAX_WID - 1; i++) {
-        border.south[i] = floor_ptr->grid_array[1][i].feat;
+        border.south[i] = floor.grid_array[1][i].feat;
     }
 
     /* West border */
-    generate_area(player_ptr, y, x - 1, true, false);
+    generate_area(player_ptr, wild_y, wild_x - 1, true, false);
     for (int i = 1; i < MAX_HGT - 1; i++) {
-        border.west[i] = floor_ptr->grid_array[i][MAX_WID - 2].feat;
+        border.west[i] = floor.grid_array[i][MAX_WID - 2].feat;
     }
 
     /* East border */
-    generate_area(player_ptr, y, x + 1, true, false);
+    generate_area(player_ptr, wild_y, wild_x + 1, true, false);
     for (int i = 1; i < MAX_HGT - 1; i++) {
-        border.east[i] = floor_ptr->grid_array[i][1].feat;
+        border.east[i] = floor.grid_array[i][1].feat;
     }
 
     /* North west corner */
-    generate_area(player_ptr, y - 1, x - 1, false, true);
-    border.north_west = floor_ptr->grid_array[MAX_HGT - 2][MAX_WID - 2].feat;
+    generate_area(player_ptr, wild_y - 1, wild_x - 1, false, true);
+    border.north_west = floor.grid_array[MAX_HGT - 2][MAX_WID - 2].feat;
 
     /* North east corner */
-    generate_area(player_ptr, y - 1, x + 1, false, true);
-    border.north_east = floor_ptr->grid_array[MAX_HGT - 2][1].feat;
+    generate_area(player_ptr, wild_y - 1, wild_x + 1, false, true);
+    border.north_east = floor.grid_array[MAX_HGT - 2][1].feat;
 
     /* South west corner */
-    generate_area(player_ptr, y + 1, x - 1, false, true);
-    border.south_west = floor_ptr->grid_array[1][MAX_WID - 2].feat;
+    generate_area(player_ptr, wild_y + 1, wild_x - 1, false, true);
+    border.south_west = floor.grid_array[1][MAX_WID - 2].feat;
 
     /* South east corner */
-    generate_area(player_ptr, y + 1, x + 1, false, true);
-    border.south_east = floor_ptr->grid_array[1][1].feat;
+    generate_area(player_ptr, wild_y + 1, wild_x + 1, false, true);
+    border.south_east = floor.grid_array[1][1].feat;
 
     /* Create terrain of the current area */
-    generate_area(player_ptr, y, x, false, false);
+    generate_area(player_ptr, wild_y, wild_x, false, false);
 
     /* Special boundary walls -- North */
-    for (int i = 0; i < MAX_WID; i++) {
-        floor_ptr->grid_array[0][i].feat = feat_permanent;
-        floor_ptr->grid_array[0][i].mimic = border.north[i];
+    for (auto i = 0; i < MAX_WID; i++) {
+        auto &grid = floor.get_grid({ 0, i });
+        grid.feat = feat_permanent;
+        grid.mimic = border.north[i];
     }
 
     /* Special boundary walls -- South */
-    for (int i = 0; i < MAX_WID; i++) {
-        floor_ptr->grid_array[MAX_HGT - 1][i].feat = feat_permanent;
-        floor_ptr->grid_array[MAX_HGT - 1][i].mimic = border.south[i];
+    for (auto i = 0; i < MAX_WID; i++) {
+        auto &grid = floor.get_grid({ MAX_HGT - 1, i });
+        grid.feat = feat_permanent;
+        grid.mimic = border.south[i];
     }
 
     /* Special boundary walls -- West */
-    for (int i = 0; i < MAX_HGT; i++) {
-        floor_ptr->grid_array[i][0].feat = feat_permanent;
-        floor_ptr->grid_array[i][0].mimic = border.west[i];
+    for (auto i = 0; i < MAX_HGT; i++) {
+        auto &grid = floor.get_grid({ i, 0 });
+        grid.feat = feat_permanent;
+        grid.mimic = border.west[i];
     }
 
     /* Special boundary walls -- East */
-    for (int i = 0; i < MAX_HGT; i++) {
-        floor_ptr->grid_array[i][MAX_WID - 1].feat = feat_permanent;
-        floor_ptr->grid_array[i][MAX_WID - 1].mimic = border.east[i];
-    }
-
-    floor_ptr->grid_array[0][0].mimic = border.north_west;
-    floor_ptr->grid_array[0][MAX_WID - 1].mimic = border.north_east;
-    floor_ptr->grid_array[MAX_HGT - 1][0].mimic = border.south_west;
-    floor_ptr->grid_array[MAX_HGT - 1][MAX_WID - 1].mimic = border.south_east;
-    for (y = 0; y < floor_ptr->height; y++) {
-        for (x = 0; x < floor_ptr->width; x++) {
-            grid_type *g_ptr;
-            g_ptr = &floor_ptr->grid_array[y][x];
-            if (is_daytime()) {
-                g_ptr->info |= CAVE_GLOW;
+    for (auto i = 0; i < MAX_HGT; i++) {
+        auto &grid = floor.get_grid({ i, MAX_WID - 1 });
+        grid.feat = feat_permanent;
+        grid.mimic = border.east[i];
+    }
+
+    floor.get_grid({ 0, 0 }).mimic = border.north_west;
+    floor.get_grid({ 0, MAX_WID - 1 }).mimic = border.north_east;
+    floor.get_grid({ MAX_HGT - 1, 0 }).mimic = border.south_west;
+    floor.get_grid({ MAX_HGT - 1, MAX_WID - 1 }).mimic = border.south_east;
+    for (auto y = 0; y < floor.height; y++) {
+        for (auto x = 0; x < floor.width; x++) {
+            auto &grid = floor.get_grid({ y, x });
+            if (w_ptr->is_daytime()) {
+                grid.info |= CAVE_GLOW;
                 if (view_perma_grids) {
-                    g_ptr->info |= CAVE_MARK;
+                    grid.info |= CAVE_MARK;
                 }
 
                 continue;
             }
 
-            TerrainType *f_ptr;
-            f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
-            auto can_darken = !g_ptr->is_mirror();
-            can_darken &= f_ptr->flags.has_none_of({ TerrainCharacteristics::QUEST_ENTER, TerrainCharacteristics::ENTRANCE });
+            const auto &terrain = grid.get_terrain_mimic();
+            auto can_darken = !grid.is_mirror();
+            can_darken &= terrain.flags.has_none_of({ TerrainCharacteristics::QUEST_ENTER, TerrainCharacteristics::ENTRANCE });
             if (can_darken) {
-                g_ptr->info &= ~(CAVE_GLOW);
-                if (f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
-                    g_ptr->info &= ~(CAVE_MARK);
+                grid.info &= ~(CAVE_GLOW);
+                if (terrain.flags.has_not(TerrainCharacteristics::REMEMBER)) {
+                    grid.info &= ~(CAVE_MARK);
                 }
 
                 continue;
             }
 
-            if (f_ptr->flags.has_not(TerrainCharacteristics::ENTRANCE)) {
+            if (terrain.flags.has_not(TerrainCharacteristics::ENTRANCE)) {
                 continue;
             }
 
-            g_ptr->info |= CAVE_GLOW;
+            grid.info |= CAVE_GLOW;
             if (view_perma_grids) {
-                g_ptr->info |= CAVE_MARK;
+                grid.info |= CAVE_MARK;
             }
         }
     }
 
     if (player_ptr->teleport_town) {
-        for (y = 0; y < floor_ptr->height; y++) {
-            for (x = 0; x < floor_ptr->width; x++) {
-                grid_type *g_ptr;
-                g_ptr = &floor_ptr->grid_array[y][x];
-                TerrainType *f_ptr;
-                f_ptr = &terrains_info[g_ptr->feat];
-                if (f_ptr->flags.has_not(TerrainCharacteristics::BLDG)) {
+        for (auto y = 0; y < floor.height; y++) {
+            for (auto x = 0; x < floor.width; x++) {
+                auto &grid = floor.get_grid({ y, x });
+                const auto &terrain = grid.get_terrain();
+                if (terrain.flags.has_not(TerrainCharacteristics::BLDG)) {
                     continue;
                 }
 
-                if ((f_ptr->subtype != 4) && !((player_ptr->town_num == 1) && (f_ptr->subtype == 0))) {
+                if ((terrain.subtype != 4) && !((player_ptr->town_num == 1) && (terrain.subtype == 0))) {
                     continue;
                 }
 
-                if (g_ptr->m_idx != 0) {
-                    delete_monster_idx(player_ptr, g_ptr->m_idx);
+                if (grid.m_idx != 0) {
+                    delete_monster_idx(player_ptr, grid.m_idx);
                 }
 
                 player_ptr->oldpy = y;
@@ -564,16 +562,15 @@ void wilderness_gen(PlayerType *player_ptr)
 
         player_ptr->teleport_town = false;
     } else if (player_ptr->leaving_dungeon) {
-        for (y = 0; y < floor_ptr->height; y++) {
-            for (x = 0; x < floor_ptr->width; x++) {
-                grid_type *g_ptr;
-                g_ptr = &floor_ptr->grid_array[y][x];
-                if (!g_ptr->cave_has_flag(TerrainCharacteristics::ENTRANCE)) {
+        for (auto y = 0; y < floor.height; y++) {
+            for (auto x = 0; x < floor.width; x++) {
+                auto &grid = floor.get_grid({ y, x });
+                if (!grid.cave_has_flag(TerrainCharacteristics::ENTRANCE)) {
                     continue;
                 }
 
-                if (g_ptr->m_idx != 0) {
-                    delete_monster_idx(player_ptr, g_ptr->m_idx);
+                if (grid.m_idx != 0) {
+                    delete_monster_idx(player_ptr, grid.m_idx);
                 }
 
                 player_ptr->oldpy = y;
@@ -743,7 +740,7 @@ parse_error_type parse_line_wilderness(PlayerType *player_ptr, char *buf, int xm
             wilderness[*y][*x].level = w_letter[id].level;
             wilderness[*y][*x].town = w_letter[id].town;
             wilderness[*y][*x].road = w_letter[id].road;
-            strcpy(towns_info[w_letter[id].town].name, w_letter[id].name);
+            towns_info[w_letter[id].town].name = w_letter[id].name;
         }
 
         (*y)++;
@@ -929,7 +926,7 @@ bool change_wild_mode(PlayerType *player_ptr, bool encount)
 
     if (has_pet) {
         concptr msg = _("ペットを置いて広域マップに入りますか?", "Do you leave your pets behind? ");
-        if (!get_check_strict(player_ptr, msg, CHECK_OKAY_CANCEL)) {
+        if (!input_check_strict(player_ptr, msg, UserCheck::OKAY_CANCEL)) {
             energy.reset_player_turn();
             return false;
         }
index 6637bcc..3b23732 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <vector>
index c8092a1..b2aa6b1 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/auto-destruction-options.h"
+#include "game-option/auto-destruction-options.h"
 
 bool destroy_items; /* Use easy auto-destroyer */
 bool destroy_feeling; /* Apply auto-destroy as sense feeling */
index e9255fb..e01afe5 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/birth-options.h"
+#include "game-option/birth-options.h"
 
 bool smart_learn; /* Monsters learn from their mistakes (*) */
 bool smart_cheat; /* Monsters exploit players weaknesses (*) */
index 69f9308..911ed13 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index dbcf4ed..b166d45 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/cheat-options.h"
+#include "game-option/cheat-options.h"
 
 bool cheat_peek; /* Peek into object creation */
 bool cheat_hear; /* Peek into monster creation */
index 1f8d1ae..6e8df06 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 7334790..52a8a94 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum cheat_type {
     CHEAT_OBJECT = 0,
index b4d5c7e..d3a427a 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/disturbance-options.h"
+#include "game-option/disturbance-options.h"
 
 bool find_ignore_stairs; /* Run past stairs */
 bool find_ignore_doors; /* Run through open doors */
index 696c77e..6ed5288 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 6b05332..59bbed2 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/game-play-options.h"
+#include "game-option/game-play-options.h"
 
 bool stack_force_notes; /* Merge inscriptions when stacking */
 bool stack_force_costs; /* Merge discounts when stacking */
index 9884a15..3cf3b76 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 7a0ff4f..1346425 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/input-options.h"
+#include "game-option/input-options.h"
 
 bool rogue_like_commands; /* Rogue-like commands */
 bool always_pickup; /* Pick things up by default */
index e74ee36..5f65434 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 683e18a..f6e2315 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/keymap-directory-getter.h"
+#include "game-option/keymap-directory-getter.h"
 #include "game-option/input-options.h"
 #include "io/input-key-requester.h"
 #include "system/angband.h"
@@ -28,7 +28,7 @@ int get_keymap_dir(char ch)
 
         concptr act = keymap_act[mode][(byte)(ch)];
         if (act) {
-            for (concptr s = act; *s; ++s) {
+            for (auto s = act; *s; ++s) {
                 if (isdigit(*s)) {
                     d = D2I(*s);
                 }
index 517639d..9551a5a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum keymap_mode {
     KEYMAP_MODE_ORIG = 0, /*!< オリジナルキー配置 / Mode for original keyset commands */
index 5799ba4..1bdfa18 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/map-screen-options.h"
+#include "game-option/map-screen-options.h"
 
 bool center_player; /* Center map while walking (*slow*) */
 bool center_running; /* Centering even while running */
index b2b4a3a..dc7a88e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 4423570..d01c219 100644 (file)
@@ -1,6 +1,7 @@
-#include "game-option/option-flags.h"
+#include "game-option/option-flags.h"
+#include "system/redrawing-flags-updater.h"
 
-BIT_FLAGS option_flag[8]; //!< The array of normal options
-BIT_FLAGS option_mask[8]; //!< The array of normal options
-BIT_FLAGS window_flag[8]; //!< The array of window options
-BIT_FLAGS window_mask[8]; //!< The array of window options
+std::array<uint32_t, MAX_WINDOW_ENTITIES> g_option_flags = {};
+std::array<uint32_t, MAX_WINDOW_ENTITIES> g_option_masks = {};
+std::array<EnumClassFlagGroup<SubWindowRedrawingFlag>, MAX_WINDOW_ENTITIES> g_window_flags = {};
+std::array<EnumClassFlagGroup<SubWindowRedrawingFlag>, MAX_WINDOW_ENTITIES> g_window_masks = {};
index c90ea03..33aab4b 100644 (file)
@@ -1,8 +1,13 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include "system/redrawing-flags-updater.h"
+#include "util/flag-group.h"
+#include <array>
+#include <stdint.h>
 
-extern BIT_FLAGS option_flag[8];
-extern BIT_FLAGS option_mask[8];
-extern BIT_FLAGS window_flag[8];
-extern BIT_FLAGS window_mask[8];
+constexpr auto MAX_WINDOW_ENTITIES = 8;
+
+extern std::array<uint32_t, MAX_WINDOW_ENTITIES> g_option_flags;
+extern std::array<uint32_t, MAX_WINDOW_ENTITIES> g_option_masks;
+extern std::array<EnumClassFlagGroup<SubWindowRedrawingFlag>, MAX_WINDOW_ENTITIES> g_window_flags;
+extern std::array<EnumClassFlagGroup<SubWindowRedrawingFlag>, MAX_WINDOW_ENTITIES> g_window_masks;
index 1ebc642..8b1c2cf 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/option-types-table.h"
+#include "game-option/option-types-table.h"
 #include "game-option/auto-destruction-options.h"
 #include "game-option/birth-options.h"
 #include "game-option/cheat-options.h"
index 6868530..8bffe17 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <vector>
index bc8101b..5964421 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/play-record-options.h"
+#include "game-option/play-record-options.h"
 
 bool record_fix_art; /* Record fixed artifacts */
 bool record_rand_art; /* Record random artifacts */
index d758539..0ec5525 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index ec53275..400306f 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/runtime-arguments.h"
+#include "game-option/runtime-arguments.h"
 
 bool arg_sound; /* Command arg -- Request special sounds */
 int arg_sound_volume_table_index;
index ddc2627..0164f06 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index ac3d6a6..976a59e 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/special-options.h"
+#include "game-option/special-options.h"
 
 byte hitpoint_warn; /* Hitpoint warning (0 to 9) */
 byte mana_warn; /* Mana color (0 to 9) */
index ecd69b0..00c7096 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 6fb59c1..02f3f8b 100644 (file)
@@ -1,4 +1,4 @@
-#include "game-option/text-display-options.h"
+#include "game-option/text-display-options.h"
 
 bool plain_descriptions; /* Plain object descriptions */
 bool plain_pickup; /* Plain pickup messages(japanese only) */
index 05de62b..85da816 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 218ccae..878ff6b 100644 (file)
@@ -1,4 +1,4 @@
-#include "grid/door.h"
+#include "grid/door.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/cave.h"
 #include "grid/feature.h"
@@ -63,33 +63,36 @@ void add_door(PlayerType *player_ptr, POSITION x, POSITION y)
  */
 void place_secret_door(PlayerType *player_ptr, POSITION y, POSITION x, int type)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_DOORS)) {
-        place_bold(player_ptr, y, x, GB_FLOOR);
+    auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(y, x);
+    const auto &dungeon = floor.get_dungeon_definition();
+    if (dungeon.flags.has(DungeonFeatureType::NO_DOORS)) {
+        place_bold(player_ptr, pos.y, pos.x, GB_FLOOR);
         return;
     }
 
     if (type == DOOR_DEFAULT) {
-        type = (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
+        type = (dungeon.flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeon.flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
                    ? DOOR_CURTAIN
-                   : (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
+                   : (dungeon.flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
     }
 
-    place_closed_door(player_ptr, y, x, type);
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
+    place_closed_door(player_ptr, pos.y, pos.x, type);
+    auto &grid = floor.get_grid(pos);
     if (type != DOOR_CURTAIN) {
-        g_ptr->mimic = feat_wall_inner;
-        if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat)) {
-            if (terrains_info[g_ptr->mimic].flags.has(TerrainCharacteristics::MOVE) || terrains_info[g_ptr->mimic].flags.has(TerrainCharacteristics::CAN_FLY)) {
-                g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
+        grid.mimic = feat_wall_inner;
+        if (feat_supports_los(grid.mimic) && !feat_supports_los(grid.feat)) {
+            const auto &terrain_mimic = grid.get_terrain_mimic_raw();
+            if (terrain_mimic.flags.has(TerrainCharacteristics::MOVE) || terrain_mimic.flags.has(TerrainCharacteristics::CAN_FLY)) {
+                grid.feat = one_in_(2) ? grid.mimic : rand_choice(feat_ground_type);
             }
 
-            g_ptr->mimic = 0;
+            grid.mimic = 0;
         }
     }
 
-    g_ptr->info &= ~(CAVE_FLOOR);
-    delete_monster(player_ptr, y, x);
+    grid.info &= ~(CAVE_FLOOR);
+    delete_monster(player_ptr, pos.y, pos.x);
 }
 
 /*!
@@ -101,12 +104,13 @@ void place_secret_door(PlayerType *player_ptr, POSITION y, POSITION x, int type)
 void place_locked_door(PlayerType *player_ptr, POSITION y, POSITION x)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_DOORS)) {
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    if (dungeon.flags.has(DungeonFeatureType::NO_DOORS)) {
         place_bold(player_ptr, y, x, GB_FLOOR);
         return;
     }
 
-    set_cave_feat(floor_ptr, y, x, feat_locked_door_random(dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR));
+    set_cave_feat(floor_ptr, y, x, feat_locked_door_random(dungeon.flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR));
     floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
     delete_monster(player_ptr, y, x);
 }
@@ -120,18 +124,19 @@ void place_locked_door(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 void place_random_door(PlayerType *player_ptr, POSITION y, POSITION x, bool room)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
-    g_ptr->mimic = 0;
-
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_DOORS)) {
+    const Pos2D pos(y, x);
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &grid = floor.get_grid(pos);
+    grid.mimic = 0;
+    const auto &dungeon = floor.get_dungeon_definition();
+    if (dungeon.flags.has(DungeonFeatureType::NO_DOORS)) {
         place_bold(player_ptr, y, x, GB_FLOOR);
         return;
     }
 
-    int type = (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
+    int type = (dungeon.flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeon.flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
                    ? DOOR_CURTAIN
-                   : (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
+                   : (dungeon.flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
 
     int tmp = randint0(1000);
     FEAT_IDX feat = feat_none;
@@ -141,14 +146,14 @@ void place_random_door(PlayerType *player_ptr, POSITION y, POSITION x, bool room
         feat = feat_door[type].broken;
     } else if (tmp < 600) {
         place_closed_door(player_ptr, y, x, type);
-
         if (type != DOOR_CURTAIN) {
-            g_ptr->mimic = room ? feat_wall_outer : feat_wall_type[randint0(100)];
-            if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat)) {
-                if (terrains_info[g_ptr->mimic].flags.has(TerrainCharacteristics::MOVE) || terrains_info[g_ptr->mimic].flags.has(TerrainCharacteristics::CAN_FLY)) {
-                    g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
+            grid.mimic = room ? feat_wall_outer : rand_choice(feat_wall_type);
+            if (feat_supports_los(grid.mimic) && !feat_supports_los(grid.feat)) {
+                const auto &terrain_mimic = grid.get_terrain_mimic_raw();
+                if (terrain_mimic.flags.has(TerrainCharacteristics::MOVE) || terrain_mimic.flags.has(TerrainCharacteristics::CAN_FLY)) {
+                    grid.feat = one_in_(2) ? grid.mimic : rand_choice(feat_ground_type);
                 }
-                g_ptr->mimic = 0;
+                grid.mimic = 0;
             }
         }
     } else {
@@ -163,7 +168,7 @@ void place_random_door(PlayerType *player_ptr, POSITION y, POSITION x, bool room
     if (feat == feat_none) {
         place_bold(player_ptr, y, x, GB_FLOOR);
     } else {
-        set_cave_feat(floor_ptr, y, x, feat);
+        set_cave_feat(&floor, y, x, feat);
     }
 
     delete_monster(player_ptr, y, x);
@@ -179,7 +184,7 @@ void place_random_door(PlayerType *player_ptr, POSITION y, POSITION x, bool room
 void place_closed_door(PlayerType *player_ptr, POSITION y, POSITION x, int type)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_DOORS)) {
+    if (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::NO_DOORS)) {
         place_bold(player_ptr, y, x, GB_FLOOR);
         return;
     }
index 5d7061b..fa3c86b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 1935ae9..eaa8882 100644 (file)
@@ -1,4 +1,4 @@
-#include "grid/feature-action-flags.h"
+#include "grid/feature-action-flags.h"
 
 /*!
  * @brief 地形状態フラグテーブル /
index 357a908..6cbd501 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include "grid/feature-flag-types.h"
 #include "system/angband.h"
 
index e9e4f25..5a10ae5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "util/enum-converter.h"
 
index 4900267..3bbda49 100644 (file)
@@ -1,4 +1,4 @@
-#include "grid/feature-generator.h"
+#include "grid/feature-generator.h"
 #include "dungeon/dungeon-flag-mask.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h"
@@ -62,9 +62,9 @@ static bool decide_cavern(const FloorType &floor_ref, const dungeon_type &dungeo
  */
 void gen_caverns_and_lakes(PlayerType *player_ptr, dungeon_type *dungeon_ptr, dun_data_type *dd_ptr)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
+    const auto &floor = *player_ptr->current_floor_ptr;
     constexpr auto chance_destroyed = 18;
-    if ((floor_ptr->dun_level > 30) && one_in_(chance_destroyed * 2) && small_levels && dungeon_ptr->flags.has(DungeonFeatureType::DESTROY)) {
+    if ((floor.dun_level > 30) && one_in_(chance_destroyed * 2) && small_levels && dungeon_ptr->flags.has(DungeonFeatureType::DESTROY)) {
         dd_ptr->destroyed = true;
         build_lake(player_ptr, one_in_(2) ? LAKE_T_CAVE : LAKE_T_EARTH_VAULT);
     }
@@ -73,12 +73,12 @@ void gen_caverns_and_lakes(PlayerType *player_ptr, dungeon_type *dungeon_ptr, du
     if (one_in_(chance_water) && !dd_ptr->empty_level && !dd_ptr->destroyed && dungeon_ptr->flags.has_any_of(DF_LAKE_MASK)) {
         auto count = calc_cavern_terrains(*dungeon_ptr);
         if (dungeon_ptr->flags.has(DungeonFeatureType::LAKE_LAVA)) {
-            if ((floor_ptr->dun_level > 80) && (randint0(count) < 2)) {
+            if ((floor.dun_level > 80) && (randint0(count) < 2)) {
                 dd_ptr->laketype = LAKE_T_LAVA;
             }
 
             count -= 2;
-            if (!dd_ptr->laketype && (floor_ptr->dun_level > 80) && one_in_(count)) {
+            if (!dd_ptr->laketype && (floor.dun_level > 80) && one_in_(count)) {
                 dd_ptr->laketype = LAKE_T_FIRE_VAULT;
             }
 
@@ -86,12 +86,12 @@ void gen_caverns_and_lakes(PlayerType *player_ptr, dungeon_type *dungeon_ptr, du
         }
 
         if (dungeon_ptr->flags.has(DungeonFeatureType::LAKE_WATER) && !dd_ptr->laketype) {
-            if ((floor_ptr->dun_level > 50) && randint0(count) < 2) {
+            if ((floor.dun_level > 50) && randint0(count) < 2) {
                 dd_ptr->laketype = LAKE_T_WATER;
             }
 
             count -= 2;
-            if (!dd_ptr->laketype && (floor_ptr->dun_level > 50) && one_in_(count)) {
+            if (!dd_ptr->laketype && (floor.dun_level > 50) && one_in_(count)) {
                 dd_ptr->laketype = LAKE_T_WATER_VAULT;
             }
 
@@ -99,19 +99,19 @@ void gen_caverns_and_lakes(PlayerType *player_ptr, dungeon_type *dungeon_ptr, du
         }
 
         if (dungeon_ptr->flags.has(DungeonFeatureType::LAKE_RUBBLE) && !dd_ptr->laketype) {
-            if ((floor_ptr->dun_level > 35) && (randint0(count) < 2)) {
+            if ((floor.dun_level > 35) && (randint0(count) < 2)) {
                 dd_ptr->laketype = LAKE_T_CAVE;
             }
 
             count -= 2;
-            if (!dd_ptr->laketype && (floor_ptr->dun_level > 35) && one_in_(count)) {
+            if (!dd_ptr->laketype && (floor.dun_level > 35) && one_in_(count)) {
                 dd_ptr->laketype = LAKE_T_EARTH_VAULT;
             }
 
             count--;
         }
 
-        if ((floor_ptr->dun_level > 5) && dungeon_ptr->flags.has(DungeonFeatureType::LAKE_TREE) && !dd_ptr->laketype) {
+        if ((floor.dun_level > 5) && dungeon_ptr->flags.has(DungeonFeatureType::LAKE_TREE) && !dd_ptr->laketype) {
             dd_ptr->laketype = LAKE_T_AIR_VAULT;
         }
 
@@ -121,14 +121,14 @@ void gen_caverns_and_lakes(PlayerType *player_ptr, dungeon_type *dungeon_ptr, du
         }
     }
 
-    const auto should_build_cavern = decide_cavern(*floor_ptr, *dungeon_ptr, *dd_ptr);
+    const auto should_build_cavern = decide_cavern(floor, *dungeon_ptr, *dd_ptr);
     if (should_build_cavern) {
         dd_ptr->cavern = true;
         msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("洞窟を生成。", "Cavern on level."));
         build_cavern(player_ptr);
     }
 
-    if (inside_quest(quest_number(player_ptr, floor_ptr->dun_level))) {
+    if (inside_quest(floor.get_quest_id())) {
         dd_ptr->destroyed = false;
     }
 }
@@ -150,7 +150,7 @@ static int next_to_corr(FloorType *floor_ptr, POSITION y1, POSITION x1)
     for (int i = 0; i < 4; i++) {
         POSITION y = y1 + ddy_ddd[i];
         POSITION x = x1 + ddx_ddd[i];
-        grid_type *g_ptr;
+        Grid *g_ptr;
         g_ptr = &floor_ptr->grid_array[y][x];
         if (g_ptr->cave_has_flag(TerrainCharacteristics::WALL) || !g_ptr->is_floor() || g_ptr->is_room()) {
             continue;
@@ -201,7 +201,7 @@ void try_door(PlayerType *player_ptr, dt_type *dt_ptr, POSITION y, POSITION x)
 
     bool can_place_door = randint0(100) < dt_ptr->dun_tun_jct;
     can_place_door &= possible_doorway(floor_ptr, y, x);
-    can_place_door &= dungeons_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::NO_DOORS);
+    can_place_door &= floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::NO_DOORS);
     if (can_place_door) {
         place_random_door(player_ptr, y, x, false);
     }
index 4b16b80..8940b19 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 128ef16..589efca 100644 (file)
@@ -1,5 +1,4 @@
-#include "grid/feature.h"
-#include "core/player-update-types.h"
+#include "grid/feature.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/cave.h"
 #include "floor/geometry.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h" // @todo 相互依存している. 後で何とかする.
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "world/world.h"
+#include <span>
 
 enum conversion_type {
     CONVERT_TYPE_FLOOR = 0,
@@ -122,7 +123,7 @@ bool is_trap(PlayerType *player_ptr, FEAT_IDX feat)
 {
     /* 関数ポインタの都合 */
     (void)player_ptr;
-    return terrains_info[feat].flags.has(TerrainCharacteristics::TRAP);
+    return TerrainList::get_instance()[feat].flags.has(TerrainCharacteristics::TRAP);
 }
 
 /*!
@@ -134,10 +135,9 @@ bool is_closed_door(PlayerType *player_ptr, FEAT_IDX feat)
 {
     /* 関数ポインタの都合 */
     (void)player_ptr;
-    auto *f_ptr = &terrains_info[feat];
-
-    return (f_ptr->flags.has(TerrainCharacteristics::OPEN) || f_ptr->flags.has(TerrainCharacteristics::BASH)) &&
-           f_ptr->flags.has_not(TerrainCharacteristics::MOVE);
+    const auto &terrain = TerrainList::get_instance()[feat];
+    return (terrain.flags.has(TerrainCharacteristics::OPEN) || terrain.flags.has(TerrainCharacteristics::BASH)) &&
+           terrain.flags.has_not(TerrainCharacteristics::MOVE);
 }
 
 /*!
@@ -174,22 +174,18 @@ bool is_ascii_graphics(char x)
     return (x & 0x80) == 0;
 }
 
-/*
- * Determine if a "feature" is "permanent wall"
- */
-bool permanent_wall(TerrainType *f_ptr)
-{
-    return f_ptr->flags.has_all_of({ TerrainCharacteristics::WALL, TerrainCharacteristics::PERMANENT });
-}
-
 FEAT_IDX feat_locked_door_random(int door_type)
 {
-    return feat_door[door_type].num_locked ? feat_door[door_type].locked[randint0(feat_door[door_type].num_locked)] : feat_none;
+    const auto &door = feat_door[door_type];
+    std::span<const FEAT_IDX> candidates(std::begin(door.locked), door.num_locked);
+    return candidates.empty() ? feat_none : rand_choice(candidates);
 }
 
 FEAT_IDX feat_jammed_door_random(int door_type)
 {
-    return feat_door[door_type].num_jammed ? feat_door[door_type].jammed[randint0(feat_door[door_type].num_jammed)] : feat_none;
+    const auto &door = feat_door[door_type];
+    std::span<const FEAT_IDX> candidates(std::begin(door.jammed), door.num_jammed);
+    return candidates.empty() ? feat_none : rand_choice(candidates);
 }
 
 /*
@@ -199,11 +195,12 @@ void cave_set_feat(PlayerType *player_ptr, POSITION y, POSITION x, FEAT_IDX feat
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *g_ptr = &floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[feat];
+    const auto &terrain = TerrainList::get_instance()[feat];
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
     if (!w_ptr->character_dungeon) {
         g_ptr->mimic = 0;
         g_ptr->feat = feat;
-        if (f_ptr->flags.has(TerrainCharacteristics::GLOW) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS)) {
+        if (terrain.flags.has(TerrainCharacteristics::GLOW) && dungeon.flags.has_not(DungeonFeatureType::DARKNESS)) {
             for (DIRECTION i = 0; i < 9; i++) {
                 POSITION yy = y + ddy_ddd[i];
                 POSITION xx = x + ddx_ddd[i];
@@ -224,7 +221,7 @@ void cave_set_feat(PlayerType *player_ptr, POSITION y, POSITION x, FEAT_IDX feat
     g_ptr->mimic = 0;
     g_ptr->feat = feat;
     g_ptr->info &= ~(CAVE_OBJECT);
-    if (old_mirror && dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    if (old_mirror && dungeon.flags.has(DungeonFeatureType::DARKNESS)) {
         g_ptr->info &= ~(CAVE_GLOW);
         if (!view_torch_grids) {
             g_ptr->info &= ~(CAVE_MARK);
@@ -233,7 +230,7 @@ void cave_set_feat(PlayerType *player_ptr, POSITION y, POSITION x, FEAT_IDX feat
         update_local_illumination(player_ptr, y, x);
     }
 
-    if (f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::REMEMBER)) {
         g_ptr->info &= ~(CAVE_MARK);
     }
 
@@ -243,11 +240,17 @@ void cave_set_feat(PlayerType *player_ptr, POSITION y, POSITION x, FEAT_IDX feat
 
     note_spot(player_ptr, y, x);
     lite_spot(player_ptr, y, x);
-    if (old_los ^ f_ptr->flags.has(TerrainCharacteristics::LOS)) {
-        player_ptr->update |= PU_VIEW | PU_LITE | PU_MONSTER_LITE | PU_MONSTER_STATUSES;
+    if (old_los ^ terrain.flags.has(TerrainCharacteristics::LOS)) {
+        static constexpr auto flags = {
+            StatusRecalculatingFlag::VIEW,
+            StatusRecalculatingFlag::LITE,
+            StatusRecalculatingFlag::MONSTER_LITE,
+            StatusRecalculatingFlag::MONSTER_STATUSES,
+        };
+        RedrawingFlagsUpdater::get_instance().set_flags(flags);
     }
 
-    if (f_ptr->flags.has_not(TerrainCharacteristics::GLOW) || dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::GLOW) || dungeon.flags.has(DungeonFeatureType::DARKNESS)) {
         return;
     }
 
@@ -277,18 +280,19 @@ void cave_set_feat(PlayerType *player_ptr, POSITION y, POSITION x, FEAT_IDX feat
     }
 }
 
-FEAT_IDX conv_dungeon_feat(FloorType *floor_ptr, FEAT_IDX newfeat)
+FEAT_IDX conv_dungeon_feat(const FloorType *floor_ptr, FEAT_IDX newfeat)
 {
-    auto *f_ptr = &terrains_info[newfeat];
-    if (f_ptr->flags.has_not(TerrainCharacteristics::CONVERT)) {
+    const auto &terrain = TerrainList::get_instance()[newfeat];
+    if (terrain.flags.has_not(TerrainCharacteristics::CONVERT)) {
         return newfeat;
     }
 
-    switch (f_ptr->subtype) {
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    switch (terrain.subtype) {
     case CONVERT_TYPE_FLOOR:
-        return feat_ground_type[randint0(100)];
+        return rand_choice(feat_ground_type);
     case CONVERT_TYPE_WALL:
-        return feat_wall_type[randint0(100)];
+        return rand_choice(feat_wall_type);
     case CONVERT_TYPE_INNER:
         return feat_wall_inner;
     case CONVERT_TYPE_OUTER:
@@ -296,9 +300,9 @@ FEAT_IDX conv_dungeon_feat(FloorType *floor_ptr, FEAT_IDX newfeat)
     case CONVERT_TYPE_SOLID:
         return feat_wall_solid;
     case CONVERT_TYPE_STREAM1:
-        return dungeons_info[floor_ptr->dungeon_idx].stream1;
+        return dungeon.stream1;
     case CONVERT_TYPE_STREAM2:
-        return dungeons_info[floor_ptr->dungeon_idx].stream2;
+        return dungeon.stream2;
     default:
         return newfeat;
     }
index 9b7d531..d2140ea 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
@@ -71,13 +71,11 @@ extern FEAT_IDX feat_wall_type[100];
 
 class FloorType;
 class PlayerType;
-class TerrainType;
 bool is_closed_door(PlayerType *player_ptr, FEAT_IDX feat);
 bool is_trap(PlayerType *player_ptr, FEAT_IDX feat);
 void apply_default_feat_lighting(TERM_COLOR *f_attr, char *f_char);
 bool is_ascii_graphics(char x);
-bool permanent_wall(TerrainType *f_ptr);
 FEAT_IDX feat_locked_door_random(int door_type);
 FEAT_IDX feat_jammed_door_random(int door_type);
 void cave_set_feat(PlayerType *player_ptr, POSITION y, POSITION x, FEAT_IDX feat);
-FEAT_IDX conv_dungeon_feat(FloorType *floor_ptr, FEAT_IDX newfeat);
+FEAT_IDX conv_dungeon_feat(const FloorType *floor_ptr, FEAT_IDX newfeat);
index cda3c6b..e863b8f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief グリッドの実装 / low level dungeon routines -BEN-
  * @date 2013/12/30
  * @author
@@ -52,6 +52,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "term/gameterm.h"
 #include "term/term-color-types.h"
  */
 bool new_player_spot(PlayerType *player_ptr)
 {
-    POSITION y = 0, x = 0;
-    int max_attempts = 10000;
-
-    grid_type *g_ptr;
-    TerrainType *f_ptr;
-
-    auto *floor_ptr = player_ptr->current_floor_ptr;
+    auto max_attempts = 10000;
+    auto y = 0;
+    auto x = 0;
+    auto &floor = *player_ptr->current_floor_ptr;
     while (max_attempts--) {
         /* Pick a legal spot */
-        y = (POSITION)rand_range(1, floor_ptr->height - 2);
-        x = (POSITION)rand_range(1, floor_ptr->width - 2);
+        y = (POSITION)rand_range(1, floor.height - 2);
+        x = (POSITION)rand_range(1, floor.width - 2);
 
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+        const auto &grid = player_ptr->current_floor_ptr->get_grid({ y, x });
 
         /* Must be a "naked" floor grid */
-        if (g_ptr->m_idx) {
+        if (grid.m_idx) {
             continue;
         }
-        if (floor_ptr->is_in_dungeon()) {
-            f_ptr = &terrains_info[g_ptr->feat];
+        if (floor.is_in_dungeon()) {
+            const auto &terrain = grid.get_terrain();
 
             if (max_attempts > 5000) /* Rule 1 */
             {
-                if (f_ptr->flags.has_not(TerrainCharacteristics::FLOOR)) {
+                if (terrain.flags.has_not(TerrainCharacteristics::FLOOR)) {
                     continue;
                 }
             } else /* Rule 2 */
             {
-                if (f_ptr->flags.has_not(TerrainCharacteristics::MOVE)) {
+                if (terrain.flags.has_not(TerrainCharacteristics::MOVE)) {
                     continue;
                 }
-                if (f_ptr->flags.has(TerrainCharacteristics::HIT_TRAP)) {
+                if (terrain.flags.has(TerrainCharacteristics::HIT_TRAP)) {
                     continue;
                 }
             }
 
             /* Refuse to start on anti-teleport grids in dungeon */
-            if (f_ptr->flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
+            if (terrain.flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
                 continue;
             }
         }
-        if (!player_can_enter(player_ptr, g_ptr->feat, 0)) {
+        if (!player_can_enter(player_ptr, grid.feat, 0)) {
             continue;
         }
-        if (!in_bounds(floor_ptr, y, x)) {
+        if (!in_bounds(&floor, y, x)) {
             continue;
         }
 
         /* Refuse to start on anti-teleport grids */
-        if (g_ptr->is_icky()) {
+        if (grid.is_icky()) {
             continue;
         }
 
@@ -143,16 +141,12 @@ bool new_player_spot(PlayerType *player_ptr)
 /*!
  * @brief マスに隠されたドアがあるかの判定を行う。 / Return TRUE if the given grid is a hidden closed door
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param g_ptr マス構造体の参照ポインタ
+ * @param grid マス構造体の参照ポインタ
  * @return 隠されたドアがあるならTRUEを返す。
  */
-bool is_hidden_door(PlayerType *player_ptr, grid_type *g_ptr)
+bool is_hidden_door(PlayerType *player_ptr, const Grid &grid)
 {
-    if ((g_ptr->mimic || g_ptr->cave_has_flag(TerrainCharacteristics::SECRET)) && is_closed_door(player_ptr, g_ptr->feat)) {
-        return true;
-    } else {
-        return false;
-    }
+    return (grid.mimic || grid.cave_has_flag(TerrainCharacteristics::SECRET)) && is_closed_door(player_ptr, grid.feat);
 }
 
 /*!
@@ -163,21 +157,18 @@ bool is_hidden_door(PlayerType *player_ptr, grid_type *g_ptr)
  */
 bool check_local_illumination(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    /* Hack -- move towards player */
-    POSITION yy = (y < player_ptr->y) ? (y + 1) : (y > player_ptr->y) ? (y - 1)
-                                                                      : y;
-    POSITION xx = (x < player_ptr->x) ? (x + 1) : (x > player_ptr->x) ? (x - 1)
-                                                                      : x;
-
-    /* Check for "local" illumination */
-
-    /* Check for "complex" illumination */
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((feat_supports_los(floor_ptr->grid_array[yy][xx].get_feat_mimic()) && (floor_ptr->grid_array[yy][xx].info & CAVE_GLOW)) || (feat_supports_los(floor_ptr->grid_array[y][xx].get_feat_mimic()) && (floor_ptr->grid_array[y][xx].info & CAVE_GLOW)) || (feat_supports_los(floor_ptr->grid_array[yy][x].get_feat_mimic()) && (floor_ptr->grid_array[yy][x].info & CAVE_GLOW))) {
-        return true;
-    } else {
-        return false;
-    }
+    const auto yy = (y < player_ptr->y) ? (y + 1) : (y > player_ptr->y) ? (y - 1)
+                                                                        : y;
+    const auto xx = (x < player_ptr->x) ? (x + 1) : (x > player_ptr->x) ? (x - 1)
+                                                                        : x;
+    const auto *floor_ptr = player_ptr->current_floor_ptr;
+    const auto &grid_yyxx = floor_ptr->grid_array[yy][xx];
+    const auto &grid_yxx = floor_ptr->grid_array[y][xx];
+    const auto &grid_yyx = floor_ptr->grid_array[yy][x];
+    auto is_illuminated = feat_supports_los(grid_yyxx.get_feat_mimic()) && (grid_yyxx.info & CAVE_GLOW);
+    is_illuminated |= feat_supports_los(grid_yxx.get_feat_mimic()) && (grid_yxx.info & CAVE_GLOW);
+    is_illuminated |= feat_supports_los(grid_yyx.get_feat_mimic()) && (grid_yyx.info & CAVE_GLOW);
+    return is_illuminated;
 }
 
 /*!
@@ -188,11 +179,13 @@ bool check_local_illumination(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 static void update_local_illumination_aux(PlayerType *player_ptr, int y, int x)
 {
-    if (!player_has_los_bold(player_ptr, y, x)) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(y, x);
+    const auto &grid = floor.get_grid(pos);
+    if (!grid.has_los()) {
         return;
     }
 
-    const auto &grid = player_ptr->current_floor_ptr->grid_array[y][x];
     if (grid.m_idx > 0) {
         update_monster(player_ptr, grid.m_idx, false);
     }
@@ -289,7 +282,7 @@ void print_rel(PlayerType *player_ptr, char c, TERM_COLOR a, POSITION y, POSITIO
 
 void print_bolt_pict(PlayerType *player_ptr, POSITION y, POSITION x, POSITION ny, POSITION nx, AttributeType typ)
 {
-    const auto [a, c] = bolt_pict(y, x, ny, nx, typ);
+    const auto &[a, c] = bolt_pict(y, x, ny, nx, typ);
     print_rel(player_ptr, c, a, ny, nx);
 }
 
@@ -334,7 +327,9 @@ void print_bolt_pict(PlayerType *player_ptr, POSITION y, POSITION x, POSITION ny
  */
 void note_spot(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+    const Pos2D pos(y, x);
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &grid = floor.get_grid(pos);
 
     /* Blind players see nothing */
     if (player_ptr->effects()->blindness()->is_blind()) {
@@ -342,14 +337,14 @@ void note_spot(PlayerType *player_ptr, POSITION y, POSITION x)
     }
 
     /* Analyze non-torch-lit grids */
-    if (!(g_ptr->info & (CAVE_LITE | CAVE_MNLT))) {
+    if (!(grid.info & (CAVE_LITE | CAVE_MNLT))) {
         /* Require line of sight to the grid */
-        if (!(g_ptr->info & (CAVE_VIEW))) {
+        if (!(grid.info & (CAVE_VIEW))) {
             return;
         }
 
         /* Require "perma-lite" of the grid */
-        if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
+        if ((grid.info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
             /* Not Ninja */
             if (!player_ptr->see_nocto) {
                 return;
@@ -358,55 +353,53 @@ void note_spot(PlayerType *player_ptr, POSITION y, POSITION x)
     }
 
     /* Hack -- memorize objects */
-    for (const auto this_o_idx : g_ptr->o_idx_list) {
-        auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
-
-        /* Memorize objects */
-        o_ptr->marked.set(OmType::FOUND);
-        player_ptr->window_flags |= PW_FOUND_ITEMS;
+    for (const auto this_o_idx : grid.o_idx_list) {
+        auto &item = floor.o_list[this_o_idx];
+        item.marked.set(OmType::FOUND);
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::FOUND_ITEMS);
     }
 
     /* Hack -- memorize grids */
-    if (!g_ptr->is_mark()) {
+    if (!grid.is_mark()) {
         /* Feature code (applying "mimic" field) */
-        auto *f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
+        const auto &terrain = grid.get_terrain_mimic();
 
         /* Memorize some "boring" grids */
-        if (f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
+        if (terrain.flags.has_not(TerrainCharacteristics::REMEMBER)) {
             /* Option -- memorize all torch-lit floors */
-            if (view_torch_grids && ((g_ptr->info & (CAVE_LITE | CAVE_MNLT)) || player_ptr->see_nocto)) {
-                g_ptr->info |= (CAVE_MARK);
+            if (view_torch_grids && ((grid.info & (CAVE_LITE | CAVE_MNLT)) || player_ptr->see_nocto)) {
+                grid.info |= (CAVE_MARK);
             }
 
             /* Option -- memorize all perma-lit floors */
-            else if (view_perma_grids && ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW)) {
-                g_ptr->info |= (CAVE_MARK);
+            else if (view_perma_grids && ((grid.info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW)) {
+                grid.info |= (CAVE_MARK);
             }
         }
 
         /* Memorize normal grids */
-        else if (f_ptr->flags.has(TerrainCharacteristics::LOS)) {
-            g_ptr->info |= (CAVE_MARK);
+        else if (terrain.flags.has(TerrainCharacteristics::LOS)) {
+            grid.info |= (CAVE_MARK);
         }
 
         /* Memorize torch-lit walls */
-        else if (g_ptr->info & (CAVE_LITE | CAVE_MNLT)) {
-            g_ptr->info |= (CAVE_MARK);
+        else if (grid.info & (CAVE_LITE | CAVE_MNLT)) {
+            grid.info |= (CAVE_MARK);
         }
 
         /* Memorize walls seen by noctovision of Ninja */
         else if (player_ptr->see_nocto) {
-            g_ptr->info |= (CAVE_MARK);
+            grid.info |= (CAVE_MARK);
         }
 
         /* Memorize certain non-torch-lit wall grids */
         else if (check_local_illumination(player_ptr, y, x)) {
-            g_ptr->info |= (CAVE_MARK);
+            grid.info |= (CAVE_MARK);
         }
     }
 
     /* Memorize terrain of the grid */
-    g_ptr->info |= (CAVE_KNOWN);
+    grid.info |= (CAVE_KNOWN);
 }
 
 /*
@@ -416,7 +409,6 @@ void note_spot(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 void lite_spot(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    /* Redraw if on screen */
     if (panel_contains(y, x) && in_bounds2(player_ptr->current_floor_ptr, y, x)) {
         TERM_COLOR a;
         char c;
@@ -424,8 +416,6 @@ void lite_spot(PlayerType *player_ptr, POSITION y, POSITION x)
         char tc;
 
         map_info(player_ptr, y, x, &a, &c, &ta, &tc);
-
-        /* Hack -- fake monochrome */
         if (!use_graphics) {
             if (w_ptr->timewalk_m_idx) {
                 a = TERM_DARK;
@@ -436,11 +426,12 @@ void lite_spot(PlayerType *player_ptr, POSITION y, POSITION x)
             }
         }
 
-        /* Hack -- Queue it */
         term_queue_bigchar(panel_col_of(x), y - panel_row_prt, a, c, ta, tc);
-
-        /* Update sub-windows */
-        player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::OVERHEAD,
+            SubWindowRedrawingFlag::DUNGEON,
+        };
+        RedrawingFlagsUpdater::get_instance().set_flags(flags);
     }
 }
 
@@ -673,23 +664,22 @@ static POSITION flow_y = 0;
  */
 void update_flow(PlayerType *player_ptr)
 {
-    POSITION x, y;
-    DIRECTION d;
-    FloorType *f_ptr = player_ptr->current_floor_ptr;
+    auto &floor = *player_ptr->current_floor_ptr;
 
     /* The last way-point is on the map */
-    if (player_ptr->running && in_bounds(f_ptr, flow_y, flow_x)) {
+    if (player_ptr->running && in_bounds(&floor, flow_y, flow_x)) {
         /* The way point is in sight - do not update.  (Speedup) */
-        if (f_ptr->grid_array[flow_y][flow_x].info & CAVE_VIEW) {
+        if (floor.grid_array[flow_y][flow_x].info & CAVE_VIEW) {
             return;
         }
     }
 
     /* Erase all of the current flow information */
-    for (y = 0; y < f_ptr->height; y++) {
-        for (x = 0; x < f_ptr->width; x++) {
-            memset(&f_ptr->grid_array[y][x].costs, 0, sizeof(f_ptr->grid_array[y][x].costs));
-            memset(&f_ptr->grid_array[y][x].dists, 0, sizeof(f_ptr->grid_array[y][x].dists));
+    for (auto y = 0; y < floor.height; y++) {
+        for (auto x = 0; x < floor.width; x++) {
+            auto &grid = floor.grid_array[y][x];
+            grid.reset_costs();
+            grid.reset_dists();
         }
     }
 
@@ -697,63 +687,59 @@ void update_flow(PlayerType *player_ptr)
     flow_y = player_ptr->y;
     flow_x = player_ptr->x;
 
-    for (int i = 0; i < FLOW_MAX; i++) {
+    for (auto i = 0; i < FLOW_MAX; i++) {
         // 幅優先探索用のキュー。
         std::queue<Pos2D> que;
         que.emplace(player_ptr->y, player_ptr->x);
 
         /* Now process the queue */
         while (!que.empty()) {
-            /* Extract the next entry */
-            const auto [ty, tx] = que.front();
+            const Pos2D pos = std::move(que.front());
             que.pop();
+            const auto &grid = floor.get_grid(pos);
 
             /* Add the "children" */
-            for (d = 0; d < 8; d++) {
-                byte m = player_ptr->current_floor_ptr->grid_array[ty][tx].costs[i] + 1;
-                byte n = player_ptr->current_floor_ptr->grid_array[ty][tx].dists[i] + 1;
-
-                /* Child location */
-                y = ty + ddy_ddd[d];
-                x = tx + ddx_ddd[d];
+            for (auto d = 0; d < 8; d++) {
+                byte m = grid.costs[i] + 1;
+                byte n = grid.dists[i] + 1;
+                const Pos2D pos_neighbor(pos.y + ddy_ddd[d], pos.x + ddx_ddd[d]);
 
                 /* Ignore player's grid */
-                if (player_bold(player_ptr, y, x)) {
+                if (player_ptr->is_located_at(pos_neighbor)) {
                     continue;
                 }
 
-                auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-
-                if (is_closed_door(player_ptr, g_ptr->feat)) {
+                auto &grid_neighbor = floor.get_grid(pos_neighbor);
+                if (is_closed_door(player_ptr, grid_neighbor.feat)) {
                     m += 3;
                 }
 
                 /* Ignore "pre-stamped" entries */
-                if (g_ptr->dists[i] != 0 && g_ptr->dists[i] <= n && g_ptr->costs[i] <= m) {
+                if ((grid_neighbor.dists[i] != 0) && (grid_neighbor.dists[i] <= n) && (grid_neighbor.costs[i] <= m)) {
                     continue;
                 }
 
                 /* Ignore "walls", "holes" and "rubble" */
-                bool can_move = false;
+                auto can_move = false;
                 switch (i) {
                 case FLOW_CAN_FLY:
-                    can_move = g_ptr->cave_has_flag(TerrainCharacteristics::MOVE) || g_ptr->cave_has_flag(TerrainCharacteristics::CAN_FLY);
+                    can_move = grid_neighbor.cave_has_flag(TerrainCharacteristics::MOVE) || grid_neighbor.cave_has_flag(TerrainCharacteristics::CAN_FLY);
                     break;
                 default:
-                    can_move = g_ptr->cave_has_flag(TerrainCharacteristics::MOVE);
+                    can_move = grid_neighbor.cave_has_flag(TerrainCharacteristics::MOVE);
                     break;
                 }
 
-                if (!can_move && !is_closed_door(player_ptr, g_ptr->feat)) {
+                if (!can_move && !is_closed_door(player_ptr, grid_neighbor.feat)) {
                     continue;
                 }
 
                 /* Save the flow cost */
-                if (g_ptr->costs[i] == 0 || g_ptr->costs[i] > m) {
-                    g_ptr->costs[i] = m;
+                if (grid_neighbor.costs[i] == 0 || (grid_neighbor.costs[i] > m)) {
+                    grid_neighbor.costs[i] = m;
                 }
-                if (g_ptr->dists[i] == 0 || g_ptr->dists[i] > n) {
-                    g_ptr->dists[i] = n;
+                if (grid_neighbor.dists[i] == 0 || (grid_neighbor.dists[i] > n)) {
+                    grid_neighbor.dists[i] = n;
                 }
 
                 // 敵のプレイヤーに対する移動道のりの最大値(この値以上は処理を打ち切る).
@@ -762,8 +748,7 @@ void update_flow(PlayerType *player_ptr)
                     continue;
                 }
 
-                /* Enqueue that entry */
-                que.emplace(y, x);
+                que.emplace(pos_neighbor);
             }
         }
     }
@@ -773,23 +758,22 @@ void update_flow(PlayerType *player_ptr)
  * Take a feature, determine what that feature becomes
  * through applying the given action.
  */
-FEAT_IDX feat_state(FloorType *floor_ptr, FEAT_IDX feat, TerrainCharacteristics action)
+FEAT_IDX feat_state(const FloorType *floor_ptr, FEAT_IDX feat, TerrainCharacteristics action)
 {
-    auto *f_ptr = &terrains_info[feat];
-    int i;
+    const auto &terrain = TerrainList::get_instance()[feat];
 
     /* Get the new feature */
-    for (i = 0; i < MAX_FEAT_STATES; i++) {
-        if (f_ptr->state[i].action == action) {
-            return conv_dungeon_feat(floor_ptr, f_ptr->state[i].result);
+    for (auto i = 0; i < MAX_FEAT_STATES; i++) {
+        if (terrain.state[i].action == action) {
+            return conv_dungeon_feat(floor_ptr, terrain.state[i].result);
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
+    if (terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
         return feat;
     }
 
-    return (terrain_action_flags[enum2i(action)] & FAF_DESTROY) ? conv_dungeon_feat(floor_ptr, f_ptr->destroyed) : feat;
+    return (terrain_action_flags[enum2i(action)] & FAF_DESTROY) ? conv_dungeon_feat(floor_ptr, terrain.destroyed) : feat;
 }
 
 /*
@@ -812,21 +796,21 @@ void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, TerrainChar
 
     /* Set the new feature */
     cave_set_feat(player_ptr, y, x, newfeat);
-
+    const auto &terrains = TerrainList::get_instance();
     if (!(terrain_action_flags[enum2i(action)] & FAF_NO_DROP)) {
-        TerrainType *old_f_ptr = &terrains_info[oldfeat];
-        auto *f_ptr = &terrains_info[newfeat];
+        const auto &old_terrain = terrains[oldfeat];
+        const auto &new_terrain = terrains[newfeat];
         bool found = false;
 
         /* Handle gold */
-        if (old_f_ptr->flags.has(TerrainCharacteristics::HAS_GOLD) && f_ptr->flags.has_not(TerrainCharacteristics::HAS_GOLD)) {
+        if (old_terrain.flags.has(TerrainCharacteristics::HAS_GOLD) && new_terrain.flags.has_not(TerrainCharacteristics::HAS_GOLD)) {
             /* Place some gold */
             place_gold(player_ptr, y, x);
             found = true;
         }
 
         /* Handle item */
-        if (old_f_ptr->flags.has(TerrainCharacteristics::HAS_ITEM) && f_ptr->flags.has_not(TerrainCharacteristics::HAS_ITEM) && (randint0(100) < (15 - floor_ptr->dun_level / 2))) {
+        if (old_terrain.flags.has(TerrainCharacteristics::HAS_ITEM) && new_terrain.flags.has_not(TerrainCharacteristics::HAS_ITEM) && (randint0(100) < (15 - floor_ptr->dun_level / 2))) {
             /* Place object */
             place_object(player_ptr, y, x, 0L);
             found = true;
@@ -838,9 +822,8 @@ void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, TerrainChar
     }
 
     if (terrain_action_flags[enum2i(action)] & FAF_CRASH_GLASS) {
-        TerrainType *old_f_ptr = &terrains_info[oldfeat];
-
-        if (old_f_ptr->flags.has(TerrainCharacteristics::GLASS) && w_ptr->character_dungeon) {
+        const auto &old_terrain = terrains[oldfeat];
+        if (old_terrain.flags.has(TerrainCharacteristics::GLASS) && w_ptr->character_dungeon) {
             project(player_ptr, PROJECT_WHO_GLASS_SHARDS, 1, y, x, std::min(floor_ptr->dun_level, 100) / 4, AttributeType::SHARDS,
                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_HIDE | PROJECT_JUMP | PROJECT_NO_HANGEKI));
         }
@@ -858,37 +841,37 @@ void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, TerrainChar
  */
 bool cave_monster_teleportable_bold(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, teleport_flags mode)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    const Pos2D pos(y, x);
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.get_grid(pos);
+    const auto &terrain = grid.get_terrain();
 
     /* Require "teleportable" space */
-    if (f_ptr->flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
         return false;
     }
 
-    if (g_ptr->m_idx && (g_ptr->m_idx != m_idx)) {
+    if (grid.m_idx && (grid.m_idx != m_idx)) {
         return false;
     }
-    if (player_bold(player_ptr, y, x)) {
+    if (player_ptr->is_located_at(pos)) {
         return false;
     }
 
     /* Hack -- no teleport onto rune of protection */
-    if (g_ptr->is_rune_protection()) {
+    if (grid.is_rune_protection()) {
         return false;
     }
-    if (g_ptr->is_rune_explosion()) {
+    if (grid.is_rune_explosion()) {
         return false;
     }
 
-    if (!(mode & TELEPORT_PASSIVE)) {
-        if (!monster_can_cross_terrain(player_ptr, g_ptr->feat, &monraces_info[m_ptr->r_idx], 0)) {
-            return false;
-        }
+    if (any_bits(mode, TELEPORT_PASSIVE)) {
+        return true;
     }
 
-    return true;
+    const auto &monster = floor.m_list[m_idx];
+    return monster_can_cross_terrain(player_ptr, grid.feat, &monster.get_monrace(), 0);
 }
 
 /*!
@@ -901,53 +884,54 @@ bool cave_monster_teleportable_bold(PlayerType *player_ptr, MONSTER_IDX m_idx, P
  */
 bool cave_player_teleportable_bold(PlayerType *player_ptr, POSITION y, POSITION x, teleport_flags mode)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
 
     /* Require "teleportable" space */
-    if (f_ptr->flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
         return false;
     }
 
     /* No magical teleporting into vaults and such */
-    if (!(mode & TELEPORT_NONMAGICAL) && g_ptr->is_icky()) {
+    if (!(mode & TELEPORT_NONMAGICAL) && grid.is_icky()) {
         return false;
     }
 
-    if (g_ptr->m_idx && (g_ptr->m_idx != player_ptr->riding)) {
+    if (grid.m_idx && (grid.m_idx != player_ptr->riding)) {
         return false;
     }
 
     /* don't teleport on a trap. */
-    if (f_ptr->flags.has(TerrainCharacteristics::HIT_TRAP)) {
+    if (terrain.flags.has(TerrainCharacteristics::HIT_TRAP)) {
         return false;
     }
 
-    if (!(mode & TELEPORT_PASSIVE)) {
-        if (!player_can_enter(player_ptr, g_ptr->feat, 0)) {
-            return false;
-        }
+    if (any_bits(mode, TELEPORT_PASSIVE)) {
+        return true;
+    }
 
-        if (f_ptr->flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP })) {
-            if (!player_ptr->levitation && !player_ptr->can_swim) {
-                return false;
-            }
+    if (!player_can_enter(player_ptr, grid.feat, 0)) {
+        return false;
+    }
+
+    if (terrain.flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP })) {
+        if (!player_ptr->levitation && !player_ptr->can_swim) {
+            return false;
         }
+    }
 
-        if (f_ptr->flags.has(TerrainCharacteristics::LAVA) && !has_immune_fire(player_ptr) && !is_invuln(player_ptr)) {
-            /* Always forbid deep lava */
-            if (f_ptr->flags.has(TerrainCharacteristics::DEEP)) {
-                return false;
-            }
+    if (terrain.flags.has_not(TerrainCharacteristics::LAVA) || has_immune_fire(player_ptr) || is_invuln(player_ptr)) {
+        return true;
+    }
 
-            /* Forbid shallow lava when the player don't have levitation */
-            if (!player_ptr->levitation) {
-                return false;
-            }
-        }
+    /* Always forbid deep lava */
+    if (terrain.flags.has(TerrainCharacteristics::DEEP)) {
+        return false;
     }
 
-    return true;
+    /* Forbid shallow lava when the player don't have levitation */
+    return player_ptr->levitation != 0;
 }
 
 /*!
@@ -958,7 +942,8 @@ bool cave_player_teleportable_bold(PlayerType *player_ptr, POSITION y, POSITION
  */
 bool is_open(PlayerType *player_ptr, FEAT_IDX feat)
 {
-    return terrains_info[feat].flags.has(TerrainCharacteristics::CLOSE) && (feat != feat_state(player_ptr->current_floor_ptr, feat, TerrainCharacteristics::CLOSE));
+    const auto &terrain = TerrainList::get_instance()[feat];
+    return terrain.flags.has(TerrainCharacteristics::CLOSE) && (feat != feat_state(player_ptr->current_floor_ptr, feat, TerrainCharacteristics::CLOSE));
 }
 
 /*!
@@ -969,47 +954,46 @@ bool is_open(PlayerType *player_ptr, FEAT_IDX feat)
  */
 bool player_can_enter(PlayerType *player_ptr, FEAT_IDX feature, BIT_FLAGS16 mode)
 {
-    auto *f_ptr = &terrains_info[feature];
-
+    const auto &terrain = TerrainList::get_instance()[feature];
     if (player_ptr->riding) {
         return monster_can_cross_terrain(
             player_ptr, feature, &monraces_info[player_ptr->current_floor_ptr->m_list[player_ptr->riding].r_idx], mode | CEM_RIDING);
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::PATTERN)) {
+    if (terrain.flags.has(TerrainCharacteristics::PATTERN)) {
         if (!(mode & CEM_P_CAN_ENTER_PATTERN)) {
             return false;
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::CAN_FLY) && player_ptr->levitation) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_FLY) && player_ptr->levitation) {
         return true;
     }
-    if (f_ptr->flags.has(TerrainCharacteristics::CAN_SWIM) && player_ptr->can_swim) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_SWIM) && player_ptr->can_swim) {
         return true;
     }
-    if (f_ptr->flags.has(TerrainCharacteristics::CAN_PASS) && has_pass_wall(player_ptr)) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_PASS) && has_pass_wall(player_ptr)) {
         return true;
     }
 
-    if (f_ptr->flags.has_not(TerrainCharacteristics::MOVE)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::MOVE)) {
         return false;
     }
 
     return true;
 }
 
-void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type)
+void place_grid(PlayerType *player_ptr, Grid *g_ptr, grid_bold_type gb_type)
 {
     switch (gb_type) {
     case GB_FLOOR: {
-        g_ptr->feat = feat_ground_type[randint0(100)];
+        g_ptr->feat = rand_choice(feat_ground_type);
         g_ptr->info &= ~(CAVE_MASK);
         g_ptr->info |= CAVE_FLOOR;
         break;
     }
     case GB_EXTRA: {
-        g_ptr->feat = feat_wall_type[randint0(100)];
+        g_ptr->feat = rand_choice(feat_wall_type);
         g_ptr->info &= ~(CAVE_MASK);
         g_ptr->info |= CAVE_EXTRA;
         break;
@@ -1039,8 +1023,8 @@ void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type
         break;
     }
     case GB_OUTER_NOPERM: {
-        auto *f_ptr = &terrains_info[feat_wall_outer];
-        if (permanent_wall(f_ptr)) {
+        const auto &terrain = TerrainList::get_instance()[feat_wall_outer];
+        if (terrain.is_permanent_wall()) {
             g_ptr->feat = (int16_t)feat_state(player_ptr->current_floor_ptr, feat_wall_outer, TerrainCharacteristics::UNPERM);
         } else {
             g_ptr->feat = feat_wall_outer;
@@ -1063,8 +1047,8 @@ void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type
         break;
     }
     case GB_SOLID_NOPERM: {
-        auto *f_ptr = &terrains_info[feat_wall_solid];
-        if ((g_ptr->info & CAVE_VAULT) && permanent_wall(f_ptr)) {
+        const auto &terrain = TerrainList::get_instance()[feat_wall_solid];
+        if ((g_ptr->info & CAVE_VAULT) && terrain.is_permanent_wall()) {
             g_ptr->feat = (int16_t)feat_state(player_ptr->current_floor_ptr, feat_wall_solid, TerrainCharacteristics::UNPERM);
         } else {
             g_ptr->feat = feat_wall_solid;
@@ -1086,17 +1070,17 @@ void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type
 /*!
  * モンスターにより照明が消されている地形か否かを判定する。 / Is this grid "darkened" by monster?
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param g_ptr グリッドへの参照ポインタ
+ * @param grid グリッドへの参照ポインタ
  * @return 照明が消されている地形ならばTRUE
  */
-bool darkened_grid(PlayerType *player_ptr, grid_type *g_ptr)
+bool darkened_grid(PlayerType *player_ptr, Grid *g_ptr)
 {
     return ((g_ptr->info & (CAVE_VIEW | CAVE_LITE | CAVE_MNLT | CAVE_MNDK)) == (CAVE_VIEW | CAVE_MNDK)) && !player_ptr->see_nocto;
 }
 
 void place_bold(PlayerType *player_ptr, POSITION y, POSITION x, grid_bold_type gb_type)
 {
-    grid_type *const g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+    Grid *const g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
     place_grid(player_ptr, g_ptr, gb_type);
 }
 
@@ -1106,44 +1090,37 @@ void set_cave_feat(FloorType *floor_ptr, POSITION y, POSITION x, FEAT_IDX featur
 }
 
 /*!
- * @brief プレイヤーの周辺9マスに該当する地形がいくつあるかを返す /
- * Attempt to open the given chest at the given location
- * @param y 該当する地形の中から1つのY座標を返す参照ポインタ
- * @param x 該当する地形の中から1つのX座標を返す参照ポインタ
+ * @brief プレイヤーの周辺9マスに該当する地形がいくつあるかを返す
+ * @param player_ptr プレイヤーへの参照ポインタ
  * @param test 地形条件を判定するための関数ポインタ
  * @param under TRUEならばプレイヤーの直下の座標も走査対象にする
- * @return 該当する地形の数
- * @details Return the number of features around (or under) the character.
- * Usually look for doors and floor traps.
+ * @return 該当する地形の数と、該当する地形の中から1つの座標
  */
-int count_dt(PlayerType *player_ptr, POSITION *y, POSITION *x, bool (*test)(PlayerType *, FEAT_IDX), bool under)
+std::pair<int, Pos2D> count_dt(PlayerType *player_ptr, bool (*test)(PlayerType *, short), bool under)
 {
-    int count = 0;
-    for (DIRECTION d = 0; d < 9; d++) {
-        grid_type *g_ptr;
-        FEAT_IDX feat;
+    auto count = 0;
+    Pos2D pos(0, 0);
+    for (auto d = 0; d < 9; d++) {
         if ((d == 8) && !under) {
             continue;
         }
 
-        POSITION yy = player_ptr->y + ddy_ddd[d];
-        POSITION xx = player_ptr->x + ddx_ddd[d];
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[yy][xx];
-        if (!g_ptr->is_mark()) {
+        Pos2D pos_neighbor(player_ptr->y + ddy_ddd[d], player_ptr->x + ddx_ddd[d]);
+        const auto &grid = player_ptr->current_floor_ptr->get_grid(pos_neighbor);
+        if (!grid.is_mark()) {
             continue;
         }
 
-        feat = g_ptr->get_feat_mimic();
+        const auto feat = grid.get_feat_mimic();
         if (!((*test)(player_ptr, feat))) {
             continue;
         }
 
         ++count;
-        *y = yy;
-        *x = xx;
+        pos = pos_neighbor;
     }
 
-    return count;
+    return { count, pos };
 }
 
 /*!
@@ -1151,7 +1128,7 @@ int count_dt(PlayerType *player_ptr, POSITION *y, POSITION *x, bool (*test)(Play
  */
 bool feat_uses_special(FEAT_IDX f_idx)
 {
-    return terrains_info[(f_idx)].flags.has(TerrainCharacteristics::SPECIAL);
+    return TerrainList::get_instance()[(f_idx)].flags.has(TerrainCharacteristics::SPECIAL);
 }
 
 /*
index e7394d0..e9ea2a4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @file grid.h
@@ -17,6 +17,8 @@
 #include "object/object-index-list.h"
 #include "spell/spells-util.h"
 #include "system/angband.h"
+#include "util/point-2d.h"
+#include <utility>
 
 enum class AttributeType;
 
@@ -43,12 +45,12 @@ enum grid_bold_type {
 };
 
 class FloorType;
-struct grid_type;
+class Grid;
 class PlayerType;
 class MonsterRaceInfo;
 enum class TerrainCharacteristics;
 bool new_player_spot(PlayerType *player_ptr);
-bool is_hidden_door(PlayerType *player_ptr, grid_type *g_ptr);
+bool is_hidden_door(PlayerType *player_ptr, const Grid &grid);
 bool player_can_enter(PlayerType *player_ptr, FEAT_IDX feature, BIT_FLAGS16 mode);
 bool feat_uses_special(FEAT_IDX f_idx);
 void update_local_illumination(PlayerType *player_ptr, POSITION y, POSITION x);
@@ -58,18 +60,18 @@ void print_bolt_pict(PlayerType *player_ptr, POSITION y, POSITION x, POSITION ny
 void note_spot(PlayerType *player_ptr, POSITION y, POSITION x);
 void lite_spot(PlayerType *player_ptr, POSITION y, POSITION x);
 void update_flow(PlayerType *player_ptr);
-FEAT_IDX feat_state(FloorType *floor_ptr, FEAT_IDX feat, TerrainCharacteristics action);
+FEAT_IDX feat_state(const FloorType *floor_ptr, FEAT_IDX feat, TerrainCharacteristics action);
 void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, TerrainCharacteristics action);
 bool is_open(PlayerType *player_ptr, FEAT_IDX feat);
 bool check_local_illumination(PlayerType *player_ptr, POSITION y, POSITION x);
 bool cave_monster_teleportable_bold(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, teleport_flags mode);
 bool cave_player_teleportable_bold(PlayerType *player_ptr, POSITION y, POSITION x, teleport_flags mode);
-void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type pg_type);
-bool darkened_grid(PlayerType *player_ptr, grid_type *g_ptr);
+void place_grid(PlayerType *player_ptr, Grid *g_ptr, grid_bold_type pg_type);
+bool darkened_grid(PlayerType *player_ptr, Grid *g_ptr);
 void delete_monster(PlayerType *player_ptr, POSITION y, POSITION x);
 void place_bold(PlayerType *player_ptr, POSITION y, POSITION x, grid_bold_type gh_type);
 void set_cave_feat(FloorType *floor_ptr, POSITION y, POSITION x, FEAT_IDX feature_idx);
-int count_dt(PlayerType *player_ptr, POSITION *y, POSITION *x, bool (*test)(PlayerType *, FEAT_IDX), bool under);
+std::pair<int, Pos2D> count_dt(PlayerType *player_ptr, bool (*test)(PlayerType *, short), bool under);
 void cave_lite_hack(FloorType *floor_ptr, POSITION y, POSITION x);
 void cave_redraw_later(FloorType *floor_ptr, POSITION y, POSITION x);
 void cave_note_and_redraw_later(FloorType *floor_ptr, POSITION y, POSITION x);
index 80b2d48..71aee4e 100644 (file)
@@ -1,4 +1,4 @@
-#include "grid/lighting-colors-table.h"
+#include "grid/lighting-colors-table.h"
 #include "term/term-color-types.h"
 
 /*!
index f1509b6..0274196 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 5b338ea..e1480c2 100644 (file)
@@ -1,4 +1,4 @@
-#include "grid/object-placer.h"
+#include "grid/object-placer.h"
 #include "floor/cave.h"
 #include "floor/floor-object.h"
 #include "grid/grid.h"
index 203675f..e3e29b8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index c07cd44..a669a9a 100644 (file)
@@ -1,4 +1,4 @@
-#include "grid/stair.h"
+#include "grid/stair.h"
 #include "dungeon/quest.h"
 #include "floor/cave.h"
 #include "game-option/birth-options.h"
@@ -21,14 +21,13 @@ void place_random_stairs(PlayerType *player_ptr, POSITION y, POSITION x)
 {
     bool up_stairs = true;
     bool down_stairs = true;
-    grid_type *g_ptr;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    g_ptr = &floor_ptr->grid_array[y][x];
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto *g_ptr = &floor.grid_array[y][x];
     if (!g_ptr->is_floor() || !g_ptr->o_idx_list.empty()) {
         return;
     }
 
-    if (!floor_ptr->dun_level) {
+    if (!floor.dun_level) {
         up_stairs = false;
     }
 
@@ -36,11 +35,11 @@ void place_random_stairs(PlayerType *player_ptr, POSITION y, POSITION x)
         up_stairs = false;
     }
 
-    if (floor_ptr->dun_level >= dungeons_info[player_ptr->dungeon_idx].maxdepth) {
+    if (floor.dun_level >= floor.get_dungeon_definition().maxdepth) {
         down_stairs = false;
     }
 
-    if (inside_quest(quest_number(player_ptr, floor_ptr->dun_level)) && (floor_ptr->dun_level > 1)) {
+    if (inside_quest(floor.get_quest_id()) && (floor.dun_level > 1)) {
         down_stairs = false;
     }
 
@@ -53,9 +52,9 @@ void place_random_stairs(PlayerType *player_ptr, POSITION y, POSITION x)
     }
 
     if (up_stairs) {
-        set_cave_feat(floor_ptr, y, x, feat_up_stair);
+        set_cave_feat(&floor, y, x, feat_up_stair);
     } else if (down_stairs) {
-        set_cave_feat(floor_ptr, y, x, feat_down_stair);
+        set_cave_feat(&floor, y, x, feat_down_stair);
     }
 }
 
index 3b567d8..00d76c5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b70b65a..6049a7f 100644 (file)
@@ -1,4 +1,4 @@
-#include "grid/trap.h"
+#include "grid/trap.h"
 #include "cmd-io/cmd-dump.h"
 #include "cmd-io/cmd-save.h"
 #include "core/disturbance.h"
@@ -153,43 +153,31 @@ void init_normal_traps(void)
 }
 
 /*!
- * @brief 基本トラップをランダムに選択する /
- * Get random trap
+ * @brief 基本トラップをランダムに選択する
+ * @param floor_ptr 現在フロアへの参照ポインタ
  * @return 選択したトラップのID
- * @details
- * This routine should be redone to reflect trap "level".\n
- * That is, it does not make sense to have spiked pits at 50 feet.\n
- * Actually, it is not this routine, but the "trap instantiation"\n
- * code, which should also check for "trap doors" on quest levels.\n
+ * @details トラップドアでないならばそのID.
+ * トラップドアは、アリーナ・クエスト・ダンジョンの最下層には設置しない.
  */
-FEAT_IDX choose_random_trap(PlayerType *player_ptr)
+short choose_random_trap(FloorType *floor_ptr)
 {
-    FEAT_IDX feat;
-
-    /* Pick a trap */
-    auto *floor_ptr = player_ptr->current_floor_ptr;
+    const auto &terrains = TerrainList::get_instance();
     while (true) {
-        feat = normal_traps[randint0(normal_traps.size())];
-
-        /* Accept non-trapdoors */
-        if (terrains_info[feat].flags.has_not(TerrainCharacteristics::MORE)) {
-            break;
+        const auto terrain_id = rand_choice(normal_traps);
+        if (terrains[terrain_id].flags.has_not(TerrainCharacteristics::MORE)) {
+            return terrain_id;
         }
 
-        /* Hack -- no trap doors on special levels */
-        if (floor_ptr->inside_arena || inside_quest(quest_number(player_ptr, floor_ptr->dun_level))) {
+        if (floor_ptr->inside_arena || inside_quest(floor_ptr->get_quest_id())) {
             continue;
         }
 
-        /* Hack -- no trap doors on the deepest level */
-        if (floor_ptr->dun_level >= dungeons_info[floor_ptr->dungeon_idx].maxdepth) {
+        if (floor_ptr->dun_level >= floor_ptr->get_dungeon_definition().maxdepth) {
             continue;
         }
 
-        break;
+        return terrain_id;
     }
-
-    return feat;
 }
 
 /*!
@@ -225,9 +213,8 @@ void disclose_grid(PlayerType *player_ptr, POSITION y, POSITION x)
  * when they are "discovered" (by detecting them or setting them off),\n
  * the trap is "instantiated" as a visible, "typed", trap.\n
  */
-void place_trap(PlayerType *player_ptr, POSITION y, POSITION x)
+void place_trap(FloorType *floor_ptr, POSITION y, POSITION x)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *g_ptr = &floor_ptr->grid_array[y][x];
 
     /* Paranoia -- verify location */
@@ -242,7 +229,7 @@ void place_trap(PlayerType *player_ptr, POSITION y, POSITION x)
 
     /* Place an invisible trap */
     g_ptr->mimic = g_ptr->feat;
-    g_ptr->feat = choose_random_trap(player_ptr);
+    g_ptr->feat = choose_random_trap(floor_ptr);
 }
 
 /*!
@@ -398,16 +385,14 @@ static void hit_trap_slow(PlayerType *player_ptr)
  */
 void hit_trap(PlayerType *player_ptr, bool break_trap)
 {
-    int i, num, dam;
-    POSITION x = player_ptr->x, y = player_ptr->y;
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    TrapType trap_feat_type = f_ptr->flags.has(TerrainCharacteristics::TRAP) ? i2enum<TrapType>(f_ptr->subtype) : TrapType::NOT_TRAP;
-    concptr name = _("トラップ", "a trap");
+    const Pos2D p_pos(player_ptr->y, player_ptr->x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(p_pos);
+    const auto &terrain = grid.get_terrain();
+    TrapType trap_feat_type = terrain.flags.has(TerrainCharacteristics::TRAP) ? i2enum<TrapType>(terrain.subtype) : TrapType::NOT_TRAP;
 
     disturb(player_ptr, false, true);
 
-    cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HIT_TRAP);
+    cave_alter_feat(player_ptr, p_pos.y, p_pos.x, TerrainCharacteristics::HIT_TRAP);
 
     /* Analyze */
     switch (trap_feat_type) {
@@ -423,8 +408,8 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
             }
 
             sound(SOUND_FALL);
-            dam = damroll(2, 8);
-            name = _("落とし戸", "a trap door");
+            const auto dam = damroll(2, 8);
+            constexpr auto name = _("落とし戸", "a trap door");
 
             take_hit(player_ptr, DAMAGE_NOESCAPE, dam, name);
 
@@ -433,7 +418,7 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
                 do_cmd_save_game(player_ptr, true);
             }
 
-            exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, _("落とし戸に落ちた", "fell through a trap door!"));
+            exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, _("落とし戸に落ちた", "fell through a trap door!"));
             prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT);
             player_ptr->leaving = true;
         }
@@ -449,9 +434,9 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
 
     case TrapType::TY_CURSE: {
         msg_print(_("何かがピカッと光った!", "There is a flash of shimmering light!"));
-        num = 2 + randint1(3);
-        for (i = 0; i < num; i++) {
-            (void)summon_specific(player_ptr, 0, y, x, player_ptr->current_floor_ptr->dun_level, SUMMON_NONE, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
+        const auto num = 2 + randint1(3);
+        for (auto i = 0; i < num; i++) {
+            (void)summon_specific(player_ptr, 0, p_pos.y, p_pos.x, player_ptr->current_floor_ptr->dun_level, SUMMON_NONE, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
         }
 
         if (player_ptr->current_floor_ptr->dun_level > randint1(100)) /* No nasty effect for low levels */
@@ -474,14 +459,14 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
 
     case TrapType::FIRE: {
         msg_print(_("炎に包まれた!", "You are enveloped in flames!"));
-        dam = damroll(4, 6);
+        const auto dam = damroll(4, 6);
         (void)fire_dam(player_ptr, dam, _("炎のトラップ", "a fire trap"), false);
         break;
     }
 
     case TrapType::ACID: {
         msg_print(_("酸が吹きかけられた!", "You are splashed with acid!"));
-        dam = damroll(4, 6);
+        const auto dam = damroll(4, 6);
         (void)acid_dam(player_ptr, dam, _("酸のトラップ", "an acid trap"), false);
         break;
     }
@@ -550,7 +535,7 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
     case TrapType::TRAPS: {
         msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
         /* Make some new traps */
-        project(player_ptr, 0, 1, y, x, 0, AttributeType::MAKE_TRAP, PROJECT_HIDE | PROJECT_JUMP | PROJECT_GRID);
+        project(player_ptr, 0, 1, p_pos.y, p_pos.x, 0, AttributeType::MAKE_TRAP, PROJECT_HIDE | PROJECT_JUMP | PROJECT_GRID);
 
         break;
     }
@@ -565,9 +550,9 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
 
     case TrapType::OPEN: {
         msg_print(_("大音響と共にまわりの壁が崩れた!", "Suddenly, surrounding walls are opened!"));
-        (void)project(player_ptr, 0, 3, y, x, 0, AttributeType::DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE);
-        (void)project(player_ptr, 0, 3, y, x - 4, 0, AttributeType::DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE);
-        (void)project(player_ptr, 0, 3, y, x + 4, 0, AttributeType::DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE);
+        (void)project(player_ptr, 0, 3, p_pos.y, p_pos.x, 0, AttributeType::DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE);
+        (void)project(player_ptr, 0, 3, p_pos.y, p_pos.x - 4, 0, AttributeType::DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE);
+        (void)project(player_ptr, 0, 3, p_pos.y, p_pos.x + 4, 0, AttributeType::DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE);
         aggravate_monsters(player_ptr, 0);
 
         break;
@@ -582,10 +567,10 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
 
         /* Summon Demons and Angels */
         for (lev = player_ptr->current_floor_ptr->dun_level; lev >= 20; lev -= 1 + lev / 16) {
-            num = levs[std::min(lev / 10, 9)];
-            for (i = 0; i < num; i++) {
-                POSITION x1 = rand_spread(x, 7);
-                POSITION y1 = rand_spread(y, 5);
+            const auto num = levs[std::min(lev / 10, 9)];
+            for (auto i = 0; i < num; i++) {
+                POSITION x1 = rand_spread(p_pos.x, 7);
+                POSITION y1 = rand_spread(p_pos.y, 5);
 
                 if (!in_bounds(player_ptr->current_floor_ptr, y1, x1)) {
                     continue;
@@ -626,9 +611,9 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
         fire_ball_hide(player_ptr, AttributeType::WATER_FLOW, 0, 1, 10);
 
         /* Summon Piranhas */
-        num = 1 + player_ptr->current_floor_ptr->dun_level / 20;
-        for (i = 0; i < num; i++) {
-            (void)summon_specific(player_ptr, 0, y, x, player_ptr->current_floor_ptr->dun_level, SUMMON_PIRANHAS, (PM_ALLOW_GROUP | PM_NO_PET));
+        const auto num = 1 + player_ptr->current_floor_ptr->dun_level / 20;
+        for (auto i = 0; i < num; i++) {
+            (void)summon_specific(player_ptr, 0, p_pos.y, p_pos.x, player_ptr->current_floor_ptr->dun_level, SUMMON_PIRANHAS, (PM_ALLOW_GROUP | PM_NO_PET));
         }
         break;
     }
@@ -637,8 +622,8 @@ void hit_trap(PlayerType *player_ptr, bool break_trap)
         break;
     }
 
-    if (break_trap && is_trap(player_ptr, g_ptr->feat)) {
-        cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::DISARM);
+    if (break_trap && is_trap(player_ptr, grid.feat)) {
+        cave_alter_feat(player_ptr, p_pos.y, p_pos.x, TerrainCharacteristics::DISARM);
         msg_print(_("トラップを粉砕した。", "You destroyed the trap."));
     }
 }
index 1173454..e300c3f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "util/flag-group.h"
@@ -55,9 +55,10 @@ enum class TrapType {
 
 extern const std::vector<EnumClassFlagGroup<ChestTrapType>> chest_traps;
 
+class FloorType;
 class PlayerType;
 void init_normal_traps(void);
-FEAT_IDX choose_random_trap(PlayerType *player_ptr);
+short choose_random_trap(FloorType *floor_ptr);
 void disclose_grid(PlayerType *player_ptr, POSITION y, POSITION x);
-void place_trap(PlayerType *player_ptr, POSITION y, POSITION x);
+void place_trap(FloorType *floor_ptr, POSITION y, POSITION x);
 void hit_trap(PlayerType *player_ptr, bool break_trap);
index b4ede07..fc465d0 100644 (file)
@@ -1,7 +1,6 @@
-#include "hpmp/hp-mp-processor.h"
+#include "hpmp/hp-mp-processor.h"
 #include "avatar/avatar.h"
 #include "cmd-action/cmd-pet.h"
-#include "core/player-redraw-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -17,7 +16,6 @@
 #include "object-enchant/object-ego.h"
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "pet/pet-util.h"
 #include "player-base/player-class.h"
@@ -42,6 +40,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "timed-effect/player-cut.h"
 #include "timed-effect/player-poison.h"
@@ -55,7 +54,7 @@
 /*!
  * @brief 地形によるダメージを与える / Deal damage from feature.
  * @param player_ptr プレイヤー情報への参照ポインタ
- * @param g_ptr 現在の床の情報への参照ポインタ
+ * @param grid 現在の床の情報への参照
  * @param msg_levitation 浮遊時にダメージを受けた場合に表示するメッセージ
  * @param msg_normal 通常時にダメージを受けた場合に表示するメッセージの述部
  * @param 耐性等によるダメージレートを計算する関数
  * @details
  * ダメージを受けた場合、自然回復できない。
  */
-static bool deal_damege_by_feat(PlayerType *player_ptr, grid_type *g_ptr, concptr msg_levitation, concptr msg_normal,
+static bool deal_damege_by_feat(PlayerType *player_ptr, const Grid &grid, concptr msg_levitation, concptr msg_normal,
     std::function<PERCENTAGE(PlayerType *)> damage_rate, std::function<void(PlayerType *, int)> additional_effect)
 {
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    int damage = 0;
-
-    if (f_ptr->flags.has(TerrainCharacteristics::DEEP)) {
+    const auto &terrain = grid.get_terrain();
+    auto damage = 0;
+    if (terrain.flags.has(TerrainCharacteristics::DEEP)) {
         damage = 6000 + randint0(4000);
     } else if (!player_ptr->levitation) {
         damage = 3000 + randint0(2000);
@@ -90,15 +88,16 @@ static bool deal_damege_by_feat(PlayerType *player_ptr, grid_type *g_ptr, concpt
 
     if (player_ptr->levitation) {
         msg_print(msg_levitation);
-
-        take_hit(player_ptr, DAMAGE_NOESCAPE, damage, format(_("%sの上に浮遊したダメージ", "flying over %s"), terrains_info[g_ptr->get_feat_mimic()].name.data()).data());
+        constexpr auto mes = _("%sの上に浮遊したダメージ", "flying over %s");
+        take_hit(player_ptr, DAMAGE_NOESCAPE, damage, format(mes, grid.get_terrain_mimic().name.data()));
 
         if (additional_effect != nullptr) {
             additional_effect(player_ptr, damage);
         }
     } else {
-        concptr name = terrains_info[player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].get_feat_mimic()].name.data();
-        msg_format(_("%s%s!", "The %s %s!"), name, msg_normal);
+        const auto p_pos = player_ptr->get_position();
+        const auto &name = player_ptr->current_floor_ptr->get_grid(p_pos).get_terrain_mimic().name;
+        msg_format(_("%s%s!", "The %s %s!"), name.data(), msg_normal);
         take_hit(player_ptr, DAMAGE_NOESCAPE, damage, name);
 
         if (additional_effect != nullptr) {
@@ -115,9 +114,9 @@ static bool deal_damege_by_feat(PlayerType *player_ptr, grid_type *g_ptr, concpt
  */
 void process_player_hp_mp(PlayerType *player_ptr)
 {
-    auto &floor_ref = *player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ref.grid_array[player_ptr->y][player_ptr->x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.get_grid(player_ptr->get_position());
+    const auto &terrain = grid.get_terrain();
     bool cave_no_regen = false;
     int upkeep_factor = 0;
     int regen_amount = PY_REGEN_NORMAL;
@@ -139,17 +138,16 @@ void process_player_hp_mp(PlayerType *player_ptr)
 
     const PlayerRace race(player_ptr);
     if (race.life() == PlayerRaceLifeType::UNDEAD && race.tr_flags().has(TR_VUL_LITE)) {
-        if (!floor_ref.is_in_dungeon() && !has_resist_lite(player_ptr) && !is_invuln(player_ptr) && is_daytime()) {
-            if ((floor_ref.grid_array[player_ptr->y][player_ptr->x].info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW) {
+        if (!floor.is_in_dungeon() && !has_resist_lite(player_ptr) && !is_invuln(player_ptr) && w_ptr->is_daytime()) {
+            if ((floor.grid_array[player_ptr->y][player_ptr->x].info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW) {
                 msg_print(_("日光があなたのアンデッドの肉体を焼き焦がした!", "The sun's rays scorch your undead flesh!"));
                 take_hit(player_ptr, DAMAGE_NOESCAPE, 1, _("日光", "sunlight"));
                 cave_no_regen = true;
             }
         }
 
-        ItemEntity *o_ptr;
-        o_ptr = &player_ptr->inventory_list[INVEN_LITE];
-        auto flags = object_flags(o_ptr);
+        const auto *o_ptr = &player_ptr->inventory_list[INVEN_LITE];
+        const auto flags = o_ptr->get_flags();
 
         if ((player_ptr->inventory_list[INVEN_LITE].bi_key.tval() != ItemKindType::NONE) && flags.has_not(TR_DARK_SOURCE) && !has_resist_lite(player_ptr)) {
             const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
@@ -159,45 +157,51 @@ void process_player_hp_mp(PlayerType *player_ptr)
                 const auto wielding_item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
                 std::stringstream ss;
                 ss << _(wielding_item_name, "wielding ") << _("を装備したダメージ", wielding_item_name);
-                take_hit(player_ptr, DAMAGE_NOESCAPE, 1, ss.str().data());
+                take_hit(player_ptr, DAMAGE_NOESCAPE, 1, ss.str());
             }
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::LAVA) && !is_invuln(player_ptr) && !has_immune_fire(player_ptr)) {
-        if (deal_damege_by_feat(
-                player_ptr, g_ptr, _("熱で火傷した!", "The heat burns you!"), _("で火傷した!", "burns you!"), calc_fire_damage_rate, nullptr)) {
+    if (terrain.flags.has(TerrainCharacteristics::LAVA) && !is_invuln(player_ptr) && !has_immune_fire(player_ptr)) {
+        constexpr auto mes_leviation = _("熱で火傷した!", "The heat burns you!");
+        constexpr auto mes_normal = _("で火傷した!", "burns you!");
+        if (deal_damege_by_feat(player_ptr, grid, mes_leviation, mes_normal, calc_fire_damage_rate, nullptr)) {
             cave_no_regen = true;
             sound(SOUND_TERRAIN_DAMAGE);
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::COLD_PUDDLE) && !is_invuln(player_ptr) && !has_immune_cold(player_ptr)) {
-        if (deal_damege_by_feat(
-                player_ptr, g_ptr, _("冷気に覆われた!", "The cold engulfs you!"), _("に凍えた!", "frostbites you!"), calc_cold_damage_rate, nullptr)) {
+    if (terrain.flags.has(TerrainCharacteristics::COLD_PUDDLE) && !is_invuln(player_ptr) && !has_immune_cold(player_ptr)) {
+        constexpr auto mes_leviation = _("冷気に覆われた!", "The cold engulfs you!");
+        constexpr auto mes_normal = _("に凍えた!", "frostbites you!");
+        if (deal_damege_by_feat(player_ptr, grid, mes_leviation, mes_normal, calc_cold_damage_rate, nullptr)) {
             cave_no_regen = true;
             sound(SOUND_TERRAIN_DAMAGE);
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::ELEC_PUDDLE) && !is_invuln(player_ptr) && !has_immune_elec(player_ptr)) {
-        if (deal_damege_by_feat(
-                player_ptr, g_ptr, _("電撃を受けた!", "The electricity shocks you!"), _("に感電した!", "shocks you!"), calc_elec_damage_rate, nullptr)) {
+    if (terrain.flags.has(TerrainCharacteristics::ELEC_PUDDLE) && !is_invuln(player_ptr) && !has_immune_elec(player_ptr)) {
+        constexpr auto mes_leviation = _("電撃を受けた!", "The electricity shocks you!");
+        constexpr auto mes_normal = _("に感電した!", "shocks you!");
+        if (deal_damege_by_feat(player_ptr, grid, mes_leviation, mes_normal, calc_elec_damage_rate, nullptr)) {
             cave_no_regen = true;
             sound(SOUND_TERRAIN_DAMAGE);
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::ACID_PUDDLE) && !is_invuln(player_ptr) && !has_immune_acid(player_ptr)) {
-        if (deal_damege_by_feat(
-                player_ptr, g_ptr, _("酸が飛び散った!", "The acid melts you!"), _("に溶かされた!", "melts you!"), calc_acid_damage_rate, nullptr)) {
+    if (terrain.flags.has(TerrainCharacteristics::ACID_PUDDLE) && !is_invuln(player_ptr) && !has_immune_acid(player_ptr)) {
+        constexpr auto mes_leviation = _("酸が飛び散った!", "The acid melts you!");
+        constexpr auto mes_normal = _("に溶かされた!", "melts you!");
+        if (deal_damege_by_feat(player_ptr, grid, mes_leviation, mes_normal, calc_acid_damage_rate, nullptr)) {
             cave_no_regen = true;
             sound(SOUND_TERRAIN_DAMAGE);
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::POISON_PUDDLE) && !is_invuln(player_ptr)) {
-        if (deal_damege_by_feat(player_ptr, g_ptr, _("毒気を吸い込んだ!", "The gas poisons you!"), _("に毒された!", "poisons you!"), calc_acid_damage_rate,
+    if (terrain.flags.has(TerrainCharacteristics::POISON_PUDDLE) && !is_invuln(player_ptr)) {
+        constexpr auto mes_leviation = _("毒気を吸い込んだ!", "The gas poisons you!");
+        constexpr auto mes_normal = _("に毒された!", "poisons you!");
+        if (deal_damege_by_feat(player_ptr, grid, mes_leviation, mes_normal, calc_acid_damage_rate,
                 [](PlayerType *player_ptr, int damage) {
                     if (!has_resist_pois(player_ptr)) {
                         (void)BadStatusSetter(player_ptr).mod_poison(static_cast<TIME_EFFECT>(damage));
@@ -208,7 +212,8 @@ void process_player_hp_mp(PlayerType *player_ptr)
         }
     }
 
-    if (f_ptr->flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP }) && !player_ptr->levitation && !player_ptr->can_swim && !has_resist_water(player_ptr)) {
+    const auto can_drown = terrain.flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP });
+    if (can_drown && !player_ptr->levitation && !player_ptr->can_swim && !has_resist_water(player_ptr)) {
         if (calc_inventory_weight(player_ptr) > calc_weight_limit(player_ptr)) {
             msg_print(_("溺れている!", "You are drowning!"));
             take_hit(player_ptr, DAMAGE_NOESCAPE, randint1(player_ptr->lev), _("溺れ", "drowning"));
@@ -273,9 +278,9 @@ void process_player_hp_mp(PlayerType *player_ptr)
 
     if (player_ptr->riding) {
         int damage;
-        auto auras = monraces_info[floor_ref.m_list[player_ptr->riding].r_idx].aura_flags;
+        auto auras = monraces_info[floor.m_list[player_ptr->riding].r_idx].aura_flags;
         if (auras.has(MonsterAuraType::FIRE) && !has_immune_fire(player_ptr)) {
-            damage = monraces_info[floor_ref.m_list[player_ptr->riding].r_idx].level / 2;
+            damage = monraces_info[floor.m_list[player_ptr->riding].r_idx].level / 2;
             if (race.tr_flags().has(TR_VUL_FIRE)) {
                 damage += damage / 3;
             }
@@ -292,7 +297,7 @@ void process_player_hp_mp(PlayerType *player_ptr)
         }
 
         if (auras.has(MonsterAuraType::ELEC) && !has_immune_elec(player_ptr)) {
-            damage = monraces_info[floor_ref.m_list[player_ptr->riding].r_idx].level / 2;
+            damage = monraces_info[floor.m_list[player_ptr->riding].r_idx].level / 2;
             if (race.tr_flags().has(TR_VUL_ELEC)) {
                 damage += damage / 3;
             }
@@ -309,7 +314,7 @@ void process_player_hp_mp(PlayerType *player_ptr)
         }
 
         if (auras.has(MonsterAuraType::COLD) && !has_immune_cold(player_ptr)) {
-            damage = monraces_info[floor_ref.m_list[player_ptr->riding].r_idx].level / 2;
+            damage = monraces_info[floor.m_list[player_ptr->riding].r_idx].level / 2;
             if (race.tr_flags().has(TR_VUL_COLD)) {
                 damage += damage / 3;
             }
@@ -333,8 +338,12 @@ void process_player_hp_mp(PlayerType *player_ptr)
      * reduced below 0 hp by being inside a stone wall; others
      * WILL BE!
      */
-    if (f_ptr->flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY })) {
-        if (!is_invuln(player_ptr) && !player_ptr->wraith_form && !player_ptr->tim_pass_wall && ((player_ptr->chp > (player_ptr->lev / 5)) || !has_pass_wall(player_ptr))) {
+    if (terrain.flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY })) {
+        auto should_damage = !is_invuln(player_ptr);
+        should_damage &= player_ptr->wraith_form == 0;
+        should_damage &= player_ptr->tim_pass_wall == 0;
+        should_damage &= (player_ptr->chp > (player_ptr->lev / 5)) || !has_pass_wall(player_ptr);
+        if (should_damage) {
             concptr dam_desc;
             cave_no_regen = true;
 
@@ -446,8 +455,9 @@ bool hp_player(PlayerType *player_ptr, int num)
             player_ptr->chp_frac = 0;
         }
 
-        player_ptr->redraw |= (PR_HP);
-        player_ptr->window_flags |= (PW_PLAYER);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::HP);
+        rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
         if (num < 5) {
             msg_print(_("少し気分が良くなった。", "You feel a little better."));
         } else if (num < 15) {
index 47d849b..850cc9b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void process_player_hp_mp(PlayerType *player_ptr);
index e0833c5..0551200 100644 (file)
@@ -1,7 +1,5 @@
-#include "hpmp/hp-mp-regenerator.h"
+#include "hpmp/hp-mp-regenerator.h"
 #include "cmd-item/cmd-magiceat.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "inventory/inventory-slot-types.h"
 #include "monster-race/monster-race.h"
@@ -18,6 +16,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 
 /*!<広域マップ移動時の自然回復処理カウンタ(広域マップ1マス毎に20回処理を基本とする)*/
 int wild_regen = 20;
@@ -52,8 +51,9 @@ void regenhp(PlayerType *player_ptr, int percent)
     }
 
     if (old_chp != player_ptr->chp) {
-        player_ptr->redraw |= (PR_HP);
-        player_ptr->window_flags |= (PW_PLAYER);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::HP);
+        rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
         wild_regen = 20;
     }
 }
@@ -108,9 +108,13 @@ void regenmana(PlayerType *player_ptr, MANA_POINT upkeep_factor, MANA_POINT rege
     }
 
     if (old_csp != player_ptr->csp) {
-        player_ptr->redraw |= (PR_MP);
-        player_ptr->window_flags |= (PW_PLAYER);
-        player_ptr->window_flags |= (PW_SPELL);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::MP);
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::PLAYER,
+            SubWindowRedrawingFlag::SPELL,
+        };
+        rfu.set_flags(flags);
         wild_regen = 20;
     }
 }
@@ -170,7 +174,7 @@ void regenerate_monsters(PlayerType *player_ptr)
 {
     for (int i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
         auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
 
         if (!m_ptr->is_valid()) {
             continue;
@@ -193,11 +197,12 @@ void regenerate_monsters(PlayerType *player_ptr)
                 m_ptr->hp = m_ptr->maxhp;
             }
 
+            auto &rfu = RedrawingFlagsUpdater::get_instance();
             if (player_ptr->health_who == i) {
-                player_ptr->redraw |= (PR_HEALTH);
+                rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
             }
             if (player_ptr->riding == i) {
-                player_ptr->redraw |= (PR_UHEALTH);
+                rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
             }
         }
     }
@@ -246,10 +251,14 @@ void regenerate_captured_monsters(PlayerType *player_ptr)
     }
 
     if (heal) {
-        player_ptr->update |= (PU_COMBINATION);
-        // FIXME 広域マップ移動で1歩毎に何度も再描画されて重くなる。現在はボール中モンスターのHP回復でボールの表示は変わらないためコメントアウトする。
-        // player_ptr->window_flags |= (PW_INVENTORY);
-        // player_ptr->window_flags |= (PW_EQUIPMENT);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::COMBINATION);
+
+        /*!
+         * @todo FIXME 広域マップ移動で1歩毎に何度も再描画されて重くなる.
+         * 現在はボール中モンスターのHP回復でボールの表示は変わらないためコメントアウトする.
+         */
+        // rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
+        // rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
         wild_regen = 20;
     }
 }
index 299ca40..c58ede5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d57f4e6..2e21a36 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/artifact-reader.h"
+#include "info-reader/artifact-reader.h"
 #include "artifact/fixed-art-types.h"
 #include "artifact/random-art-effects.h"
 #include "info-reader/baseitem-tokens-table.h"
@@ -86,25 +86,28 @@ errr parse_artifacts_info(std::string_view buf, angband_header *)
     if (tokens[0] == "D") {
         // D:JapaneseText
         // D:$EnglishText
-        if (tokens.size() < 2 || tokens[1].size() == 0) {
+        if (tokens.size() < 2 || buf.length() < 3) {
             return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         }
 #ifdef JP
-        if (tokens[1][0] == '$') {
+        if (buf[2] == '$') {
             return PARSE_ERROR_NONE;
         }
 
         const auto it = artifacts_info.rbegin();
         auto &artifact = it->second;
-        artifact.text.append(tokens[1]);
+        artifact.text.append(buf.substr(2));
 #else
-        if (tokens[1][0] != '$') {
+        if (buf[2] != '$') {
             return PARSE_ERROR_NONE;
         }
+        if (buf.length() == 3) {
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
+        }
 
         const auto it = artifacts_info.rbegin();
         auto &artifact = it->second;
-        append_english_text(artifact.text, tokens[1].substr(1));
+        append_english_text(artifact.text, buf.substr(3));
 #endif
         return PARSE_ERROR_NONE;
     }
@@ -168,7 +171,7 @@ errr parse_artifacts_info(std::string_view buf, angband_header *)
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
 
-        auto n = grab_one_activation_flag(tokens[1].data());
+        auto n = grab_one_activation_flag(tokens[1]);
         if (n <= RandomArtActType::NONE) {
             return PARSE_ERROR_INVALID_FLAG;
         }
index 26e5c72..47f131f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 43e606a..d1a17fe 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief ベースアイテム定義の読み込み処理
  * @author Hourier
  * @date 2022/10/10
@@ -93,18 +93,21 @@ errr parse_baseitems_info(std::string_view buf, angband_header *head)
     } else if (tokens[0] == "D") {
         // D:text_ja
         // D:$text_en
-        if (tokens.size() < 2 || tokens[1].size() == 0) {
+        if (tokens.size() < 2 || buf.length() < 3) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
 #ifdef JP
-        if (tokens[1][0] == '$') {
+        if (buf[2] == '$') {
             return PARSE_ERROR_NONE;
         }
         bii_ptr->text.append(buf.substr(2));
 #else
-        if (tokens[1][0] != '$') {
+        if (buf[2] != '$') {
             return PARSE_ERROR_NONE;
         }
+        if (buf.length() == 3) {
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        }
         append_english_text(bii_ptr->text, buf.substr(3));
 #endif
     } else if (tokens[0] == "G") {
@@ -183,7 +186,7 @@ errr parse_baseitems_info(std::string_view buf, angband_header *head)
         if (tokens.size() < 2 || tokens[1].size() == 0) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
-        auto n = grab_one_activation_flag(tokens[1].data());
+        auto n = grab_one_activation_flag(tokens[1]);
         if (n <= RandomArtActType::NONE) {
             return PARSE_ERROR_INVALID_FLAG;
         }
index 842808c..bc24753 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 0b08f64..6acbcc1 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/baseitem-tokens-table.h"
+#include "info-reader/baseitem-tokens-table.h"
 
 // clang-format off
 /*!
@@ -154,7 +154,6 @@ const std::unordered_map<std::string_view, tr_type> baseitem_flags = {
     { "EASY2_WEAPON", TR_EASY2_WEAPON },
     { "DOWN_SAVING", TR_DOWN_SAVING },
     { "NO_AC", TR_NO_AC },
-    { "HEAVY_SPELL", TR_HEAVY_SPELL },
     { "RES_TIME", TR_RES_TIME },
     { "RES_WATER", TR_RES_WATER },
     { "INVULN_ARROW", TR_INVULN_ARROW },
index 7617b6a..20a5168 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trg-types.h"
index e85a2ec..84ebcc1 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/dungeon-info-tokens-table.h"
+#include "info-reader/dungeon-info-tokens-table.h"
 #include "dungeon/dungeon-flag-types.h"
 
 /*!
index a2fdc72..5830924 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/dungeon-reader.h"
+#include "info-reader/dungeon-reader.h"
 #include "grid/feature.h"
 #include "info-reader/dungeon-info-tokens-table.h"
 #include "info-reader/feature-reader.h"
@@ -45,10 +45,6 @@ static bool grab_one_basic_monster_flag(dungeon_type *d_ptr, std::string_view wh
         return true;
     }
 
-    if (info_grab_one_flag(d_ptr->mflags3, r_info_flags3, what)) {
-        return true;
-    }
-
     if (info_grab_one_flag(d_ptr->mflags7, r_info_flags7, what)) {
         return true;
     }
@@ -162,18 +158,21 @@ errr parse_dungeons_info(std::string_view buf, angband_header *)
     } else if (tokens[0] == "D") {
         // D:text_ja
         // D:$text_en
-        if (tokens.size() < 2 || tokens[1].size() == 0) {
+        if (tokens.size() < 2 || buf.length() < 3) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
 #ifdef JP
-        if (tokens[1][0] == '$') {
+        if (buf[2] == '$') {
             return PARSE_ERROR_NONE;
         }
         d_ptr->text.append(buf.substr(2));
 #else
-        if (tokens[1][0] != '$') {
+        if (buf[2] != '$') {
             return PARSE_ERROR_NONE;
         }
+        if (buf.length() == 3) {
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        }
         append_english_text(d_ptr->text, buf.substr(3));
 #endif
     } else if (tokens[0] == "W") {
@@ -299,6 +298,17 @@ errr parse_dungeons_info(std::string_view buf, angband_header *)
         }
     } else if (tokens[0] == "M") {
         // M:monsterflags
+        if (tokens[1] == "X") {
+            if (tokens.size() < 3) {
+                return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+            }
+            uint32_t sex;
+            if (!info_grab_one_const(sex, r_info_sex, tokens[2])) {
+                return PARSE_ERROR_INVALID_FLAG;
+            }
+            d_ptr->mon_sex = static_cast<MonsterSex>(sex);
+            return 0;
+        }
         if (tokens.size() < 2) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
index 164f55d..e88f4e2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 59e40f3..f803d3c 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/ego-reader.h"
+#include "info-reader/ego-reader.h"
 #include "artifact/random-art-effects.h"
 #include "info-reader/baseitem-tokens-table.h"
 #include "info-reader/info-reader-util.h"
@@ -139,7 +139,7 @@ errr parse_egos_info(std::string_view buf, angband_header *)
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
 
-        auto n = grab_one_activation_flag(tokens[1].data());
+        auto n = grab_one_activation_flag(tokens[1]);
         if (n <= RandomArtActType::NONE) {
             return PARSE_ERROR_INVALID_FLAG;
         }
index cebc1aa..56deac7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 39648a2..1b540a4 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/feature-info-tokens-table.h"
+#include "info-reader/feature-info-tokens-table.h"
 
 /*!
  * @brief 地形属性トークンの定義 / Feature info flags
index 5fb8841..453e096 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "grid/feature-flag-types.h"
 #include "system/angband.h"
index 38ffb6c..928b9fe 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/feature-reader.h"
+#include "info-reader/feature-reader.h"
 #include "floor/wild.h"
 #include "grid/feature.h"
 #include "grid/grid.h"
@@ -61,11 +61,11 @@ static bool grab_one_feat_action(TerrainType *f_ptr, std::string_view what, int
  */
 errr parse_terrains_info(std::string_view buf, angband_header *)
 {
-    static TerrainType *f_ptr = nullptr;
     const auto &tokens = str_split(buf, ':', false, 10);
+    auto &terrains = TerrainList::get_instance();
 
+    // N:index:tag
     if (tokens[0] == "N") {
-        // N:index:tag
         if (tokens.size() < 3) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
@@ -74,44 +74,62 @@ errr parse_terrains_info(std::string_view buf, angband_header *)
             return PARSE_ERROR_GENERIC;
         }
 
-        auto i = std::stoi(tokens[1]);
+        const auto i = std::stoi(tokens[1]);
         if (i < error_idx) {
             return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         }
-        if (i >= static_cast<int>(terrains_info.size())) {
-            terrains_info.resize(i + 1);
+
+        if (i >= static_cast<int>(TerrainList::get_instance().size())) {
+            terrains.resize(i + 1);
         }
 
         error_idx = i;
-        f_ptr = &terrains_info[i];
-        f_ptr->idx = static_cast<FEAT_IDX>(i);
-        f_ptr->tag = tokens[2];
-
-        f_ptr->mimic = (FEAT_IDX)i;
-        f_ptr->destroyed = (FEAT_IDX)i;
-        for (i = 0; i < MAX_FEAT_STATES; i++) {
-            f_ptr->state[i].action = TerrainCharacteristics::MAX;
+        const auto s = static_cast<short>(i);
+        auto &terrain = terrains[s];
+        terrain.idx = s;
+        terrain.tag = tokens[2];
+
+        terrain.mimic = s;
+        terrain.destroyed = s;
+        for (auto j = 0; j < MAX_FEAT_STATES; j++) {
+            terrain.state[j].action = TerrainCharacteristics::MAX;
         }
 
-    } else if (!f_ptr) {
+        return PARSE_ERROR_NONE;
+    }
+
+    if (terrains.empty()) {
         return PARSE_ERROR_MISSING_RECORD_HEADER;
-    } else if (tokens[0] == _("J", "E")) {
-        // J:name_ja
-        // E:name_en
+    }
+
+    // J:name_ja, E:name_en
+    auto &terrain = *(terrains.end() - 1);
+    if (tokens[0] == _("J", "E")) {
         if (tokens.size() < 2 || tokens[1].size() == 0) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
-        f_ptr->name = tokens[1];
-    } else if (tokens[0] == _("E", "J")) {
-        // pass
-    } else if (tokens[0] == "M") {
-        // M:mimic_tag
+
+        terrain.name = tokens[1];
+        return PARSE_ERROR_NONE;
+    }
+
+    // pass
+    if (tokens[0] == _("E", "J")) {
+        return PARSE_ERROR_NONE;
+    }
+
+    // M:mimic_tag
+    if (tokens[0] == "M") {
         if (tokens.size() < 2 || tokens[1].size() == 0) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
-        f_ptr->mimic_tag = tokens[1];
-    } else if (tokens[0] == "G") {
-        // G:symbol:color:lite:lite_symbol:lite_color:dark_symbol:dark_color
+
+        terrain.mimic_tag = tokens[1];
+        return PARSE_ERROR_NONE;
+    }
+
+    // G:symbol:color:lite:lite_symbol:lite_color:dark_symbol:dark_color
+    if (tokens[0] == "G") {
         if (tokens.size() < 3) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
@@ -137,44 +155,54 @@ errr parse_terrains_info(std::string_view buf, angband_header *)
             return PARSE_ERROR_GENERIC;
         }
 
-        f_ptr->d_char[F_LIT_STANDARD] = s_char;
-        f_ptr->d_attr[F_LIT_STANDARD] = s_attr;
+        terrain.d_char[F_LIT_STANDARD] = s_char;
+        terrain.d_attr[F_LIT_STANDARD] = s_attr;
         if (tokens.size() == n) {
             for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
-                f_ptr->d_char[j] = s_char;
-                f_ptr->d_attr[j] = s_attr;
+                terrain.d_char[j] = s_char;
+                terrain.d_attr[j] = s_attr;
             }
-        } else if (tokens[n++] == "LIT") {
-            apply_default_feat_lighting(f_ptr->d_attr, f_ptr->d_char);
 
-            for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
+            return PARSE_ERROR_NONE;
+        }
+
+        if (tokens[n++] == "LIT") {
+            apply_default_feat_lighting(terrain.d_attr, terrain.d_char);
+            for (auto j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
                 auto c_idx = n + (j - F_LIT_NS_BEGIN) * 2;
                 auto a_idx = c_idx + 1;
                 if (tokens.size() <= (size_t)a_idx) {
                     continue;
                 }
+
                 if (tokens[c_idx].size() != 1 || tokens[a_idx].size() != 1) {
                     continue;
                 }
 
-                f_ptr->d_char[j] = tokens[c_idx][0];
-
+                terrain.d_char[j] = tokens[c_idx][0];
                 if (tokens[a_idx] == "*") {
-                    // pass
-                } else if (tokens[a_idx] == "-") {
-                    f_ptr->d_attr[j] = s_attr;
-                } else {
-                    f_ptr->d_attr[j] = color_char_to_attr(tokens[a_idx][0]);
-                    if (f_ptr->d_attr[j] > 127) {
-                        return PARSE_ERROR_GENERIC;
-                    }
+                    continue;
+                }
+
+                if (tokens[a_idx] == "-") {
+                    terrain.d_attr[j] = s_attr;
+                    continue;
+                }
+
+                terrain.d_attr[j] = color_char_to_attr(tokens[a_idx][0]);
+                if (terrain.d_attr[j] > 127) {
+                    return PARSE_ERROR_GENERIC;
                 }
             }
-        } else {
-            return PARSE_ERROR_GENERIC;
+
+            return PARSE_ERROR_NONE;
         }
-    } else if (tokens[0] == "F") {
-        // F:flags
+
+        return PARSE_ERROR_GENERIC;
+    }
+
+    // F:flags
+    if (tokens[0] == "F") {
         if (tokens.size() < 2 || tokens[1].size() == 0) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
@@ -188,36 +216,47 @@ errr parse_terrains_info(std::string_view buf, angband_header *)
             const auto &f_tokens = str_split(f, '_', false, 2);
             if (f_tokens.size() == 2) {
                 if (f_tokens[0] == "SUBTYPE") {
-                    info_set_value(f_ptr->subtype, f_tokens[1]);
+                    info_set_value(terrain.subtype, f_tokens[1]);
                     continue;
-                } else if (f_tokens[0] == "POWER") {
-                    info_set_value(f_ptr->power, f_tokens[1]);
+                }
+
+                if (f_tokens[0] == "POWER") {
+                    info_set_value(terrain.power, f_tokens[1]);
                     continue;
                 }
             }
 
-            if (!grab_one_feat_flag(f_ptr, f)) {
+            if (!grab_one_feat_flag(&terrain, f)) {
                 return PARSE_ERROR_INVALID_FLAG;
             }
         }
-    } else if (tokens[0] == "W") {
-        // W:priority
+
+        return PARSE_ERROR_NONE;
+    }
+
+    // W:priority
+    if (tokens[0] == "W") {
         if (tokens.size() < 2 || tokens[1].size() == 0) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
-        info_set_value(f_ptr->priority, tokens[1]);
-    } else if (tokens[0] == "K") {
-        // K:state:feat
+
+        info_set_value(terrain.priority, tokens[1]);
+        return PARSE_ERROR_NONE;
+    }
+
+    // K:state:feat
+    if (tokens[0] == "K") {
         if (tokens.size() < 3) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
+
         if (tokens[1].size() == 0 || tokens[2].size() == 0) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
 
-        int i = 0;
+        auto i = 0;
         for (; i < MAX_FEAT_STATES; i++) {
-            if (f_ptr->state[i].action == TerrainCharacteristics::MAX) {
+            if (terrain.state[i].action == TerrainCharacteristics::MAX) {
                 break;
             }
         }
@@ -227,19 +266,19 @@ errr parse_terrains_info(std::string_view buf, angband_header *)
         }
 
         if (tokens[1] == "DESTROYED") {
-            f_ptr->destroyed_tag = tokens[2];
-        } else {
-            if (!grab_one_feat_action(f_ptr, tokens[1], i)) {
-                return PARSE_ERROR_INVALID_FLAG;
-            }
+            terrain.destroyed_tag = tokens[2];
+            return PARSE_ERROR_NONE;
+        }
 
-            f_ptr->state[i].result_tag = tokens[2];
+        if (!grab_one_feat_action(&terrain, tokens[1], i)) {
+            return PARSE_ERROR_INVALID_FLAG;
         }
-    } else {
-        return PARSE_ERROR_UNDEFINED_DIRECTIVE;
+
+        terrain.state[i].result_tag = tokens[2];
+        return PARSE_ERROR_NONE;
     }
 
-    return PARSE_ERROR_NONE;
+    return PARSE_ERROR_UNDEFINED_DIRECTIVE;
 }
 
 /*!
@@ -412,8 +451,9 @@ errr init_feat_variables(void)
  */
 FEAT_IDX f_tag_to_index(std::string_view str)
 {
-    for (size_t i = 0; i < terrains_header.info_num; i++) {
-        if (terrains_info[i].tag == str) {
+    const auto &terrains = TerrainList::get_instance();
+    for (short i = 0; i < terrains_header.info_num; i++) {
+        if (terrains[i].tag == str) {
             return (FEAT_IDX)i;
         }
     }
@@ -449,8 +489,9 @@ static FEAT_IDX search_real_feat(std::string feat)
         return -1;
     }
 
-    for (FEAT_IDX i = 0; i < terrains_header.info_num; i++) {
-        if (feat.compare(terrains_info[i].tag) == 0) {
+    const auto &terrains = TerrainList::get_instance();
+    for (short i = 0; i < terrains_header.info_num; i++) {
+        if (feat == terrains[i].tag) {
             return i;
         }
     }
@@ -465,15 +506,16 @@ static FEAT_IDX search_real_feat(std::string feat)
  */
 void retouch_terrains_info(angband_header *head)
 {
-    for (int i = 0; i < head->info_num; i++) {
-        auto *f_ptr = &terrains_info[i];
-        FEAT_IDX k = search_real_feat(f_ptr->mimic_tag);
-        f_ptr->mimic = k < 0 ? f_ptr->mimic : k;
-        k = search_real_feat(f_ptr->destroyed_tag);
-        f_ptr->destroyed = k < 0 ? f_ptr->destroyed : k;
+    auto &terrains = TerrainList::get_instance();
+    for (short i = 0; i < head->info_num; i++) {
+        auto &terrain = terrains[i];
+        FEAT_IDX k = search_real_feat(terrain.mimic_tag);
+        terrain.mimic = k < 0 ? terrain.mimic : k;
+        k = search_real_feat(terrain.destroyed_tag);
+        terrain.destroyed = k < 0 ? terrain.destroyed : k;
         for (FEAT_IDX j = 0; j < MAX_FEAT_STATES; j++) {
-            k = search_real_feat(f_ptr->state[j].result_tag);
-            f_ptr->state[j].result = k < 0 ? f_ptr->state[j].result : k;
+            k = search_real_feat(terrain.state[j].result_tag);
+            terrain.state[j].result = k < 0 ? terrain.state[j].result : k;
         }
     }
 }
index 3e93675..e61696b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 7299842..e4404ca 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ゲームデータ初期化1 / Initialization (part 1) -BEN-
  * @date 2014/01/28
  * @author
@@ -17,6 +17,7 @@
 #include "player-info/class-info.h"
 #include "player-info/race-info.h"
 #include "realm/realm-names-table.h"
+#include "system/angband-exceptions.h"
 #include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
 #include "util/angband-files.h"
@@ -25,7 +26,6 @@
 #include "world/world.h"
 #include <algorithm>
 #include <sstream>
-#include <stdexcept>
 
 static concptr variant = "ZANGBAND";
 
@@ -253,9 +253,8 @@ static concptr parse_fixed_map_expression(PlayerType *player_ptr, char **sp, cha
  */
 parse_error_type parse_fixed_map(PlayerType *player_ptr, std::string_view name, int ymin, int xmin, int ymax, int xmax)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, name);
-    auto *fp = angband_fopen(buf, FileOpenMode::READ);
+    const auto &path = path_build(ANGBAND_DIR_EDIT, name);
+    auto *fp = angband_fopen(path, FileOpenMode::READ);
     if (fp == nullptr) {
         return PARSE_ERROR_GENERIC;
     }
@@ -266,6 +265,7 @@ parse_error_type parse_fixed_map(PlayerType *player_ptr, std::string_view name,
     int x = xmin;
     int y = ymin;
     qtwg_type tmp_qg;
+    char buf[1024]{};
     qtwg_type *qg_ptr = initialize_quest_generator_type(&tmp_qg, buf, ymin, xmin, ymax, xmax, &y, &x);
     while (angband_fgets(fp, buf, sizeof(buf)) == 0) {
         num++;
@@ -338,19 +338,18 @@ static void parse_quest_info_aux(std::string_view file_name, std::set<QuestId> &
         if (key_list_ref.find(q) != key_list_ref.end()) {
             std::stringstream ss;
             ss << _("重複したQuestID ", "Duplicated Quest Id ") << enum2i(q) << '(' << file_name << ", L" << line << ')';
-            throw std::runtime_error(ss.str());
+            THROW_EXCEPTION(std::runtime_error, ss.str());
         }
 
         key_list_ref.insert(q);
     };
 
-    char file_buf[1024];
-    path_build(file_buf, sizeof(file_buf), ANGBAND_DIR_EDIT, file_name);
-    auto *fp = angband_fopen(file_buf, FileOpenMode::READ);
+    const auto &path = path_build(ANGBAND_DIR_EDIT, file_name);
+    auto *fp = angband_fopen(path, FileOpenMode::READ);
     if (fp == nullptr) {
         std::stringstream ss;
         ss << _("ファイルが見つかりません (", "File is not found (") << file_name << ')';
-        throw std::runtime_error(ss.str());
+        THROW_EXCEPTION(std::runtime_error, ss.str());
     }
 
     char buf[4096];
index 2b8b9b3..6e9a845 100644 (file)
@@ -1,10 +1,10 @@
-#pragma once
+#pragma once
 
 #include <set>
 #include <string_view>
 
 class PlayerType;
 enum parse_error_type : int;
-enum class QuestId : int16_t;
+enum class QuestId : short;
 parse_error_type parse_fixed_map(PlayerType *player_ptr, std::string_view name, int ymin, int xmin, int ymax, int xmax);
 std::set<QuestId> parse_quest_info(std::string_view file_name);
index f1fe625..26b5b0c 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/general-parser.h"
+#include "info-reader/general-parser.h"
 #include "artifact/fixed-art-types.h"
 #include "dungeon/quest.h"
 #include "grid/feature.h"
@@ -29,42 +29,44 @@ dungeon_grid letter[255];
  * @param buf 読み取りに使うバッファ領域
  * @param head ヘッダ構造体
  * @param parse_info_txt_line パース関数
- * @return エラーコード
+ * @return エラーコード, エラー行番号
  */
-errr init_info_txt(FILE *fp, char *buf, angband_header *head, Parser parse_info_txt_line)
+std::tuple<errr, int> init_info_txt(FILE *fp, char *buf, angband_header *head, Parser parse_info_txt_line)
 {
     error_idx = -1;
-    error_line = 0;
+    auto error_line = 0;
+
+    util::SHA256 sha256;
 
-    errr err;
     while (angband_fgets(fp, buf, 1024) == 0) {
         error_line++;
-        if (!buf[0] || (buf[0] == '#')) {
+        const std::string_view line = buf;
+        if (line.empty() || line.starts_with('#')) {
             continue;
         }
 
-        if (buf[1] != ':') {
-            return PARSE_ERROR_GENERIC;
+        if (!line.substr(1).starts_with(':')) {
+            return { PARSE_ERROR_GENERIC, error_line };
         }
 
-        if (buf[0] == 'V') {
+        if (line.starts_with('V')) {
             continue;
         }
 
-        if (buf[0] != 'N' && buf[0] != 'D') {
-            int i;
-            for (i = 0; buf[i]; i++) {
-                head->checksum += (byte)buf[i];
-                head->checksum ^= (1U << (i % 8));
-            }
+        // 文字コードの差異を吸収するため、日本語が含まれる可能性のある
+        // 「N:」「D:」「J:」はハッシュ計算から除外する
+        if (!line.starts_with('N') && !line.starts_with('D') && !line.starts_with('J')) {
+            sha256.update(line);
         }
 
-        if ((err = parse_info_txt_line(buf, head)) != 0) {
-            return err;
+        if (auto err = parse_info_txt_line(line, head); err != 0) {
+            return { err, error_line };
         }
     }
 
-    return 0;
+    head->digest = sha256.digest();
+
+    return { PARSE_ERROR_NONE, error_line };
 }
 
 /*!
@@ -118,7 +120,7 @@ parse_error_type parse_line_feature(FloorType *floor_ptr, char *buf)
                 letter[index].artifact = i2enum<FixedArtifactId>(atoi(zz[6] + 1));
             }
         } else if (zz[6][0] == '!') {
-            if (inside_quest(floor_ptr->quest_number)) {
+            if (floor_ptr->is_in_quest()) {
                 const auto &quest_list = QuestList::get_instance();
                 letter[index].artifact = quest_list[floor_ptr->quest_number].reward_artifact_idx;
             }
@@ -143,7 +145,7 @@ parse_error_type parse_line_feature(FloorType *floor_ptr, char *buf)
                 letter[index].object = (OBJECT_IDX)atoi(zz[4] + 1);
             }
         } else if (zz[4][0] == '!') {
-            if (inside_quest(floor_ptr->quest_number)) {
+            if (floor_ptr->is_in_quest()) {
                 const auto &quest = QuestList::get_instance()[floor_ptr->quest_number];
                 if (quest.has_reward()) {
                     const auto &artifact = quest.get_reward();
@@ -226,9 +228,9 @@ parse_error_type parse_line_building(char *buf)
     switch (s[0]) {
     case 'N': {
         if (tokenize(s + 2, 3, zz, 0) == 3) {
-            strcpy(building[index].name, zz[0]);
-            strcpy(building[index].owner_name, zz[1]);
-            strcpy(building[index].owner_race, zz[2]);
+            strcpy(buildings[index].name, zz[0]);
+            strcpy(buildings[index].owner_name, zz[1]);
+            strcpy(buildings[index].owner_race, zz[2]);
             break;
         }
 
@@ -237,12 +239,12 @@ parse_error_type parse_line_building(char *buf)
     case 'A': {
         if (tokenize(s + 2, 8, zz, 0) >= 7) {
             int action_index = atoi(zz[0]);
-            strcpy(building[index].act_names[action_index], zz[1]);
-            building[index].member_costs[action_index] = (PRICE)atoi(zz[2]);
-            building[index].other_costs[action_index] = (PRICE)atoi(zz[3]);
-            building[index].letters[action_index] = zz[4][0];
-            building[index].actions[action_index] = static_cast<int16_t>(atoi(zz[5]));
-            building[index].action_restr[action_index] = static_cast<int16_t>(atoi(zz[6]));
+            strcpy(buildings[index].act_names[action_index], zz[1]);
+            buildings[index].member_costs[action_index] = (PRICE)atoi(zz[2]);
+            buildings[index].other_costs[action_index] = (PRICE)atoi(zz[3]);
+            buildings[index].letters[action_index] = zz[4][0];
+            buildings[index].actions[action_index] = static_cast<int16_t>(atoi(zz[5]));
+            buildings[index].action_restr[action_index] = static_cast<int16_t>(atoi(zz[6]));
             break;
         }
 
@@ -252,7 +254,7 @@ parse_error_type parse_line_building(char *buf)
         auto pct_max = PLAYER_CLASS_TYPE_MAX;
         auto n = tokenize(s + 2, pct_max, zz, 0);
         for (auto i = 0; i < pct_max; i++) {
-            building[index].member_class[i] = (i < n) ? atoi(zz[i]) : 1;
+            buildings[index].member_class[i] = (i < n) ? atoi(zz[i]) : 1;
         }
 
         break;
@@ -260,7 +262,7 @@ parse_error_type parse_line_building(char *buf)
     case 'R': {
         auto n = tokenize(s + 2, MAX_RACES, zz, 0);
         for (int i = 0; i < MAX_RACES; i++) {
-            building[index].member_race[i] = (i < n) ? atoi(zz[i]) : 1;
+            buildings[index].member_race[i] = (i < n) ? atoi(zz[i]) : 1;
         }
 
         break;
@@ -269,7 +271,7 @@ parse_error_type parse_line_building(char *buf)
         int n;
         n = tokenize(s + 2, MAX_MAGIC, zz, 0);
         for (int i = 0; i < MAX_MAGIC; i++) {
-            building[index].member_realm[i + 1] = ((i < n) ? static_cast<int16_t>(atoi(zz[i])) : 1);
+            buildings[index].member_realm[i + 1] = ((i < n) ? static_cast<int16_t>(atoi(zz[i])) : 1);
         }
 
         break;
index 75dc5e1..240b0cf 100644 (file)
@@ -1,9 +1,10 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/object-ego.h"
 #include "system/angband.h"
 #include <functional>
 #include <string_view>
+#include <tuple>
 
 enum class FixedArtifactId : short;
 enum parse_error_type : int;
@@ -26,6 +27,6 @@ struct angband_header;
 class FloorType;
 
 using Parser = std::function<errr(std::string_view, angband_header *)>;
-errr init_info_txt(FILE *fp, char *buf, angband_header *head, Parser parse_info_txt_line);
+std::tuple<errr, int> init_info_txt(FILE *fp, char *buf, angband_header *head, Parser parse_info_txt_line);
 parse_error_type parse_line_feature(FloorType *floor_ptr, char *buf);
 parse_error_type parse_line_building(char *buf);
index f208b11..20bb16d 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/info-reader-util.h"
+#include "info-reader/info-reader-util.h"
 #include "artifact/random-art-effects.h"
 #include "main/angband-headers.h"
 #include "object-enchant/activation-info-table.h"
@@ -16,24 +16,20 @@ int error_line; /*!< データ読み込み/初期化時に汎用的にエラー
  * @param what 参照元の文字列ポインタ
  * @return 発動能力ID
  */
-RandomArtActType grab_one_activation_flag(concptr what)
+RandomArtActType grab_one_activation_flag(std::string_view what)
 {
-    for (auto i = 0;; i++) {
-        if (activation_info[i].flag == nullptr) {
-            break;
-        }
-
-        if (streq(what, activation_info[i].flag)) {
-            return activation_info[i].index;
+    for (const auto &activation : activation_info) {
+        if (what == activation.flag) {
+            return activation.index;
         }
     }
 
-    auto j = atoi(what);
+    auto j = std::stoi(what.data());
     if (j > 0) {
         return i2enum<RandomArtActType>(j);
     }
 
-    msg_format(_("未知の発動・フラグ '%s'。", "Unknown activation flag '%s'."), what);
+    msg_format(_("未知の発動・フラグ '%s'。", "Unknown activation flag '%s'."), what.data());
     return RandomArtActType::NONE;
 }
 
index 7008e12..a439b89 100644 (file)
@@ -1,7 +1,9 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
 #include "util/bit-flags-calculator.h"
+#include <concepts>
+#include <map>
+#include <optional>
 #include <string>
 #include <string_view>
 #include <unordered_map>
  * Size of memory reserved for initialization of some arrays
  */
 extern int error_idx; //!< エラーが発生したinfo ID
-extern int error_line; //!< エラーが発生した行
 
 enum class RandomArtActType : short;
-RandomArtActType grab_one_activation_flag(concptr what);
+RandomArtActType grab_one_activation_flag(std::string_view what);
 
 #ifndef JP
 void append_english_text(std::string &text, std::string_view add);
 #endif
 
+/// @note clang-formatによるconceptの整形が安定していないので抑制しておく
+// clang-format off
+/*!
+ * @brief 型Keyをキーとして持つような連想配列型のコンセプト
+ * std::mapやstd::unordered_mapなどが該当する
+ */
+template <typename T, typename Key>
+concept DictIndexedBy = requires(T t, Key k) {
+    std::same_as<typename T::key_type, Key>;
+    typename T::mapped_type;
+    { t.find(k) } -> std::same_as<typename T::iterator>;
+    { t.find(k)->second } -> std::convertible_to<typename T::mapped_type>;
+    { t.end() } -> std::same_as<typename T::iterator>;
+};
+// clang-format on
+
+/*!
+ * @brief info文字列から定数を取得し、それを返す
+ * @param dict 文字列辞書
+ * @param what 文字列
+ * @return 見つけたら定数を返す。見つからなければnulloptを返す
+ */
+template <typename Key, DictIndexedBy<Key> Dict>
+std::optional<typename Dict::mapped_type> info_get_const(const Dict &dict, Key &&what)
+{
+    if (auto it = dict.find(what); it != dict.end()) {
+        return it->second;
+    }
+    return std::nullopt;
+}
+
 /*!
  * @brief infoフラグ文字列をフラグビットに変換する
  * @param flags ビットフラグ変数
- * @param names フラグ文字列変換表
+ * @param dict フラグ文字列変換表
  * @param what フラグ文字列
  * @return 見つけたらtrue
  */
-template <typename T>
-bool info_grab_one_flag(uint32_t &flags, const std::unordered_map<std::string_view, T> &names, std::string_view what)
+template <typename Key, DictIndexedBy<Key> Dict>
+bool info_grab_one_flag(uint32_t &flags, const Dict &dict, Key &&what)
 {
-    if (auto it = names.find(what); it != names.end()) {
+    if (auto it = dict.find(what); it != dict.end()) {
         set_bits(flags, it->second);
         return true;
     }
@@ -37,6 +69,24 @@ bool info_grab_one_flag(uint32_t &flags, const std::unordered_map<std::string_vi
 }
 
 /*!
+ * @brief info文字列を定数に変換する
+ * @param buf 格納変数
+ * @param dict 定数文字列変換表
+ * @param what 定数文字列
+ * @return 見つけたらtrue
+ */
+template <typename Key, DictIndexedBy<Key> Dict>
+bool info_grab_one_const(uint32_t &buf, const Dict &dict, Key &&what)
+{
+    auto val = info_get_const(dict, std::forward<Key>(what));
+    if (val) {
+        buf = static_cast<uint32_t>(*val);
+        return true;
+    }
+    return false;
+}
+
+/*!
  * @brief infoパラメータに値をセットする
  * @param パラメータ変数
  * @val 値
index cc1b850..1250130 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/magic-reader.h"
+#include "info-reader/magic-reader.h"
 #include "info-reader/info-reader-util.h"
 #include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
index 3245254..e74ad10 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 3900479..3a94a68 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum parse_error_type : int {
     PARSE_ERROR_NONE = 0,
index aac612e..9eab09b 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/race-info-tokens-table.h"
+#include "info-reader/race-info-tokens-table.h"
 #include "monster-attack/monster-attack-effect.h"
 #include "monster-attack/monster-attack-table.h"
 #include "monster-race/race-ability-flags.h"
@@ -7,6 +7,7 @@
 #include "monster-race/race-feature-flags.h"
 #include "monster-race/race-kind-flags.h"
 #include "monster-race/race-population-flags.h"
+#include "monster-race/race-sex-const.h"
 #include "monster-race/race-speak-flags.h"
 #include "monster-race/race-visual-flags.h"
 #include "monster-race/race-wilderness-flags.h"
@@ -84,6 +85,7 @@ const std::unordered_map<std::string_view, RaceBlowEffectType> r_info_blow_effec
     { "INERTIA", RaceBlowEffectType::INERTIA },
     { "STUN", RaceBlowEffectType::STUN },
     { "HUNGRY", RaceBlowEffectType::HUNGRY },
+    { "CHAOS", RaceBlowEffectType::CHAOS },
     { "FLAVOR", RaceBlowEffectType::FLAVOR },
 };
 
@@ -93,8 +95,6 @@ const std::unordered_map<std::string_view, RaceBlowEffectType> r_info_blow_effec
  */
 const std::unordered_map<std::string_view, race_flags1> r_info_flags1 = {
     { "QUESTOR", RF1_QUESTOR },
-    { "MALE", RF1_MALE },
-    { "FEMALE", RF1_FEMALE },
     { "FORCE_DEPTH", RF1_FORCE_DEPTH },
     { "FORCE_MAXHP", RF1_FORCE_MAXHP },
     { "FORCE_EXTRA", RF1_FORCE_EXTRA },
@@ -123,18 +123,6 @@ const std::unordered_map<std::string_view, race_flags2> r_info_flags2 = {
 };
 
 /*!
- * モンスター特性トークンの定義3 /
- * Monster race flags
- */
-const std::unordered_map<std::string_view, race_flags3> r_info_flags3 = {
-    { "FLAGS3_XX10", RF3_XX10 },
-    { "NO_FEAR", RF3_NO_FEAR },
-    { "NO_STUN", RF3_NO_STUN },
-    { "NO_CONF", RF3_NO_CONF },
-    { "NO_SLEEP", RF3_NO_SLEEP }
-};
-
-/*!
  * モンスター特性トークン (発動型能力) /
  * Monster race flags
  */
@@ -186,6 +174,7 @@ const std::unordered_map<std::string_view, MonsterAbilityType> r_info_ability_fl
        {"BA_DARK", MonsterAbilityType::BA_DARK },
        {"BA_VOID", MonsterAbilityType::BA_VOID },
        {"BA_ABYSS", MonsterAbilityType::BA_ABYSS },
+       {"BA_METEOR", MonsterAbilityType::BA_METEOR },
        {"DRAIN_MANA", MonsterAbilityType::DRAIN_MANA },
        {"MIND_BLAST", MonsterAbilityType::MIND_BLAST },
        {"BRAIN_SMASH", MonsterAbilityType::BRAIN_SMASH },
@@ -205,6 +194,8 @@ const std::unordered_map<std::string_view, MonsterAbilityType> r_info_ability_fl
        {"BO_ICEE", MonsterAbilityType::BO_ICEE },
        {"BO_VOID", MonsterAbilityType::BO_VOID },
        {"BO_ABYSS", MonsterAbilityType::BO_ABYSS },
+       {"BO_METEOR", MonsterAbilityType::BO_METEOR },
+       {"BO_LITE", MonsterAbilityType::BO_LITE },
        {"MISSILE", MonsterAbilityType::MISSILE },
        {"SCARE", MonsterAbilityType::SCARE },
        {"BLIND", MonsterAbilityType::BLIND },
@@ -244,6 +235,7 @@ const std::unordered_map<std::string_view, MonsterAbilityType> r_info_ability_fl
        {"S_HI_DRAGON", MonsterAbilityType::S_HI_DRAGON },
        {"S_AMBERITES", MonsterAbilityType::S_AMBERITES },
        {"S_UNIQUE", MonsterAbilityType::S_UNIQUE },
+       {"S_DEAD_UNIQUE", MonsterAbilityType::S_DEAD_UNIQUE },
 };
 /* clang-format on */
 
@@ -253,7 +245,6 @@ const std::unordered_map<std::string_view, MonsterAbilityType> r_info_ability_fl
  * HOGE は、MonsterRaceDefinitions で定義したモンスター種族ID
  */
 const std::unordered_map<std::string_view, race_flags7> r_info_flags7 = {
-    { "UNIQUE2", RF7_UNIQUE2 },
     { "RIDING", RF7_RIDING },
     { "KAGE", RF7_KAGE },
     { "CHAMELEON", RF7_CHAMELEON },
@@ -324,6 +315,13 @@ const std::unordered_map<std::string_view, MonsterResistanceType> r_info_flagsr
     { "RES_ABYSS", MonsterResistanceType::RESIST_ABYSS },
     { "HURT_VOID", MonsterResistanceType::HURT_VOID_MAGIC },
     { "RES_VOID", MonsterResistanceType::RESIST_VOID_MAGIC },
+    { "HURT_METEOR", MonsterResistanceType::HURT_METEOR },
+    { "RES_METEOR", MonsterResistanceType::RESIST_METEOR },
+    { "NO_FEAR", MonsterResistanceType::NO_FEAR },
+    { "NO_STUN", MonsterResistanceType::NO_STUN },
+    { "NO_CONF", MonsterResistanceType::NO_CONF },
+    { "NO_SLEEP", MonsterResistanceType::NO_SLEEP },
+    { "NO_INSTANTLY_DEATH", MonsterResistanceType::NO_INSTANTLY_DEATH }
 };
 
 const std::unordered_map<std::string_view, MonsterAuraType> r_info_aura_flags = {
@@ -436,6 +434,7 @@ const std::unordered_map<std::string_view, MonsterFeatureType> r_info_feature_fl
 
 const std::unordered_map<std::string_view, MonsterPopulationType> r_info_population_flags = {
     { "NAZGUL", MonsterPopulationType::NAZGUL },
+    { "ONLY_ONE", MonsterPopulationType::ONLY_ONE },
 };
 
 const std::unordered_map<std::string_view, MonsterSpeakType> r_info_speak_flags = {
@@ -457,3 +456,9 @@ const std::unordered_map<std::string_view, MonsterBrightnessType> r_info_brightn
     { "HAS_DARK_2", MonsterBrightnessType::HAS_DARK_2 },
     { "SELF_DARK_2", MonsterBrightnessType::SELF_DARK_2 },
 };
+
+const std::unordered_map<std::string_view, MonsterSex> r_info_sex = {
+    { "NONE", MonsterSex::NONE },
+    { "MALE", MonsterSex::MALE },
+    { "FEMALE", MonsterSex::FEMALE },
+};
index 21256e4..1c2afe6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "monster-attack/monster-attack-effect.h"
 #include "monster-attack/monster-attack-table.h"
@@ -16,6 +16,7 @@
 #include "monster-race/race-flags8.h"
 #include "monster-race/race-kind-flags.h"
 #include "monster-race/race-population-flags.h"
+#include "monster-race/race-sex-const.h"
 #include "monster-race/race-speak-flags.h"
 #include "monster-race/race-visual-flags.h"
 #include "monster-race/race-wilderness-flags.h"
@@ -30,7 +31,6 @@ extern const std::unordered_map<std::string_view, RaceBlowMethodType> r_info_blo
 extern const std::unordered_map<std::string_view, RaceBlowEffectType> r_info_blow_effect;
 extern const std::unordered_map<std::string_view, race_flags1> r_info_flags1;
 extern const std::unordered_map<std::string_view, race_flags2> r_info_flags2;
-extern const std::unordered_map<std::string_view, race_flags3> r_info_flags3;
 extern const std::unordered_map<std::string_view, MonsterAbilityType> r_info_ability_flags;
 extern const std::unordered_map<std::string_view, race_flags7> r_info_flags7;
 extern const std::unordered_map<std::string_view, race_flags8> r_info_flags8;
@@ -45,3 +45,4 @@ extern const std::unordered_map<std::string_view, MonsterFeatureType> r_info_fea
 extern const std::unordered_map<std::string_view, MonsterPopulationType> r_info_population_flags;
 extern const std::unordered_map<std::string_view, MonsterSpeakType> r_info_speak_flags;
 extern const std::unordered_map<std::string_view, MonsterBrightnessType> r_info_brightness_flags;
+extern const std::unordered_map<std::string_view, MonsterSex> r_info_sex;
index c9e04b7..3ddc31e 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/race-reader.h"
+#include "info-reader/race-reader.h"
 #include "info-reader/info-reader-util.h"
 #include "info-reader/parse-error-types.h"
 #include "info-reader/race-info-tokens-table.h"
@@ -28,10 +28,6 @@ static bool grab_one_basic_flag(MonsterRaceInfo *r_ptr, std::string_view what)
         return true;
     }
 
-    if (info_grab_one_flag(r_ptr->flags3, r_info_flags3, what)) {
-        return true;
-    }
-
     if (info_grab_one_flag(r_ptr->flags7, r_info_flags7, what)) {
         return true;
     }
@@ -148,18 +144,21 @@ errr parse_monraces_info(std::string_view buf, angband_header *)
     } else if (tokens[0] == "D") {
         // D:text_ja
         // D:$text_en
-        if (tokens.size() < 2 || tokens[1].size() == 0) {
+        if (tokens.size() < 2 || buf.length() < 3) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
 #ifdef JP
-        if (tokens[1][0] == '$') {
+        if (buf[2] == '$') {
             return PARSE_ERROR_NONE;
         }
         r_ptr->text.append(buf.substr(2));
 #else
-        if (tokens[1][0] != '$') {
+        if (buf[2] != '$') {
             return PARSE_ERROR_NONE;
         }
+        if (buf.length() == 3) {
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        }
         append_english_text(r_ptr->text, buf.substr(3));
 #endif
     } else if (tokens[0] == "G") {
@@ -229,7 +228,7 @@ errr parse_monraces_info(std::string_view buf, angband_header *)
         // B:blow_type:blow_effect:dice
         size_t i = 0;
         for (; i < 4; i++) {
-            if (r_ptr->blow[i].method == RaceBlowMethodType::NONE) {
+            if (r_ptr->blows[i].method == RaceBlowMethodType::NONE) {
                 break;
             }
         }
@@ -255,16 +254,16 @@ errr parse_monraces_info(std::string_view buf, angband_header *)
             return PARSE_ERROR_INVALID_FLAG;
         }
 
-        r_ptr->blow[i].method = rbm->second;
-        r_ptr->blow[i].effect = rbe->second;
+        r_ptr->blows[i].method = rbm->second;
+        r_ptr->blows[i].effect = rbe->second;
 
         if (tokens.size() < 4) {
             return PARSE_ERROR_NONE;
         }
 
         const auto &dice = str_split(tokens[3], 'd', false, 2);
-        info_set_value(r_ptr->blow[i].d_dice, dice[0]);
-        info_set_value(r_ptr->blow[i].d_side, dice[1]);
+        info_set_value(r_ptr->blows[i].d_dice, dice[0]);
+        info_set_value(r_ptr->blows[i].d_side, dice[1]);
     } else if (tokens[0] == "F") {
         // F:flags
         if (tokens.size() < 2 || tokens[1].size() == 0) {
@@ -327,6 +326,16 @@ errr parse_monraces_info(std::string_view buf, angband_header *)
         info_set_value(a_idx, tokens[1]);
         info_set_value(chance, tokens[2]);
         r_ptr->drop_artifacts.emplace_back(a_idx, chance);
+    } else if (tokens[0] == "X") {
+        if (tokens.size() < 2) {
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        }
+        uint32_t sex;
+        if (!info_grab_one_const(sex, r_info_sex, tokens[1])) {
+            return PARSE_ERROR_INVALID_FLAG;
+        }
+        r_ptr->sex = static_cast<MonsterSex>(sex);
+
     } else if (tokens[0] == "V") {
         // V:arena_odds
         if (tokens.size() < 2) {
index 3e36533..3563af9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index cd6176b..b368ad9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* Random dungeon grid effects */
 enum rdge_type {
index 1527579..70ed101 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/skill-reader.h"
+#include "info-reader/skill-reader.h"
 #include "info-reader/info-reader-util.h"
 #include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
index 88adad1..12593d3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index ba0ba9d..08cf319 100644 (file)
@@ -1,4 +1,4 @@
-#include "info-reader/vault-reader.h"
+#include "info-reader/vault-reader.h"
 #include "info-reader/info-reader-util.h"
 #include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
@@ -41,7 +41,7 @@ errr parse_vaults_info(std::string_view buf, angband_header *)
         return PARSE_ERROR_MISSING_RECORD_HEADER;
     } else if (tokens[0] == "D") {
         // D:MapText
-        if (tokens.size() < 2 || tokens[1].size() == 0) {
+        if (tokens.size() < 2 || buf.length() < 3) {
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
         }
 
index 0aa58a4..5050a87 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 95ee7b0..6adbefb 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief オブジェクト選択処理
  * @date 2020/07/02
  * @author Hourier
@@ -27,6 +27,7 @@
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
@@ -258,7 +259,8 @@ bool get_item_floor(PlayerType *player_ptr, COMMAND_CODE *cp, concptr pmt, concp
 
     fis_ptr->floor_num = 0;
     if (fis_ptr->floor) {
-        fis_ptr->floor_num = scan_floor_items(player_ptr, fis_ptr->floor_list, player_ptr->y, player_ptr->x, SCAN_FLOOR_ITEM_TESTER | SCAN_FLOOR_ONLY_MARKED, item_tester);
+        constexpr auto options = SCAN_FLOOR_ITEM_TESTER | SCAN_FLOOR_ONLY_MARKED;
+        fis_ptr->floor_num = scan_floor_items(player_ptr, fis_ptr->floor_list, player_ptr->y, player_ptr->x, options, item_tester);
     }
 
     if ((mode & USE_INVEN) && (fis_ptr->i1 <= fis_ptr->i2)) {
@@ -303,6 +305,11 @@ bool get_item_floor(PlayerType *player_ptr, COMMAND_CODE *cp, concptr pmt, concp
         screen_save();
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+    };
     while (!fis_ptr->done) {
         int ni = 0;
         int ne = 0;
@@ -311,21 +318,21 @@ bool get_item_floor(PlayerType *player_ptr, COMMAND_CODE *cp, concptr pmt, concp
                 continue;
             }
 
-            if (window_flag[i] & PW_INVENTORY) {
+            if (g_window_flags[i].has(SubWindowRedrawingFlag::INVENTORY)) {
                 ni++;
             }
 
-            if (window_flag[i] & PW_EQUIPMENT) {
+            if (g_window_flags[i].has(SubWindowRedrawingFlag::EQUIPMENT)) {
                 ne++;
             }
         }
 
         if ((command_wrk == (USE_EQUIP) && ni && !ne) || (command_wrk == (USE_INVEN) && !ni && ne)) {
-            toggle_inventory_equipment(player_ptr);
+            toggle_inventory_equipment();
             fis_ptr->toggle = !fis_ptr->toggle;
         }
 
-        player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT);
+        rfu.set_flags(flags);
         handle_stuff(player_ptr);
         COMMAND_CODE get_item_label = 0;
         if (command_wrk == USE_INVEN) {
@@ -664,10 +671,10 @@ bool get_item_floor(PlayerType *player_ptr, COMMAND_CODE *cp, concptr pmt, concp
                 g_ptr->o_idx_list.rotate(player_ptr->current_floor_ptr);
             }
 
-            player_ptr->window_flags |= PW_FLOOR_ITEMS;
+            rfu.set_flag(SubWindowRedrawingFlag::FLOOR_ITEMS);
             window_stuff(player_ptr);
-
-            fis_ptr->floor_num = scan_floor_items(player_ptr, fis_ptr->floor_list, player_ptr->y, player_ptr->x, SCAN_FLOOR_ITEM_TESTER | SCAN_FLOOR_ONLY_MARKED, item_tester);
+            constexpr auto options = SCAN_FLOOR_ITEM_TESTER | SCAN_FLOOR_ONLY_MARKED;
+            fis_ptr->floor_num = scan_floor_items(player_ptr, fis_ptr->floor_list, player_ptr->y, player_ptr->x, options, item_tester);
             if (command_see) {
                 screen_load();
                 screen_save();
@@ -877,10 +884,10 @@ bool get_item_floor(PlayerType *player_ptr, COMMAND_CODE *cp, concptr pmt, concp
     }
 
     if (fis_ptr->toggle) {
-        toggle_inventory_equipment(player_ptr);
+        toggle_inventory_equipment();
     }
 
-    player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT);
+    rfu.set_flags(flags);
     handle_stuff(player_ptr);
     prt("", 0, 0);
     if (fis_ptr->oops && str) {
index a39639d..32d56ba 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 #include "system/angband.h"
index 4620aff..83460d9 100644 (file)
@@ -1,9 +1,7 @@
-#include "inventory/inventory-curse.h"
+#include "inventory/inventory-curse.h"
 #include "artifact/fixed-art-types.h"
 #include "core/asking-player.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "inventory/inventory-slot-types.h"
@@ -15,7 +13,6 @@
 #include "object-enchant/special-object-flags.h"
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
-#include "object/object-flags.h"
 #include "perception/object-perception.h"
 #include "player-base/player-race.h"
 #include "player-info/race-types.h"
 #include "spell/summon-types.h"
 #include "status/bad-status-setter.h"
 #include "status/buff-setter.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 #include <optional>
 #include <string>
 
+// clang-format off
 namespace {
-const EnumClassFlagGroup<CurseTraitType> TRC_P_FLAG_MASK({ CurseTraitType::TY_CURSE, CurseTraitType::DRAIN_EXP, CurseTraitType::ADD_L_CURSE, CurseTraitType::ADD_H_CURSE, CurseTraitType::CALL_ANIMAL, CurseTraitType::CALL_DEMON,
-    CurseTraitType::CALL_DRAGON, CurseTraitType::COWARDICE, CurseTraitType::TELEPORT, CurseTraitType::DRAIN_HP, CurseTraitType::DRAIN_MANA, CurseTraitType::CALL_UNDEAD, CurseTraitType::BERS_RAGE, CurseTraitType::PERSISTENT_CURSE });
-const EnumClassFlagGroup<CurseSpecialTraitType> TRCS_P_FLAG_MASK({ CurseSpecialTraitType::TELEPORT_SELF, CurseSpecialTraitType::CHAINSWORD });
+const EnumClassFlagGroup<CurseTraitType> TRC_P_FLAG_MASK({
+    CurseTraitType::TY_CURSE,
+    CurseTraitType::DRAIN_EXP,
+    CurseTraitType::ADD_L_CURSE,
+    CurseTraitType::ADD_H_CURSE,
+    CurseTraitType::CALL_ANIMAL,
+    CurseTraitType::CALL_DEMON,
+    CurseTraitType::CALL_DRAGON,
+    CurseTraitType::COWARDICE,
+    CurseTraitType::TELEPORT,
+    CurseTraitType::DRAIN_HP,
+    CurseTraitType::DRAIN_MANA,
+    CurseTraitType::CALL_UNDEAD,
+    CurseTraitType::BERS_RAGE,
+    CurseTraitType::PERSISTENT_CURSE });
+const EnumClassFlagGroup<CurseSpecialTraitType> TRCS_P_FLAG_MASK({
+    CurseSpecialTraitType::TELEPORT_SELF,
+    CurseSpecialTraitType::CHAINSWORD });
 }
+// clang-format on
 
 static bool is_specific_curse(CurseTraitType flag)
 {
@@ -75,7 +90,7 @@ static void choise_cursed_item(CurseTraitType flag, ItemEntity *o_ptr, int *choi
     }
 
     tr_type cf = TR_STR;
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
     switch (flag) {
     case CurseTraitType::ADD_L_CURSE:
         cf = TR_ADD_L_CURSE;
@@ -186,7 +201,7 @@ static void curse_teleport(PlayerType *player_ptr)
             continue;
         }
 
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
 
         if (flags.has_not(TR_TELEPORT)) {
             continue;
@@ -205,7 +220,7 @@ static void curse_teleport(PlayerType *player_ptr)
     o_ptr = &player_ptr->inventory_list[i_keep];
     const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
     msg_format(_("%sがテレポートの能力を発動させようとしている。", "Your %s tries to teleport you."), item_name.data());
-    if (get_check_strict(player_ptr, _("テレポートしますか?", "Teleport? "), CHECK_OKAY_CANCEL)) {
+    if (input_check_strict(player_ptr, _("テレポートしますか?", "Teleport? "), UserCheck::OKAY_CANCEL)) {
         disturb(player_ptr, false, true);
         teleport_player(player_ptr, 50, TELEPORT_SPONTANEOUS);
     } else {
@@ -225,8 +240,8 @@ static void occur_chainsword_effect(PlayerType *player_ptr)
     }
 
     const auto noise = get_random_line(_("chainswd_j.txt", "chainswd.txt"), 0);
-    if (noise.has_value()) {
-        msg_print(noise.value());
+    if (noise) {
+        msg_print(*noise);
     }
 
     disturb(player_ptr, false, false);
@@ -267,7 +282,7 @@ static void multiply_low_curse(PlayerType *player_ptr)
     o_ptr->curse_flags.set(new_curse);
     msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), item_name.data());
     o_ptr->feeling = FEEL_NONE;
-    player_ptr->update |= (PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 static void multiply_high_curse(PlayerType *player_ptr)
@@ -287,7 +302,7 @@ static void multiply_high_curse(PlayerType *player_ptr)
     o_ptr->curse_flags.set(new_curse);
     msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), item_name.data());
     o_ptr->feeling = FEEL_NONE;
-    player_ptr->update |= (PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 static void persist_curse(PlayerType *player_ptr)
@@ -306,7 +321,7 @@ static void persist_curse(PlayerType *player_ptr)
     o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
     msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), item_name.data());
     o_ptr->feeling = FEEL_NONE;
-    player_ptr->update |= (PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 static void curse_call_monster(PlayerType *player_ptr)
@@ -406,9 +421,10 @@ static void curse_drain_hp(PlayerType *player_ptr)
         return;
     }
 
-    const auto item_name = describe_flavor(player_ptr, choose_cursed_obj_name(player_ptr, CurseTraitType::DRAIN_HP), (OD_OMIT_PREFIX | OD_NAME_ONLY));
+    const auto *item_ptr = choose_cursed_obj_name(player_ptr, CurseTraitType::DRAIN_HP);
+    const auto item_name = describe_flavor(player_ptr, item_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
     msg_format(_("%sはあなたの体力を吸収した!", "Your %s drains HP from you!"), item_name.data());
-    take_hit(player_ptr, DAMAGE_LOSELIFE, std::min(player_ptr->lev * 2, 100), item_name.data());
+    take_hit(player_ptr, DAMAGE_LOSELIFE, std::min(player_ptr->lev * 2, 100), item_name);
 }
 
 static void curse_drain_mp(PlayerType *player_ptr)
@@ -417,7 +433,8 @@ static void curse_drain_mp(PlayerType *player_ptr)
         return;
     }
 
-    const auto item_name = describe_flavor(player_ptr, choose_cursed_obj_name(player_ptr, CurseTraitType::DRAIN_MANA), (OD_OMIT_PREFIX | OD_NAME_ONLY));
+    const auto *item_ptr = choose_cursed_obj_name(player_ptr, CurseTraitType::DRAIN_MANA);
+    const auto item_name = describe_flavor(player_ptr, item_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
     msg_format(_("%sはあなたの魔力を吸収した!", "Your %s drains mana from you!"), item_name.data());
     player_ptr->csp -= std::min<short>(player_ptr->lev, 50);
     if (player_ptr->csp < 0) {
@@ -425,12 +442,14 @@ static void curse_drain_mp(PlayerType *player_ptr)
         player_ptr->csp_frac = 0;
     }
 
-    player_ptr->redraw |= PR_MP;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
 }
 
 static void occur_curse_effects(PlayerType *player_ptr)
 {
-    if ((player_ptr->cursed.has_none_of(TRC_P_FLAG_MASK) && player_ptr->cursed_special.has_none_of(TRCS_P_FLAG_MASK)) || player_ptr->phase_out || player_ptr->wild_mode) {
+    auto is_cursed = player_ptr->cursed.has_any_of(TRC_P_FLAG_MASK);
+    is_cursed |= player_ptr->cursed_special.has_any_of(TRCS_P_FLAG_MASK);
+    if (!is_cursed || AngbandSystem::get_instance().is_phase_out() || player_ptr->wild_mode) {
         return;
     }
 
index ccc2482..1a6b018 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 4321f84..42a45a1 100644 (file)
@@ -1,4 +1,4 @@
-#include "inventory/inventory-damage.h"
+#include "inventory/inventory-damage.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "inventory/inventory-object.h"
index d3bc344..c1dd553 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/object-broken.h"
 
index b4dfaa0..29fe4e4 100644 (file)
@@ -1,4 +1,4 @@
-#include "inventory/inventory-describer.h"
+#include "inventory/inventory-describer.h"
 #include "game-option/birth-options.h"
 #include "inventory/inventory-slot-types.h"
 #include "player/player-status-flags.h"
index 7118017..8da2877 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 867c22f..0b70cca 100644 (file)
@@ -1,5 +1,4 @@
-#include "inventory/inventory-object.h"
-#include "core/player-update-types.h"
+#include "inventory/inventory-object.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "floor/floor-object.h"
 #include "spell-realm/spells-craft.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/object-sort.h"
 #include "view/display-messages.h"
 #include "view/object-describer.h"
 
-void vary_item(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
+void vary_item(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER num)
 {
-    if (item >= 0) {
-        inven_item_increase(player_ptr, item, num);
-        inven_item_describe(player_ptr, item);
-        inven_item_optimize(player_ptr, item);
+    if (i_idx >= 0) {
+        inven_item_increase(player_ptr, i_idx, num);
+        inven_item_describe(player_ptr, i_idx);
+        inven_item_optimize(player_ptr, i_idx);
         return;
     }
 
-    floor_item_increase(player_ptr, 0 - item, num);
-    floor_item_describe(player_ptr, 0 - item);
-    floor_item_optimize(player_ptr, 0 - item);
+    floor_item_increase(player_ptr, 0 - i_idx, num);
+    floor_item_describe(player_ptr, 0 - i_idx);
+    floor_item_optimize(player_ptr, 0 - i_idx);
 }
 
 /*!
- * @brief アイテムを増減させ残り所持数メッセージを表示する /
- * Increase the "number" of an item in the inventory
+ * @brief アイテムを増減させ残り所持数メッセージを表示する
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 所持数を増やしたいプレイヤーのアイテム所持スロット
+ * @param i_idx 所持数を増やしたいプレイヤーのアイテム所持スロット
  * @param num 増やしたい量
  */
-void inven_item_increase(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER num)
+void inven_item_increase(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER num)
 {
-    auto *o_ptr = &player_ptr->inventory_list[item];
+    auto *o_ptr = &player_ptr->inventory_list[i_idx];
     num += o_ptr->number;
     if (num > 255) {
         num = 255;
@@ -54,18 +53,27 @@ void inven_item_increase(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER
     }
 
     o_ptr->number += num;
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->update |= (PU_MP);
-    player_ptr->update |= (PU_COMBINATION);
-    player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::COMBINATION,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+    };
+    rfu.set_flags(flags_swrf);
     if (o_ptr->number || !player_ptr->ele_attack) {
         return;
     }
-    if (!(item == INVEN_MAIN_HAND) && !(item == INVEN_SUB_HAND)) {
+
+    if (!(i_idx == INVEN_MAIN_HAND) && !(i_idx == INVEN_SUB_HAND)) {
         return;
     }
-    if (has_melee_weapon(player_ptr, enum2i(INVEN_MAIN_HAND + INVEN_SUB_HAND) - item)) {
+
+    if (has_melee_weapon(player_ptr, enum2i(INVEN_MAIN_HAND + INVEN_SUB_HAND) - i_idx)) {
         return;
     }
 
@@ -73,14 +81,13 @@ void inven_item_increase(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER
 }
 
 /*!
- * @brief 所持アイテムスロットから所持数のなくなったアイテムを消去する /
- * Erase an inventory slot if it has no more items
+ * @brief 所持アイテムスロットから所持数のなくなったアイテムを消去する
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 消去したいプレイヤーのアイテム所持スロット
+ * @param i_idx 消去したいプレイヤーのアイテム所持スロット
  */
-void inven_item_optimize(PlayerType *player_ptr, INVENTORY_IDX item)
+void inven_item_optimize(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
-    auto *o_ptr = &player_ptr->inventory_list[item];
+    auto *o_ptr = &player_ptr->inventory_list[i_idx];
     if (!o_ptr->is_valid()) {
         return;
     }
@@ -88,43 +95,49 @@ void inven_item_optimize(PlayerType *player_ptr, INVENTORY_IDX item)
         return;
     }
 
-    if (item >= INVEN_MAIN_HAND) {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    if (i_idx >= INVEN_MAIN_HAND) {
         player_ptr->equip_cnt--;
-        (&player_ptr->inventory_list[item])->wipe();
-        player_ptr->update |= PU_BONUS;
-        player_ptr->update |= PU_TORCH;
-        player_ptr->update |= PU_MP;
-
-        player_ptr->window_flags |= PW_EQUIPMENT;
-        player_ptr->window_flags |= PW_SPELL;
+        (&player_ptr->inventory_list[i_idx])->wipe();
+        static constexpr auto flags_srf = {
+            StatusRecalculatingFlag::BONUS,
+            StatusRecalculatingFlag::TORCH,
+            StatusRecalculatingFlag::MP,
+        };
+        rfu.set_flags(flags_srf);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::EQUIPMENT,
+            SubWindowRedrawingFlag::SPELL,
+        };
+        rfu.set_flags(flags_swrf);
         return;
     }
 
     player_ptr->inven_cnt--;
     int i;
-    for (i = item; i < INVEN_PACK; i++) {
+    for (i = i_idx; i < INVEN_PACK; i++) {
         player_ptr->inventory_list[i] = player_ptr->inventory_list[i + 1];
     }
 
     (&player_ptr->inventory_list[i])->wipe();
-    player_ptr->window_flags |= PW_INVENTORY;
-    player_ptr->window_flags |= PW_SPELL;
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags);
 }
 
 /*!
- * @brief 所持スロットから床下にオブジェクトを落とすメインルーチン /
- * Drop (some of) a non-cursed inventory/equipment item
+ * @brief 所持スロットから床下にオブジェクトを落とすメインルーチン
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 所持テーブルのID
+ * @param i_idx 所持テーブルのID
  * @param amt 落としたい個数
- * @details
- * The object will be dropped "near" the current location
  */
-void drop_from_inventory(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
+void drop_from_inventory(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER amt)
 {
     ItemEntity forge;
     ItemEntity *q_ptr;
-    auto *o_ptr = &player_ptr->inventory_list[item];
+    auto *o_ptr = &player_ptr->inventory_list[i_idx];
     if (amt <= 0) {
         return;
     }
@@ -133,9 +146,9 @@ void drop_from_inventory(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER
         amt = o_ptr->number;
     }
 
-    if (item >= INVEN_MAIN_HAND) {
-        item = inven_takeoff(player_ptr, item, amt);
-        o_ptr = &player_ptr->inventory_list[item];
+    if (i_idx >= INVEN_MAIN_HAND) {
+        i_idx = inven_takeoff(player_ptr, i_idx, amt);
+        o_ptr = &player_ptr->inventory_list[i_idx];
     }
 
     q_ptr = &forge;
@@ -144,9 +157,9 @@ void drop_from_inventory(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER
 
     q_ptr->number = amt;
     const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
-    msg_format(_("%s(%c)を落とした。", "You drop %s (%c)."), item_name.data(), index_to_label(item));
+    msg_format(_("%s(%c)を落とした。", "You drop %s (%c)."), item_name.data(), index_to_label(i_idx));
     (void)drop_near(player_ptr, q_ptr, 0, player_ptr->y, player_ptr->x);
-    vary_item(player_ptr, item, -amt);
+    vary_item(player_ptr, i_idx, -amt);
 }
 
 /*!
@@ -214,7 +227,7 @@ void combine_pack(PlayerType *player_ptr)
                     }
                 }
 
-                player_ptr->window_flags |= (PW_INVENTORY);
+                RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::INVENTORY);
                 combined = true;
                 break;
             }
@@ -271,7 +284,7 @@ void reorder_pack(PlayerType *player_ptr)
         }
 
         (&player_ptr->inventory_list[j])->copy_from(q_ptr);
-        player_ptr->window_flags |= (PW_INVENTORY);
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::INVENTORY);
     }
 
     if (flag) {
@@ -280,24 +293,10 @@ void reorder_pack(PlayerType *player_ptr)
 }
 
 /*!
- * @brief オブジェクトをプレイヤーが拾って所持スロットに納めるメインルーチン /
- * Add an item to the players inventory, and return the slot used.
+ * @brief オブジェクトをプレイヤーが拾って所持スロットに納めるメインルーチン
+ * @param player_ptr プレイヤーへの参照ポインタ
  * @param o_ptr 拾うオブジェクトの構造体参照ポインタ
  * @return 収められた所持スロットのID、拾うことができなかった場合-1を返す。
- * @details
- * If the new item can combine with an existing item in the inventory,\n
- * it will do so, using "object_similar()" and "object_absorb()", else,\n
- * the item will be placed into the "proper" location in the inventory.\n
- *\n
- * This function can be used to "over-fill" the player's pack, but only\n
- * once, and such an action must trigger the "overflow" code immediately.\n
- * Note that when the pack is being "over-filled", the new item must be\n
- * placed into the "overflow" slot, and the "overflow" must take place\n
- * before the pack is reordered, but (optionally) after the pack is\n
- * combined.  This may be tricky.  See "dungeon.c" for info.\n
- *\n
- * Note that this code must remove any location/stack information\n
- * from the object once it is placed into the inventory.\n
  */
 int16_t store_item_to_inventory(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
@@ -305,6 +304,11 @@ int16_t store_item_to_inventory(PlayerType *player_ptr, ItemEntity *o_ptr)
     INVENTORY_IDX n = -1;
 
     ItemEntity *j_ptr;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::PLAYER,
+    };
     for (j = 0; j < INVEN_PACK; j++) {
         j_ptr = &player_ptr->inventory_list[j];
         if (!j_ptr->is_valid()) {
@@ -314,9 +318,8 @@ int16_t store_item_to_inventory(PlayerType *player_ptr, ItemEntity *o_ptr)
         n = j;
         if (object_similar(j_ptr, o_ptr)) {
             object_absorb(j_ptr, o_ptr);
-
-            player_ptr->update |= (PU_BONUS);
-            player_ptr->window_flags |= (PW_INVENTORY | PW_PLAYER);
+            rfu.set_flag(StatusRecalculatingFlag::BONUS);
+            rfu.set_flags(flags_swrf);
             return j;
         }
     }
@@ -356,9 +359,13 @@ int16_t store_item_to_inventory(PlayerType *player_ptr, ItemEntity *o_ptr)
     j_ptr->marked.clear().set(OmType::TOUCHED);
 
     player_ptr->inven_cnt++;
-    player_ptr->update |= (PU_BONUS | PU_COMBINATION | PU_REORDER);
-    player_ptr->window_flags |= (PW_INVENTORY | PW_PLAYER);
-
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flags(flags_swrf);
     return i;
 }
 
@@ -390,26 +397,20 @@ bool check_store_item_to_inventory(PlayerType *player_ptr, const ItemEntity *o_p
 }
 
 /*!
- * @brief 装備スロットからオブジェクトを外すメインルーチン /
- * Take off (some of) a non-cursed equipment item
+ * @brief 装備スロットから装備を外すメインルーチン
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item オブジェクトを外したい所持テーブルのID
+ * @param i_idx 装備を外したいインベントリのID
  * @param amt 外したい個数
  * @return 収められた所持スロットのID、拾うことができなかった場合-1を返す。
- * @details
- * Note that only one item at a time can be wielded per slot.\n
- * Note that taking off an item when "full" may cause that item\n
- * to fall to the ground.\n
- * Return the inventory slot into which the item is placed.\n
  */
-INVENTORY_IDX inven_takeoff(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER amt)
+INVENTORY_IDX inven_takeoff(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER amt)
 {
     INVENTORY_IDX slot;
     ItemEntity forge;
     ItemEntity *q_ptr;
     ItemEntity *o_ptr;
     concptr act;
-    o_ptr = &player_ptr->inventory_list[item];
+    o_ptr = &player_ptr->inventory_list[i_idx];
     if (amt <= 0) {
         return -1;
     }
@@ -421,18 +422,18 @@ INVENTORY_IDX inven_takeoff(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUM
     q_ptr->copy_from(o_ptr);
     q_ptr->number = amt;
     const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
-    if (((item == INVEN_MAIN_HAND) || (item == INVEN_SUB_HAND)) && o_ptr->is_melee_weapon()) {
+    if (((i_idx == INVEN_MAIN_HAND) || (i_idx == INVEN_SUB_HAND)) && o_ptr->is_melee_weapon()) {
         act = _("を装備からはずした", "You were wielding");
-    } else if (item == INVEN_BOW) {
+    } else if (i_idx == INVEN_BOW) {
         act = _("を装備からはずした", "You were holding");
-    } else if (item == INVEN_LITE) {
+    } else if (i_idx == INVEN_LITE) {
         act = _("を光源からはずした", "You were holding");
     } else {
         act = _("を装備からはずした", "You were wearing");
     }
 
-    inven_item_increase(player_ptr, item, -amt);
-    inven_item_optimize(player_ptr, item);
+    inven_item_increase(player_ptr, i_idx, -amt);
+    inven_item_optimize(player_ptr, i_idx);
 
     slot = store_item_to_inventory(player_ptr, q_ptr);
 #ifdef JP
index 246d5d9..c458776 100644 (file)
@@ -1,15 +1,15 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 class ItemEntity;
 class PlayerType;
-void vary_item(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER num);
-void inven_item_increase(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER num);
-void inven_item_optimize(PlayerType *player_ptr, INVENTORY_IDX item);
-void drop_from_inventory(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER amt);
+void vary_item(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER num);
+void inven_item_increase(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER num);
+void inven_item_optimize(PlayerType *player_ptr, INVENTORY_IDX i_idx);
+void drop_from_inventory(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER amt);
 void combine_pack(PlayerType *player_ptr);
 void reorder_pack(PlayerType *player_ptr);
 int16_t store_item_to_inventory(PlayerType *player_ptr, ItemEntity *o_ptr);
 bool check_store_item_to_inventory(PlayerType *player_ptr, const ItemEntity *o_ptr);
-INVENTORY_IDX inven_takeoff(PlayerType *player_ptr, INVENTORY_IDX item, ITEM_NUMBER amt);
+INVENTORY_IDX inven_takeoff(PlayerType *player_ptr, INVENTORY_IDX i_idx, ITEM_NUMBER amt);
index d69096a..48d05f1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum inventory_slot_type {
     INVEN_PACK = 23, /*!< アイテムスロット…所持品(0~) */
index ab09198..54597ed 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief インベントリ関係のユーティリティ
  * @date 2020/07/02
  * @author Hourier
@@ -15,8 +15,8 @@
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "util/bit-flags-calculator.h"
 #include "util/int-char-converter.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include <sstream>
 
@@ -192,24 +192,22 @@ bool get_item_okay(PlayerType *player_ptr, OBJECT_IDX i, const ItemTester &item_
 }
 
 /*!
- * @brief 選択したアイテムの確認処理のメインルーチン /
+ * @brief 選択したアイテムの確認処理のメインルーチン
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 選択アイテムID
+ * @param i_idx 選択アイテムID
  * @return 確認がYesならTRUEを返す。
- * @details The item can be negative to mean "item on floor".
- * Hack -- allow user to "prevent" certain choices
  */
-bool get_item_allow(PlayerType *player_ptr, INVENTORY_IDX item)
+bool get_item_allow(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
     if (!command_cmd) {
         return true;
     }
 
     ItemEntity *o_ptr;
-    if (item >= 0) {
-        o_ptr = &player_ptr->inventory_list[item];
+    if (i_idx >= 0) {
+        o_ptr = &player_ptr->inventory_list[i_idx];
     } else {
-        o_ptr = &player_ptr->current_floor_ptr->o_list[0 - item];
+        o_ptr = &player_ptr->current_floor_ptr->o_list[0 - i_idx];
     }
 
     if (!o_ptr->is_inscribed()) {
@@ -219,7 +217,7 @@ bool get_item_allow(PlayerType *player_ptr, INVENTORY_IDX item)
     auto s = angband_strchr(o_ptr->inscription->data(), '!');
     while (s) {
         if ((s[1] == command_cmd) || (s[1] == '*')) {
-            if (!verify(player_ptr, _("本当に", "Really try"), item)) {
+            if (!verify(player_ptr, _("本当に", "Really try"), i_idx)) {
                 return false;
             }
         }
@@ -275,21 +273,19 @@ INVENTORY_IDX label_to_inventory(PlayerType *player_ptr, int c)
 }
 
 /*!
- * @brief 選択したアイテムの確認処理の補助 /
- * Verify the choice of an item.
+ * @brief 選択したアイテムの確認処理の補助
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param prompt メッセージ表示の一部
- * @param item 選択アイテムID
+ * @param i_idx 選択アイテムID
  * @return 確認がYesならTRUEを返す。
- * @details The item can be negative to mean "item on floor".
  */
-bool verify(PlayerType *player_ptr, concptr prompt, INVENTORY_IDX item)
+bool verify(PlayerType *player_ptr, concptr prompt, INVENTORY_IDX i_idx)
 {
     ItemEntity *o_ptr;
-    if (item >= 0) {
-        o_ptr = &player_ptr->inventory_list[item];
+    if (i_idx >= 0) {
+        o_ptr = &player_ptr->inventory_list[i_idx];
     } else {
-        o_ptr = &player_ptr->current_floor_ptr->o_list[0 - item];
+        o_ptr = &player_ptr->current_floor_ptr->o_list[0 - i_idx];
     }
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
@@ -299,7 +295,7 @@ bool verify(PlayerType *player_ptr, concptr prompt, INVENTORY_IDX item)
     ss << ' ';
 #endif
     ss << item_name << _("ですか? ", "? ");
-    return get_check(ss.str());
+    return input_check(ss.str());
 }
 
 /*!
@@ -312,7 +308,7 @@ bool verify(PlayerType *player_ptr, concptr prompt, INVENTORY_IDX item)
 void prepare_label_string(PlayerType *player_ptr, char *label, BIT_FLAGS mode, const ItemTester &item_tester)
 {
     concptr alphabet_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-    int offset = (mode == USE_EQUIP) ? INVEN_MAIN_HAND : 0;
+    int offset = match_bits(mode, USE_EQUIP, USE_EQUIP) ? INVEN_MAIN_HAND : 0;
     strcpy(label, alphabet_chars);
     for (int i = 0; i < 52; i++) {
         COMMAND_CODE index;
index 0798290..33154f6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 #include "system/angband.h"
@@ -10,8 +10,8 @@ bool is_ring_slot(int i);
 bool get_tag_floor(FloorType *floor_ptr, COMMAND_CODE *cp, char tag, FLOOR_IDX floor_list[], ITEM_NUMBER floor_num);
 bool get_tag(PlayerType *player_ptr, COMMAND_CODE *cp, char tag, BIT_FLAGS mode, const ItemTester &item_tester);
 bool get_item_okay(PlayerType *player_ptr, OBJECT_IDX i, const ItemTester &item_tester);
-bool get_item_allow(PlayerType *player_ptr, INVENTORY_IDX item);
+bool get_item_allow(PlayerType *player_ptr, INVENTORY_IDX i_idx);
 INVENTORY_IDX label_to_equipment(PlayerType *player_ptr, int c);
 INVENTORY_IDX label_to_inventory(PlayerType *player_ptr, int c);
-bool verify(PlayerType *player_ptr, concptr prompt, INVENTORY_IDX item);
+bool verify(PlayerType *player_ptr, concptr prompt, INVENTORY_IDX i_idx);
 void prepare_label_string(PlayerType *player_ptr, char *label, BIT_FLAGS mode, const ItemTester &item_tester);
index a5ba037..71604a8 100644 (file)
@@ -1,4 +1,4 @@
-#include "inventory/item-getter.h"
+#include "inventory/item-getter.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "game-option/input-options.h"
@@ -21,6 +21,7 @@
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
@@ -82,15 +83,15 @@ static bool check_item_tag_aux(PlayerType *player_ptr, item_selection_type *item
  */
 static bool check_item_tag_inventory(PlayerType *player_ptr, item_selection_type *item_selection_ptr, char *prev_tag, const ItemTester &item_tester)
 {
-    if ((!item_selection_ptr->inven || (*item_selection_ptr->cp < 0) || (*item_selection_ptr->cp >= INVEN_PACK)) && (!item_selection_ptr->equip || (*item_selection_ptr->cp < INVEN_MAIN_HAND) || (*item_selection_ptr->cp >= INVEN_TOTAL))) {
+    auto should_check = !item_selection_ptr->inven || (*item_selection_ptr->cp < 0) || (*item_selection_ptr->cp >= INVEN_PACK);
+    should_check &= !item_selection_ptr->equip || (*item_selection_ptr->cp < INVEN_MAIN_HAND) || (*item_selection_ptr->cp >= INVEN_TOTAL);
+    if (should_check) {
         return false;
     }
 
     if (*prev_tag && command_cmd) {
-
-        bool flag = false;
-        item_use_flag use_flag = (*item_selection_ptr->cp >= INVEN_MAIN_HAND) ? USE_EQUIP : USE_INVEN;
-
+        auto flag = false;
+        const auto use_flag = (*item_selection_ptr->cp >= INVEN_MAIN_HAND) ? USE_EQUIP : USE_INVEN;
         flag |= !get_tag(player_ptr, &item_selection_ptr->k, *prev_tag, use_flag, item_tester);
         flag |= !get_item_okay(player_ptr, item_selection_ptr->k, item_tester);
 
@@ -294,6 +295,11 @@ bool get_item(PlayerType *player_ptr, OBJECT_IDX *cp, concptr pmt, concptr str,
         screen_save();
     }
 
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+    };
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     while (!item_selection_ptr->done) {
         COMMAND_CODE get_item_label = 0;
         int ni = 0;
@@ -303,21 +309,21 @@ bool get_item(PlayerType *player_ptr, OBJECT_IDX *cp, concptr pmt, concptr str,
                 continue;
             }
 
-            if (window_flag[i] & (PW_INVENTORY)) {
+            if (g_window_flags[i].has(SubWindowRedrawingFlag::INVENTORY)) {
                 ni++;
             }
 
-            if (window_flag[i] & (PW_EQUIPMENT)) {
+            if (g_window_flags[i].has(SubWindowRedrawingFlag::EQUIPMENT)) {
                 ne++;
             }
         }
 
         if ((command_wrk && ni && !ne) || (!command_wrk && !ni && ne)) {
-            toggle_inventory_equipment(player_ptr);
+            toggle_inventory_equipment();
             item_selection_ptr->toggle = !item_selection_ptr->toggle;
         }
 
-        player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT);
+        rfu.set_flags(flags);
         handle_stuff(player_ptr);
 
         if (!command_wrk) {
@@ -637,10 +643,10 @@ bool get_item(PlayerType *player_ptr, OBJECT_IDX *cp, concptr pmt, concptr str,
     }
 
     if (item_selection_ptr->toggle) {
-        toggle_inventory_equipment(player_ptr);
+        toggle_inventory_equipment();
     }
 
-    player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT);
+    rfu.set_flags(flags);
     handle_stuff(player_ptr);
     prt("", 0, 0);
     if (item_selection_ptr->oops && str) {
index ebe91d4..b8abec7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 4a934ca..ee3dd69 100644 (file)
@@ -1,4 +1,4 @@
-#include "inventory/item-selection-util.h"
+#include "inventory/item-selection-util.h"
 #include "io/input-key-requester.h"
 #include "object/item-use-flags.h"
 
index 9e07d5f..7aa9ce6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 #include "system/angband.h"
index 6c16d88..a302722 100644 (file)
@@ -1,4 +1,4 @@
-#include "inventory/pack-overflow.h"
+#include "inventory/pack-overflow.h"
 #include "core/disturbance.h"
 #include "core/stuff-handler.h"
 #include "flavor/flavor-describer.h"
index 8870728..a57469e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void pack_overflow(PlayerType *player_ptr);
index d646300..8ffd756 100644 (file)
@@ -1,9 +1,7 @@
-#include "inventory/player-inventory.h"
+#include "inventory/player-inventory.h"
 #include "autopick/autopick.h"
 #include "core/asking-player.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "dungeon/quest.h"
@@ -30,6 +28,7 @@
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "term/z-form.h"
 #include "util/string-processor.h"
@@ -54,8 +53,9 @@ bool can_get_item(PlayerType *player_ptr, const ItemTester &item_tester)
         }
     }
 
+    constexpr auto mode = SCAN_FLOOR_ITEM_TESTER | SCAN_FLOOR_ONLY_MARKED;
     OBJECT_IDX floor_list[23];
-    ITEM_NUMBER floor_num = scan_floor_items(player_ptr, floor_list, player_ptr->y, player_ptr->x, SCAN_FLOOR_ITEM_TESTER | SCAN_FLOOR_ONLY_MARKED, item_tester);
+    ITEM_NUMBER floor_num = scan_floor_items(player_ptr, floor_list, player_ptr->y, player_ptr->x, mode, item_tester);
     return floor_num != 0;
 }
 
@@ -65,12 +65,12 @@ bool can_get_item(PlayerType *player_ptr, const ItemTester &item_tester)
  */
 static bool py_pickup_floor_aux(PlayerType *player_ptr)
 {
-    OBJECT_IDX this_o_idx;
-    OBJECT_IDX item;
-    concptr q = _("どれを拾いますか?", "Get which item? ");
-    concptr s = _("もうザックには床にあるどのアイテムも入らない。", "You no longer have any room for the objects on the floor.");
-    if (choose_object(player_ptr, &item, q, s, (USE_FLOOR), FuncItemTester(check_store_item_to_inventory, player_ptr))) {
-        this_o_idx = 0 - item;
+    short this_o_idx;
+    short i_idx;
+    constexpr auto q = _("どれを拾いますか?", "Get which item? ");
+    constexpr auto s = _("もうザックには床にあるどのアイテムも入らない。", "You no longer have any room for the objects on the floor.");
+    if (choose_object(player_ptr, &i_idx, q, s, (USE_FLOOR), FuncItemTester(check_store_item_to_inventory, player_ptr))) {
+        this_o_idx = 0 - i_idx;
     } else {
         return false;
     }
@@ -91,6 +91,7 @@ void py_pickup_floor(PlayerType *player_ptr, bool pickup)
     OBJECT_IDX floor_o_idx = 0;
     int can_pickup = 0;
     auto &o_idx_list = player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].o_idx_list;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     for (auto it = o_idx_list.begin(); it != o_idx_list.end();) {
         const OBJECT_IDX this_o_idx = *it++;
         auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
@@ -101,8 +102,8 @@ void py_pickup_floor(PlayerType *player_ptr, bool pickup)
             msg_format(mes, (long)o_ptr->pval, item_name.data());
             sound(SOUND_SELL);
             player_ptr->au += o_ptr->pval;
-            player_ptr->redraw |= (PR_GOLD);
-            player_ptr->window_flags |= (PW_PLAYER);
+            rfu.set_flag(MainWindowRedrawingFlag::GOLD);
+            rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
             delete_object_idx(player_ptr, this_o_idx);
             continue;
         } else if (o_ptr->marked.has(OmType::SUPRESS_MESSAGE)) {
@@ -165,7 +166,7 @@ void py_pickup_floor(PlayerType *player_ptr, bool pickup)
     auto *o_ptr = &player_ptr->current_floor_ptr->o_list[floor_o_idx];
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
     strnfmt(out_val, sizeof(out_val), _("%sを拾いますか? ", "Pick up %s? "), item_name.data());
-    if (!get_check(out_val)) {
+    if (!input_check(out_val)) {
         return;
     }
 
@@ -225,10 +226,10 @@ void describe_pickup_item(PlayerType *player_ptr, OBJECT_IDX o_idx)
         }
     }
 
-    angband_strcpy(record_o_name, old_item_name.data(), old_item_name.length());
+    angband_strcpy(record_o_name, old_item_name, old_item_name.length());
 #else
     msg_format("You have %s (%c).", item_name.data(), index_to_label(slot));
-    angband_strcpy(record_o_name, item_name.data(), item_name.length());
+    angband_strcpy(record_o_name, item_name, item_name.length());
 #endif
     record_turn = w_ptr->game_turn;
     check_find_art_quest_completion(player_ptr, o_ptr);
@@ -242,9 +243,10 @@ void describe_pickup_item(PlayerType *player_ptr, OBJECT_IDX o_idx)
 void carry(PlayerType *player_ptr, bool pickup)
 {
     verify_panel(player_ptr);
-    player_ptr->update |= PU_MONSTER_STATUSES;
-    player_ptr->redraw |= PR_MAP;
-    player_ptr->window_flags |= PW_OVERHEAD;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    rfu.set_flag(SubWindowRedrawingFlag::OVERHEAD);
     handle_stuff(player_ptr);
     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
     autopick_pickup_items(player_ptr, g_ptr);
@@ -264,8 +266,8 @@ void carry(PlayerType *player_ptr, bool pickup)
             msg_format(_(" $%ld の価値がある%sを見つけた。", "You collect %ld gold pieces worth of %s."), (long)value, item_name.data());
             sound(SOUND_SELL);
             player_ptr->au += value;
-            player_ptr->redraw |= (PR_GOLD);
-            player_ptr->window_flags |= (PW_PLAYER);
+            rfu.set_flag(MainWindowRedrawingFlag::GOLD);
+            rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
             continue;
         }
 
@@ -288,7 +290,7 @@ void carry(PlayerType *player_ptr, bool pickup)
         if (carry_query_flag) {
             char out_val[MAX_NLEN + 20];
             strnfmt(out_val, sizeof(out_val), _("%sを拾いますか? ", "Pick up %s? "), item_name.data());
-            is_pickup_successful = get_check(out_val);
+            is_pickup_successful = input_check(out_val);
         }
 
         if (is_pickup_successful) {
index c0cbb93..5238ee5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 #include "system/angband.h"
index e318bc5..99a5980 100644 (file)
@@ -1,4 +1,4 @@
-#include "inventory/recharge-processor.h"
+#include "inventory/recharge-processor.h"
 #include "core/disturbance.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
@@ -10,7 +10,7 @@
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
-#include "util/quarks.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 
@@ -71,8 +71,9 @@ void recharge_magic_items(PlayerType *player_ptr)
         }
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (changed) {
-        player_ptr->window_flags |= (PW_EQUIPMENT);
+        rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
         wild_regen = 20;
     }
 
@@ -109,7 +110,7 @@ void recharge_magic_items(PlayerType *player_ptr)
     }
 
     if (changed) {
-        player_ptr->window_flags |= (PW_INVENTORY);
+        rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
         wild_regen = 20;
     }
 
index dbd54c8..4925441 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void recharge_magic_items(PlayerType *player_ptr);
index 8f8a883..c26a5b5 100644 (file)
@@ -1,4 +1,4 @@
-#include "io-dump/character-dump.h"
+#include "io-dump/character-dump.h"
 #include "artifact/fixed-art-types.h"
 #include "avatar/avatar.h"
 #include "cmd-building/cmd-building.h"
@@ -39,6 +39,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "term/gameterm.h"
 #include "term/z-form.h"
 #include "util/enum-converter.h"
 #include "util/int-char-converter.h"
@@ -145,18 +146,20 @@ static void dump_aux_last_message(PlayerType *player_ptr, FILE *fff)
     if (!w_ptr->total_winner) {
         fprintf(fff, _("\n  [死ぬ直前のメッセージ]\n\n", "\n  [Last Messages]\n\n"));
         for (int i = std::min(message_num(), 30); i >= 0; i--) {
-            fprintf(fff, "> %s\n", message_str((int16_t)i));
+            fprintf(fff, "> %s\n", message_str(i)->data());
         }
 
         fputc('\n', fff);
         return;
     }
 
-    if (player_ptr->last_message) {
-        fprintf(fff, _("\n  [*勝利*メッセージ]\n\n", "\n  [*Winning* Message]\n\n"));
-        fprintf(fff, "  %s\n", player_ptr->last_message);
-        fputc('\n', fff);
+    if (player_ptr->last_message.empty()) {
+        return;
     }
+
+    fprintf(fff, _("\n  [*勝利*メッセージ]\n\n", "\n  [*Winning* Message]\n\n"));
+    fprintf(fff, "  %s\n", player_ptr->last_message.data());
+    fputc('\n', fff);
 }
 
 /*!
@@ -260,16 +263,18 @@ static void dump_aux_arena(PlayerType *player_ptr, FILE *fff)
         return;
     }
 
-    if (player_ptr->arena_number < 0) {
-        if (player_ptr->arena_number <= ARENA_DEFEATED_OLD_VER) {
+    const auto arena_number = player_ptr->arena_number;
+    if (arena_number < 0) {
+        if (arena_number <= ARENA_DEFEATED_OLD_VER) {
             fprintf(fff, _("\n 闘技場: 敗北\n", "\n Arena: Defeated\n"));
         } else {
+            constexpr auto mes = _("\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_monrace = monraces_info[arena.r_idx];
 #ifdef JP
-            fprintf(
-                fff, "\n 闘技場: %d回戦で%sの前に敗北\n", -player_ptr->arena_number, monraces_info[arena_info[-1 - player_ptr->arena_number].r_idx].name.data());
+            fprintf(fff, mes, -arena_number, arena_monrace.name.data());
 #else
-            fprintf(fff, "\n Arena: Defeated by %s in the %d%s fight\n", monraces_info[arena_info[-1 - player_ptr->arena_number].r_idx].name.data(),
-                -player_ptr->arena_number, get_ordinal_number_suffix(-player_ptr->arena_number));
+            fprintf(fff, mes, arena_monrace.name.data(), -arena_number, get_ordinal_number_suffix(-arena_number).data());
 #endif
         }
 
@@ -277,23 +282,23 @@ static void dump_aux_arena(PlayerType *player_ptr, FILE *fff)
         return;
     }
 
-    if (player_ptr->arena_number > MAX_ARENA_MONS + 2) {
+    if (arena_number > MAX_ARENA_MONS + 2) {
         fprintf(fff, _("\n 闘技場: 真のチャンピオン\n", "\n Arena: True Champion\n"));
         fprintf(fff, "\n");
         return;
     }
 
-    if (player_ptr->arena_number > MAX_ARENA_MONS - 1) {
+    if (arena_number > MAX_ARENA_MONS - 1) {
         fprintf(fff, _("\n 闘技場: チャンピオン\n", "\n Arena: Champion\n"));
         fprintf(fff, "\n");
         return;
     }
 
+    const auto victory_count = arena_number > MAX_ARENA_MONS ? MAX_ARENA_MONS : arena_number;
 #ifdef JP
-    fprintf(fff, "\n 闘技場: %2d勝\n", (player_ptr->arena_number > MAX_ARENA_MONS ? MAX_ARENA_MONS : player_ptr->arena_number));
+    fprintf(fff, "\n 闘技場: %2d勝\n", victory_count);
 #else
-    fprintf(fff, "\n Arena: %2d Victor%s\n", (player_ptr->arena_number > MAX_ARENA_MONS ? MAX_ARENA_MONS : player_ptr->arena_number),
-        (player_ptr->arena_number > 1) ? "ies" : "y");
+    fprintf(fff, "\n Arena: %2d %s\n", victory_count, (arena_number > 1) ? "Victories" : "Victory");
 #endif
     fprintf(fff, "\n");
 }
@@ -312,26 +317,26 @@ static void dump_aux_monsters(PlayerType *player_ptr, FILE *fff)
 
     /* Count monster kills */
     auto norm_total = 0;
-    for (const auto &[r_idx, r_ref] : monraces_info) {
+    for (const auto &[monrace_id, monrace] : monraces_info) {
         /* Ignore unused index */
-        if (!MonsterRace(r_ref.idx).is_valid() || r_ref.name.empty()) {
+        if (!MonsterRace(monrace_id).is_valid()) {
             continue;
         }
 
-        if (r_ref.kind_flags.has(MonsterKindType::UNIQUE)) {
-            bool dead = (r_ref.max_num == 0);
+        if (monrace.kind_flags.has(MonsterKindType::UNIQUE)) {
+            auto dead = (monrace.max_num == 0);
             if (dead) {
                 norm_total++;
 
                 /* Add a unique monster to the list */
-                who.push_back(r_ref.idx);
+                who.push_back(monrace.idx);
             }
 
             continue;
         }
 
-        if (r_ref.r_pkills > 0) {
-            norm_total += r_ref.r_pkills;
+        if (monrace.r_pkills > 0) {
+            norm_total += monrace.r_pkills;
         }
     }
 
@@ -532,7 +537,7 @@ static void dump_aux_equipment_inventory(PlayerType *player_ptr, FILE *fff)
  */
 static void dump_aux_home_museum(PlayerType *player_ptr, FILE *fff)
 {
-    const auto *store_ptr = &towns_info[1].store[enum2i(StoreSaleType::HOME)];
+    const auto *store_ptr = &towns_info[1].stores[StoreSaleType::HOME];
     if (store_ptr->stock_num) {
         fprintf(fff, _("  [我が家のアイテム]\n", "  [Home Inventory]\n"));
         auto page = 1;
@@ -548,7 +553,7 @@ static void dump_aux_home_museum(PlayerType *player_ptr, FILE *fff)
         fprintf(fff, "\n\n");
     }
 
-    store_ptr = &towns_info[1].store[enum2i(StoreSaleType::MUSEUM)];
+    store_ptr = &towns_info[1].stores[StoreSaleType::MUSEUM];
 
     if (store_ptr->stock_num == 0) {
         return;
@@ -575,9 +580,24 @@ static void dump_aux_home_museum(PlayerType *player_ptr, FILE *fff)
  */
 static std::string get_check_sum(void)
 {
-    return format("%02x%02x%02x%02x%02x%02x%02x%02x%02x", terrains_header.checksum, baseitems_header.checksum,
-        artifacts_header.checksum, egos_header.checksum, monraces_header.checksum, dungeons_header.checksum,
-        class_magics_header.checksum, class_skills_header.checksum, vaults_header.checksum);
+    static constexpr auto headers = {
+        &artifacts_header,
+        &baseitems_header,
+        &class_magics_header,
+        &class_skills_header,
+        &dungeons_header,
+        &egos_header,
+        &monraces_header,
+        &terrains_header,
+        &vaults_header,
+    };
+
+    util::SHA256 sha256;
+    for (const auto *header : headers) {
+        sha256.update(header->digest.data(), header->digest.size());
+    }
+
+    return util::to_string(sha256.digest());
 }
 
 /*!
@@ -589,7 +609,7 @@ static std::string get_check_sum(void)
  */
 void make_character_dump(PlayerType *player_ptr, FILE *fff)
 {
-    TermCenteredOffsetSetter tos(std::nullopt, std::nullopt);
+    TermCenteredOffsetSetter tos(MAIN_TERM_MIN_COLS, std::nullopt);
 
     fprintf(fff, _("  [%s キャラクタ情報]\n\n", "  [%s Character Dump]\n\n"), get_version().data());
 
@@ -610,5 +630,7 @@ void make_character_dump(PlayerType *player_ptr, FILE *fff)
     dump_aux_equipment_inventory(player_ptr, fff);
     dump_aux_home_museum(player_ptr, fff);
 
-    fprintf(fff, _("  [チェックサム: \"%s\"]\n\n", "  [Check Sum: \"%s\"]\n\n"), get_check_sum().data());
+    // ダンプの幅をはみ出さないように48文字目以降を切り捨てる
+    const auto checksum = get_check_sum().erase(48);
+    fprintf(fff, _("  [チェックサム: \"%s\"]\n\n", "  [Check Sum: \"%s\"]\n\n"), checksum.data());
 }
index efeea8f..4adf25d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f0a901d..e970578 100644 (file)
@@ -1,4 +1,4 @@
-#include "io-dump/dump-remover.h"
+#include "io-dump/dump-remover.h"
 #include "io-dump/dump-util.h"
 #include "io/read-pref-file.h"
 #include "term/z-form.h"
index 85186e2..3ee062a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <filesystem>
 #include <string_view>
index 3d5d198..6c0f7f1 100644 (file)
@@ -1,4 +1,4 @@
-#include "io-dump/dump-util.h"
+#include "io-dump/dump-util.h"
 #include "floor/geometry.h"
 #include "game-option/keymap-directory-getter.h"
 #include "game-option/special-options.h"
@@ -64,8 +64,8 @@ bool visual_mode_command(char ch, bool *visual_list_ptr,
         }
 
         *visual_list_ptr = true;
-        *attr_top_ptr = std::max<byte>(0, (*cur_attr_ptr & 0x7f) - 5);
-        *char_left_ptr = std::max<byte>(0, *cur_char_ptr - 10);
+        *attr_top_ptr = std::max<int8_t>(0, (*cur_attr_ptr & 0x7f) - 5);
+        *char_left_ptr = std::max<int8_t>(0, *cur_char_ptr - 10);
         attr_old = *cur_attr_ptr;
         char_old = *cur_char_ptr;
         return true;
@@ -85,7 +85,7 @@ bool visual_mode_command(char ch, bool *visual_list_ptr,
     case 'p': {
         if (attr_idx || (!(char_idx & 0x80) && char_idx)) {
             *cur_attr_ptr = attr_idx;
-            *attr_top_ptr = std::max<byte>(0, (*cur_attr_ptr & 0x7f) - 5);
+            *attr_top_ptr = std::max<int8_t>(0, (*cur_attr_ptr & 0x7f) - 5);
             if (!*visual_list_ptr) {
                 *need_redraw = true;
             }
@@ -94,7 +94,7 @@ bool visual_mode_command(char ch, bool *visual_list_ptr,
         if (char_idx) {
             /* Set the char */
             *cur_char_ptr = char_idx;
-            *char_left_ptr = std::max<byte>(0, *cur_char_ptr - 10);
+            *char_left_ptr = std::max<int8_t>(0, *cur_char_ptr - 10);
             if (!*visual_list_ptr) {
                 *need_redraw = true;
             }
@@ -277,8 +277,7 @@ void browser_cursor(char ch, int *column, IDX *grp_cur, int grp_cnt, IDX *list_c
 
     if ((ddx[d] > 0) && ddy[d]) {
         int browser_rows;
-        int wid, hgt;
-        term_get_size(&wid, &hgt);
+        const auto &[wid, hgt] = term_get_size();
         browser_rows = hgt - 8;
         if (!col) {
             int old_grp = grp;
index cdec972..e9d4144 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "system/terrain-type-definition.h"
index afe8120..21f5892 100644 (file)
@@ -1,4 +1,4 @@
-#include "io-dump/player-status-dump.h"
+#include "io-dump/player-status-dump.h"
 #include "view/display-player.h"
 
 /*!
index bfc1909..d022569 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 0753d00..5ca4cf7 100644 (file)
@@ -1,4 +1,4 @@
-#include "io-dump/random-art-info-dumper.h"
+#include "io-dump/random-art-info-dumper.h"
 #include "floor/floor-town.h"
 #include "inventory/inventory-slot-types.h"
 #include "io/files-util.h"
@@ -7,10 +7,12 @@
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
 #include "util/angband-files.h"
+#include "util/finalizer.h"
 #include "view/display-messages.h"
 #include "wizard/artifact-analyzer.h"
 #include "wizard/fixed-artifacts-spoiler.h"
 #include "wizard/spoiler-util.h"
+#include <sstream>
 
 /*!
  * @brief ランダムアーティファクト1件をスポイラー出力する /
  * @param art_ptr 記述内容を収めた構造体参照ポインタ
  * Fill in an object description structure for a given object
  */
-static void spoiler_print_randart(ItemEntity *o_ptr, obj_desc_list *art_ptr)
+static void spoiler_print_randart(ItemEntity *o_ptr, const ArtifactsDumpInfo *art_ptr, std::ofstream &ofs)
 {
-    pval_info_type *pval_ptr = &art_ptr->pval_info;
-    fprintf(spoiler_file, "%s\n", art_ptr->description);
+    const auto finalizer = util::make_finalizer([art_ptr, &ofs]() {
+        ofs << spoiler_indent << art_ptr->misc_desc << "\n\n";
+    });
+    const auto *pval_ptr = &art_ptr->pval_info;
+    ofs << art_ptr->description << '\n';
     if (!o_ptr->is_fully_known()) {
-        fprintf(spoiler_file, _("%s不明\n", "%sUnknown\n"), spoiler_indent);
-    } else {
-        if (pval_ptr->pval_desc[0]) {
-            spoiler_outlist(std::string(pval_ptr->pval_desc).append(_("の修正:", " to")).data(), pval_ptr->pval_affects, item_separator);
-        }
+        ofs << format(_("%s不明\n", "%sUnknown\n"), spoiler_indent.data());
+        return;
+    }
 
-        spoiler_outlist(_("対:", "Slay"), art_ptr->slays, item_separator);
-        spoiler_outlist(_("武器属性:", ""), art_ptr->brands, list_separator);
-        spoiler_outlist(_("免疫:", "Immunity to"), art_ptr->immunities, item_separator);
-        spoiler_outlist(_("耐性:", "Resist"), art_ptr->resistances, item_separator);
-        spoiler_outlist(_("維持:", "Sustain"), art_ptr->sustains, item_separator);
-        spoiler_outlist("", art_ptr->misc_magic, list_separator);
-        if (art_ptr->activation) {
-            fprintf(spoiler_file, _("%s発動: %s\n", "%sActivates for %s\n"), spoiler_indent, art_ptr->activation);
-        }
+    if (!pval_ptr->pval_desc.empty()) {
+        std::stringstream ss;
+        ss << pval_ptr->pval_desc << _("の修正:", " to");
+        spoiler_outlist(ss.str(), pval_ptr->pval_affects, item_separator, ofs);
     }
 
-    fprintf(spoiler_file, "%s%s\n\n", spoiler_indent, art_ptr->misc_desc);
+    spoiler_outlist(_("対:", "Slay"), art_ptr->slays, item_separator, ofs);
+    spoiler_outlist(_("武器属性:", ""), art_ptr->brands, list_separator, ofs);
+    spoiler_outlist(_("免疫:", "Immunity to"), art_ptr->immunities, item_separator, ofs);
+    spoiler_outlist(_("耐性:", "Resist"), art_ptr->resistances, item_separator, ofs);
+    spoiler_outlist(_("維持:", "Sustain"), art_ptr->sustenances, item_separator, ofs);
+    spoiler_outlist("", art_ptr->misc_magic, list_separator, ofs);
+    if (!art_ptr->activation.empty()) {
+        ofs << format(_("%s発動: %s\n", "%sActivates for %s\n"), spoiler_indent.data(), art_ptr->activation.data());
+    }
 }
 
 /*!
@@ -50,63 +56,56 @@ static void spoiler_print_randart(ItemEntity *o_ptr, obj_desc_list *art_ptr)
  * @param o_ptr ランダムアーティファクトのオブジェクト構造体参照ポインタ
  * @param tval 出力したいランダムアーティファクトの種類
  */
-static void spoil_random_artifact_aux(PlayerType *player_ptr, ItemEntity *o_ptr, ItemKindType tval)
+static void spoil_random_artifact_aux(PlayerType *player_ptr, ItemEntity *o_ptr, ItemKindType tval, std::ofstream &ofs)
 {
-    obj_desc_list artifact;
     if (!o_ptr->is_known() || !o_ptr->is_random_artifact() || (o_ptr->bi_key.tval() != tval)) {
         return;
     }
 
-    random_artifact_analyze(player_ptr, o_ptr, &artifact);
-    spoiler_print_randart(o_ptr, &artifact);
+    const auto artifacts_list = random_artifact_analyze(player_ptr, o_ptr);
+    spoiler_print_randart(o_ptr, &artifacts_list, ofs);
 }
 
 /*!
- * @brief ランダムアーティファクト内容をスポイラー出力するメインルーチン /
- * Create a list file for random artifacts
- * @param fname 出力ファイル名
+ * @brief ランダムアーティファクト内容をスポイラー出力するメインルーチン
+ * @param player_ptr プレイヤーへの参照ポインタ
  */
-void spoil_random_artifact(PlayerType *player_ptr, concptr fname)
+void spoil_random_artifact(PlayerType *player_ptr)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
-    spoiler_file = angband_fopen(buf, FileOpenMode::WRITE);
-    if (!spoiler_file) {
+    const auto &path = path_build(ANGBAND_DIR_USER, "randifact.txt");
+    std::ofstream ofs(path);
+    if (!ofs) {
         msg_print("Cannot create list file.");
         return;
     }
 
-    spoiler_underline("Random artifacts list.\r");
+    spoiler_underline("Random artifacts list.\r", ofs);
     for (const auto &[tval_list, name] : group_artifact_list) {
         for (auto tval : tval_list) {
             for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
                 auto *q_ptr = &player_ptr->inventory_list[i];
-                spoil_random_artifact_aux(player_ptr, q_ptr, tval);
+                spoil_random_artifact_aux(player_ptr, q_ptr, tval, ofs);
             }
 
             for (int i = 0; i < INVEN_PACK; i++) {
                 auto *q_ptr = &player_ptr->inventory_list[i];
-                spoil_random_artifact_aux(player_ptr, q_ptr, tval);
+                spoil_random_artifact_aux(player_ptr, q_ptr, tval, ofs);
             }
 
-            const auto *store_ptr = &towns_info[1].store[enum2i(StoreSaleType::HOME)];
+            const auto *store_ptr = &towns_info[1].stores[StoreSaleType::HOME];
             for (int i = 0; i < store_ptr->stock_num; i++) {
                 auto *q_ptr = &store_ptr->stock[i];
-                spoil_random_artifact_aux(player_ptr, q_ptr, tval);
+                spoil_random_artifact_aux(player_ptr, q_ptr, tval, ofs);
             }
 
-            store_ptr = &towns_info[1].store[enum2i(StoreSaleType::MUSEUM)];
+            store_ptr = &towns_info[1].stores[StoreSaleType::MUSEUM];
             for (int i = 0; i < store_ptr->stock_num; i++) {
                 auto *q_ptr = &store_ptr->stock[i];
-                spoil_random_artifact_aux(player_ptr, q_ptr, tval);
+                spoil_random_artifact_aux(player_ptr, q_ptr, tval, ofs);
             }
         }
     }
 
-    if (ferror(spoiler_file) || angband_fclose(spoiler_file)) {
-        msg_print("Cannot close list file.");
-        return;
-    }
-
-    msg_print("Successfully created a list file.");
+    const auto mes = ofs.good() ? "Successfully created a list file." : "Failed to create a list file.";
+    msg_print(mes);
 }
index 7d49fe4..22442c0 100644 (file)
@@ -1,6 +1,4 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 class PlayerType;
-void spoil_random_artifact(PlayerType *player_ptr, concptr fname);
+void spoil_random_artifact(PlayerType *player_ptr);
index 446b01d..69463b4 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 一部職業でのみダンプする能力の出力処理
  * @date 2020/03/07
  * @author Hourier
index 76bb44e..330dfb4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 481d142..1e515f3 100644 (file)
@@ -1,35 +1,35 @@
-#include "io/command-repeater.h"
+#include "io/command-repeater.h"
 #include "io/input-key-requester.h"
 #include "util/int-char-converter.h"
 
 #define REPEAT_MAX 20
 
 /* Number of chars saved */
-static int repeat__cnt = 0;
+static int repeat_counter = 0;
 
 /* Current index */
-static int repeat__idx = 0;
+static int repeat_index = 0;
 
 /* Saved "stuff" */
-static COMMAND_CODE repeat__key[REPEAT_MAX];
+static COMMAND_CODE repeat_keys[REPEAT_MAX];
 
 void repeat_push(COMMAND_CODE what)
 {
-    if (repeat__cnt == REPEAT_MAX) {
+    if (repeat_counter == REPEAT_MAX) {
         return;
     }
 
-    repeat__key[repeat__cnt++] = what;
-    ++repeat__idx;
+    repeat_keys[repeat_counter++] = what;
+    ++repeat_index;
 }
 
 bool repeat_pull(COMMAND_CODE *what)
 {
-    if (repeat__idx == repeat__cnt) {
+    if (repeat_index == repeat_counter) {
         return false;
     }
 
-    *what = repeat__key[repeat__idx++];
+    *what = repeat_keys[repeat_index++];
     return true;
 }
 
@@ -50,13 +50,13 @@ void repeat_check(void)
 
     COMMAND_CODE what;
     if (command_cmd == 'n') {
-        repeat__idx = 0;
+        repeat_index = 0;
         if (repeat_pull(&what)) {
             command_cmd = what;
         }
     } else {
-        repeat__cnt = 0;
-        repeat__idx = 0;
+        repeat_counter = 0;
+        repeat_index = 0;
         what = command_cmd;
         repeat_push(what);
     }
index f9db57f..b6c40b8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 5a40114..01aaba3 100644 (file)
@@ -1,6 +1,4 @@
-#include "io/cursor.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "io/cursor.h"
 #include "core/stuff-handler.h"
 #include "effect/effect-characteristics.h"
 #include "effect/spells-effect-util.h"
 #include "grid/feature.h"
 #include "io/screen-util.h"
 #include "player/player-status.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/projection-path-calculator.h"
 #include "term/term-color-types.h"
@@ -45,8 +45,8 @@ void print_path(PlayerType *player_ptr, POSITION y, POSITION x)
     }
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    projection_path path_g(player_ptr, (project_length ? project_length : get_max_range(player_ptr)), player_ptr->y, player_ptr->x, y, x, PROJECT_PATH | PROJECT_THRU);
-    player_ptr->redraw |= (PR_MAP);
+    projection_path path_g(player_ptr, (project_length ? project_length : AngbandSystem::get_instance().get_max_range()), player_ptr->y, player_ptr->x, y, x, PROJECT_PATH | PROJECT_THRU);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MAP);
     handle_stuff(player_ptr);
     for (const auto &[ny, nx] : path_g) {
         auto *g_ptr = &floor_ptr->grid_array[ny][nx];
@@ -105,9 +105,7 @@ void print_path(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 bool change_panel(PlayerType *player_ptr, POSITION dy, POSITION dx)
 {
-    TERM_LEN wid, hgt;
-    get_screen_size(&wid, &hgt);
-
+    const auto &[wid, hgt] = get_screen_size();
     POSITION y = panel_row_min + dy * hgt / 2;
     POSITION x = panel_col_min + dx * wid / 2;
 
@@ -133,9 +131,9 @@ bool change_panel(PlayerType *player_ptr, POSITION dy, POSITION dx)
     panel_row_min = y;
     panel_col_min = x;
     panel_bounds_center();
-
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-    player_ptr->redraw |= (PR_MAP);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
     handle_stuff(player_ptr);
     return true;
 }
@@ -146,8 +144,7 @@ bool change_panel(PlayerType *player_ptr, POSITION dy, POSITION dx)
  */
 void panel_bounds_center(void)
 {
-    TERM_LEN wid, hgt;
-    get_screen_size(&wid, &hgt);
+    const auto &[wid, hgt] = get_screen_size();
     panel_row_max = panel_row_min + hgt - 1;
     panel_row_prt = panel_row_min - 1;
     panel_col_max = panel_col_min + wid - 1;
index dda9406..9def126 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d5acca9..f3c96eb 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 異常発生時のゲーム緊急終了処理
  * @date 2020/03/01
  * @author Hourier
index 7d7f0b4..c261063 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*
  * Windowsのコードからは呼ばれない。よってVSからは見えない
  */
index 0630988..6531e4e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ファイル入出力管理 / Purpose: code dealing with files (and death)
  * @date 2014/01/28
  * @author
@@ -18,6 +18,7 @@
 #include "io/uid-checker.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
+#include "system/angband-exceptions.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h"
@@ -25,6 +26,9 @@
 #include "util/angband-files.h"
 #include "view/display-messages.h"
 #include <algorithm>
+#ifdef SAVEFILE_USE_UID
+#include "main-unix/unix-user-ids.h"
+#endif
 
 std::filesystem::path ANGBAND_DIR; //!< Path name: The main "lib" directory This variable is not actually used anywhere in the code
 std::filesystem::path ANGBAND_DIR_APEX; //!< High score files (binary) These files may be portable between platforms
@@ -41,13 +45,9 @@ std::filesystem::path ANGBAND_DIR_DEBUG_SAVE; //*< Savefiles for debug data
 std::filesystem::path ANGBAND_DIR_USER; //!< User "preference" files (ascii) These files are rarely portable between platforms
 std::filesystem::path ANGBAND_DIR_XTRA; //!< Various extra files (binary) These files are rarely portable between platforms
 
-/*
- * Buffer to hold the current savefile name
- * 'savefile' holds full path name. 'savefile_base' holds only base name.
- */
-char savefile[1024];
-char savefile_base[40];
-char debug_savefile[1024];
+std::filesystem::path savefile;
+std::string savefile_base;
+std::filesystem::path debug_savefile;
 
 /*!
  * @brief プレイヤーステータスをファイルダンプ出力する
@@ -59,39 +59,48 @@ char debug_savefile[1024];
  * Allow the "full" flag to dump additional info,
  * and trigger its usage from various places in the code.
  */
-errr file_character(PlayerType *player_ptr, concptr name)
+void file_character(PlayerType *player_ptr, std::string_view filename)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
-    auto fd = fd_open(buf, O_RDONLY);
+    const auto &path = path_build(ANGBAND_DIR_USER, filename);
+    auto fd = fd_open(path, O_RDONLY);
     if (fd >= 0) {
-        std::string query = _("現存するファイル ", "Replace existing file ");
-        query.append(buf).append(_(" に上書きしますか? ", "? "));
+        const auto &path_str = path.string();
+        std::stringstream ss;
+        ss << _("現存するファイル ", "Replace existing file ") << path_str << _(" に上書きしますか? ", "? ");
         (void)fd_close(fd);
-        if (get_check_strict(player_ptr, query, CHECK_NO_HISTORY)) {
+        if (input_check_strict(player_ptr, ss.str(), UserCheck::NO_HISTORY)) {
             fd = -1;
+        } else {
+            return;
         }
     }
 
     FILE *fff = nullptr;
     if (fd < 0) {
-        fff = angband_fopen(buf, FileOpenMode::WRITE);
+        fff = angband_fopen(path, FileOpenMode::WRITE);
     }
 
+    constexpr auto error_msg = _("キャラクタ情報のファイルへの書き出しに失敗しました!", "Character dump failed!");
     if (!fff) {
-        prt(_("キャラクタ情報のファイルへの書き出しに失敗しました!", "Character dump failed!"), 0, 0);
-        (void)inkey();
-        return -1;
+        msg_print(error_msg);
+        msg_print(nullptr);
+        return;
     }
 
     screen_save();
     make_character_dump(player_ptr, fff);
     screen_load();
 
+    if (ferror(fff)) {
+        angband_fclose(fff);
+        msg_print(error_msg);
+        msg_print(nullptr);
+        return;
+    }
+
     angband_fclose(fff);
     msg_print(_("キャラクタ情報のファイルへの書き出しに成功しました。", "Character dump successful."));
     msg_print(nullptr);
-    return 0;
 }
 
 /*!
@@ -102,9 +111,8 @@ errr file_character(PlayerType *player_ptr, concptr name)
  */
 std::optional<std::string> get_random_line(concptr file_name, int entry)
 {
-    char filename[1024];
-    path_build(filename, sizeof(filename), ANGBAND_DIR_FILE, file_name);
-    auto *fp = angband_fopen(filename, FileOpenMode::READ);
+    const auto &path = path_build(ANGBAND_DIR_FILE, file_name);
+    auto *fp = angband_fopen(path, FileOpenMode::READ);
     if (!fp) {
         return std::nullopt;
     }
@@ -128,11 +136,11 @@ std::optional<std::string> get_random_line(concptr file_name, int entry)
         }
 
         if (buf[2] == 'M') {
-            if (monraces_info[i2enum<MonsterRaceId>(entry)].flags1 & RF1_MALE) {
+            if (is_male(monraces_info[i2enum<MonsterRaceId>(entry)])) {
                 break;
             }
         } else if (buf[2] == 'F') {
-            if (monraces_info[i2enum<MonsterRaceId>(entry)].flags1 & RF1_FEMALE) {
+            if (is_female(monraces_info[i2enum<MonsterRaceId>(entry)])) {
                 break;
             }
         } else if (sscanf(&(buf[2]), "%d", &test) != EOF) {
@@ -193,12 +201,12 @@ std::optional<std::string> get_random_line_ja_only(concptr file_name, int entry,
     std::optional<std::string> line;
     for (auto i = 0; i < count; i++) {
         line = get_random_line(file_name, entry);
-        if (!line.has_value()) {
+        if (!line) {
             return std::nullopt;
         }
 
         auto is_kanji = false;
-        for (const auto c : line.value()) {
+        for (const auto c : *line) {
             is_kanji |= iskanji(c);
         }
 
@@ -225,9 +233,10 @@ static errr counts_seek(PlayerType *player_ptr, int fd, uint32_t where, bool fla
     char temp1[128]{}, temp2[128]{};
     auto short_pclass = enum2i(player_ptr->pclass);
 #ifdef SAVEFILE_USE_UID
-    strnfmt(temp1, sizeof(temp1), "%d.%s.%d%d%d", player_ptr->player_uid, savefile_base, short_pclass, player_ptr->ppersonality, player_ptr->age);
+    const auto user_id = UnixUserIds::get_instance().get_user_id();
+    strnfmt(temp1, sizeof(temp1), "%d.%s.%d%d%d", user_id, savefile_base.data(), short_pclass, player_ptr->ppersonality, player_ptr->age);
 #else
-    strnfmt(temp1, sizeof(temp1), "%s.%d%d%d", savefile_base, short_pclass, player_ptr->ppersonality, player_ptr->age);
+    strnfmt(temp1, sizeof(temp1), "%s.%d%d%d", savefile_base.data(), short_pclass, player_ptr->ppersonality, player_ptr->age);
 #endif
     for (int i = 0; temp1[i]; i++) {
         temp1[i] ^= (i + 1) * 63;
@@ -269,9 +278,8 @@ static errr counts_seek(PlayerType *player_ptr, int fd, uint32_t where, bool fla
  */
 uint32_t counts_read(PlayerType *player_ptr, int where)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
-    auto fd = fd_open(buf, O_RDONLY);
+    const auto &path = path_build(ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
+    auto fd = fd_open(path, O_RDONLY);
     uint32_t count = 0;
     if (counts_seek(player_ptr, fd, where, false) || fd_read(fd, (char *)(&count), sizeof(uint32_t))) {
         count = 0;
@@ -291,19 +299,17 @@ uint32_t counts_read(PlayerType *player_ptr, int where)
  */
 errr counts_write(PlayerType *player_ptr, int where, uint32_t count)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
-
-    safe_setuid_grab(player_ptr);
-    auto fd = fd_open(buf, O_RDWR);
+    const auto &path = path_build(ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
+    safe_setuid_grab();
+    auto fd = fd_open(path, O_RDWR);
     safe_setuid_drop();
     if (fd < 0) {
-        safe_setuid_grab(player_ptr);
-        fd = fd_make(buf);
+        safe_setuid_grab();
+        fd = fd_make(path);
         safe_setuid_drop();
     }
 
-    safe_setuid_grab(player_ptr);
+    safe_setuid_grab();
     auto err = fd_lock(fd, F_WRLCK);
     safe_setuid_drop();
     if (err) {
@@ -312,7 +318,7 @@ errr counts_write(PlayerType *player_ptr, int where, uint32_t count)
 
     counts_seek(player_ptr, fd, where, true);
     fd_write(fd, (char *)(&count), sizeof(uint32_t));
-    safe_setuid_grab(player_ptr);
+    safe_setuid_grab();
     err = fd_lock(fd, F_UNLCK);
     safe_setuid_drop();
 
@@ -329,14 +335,14 @@ errr counts_write(PlayerType *player_ptr, int where, uint32_t count)
  */
 void read_dead_file()
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("dead_j.txt", "dead.txt"));
-    auto *fp = angband_fopen(buf, FileOpenMode::READ);
+    const auto &path = path_build(ANGBAND_DIR_FILE, _("dead_j.txt", "dead.txt"));
+    auto *fp = angband_fopen(path, FileOpenMode::READ);
     if (!fp) {
         return;
     }
 
     int i = 0;
+    char buf[1024]{};
     while (angband_fgets(fp, buf, sizeof(buf)) == 0) {
         put_str(buf, i++, 0);
     }
index 8aadb42..7154b63 100644 (file)
@@ -1,13 +1,14 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <filesystem>
 #include <optional>
 #include <string>
+#include <string_view>
 
-extern char savefile[1024];
-extern char savefile_base[40];
-extern char debug_savefile[1024];
+extern std::filesystem::path savefile; //!< セーブファイルのフルパス
+extern std::string savefile_base; //!< セーブファイル名
+extern std::filesystem::path debug_savefile; //!< デバッグセーブファイルのフルパス
 
 extern std::filesystem::path ANGBAND_DIR;
 extern std::filesystem::path ANGBAND_DIR_APEX;
@@ -27,7 +28,7 @@ extern std::filesystem::path ANGBAND_DIR_XTRA;
 class PlayerType;
 typedef void (*update_playtime_pf)(void);
 
-errr file_character(PlayerType *player_ptr, concptr name);
+void file_character(PlayerType *player_ptr, std::string_view filename);
 std::optional<std::string> get_random_line(concptr file_name, int entry);
 void read_dead_file();
 
index be85573..6843595 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief Index of spell type names
  */
 
index ea60992..3c6f772 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 #include <vector>
diff --git a/src/io/inet.cpp b/src/io/inet.cpp
deleted file mode 100644 (file)
index 6644643..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * @brief ネットワーク機能処理
- * @date 2002/01/12
- * @author mogami
- */
-
-#include "io/inet.h"
-#include "io/files-util.h"
-#include "util/angband-files.h"
-
-#ifdef WORLD_SCORE
-#ifdef WINDOWS
-#include <winsock.h>
-#else
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <setjmp.h>
-#include <signal.h>
-#endif
-
-#include <stdlib.h>
-
-static concptr errstr;
-static char *proxy;
-static int proxy_port;
-
-/* プロキシサーバのアドレスををファイルから読んで設定する */
-void set_proxy(char *default_url, int default_port)
-{
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, "proxy.prf");
-    auto *fp = angband_fopen(buf, FileOpenMode::READ);
-    if (!fp) {
-        proxy = default_url;
-        proxy_port = default_port;
-        return;
-    }
-
-    while (angband_fgets(fp, buf, sizeof(buf)) == 0) {
-        if (buf[0] != '#' && buf[0] != '\0') {
-            break;
-        }
-    }
-
-    angband_fclose(fp);
-    auto *s = buf;
-
-    /* "http://" から始まっている場合はその部分をカットする。 */
-#if defined(WINDOWS)
-    if (!strnicmp(s, "http://", 7)) {
-        s += 7;
-    }
-#else
-    if (!strncasecmp(s, "http://", 7)) {
-        s += 7;
-    }
-#endif
-
-    /* 文字列の長さを調べ、必要なメモリを確保 */
-    auto len = strlen(s);
-    proxy = static_cast<char *>(malloc(len + 1));
-
-    /* ポート番号があるかどうかを調べ、あればproxy_portに設定。 */
-    --len;
-    while (len > 0 && isdigit((unsigned char)s[len])) {
-        --len;
-    }
-    if (len > 0 && s[len] == ':' && s[len + 1] != '\0') {
-        s[len] = '\0';
-        strcpy(proxy, s);
-        proxy_port = atoi(s + (len + 1));
-    } else {
-        strcpy(proxy, s);
-        proxy_port = default_port;
-    }
-
-    /* プロキシのアドレスをproxyにコピー */
-    strcpy(proxy, s);
-
-    if (proxy_port == 0) {
-        proxy_port = 80;
-    }
-}
-
-/* ソケットにバッファの内容を書き込む */
-int soc_write(int sd, char *buf, size_t sz)
-{
-    int nleft, nwritten;
-
-    nleft = sz;
-
-    while (nleft > 0) {
-        nwritten = send(sd, buf, nleft, 0);
-        if (nwritten <= 0) {
-            return nwritten;
-        }
-        nleft -= nwritten;
-        buf += nwritten;
-    }
-
-    return sz;
-}
-
-int soc_read(int sd, char *buf, size_t sz)
-{
-    int nleft, nread = 0;
-
-    nleft = sz;
-
-    while (nleft > 0) {
-        int n;
-        n = recv(sd, buf + nread, nleft, 0);
-        if (n <= 0) {
-            return nread;
-        }
-        nleft -= n;
-        nread += n;
-    }
-
-    return nread;
-}
-
-#if !defined(WINDOWS)
-static sigjmp_buf env;
-static void (*sig_int_saved)(int);
-static void (*sig_alm_saved)(int);
-#endif
-
-static void restore_signal(void)
-{
-#if !defined(WINDOWS)
-    struct itimerval val0;
-
-    /* itimerリセット用 */
-    val0.it_interval.tv_sec = 0;
-    val0.it_interval.tv_usec = 0;
-    val0.it_value.tv_sec = 0;
-    val0.it_value.tv_usec = 0;
-
-    /* アラーム解除 */
-    setitimer(ITIMER_REAL, &val0, nullptr);
-    signal(SIGALRM, sig_alm_saved);
-    signal(SIGINT, sig_int_saved);
-#endif
-}
-
-#if !defined(WINDOWS)
-static void interrupt_report(int sig)
-{
-    restore_signal();
-    siglongjmp(env, sig);
-}
-#endif
-
-/* サーバにコネクトする関数。 */
-int connect_server(int timeout, concptr host, int port)
-{
-    int sd;
-    struct sockaddr_in to;
-    struct hostent *hp;
-
-#ifndef WINDOWS
-    struct itimerval val;
-    int ret;
-
-    /* itimer設定用 */
-    val.it_interval.tv_sec = 0;
-    val.it_interval.tv_usec = 0;
-    val.it_value.tv_sec = timeout;
-    val.it_value.tv_usec = 0;
-
-    /* タイムアウト、もしくは中断した時の処理。 */
-    if ((ret = sigsetjmp(env, 1)) != 0) {
-#ifdef JP
-        if (ret == SIGALRM) {
-            errstr = "エラー: タイムアウト";
-        } else {
-            errstr = "エラー: インタラプト";
-        }
-#else
-        if (ret == SIGALRM) {
-            errstr = "Error : time out";
-        } else {
-            errstr = "Error : interupted";
-        }
-#endif
-        return -1;
-    }
-    sig_int_saved = signal(SIGINT, interrupt_report);
-    sig_alm_saved = signal(SIGALRM, interrupt_report);
-
-    /* タイムアウトの時間を設定 */
-    setitimer(ITIMER_REAL, &val, nullptr);
-#else
-    /* Unused in Windows */
-    (void)timeout;
-#endif
-
-    /* プロキシが設定されていればプロキシに繋ぐ */
-    if (proxy && proxy[0]) {
-        if ((hp = gethostbyname(proxy)) == nullptr) {
-#ifdef JP
-            errstr = "エラー: プロキシのアドレスが不正です";
-#else
-            errstr = "Error : wrong proxy address";
-#endif
-
-            restore_signal();
-
-            return -1;
-        }
-    } else if ((hp = gethostbyname(host)) == nullptr) {
-#ifdef JP
-        errstr = "エラー: サーバのアドレスが不正です";
-#else
-        errstr = "Error : wrong server address";
-#endif
-
-        restore_signal();
-
-        return -1;
-    }
-
-    memset(&to, 0, sizeof(to));
-    memcpy(&to.sin_addr, hp->h_addr_list[0], hp->h_length);
-
-    to.sin_family = AF_INET;
-
-    if (proxy && proxy[0] && proxy_port) {
-        to.sin_port = htons(static_cast<ushort>(proxy_port));
-    } else {
-        to.sin_port = htons(static_cast<ushort>(port));
-    }
-
-#ifndef WINDOWS
-    if ((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
-#else
-    if ((sd = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
-#endif
-    {
-#ifdef JP
-        errstr = "エラー: ソケットを生成できません";
-#else
-        errstr = "Error : cannot create socket.";
-#endif
-        restore_signal();
-        return -1;
-    }
-
-    if (connect(sd, (struct sockaddr *)&to, sizeof(to)) < 0) {
-#ifdef JP
-        errstr = "エラー: サーバに接続できません";
-#else
-        errstr = "Error : failed to connect server";
-#endif
-        restore_signal();
-#ifndef WINDOWS
-        close(sd);
-#else
-        closesocket(sd);
-#endif
-        return -1;
-    }
-
-    restore_signal();
-
-    return sd;
-}
-
-int disconnect_server(int sd)
-{
-#if defined(WINDOWS)
-    return closesocket(sd);
-#else
-    return close(sd);
-#endif
-}
-
-concptr soc_err()
-{
-    return errstr;
-}
-
-#endif /* WORLD_SCORE */
diff --git a/src/io/inet.h b/src/io/inet.h
deleted file mode 100644 (file)
index e26c744..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-#include "system/angband.h"
-
-int soc_write(int sd, char *buf, size_t sz);
-int soc_read(int sd, char *buf, size_t sz);
-void set_proxy(char *default_url, int default_port);
-int connect_server(int timeout, concptr host, int port);
-int disconnect_server(int sd);
-concptr soc_err(void);
index 7c10b11..f8ba3e5 100644 (file)
@@ -1,4 +1,4 @@
-#include "io/input-key-acceptor.h"
+#include "io/input-key-acceptor.h"
 #include "cmd-io/macro-util.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
@@ -6,6 +6,7 @@
 #include "game-option/map-screen-options.h"
 #include "io/signal-handlers.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "util/string-processor.h"
 #include "world/world.h"
@@ -53,7 +54,7 @@ static void all_term_fresh()
     term_activate(angband_terms[0]);
     term_locate(&x, &y);
 
-    p_ptr->window_flags |= PW_ALL;
+    RedrawingFlagsUpdater::get_instance().fill_up_sub_flags();
     handle_stuff(p_ptr);
 
     term_activate(angband_terms[0]);
@@ -173,7 +174,7 @@ static char inkey_aux(void)
         return ch;
     }
 
-    concptr pat = macro__pat[k].data();
+    concptr pat = macro_patterns[k].data();
     n = strlen(pat);
     while (p > n) {
         if (term_key_push(buf[--p])) {
@@ -186,7 +187,7 @@ static char inkey_aux(void)
         return 0;
     }
 
-    concptr act = macro__act[k].data();
+    concptr act = macro_actions[k].data();
 
     n = strlen(act);
     while (n > 0) {
index 1180b82..8193903 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 0dd5ea3..1795505 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief キー入力に応じてゲーム内コマンドを実行する
  * @date 2022/02/20
  * @author Hourier
@@ -46,8 +46,6 @@
 #include "cmd-visual/cmd-map.h"
 #include "cmd-visual/cmd-visuals.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/special-internal-keys.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h" //!< @do_cmd_quest() がある。後で移設する.
@@ -89,6 +87,7 @@
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
@@ -115,12 +114,12 @@ bool enter_wizard_mode(PlayerType *player_ptr)
         msg_print(_("ウィザードモードはデバッグと実験のためのモードです。 ", "Wizard mode is for debugging and experimenting."));
         msg_print(_("一度ウィザードモードに入るとスコアは記録されません。", "The game will not be scored if you enter wizard mode."));
         msg_print(nullptr);
-        if (!get_check(_("本当にウィザードモードに入りたいのですか? ", "Are you sure you want to enter wizard mode? "))) {
+        if (!input_check(_("本当にウィザードモードに入りたいのですか? ", "Are you sure you want to enter wizard mode? "))) {
             return false;
         }
 
-        exe_write_diary(
-            player_ptr, DIARY_DESCRIPTION, 0, _("ウィザードモードに突入してスコアを残せなくなった。", "gave up recording score to enter wizard mode."));
+        constexpr auto mes = _("ウィザードモードに突入してスコアを残せなくなった。", "gave up recording score to enter wizard mode.");
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, mes);
         w_ptr->noscore |= 0x0002;
     }
 
@@ -144,12 +143,12 @@ static bool enter_debug_mode(PlayerType *player_ptr)
         msg_print(_("デバッグ・コマンドはデバッグと実験のためのコマンドです。 ", "The debug commands are for debugging and experimenting."));
         msg_print(_("デバッグ・コマンドを使うとスコアは記録されません。", "The game will not be scored if you use debug commands."));
         msg_print(nullptr);
-        if (!get_check(_("本当にデバッグ・コマンドを使いますか? ", "Are you sure you want to use debug commands? "))) {
+        if (!input_check(_("本当にデバッグ・コマンドを使いますか? ", "Are you sure you want to use debug commands? "))) {
             return false;
         }
 
-        exe_write_diary(
-            player_ptr, DIARY_DESCRIPTION, 0, _("デバッグモードに突入してスコアを残せなくなった。", "gave up sending score to use debug commands."));
+        constexpr auto mes = _("デバッグモードに突入してスコアを残せなくなった。", "gave up sending score to use debug commands.");
+        exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, mes);
         w_ptr->noscore |= 0x0008;
     }
 
@@ -166,7 +165,7 @@ void process_command(PlayerType *player_ptr)
     COMMAND_CODE old_now_message = now_message;
     repeat_check();
     now_message = 0;
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     if (sniper_data && sniper_data->concent > 0) {
         sniper_data->reset_concent = true;
     }
@@ -189,8 +188,9 @@ void process_command(PlayerType *player_ptr)
             msg_print(_("ウィザードモード突入。", "Wizard mode on."));
         }
 
-        player_ptr->update |= (PU_MONSTER_STATUSES);
-        player_ptr->redraw |= (PR_TITLE);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+        rfu.set_flag(MainWindowRedrawingFlag::TITLE);
         break;
     }
     case KTRL('A'): {
@@ -239,7 +239,7 @@ void process_command(PlayerType *player_ptr)
     }
 
     case KTRL('I'): {
-        toggle_inventory_equipment(player_ptr);
+        toggle_inventory_equipment();
         break;
     }
     case '+': {
@@ -309,7 +309,7 @@ void process_command(PlayerType *player_ptr)
         break;
     }
     case '<': {
-        if (!player_ptr->wild_mode && !floor_ptr->dun_level && !floor_ptr->inside_arena && !inside_quest(floor_ptr->quest_number)) {
+        if (!player_ptr->wild_mode && !floor_ptr->dun_level && !floor_ptr->inside_arena && !floor_ptr->is_in_quest()) {
             if (vanilla_town) {
                 break;
             }
@@ -403,13 +403,16 @@ void process_command(PlayerType *player_ptr)
             break;
         }
 
-        if (floor_ptr->dun_level && dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MAGIC) && !pc.equals(PlayerClassType::BERSERKER) && !pc.equals(PlayerClassType::SMITH)) {
+        const auto &dungeon = floor_ptr->get_dungeon_definition();
+        auto non_magic_class = pc.equals(PlayerClassType::BERSERKER);
+        non_magic_class |= pc.equals(PlayerClassType::SMITH);
+        if (floor_ptr->dun_level && dungeon.flags.has(DungeonFeatureType::NO_MAGIC) && !non_magic_class) {
             msg_print(_("ダンジョンが魔法を吸収した!", "The dungeon absorbs all attempted magic!"));
             msg_print(nullptr);
             break;
         }
 
-        if (player_ptr->anti_magic && !pc.equals(PlayerClassType::BERSERKER) && !pc.equals(PlayerClassType::SMITH)) {
+        if (player_ptr->anti_magic && !non_magic_class) {
             concptr which_power = _("魔法", "magic");
             switch (player_ptr->pclass) {
             case PlayerClassType::MINDCRAFTER:
@@ -667,7 +670,7 @@ void process_command(PlayerType *player_ptr)
         break;
     }
     case KTRL('V'): {
-        spoil_random_artifact(player_ptr, "randifact.txt");
+        spoil_random_artifact(player_ptr);
         break;
     }
     case '`': {
@@ -685,8 +688,8 @@ void process_command(PlayerType *player_ptr)
         if (one_in_(2)) {
             sound(SOUND_ILLEGAL);
             const auto error_mes = get_random_line(_("error_j.txt", "error.txt"), 0);
-            if (error_mes.has_value()) {
-                msg_print(error_mes.value());
+            if (error_mes) {
+                msg_print(*error_mes);
             }
         } else {
             prt(_(" '?' でヘルプが表示されます。", "Type '?' for help."), 0, 0);
index c417b92..ef259bb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool enter_wizard_mode(PlayerType *player_ptr);
index 03bc911..c91c015 100644 (file)
@@ -1,10 +1,11 @@
-#include "io/input-key-requester.h"
+#include "io/input-key-requester.h"
 #include "cmd-io/cmd-menu-content-table.h"
 #include "cmd-io/macro-util.h"
 #include "core/asking-player.h" //!< @todo 相互依存している、後で何とかする.
 #include "core/player-processor.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
+#include "dungeon/quest.h"
 #include "game-option/game-play-options.h"
 #include "game-option/input-options.h"
 #include "game-option/map-screen-options.h"
@@ -19,7 +20,6 @@
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h" //!< @todo 相互依存している、後で何とかする.
 #include "util/int-char-converter.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 #include "window/display-sub-windows.h"
@@ -61,7 +61,7 @@ void InputKeyRequestor::request_command()
     command_arg = 0;
     command_dir = 0;
     use_menu = false;
-    this->input_command();
+    this->process_input_command();
     if (always_repeat && (command_arg <= 0)) {
         if (angband_strchr("TBDoc+", (char)command_cmd)) {
             command_arg = 99;
@@ -73,7 +73,7 @@ void InputKeyRequestor::request_command()
     prt("", 0, 0);
 }
 
-void InputKeyRequestor::input_command()
+void InputKeyRequestor::process_input_command()
 {
     while (true) {
         if (!this->shopping && !macro_running() && !command_new && auto_debug_save && (!inkey_next || *inkey_next == '\0')) {
@@ -226,13 +226,8 @@ bool InputKeyRequestor::process_repeat_num(short &cmd)
         return false;
     }
 
-    char tmp_cmd;
-    auto ret_cmd = get_com(_("コマンド: ", "Command: "), &tmp_cmd, false);
-    cmd = tmp_cmd;
-    if (ret_cmd) {
-        return false;
-    }
-
+    const auto ret_cmd = input_command(_("コマンド: ", "Command: "));
+    cmd = ret_cmd.value_or(ESCAPE);
     command_arg = 0;
     return true;
 }
@@ -248,9 +243,8 @@ void InputKeyRequestor::process_command_command(short &cmd)
         return;
     }
 
-    char tmp_cmd;
-    (void)get_com(_("コマンド: ", "Command: "), &tmp_cmd, false);
-    cmd = tmp_cmd;
+    const auto new_command = input_command(_("コマンド: ", "Command: "));
+    cmd = new_command.value_or(ESCAPE);
     if (inkey_next == nullptr) {
         inkey_next = "";
     }
@@ -262,10 +256,10 @@ void InputKeyRequestor::process_control_command(short &cmd)
         return;
     }
 
-    char tmp_cmd;
-    auto ret_cmd = get_com(_("CTRL: ", "Control: "), &tmp_cmd, false);
-    cmd = tmp_cmd;
-    if (ret_cmd) {
+    const auto new_command = input_command(_("CTRL: ", "Control: "));
+    const auto is_input = new_command.has_value();
+    cmd = new_command.value_or(ESCAPE);
+    if (is_input) {
         cmd = KTRL(cmd);
     }
 }
@@ -324,23 +318,27 @@ void InputKeyRequestor::sweep_confirmation_equipments()
             continue;
         }
 
-        this->confirm_command(item, caret_command);
+        this->confirm_command(item.inscription, caret_command);
     }
 }
 
-void InputKeyRequestor::confirm_command(ItemEntity &o_ref, const int caret_command)
+void InputKeyRequestor::confirm_command(const std::optional<std::string> &inscription, const int caret_command)
 {
-    auto s = o_ref.inscription->data();
+    if (!inscription) {
+        return;
+    }
+
+    auto s = inscription->data();
     s = angband_strchr(s, '^');
-    while (s) {
+    while (s != nullptr) {
 #ifdef JP
-        auto sure = (s[1] == caret_command) || (s[1] == '*');
+        auto sure = s[1] == caret_command;
 #else
-        auto sure = (s[1] == command_cmd) || (s[1] == '*');
+        auto sure = s[1] == command_cmd;
         (void)caret_command;
 #endif
         if (sure) {
-            if (!get_check(_("本当ですか? ", "Are you sure? "))) {
+            if (!input_check(_("本当ですか? ", "Are you sure? "))) {
                 command_cmd = ' ';
             }
         }
@@ -367,14 +365,14 @@ std::string InputKeyRequestor::switch_special_menu_condition(const SpecialMenuCo
     case SpecialMenuType::NONE:
         return "";
     case SpecialMenuType::CLASS:
-        if (PlayerClass(this->player_ptr).equals(special_menu.class_condition.value())) {
+        if (PlayerClass(this->player_ptr).equals(*special_menu.class_condition)) {
             return std::string(special_menu.name);
         }
 
         return "";
     case SpecialMenuType::WILD: {
         auto floor_ptr = this->player_ptr->current_floor_ptr;
-        if ((floor_ptr->dun_level > 0) || floor_ptr->inside_arena || inside_quest(floor_ptr->quest_number)) {
+        if ((floor_ptr->dun_level > 0) || floor_ptr->inside_arena || floor_ptr->is_in_quest()) {
             return "";
         }
 
@@ -413,7 +411,7 @@ int InputKeyRequestor::get_command_per_menu_num()
             }
         }
 
-        put_str(menu_name.data(), this->base_y + 1 + command_per_menu_num / 2, this->base_x + 4 + (command_per_menu_num % 2) * 24);
+        put_str(menu_name, this->base_y + 1 + command_per_menu_num / 2, this->base_x + 4 + (command_per_menu_num % 2) * 24);
     }
 
     return command_per_menu_num;
index ad8dd90..76b10c1 100644 (file)
@@ -1,7 +1,8 @@
-#pragma once
+#pragma once
 
 #include "game-option/keymap-directory-getter.h"
 #include "system/angband.h"
+#include <optional>
 #include <string>
 
 extern concptr keymap_act[KEYMAP_MODES][256];
@@ -17,7 +18,6 @@ extern TERM_LEN command_gap;
 extern int16_t command_wrk;
 extern int16_t command_new;
 
-class ItemEntity;
 class PlayerType;
 class SpecialMenuContent;
 class InputKeyRequestor {
@@ -38,7 +38,7 @@ private:
     bool is_max_num_odd = false;
     char sub_cmd = 0;
 
-    void input_command();
+    void process_input_command();
     short get_command();
     char inkey_from_menu();
     bool process_repeat_num(short &cmd);
@@ -48,7 +48,7 @@ private:
     void change_shopping_command();
     int get_caret_command();
     void sweep_confirmation_equipments();
-    void confirm_command(ItemEntity &o_ref, const int caret_command);
+    void confirm_command(const std::optional<std::string> &inscription, const int caret_command);
 
     void make_commands_frame();
     std::string switch_special_menu_condition(const SpecialMenuContent &special_menu);
index 69b7768..0144aa9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief prefファイルの内容を解釈しメモリに展開する
  * @date 2020/03/01
  * @author Hourier
@@ -20,7 +20,6 @@
 #include "system/player-type-definition.h"
 #include "system/terrain-type-definition.h"
 #include "term/gameterm.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 #include "world/world.h"
@@ -98,33 +97,31 @@ static errr interpret_k_token(char *buf)
  */
 static errr decide_feature_type(int i, int num, char **zz)
 {
-    TerrainType *f_ptr;
-    f_ptr = &terrains_info[i];
-
+    auto &terrain = TerrainList::get_instance()[static_cast<short>(i)];
     TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], nullptr, 0);
     auto n2 = static_cast<char>(strtol(zz[2], nullptr, 0));
     if (n1 || (!(n2 & 0x80) && n2)) {
-        f_ptr->x_attr[F_LIT_STANDARD] = n1;
+        terrain.x_attr[F_LIT_STANDARD] = n1;
     } /* Allow TERM_DARK text */
     if (n2) {
-        f_ptr->x_char[F_LIT_STANDARD] = n2;
+        terrain.x_char[F_LIT_STANDARD] = n2;
     }
 
     switch (num) {
     case 3: {
         /* No lighting support */
-        n1 = f_ptr->x_attr[F_LIT_STANDARD];
-        n2 = f_ptr->x_char[F_LIT_STANDARD];
+        n1 = terrain.x_attr[F_LIT_STANDARD];
+        n2 = terrain.x_char[F_LIT_STANDARD];
         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
-            f_ptr->x_attr[j] = n1;
-            f_ptr->x_char[j] = n2;
+            terrain.x_attr[j] = n1;
+            terrain.x_char[j] = n2;
         }
 
         return 0;
     }
     case 4: {
         /* Use default lighting */
-        apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
+        apply_default_feat_lighting(terrain.x_attr, terrain.x_char);
         return 0;
     }
     case F_LIT_MAX * 2 + 1: {
@@ -133,10 +130,10 @@ static errr decide_feature_type(int i, int num, char **zz)
             n1 = (TERM_COLOR)strtol(zz[j * 2 + 1], nullptr, 0);
             n2 = static_cast<char>(strtol(zz[j * 2 + 2], nullptr, 0));
             if (n1 || (!(n2 & 0x80) && n2)) {
-                f_ptr->x_attr[j] = n1;
+                terrain.x_attr[j] = n1;
             } /* Allow TERM_DARK text */
             if (n2) {
-                f_ptr->x_char[j] = n2;
+                terrain.x_char[j] = n2;
             }
         }
 
@@ -168,7 +165,7 @@ static errr interpret_f_token(char *buf)
     }
 
     int i = (int)strtol(zz[0], nullptr, 0);
-    if (i >= static_cast<int>(terrains_info.size())) {
+    if (i >= static_cast<int>(TerrainList::get_instance().size())) {
         return 1;
     }
 
@@ -254,7 +251,7 @@ static errr interpret_p_token(char *buf)
 {
     char tmp[1024];
     text_to_ascii(tmp, buf + 2, sizeof(tmp));
-    return macro_add(tmp, macro__buf.data());
+    return macro_add(tmp, macro_buffers.data());
 }
 
 /*!
@@ -282,7 +279,7 @@ static errr interpret_c_token(char *buf)
 
     int i = (byte)(tmp[0]);
     string_free(keymap_act[mode][i]);
-    keymap_act[mode][i] = string_make(macro__buf.data());
+    keymap_act[mode][i] = string_make(macro_buffers.data());
     return 0;
 }
 
@@ -335,12 +332,12 @@ static errr interpret_xy_token(PlayerType *player_ptr, char *buf)
         }
 
         if (buf[0] == 'X') {
-            option_flag[os] &= ~(1UL << ob);
+            g_option_flags[os] &= ~(1UL << ob);
             (*option_info[i].o_var) = false;
             return 0;
         }
 
-        option_flag[os] |= (1UL << ob);
+        g_option_flags[os] |= (1UL << ob);
         (*option_info[i].o_var) = true;
         return 0;
     }
@@ -528,7 +525,7 @@ errr interpret_pref_file(PlayerType *player_ptr, char *buf)
         return interpret_e_token(buf);
     case 'A': {
         /* Process "A:<str>" -- save an "action" for later */
-        text_to_ascii(macro__buf.data(), buf + 2, macro__buf.size());
+        text_to_ascii(macro_buffers.data(), buf + 2, macro_buffers.size());
         return 0;
     }
     case 'P':
index 0fc5f65..5fced6e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 0768718..bd66b61 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 突然変異の一覧を出力する
  * @date 2020/04/24
  * @author Hourier
index 887e166..d5d9957 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 2d4348b..b69ce43 100644 (file)
@@ -1,4 +1,4 @@
-#include "io/pref-file-expressor.h"
+#include "io/pref-file-expressor.h"
 #include "game-option/runtime-arguments.h"
 #include "player-info/class-info.h"
 #include "player-info/race-info.h"
index 50bb930..659b26c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index eb63c77..3d1c284 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief プレイヤーのインターフェイスに関するコマンドの実装 / Interface commands
  * @date 2023/04/30
  * @author Mogami & Hourier
@@ -58,31 +58,31 @@ static errr process_pref_file_aux(PlayerType *player_ptr, const std::filesystem:
     int line = -1;
     errr err = 0;
     bool bypass = false;
-    std::vector<char> file_read__buf(FILE_READ_BUFF_SIZE);
+    std::vector<char> file_read_buf(FILE_READ_BUFF_SIZE);
     std::string error_line;
-    while (angband_fgets(fp, file_read__buf.data(), file_read__buf.size()) == 0) {
+    while (angband_fgets(fp, file_read_buf.data(), file_read_buf.size()) == 0) {
         line++;
-        if (!file_read__buf[0]) {
+        if (!file_read_buf[0]) {
             continue;
         }
 
 #ifdef JP
-        if (!iskanji(file_read__buf[0]))
+        if (!iskanji(file_read_buf[0]))
 #endif
-            if (iswspace(file_read__buf[0])) {
+            if (iswspace(file_read_buf[0])) {
                 continue;
             }
 
-        if (file_read__buf[0] == '#') {
+        if (file_read_buf[0] == '#') {
             continue;
         }
-        error_line = file_read__buf.data();
+        error_line = file_read_buf.data();
 
         /* Process "?:<expr>" */
-        if ((file_read__buf[0] == '?') && (file_read__buf[1] == ':')) {
+        if ((file_read_buf[0] == '?') && (file_read_buf[1] == ':')) {
             char f;
             char *s;
-            s = file_read__buf.data() + 2;
+            s = file_read_buf.data() + 2;
             concptr v = process_pref_file_expr(player_ptr, &s, &f);
             bypass = streq(v, "0");
             continue;
@@ -93,7 +93,7 @@ static errr process_pref_file_aux(PlayerType *player_ptr, const std::filesystem:
         }
 
         /* Process "%:<file>" */
-        if (file_read__buf[0] == '%') {
+        if (file_read_buf[0] == '%') {
             static int depth_count = 0;
             if (depth_count > 20) {
                 continue;
@@ -102,13 +102,13 @@ static errr process_pref_file_aux(PlayerType *player_ptr, const std::filesystem:
             depth_count++;
             switch (preftype) {
             case PREF_TYPE_AUTOPICK:
-                (void)process_autopick_file(player_ptr, file_read__buf.data() + 2);
+                (void)process_autopick_file(player_ptr, file_read_buf.data() + 2);
                 break;
             case PREF_TYPE_HISTPREF:
-                (void)process_histpref_file(player_ptr, file_read__buf.data() + 2);
+                (void)process_histpref_file(player_ptr, file_read_buf.data() + 2);
                 break;
             default:
-                (void)process_pref_file(player_ptr, file_read__buf.data() + 2);
+                (void)process_pref_file(player_ptr, file_read_buf.data() + 2);
                 break;
             }
 
@@ -116,13 +116,13 @@ static errr process_pref_file_aux(PlayerType *player_ptr, const std::filesystem:
             continue;
         }
 
-        err = interpret_pref_file(player_ptr, file_read__buf.data());
+        err = interpret_pref_file(player_ptr, file_read_buf.data());
         if (err != 0) {
             if (preftype != PREF_TYPE_AUTOPICK) {
                 break;
             }
 
-            process_autopick_file_command(file_read__buf.data());
+            process_autopick_file_command(file_read_buf.data());
             err = 0;
         }
     }
@@ -156,18 +156,17 @@ static errr process_pref_file_aux(PlayerType *player_ptr, const std::filesystem:
  */
 errr process_pref_file(PlayerType *player_ptr, std::string_view name, bool only_user_dir)
 {
-    char buf[1024];
     errr err1 = 0;
     if (!only_user_dir) {
-        path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, name);
-        err1 = process_pref_file_aux(player_ptr, buf, PREF_TYPE_NORMAL);
+        const auto &path = path_build(ANGBAND_DIR_PREF, name);
+        err1 = process_pref_file_aux(player_ptr, path, PREF_TYPE_NORMAL);
         if (err1 > 0) {
             return err1;
         }
     }
 
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
-    errr err2 = process_pref_file_aux(player_ptr, buf, PREF_TYPE_NORMAL);
+    const auto &path = path_build(ANGBAND_DIR_USER, name);
+    errr err2 = process_pref_file_aux(player_ptr, path, PREF_TYPE_NORMAL);
     if (err2 < 0 && !err1) {
         return -2;
     }
@@ -183,9 +182,8 @@ errr process_pref_file(PlayerType *player_ptr, std::string_view name, bool only_
  */
 errr process_autopick_file(PlayerType *player_ptr, std::string_view name)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
-    return process_pref_file_aux(player_ptr, buf, PREF_TYPE_AUTOPICK);
+    const auto &path = path_build(ANGBAND_DIR_USER, name);
+    return process_pref_file_aux(player_ptr, path, PREF_TYPE_AUTOPICK);
 }
 
 /*!
@@ -199,12 +197,9 @@ errr process_autopick_file(PlayerType *player_ptr, std::string_view name)
 errr process_histpref_file(PlayerType *player_ptr, std::string_view name)
 {
     bool old_character_xtra = w_ptr->character_xtra;
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
-
-    /* Hack -- prevent modification birth options in this file */
+    const auto &path = path_build(ANGBAND_DIR_USER, name);
     w_ptr->character_xtra = true;
-    errr err = process_pref_file_aux(player_ptr, buf, PREF_TYPE_HISTPREF);
+    errr err = process_pref_file_aux(player_ptr, path, PREF_TYPE_HISTPREF);
     w_ptr->character_xtra = old_character_xtra;
     return err;
 }
@@ -284,16 +279,16 @@ void close_auto_dump(FILE **fpp, std::string_view mark)
 void load_all_pref_files(PlayerType *player_ptr)
 {
     process_pref_file(player_ptr, "user.prf");
-    process_pref_file(player_ptr, std::string("user-").append(ANGBAND_SYS).append(".prf").data());
-    process_pref_file(player_ptr, std::string(rp_ptr->title).append(".prf").data());
-    process_pref_file(player_ptr, std::string(cp_ptr->title).append(".prf").data());
-    process_pref_file(player_ptr, std::string(player_ptr->base_name).append(".prf").data());
+    process_pref_file(player_ptr, std::string("user-").append(ANGBAND_SYS).append(".prf"));
+    process_pref_file(player_ptr, std::string(rp_ptr->title).append(".prf"));
+    process_pref_file(player_ptr, std::string(cp_ptr->title).append(".prf"));
+    process_pref_file(player_ptr, std::string(player_ptr->base_name).append(".prf"));
     if (player_ptr->realm1 != REALM_NONE) {
-        process_pref_file(player_ptr, std::string(realm_names[player_ptr->realm1]).append(".prf").data());
+        process_pref_file(player_ptr, std::string(realm_names[player_ptr->realm1]).append(".prf"));
     }
 
     if (player_ptr->realm2 != REALM_NONE) {
-        process_pref_file(player_ptr, std::string(realm_names[player_ptr->realm2]).append(".prf").data());
+        process_pref_file(player_ptr, std::string(realm_names[player_ptr->realm2]).append(".prf"));
     }
 
     autopick_load_pref(player_ptr, false);
@@ -309,7 +304,7 @@ bool read_histpref(PlayerType *player_ptr)
     char *s;
     char histbuf[HISTPREF_LIMIT];
 
-    if (!get_check(_("生い立ち設定ファイルをロードしますか? ", "Load background history preference file? "))) {
+    if (!input_check(_("生い立ち設定ファイルをロードしますか? ", "Load background history preference file? "))) {
         return false;
     }
 
@@ -352,7 +347,7 @@ bool read_histpref(PlayerType *player_ptr)
     const auto history_lines = shape_buffer(s, max_line_len);
     const auto max_lines = std::min<int>(4, history_lines.size());
     for (auto l = 0; l < max_lines; ++l) {
-        angband_strcpy(player_ptr->history[l], history_lines[l].data(), max_line_len);
+        angband_strcpy(player_ptr->history[l], history_lines[l], max_line_len);
     }
 
     for (i = 0; i < 4; i++) {
index c62fd7f..eed8f20 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <filesystem>
index 06c0b42..9d3f782 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 録画・再生機能
  * @date 2014/01/02
  * @author 2014 Deskull rearranged comment for Doxygen.
@@ -9,7 +9,6 @@
 #include "cmd-visual/cmd-draw.h"
 #include "core/asking-player.h"
 #include "io/files-util.h"
-#include "io/inet.h"
 #include "io/signal-handlers.h"
 #include "locale/japanese.h"
 #include "system/player-type-definition.h"
@@ -19,6 +18,7 @@
 #include "view/display-messages.h"
 #include <algorithm>
 #include <sstream>
+#include <vector>
 
 #ifdef WINDOWS
 #include <windows.h>
@@ -52,10 +52,10 @@ static struct {
 
 /* リングバッファ構造体 */
 static struct {
-    char *buf;
-    int wptr;
-    int rptr;
-    int inlen;
+    std::vector<char> buf{};
+    int wptr = 0;
+    int rptr = 0;
+    int inlen = 0;
 } ring;
 
 /*
@@ -78,17 +78,12 @@ static void disable_chuukei_server(void)
 }
 
 /* ANSI Cによればstatic変数は0で初期化されるが一応初期化する */
-static errr init_buffer(void)
+static void init_buffer(void)
 {
     fresh_queue.next = fresh_queue.tail = 0;
     ring.wptr = ring.rptr = ring.inlen = 0;
     fresh_queue.time[0] = 0;
-    ring.buf = static_cast<char *>(malloc(RINGBUF_SIZE));
-    if (ring.buf == nullptr) {
-        return -1;
-    }
-
-    return 0;
+    ring.buf.resize(RINGBUF_SIZE);
 }
 
 /* 現在の時間を100ms単位で取得する */
@@ -129,11 +124,11 @@ static errr insert_ringbuf(std::string_view header, std::string_view payload = "
 
     /* バッファの終端までに収まる */
     if (ring.wptr + all_length + 1 < RINGBUF_SIZE) {
-        memcpy(ring.buf + ring.wptr, header.data(), header.length());
+        std::copy_n(header.begin(), header.length(), ring.buf.begin() + ring.wptr);
         if (!payload.empty()) {
-            memcpy(ring.buf + ring.wptr + header.length(), payload.data(), payload.length());
+            std::copy_n(payload.begin(), payload.length(), ring.buf.begin() + ring.wptr + header.length());
         }
-        *(ring.buf + ring.wptr + all_length) = '\0';
+        ring.buf[ring.wptr + all_length] = '\0';
         ring.wptr += all_length + 1;
     }
     /* バッファの終端までに収まらない(ピッタリ収まる場合も含む) */
@@ -142,21 +137,21 @@ static errr insert_ringbuf(std::string_view header, std::string_view payload = "
         int tail = all_length - head; /* 後半 */
 
         if ((int)header.length() <= head) {
-            memcpy(ring.buf + ring.wptr, header.data(), header.length());
+            std::copy_n(header.begin(), header.length(), ring.buf.begin() + ring.wptr);
             head -= header.length();
             if (head > 0) {
-                memcpy(ring.buf + ring.wptr + header.length(), payload.data(), head);
+                std::copy_n(payload.begin(), head, ring.buf.begin() + ring.wptr + header.length());
             }
-            memcpy(ring.buf, payload.data() + head, tail);
+            std::copy_n(payload.data() + head, tail, ring.buf.begin());
         } else {
-            memcpy(ring.buf + ring.wptr, header.data(), head);
+            std::copy_n(header.begin(), head, ring.buf.begin() + ring.wptr);
             int part = header.length() - head;
-            memcpy(ring.buf, header.data() + head, part);
+            std::copy_n(header.data() + head, part, ring.buf.begin());
             if (tail > part) {
-                memcpy(ring.buf + part, payload.data(), tail - part);
+                std::copy_n(payload.begin(), tail - part, ring.buf.begin() + part);
             }
         }
-        *(ring.buf + tail) = '\0';
+        ring.buf[tail] = '\0';
         ring.wptr = tail + 1;
     }
 
@@ -335,6 +330,8 @@ void prepare_chuukei_hooks(void)
  */
 void prepare_movie_hooks(PlayerType *player_ptr)
 {
+    TermCenteredOffsetSetter tcos(std::nullopt, std::nullopt);
+
     if (movie_mode) {
         movie_mode = 0;
         disable_chuukei_server();
@@ -345,26 +342,28 @@ void prepare_movie_hooks(PlayerType *player_ptr)
 
     std::stringstream ss;
     ss << player_ptr->base_name << ".amv";
-    auto movie_filename = ss.str();
-    if (!get_string(_("ムービー記録ファイル: ", "Movie file name: "), movie_filename.data(), 80)) {
+    auto initial_movie_filename = ss.str();
+    constexpr auto prompt = _("ムービー記録ファイル: ", "Movie file name: ");
+    const auto movie_filename = input_string(prompt, 80, initial_movie_filename.data());
+    if (!movie_filename) {
         return;
     }
 
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, movie_filename);
-    auto fd = fd_open(buf, O_RDONLY);
+    const auto &path = path_build(ANGBAND_DIR_USER, *movie_filename);
+    auto fd = fd_open(path, O_RDONLY);
     if (fd >= 0) {
+        const auto &filename = path.string();
         (void)fd_close(fd);
-        std::string query = _("現存するファイルに上>書きしますか? (", "Replace existing file ");
-        query.append(buf);
+        std::string query = _("現存するファイルに上書きしますか? (", "Replace existing file ");
+        query.append(filename);
         query.append(_(")", "? "));
-        if (!get_check(query)) {
+        if (!input_check(query)) {
             return;
         }
 
-        movie_fd = fd_open(buf, O_WRONLY | O_TRUNC);
+        movie_fd = fd_open(path, O_WRONLY | O_TRUNC);
     } else {
-        movie_fd = fd_make(buf);
+        movie_fd = fd_make(path);
     }
 
     if (!movie_fd) {
@@ -500,11 +499,9 @@ static bool get_nextbuf(char *buf)
 /* プレイホストのマップが大きいときクライアントのマップもリサイズする */
 static void update_term_size(int x, int y, int len)
 {
-    int ox, oy;
-    int nx, ny;
-    term_get_size(&ox, &oy);
-    nx = ox;
-    ny = oy;
+    const auto &[ox, oy] = term_get_size();
+    auto nx = ox;
+    auto ny = oy;
 
     /* 横方向のチェック */
     if (x + len > ox) {
@@ -522,8 +519,6 @@ static void update_term_size(int x, int y, int len)
 
 static bool flush_ringbuf_client()
 {
-    char buf[1024];
-
     /* 書くデータなし */
     if (fresh_queue.next == fresh_queue.tail) {
         return false;
@@ -535,21 +530,16 @@ static bool flush_ringbuf_client()
     }
 
     /* 時間情報(区切り)が得られるまで書く */
+    char buf[1024]{};
     while (get_nextbuf(buf)) {
-        char id;
-        int x, y, len;
-        TERM_COLOR col;
-        int i;
-        unsigned char tmp1, tmp2, tmp3, tmp4;
+        auto id = buf[0];
+        auto x = static_cast<uint8_t>(buf[1]) - 1;
+        auto y = static_cast<uint8_t>(buf[2]) - 1;
+        int len = static_cast<uint8_t>(buf[3]);
+        uint8_t col = buf[4];
         char *mesg;
-
-        sscanf(buf, "%c%c%c%c%c", &id, &tmp1, &tmp2, &tmp3, &tmp4);
-        x = tmp1 - 1;
-        y = tmp2 - 1;
-        len = tmp3;
-        col = tmp4;
         if (id == 's') {
-            col = tmp3;
+            col = buf[3];
             mesg = &buf[4];
         } else {
             mesg = &buf[5];
@@ -565,44 +555,47 @@ static bool flush_ringbuf_client()
 #endif
             update_term_size(x, y, len);
             (void)((*angband_terms[0]->text_hook)(x, y, len, (byte)col, mesg));
-            memcpy(&game_term->scr->c[y][x], mesg, len);
-            for (i = x; i < x + len; i++) {
+            std::copy_n(mesg, len, &game_term->scr->c[y][x]);
+            for (auto i = x; i < x + len; i++) {
                 game_term->scr->a[y][i] = col;
             }
-            break;
 
+            break;
         case 'n': /* 繰り返し */
-            for (i = 1; i < len; i++) {
+            for (auto i = 1; i < len + 1; i++) {
+                if (i == len) {
+                    mesg[i] = '\0';
+                    break;
+                }
+
                 mesg[i] = mesg[0];
             }
-            mesg[i] = '\0';
+
             update_term_size(x, y, len);
             (void)((*angband_terms[0]->text_hook)(x, y, len, (byte)col, mesg));
-            memcpy(&game_term->scr->c[y][x], mesg, len);
-            for (i = x; i < x + len; i++) {
+            std::copy_n(mesg, len, &game_term->scr->c[y][x]);
+            for (auto i = x; i < x + len; i++) {
                 game_term->scr->a[y][i] = col;
             }
-            break;
 
+            break;
         case 's': /* 一文字 */
             update_term_size(x, y, 1);
             (void)((*angband_terms[0]->text_hook)(x, y, 1, (byte)col, mesg));
-            memcpy(&game_term->scr->c[y][x], mesg, 1);
+            std::copy_n(&game_term->scr->c[y][x], 1, mesg);
             game_term->scr->a[y][x] = col;
             break;
-
         case 'w':
             update_term_size(x, y, len);
             (void)((*angband_terms[0]->wipe_hook)(x, y, len));
             break;
-
         case 'x':
             if (x == TERM_XTRA_CLEAR) {
                 term_clear();
             }
+
             (void)((*angband_terms[0]->xtra_hook)(x, 0));
             break;
-
         case 'c':
             update_term_size(x, y, 1);
             (void)((*angband_terms[0]->curs_hook)(x, y));
@@ -621,9 +614,9 @@ static bool flush_ringbuf_client()
     return true;
 }
 
-void prepare_browse_movie_without_path_build(std::string_view filename)
+void prepare_browse_movie_without_path_build(const std::filesystem::path &path)
 {
-    movie_fd = fd_open(filename, O_RDONLY);
+    movie_fd = fd_open(path, O_RDONLY);
     init_buffer();
 }
 
@@ -652,9 +645,8 @@ void browse_movie(void)
 #ifndef WINDOWS
 void prepare_browse_movie_with_path_build(std::string_view filename)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
-    movie_fd = fd_open(buf, O_RDONLY);
+    const auto &path = path_build(ANGBAND_DIR_USER, filename);
+    movie_fd = fd_open(path, O_RDONLY);
     init_buffer();
 }
 #endif
index ec6a2fc..15f1237 100644 (file)
@@ -1,10 +1,11 @@
-#pragma once
+#pragma once
 
+#include <filesystem>
 #include <string_view>
 
 class PlayerType;
 void prepare_movie_hooks(PlayerType *player_ptr);
-void prepare_browse_movie_without_path_build(std::string_view filename);
+void prepare_browse_movie_without_path_build(const std::filesystem::path &path);
 void browse_movie();
 #ifndef WINDOWS
 void prepare_browse_movie_with_path_build(std::string_view filename);
index cbc11aa..3c3f91c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file report.c
  * @brief スコアサーバ転送機能の実装
  * @date 2014/07/14
@@ -7,15 +7,14 @@
 
 #include "io/report.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "core/turn-compensator.h"
 #include "core/visuals-reseter.h"
 #include "game-option/special-options.h"
 #include "io-dump/character-dump.h"
-#include "io/inet.h"
 #include "io/input-key-acceptor.h"
 #include "mind/mind-elementalist.h"
+#include "net/http-client.h"
 #include "player-base/player-class.h"
 #include "player-info/class-info.h"
 #include "player-info/race-info.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/system-variables.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
+#include "term/z-form.h"
 #include "util/angband-files.h"
 #include "view/display-messages.h"
 #include "world/world.h"
+#include <algorithm>
+#include <fstream>
+#include <span>
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <vector>
 
 #ifdef WORLD_SCORE
 
-#ifdef WINDOWS
-#define CURL_STATICLIB
-#endif
-#include <curl/curl.h>
-
 concptr screen_dump = nullptr;
 
-/*
- * internet resource value
- */
-#define HTTP_TIMEOUT 30 /*!< デフォルトのタイムアウト時間(秒) / Timeout length (second) */
-
 #ifdef JP
-#define SCORE_PATH "http://mars.kmc.gr.jp/~dis/heng_score/register_score.php" /*!< スコア開示URL */
-#else
-#define SCORE_PATH "http://moon.kmc.gr.jp/hengband/hengscore-en/score.cgi" /*!< スコア開示URL */
+constexpr auto SCORE_POST_URL = "http://mars.kmc.gr.jp/~dis/heng_score/register_score.php"; /*!< スコア開示URL */
 #endif
 
-/*
- * simple buffer library
- */
-struct BUF {
-    size_t max_size;
-    size_t size;
-    size_t read_head;
-    char *data;
-};
-
-#define BUFSIZE (65536) /*!< スコアサーバ転送バッファサイズ */
-
-/*!
- * @brief 転送用バッファの確保
- * @return 確保したバッファの参照ポインタ
- */
-static BUF *buf_new(void)
-{
-    BUF *p;
-    p = static_cast<BUF *>(malloc(sizeof(BUF)));
-    if (!p) {
-        return nullptr;
-    }
-
-    p->size = 0;
-    p->max_size = BUFSIZE;
-    p->data = static_cast<char *>(malloc(BUFSIZE));
-    if (!p->data) {
-        free(p);
-        return nullptr;
-    }
-
-    return p;
-}
-
-/*!
- * @brief 転送用バッファの解放
- * @param b 解放するバッファの参照ポインタ
- */
-static void buf_delete(BUF *b)
-{
-    free(b->data);
-    free(b);
-}
-
-/*!
- * @brief 転送用バッファにデータを追加する
- * @param buf 追加先バッファの参照ポインタ
- * @param data 追加元データ
- * @param size 追加サイズ
- * @return 追加後のバッファ容量
- */
-static int buf_append(BUF *buf, concptr data, size_t size)
-{
-    while (buf->size + size > buf->max_size) {
-        char *tmp;
-        if ((tmp = static_cast<char *>(malloc(buf->max_size * 2))) == nullptr) {
-            return -1;
-        }
-
-        memcpy(tmp, buf->data, buf->max_size);
-        free(buf->data);
-
-        buf->data = tmp;
-
-        buf->max_size *= 2;
-    }
-    memcpy(buf->data + buf->size, data, size);
-    buf->size += size;
-
-    return buf->size;
-}
-
-/*!
- * @brief 転送用バッファにフォーマット指定した文字列データを追加する
- * @param buf 追加先バッファの参照ポインタ
- * @param fmt 文字列フォーマット
- * @return 追加後のバッファ容量
- */
-static int buf_sprintf(BUF *buf, concptr fmt, ...)
-{
-    int ret;
-    char tmpbuf[8192];
-    va_list ap;
-
-    va_start(ap, fmt);
-#if defined(HAVE_VSNPRINTF)
-    ret = vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
-#else
-    ret = vsprintf(tmpbuf, fmt, ap);
-#endif
-    va_end(ap);
-
-    if (ret < 0) {
-        return -1;
-    }
-
-    ret = buf_append(buf, tmpbuf, strlen(tmpbuf));
-    return ret;
-}
-
-size_t read_callback(char *buffer, size_t size, size_t nitems, void *userdata)
-{
-    BUF *buf = static_cast<BUF *>(userdata);
-    const size_t remain = buf->size - buf->read_head;
-    const size_t copy_size = std::min<size_t>(size * nitems, remain);
-
-    strncpy(buffer, buf->data + buf->read_head, copy_size);
-    buf->read_head += copy_size;
-
-    return copy_size;
-}
-
-/*!
- * @brief HTTPによるダンプ内容伝送
- * @param url 伝送先URL
- * @param buf 伝送内容バッファ
- * @return 送信に成功した場合TRUE、失敗した場合FALSE
- */
-static bool http_post(concptr url, BUF *buf)
+static constexpr auto get_score_content_type()
 {
-    bool succeeded = false;
-    CURL *curl = curl_easy_init();
-    if (curl == nullptr) {
-        return false;
-    }
-
-    struct curl_slist *slist = nullptr;
-    slist = curl_slist_append(slist,
 #ifdef JP
 #ifdef SJIS
-        "Content-Type: text/plain; charset=SHIFT_JIS"
+    return "text/plain; charset=SHIFT_JIS";
 #endif
 #ifdef EUC
-        "Content-Type: text/plain; charset=EUC-JP"
+    return "text/plain; charset=EUC-JP";
 #endif
 #else
-        "Content-Type: text/plain; charset=ASCII"
+    return "text/plain; charset=ASCII";
 #endif
-    );
-
-    curl_easy_setopt(curl, CURLOPT_URL, url);
-    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
-
-    char user_agent[64];
-    snprintf(user_agent, sizeof(user_agent), "Hengband %d.%d.%d", H_VER_MAJOR, H_VER_MINOR, H_VER_PATCH);
-    curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent);
-
-    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
-    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
+}
 
-    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
-    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, HTTP_TIMEOUT);
-    curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_TIMEOUT);
+/*!
+ * @brief スコアサーバにスコアを送信する
+ * @param score_data 送信するスコアデータ
+ * @return 送信に成功した場合true、失敗した場合false
+ */
+static bool post_score_to_score_server(PlayerType *player_ptr, const std::string &score_data)
+{
+    http::Client client;
+    client.user_agent = format("Hengband %d.%d.%d", H_VER_MAJOR, H_VER_MINOR, H_VER_PATCH);
 
-    curl_easy_setopt(curl, CURLOPT_POST, 1);
+    term_clear();
 
-    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10);
-    curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
+    while (true) {
+        term_fresh();
+        prt(_("スコア送信中...", "Sending the score..."), 0, 0);
+        term_fresh();
 
-    buf->read_head = 0;
-    curl_easy_setopt(curl, CURLOPT_READDATA, buf);
-    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
-    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, buf->size);
+        const auto res = client.post(SCORE_POST_URL, score_data, get_score_content_type());
+        if (res && (res->status == 200)) {
+            return true;
+        }
 
-    if (curl_easy_perform(curl) == CURLE_OK) {
-        long response_code;
-        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
-        if (response_code == 200) {
-            succeeded = true;
+        prt(_("スコア・サーバへの送信に失敗しました。", "Failed to send to the score server."), 0, 0);
+        (void)inkey();
+        if (!input_check_strict(player_ptr, _("もう一度接続を試みますか? ", "Try again? "), UserCheck::NO_HISTORY)) {
+            return false;
         }
     }
-
-    curl_slist_free_all(slist);
-    curl_easy_cleanup(curl);
-
-    return succeeded;
 }
 
 /*!
- * @brief キャラクタダンプを作って BUFに保存
+ * @brief キャラクタダンプを引数で指定した出力ストリームに書き込む
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param dumpbuf 伝送内容バッファ
+ * @param stream 書き込む出力ストリーム
  * @return エラーコード
  */
-static errr make_dump(PlayerType *player_ptr, BUF *dumpbuf)
+static errr make_dump(PlayerType *player_ptr, std::ostream &stream)
 {
-    char buf[1024];
     FILE *fff;
     GAME_TEXT file_name[1024];
 
@@ -261,13 +120,12 @@ static errr make_dump(PlayerType *player_ptr, BUF *dumpbuf)
     make_character_dump(player_ptr, fff);
     angband_fclose(fff);
 
-    /* Open for read */
-    fff = angband_fopen(file_name, FileOpenMode::READ);
-
-    while (fgets(buf, 1024, fff)) {
-        (void)buf_sprintf(dumpbuf, "%s", buf);
+    // 一時ファイルを削除する前に閉じるためブロックにする
+    {
+        std::ifstream ifs(file_name);
+        stream << ifs.rdbuf();
     }
-    angband_fclose(fff);
+
     fd_kill(file_name);
 
     /* Success */
@@ -280,27 +138,17 @@ static errr make_dump(PlayerType *player_ptr, BUF *dumpbuf)
  */
 concptr make_screen_dump(PlayerType *player_ptr)
 {
-    static concptr html_head[] = {
-        "<html>\n<body text=\"#ffffff\" bgcolor=\"#000000\">\n",
-        "<pre>",
-        0,
-    };
-    static concptr html_foot[] = {
-        "</pre>\n",
-        "</body>\n</html>\n",
-        0,
-    };
+    constexpr auto html_head =
+        "<html>\n<body text=\"#ffffff\" bgcolor=\"#000000\">\n"
+        "<pre>\n";
+    constexpr auto html_foot =
+        "</pre>\n"
+        "</body>\n</html>\n";
 
-    int wid, hgt;
-    term_get_size(&wid, &hgt);
-
-    /* Alloc buffer */
-    BUF *screen_buf;
-    screen_buf = buf_new();
-    if (screen_buf == nullptr) {
-        return nullptr;
-    }
+    const auto &[wid, hgt] = term_get_size();
+    std::stringstream screen_ss;
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     bool old_use_graphics = use_graphics;
     if (old_use_graphics) {
         /* Clear -more- prompt first */
@@ -309,19 +157,24 @@ concptr make_screen_dump(PlayerType *player_ptr)
         use_graphics = false;
         reset_visuals(player_ptr);
 
-        player_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
+        static constexpr auto flags = {
+            MainWindowRedrawingFlag::WIPE,
+            MainWindowRedrawingFlag::BASIC,
+            MainWindowRedrawingFlag::EXTRA,
+            MainWindowRedrawingFlag::MAP,
+            MainWindowRedrawingFlag::EQUIPPY,
+        };
+        rfu.set_flags(flags);
         handle_stuff(player_ptr);
     }
 
-    for (int i = 0; html_head[i]; i++) {
-        buf_sprintf(screen_buf, html_head[i]);
-    }
+    screen_ss << html_head;
 
     /* Dump the screen */
     for (int y = 0; y < hgt; y++) {
         /* Start the row */
         if (y != 0) {
-            buf_sprintf(screen_buf, "\n");
+            screen_ss << '\n';
         }
 
         /* Dump each row */
@@ -364,46 +217,44 @@ concptr make_screen_dump(PlayerType *player_ptr)
                 rv = angband_color_table[a][1];
                 gv = angband_color_table[a][2];
                 bv = angband_color_table[a][3];
-                buf_sprintf(screen_buf, "%s<font color=\"#%02x%02x%02x\">", ((y == 0 && x == 0) ? "" : "</font>"), rv, gv, bv);
+                screen_ss << format("%s<font color=\"#%02x%02x%02x\">", ((y == 0 && x == 0) ? "" : "</font>"), rv, gv, bv);
                 old_a = a;
             }
 
             if (cc) {
-                buf_sprintf(screen_buf, "%s", cc);
+                screen_ss << cc;
             } else {
-                buf_sprintf(screen_buf, "%c", c);
+                screen_ss << c;
             }
         }
     }
 
-    buf_sprintf(screen_buf, "</font>");
+    screen_ss << "</font>\n";
 
-    for (int i = 0; html_foot[i]; i++) {
-        buf_sprintf(screen_buf, html_foot[i]);
-    }
+    screen_ss << html_foot;
 
-    /* Screen dump size is too big ? */
     concptr ret;
-    if (screen_buf->size + 1 > SCREEN_BUF_MAX_SIZE) {
-        ret = nullptr;
+    if (const auto screen_dump_size = screen_ss.tellp();
+        (0 <= screen_dump_size) && (screen_dump_size < SCREEN_BUF_MAX_SIZE)) {
+        ret = string_make(screen_ss.str().data());
     } else {
-        /* Terminate string */
-        buf_append(screen_buf, "", 1);
-
-        ret = string_make(screen_buf->data);
+        ret = nullptr;
     }
 
-    /* Free buffer */
-    buf_delete(screen_buf);
-
     if (!old_use_graphics) {
         return ret;
     }
 
     use_graphics = true;
     reset_visuals(player_ptr);
-
-    player_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
+    static constexpr auto flags = {
+        MainWindowRedrawingFlag::WIPE,
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::EQUIPPY,
+    };
+    rfu.set_flags(flags);
     handle_stuff(player_ptr);
     return ret;
 }
@@ -415,54 +266,36 @@ concptr make_screen_dump(PlayerType *player_ptr)
  */
 bool report_score(PlayerType *player_ptr)
 {
-    auto *score = buf_new();
+    std::stringstream score_ss;
     std::string personality_desc = ap_ptr->title;
     personality_desc.append(_(ap_ptr->no ? "の" : "", " "));
 
     auto realm1_name = PlayerClass(player_ptr).equals(PlayerClassType::ELEMENTALIST) ? get_element_title(player_ptr->element) : realm_names[player_ptr->realm1];
-    buf_sprintf(score, "name: %s\n", player_ptr->name);
-    buf_sprintf(score, "version: %s\n", get_version().data());
-    buf_sprintf(score, "score: %d\n", calc_score(player_ptr));
-    buf_sprintf(score, "level: %d\n", player_ptr->lev);
-    buf_sprintf(score, "depth: %d\n", player_ptr->current_floor_ptr->dun_level);
-    buf_sprintf(score, "maxlv: %d\n", player_ptr->max_plv);
-    buf_sprintf(score, "maxdp: %d\n", max_dlv[DUNGEON_ANGBAND]);
-    buf_sprintf(score, "au: %d\n", player_ptr->au);
-    buf_sprintf(score, "turns: %d\n", turn_real(player_ptr, w_ptr->game_turn));
-    buf_sprintf(score, "sex: %d\n", player_ptr->psex);
-    buf_sprintf(score, "race: %s\n", rp_ptr->title);
-    buf_sprintf(score, "class: %s\n", cp_ptr->title);
-    buf_sprintf(score, "seikaku: %s\n", personality_desc.data());
-    buf_sprintf(score, "realm1: %s\n", realm1_name);
-    buf_sprintf(score, "realm2: %s\n", realm_names[player_ptr->realm2]);
-    buf_sprintf(score, "killer: %s\n", player_ptr->died_from.data());
-    buf_sprintf(score, "-----charcter dump-----\n");
-
-    make_dump(player_ptr, score);
+    score_ss << format("name: %s\n", player_ptr->name)
+             << format("version: %s\n", get_version().data())
+             << format("score: %ld\n", calc_score(player_ptr))
+             << format("level: %d\n", player_ptr->lev)
+             << format("depth: %d\n", player_ptr->current_floor_ptr->dun_level)
+             << format("maxlv: %d\n", player_ptr->max_plv)
+             << format("maxdp: %d\n", max_dlv[DUNGEON_ANGBAND])
+             << format("au: %d\n", player_ptr->au)
+             << format("turns: %d\n", turn_real(player_ptr, w_ptr->game_turn))
+             << format("sex: %d\n", player_ptr->psex)
+             << format("race: %s\n", rp_ptr->title)
+             << format("class: %s\n", cp_ptr->title)
+             << format("seikaku: %s\n", personality_desc.data())
+             << format("realm1: %s\n", realm1_name)
+             << format("realm2: %s\n", realm_names[player_ptr->realm2])
+             << format("killer: %s\n", player_ptr->died_from.data())
+             << "-----charcter dump-----\n";
+
+    make_dump(player_ptr, score_ss);
     if (screen_dump) {
-        buf_sprintf(score, "-----screen shot-----\n");
-        buf_append(score, screen_dump, strlen(screen_dump));
+        score_ss << "-----screen shot-----\n"
+                 << screen_dump;
     }
 
-    term_clear();
-    while (true) {
-        term_fresh();
-        prt(_("スコア送信中...", "Sending the score..."), 0, 0);
-        term_fresh();
-        if (http_post(SCORE_PATH, score)) {
-            buf_delete(score);
-            return true;
-        }
-
-        prt(_("スコア・サーバへの送信に失敗しました。", "Failed to send to the score server."), 0, 0);
-        (void)inkey();
-        if (get_check_strict(player_ptr, _("もう一度接続を試みますか? ", "Try again? "), CHECK_NO_HISTORY)) {
-            continue;
-        }
-
-        buf_delete(score);
-        return false;
-    }
+    return post_score_to_score_server(player_ptr, score_ss.str());
 }
 #else
 concptr screen_dump = nullptr;
index 46418b7..7b94824 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 508dc81..211c548 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 画面描画のユーティリティ
  * @date 2018/09/25
  * @author
@@ -11,8 +11,6 @@
 
 #include "io/screen-util.h"
 #include "core/player-processor.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "dungeon/quest.h"
 #include "effect/effect-characteristics.h"
@@ -29,6 +27,7 @@
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
@@ -55,12 +54,29 @@ void resize_map()
     panel_col_min = p_ptr->current_floor_ptr->width;
     verify_panel(p_ptr);
 
-    p_ptr->update |= (PU_TORCH | PU_BONUS | PU_HP | PU_MP | PU_SPELLS);
-    p_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
-    p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTER_LITE);
-    p_ptr->update |= (PU_MONSTER_STATUSES);
-    p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::TORCH,
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+        StatusRecalculatingFlag::UN_VIEW,
+        StatusRecalculatingFlag::UN_LITE,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::WIPE,
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::EQUIPPY,
+    };
+    rfu.set_flags(flags_mwrf);
     handle_stuff(p_ptr);
     term_redraw();
 
@@ -72,26 +88,25 @@ void resize_map()
 }
 
 /*!
- * @brief 現在のコンソール表示の縦横を返す。 /
- * Get term size and calculate screen size
- * @param wid_p コンソールの表示幅文字数を返す
- * @param hgt_p コンソールの表示行数を返す
+ * @brief 現在のコンソール表示の縦横を返す
  */
-void get_screen_size(TERM_LEN *wid_p, TERM_LEN *hgt_p)
+std::pair<int, int> get_screen_size()
 {
-    term_get_size(wid_p, hgt_p);
-    *hgt_p -= ROW_MAP + 2;
-    *wid_p -= COL_MAP + 2;
+    auto [width, height] = term_get_size();
+    height -= ROW_MAP + 2;
+    width -= COL_MAP + 2;
     if (use_bigtile) {
-        *wid_p /= 2;
+        width /= 2;
     }
+
+    return { width, height };
 }
 
 /*
  * Determines if a map location is currently "on screen" -RAK-
  * Note that "panel_contains(Y,X)" always implies "in_bounds2(Y,X)".
  */
-bool panel_contains(POSITION y, POSITION x)
+bool panel_contains(int y, int x)
 {
     return (y >= panel_row_min) && (y <= panel_row_max) && (x >= panel_col_min) && (x <= panel_col_max);
 }
index c40f899..79a7161 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <utility>
 
-void get_screen_size(TERM_LEN *wid_p, TERM_LEN *hgt_p);
+std::pair<int, int> get_screen_size();
 void resize_map(void);
-bool panel_contains(POSITION y, POSITION x);
+bool panel_contains(int y, int x);
index fe188e1..fb659a9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file signal-handlers.c
  * @brief シグナルハンドラの管理 / Controlling signal handlers
  * @date 2020/02/23
@@ -89,7 +89,7 @@ static void handle_signal_simple(int sig)
         quit(_("強制終了", "interrupt"));
     } else if (signal_count >= 4) {
         term_xtra(TERM_XTRA_NOISE, 0);
-        term_erase(0, 0, 255);
+        term_erase(0, 0);
         term_putstr(0, 0, -1, TERM_WHITE, _("熟慮の上の自殺!", "Contemplating suicide!"));
         term_fresh();
     } else if (signal_count >= 2) {
@@ -118,9 +118,7 @@ static void handle_signal_simple(int sig)
  */
 static void handle_signal_abort(int sig)
 {
-    int wid, hgt;
-    term_get_size(&wid, &hgt);
-
+    const auto &[wid, hgt] = term_get_size();
     (void)signal(sig, SIG_IGN);
     if (!w_ptr->character_generated || w_ptr->character_saved) {
         quit(nullptr);
@@ -130,12 +128,12 @@ static void handle_signal_abort(int sig)
     forget_view(p_ptr->current_floor_ptr);
     clear_mon_lite(p_ptr->current_floor_ptr);
 
-    term_erase(0, hgt - 1, 255);
+    term_erase(0, hgt - 1);
     term_putstr(0, hgt - 1, -1, TERM_RED, _("恐ろしいソフトのバグが飛びかかってきた!", "A gruesome software bug LEAPS out at you!"));
 
     term_putstr(45, hgt - 1, -1, TERM_RED, _("緊急セーブ...", "Panic save..."));
 
-    exe_write_diary(p_ptr, DIARY_GAMESTART, 0, _("----ゲーム異常終了----", "-- Tried Panic Save and Aborted Game --"));
+    exe_write_diary(p_ptr, DiaryKind::GAMESTART, 0, _("----ゲーム異常終了----", "-- Tried Panic Save and Aborted Game --"));
     term_fresh();
 
     p_ptr->panic_save = 1;
index 908b4fd..47b4d23 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 extern int16_t signal_count;
index a995616..5106707 100644 (file)
@@ -1,4 +1,4 @@
-#include "io/tokenizer.h"
+#include "io/tokenizer.h"
 
 /*!
  * @brief 各種データテキストをトークン単位に分解する / Extract the first few "tokens" from a buffer
index 2c041b7..75c8c65 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d88885e..f2a5c08 100644 (file)
@@ -1,10 +1,13 @@
-#include "io/uid-checker.h"
-#include "system/player-type-definition.h"
+#include "io/uid-checker.h"
+#include "system/angband.h"
+#if defined(SET_UID) && defined(SAFE_SETUID) && defined(SAFE_SETUID_POSIX)
+#include "main-unix/unix-user-ids.h"
+#endif
 
 /*!
  * @brief ファイルのドロップパーミッションチェック / Check drop permissions
  */
-void safe_setuid_drop(void)
+void safe_setuid_drop()
 {
 #if defined(SET_UID) && defined(SAFE_SETUID)
 #ifdef SAFE_SETUID_POSIX
@@ -33,23 +36,22 @@ void safe_setuid_drop(void)
 
 /*!
  * @brief ファイルのグラブパーミッションチェック / Check grab permissions
- * @param プレイヤーへの参照ポインタ
  */
-void safe_setuid_grab(PlayerType *player_ptr)
+void safe_setuid_grab()
 {
 #if defined(SET_UID) && defined(SAFE_SETUID)
 #ifdef SAFE_SETUID_POSIX
-    if (auto ret = setuid(player_ptr->player_euid); ret != 0) {
+    auto &ids = UnixUserIds::get_instance();
+    if (auto ret = setuid(ids.get_effective_user_id()); ret != 0) {
         auto msg = _("setuid(): 正しく許可が取れません! エラーコード:%d", "setuid(): cannot set permissions correctly! Error code: %d");
         quit_fmt(msg, ret);
     }
 
-    if (auto ret = setgid(player_ptr->player_egid); ret != 0) {
+    if (auto ret = setgid(ids.get_effective_group_id()); ret != 0) {
         auto msg = _("setgid(): 正しく許可が取れません! エラーコード:%d", "setgid(): cannot set permissions correctly! Error code: %d");
         quit_fmt(msg, ret);
     }
 #else
-    (void)player_ptr;
     if (auto ret = setreuid(geteuid(), getuid()); ret != 0) {
         auto msg = _("setreuid(): 正しく許可が取れません! エラーコード:%d", "setreuid(): cannot set permissions correctly! Error code: %d");
         quit_fmt(msg, ret);
@@ -61,6 +63,5 @@ void safe_setuid_grab(PlayerType *player_ptr)
     }
 #endif
 #else
-    (void)player_ptr;
 #endif
 }
index daab892..6dcebf9 100644 (file)
@@ -1,5 +1,4 @@
-#pragma once
+#pragma once
 
-class PlayerType;
-void safe_setuid_drop(void);
-void safe_setuid_grab(PlayerType *player_ptr);
+void safe_setuid_drop();
+void safe_setuid_grab();
index 58fef99..c6a45cb 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 日記へのメッセージ追加処理
  * @date 2020/03/08
  * @author Hourier
@@ -31,7 +31,7 @@ bool write_level; //!< @todo *抹殺* したい…
  * @param num number
  * @return pointer of suffix string.
  */
-concptr get_ordinal_number_suffix(int num)
+std::string get_ordinal_number_suffix(int num)
 {
     num = std::abs(num) % 100;
     switch (num % 10) {
@@ -58,14 +58,15 @@ static bool open_diary_file(FILE **fff, bool *disable_diary)
 {
     std::stringstream ss;
     ss << _("playrecord-", "playrec-") << savefile_base << ".txt";
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, ss.str());
-    *fff = angband_fopen(buf, FileOpenMode::APPEND);
+    const auto &path = path_build(ANGBAND_DIR_USER, ss.str());
+    *fff = angband_fopen(path, FileOpenMode::APPEND);
     if (*fff) {
         return true;
     }
 
-    msg_format(_("%s を開くことができませんでした。プレイ記録を一時停止します。", "Failed to open %s. Play-Record is disabled temporarily."), buf);
+    constexpr auto mes = _("%s を開くことができませんでした。プレイ記録を一時停止します。", "Failed to open %s. Play-Record is disabled temporarily.");
+    const auto &filename = path.string();
+    msg_format(mes, filename.data());
     msg_print(nullptr);
     *disable_diary = true;
     return false;
@@ -76,29 +77,32 @@ static bool open_diary_file(FILE **fff, bool *disable_diary)
  * @param player_ptr プレイヤーへの参照ポインタ
  * @return クエストIDとレベルノートのペア
  */
-static std::pair<QuestId, std::string> write_floor(PlayerType *player_ptr)
+static std::pair<QuestId, std::string> write_floor(const FloorType &floor)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto q_idx = quest_number(player_ptr, floor_ptr->dun_level);
+    auto q_idx = floor.get_quest_id();
     if (!write_level) {
-        return make_pair(q_idx, std::string());
+        return std::make_pair(q_idx, std::string());
+    }
+
+    if (floor.inside_arena) {
+        return std::make_pair(q_idx, std::string(_("アリーナ:", "Arena:")));
+    }
+
+    if (!floor.dun_level) {
+        return std::make_pair(q_idx, std::string(_("地上:", "Surface:")));
+    }
+
+    if (inside_quest(q_idx) && QuestType::is_fixed(q_idx) && !((q_idx == QuestId::OBERON) || (q_idx == QuestId::SERPENT))) {
+        return std::make_pair(q_idx, std::string(_("クエスト:", "Quest:")));
     }
 
-    if (floor_ptr->inside_arena) {
-        return make_pair(q_idx, std::string(_("アリーナ:", "Arena:")));
-    } else if (!floor_ptr->dun_level) {
-        return make_pair(q_idx, std::string(_("地上:", "Surface:")));
-    } else if (inside_quest(q_idx) && QuestType::is_fixed(q_idx) && !((q_idx == QuestId::OBERON) || (q_idx == QuestId::SERPENT))) {
-        return make_pair(q_idx, std::string(_("クエスト:", "Quest:")));
-    } else {
-        char desc[40];
+    const auto &dungeon = floor.get_dungeon_definition();
 #ifdef JP
-        strnfmt(desc, sizeof(desc), "%d階(%s):", (int)floor_ptr->dun_level, dungeons_info[player_ptr->dungeon_idx].name.data());
+    const auto desc = format("%d階(%s):", floor.dun_level, dungeon.name.data());
 #else
-        strnfmt(desc, sizeof(desc), "%s L%d:", dungeons_info[player_ptr->dungeon_idx].name.data(), (int)floor_ptr->dun_level);
+    const auto desc = format("%s L%d:", dungeon.name.data(), floor.dun_level);
 #endif
-        return make_pair(q_idx, std::string(desc));
-    }
+    return std::make_pair(q_idx, desc);
 }
 
 /*!
@@ -107,53 +111,53 @@ static std::pair<QuestId, std::string> write_floor(PlayerType *player_ptr)
  * @param num 日記へ追加する内容番号
  * @param note 日記内容のIDに応じた文字列参照ポインタ
  */
-static void write_diary_pet(FILE *fff, int num, concptr note)
+static void write_diary_pet(FILE *fff, int num, std::string_view note)
 {
     switch (num) {
     case RECORD_NAMED_PET_NAME:
-        fprintf(fff, _("%sを旅の友にすることに決めた。\n", "decided to travel together with %s.\n"), note);
+        fprintf(fff, _("%sを旅の友にすることに決めた。\n", "decided to travel together with %s.\n"), note.data());
         break;
     case RECORD_NAMED_PET_UNNAME:
-        fprintf(fff, _("%sの名前を消した。\n", "unnamed %s.\n"), note);
+        fprintf(fff, _("%sの名前を消した。\n", "unnamed %s.\n"), note.data());
         break;
     case RECORD_NAMED_PET_DISMISS:
-        fprintf(fff, _("%sを解放した。\n", "dismissed %s.\n"), note);
+        fprintf(fff, _("%sを解放した。\n", "dismissed %s.\n"), note.data());
         break;
     case RECORD_NAMED_PET_DEATH:
-        fprintf(fff, _("%sが死んでしまった。\n", "%s died.\n"), note);
+        fprintf(fff, _("%sが死んでしまった。\n", "%s died.\n"), note.data());
         break;
     case RECORD_NAMED_PET_MOVED:
-        fprintf(fff, _("%sをおいて別のマップへ移動した。\n", "moved to another map leaving %s behind.\n"), note);
+        fprintf(fff, _("%sをおいて別のマップへ移動した。\n", "moved to another map leaving %s behind.\n"), note.data());
         break;
     case RECORD_NAMED_PET_LOST_SIGHT:
-        fprintf(fff, _("%sとはぐれてしまった。\n", "lost sight of %s.\n"), note);
+        fprintf(fff, _("%sとはぐれてしまった。\n", "lost sight of %s.\n"), note.data());
         break;
     case RECORD_NAMED_PET_DESTROY:
-        fprintf(fff, _("%sが*破壊*によって消え去った。\n", "%s was killed by *destruction*.\n"), note);
+        fprintf(fff, _("%sが*破壊*によって消え去った。\n", "%s was killed by *destruction*.\n"), note.data());
         break;
     case RECORD_NAMED_PET_EARTHQUAKE:
-        fprintf(fff, _("%sが岩石に押し潰された。\n", "%s was crushed by falling rocks.\n"), note);
+        fprintf(fff, _("%sが岩石に押し潰された。\n", "%s was crushed by falling rocks.\n"), note.data());
         break;
     case RECORD_NAMED_PET_GENOCIDE:
-        fprintf(fff, _("%sが抹殺によって消え去った。\n", "%s was a victim of genocide.\n"), note);
+        fprintf(fff, _("%sが抹殺によって消え去った。\n", "%s was a victim of genocide.\n"), note.data());
         break;
     case RECORD_NAMED_PET_WIZ_ZAP:
-        fprintf(fff, _("%sがデバッグコマンドによって消え去った。\n", "%s was removed by debug command.\n"), note);
+        fprintf(fff, _("%sがデバッグコマンドによって消え去った。\n", "%s was removed by debug command.\n"), note.data());
         break;
     case RECORD_NAMED_PET_TELE_LEVEL:
-        fprintf(fff, _("%sがテレポート・レベルによって消え去った。\n", "%s was lost after teleporting a level.\n"), note);
+        fprintf(fff, _("%sがテレポート・レベルによって消え去った。\n", "%s was lost after teleporting a level.\n"), note.data());
         break;
     case RECORD_NAMED_PET_BLAST:
-        fprintf(fff, _("%sを爆破した。\n", "blasted %s.\n"), note);
+        fprintf(fff, _("%sを爆破した。\n", "blasted %s.\n"), note.data());
         break;
     case RECORD_NAMED_PET_HEAL_LEPER:
-        fprintf(fff, _("%sの病気が治り旅から外れた。\n", "%s was healed and left.\n"), note);
+        fprintf(fff, _("%sの病気が治り旅から外れた。\n", "%s was healed and left.\n"), note.data());
         break;
     case RECORD_NAMED_PET_COMPACT:
-        fprintf(fff, _("%sがモンスター情報圧縮によって消え去った。\n", "%s was lost when the monster list was pruned.\n"), note);
+        fprintf(fff, _("%sがモンスター情報圧縮によって消え去った。\n", "%s was lost when the monster list was pruned.\n"), note.data());
         break;
     case RECORD_NAMED_PET_LOSE_PARENT:
-        fprintf(fff, _("%sの召喚者が既にいないため消え去った。\n", "%s disappeared because its summoner left.\n"), note);
+        fprintf(fff, _("%sの召喚者が既にいないため消え去った。\n", "%s disappeared because its summoner left.\n"), note.data());
         break;
     default:
         fprintf(fff, "\n");
@@ -161,43 +165,39 @@ static void write_diary_pet(FILE *fff, int num, concptr note)
     }
 }
 
-/**
+/*!
  * @brief 日記にクエストに関するメッセージを追加する
- *
- * @param type 日記内容のID
+ * @param dk 日記内容のID
  * @param num 日記内容のIDに応じた番号
  * @return エラーコード
  */
-int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num)
+int exe_write_diary_quest(PlayerType *player_ptr, DiaryKind dk, QuestId num)
 {
-    static bool disable_diary = false;
-
-    int day, hour, min;
-    extract_day_hour_min(player_ptr, &day, &hour, &min);
-
+    static auto disable_diary = false;
+    const auto &[day, hour, min] = w_ptr->extract_date_time(player_ptr->start_race);
     if (disable_diary) {
         return -1;
     }
 
-    auto old_quest = player_ptr->current_floor_ptr->quest_number;
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto old_quest = floor.quest_number;
     const auto &quest_list = QuestList::get_instance();
     const auto &quest = quest_list[num];
-    player_ptr->current_floor_ptr->quest_number = (quest.type == QuestKindType::RANDOM) ? QuestId::NONE : num;
+    floor.quest_number = (quest.type == QuestKindType::RANDOM) ? QuestId::NONE : num;
     init_flags = INIT_NAME_ONLY;
     parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
-    player_ptr->current_floor_ptr->quest_number = old_quest;
+    floor.quest_number = old_quest;
 
-    const auto [q_idx, note_level] = write_floor(player_ptr);
+    const auto &[q_idx, note_level] = write_floor(floor);
 
     FILE *fff = nullptr;
     if (!open_diary_file(&fff, &disable_diary)) {
         return -1;
     }
 
-    bool do_level = true;
-
-    switch (type) {
-    case DIARY_FIX_QUEST_C: {
+    auto do_level = true;
+    switch (dk) {
+    case DiaryKind::FIX_QUEST_C: {
         if (any_bits(quest.flags, QUEST_FLAG_SILENT)) {
             break;
         }
@@ -206,7 +206,7 @@ int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num)
         fprintf(fff, mes, hour, min, note_level.data(), quest.name.data());
         break;
     }
-    case DIARY_FIX_QUEST_F: {
+    case DiaryKind::FIX_QUEST_F: {
         if (any_bits(quest.flags, QUEST_FLAG_SILENT)) {
             break;
         }
@@ -215,17 +215,17 @@ int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num)
         fprintf(fff, mes, hour, min, note_level.data(), quest.name.data());
         break;
     }
-    case DIARY_RAND_QUEST_C: {
+    case DiaryKind::RAND_QUEST_C: {
         constexpr auto mes = _(" %2d:%02d %20s ランダムクエスト(%s)を達成した。\n", " %2d:%02d %20s completed random quest '%s'\n");
         fprintf(fff, mes, hour, min, note_level.data(), monraces_info[quest.r_idx].name.data());
         break;
     }
-    case DIARY_RAND_QUEST_F: {
+    case DiaryKind::RAND_QUEST_F: {
         constexpr auto mes = _(" %2d:%02d %20s ランダムクエスト(%s)から逃げ出した。\n", " %2d:%02d %20s ran away from quest '%s'.\n");
         fprintf(fff, mes, hour, min, note_level.data(), monraces_info[quest.r_idx].name.data());
         break;
     }
-    case DIARY_TO_QUEST: {
+    case DiaryKind::TO_QUEST: {
         if (any_bits(quest.flags, QUEST_FLAG_SILENT)) {
             break;
         }
@@ -247,34 +247,29 @@ int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num)
 }
 
 /*!
- * @brief 日記にメッセージを追加する /
- * Take note to the diary.
- * @param type 日記内容のID
+ * @brief 日記にメッセージを追加する
+ * @param dk 日記内容のID
  * @param num 日記内容のIDに応じた数値
- * @param note 日記内容のIDに応じた文字列参照ポインタ
- * @return エラーコード
+ * @param note 日記内容のIDに応じた文字列
  */
-errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
+void exe_write_diary(PlayerType *player_ptr, DiaryKind dk, int num, std::string_view note)
 {
-    static bool disable_diary = false;
-
-    int day, hour, min;
-    extract_day_hour_min(player_ptr, &day, &hour, &min);
-
+    static auto disable_diary = false;
+    const auto &[day, hour, min] = w_ptr->extract_date_time(player_ptr->start_race);
     if (disable_diary) {
-        return -1;
+        return;
     }
 
     FILE *fff = nullptr;
     if (!open_diary_file(&fff, &disable_diary)) {
-        return -1;
+        return;
     }
 
-    const auto [q_idx, note_level] = write_floor(player_ptr);
-
-    bool do_level = true;
-    switch (type) {
-    case DIARY_DIALY: {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &[q_idx, note_level] = write_floor(floor);
+    auto do_level = true;
+    switch (dk) {
+    case DiaryKind::DIALY:
         if (day < MAX_DAYS) {
             fprintf(fff, _("%d日目\n", "Day %d\n"), day);
         } else {
@@ -283,135 +278,134 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
 
         do_level = false;
         break;
-    }
-    case DIARY_DESCRIPTION: {
+    case DiaryKind::DESCRIPTION:
         if (num) {
-            fprintf(fff, "%s\n", note);
+            fprintf(fff, "%s\n", note.data());
             do_level = false;
         } else {
-            fprintf(fff, " %2d:%02d %20s %s\n", hour, min, note_level.data(), note);
+            fprintf(fff, " %2d:%02d %20s %s\n", hour, min, note_level.data(), note.data());
         }
 
         break;
-    }
-    case DIARY_ART: {
-        fprintf(fff, _(" %2d:%02d %20s %sを発見した。\n", " %2d:%02d %20s discovered %s.\n"), hour, min, note_level.data(), note);
+    case DiaryKind::ART: {
+        constexpr auto mes = _(" %2d:%02d %20s %sを発見した。\n", " %2d:%02d %20s discovered %s.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), note.data());
         break;
     }
-    case DIARY_ART_SCROLL: {
-        fprintf(fff, _(" %2d:%02d %20s 巻物によって%sを生成した。\n", " %2d:%02d %20s created %s by scroll.\n"), hour, min, note_level.data(), note);
+    case DiaryKind::ART_SCROLL: {
+        constexpr auto mes = _(" %2d:%02d %20s 巻物によって%sを生成した。\n", " %2d:%02d %20s created %s by scroll.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), note.data());
         break;
     }
-    case DIARY_UNIQUE: {
-        fprintf(fff, _(" %2d:%02d %20s %sを倒した。\n", " %2d:%02d %20s defeated %s.\n"), hour, min, note_level.data(), note);
+    case DiaryKind::UNIQUE: {
+        constexpr auto mes = _(" %2d:%02d %20s %sを倒した。\n", " %2d:%02d %20s defeated %s.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), note.data());
         break;
     }
-    case DIARY_MAXDEAPTH: {
-        fprintf(fff, _(" %2d:%02d %20s %sの最深階%d階に到達した。\n", " %2d:%02d %20s reached level %d of %s for the first time.\n"), hour, min, note_level.data(),
-            _(dungeons_info[player_ptr->dungeon_idx].name.data(), num),
-            _(num, dungeons_info[player_ptr->dungeon_idx].name.data()));
+    case DiaryKind::MAXDEAPTH: {
+        constexpr auto mes = _(" %2d:%02d %20s %sの最深階%d階に到達した。\n", " %2d:%02d %20s reached level %d of %s for the first time.\n");
+        const auto &dungeon = floor.get_dungeon_definition();
+        fprintf(fff, mes, hour, min, note_level.data(), _(dungeon.name.data(), num), _(num, dungeon.name.data()));
         break;
     }
-    case DIARY_TRUMP: {
-        fprintf(fff, _(" %2d:%02d %20s %s%sの最深階を%d階にセットした。\n", " %2d:%02d %20s reset recall level of %s to %d %s.\n"), hour, min, note_level.data(), note,
-            _(dungeons_info[num].name.data(), (int)max_dlv[num]),
-            _((int)max_dlv[num], dungeons_info[num].name.data()));
+    case DiaryKind::TRUMP: {
+        constexpr auto mes = _(" %2d:%02d %20s %s%sの最深階を%d階にセットした。\n", " %2d:%02d %20s reset recall level of %s to %d %s.\n");
+        const auto &dungeon = floor.get_dungeon_definition();
+        fprintf(fff, mes, hour, min, note_level.data(), note.data(), _(dungeon.name.data(), (int)max_dlv[num]), _((int)max_dlv[num], dungeon.name.data()));
         break;
     }
-    case DIARY_STAIR: {
+    case DiaryKind::STAIR: {
         auto to = inside_quest(q_idx) && (QuestType::is_fixed(q_idx) && !((q_idx == QuestId::OBERON) || (q_idx == QuestId::SERPENT)))
                       ? _("地上", "the surface")
                   : !(player_ptr->current_floor_ptr->dun_level + num)
                       ? _("地上", "the surface")
                       : format(_("%d階", "level %d"), player_ptr->current_floor_ptr->dun_level + num);
-        fprintf(fff, _(" %2d:%02d %20s %sへ%s。\n", " %2d:%02d %20s %s %s.\n"), hour, min, note_level.data(), _(to.data(), note), _(note, to.data()));
+        constexpr auto mes = _(" %2d:%02d %20s %sへ%s。\n", " %2d:%02d %20s %s %s.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), _(to.data(), note.data()), _(note.data(), to.data()));
         break;
     }
-    case DIARY_RECALL: {
+    case DiaryKind::RECALL:
         if (!num) {
-            fprintf(fff, _(" %2d:%02d %20s 帰還を使って%sの%d階へ下りた。\n", " %2d:%02d %20s recalled to dungeon level %d of %s.\n"),
-                hour, min, note_level.data(), _(dungeons_info[player_ptr->dungeon_idx].name.data(), (int)max_dlv[player_ptr->dungeon_idx]),
-                _((int)max_dlv[player_ptr->dungeon_idx], dungeons_info[player_ptr->dungeon_idx].name.data()));
+            constexpr auto mes = _(" %2d:%02d %20s 帰還を使って%sの%d階へ下りた。\n", " %2d:%02d %20s recalled to dungeon level %d of %s.\n");
+            const auto &dungeon = floor.get_dungeon_definition();
+            fprintf(fff, mes, hour, min, note_level.data(), _(dungeon.name.data(), (int)max_dlv[floor.dungeon_idx]), _((int)max_dlv[floor.dungeon_idx], dungeon.name.data()));
         } else {
-            fprintf(fff, _(" %2d:%02d %20s 帰還を使って地上へと戻った。\n", " %2d:%02d %20s recalled from dungeon to surface.\n"), hour, min, note_level.data());
+            constexpr auto mes = _(" %2d:%02d %20s 帰還を使って地上へと戻った。\n", " %2d:%02d %20s recalled from dungeon to surface.\n");
+            fprintf(fff, mes, hour, min, note_level.data());
         }
 
         break;
-    }
-    case DIARY_TELEPORT_LEVEL: {
-        fprintf(fff, _(" %2d:%02d %20s レベル・テレポートで脱出した。\n", " %2d:%02d %20s got out using teleport level.\n"),
-            hour, min, note_level.data());
+    case DiaryKind::TELEPORT_LEVEL: {
+        constexpr auto mes = _(" %2d:%02d %20s レベル・テレポートで脱出した。\n", " %2d:%02d %20s got out using teleport level.\n");
+        fprintf(fff, mes, hour, min, note_level.data());
         break;
     }
-    case DIARY_BUY: {
-        fprintf(fff, _(" %2d:%02d %20s %sを購入した。\n", " %2d:%02d %20s bought %s.\n"), hour, min, note_level.data(), note);
+    case DiaryKind::BUY: {
+        constexpr auto mes = _(" %2d:%02d %20s %sを購入した。\n", " %2d:%02d %20s bought %s.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), note.data());
         break;
     }
-    case DIARY_SELL: {
-        fprintf(fff, _(" %2d:%02d %20s %sを売却した。\n", " %2d:%02d %20s sold %s.\n"), hour, min, note_level.data(), note);
+    case DiaryKind::SELL: {
+        constexpr auto mes = _(" %2d:%02d %20s %sを売却した。\n", " %2d:%02d %20s sold %s.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), note.data());
         break;
     }
-    case DIARY_ARENA: {
+    case DiaryKind::ARENA: {
         if (num < 0) {
             int n = -num;
-            fprintf(fff, _(" %2d:%02d %20s 闘技場の%d%s回戦で、%sの前に敗れ去った。\n", " %2d:%02d %20s beaten by %s in the %d%s fight.\n"),
-                hour, min, note_level.data(), _(n, note), _("", n), _(note, get_ordinal_number_suffix(n)));
+            constexpr auto mes = _(" %2d:%02d %20s 闘技場の%d%s回戦で、%sの前に敗れ去った。\n", " %2d:%02d %20s beaten by %s in the %d%s fight.\n");
+            fprintf(fff, mes, hour, min, note_level.data(), _(n, note.data()), _("", n), _(note.data(), get_ordinal_number_suffix(n).data()));
             break;
         }
 
-        fprintf(fff, _(" %2d:%02d %20s 闘技場の%d%s回戦(%s)に勝利した。\n", " %2d:%02d %20s won the %d%s fight (%s).\n"),
-            hour, min, note_level.data(), num, _("", get_ordinal_number_suffix(num)), note);
+        constexpr auto mes = _(" %2d:%02d %20s 闘技場の%d%s回戦(%s)に勝利した。\n", " %2d:%02d %20s won the %d%s fight (%s).\n");
+        fprintf(fff, mes, hour, min, note_level.data(), num, _("", get_ordinal_number_suffix(num).data()), note.data());
 
         if (num == MAX_ARENA_MONS) {
-            fprintf(fff, _("                 闘技場のすべての敵に勝利し、チャンピオンとなった。\n",
-                             "                 won all fights to become a Champion.\n"));
+            constexpr auto mes_champion = _("                 闘技場のすべての敵に勝利し、チャンピオンとなった。\n",
+                "                 won all fights to become a Champion.\n");
+            fprintf(fff, mes_champion);
             do_level = false;
         }
 
         break;
     }
-    case DIARY_FOUND: {
-        fprintf(fff, _(" %2d:%02d %20s %sを識別した。\n", " %2d:%02d %20s identified %s.\n"), hour, min, note_level.data(), note);
+    case DiaryKind::FOUND: {
+        constexpr auto mes = _(" %2d:%02d %20s %sを識別した。\n", " %2d:%02d %20s identified %s.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), note.data());
         break;
     }
-    case DIARY_WIZ_TELE: {
+    case DiaryKind::PAT_TELE: {
         const auto &floor_ref = *player_ptr->current_floor_ptr;
         auto to = !floor_ref.is_in_dungeon()
                       ? _("地上", "the surface")
-                      : format(_("%d階(%s)", "level %d of %s"), floor_ref.dun_level, dungeons_info[player_ptr->dungeon_idx].name.data());
-        fprintf(fff, _(" %2d:%02d %20s %sへとウィザード・テレポートで移動した。\n", " %2d:%02d %20s wizard-teleported to %s.\n"), hour, min, note_level.data(), to.data());
+                      : format(_("%d階(%s)", "level %d of %s"), floor.dun_level, floor.get_dungeon_definition().name.data());
+        constexpr auto mes = _(" %2d:%02d %20s %sへとパターンの力で移動した。\n", " %2d:%02d %20s used Pattern to teleport to %s.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), to.data());
         break;
     }
-    case DIARY_PAT_TELE: {
-        const auto &floor_ref = *player_ptr->current_floor_ptr;
-        auto to = !floor_ref.is_in_dungeon()
-                      ? _("地上", "the surface")
-                      : format(_("%d階(%s)", "level %d of %s"), floor_ref.dun_level, dungeons_info[player_ptr->dungeon_idx].name.data());
-        fprintf(fff, _(" %2d:%02d %20s %sへとパターンの力で移動した。\n", " %2d:%02d %20s used Pattern to teleport to %s.\n"), hour, min, note_level.data(), to.data());
+    case DiaryKind::LEVELUP: {
+        constexpr auto mes = _(" %2d:%02d %20s レベルが%dに上がった。\n", " %2d:%02d %20s reached player level %d.\n");
+        fprintf(fff, mes, hour, min, note_level.data(), num);
         break;
     }
-    case DIARY_LEVELUP: {
-        fprintf(fff, _(" %2d:%02d %20s レベルが%dに上がった。\n", " %2d:%02d %20s reached player level %d.\n"), hour, min, note_level.data(), num);
-        break;
-    }
-    case DIARY_GAMESTART: {
+    case DiaryKind::GAMESTART: {
         time_t ct = time((time_t *)0);
         do_level = false;
         if (num) {
-            fprintf(fff, "%s %s", note, ctime(&ct));
+            fprintf(fff, "%s %s", note.data(), ctime(&ct));
         } else {
-            fprintf(fff, " %2d:%02d %20s %s %s", hour, min, note_level.data(), note, ctime(&ct));
+            fprintf(fff, " %2d:%02d %20s %s %s", hour, min, note_level.data(), note.data(), ctime(&ct));
         }
 
         break;
     }
-    case DIARY_NAMED_PET: {
+    case DiaryKind::NAMED_PET:
         fprintf(fff, " %2d:%02d %20s ", hour, min, note_level.data());
-        write_diary_pet(fff, num, note);
+        write_diary_pet(fff, num, note.data());
         break;
-    }
-    case DIARY_WIZARD_LOG:
-        fprintf(fff, "%s\n", note);
+    case DiaryKind::WIZARD_LOG:
+        fprintf(fff, "%s\n", note.data());
         break;
     default:
         break;
@@ -422,5 +416,5 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
         write_level = false;
     }
 
-    return 0;
+    return;
 }
index cd9d371..f1ebaa8 100644 (file)
@@ -1,32 +1,37 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <string_view>
+#ifdef JP
+#else
+#include <string>
+#endif
 
-#define DIARY_DIALY 0
-#define DIARY_DESCRIPTION 1
-#define DIARY_ART 2
-#define DIARY_UNIQUE 3
-#define DIARY_FIX_QUEST_C 4
-#define DIARY_FIX_QUEST_F 5
-#define DIARY_RAND_QUEST_C 6
-#define DIARY_RAND_QUEST_F 7
-#define DIARY_MAXDEAPTH 8
-#define DIARY_TRUMP 9
-#define DIARY_STAIR 10
-#define DIARY_RECALL 11
-#define DIARY_TO_QUEST 12
-#define DIARY_TELEPORT_LEVEL 13
-#define DIARY_BUY 14
-#define DIARY_SELL 15
-#define DIARY_ARENA 16
-#define DIARY_FOUND 17
-#define DIARY_LEVELUP 18
-#define DIARY_GAMESTART 19
-#define DIARY_WIZ_TELE 20
-#define DIARY_NAMED_PET 21
-#define DIARY_PAT_TELE 22
-#define DIARY_ART_SCROLL 23
-#define DIARY_WIZARD_LOG 24
+enum class DiaryKind {
+    DIALY,
+    DESCRIPTION,
+    ART,
+    UNIQUE,
+    FIX_QUEST_C,
+    FIX_QUEST_F,
+    RAND_QUEST_C,
+    RAND_QUEST_F,
+    MAXDEAPTH,
+    TRUMP,
+    STAIR,
+    RECALL,
+    TO_QUEST,
+    TELEPORT_LEVEL,
+    BUY,
+    SELL,
+    ARENA,
+    FOUND,
+    LEVELUP,
+    GAMESTART,
+    NAMED_PET,
+    PAT_TELE,
+    ART_SCROLL,
+    WIZARD_LOG,
+};
 
 #define RECORD_NAMED_PET_NAME 0
 #define RECORD_NAMED_PET_UNNAME 1
 extern bool write_level;
 
 class PlayerType;
-enum class QuestId : int16_t;
+enum class QuestId : short;
 #ifdef JP
 #else
-concptr get_ordinal_number_suffix(int num);
+std::string get_ordinal_number_suffix(int num);
 #endif
-int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num);
-errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note);
+int exe_write_diary_quest(PlayerType *player_ptr, DiaryKind dk, QuestId num);
+void exe_write_diary(PlayerType *player_ptr, DiaryKind dk, int num, std::string_view note = "");
index 0478756..fa37fcf 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief アイテムのフレーバー初期化 (未鑑定名のシャッフル処理)
  * @author Hourier
  * @date 2022/12/28
@@ -41,7 +41,7 @@ static void shuffle_flavors(ItemKindType tval)
  */
 void initialize_items_flavor()
 {
-    const auto state_backup = w_ptr->rng.get_state();
+    const auto rng_backup = w_ptr->rng;
     w_ptr->rng.set_state(w_ptr->seed_flavor);
     for (auto &baseitem : baseitems_info) {
         if (baseitem.flavor_name.empty()) {
@@ -59,7 +59,7 @@ void initialize_items_flavor()
     shuffle_flavors(ItemKindType::FOOD);
     shuffle_flavors(ItemKindType::POTION);
     shuffle_flavors(ItemKindType::SCROLL);
-    w_ptr->rng.set_state(state_backup);
+    w_ptr->rng = rng_backup;
     for (auto &baseitem : baseitems_info) {
         if (baseitem.idx == 0 || baseitem.name.empty()) {
             continue;
index 78cb77d..dd6401c 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 void initialize_items_flavor();
index 1c06a37..910f4cc 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自動拾いの登録状況を表示する
  * @date 2020/04/23
  * @author Hourier
@@ -21,7 +21,7 @@
  */
 void do_cmd_reload_autopick(PlayerType *player_ptr)
 {
-    if (!get_check(_("自動拾い設定ファイルをロードしますか? ", "Reload auto-pick preference file? "))) {
+    if (!input_check(_("自動拾い設定ファイルをロードしますか? ", "Reload auto-pick preference file? "))) {
         return;
     }
 
@@ -73,6 +73,6 @@ void do_cmd_knowledge_autopick(PlayerType *player_ptr)
 
     angband_fclose(fff);
 
-    (void)show_file(player_ptr, true, file_name, _("自動拾い/破壊 設定リスト", "Auto-picker/Destroyer"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("自動拾い/破壊 設定リスト", "Auto-picker/Destroyer"));
     fd_kill(file_name);
 }
index 58a0af1..380a1e6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_reload_autopick(PlayerType *player_ptr);
index 2579d1f..1b0241c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 技能の経験を表示する
  * @date 2020/04/23
  * @author Hourier
@@ -69,7 +69,7 @@ void do_cmd_knowledge_weapon_exp(PlayerType *player_ptr)
     }
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("武器の経験値", "Weapon Proficiency"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("武器の経験値", "Weapon Proficiency"));
     fd_kill(file_name);
 }
 
@@ -161,7 +161,7 @@ void do_cmd_knowledge_spell_exp(PlayerType *player_ptr)
     }
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("魔法の経験値", "Spell Proficiency"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("魔法の経験値", "Spell Proficiency"));
     fd_kill(file_name);
 }
 
@@ -198,6 +198,6 @@ void do_cmd_knowledge_skill_exp(PlayerType *player_ptr)
     }
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("技能の経験値", "Miscellaneous Proficiency"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("技能の経験値", "Miscellaneous Proficiency"));
     fd_kill(file_name);
 }
index a97e8f4..ded38be 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_knowledge_weapon_exp(PlayerType *player_ptr);
index 0dfe106..cccc08a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 地形に関する情報を表示する
  * @date 2020/04/24
  * @author Hourier
@@ -16,6 +16,7 @@
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 #include "system/terrain-type-definition.h"
+#include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "util/angband-files.h"
 static FEAT_IDX collect_features(FEAT_IDX *feat_idx, BIT_FLAGS8 mode)
 {
     FEAT_IDX feat_cnt = 0;
-    for (const auto &f_ref : terrains_info) {
-        if (f_ref.name.empty()) {
+    for (const auto &terrain : TerrainList::get_instance()) {
+        if (terrain.name.empty()) {
             continue;
         }
-        if (f_ref.mimic != f_ref.idx) {
+        if (terrain.mimic != terrain.idx) {
             continue;
         }
 
-        feat_idx[feat_cnt++] = f_ref.idx;
+        feat_idx[feat_cnt++] = terrain.idx;
         if (mode & 0x01) {
             break;
         }
@@ -62,23 +63,24 @@ static void display_feature_list(int col, int row, int per_page, FEAT_IDX *feat_
         lit_col[i] = lit_col[F_LIT_STANDARD] + 2 + (i - F_LIT_NS_BEGIN) * 2 + (use_bigtile ? i : 0);
     }
 
+    const auto &terrains = TerrainList::get_instance();
     for (i = 0; i < per_page && (feat_idx[feat_top + i] >= 0); i++) {
         TERM_COLOR attr;
-        FEAT_IDX f_idx = feat_idx[feat_top + i];
-        auto *f_ptr = &terrains_info[f_idx];
+        auto terrain_id = feat_idx[feat_top + i];
+        const auto &terrain = terrains[terrain_id];
         int row_i = row + i;
         attr = ((i + feat_top == feat_cur) ? TERM_L_BLUE : TERM_WHITE);
-        c_prt(attr, f_ptr->name.data(), row_i, col);
+        c_prt(attr, terrain.name.data(), row_i, col);
         if (per_page == 1) {
-            c_prt(attr, format("(%s)", lighting_level_str[lighting_level]), row_i, col + 1 + f_ptr->name.size());
-            c_prt(attr, format("%02x/%02x", f_ptr->x_attr[lighting_level], (unsigned char)f_ptr->x_char[lighting_level]), row_i,
+            c_prt(attr, format("(%s)", lighting_level_str[lighting_level]), row_i, col + 1 + terrain.name.size());
+            c_prt(attr, format("%02x/%02x", terrain.x_attr[lighting_level], (unsigned char)terrain.x_char[lighting_level]), row_i,
                 f_idx_col - ((w_ptr->wizard || visual_only) ? 6 : 2));
         }
         if (w_ptr->wizard || visual_only) {
-            c_prt(attr, format("%d", f_idx), row_i, f_idx_col);
+            c_prt(attr, format("%d", terrain_id), row_i, f_idx_col);
         }
 
-        term_queue_bigchar(lit_col[F_LIT_STANDARD], row_i, f_ptr->x_attr[F_LIT_STANDARD], f_ptr->x_char[F_LIT_STANDARD], 0, 0);
+        term_queue_bigchar(lit_col[F_LIT_STANDARD], row_i, terrain.x_attr[F_LIT_STANDARD], terrain.x_char[F_LIT_STANDARD], 0, 0);
         term_putch(lit_col[F_LIT_NS_BEGIN], row_i, TERM_SLATE, '(');
         for (int j = F_LIT_NS_BEGIN + 1; j < F_LIT_MAX; j++) {
             term_putch(lit_col[j], row_i, TERM_SLATE, '/');
@@ -86,12 +88,12 @@ static void display_feature_list(int col, int row, int per_page, FEAT_IDX *feat_
 
         term_putch(lit_col[F_LIT_MAX - 1] + (use_bigtile ? 3 : 2), row_i, TERM_SLATE, ')');
         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
-            term_queue_bigchar(lit_col[j] + 1, row_i, f_ptr->x_attr[j], f_ptr->x_char[j], 0, 0);
+            term_queue_bigchar(lit_col[j] + 1, row_i, terrain.x_attr[j], terrain.x_char[j], 0, 0);
         }
     }
 
     for (; i < per_page; i++) {
-        term_erase(col, row + i, 255);
+        term_erase(col, row + i);
     }
 }
 
@@ -100,13 +102,13 @@ static void display_feature_list(int col, int row, int per_page, FEAT_IDX *feat_
  */
 void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f_idx, IDX *lighting_level)
 {
+    TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, std::nullopt);
+
     TERM_COLOR attr_old[F_LIT_MAX] = {};
     char char_old[F_LIT_MAX] = {};
 
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-
-    std::vector<FEAT_IDX> feat_idx(terrains_info.size());
+    const auto &[wid, hgt] = term_get_size();
+    std::vector<FEAT_IDX> feat_idx(TerrainList::get_instance().size());
 
     concptr feature_group_text[] = { "terrains", nullptr };
     int len;
@@ -132,18 +134,18 @@ void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f
 
         feat_cnt = 0;
     } else {
-        auto *f_ptr = &terrains_info[direct_f_idx];
+        auto &terrain = TerrainList::get_instance()[direct_f_idx];
 
         feat_idx[0] = direct_f_idx;
         feat_cnt = 1;
         feat_idx[1] = -1;
 
-        (void)visual_mode_command('v', &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, &f_ptr->x_attr[*lighting_level],
-            &f_ptr->x_char[*lighting_level], need_redraw);
+        (void)visual_mode_command('v', &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, &terrain.x_attr[*lighting_level],
+            &terrain.x_char[*lighting_level], need_redraw);
 
         for (FEAT_IDX i = 0; i < F_LIT_MAX; i++) {
-            attr_old[i] = f_ptr->x_attr[i];
-            char_old[i] = f_ptr->x_char[i];
+            attr_old[i] = terrain.x_attr[i];
+            char_old[i] = terrain.x_char[i];
         }
     }
 
@@ -159,10 +161,9 @@ void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f
     bool redraw = true;
     TERM_COLOR *cur_attr_ptr;
     char *cur_char_ptr;
+    auto &terrains = TerrainList::get_instance();
     while (!flag) {
         char ch;
-        TerrainType *f_ptr;
-
         if (redraw) {
             clear_from(0);
 
@@ -232,9 +233,9 @@ void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f
                 (attr_idx || char_idx) ? _(", 'c', 'p'でペースト", ", 'c', 'p' to paste") : _(", 'c'でコピー", ", 'c' to copy")),
             hgt - 1, 0);
 
-        f_ptr = &terrains_info[feat_idx[feat_cur]];
-        cur_attr_ptr = &f_ptr->x_attr[*lighting_level];
-        cur_char_ptr = &f_ptr->x_char[*lighting_level];
+        auto &terrain = terrains[feat_idx[feat_cur]];
+        cur_attr_ptr = &terrain.x_attr[*lighting_level];
+        cur_char_ptr = &terrain.x_char[*lighting_level];
 
         if (visual_list) {
             place_visual_list_cursor(max + 3, 7, *cur_attr_ptr, *cur_char_ptr, attr_top, char_left);
@@ -262,28 +263,28 @@ void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f
                 }
             }
 
-            if (f_ptr->x_attr[prev_lighting_level] != f_ptr->x_attr[*lighting_level]) {
-                attr_top = std::max<byte>(0, (f_ptr->x_attr[*lighting_level] & 0x7f) - 5);
+            if (terrain.x_attr[prev_lighting_level] != terrain.x_attr[*lighting_level]) {
+                attr_top = std::max<int8_t>(0, (terrain.x_attr[*lighting_level] & 0x7f) - 5);
             }
 
-            if (f_ptr->x_char[prev_lighting_level] != f_ptr->x_char[*lighting_level]) {
-                char_left = std::max<byte>(0, f_ptr->x_char[*lighting_level] - 10);
+            if (terrain.x_char[prev_lighting_level] != terrain.x_char[*lighting_level]) {
+                char_left = std::max<int8_t>(0, terrain.x_char[*lighting_level] - 10);
             }
 
             continue;
         } else if ((ch == 'D') || (ch == 'd')) {
-            TERM_COLOR prev_x_attr = f_ptr->x_attr[*lighting_level];
-            byte prev_x_char = f_ptr->x_char[*lighting_level];
+            TERM_COLOR prev_x_attr = terrain.x_attr[*lighting_level];
+            byte prev_x_char = terrain.x_char[*lighting_level];
 
-            apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
+            apply_default_feat_lighting(terrain.x_attr, terrain.x_char);
 
             if (visual_list) {
-                if (prev_x_attr != f_ptr->x_attr[*lighting_level]) {
-                    attr_top = std::max<byte>(0, (f_ptr->x_attr[*lighting_level] & 0x7f) - 5);
+                if (prev_x_attr != terrain.x_attr[*lighting_level]) {
+                    attr_top = std::max<int8_t>(0, (terrain.x_attr[*lighting_level] & 0x7f) - 5);
                 }
 
-                if (prev_x_char != f_ptr->x_char[*lighting_level]) {
-                    char_left = std::max<byte>(0, f_ptr->x_char[*lighting_level] - 10);
+                if (prev_x_char != terrain.x_char[*lighting_level]) {
+                    char_left = std::max<int8_t>(0, terrain.x_char[*lighting_level] - 10);
                 }
             } else {
                 *need_redraw = true;
@@ -294,8 +295,8 @@ void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f
             switch (ch) {
             case ESCAPE:
                 for (FEAT_IDX i = 0; i < F_LIT_MAX; i++) {
-                    f_ptr->x_attr[i] = attr_old[i];
-                    f_ptr->x_char[i] = char_old[i];
+                    terrain.x_attr[i] = attr_old[i];
+                    terrain.x_char[i] = char_old[i];
                 }
 
                 [[fallthrough]];
@@ -310,8 +311,8 @@ void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f
             case 'V':
             case 'v':
                 for (FEAT_IDX i = 0; i < F_LIT_MAX; i++) {
-                    attr_old[i] = f_ptr->x_attr[i];
-                    char_old[i] = f_ptr->x_char[i];
+                    attr_old[i] = terrain.x_attr[i];
+                    char_old[i] = terrain.x_char[i];
                 }
                 *lighting_level = F_LIT_STANDARD;
                 break;
@@ -320,8 +321,8 @@ void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f
             case 'c':
                 if (!visual_list) {
                     for (FEAT_IDX i = 0; i < F_LIT_MAX; i++) {
-                        attr_idx_feat[i] = f_ptr->x_attr[i];
-                        char_idx_feat[i] = f_ptr->x_char[i];
+                        attr_idx_feat[i] = terrain.x_attr[i];
+                        char_idx_feat[i] = terrain.x_char[i];
                     }
                 }
                 break;
@@ -331,10 +332,10 @@ void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f
                 if (!visual_list) {
                     for (FEAT_IDX i = F_LIT_NS_BEGIN; i < F_LIT_MAX; i++) {
                         if (attr_idx_feat[i] || (!(char_idx_feat[i] & 0x80) && char_idx_feat[i])) {
-                            f_ptr->x_attr[i] = attr_idx_feat[i];
+                            terrain.x_attr[i] = attr_idx_feat[i];
                         }
                         if (char_idx_feat[i]) {
-                            f_ptr->x_char[i] = char_idx_feat[i];
+                            terrain.x_char[i] = char_idx_feat[i];
                         }
                     }
                 }
@@ -389,6 +390,6 @@ void do_cmd_knowledge_dungeon(PlayerType *player_ptr)
     }
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("今までに入ったダンジョン", "Dungeon"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("今までに入ったダンジョン", "Dungeon"));
     fd_kill(file_name);
 }
index 7bcad5d..ea76743 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 876d4eb..a5689cd 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 装備の耐性を表示する
  * @date 2020/04/20
  * @author Hourier
@@ -14,7 +14,6 @@
 #include "object-enchant/special-object-flags.h"
 #include "object-enchant/tr-types.h"
 #include "object-hook/hook-weapon.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "perception/object-perception.h"
 #include "store/store-util.h"
@@ -110,7 +109,7 @@ static bool check_item_knowledge(ItemEntity *o_ptr, ItemKindType tval)
  */
 static void display_identified_resistances_flag(ItemEntity *o_ptr, FILE *fff)
 {
-    auto flags = object_flags_known(o_ptr);
+    auto flags = o_ptr->get_flags_known();
 
     print_im_or_res_flag(TR_IM_ACID, TR_RES_ACID, flags, fff);
     print_im_or_res_flag(TR_IM_ELEC, TR_RES_ELEC, flags, fff);
@@ -152,11 +151,9 @@ static void display_identified_resistances_flag(ItemEntity *o_ptr, FILE *fff)
  */
 static void do_cmd_knowledge_inventory_aux(PlayerType *player_ptr, FILE *fff, ItemEntity *o_ptr, char *where)
 {
-    auto tmp_item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
     constexpr auto max_item_length = 26;
-    auto item_name = str_substr(tmp_item_name, 0, max_item_length);
     std::stringstream ss;
-    ss << item_name;
+    ss << describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY, max_item_length);
     const int item_length = ss.tellp();
     constexpr auto max_display_length = 28;
     for (auto i = item_length; i < max_display_length; i++) {
@@ -259,7 +256,7 @@ static void show_holding_equipment_resistances(PlayerType *player_ptr, ItemKindT
 static void show_home_equipment_resistances(PlayerType *player_ptr, ItemKindType tval, int *label_number, FILE *fff)
 {
     store_type *store_ptr;
-    store_ptr = &towns_info[1].store[enum2i(StoreSaleType::HOME)];
+    store_ptr = &towns_info[1].stores[StoreSaleType::HOME];
     char where[32];
     strcpy(where, _("家", "H "));
     for (int i = 0; i < store_ptr->stock_num; i++) {
@@ -295,6 +292,6 @@ void do_cmd_knowledge_inventory(PlayerType *player_ptr)
     }
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("*鑑定*済み武器/防具の耐性リスト", "Resistances of *identified* equipment"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("*鑑定*済み武器/防具の耐性リスト", "Resistances of *identified* equipment"));
     fd_kill(file_name);
 }
index 791a8e0..62563a2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_knowledge_inventory(PlayerType *player_ptr);
index 83e255d..65185c6 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 既知のアイテムとアーティファクトを表示する
  * @date 2020/04/23
  * @author Hourier
@@ -26,6 +26,7 @@
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "util/angband-files.h"
@@ -111,7 +112,7 @@ void do_cmd_knowledge_artifacts(PlayerType *player_ptr)
     }
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("既知の伝説のアイテム", "Artifacts Seen"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("既知の伝説のアイテム", "Artifacts Seen"));
     fd_kill(file_name);
 }
 
@@ -210,7 +211,7 @@ static void display_object_list(int col, int row, int per_page, const std::vecto
     }
 
     for (; i < per_page; i++) {
-        term_erase(col, row + i, 255);
+        term_erase(col, row + i);
     }
 }
 
@@ -241,8 +242,10 @@ static void desc_obj_fake(PlayerType *player_ptr, short bi_id)
  */
 void do_cmd_knowledge_objects(PlayerType *player_ptr, bool *need_redraw, bool visual_only, short direct_k_idx)
 {
+    TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, std::nullopt);
+
     short object_old, object_top;
-    short grp_idx[100];
+    short grp_idx[100]{};
     int object_cnt;
 
     bool visual_list = false;
@@ -250,10 +253,8 @@ void do_cmd_knowledge_objects(PlayerType *player_ptr, bool *need_redraw, bool vi
     byte char_left = 0;
     byte mode;
 
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-
-    int browser_rows = hgt - 8;
+    const auto &[wid, hgt] = term_get_size();
+    auto browser_rows = hgt - 8;
     std::vector<short> object_idx(baseitems_info.size());
 
     int len;
index 238a131..eca86f7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_knowledge_artifacts(PlayerType *player_ptr);
index 6881ed7..bcde013 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file knowledge-monsters.cpp
  * @brief 既知のモンスターに関する情報を表示する
  * @date 2020/04/24
@@ -30,6 +30,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "term/z-form.h"
@@ -57,41 +58,37 @@ static std::vector<MonsterRaceId> collect_monsters(PlayerType *player_ptr, IDX g
     bool grp_wanted = (monster_group_char[grp_cur] == (char *)-3L);
     bool grp_amberite = (monster_group_char[grp_cur] == (char *)-4L);
 
-    std::vector<MonsterRaceId> r_idx_list;
-    for (const auto &[r_idx, r_ref] : monraces_info) {
-        if (r_ref.name.empty()) {
-            continue;
-        }
-        if (((mode != MONSTER_LORE_DEBUG) && (mode != MONSTER_LORE_RESEARCH)) && !cheat_know && !r_ref.r_sights) {
+    std::vector<MonsterRaceId> monrace_ids;
+    for (const auto &[monrace_id, monrace] : monraces_info) {
+        if (((mode != MONSTER_LORE_DEBUG) && (mode != MONSTER_LORE_RESEARCH)) && !cheat_know && !monrace.r_sights) {
             continue;
         }
 
         if (grp_unique) {
-            if (r_ref.kind_flags.has_not(MonsterKindType::UNIQUE)) {
+            if (monrace.kind_flags.has_not(MonsterKindType::UNIQUE)) {
                 continue;
             }
         } else if (grp_riding) {
-            if (none_bits(r_ref.flags7, RF7_RIDING)) {
+            if (none_bits(monrace.flags7, RF7_RIDING)) {
                 continue;
             }
         } else if (grp_wanted) {
-            auto wanted = player_ptr->knows_daily_bounty && (w_ptr->today_mon == r_ref.idx);
-            wanted |= MonsterRace(r_ref.idx).is_bounty(false);
-
+            auto wanted = player_ptr->knows_daily_bounty && (w_ptr->today_mon == monrace_id);
+            wanted |= MonsterRace(monrace_id).is_bounty(false);
             if (!wanted) {
                 continue;
             }
         } else if (grp_amberite) {
-            if (r_ref.kind_flags.has_not(MonsterKindType::AMBERITE)) {
+            if (monrace.kind_flags.has_not(MonsterKindType::AMBERITE)) {
                 continue;
             }
         } else {
-            if (!angband_strchr(group_char, r_ref.d_char)) {
+            if (!angband_strchr(group_char, monrace.d_char)) {
                 continue;
             }
         }
 
-        r_idx_list.push_back(r_ref.idx);
+        monrace_ids.push_back(monrace_id);
         if (mode == MONSTER_LORE_NORMAL) {
             break;
         }
@@ -101,8 +98,8 @@ static std::vector<MonsterRaceId> collect_monsters(PlayerType *player_ptr, IDX g
     }
 
     int dummy_why;
-    ang_sort(player_ptr, r_idx_list.data(), &dummy_why, r_idx_list.size(), ang_sort_comp_monster_level, ang_sort_swap_hook);
-    return r_idx_list;
+    ang_sort(player_ptr, monrace_ids.data(), &dummy_why, monrace_ids.size(), ang_sort_comp_monster_level, ang_sort_swap_hook);
+    return monrace_ids;
 }
 
 /*!
@@ -142,7 +139,7 @@ void do_cmd_knowledge_pets(PlayerType *player_ptr)
     fprintf(fff, _(" 維持コスト: %d%% MP\n", "   Upkeep: %d%% mana.\n"), show_upkeep);
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("現在のペット", "Current Pets"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("現在のペット", "Current Pets"));
     fd_kill(file_name);
 }
 
@@ -186,9 +183,9 @@ void do_cmd_knowledge_kill_count(PlayerType *player_ptr)
 
     std::vector<MonsterRaceId> who;
     total = 0;
-    for (const auto &[r_idx, r_ref] : monraces_info) {
-        if (MonsterRace(r_ref.idx).is_valid() && !r_ref.name.empty()) {
-            who.push_back(r_ref.idx);
+    for (const auto &[monrace_id, r_ref] : monraces_info) {
+        if (MonsterRace(monrace_id).is_valid()) {
+            who.push_back(monrace_id);
         }
     }
 
@@ -222,7 +219,7 @@ void do_cmd_knowledge_kill_count(PlayerType *player_ptr)
         fprintf(fff, "     %3d %sの %s\n", (int)this_monster, number_of_kills, r_ptr->name.data());
 #else
         if (this_monster < 2) {
-            if (angband_strstr(r_ptr->name.data(), "coins")) {
+            if (r_ptr->name.find("coins") != std::string::npos) {
                 fprintf(fff, "     1 pile of %s\n", r_ptr->name.data());
             } else {
                 fprintf(fff, "     1 %s\n", r_ptr->name.data());
@@ -245,7 +242,7 @@ void do_cmd_knowledge_kill_count(PlayerType *player_ptr)
 #endif
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("倒した敵の数", "Kill Count"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("倒した敵の数", "Kill Count"));
     fd_kill(file_name);
 }
 
@@ -269,7 +266,7 @@ static void display_monster_list(int col, int row, int per_page, const std::vect
             c_prt(attr, format("%d", enum2i(r_idx)), row + i, 62);
         }
 
-        term_erase(69, row + i, 255);
+        term_erase(69, row + i);
         term_queue_bigchar(use_bigtile ? 69 : 70, row + i, r_ptr->x_attr, r_ptr->x_char, 0, 0);
         if (!visual_only) {
             if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
@@ -281,7 +278,7 @@ static void display_monster_list(int col, int row, int per_page, const std::vect
     }
 
     for (; i < per_page; i++) {
-        term_erase(col, row + i, 255);
+        term_erase(col, row + i);
     }
 }
 
@@ -295,8 +292,9 @@ static void display_monster_list(int col, int row, int per_page, const std::vect
  */
 void do_cmd_knowledge_monsters(PlayerType *player_ptr, bool *need_redraw, bool visual_only, std::optional<MonsterRaceId> direct_r_idx)
 {
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
+    TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, std::nullopt);
+
+    const auto &[wid, hgt] = term_get_size();
     std::vector<MonsterRaceId> r_idx_list;
     std::vector<IDX> grp_idx;
 
@@ -306,7 +304,7 @@ void do_cmd_knowledge_monsters(PlayerType *player_ptr, bool *need_redraw, bool v
     byte char_left = 0;
     monster_lore_mode mode;
     const int browser_rows = hgt - 8;
-    if (!direct_r_idx.has_value()) {
+    if (!direct_r_idx) {
         mode = visual_only ? MONSTER_LORE_DEBUG : MONSTER_LORE_NORMAL;
         int len;
         for (IDX i = 0; monster_group_text[i] != nullptr; i++) {
@@ -320,10 +318,10 @@ void do_cmd_knowledge_monsters(PlayerType *player_ptr, bool *need_redraw, bool v
             }
         }
     } else {
-        r_idx_list.push_back(direct_r_idx.value());
-
-        (void)visual_mode_command('v', &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, &monraces_info[direct_r_idx.value()].x_attr,
-            &monraces_info[direct_r_idx.value()].x_char, need_redraw);
+        r_idx_list.push_back(*direct_r_idx);
+        auto &monrace = monraces_info[*direct_r_idx];
+        (void)visual_mode_command('v', &visual_list, browser_rows - 1, wid - (max + 3),
+            &attr_top, &char_left, &monrace.x_attr, &monrace.x_char, need_redraw);
     }
 
     grp_idx.push_back(-1); // Sentinel
@@ -340,7 +338,7 @@ void do_cmd_knowledge_monsters(PlayerType *player_ptr, bool *need_redraw, bool v
         if (redraw) {
             clear_from(0);
             prt(format(_("%s - モンスター", "%s - monsters"), !visual_only ? _("知識", "Knowledge") : _("表示", "Visuals")), 2, 0);
-            if (!direct_r_idx.has_value()) {
+            if (!direct_r_idx) {
                 prt(_("グループ", "Group"), 4, 0);
             }
             prt(_("名前", "Name"), 4, max + 3);
@@ -356,7 +354,7 @@ void do_cmd_knowledge_monsters(PlayerType *player_ptr, bool *need_redraw, bool v
                 term_putch(i, 5, TERM_WHITE, '=');
             }
 
-            if (!direct_r_idx.has_value()) {
+            if (!direct_r_idx) {
                 for (IDX i = 0; i < browser_rows; i++) {
                     term_putch(max + 1, 6 + i, TERM_WHITE, '|');
                 }
@@ -365,7 +363,7 @@ void do_cmd_knowledge_monsters(PlayerType *player_ptr, bool *need_redraw, bool v
             redraw = false;
         }
 
-        if (!direct_r_idx.has_value()) {
+        if (!direct_r_idx) {
             if (grp_cur < grp_top) {
                 grp_top = grp_cur;
             }
@@ -428,7 +426,7 @@ void do_cmd_knowledge_monsters(PlayerType *player_ptr, bool *need_redraw, bool v
 
         char ch = inkey();
         if (visual_mode_command(ch, &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, attr_ptr, char_ptr, need_redraw)) {
-            if (direct_r_idx.has_value()) {
+            if (direct_r_idx) {
                 switch (ch) {
                 case '\n':
                 case '\r':
@@ -500,6 +498,6 @@ void do_cmd_knowledge_bounty(PlayerType *player_ptr)
     }
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("賞金首の一覧", "Wanted monsters"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("賞金首の一覧", "Wanted monsters"));
     fd_kill(file_name);
 }
index 47f987d..88b5d8a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <optional>
index ba9f19e..88a617f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 突然変異の一覧を出力する
  * @date 2020/04/24
  * @author Hourier
@@ -24,6 +24,6 @@ void do_cmd_knowledge_mutations(PlayerType *player_ptr)
     dump_mutations(player_ptr, fff);
     angband_fclose(fff);
 
-    show_file(player_ptr, true, file_name, _("突然変異", "Mutations"), 0, 0);
+    show_file(player_ptr, true, file_name, 0, 0, _("突然変異", "Mutations"));
     fd_kill(file_name);
 }
index d1fba21..9400241 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_knowledge_mutations(PlayerType *player_ptr);
index 489a924..241f53e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 既知のクエストを表示する
  * @date 2020/04/23
  * @author Hourier
@@ -207,8 +207,7 @@ static bool do_cmd_knowledge_quests_aux(PlayerType *player_ptr, FILE *fff, Quest
         }
     }
 
-    std::string playtime_str = format("%02d:%02d:%02d", quest.comptime / (60 * 60), (quest.comptime / 60) % 60, quest.comptime % 60);
-
+    const auto playtime_str = format("%02d:%02d:%02d", quest.comptime / (60 * 60), (quest.comptime / 60) % 60, quest.comptime % 60);
     auto fputs_name_remain = [fff](const auto &name) {
         for (auto i = 1U; i < name.size(); ++i) {
             fprintf(fff, "  %s\n", name[i].data());
@@ -339,6 +338,6 @@ void do_cmd_knowledge_quests(PlayerType *player_ptr)
     }
 
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("クエスト達成状況", "Quest status"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("クエスト達成状況", "Quest status"));
     fd_kill(file_name);
 }
index 9326bcf..2094a6a 100644 (file)
@@ -1,11 +1,11 @@
-#pragma once
+#pragma once
 
 #include "dungeon/quest.h"
 #include "system/angband.h"
 #include <vector>
 
 class PlayerType;
-enum class QuestId : int16_t;
+enum class QuestId : short;
 void do_cmd_checkquest(PlayerType *player_ptr);
 void do_cmd_knowledge_quests_completed(PlayerType *player_ptr, FILE *fff, const std::vector<QuestId> &quest_numbers);
 void do_cmd_knowledge_quests_failed(PlayerType *player_ptr, FILE *fff, const std::vector<QuestId> &quest_numbers);
index 7210db2..d40560f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自己に関する情報を表示する
  * @date 2020/04/24
  * @author Hourier
@@ -44,7 +44,7 @@ void do_cmd_knowledge_virtues(PlayerType *player_ptr)
     fprintf(fff, _("現在の属性 : %s\n\n", "Your alignment : %s\n\n"), alg.data());
     dump_virtues(player_ptr, fff);
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, _("八つの徳", "Virtues"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("八つの徳", "Virtues"));
     fd_kill(file_name);
 }
 
@@ -148,7 +148,7 @@ void do_cmd_knowledge_stat(PlayerType *player_ptr)
         return;
     }
 
-    update_playtime();
+    w_ptr->update_playtime();
     uint32_t play_time = w_ptr->play_time;
     uint32_t all_time = w_ptr->sf_play_time + play_time;
     fprintf(fff, _("現在のプレイ時間 : %d:%02d:%02d\n", "Current Play Time is %d:%02d:%02d\n"), play_time / (60 * 60), (play_time / 60) % 60, play_time % 60);
@@ -176,7 +176,7 @@ void do_cmd_knowledge_stat(PlayerType *player_ptr)
     dump_winner_classes(fff);
     angband_fclose(fff);
 
-    (void)show_file(player_ptr, true, file_name, _("自分に関する情報", "HP-rate & Max stat"), 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, _("自分に関する情報", "HP-rate & Max stat"));
     fd_kill(file_name);
 }
 
@@ -195,10 +195,10 @@ void do_cmd_knowledge_home(PlayerType *player_ptr)
     }
 
     constexpr auto home_inventory = _("我が家のアイテム", "Home Inventory");
-    const auto &store = towns_info[1].store[enum2i(StoreSaleType::HOME)];
+    const auto &store = towns_info[1].stores[StoreSaleType::HOME];
     if (store.stock_num == 0) {
         angband_fclose(fff);
-        (void)show_file(player_ptr, true, file_name, home_inventory, 0, 0);
+        (void)show_file(player_ptr, true, file_name, 0, 0, home_inventory);
         fd_kill(file_name);
         return;
     }
@@ -234,6 +234,6 @@ void do_cmd_knowledge_home(PlayerType *player_ptr)
 
     fprintf(fff, "\n\n");
     angband_fclose(fff);
-    (void)show_file(player_ptr, true, file_name, home_inventory, 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, home_inventory);
     fd_kill(file_name);
 }
index c30fdb6..cffcc34 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_knowledge_virtues(PlayerType *player_ptr);
index a99cc52..8ce65b4 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 既知/存命のユニークを表示する
  * @date 2020/04/23
  * @author Hourier
 #include "util/string-processor.h"
 
 struct unique_list_type {
+    unique_list_type(bool is_alive);
+    int num_uniques[10]{};
     bool is_alive;
-    uint16_t why;
-    std::vector<MonsterRaceId> who;
-    int num_uniques[10];
-    int num_uniques_surface;
-    int num_uniques_over100;
-    int num_uniques_total;
-    int max_lev;
+    uint16_t why = 2;
+    std::vector<MonsterRaceId> monrace_ids{};
+    int num_uniques_surface = 0;
+    int num_uniques_over100 = 0;
+    int num_uniques_total = 0;
+    int max_lev = -1;
 };
 
-unique_list_type *initialize_unique_lsit_type(unique_list_type *unique_list_ptr, bool is_alive)
+unique_list_type::unique_list_type(bool is_alive)
+    : is_alive(is_alive)
 {
-    unique_list_ptr->is_alive = is_alive;
-    unique_list_ptr->why = 2;
-    unique_list_ptr->num_uniques_surface = 0;
-    unique_list_ptr->num_uniques_over100 = 0;
-    unique_list_ptr->num_uniques_total = 0;
-    unique_list_ptr->max_lev = -1;
-    for (IDX i = 0; i < 10; i++) {
-        unique_list_ptr->num_uniques[i] = 0;
-    }
-
-    return unique_list_ptr;
 }
 
 /*!
@@ -52,10 +43,6 @@ unique_list_type *initialize_unique_lsit_type(unique_list_type *unique_list_ptr,
  */
 static bool sweep_uniques(MonsterRaceInfo *r_ptr, bool is_alive)
 {
-    if (r_ptr->name.empty()) {
-        return false;
-    }
-
     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
 
         return false;
@@ -117,8 +104,8 @@ static void display_uniques(unique_list_type *unique_list_ptr, FILE *fff)
         fputs(no_unique_desc, fff);
     }
 
-    for (auto r_idx : unique_list_ptr->who) {
-        auto *r_ptr = &monraces_info[r_idx];
+    for (auto monrace_id : unique_list_ptr->monrace_ids) {
+        auto *r_ptr = &monraces_info[monrace_id];
         std::string details;
 
         if (r_ptr->defeat_level && r_ptr->defeat_time) {
@@ -141,8 +128,8 @@ static void display_uniques(unique_list_type *unique_list_ptr, FILE *fff)
  */
 void do_cmd_knowledge_uniques(PlayerType *player_ptr, bool is_alive)
 {
-    unique_list_type tmp_list;
-    unique_list_type *unique_list_ptr = initialize_unique_lsit_type(&tmp_list, is_alive);
+    unique_list_type tmp_list(is_alive);
+    unique_list_type *unique_list_ptr = &tmp_list;
     FILE *fff = nullptr;
     GAME_TEXT file_name[FILE_NAME_SIZE];
     if (!open_temporary_file(&fff, file_name)) {
@@ -171,13 +158,13 @@ void do_cmd_knowledge_uniques(PlayerType *player_ptr, bool is_alive)
             unique_list_ptr->num_uniques_surface++;
         }
 
-        unique_list_ptr->who.push_back(r_ref.idx);
+        unique_list_ptr->monrace_ids.push_back(r_ref.idx);
     }
 
-    ang_sort(player_ptr, unique_list_ptr->who.data(), &unique_list_ptr->why, unique_list_ptr->who.size(), ang_sort_comp_hook, ang_sort_swap_hook);
+    ang_sort(player_ptr, unique_list_ptr->monrace_ids.data(), &unique_list_ptr->why, unique_list_ptr->monrace_ids.size(), ang_sort_comp_hook, ang_sort_swap_hook);
     display_uniques(unique_list_ptr, fff);
     angband_fclose(fff);
     concptr title_desc = unique_list_ptr->is_alive ? _("まだ生きているユニーク・モンスター", "Alive Uniques") : _("もう撃破したユニーク・モンスター", "Dead Uniques");
-    (void)show_file(player_ptr, true, file_name, title_desc, 0, 0);
+    (void)show_file(player_ptr, true, file_name, 0, 0, title_desc);
     fd_kill(file_name);
 }
index 535d511..6ba8c33 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_knowledge_uniques(PlayerType *player_ptr, bool is_alive);
index 7e14b45..eed3f58 100644 (file)
@@ -1,4 +1,4 @@
-#include "knowledge/lighting-level-table.h"
+#include "knowledge/lighting-level-table.h"
 
 /*!
  * @brief キャラクタ色の明暗表現
index 9a57760..bac05a2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "system/terrain-type-definition.h"
index fb6b1ea..5d0d7bc 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief シンボルテキストの配列群
  * @date 2020/03/08
  * @author Hourier
index 7a35c8c..d508139 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e30be72..7d99b24 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief オブジェクト種別を表すテキストの配列群
  * @date 2020/03/08
  * @author Hourier
index aaa9a53..7a49415 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <vector>
index 6ab693c..d8771ba 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/angband-version-comparer.h"
+#include "load/angband-version-comparer.h"
 #include "system/angband-version.h"
 #include "world/world.h"
 
index ec4f054..c806901 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 1494721..8cc5caa 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/birth-loader.h"
+#include "load/birth-loader.h"
 #include "birth/quick-start.h"
 #include "load/angband-version-comparer.h"
 #include "load/load-util.h"
index 7e24c65..15c3973 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 void load_quick_start(void);
index 1aa3390..d9a93ff 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/dummy-loader.h"
+#include "load/dummy-loader.h"
 #include "load/angband-version-comparer.h"
 #include "load/load-util.h"
 #include "load/monster/monster-loader-factory.h"
index fbde072..c8a4184 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void rd_dummy1(void);
index 8818401..0882488 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/dungeon-loader.h"
+#include "load/dungeon-loader.h"
 #include "dungeon/quest.h"
 #include "floor/floor-save-util.h"
 #include "floor/floor-save.h"
@@ -29,18 +29,19 @@ static errr rd_dungeon(PlayerType *player_ptr)
 {
     init_saved_floors(player_ptr, false);
     errr err = 0;
+    auto &floor = *player_ptr->current_floor_ptr;
     if (h_older_than(1, 5, 0, 0)) {
         err = rd_dungeon_old(player_ptr);
-        if (player_ptr->dungeon_idx) {
+        if (floor.dungeon_idx) {
             player_ptr->floor_id = get_new_floor_id(player_ptr);
-            get_sf_ptr(player_ptr->floor_id)->dun_level = player_ptr->current_floor_ptr->dun_level;
+            get_sf_ptr(player_ptr->floor_id)->dun_level = floor.dun_level;
         }
 
         return err;
     }
 
     max_floor_id = rd_s16b();
-    player_ptr->dungeon_idx = rd_byte(); // @todo セーブデータの方を16ビットにするかdungeon_idxの定義を8ビットにした方が良い.
+    floor.set_dungeon_index(rd_byte()); // @todo セーブデータの方を16ビットにするかdungeon_idxの定義を8ビットにした方が良い.
     auto num = rd_byte();
     if (num == 0) {
         err = rd_saved_floor(player_ptr, nullptr);
index 822c82b..34d61f9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 02d803b..18906f6 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief その他の情報を読み込む処理
  * @date 2020/07/05
  * @author Hourier
index feb3186..3a590c4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void rd_extra(PlayerType *player_ptr);
index ff5cf37..4dfce27 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/floor-loader.h"
+#include "load/floor-loader.h"
 #include "floor/floor-generator.h"
 #include "floor/floor-object.h"
 #include "floor/floor-save-util.h"
@@ -39,7 +39,7 @@
  * この関数は、セーブデータの互換性を保つために多くのデータ改変処理を備えている。
  * 現在確認している処理は以下の通り、
  * <ul>
- * <li>1.7.0.2で8bitだったgrid_typeのfeat,mimicのID値を16bitに拡張する処理。</li>
+ * <li>1.7.0.2で8bitだったGridのfeat,mimicのID値を16bitに拡張する処理。</li>
  * <li>1.7.0.8までに廃止、IDなどを差し替えたクエスト番号を置換する処理。</li>
  * </ul>
  * The monsters/objects must be loaded in the same order
@@ -196,7 +196,7 @@ errr rd_saved_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr)
         monster_loader->rd_monster(m_ptr);
         auto *g_ptr = &floor_ptr->grid_array[m_ptr->fy][m_ptr->fx];
         g_ptr->m_idx = m_idx;
-        m_ptr->get_real_r_ref().cur_num++;
+        m_ptr->get_real_monrace().cur_num++;
     }
 
     return 0;
@@ -236,10 +236,7 @@ static bool load_floor_aux(PlayerType *player_ptr, saved_floor_type *sf_ptr)
     }
 
     auto n_x_check = x_check;
-    if (rd_u32b() != n_x_check) {
-        return false;
-    }
-    return true;
+    return rd_u32b() == n_x_check;
 }
 
 /*!
@@ -287,13 +284,13 @@ bool load_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr, BIT_FLAGS mode
         old_loading_savefile_version = loading_savefile_version;
     }
 
-    std::string floor_savefile = savefile;
+    auto floor_savefile = savefile.string();
     char ext[32];
     strnfmt(ext, sizeof(ext), ".F%02d", (int)sf_ptr->savefile_id);
     floor_savefile.append(ext);
 
-    safe_setuid_grab(player_ptr);
-    loading_savefile = angband_fopen(floor_savefile.data(), FileOpenMode::READ, true);
+    safe_setuid_grab();
+    loading_savefile = angband_fopen(floor_savefile, FileOpenMode::READ, true);
     safe_setuid_drop();
 
     bool is_save_successful = true;
@@ -308,9 +305,9 @@ bool load_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr, BIT_FLAGS mode
         }
 
         angband_fclose(loading_savefile);
-        safe_setuid_grab(player_ptr);
+        safe_setuid_grab();
         if (!(mode & SLF_NO_KILL)) {
-            (void)fd_kill(floor_savefile.data());
+            (void)fd_kill(floor_savefile);
         }
 
         safe_setuid_drop();
index c8cc21b..8c42fd6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index fceb663..201693e 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/info-loader.h"
+#include "load/info-loader.h"
 #include "game-option/runtime-arguments.h"
 #include "load/angband-version-comparer.h"
 #include "load/load-util.h"
index 16b0f1d..c06f64f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 void rd_version_info(void);
 void rd_randomizer(void);
index 9f3be15..e15b455 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/inventory-loader.h"
+#include "load/inventory-loader.h"
 #include "inventory/inventory-slot-types.h"
 #include "load/item/item-loader-factory.h"
 #include "load/load-util.h"
index a22475b..7751e25 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 29fbc64..111b25c 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/item/item-loader-base.h"
+#include "load/item/item-loader-base.h"
 #include "artifact/fixed-art-types.h"
 #include "load/angband-version-comparer.h"
 #include "load/load-util.h"
index 56eb9cc..a930477 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class ItemLoaderBase {
index a4e866e..fe14040 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief アイテム情報をセーブデータから読み込むクラスを選択するファクトリクラス
  * @date 2021/10/16
  * @author Hourier
index 6ab5a24..c5cbafc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <memory>
 
index f0e98e6..fd388e6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class ItemLoaderVersionType {
     LOAD50,
index 5a2677f..98b44ef 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/load-util.h"
+#include "load/load-util.h"
 #include "locale/japanese.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
index ec3a46f..d565b77 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 96dc653..0be2338 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/load-zangband.h"
+#include "load/load-zangband.h"
 #include "avatar/avatar.h"
 #include "cmd-building/cmd-building.h"
 #include "dungeon/quest.h"
 
 void load_zangband_options(void)
 {
-    if (option_flag[5] & (0x00000001U << 4)) {
-        option_flag[5] &= ~(0x00000001U << 4);
+    if (g_option_flags[5] & (0x00000001U << 4)) {
+        g_option_flags[5] &= ~(0x00000001U << 4);
     } else {
-        option_flag[5] |= (0x00000001U << 4);
+        g_option_flags[5] |= (0x00000001U << 4);
     }
 
-    if (option_flag[2] & (0x00000001U << 5)) {
-        option_flag[2] &= ~(0x00000001U << 5);
+    if (g_option_flags[2] & (0x00000001U << 5)) {
+        g_option_flags[2] &= ~(0x00000001U << 5);
     } else {
-        option_flag[2] |= (0x00000001U << 5);
+        g_option_flags[2] |= (0x00000001U << 5);
     }
 
-    if (option_flag[4] & (0x00000001U << 5)) {
-        option_flag[4] &= ~(0x00000001U << 5);
+    if (g_option_flags[4] & (0x00000001U << 5)) {
+        g_option_flags[4] &= ~(0x00000001U << 5);
     } else {
-        option_flag[4] |= (0x00000001U << 5);
+        g_option_flags[4] |= (0x00000001U << 5);
     }
 
-    if (option_flag[5] & (0x00000001U << 0)) {
-        option_flag[5] &= ~(0x00000001U << 0);
+    if (g_option_flags[5] & (0x00000001U << 0)) {
+        g_option_flags[5] &= ~(0x00000001U << 0);
     } else {
-        option_flag[5] |= (0x00000001U << 0);
+        g_option_flags[5] |= (0x00000001U << 0);
     }
 
-    if (option_flag[5] & (0x00000001U << 12)) {
-        option_flag[5] &= ~(0x00000001U << 12);
+    if (g_option_flags[5] & (0x00000001U << 12)) {
+        g_option_flags[5] &= ~(0x00000001U << 12);
     } else {
-        option_flag[5] |= (0x00000001U << 12);
+        g_option_flags[5] |= (0x00000001U << 12);
     }
 
-    if (option_flag[1] & (0x00000001U << 0)) {
-        option_flag[1] &= ~(0x00000001U << 0);
+    if (g_option_flags[1] & (0x00000001U << 0)) {
+        g_option_flags[1] &= ~(0x00000001U << 0);
     } else {
-        option_flag[1] |= (0x00000001U << 0);
+        g_option_flags[1] |= (0x00000001U << 0);
     }
 
-    if (option_flag[1] & (0x00000001U << 18)) {
-        option_flag[1] &= ~(0x00000001U << 18);
+    if (g_option_flags[1] & (0x00000001U << 18)) {
+        g_option_flags[1] &= ~(0x00000001U << 18);
     } else {
-        option_flag[1] |= (0x00000001U << 18);
+        g_option_flags[1] |= (0x00000001U << 18);
     }
 
-    if (option_flag[1] & (0x00000001U << 19)) {
-        option_flag[1] &= ~(0x00000001U << 19);
+    if (g_option_flags[1] & (0x00000001U << 19)) {
+        g_option_flags[1] &= ~(0x00000001U << 19);
     } else {
-        option_flag[1] |= (0x00000001U << 19);
+        g_option_flags[1] |= (0x00000001U << 19);
     }
 
-    if (option_flag[5] & (0x00000001U << 3)) {
-        option_flag[1] &= ~(0x00000001U << 3);
+    if (g_option_flags[5] & (0x00000001U << 3)) {
+        g_option_flags[1] &= ~(0x00000001U << 3);
     } else {
-        option_flag[5] |= (0x00000001U << 3);
+        g_option_flags[5] |= (0x00000001U << 3);
     }
 }
 
index 6e6f196..4fe9456 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "dungeon/quest.h"
 #include "system/angband.h"
index cc43d90..5d13b94 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief セーブファイル読み込み処理 / Purpose: support for loading savefiles -BEN-
  * @date 2014/07/07
  * @author
@@ -267,7 +267,7 @@ static errr exe_reading_savefile(PlayerType *player_ptr)
  */
 static errr rd_savefile(PlayerType *player_ptr)
 {
-    safe_setuid_grab(player_ptr);
+    safe_setuid_grab();
     loading_savefile = angband_fopen(savefile, FileOpenMode::READ, true);
     safe_setuid_drop();
     if (!loading_savefile) {
@@ -309,7 +309,7 @@ static bool on_read_save_data_not_supported(PlayerType *player_ptr, bool *new_ga
     auto mes_check_restart = _("最初からプレイを始めますか?(モンスターの思い出は引き継がれます)", "Play from the beginning? (Monster recalls will be inherited.) ");
     msg_print(mes_not_play);
     msg_print(nullptr);
-    if (!get_check(mes_check_restart)) {
+    if (!input_check(mes_check_restart)) {
         msg_print(_("ゲームを終了します。", "Exit the game."));
         msg_print(nullptr);
         return false;
@@ -346,12 +346,13 @@ bool load_savedata(PlayerType *player_ptr, bool *new_game)
     auto what = "generic";
     w_ptr->game_turn = 0;
     player_ptr->is_dead = false;
-    if (!savefile[0]) {
+    if (savefile.empty()) {
         return true;
     }
 
+    const auto &savefile_str = savefile.string();
 #ifndef WINDOWS
-    if (access(savefile, 0) < 0) {
+    if (access(savefile_str.data(), 0) < 0) {
         msg_print(_("セーブファイルがありません。", "Savefile does not exist."));
         msg_print(nullptr);
         *new_game = true;
@@ -410,7 +411,7 @@ bool load_savedata(PlayerType *player_ptr, bool *new_game)
     }
 
     if (err) {
-        msg_format("%s: %s", what, savefile);
+        msg_format("%s: %s", what, savefile_str.data());
         msg_print(nullptr);
         return false;
     }
index f11e675..71d9601 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool load_savedata(PlayerType *player_ptr, bool *new_game);
index bda2dbf..4b1894d 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/lore-loader.h"
+#include "load/lore-loader.h"
 #include "game-option/runtime-arguments.h"
 #include "load/angband-version-comparer.h"
 #include "load/load-util.h"
@@ -11,6 +11,7 @@
 #include "monster-race/race-flags7.h"
 #include "system/angband.h"
 #include "system/monster-race-info.h"
+#include "system/system-variables.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
 
@@ -107,6 +108,27 @@ static void migrate_old_drop_flags(MonsterRaceInfo *r_ptr, BIT_FLAGS old_flags1)
     }
 }
 
+static void migrate_old_no_debuff_flags(MonsterRaceInfo *r_ptr)
+{
+    struct flag_list_ver19 {
+        SavedataLoreOlderThan19FlagType_No_Debuff old_flag;
+        MonsterResistanceType flag;
+    };
+
+    const std::vector<flag_list_ver19> flag_list = {
+        { SavedataLoreOlderThan19FlagType_No_Debuff::RF3_NO_FEAR, MonsterResistanceType::NO_FEAR },
+        { SavedataLoreOlderThan19FlagType_No_Debuff::RF3_NO_STUN, MonsterResistanceType::NO_STUN },
+        { SavedataLoreOlderThan19FlagType_No_Debuff::RF3_NO_CONF, MonsterResistanceType::NO_CONF },
+        { SavedataLoreOlderThan19FlagType_No_Debuff::RF3_NO_SLEEP, MonsterResistanceType::NO_SLEEP },
+    };
+
+    for (const auto &l : flag_list) {
+        if (any_bits(r_ptr->r_flags3, l.old_flag)) {
+            r_ptr->r_resistance_flags.set(l.flag);
+        }
+    }
+}
+
 static void rd_r_drop_flags(MonsterRaceInfo *r_ptr)
 {
     if (loading_savefile_version_is_older_than(18)) {
@@ -307,6 +329,7 @@ static void rd_lore(MonsterRaceInfo *r_ptr, const MonsterRaceId r_idx)
     r_ptr->r_flags1 = rd_u32b();
     r_ptr->r_flags2 = rd_u32b();
     r_ptr->r_flags3 = rd_u32b();
+    migrate_old_no_debuff_flags(r_ptr);
     migrate_old_aura_flags(r_ptr);
     rd_r_ability_flags(r_ptr, r_idx);
     rd_r_aura_flags(r_ptr);
@@ -346,5 +369,18 @@ void load_lore(void)
         rd_lore(r_ptr, r_idx);
     }
 
+    for (size_t i = loading_max_r_idx; i < monraces_info.size(); i++) {
+        auto monrace_id = i2enum<MonsterRaceId>(i);
+        auto &monrace = monraces_info[monrace_id];
+        auto max_num = MAX_MONSTER_NUM;
+        if (monrace.kind_flags.has(MonsterKindType::UNIQUE) || monrace.population_flags.has(MonsterPopulationType::ONLY_ONE)) {
+            max_num = MAX_UNIQUE_NUM;
+        } else if (monrace.population_flags.has(MonsterPopulationType::NAZGUL)) {
+            max_num = MAX_NAZGUL_NUM;
+        }
+
+        monrace.max_num = max_num;
+    }
+
     load_note(_("モンスターの思い出をロードしました", "Loaded Monster Memory"));
 }
index 9fccece..f66a8f1 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 void load_lore(void);
index c67a650..b0db636 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class MonsterEntity;
 class PlayerType;
index 52c3ce4..06f481d 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター情報をセーブデータから読み込むクラスを選択するファクトリクラス
  * @date 2021/10/16
  * @author Hourier
index afcd4bf..113f704 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterLoaderVersionType {
     LOAD50,
index 5337130..295374d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*** Terrain Feature Index (see "lib/edit/TerrainDefinitions.txt") ***/
 enum old_feature_type {
index 357973c..1420479 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class SaveDataItemFlagType : unsigned int {
     PVAL = 0x00000001,
index e735d24..df297d0 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/old/item-loader-savefile50.h"
+#include "load/old/item-loader-savefile50.h"
 #include "artifact/fixed-art-types.h"
 #include "game-option/runtime-arguments.h"
 #include "load/angband-version-comparer.h"
@@ -8,7 +8,6 @@
 #include "load/savedata-old-flag-types.h"
 #include "object-enchant/object-ego.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "sv-definition/sv-lite-types.h"
 #include "system/angband.h"
@@ -17,7 +16,6 @@
 #include "system/player-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
-#include "util/quarks.h"
 
 /*!
  * @brief アイテムオブジェクトを読み込む(v3.0.0 Savefile ver50まで)
index a0afea3..0f0d0f1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "load/item/item-loader-base.h"
 
index aa18074..cd4033b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 変愚蛮怒 v1.5.0以前の旧いセーブデータを読み込む処理
  * @date 2020/07/04
  * @author Hourier
@@ -49,7 +49,6 @@
 #include "system/player-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
-#include "util/quarks.h"
 #include "world/world-object.h"
 #include "world/world.h"
 
@@ -370,7 +369,7 @@ void rd_monster_old(PlayerType *player_ptr, MonsterEntity *m_ptr)
     }
 
     if (h_older_than(1, 0, 14)) {
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
 
         m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
         if (r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
@@ -533,7 +532,7 @@ void set_old_lore(MonsterRaceInfo *r_ptr, BIT_FLAGS f4, const MonsterRaceId r_id
     move_RF4_BR_to_RFR(r_ptr, f4, RF4_BR_WALL, MonsterResistanceType::RESIST_FORCE);
 
     if (f4 & RF4_BR_CONF) {
-        r_ptr->r_flags3 |= RF3_NO_CONF;
+        r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_CONF);
     }
 
     if (r_idx == MonsterRaceId::STORMBRINGER) {
@@ -557,9 +556,9 @@ errr rd_dungeon_old(PlayerType *player_ptr)
     auto *floor_ptr = player_ptr->current_floor_ptr;
     floor_ptr->dun_level = rd_s16b();
     if (h_older_than(0, 3, 8)) {
-        player_ptr->dungeon_idx = DUNGEON_ANGBAND;
+        floor_ptr->set_dungeon_index(DUNGEON_ANGBAND);
     } else {
-        player_ptr->dungeon_idx = rd_byte();
+        floor_ptr->set_dungeon_index(rd_byte());
     }
 
     floor_ptr->base_level = floor_ptr->dun_level;
@@ -591,7 +590,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
         }
 
         for (int i = count; i > 0; i--) {
-            grid_type *g_ptr;
+            Grid *g_ptr;
             g_ptr = &floor_ptr->grid_array[y][x];
             g_ptr->info = info;
             if (++x >= xmax) {
@@ -607,7 +606,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
         auto count = rd_byte();
         auto tmp8u = rd_byte();
         for (int i = count; i > 0; i--) {
-            grid_type *g_ptr;
+            Grid *g_ptr;
             g_ptr = &floor_ptr->grid_array[y][x];
             g_ptr->feat = (int16_t)tmp8u;
             if (++x >= xmax) {
@@ -623,7 +622,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
         auto count = rd_byte();
         auto tmp8u = rd_byte();
         for (int i = count; i > 0; i--) {
-            grid_type *g_ptr;
+            Grid *g_ptr;
             g_ptr = &floor_ptr->grid_array[y][x];
             g_ptr->mimic = (int16_t)tmp8u;
             if (++x >= xmax) {
@@ -639,7 +638,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
         auto count = rd_byte();
         auto tmp16s = rd_s16b();
         for (int i = count; i > 0; i--) {
-            grid_type *g_ptr;
+            Grid *g_ptr;
             g_ptr = &floor_ptr->grid_array[y][x];
             g_ptr->special = tmp16s;
             if (++x >= xmax) {
@@ -662,7 +661,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
     if (h_older_than(1, 1, 1, 0)) {
         for (int y = 0; y < ymax; y++) {
             for (int x = 0; x < xmax; x++) {
-                grid_type *g_ptr;
+                Grid *g_ptr;
                 g_ptr = &floor_ptr->grid_array[y][x];
 
                 /* Very old */
@@ -683,7 +682,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
     if (h_older_than(1, 3, 1, 0)) {
         for (int y = 0; y < ymax; y++) {
             for (int x = 0; x < xmax; x++) {
-                grid_type *g_ptr;
+                Grid *g_ptr;
                 g_ptr = &floor_ptr->grid_array[y][x];
 
                 /* Old CAVE_IN_MIRROR flag */
@@ -696,7 +695,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
                 } else if (g_ptr->info & CAVE_TRAP) {
                     g_ptr->info &= ~CAVE_TRAP;
                     g_ptr->mimic = g_ptr->feat;
-                    g_ptr->feat = choose_random_trap(player_ptr);
+                    g_ptr->feat = choose_random_trap(floor_ptr);
                 } else if (g_ptr->feat == OLD_FEAT_INVIS) {
                     g_ptr->mimic = feat_floor;
                     g_ptr->feat = feat_trap_open;
@@ -709,7 +708,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
     if (!vanilla_town) {
         for (int y = 0; y < ymax; y++) {
             for (int x = 0; x < xmax; x++) {
-                grid_type *g_ptr;
+                Grid *g_ptr;
                 g_ptr = &floor_ptr->grid_array[y][x];
 
                 if ((g_ptr->special == OLD_QUEST_WATER_CAVE) && !floor_ptr->dun_level) {
@@ -766,7 +765,7 @@ errr rd_dungeon_old(PlayerType *player_ptr)
         monster_loader->rd_monster(m_ptr);
         auto *g_ptr = &floor_ptr->grid_array[m_ptr->fy][m_ptr->fx];
         g_ptr->m_idx = m_idx;
-        m_ptr->get_real_r_ref().cur_num++;
+        m_ptr->get_real_monrace().cur_num++;
     }
 
     if (h_older_than(0, 3, 13) && !floor_ptr->dun_level && !floor_ptr->inside_arena) {
index 4a33358..29b55d4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "system/monster-entity.h"
index d815c22..6c8d183 100644 (file)
@@ -1,4 +1,5 @@
-#include "load/old/load-v1-7-0.h"
+#include "load/old/load-v1-7-0.h"
+#include "dungeon/quest.h"
 #include "game-option/birth-options.h"
 #include "load/load-util.h"
 #include "load/old/load-v1-5-0.h"
@@ -29,11 +30,12 @@ void set_exp_frac_old(PlayerType *player_ptr)
 
 void remove_water_cave(PlayerType *player_ptr)
 {
-    if (player_ptr->current_floor_ptr->quest_number != i2enum<QuestId>(OLD_QUEST_WATER_CAVE)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.quest_number != i2enum<QuestId>(OLD_QUEST_WATER_CAVE)) {
         return;
     }
 
-    player_ptr->dungeon_idx = lite_town ? DUNGEON_ANGBAND : DUNGEON_GALGALS;
-    player_ptr->current_floor_ptr->dun_level = 1;
-    player_ptr->current_floor_ptr->quest_number = QuestId::NONE;
+    floor.set_dungeon_index(lite_town ? DUNGEON_ANGBAND : DUNGEON_GALGALS);
+    floor.dun_level = 1;
+    floor.quest_number = QuestId::NONE;
 }
index 5811557..067af39 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void set_hp_old(PlayerType *player_ptr);
index d464e9f..ef73b51 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class SaveDataMonsterFlagType {
     AP_R_IDX = 0x00000001,
index e79edb8..dfee189 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/old/monster-loader-savefile50.h"
+#include "load/old/monster-loader-savefile50.h"
 #include "load/angband-version-comparer.h"
 #include "load/load-util.h"
 #include "load/old/load-v1-5-0.h"
@@ -7,7 +7,6 @@
 #include "system/player-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
-#include "util/quarks.h"
 
 MonsterLoader50::MonsterLoader50(PlayerType *player_ptr)
     : player_ptr(player_ptr)
index 1ec4532..543aba1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "load/monster/monster-loader-base.h"
 
index 0225e58..06fef96 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/option-loader.h"
+#include "load/option-loader.h"
 #include "cmd-io/cmd-gameoption.h"
 #include "game-option/cheat-options.h"
 #include "game-option/option-flags.h"
@@ -22,7 +22,7 @@
  * The window options are stored in the same way, but note that each
  * window gets 32 options, and their order is fixed by certain defines.
  */
-void rd_options(void)
+void rd_options()
 {
     strip_bytes(16);
 
@@ -63,26 +63,27 @@ void rd_options(void)
     autosave_t = rd_bool();
     autosave_freq = rd_s16b();
 
-    BIT_FLAGS flag[8];
-    for (int n = 0; n < 8; n++) {
+    uint32_t flag[8]{};
+    for (auto n = 0; n < MAX_WINDOW_ENTITIES; n++) {
         flag[n] = rd_u32b();
     }
 
-    BIT_FLAGS mask[8];
-    for (int n = 0; n < 8; n++) {
+    uint32_t mask[8]{};
+    for (auto n = 0; n < MAX_WINDOW_ENTITIES; n++) {
         mask[n] = rd_u32b();
     }
 
-    for (auto n = 0; n < 8; n++) {
+    for (auto n = 0; n < MAX_WINDOW_ENTITIES; n++) {
         for (auto i = 0; i < 32; i++) {
-            if (none_bits(mask[n], 1U << i) || none_bits(option_mask[n], 1U << i)) {
+            if (none_bits(mask[n], 1U << i) || none_bits(g_option_masks[n], 1U << i)) {
                 continue;
             }
 
+            auto &option_flag = g_option_flags[n];
             if (flag[n] & (1UL << i)) {
-                option_flag[n] |= (1UL << i);
+                option_flag |= (1UL << i);
             } else {
-                option_flag[n] &= ~(1UL << i);
+                option_flag &= ~(1UL << i);
             }
         }
     }
@@ -92,28 +93,19 @@ void rd_options(void)
     }
 
     extract_option_vars();
-    for (int n = 0; n < 8; n++) {
-        flag[n] = rd_u32b();
-    }
 
-    for (int n = 0; n < 8; n++) {
-        mask[n] = rd_u32b();
+    decltype(g_window_flags) savefile_window_flags;
+    for (auto &window_flag : savefile_window_flags) {
+        rd_FlagGroup_bytes(window_flag, rd_byte, 4);
     }
 
-    for (int n = 0; n < 8; n++) {
-        for (int i = 0; i < 32; i++) {
-            if (!(mask[n] & (1UL << i))) {
-                continue;
-            }
-            if (!(window_mask[n] & (1UL << i))) {
-                continue;
-            }
+    decltype(g_window_masks) savefile_window_masks;
+    for (auto &window_mask : savefile_window_masks) {
+        rd_FlagGroup_bytes(window_mask, rd_byte, 4);
+    }
 
-            if (flag[n] & (1UL << i)) {
-                window_flag[n] |= (1UL << i);
-            } else {
-                window_flag[n] &= ~(1UL << i);
-            }
-        }
+    for (auto n = 0; n < MAX_WINDOW_ENTITIES; n++) {
+        const auto window_mask = g_window_masks[n] & savefile_window_masks[n];
+        g_window_flags[n] = savefile_window_flags[n] & window_mask;
     }
 }
index 6a44680..d550ced 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
-void rd_options(void);
+void rd_options();
index df057b9..a2506fb 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/player-attack-loader.h"
+#include "load/player-attack-loader.h"
 #include "load/angband-version-comparer.h"
 #include "load/load-util.h"
 #include "load/load-zangband.h"
index 67736d6..f4d2885 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void rd_special_attack(PlayerType *player_ptr);
index c74b2b3..b851ce9 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/player-class-specific-data-loader.h"
+#include "load/player-class-specific-data-loader.h"
 #include "load/load-util.h"
 #include "player-info/bard-data-type.h"
 #include "player-info/bluemage-data-type.h"
@@ -155,7 +155,7 @@ void PlayerClassSpecificDataLoader::operator()(std::shared_ptr<mane_data_type> &
     }
 }
 
-void PlayerClassSpecificDataLoader::operator()(std::shared_ptr<sniper_data_type> &sniper_data) const
+void PlayerClassSpecificDataLoader::operator()(std::shared_ptr<SniperData> &sniper_data) const
 {
     if (loading_savefile_version_is_older_than(9)) {
         // 古いセーブファイルのスナイパーのデータは magic_num には保存されていないので読み捨てる
index 020ba8c..239e2ab 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include "system/system-variables.h"
@@ -10,7 +10,7 @@ struct bluemage_data_type;
 struct magic_eater_data_type;
 struct bard_data_type;
 struct mane_data_type;
-struct sniper_data_type;
+class SniperData;
 struct samurai_data_type;
 struct monk_data_type;
 struct ninja_data_type;
@@ -26,7 +26,7 @@ public:
     void operator()(std::shared_ptr<magic_eater_data_type> &magic_eater_data) const;
     void operator()(std::shared_ptr<bard_data_type> &bird_data) const;
     void operator()(std::shared_ptr<mane_data_type> &mane_data) const;
-    void operator()(std::shared_ptr<sniper_data_type> &sniper_data) const;
+    void operator()(std::shared_ptr<SniperData> &sniper_data) const;
     void operator()(std::shared_ptr<samurai_data_type> &samurai_data) const;
     void operator()(std::shared_ptr<monk_data_type> &monk_data) const;
     void operator()(std::shared_ptr<ninja_data_type> &ninja_data) const;
index 635fbdc..949bdef 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/player-info-loader.h"
+#include "load/player-info-loader.h"
 #include "cmd-building/cmd-building.h"
 #include "load/angband-version-comparer.h"
 #include "load/birth-loader.h"
@@ -20,6 +20,7 @@
 #include "player/player-skill.h"
 #include "spell-realm/spells-song.h"
 #include "system/angband-exceptions.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
@@ -65,9 +66,7 @@ void rd_base_info(PlayerType *player_ptr)
     if (!h_older_than(1, 7, 0, 1)) {
         char buf[1024];
         rd_string(buf, sizeof buf);
-        if (buf[0]) {
-            player_ptr->last_message = string_make(buf);
-        }
+        player_ptr->last_message = buf;
     }
 
     load_quick_start();
@@ -260,10 +259,11 @@ static void rd_phase_out(PlayerType *player_ptr)
         }
     }
     player_ptr->current_floor_ptr->quest_number = i2enum<QuestId>(quest_number);
+    auto &system = AngbandSystem::get_instance();
     if (h_older_than(0, 3, 5)) {
-        player_ptr->phase_out = false;
+        system.set_phase_out(false);
     } else {
-        player_ptr->phase_out = rd_s16b() != 0;
+        system.set_phase_out(rd_s16b() != 0);
     }
 }
 
@@ -284,7 +284,7 @@ static void rd_arena(PlayerType *player_ptr)
     }
 
     rd_phase_out(player_ptr);
-    player_ptr->exit_bldg = rd_byte();
+    w_ptr->set_arena(rd_bool());
     strip_bytes(1);
 
     player_ptr->oldpx = rd_s16b();
@@ -489,7 +489,7 @@ static void rd_player_status(PlayerType *player_ptr)
     strip_bytes(8);
     player_ptr->sc = rd_s16b();
     if (loading_savefile_version_is_older_than(9)) {
-        auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+        auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
         if (sniper_data) {
             sniper_data->concent = rd_s16b();
         } else {
index 9a5d4ef..58a9c1f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void rd_base_info(PlayerType *player_ptr);
index 8e24f27..8b82dd2 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/quest-loader.h"
+#include "load/quest-loader.h"
 #include "artifact/fixed-art-types.h"
 #include "dungeon/quest.h"
 #include "floor/floor-town.h"
index 3da0c79..84d48cf 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <tuple>
index 76951b8..923abef 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file savedata-old-flag-types.h
  * @brief 過去に存在したセーブデータ有無フラグを定義する。古いセーブデータからのマイグレーション用。
  */
@@ -71,6 +71,13 @@ enum class SavedataLoreOlderThan19FlagType {
     RF2_KILL_WALL = 0x00080000, /*!< モンスター特性: 壁を破壊して進む / Monster can destroy walls */
 };
 
+enum class SavedataLoreOlderThan19FlagType_No_Debuff : uint32_t {
+    RF3_NO_FEAR = 0x10000000, /*!< モンスター特性: 恐怖しない / Cannot be scared */
+    RF3_NO_STUN = 0x20000000, /*!< モンスター特性: 朦朧としない / Cannot be stunned */
+    RF3_NO_CONF = 0x40000000, /*!< モンスター特性: 混乱しない / Cannot be confused and resist confusion */
+    RF3_NO_SLEEP = 0x80000000, /*!< モンスター特性: 眠らない / Cannot be slept */
+};
+
 enum class OldQuestId15 {
     CITY_SEA = 17,
 };
index 80795d5..c7a6990 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/store-loader.h"
+#include "load/store-loader.h"
 #include "avatar/avatar.h"
 #include "floor/floor-town.h"
 #include "load/angband-version-comparer.h"
@@ -67,24 +67,24 @@ static void home_carry_load(PlayerType *player_ptr, store_type *store_ptr, ItemE
  * @param store_number 店舗ID
  * @return エラーID
  */
-static void rd_store(PlayerType *player_ptr, int town_number, int store_number)
+static void rd_store(PlayerType *player_ptr, int town_number, StoreSaleType store_number)
 {
     store_type *store_ptr;
     auto sort = false;
-    if (h_older_than(0, 3, 3) && (i2enum<StoreSaleType>(store_number) == StoreSaleType::HOME)) {
-        store_ptr = &towns_info[1].store[store_number];
+    if (h_older_than(0, 3, 3) && (store_number == StoreSaleType::HOME)) {
+        store_ptr = &towns_info[1].stores[store_number];
         if (store_ptr->stock_num) {
             sort = true;
         }
     } else {
-        store_ptr = &towns_info[town_number].store[store_number];
+        store_ptr = &towns_info[town_number].stores[store_number];
     }
 
     store_ptr->store_open = rd_s32b();
     store_ptr->insult_cur = rd_s16b();
     store_ptr->owner = rd_byte();
 
-    if (auto num = owners.at(i2enum<StoreSaleType>(store_number)).size();
+    if (auto num = owners.at(store_number).size();
         num <= store_ptr->owner) {
         store_ptr->owner %= num;
     }
@@ -104,7 +104,7 @@ static void rd_store(PlayerType *player_ptr, int town_number, int store_number)
     for (int j = 0; j < inven_num; j++) {
         ItemEntity item;
         item_loader->rd_item(&item);
-        auto stock_max = store_get_stock_max(i2enum<StoreSaleType>(store_number));
+        auto stock_max = store_get_stock_max(store_number);
         if (store_ptr->stock_num >= stock_max) {
             continue;
         }
@@ -120,16 +120,15 @@ static void rd_store(PlayerType *player_ptr, int town_number, int store_number)
 
 /*!
  * @brief 店舗情報を読み込む
- * @param player_ptr プレイヤー情報への参照ポインタ(未使用)
- * @return 読み込み終わったら0、失敗したら22
+ * @param player_ptr プレイヤーへの参照ポインタ
  */
 void load_store(PlayerType *player_ptr)
 {
-    int16_t town_count = rd_u16b();
-    int16_t store_count = rd_u16b();
-    for (int16_t town_idx = 1; town_idx < town_count; town_idx++) {
-        for (int16_t store_idx = 0; store_idx < store_count; store_idx++) {
-            rd_store(player_ptr, town_idx, store_idx);
+    const int town_count = rd_u16b();
+    const int store_count = rd_u16b();
+    for (auto town_idx = 1; town_idx < town_count; town_idx++) {
+        for (auto store_idx = 0; store_idx < store_count; store_idx++) {
+            rd_store(player_ptr, town_idx, i2enum<StoreSaleType>(store_idx));
         }
     }
 }
index 7c162b0..88e5f1a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void load_store(PlayerType *player_ptr);
index b8507c4..830d4e3 100644 (file)
@@ -1,4 +1,4 @@
-#include "load/world-loader.h"
+#include "load/world-loader.h"
 #include "cmd-building/cmd-building.h"
 #include "floor/wild.h"
 #include "load/angband-version-comparer.h"
index 1a4c535..ceb6130 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 2bf064f..682190d 100644 (file)
@@ -1,4 +1,4 @@
-#include "locale/english.h"
+#include "locale/english.h"
 #include "system/angband.h"
 #include "util/string-processor.h"
 
@@ -52,6 +52,8 @@ void plural_aux(char *Name)
         strcpy(&(Name[NameLen - 1]), "ies");
     } else if (suffix(Name, "ouse")) {
         strcpy(&(Name[NameLen - 4]), "ice");
+    } else if (suffix(Name, "ous")) {
+        strcpy(&(Name[NameLen - 3]), "i");
     } else if (suffix(Name, "us")) {
         strcpy(&(Name[NameLen - 2]), "i");
     } else if (suffix(Name, "kelman")) {
index f650822..47ef3a4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #ifndef JP
 void plural_aux(char *Name);
index bf5f563..c165a90 100644 (file)
@@ -1,14 +1,16 @@
-/*!
- *  @file japanese.c
+/*!
+ *  @file japanese.cpp
  *  @brief 日本語処理関数
  *  @date 2014/07/07
  */
 
 #include "locale/japanese.h"
 #include "locale/utf-8.h"
+#include "util/enum-converter.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 #include <set>
+#include <sstream>
 
 #ifdef JP
 
@@ -78,13 +80,15 @@ std::string sindarin_to_kana(std::string_view sindarin)
     return kana;
 }
 
-/*! 日本語動詞活用 (打つ>打って,打ち etc)
- * JVERB_AND: 殴る,蹴る > 殴り,蹴る
- * JVERB_TO:  殴る,蹴る > 殴って蹴る
- * JVERB_OR:  殴る,蹴る > 殴ったり蹴ったり */
-static const struct jverb_table_t {
-    const char *from;
-    const char *to[3];
+/*!
+ * 日本語動詞活用 (打つ>打って,打ち etc)
+ * AND : 殴る,蹴る > 殴り,蹴る
+ * TO  : 殴る,蹴る > 殴って蹴る
+ * OR  : 殴る,蹴る > 殴ったり蹴ったり
+ */
+static constexpr struct jverb_table_t {
+    std::string_view from;
+    std::string_view to_list[3];
 } jverb_table[] = {
     { "する", { "し", "して", "した" } },
     { "いる", { "いて", "いて", "いた" } },
@@ -114,34 +118,34 @@ static const struct jverb_table_t {
     { "ぶ", { "び", "んで", "んだ" } },
     { "む", { "み", "んで", "んだ" } },
     { "る", { "り", "って", "った" } },
-    { nullptr, { "そして", "ことにより", "ことや" } },
 };
 
 /*!
  * @brief jverb_table_tに従って動詞を活用する
- * @param in 変換元文字列ポインタ
- * @param out 変換先文字列ポインタ
- * @param flag 変換種類を指定(JVERB_AND/JVERB_TO/JVERB_OR)
- * @details
+ * @param in 変換元となる原形動詞
+ * @param type 変換種類を指定(AND/TO/OR)
+ * @return 活用形の動詞
  */
-void jverb(concptr in, char *out, int flag)
+std::string conjugate_jverb(std::string_view in, JVerbConjugationType type)
 {
-    const struct jverb_table_t *p;
-    int in_len = strlen(in);
-
-    strcpy(out, in);
+    std::stringstream ss;
 
-    for (p = jverb_table; p->from; p++) {
-        int from_len = strlen(p->from);
-        if (strncmp(&in[in_len - from_len], p->from, from_len) == 0) {
-            strcpy(&out[in_len - from_len], p->to[flag - 1]);
-            break;
+    for (const auto &[from, to_list] : jverb_table) {
+        const auto stem_length = in.length() - from.length();
+        if (in.substr(stem_length) == from) {
+            ss << in.substr(0, stem_length) << to_list[enum2i(type)];
+            return ss.str();
         }
     }
 
-    if (p->from == nullptr) {
-        strcpy(&out[in_len], p->to[flag - 1]);
-    }
+    constexpr std::string_view conjuctions[3] = {
+        "そして",
+        "ことにより",
+        "ことや",
+    };
+
+    ss << in << conjuctions[enum2i(type)];
+    return ss.str();
 }
 
 static const std::set<std::string_view> kinsoku_list{
@@ -250,9 +254,7 @@ void euc2sjis(char *str)
 byte codeconv(char *str)
 {
     byte code = 0;
-    int i;
-
-    for (i = 0; str[i]; i++) {
+    for (auto i = 0; str[i]; i++) {
         unsigned char c1;
         unsigned char c2;
 
@@ -280,9 +282,13 @@ byte codeconv(char *str)
                 /* No conversion */
                 return 0;
             }
-        }
+        } else {
+            auto is_cp932 = (0x81 <= c1 && c1 <= 0x9f) && ((0x40 <= c2 && c2 <= 0x7e) || (0x80 <= c2 && c2 <= 0xfc));
+            is_cp932 |= (0xe0 <= c1 && c1 <= 0xfc) && (0x40 <= c2 && c2 <= 0x7e);
+            if (!is_cp932) {
+                continue;
+            }
 
-        else if (((0x81 <= c1 && c1 <= 0x9f) && ((0x40 <= c2 && c2 <= 0x7e) || (0x80 <= c2 && c2 <= 0xfc))) || ((0xe0 <= c1 && c1 <= 0xfc) && (0x40 <= c2 && c2 <= 0x7e))) {
             /* Only SJIS is allowed */
             if (!code) {
                 /* SJIS */
@@ -357,20 +363,45 @@ static bool is_ascii_str(concptr str)
 }
 
 #if defined(EUC)
+#include <algorithm>
 #include <iconv.h>
+#include <initializer_list>
+#include <vector>
+
+// UTF-8 の文字列長は必ずしも3バイトとは限らないが、変愚蛮怒の仕様範囲では3固定.
+constexpr auto ENCODING_LENGTH = 3;
+class EncodingConverter {
+public:
+    EncodingConverter(const std::initializer_list<unsigned char> from, const std::initializer_list<unsigned char> to)
+        : from(from)
+        , to(to)
+    {
+    }
+
+    bool equals(const unsigned char *p) const
+    {
+        return std::equal(from.begin(), from.end(), p);
+    }
+
+    void replace(unsigned char *p) const
+    {
+        std::copy_n(to.begin(), ENCODING_LENGTH, p);
+    }
+
+private:
+    std::vector<unsigned char> from;
+    std::vector<unsigned char> to;
+};
 
-static const struct ms_to_jis_unicode_conv_t {
-    unsigned char from[3];
-    unsigned char to[3];
-} ms_to_jis_unicode_conv[] = {
-    { { 0xef, 0xbd, 0x9e }, { 0xe3, 0x80, 0x9c } }, /* FULLWIDTH TILDE -> WAVE DASH */
-    { { 0xef, 0xbc, 0x8d }, { 0xe2, 0x88, 0x92 } }, /* FULLWIDTH HYPHEN-MINUS -> MINUS SIGN */
+const std::vector<EncodingConverter> encoding_characters = {
+    { { 0xef, 0xbd, 0x9e }, { 0xe3, 0x80, 0x9c } }, /* FULLWIDTH TILDE -> WAVE DASH (全角チルダ → 波ダッシュ) */
+    { { 0xef, 0xbc, 0x8d }, { 0xe2, 0x88, 0x92 } }, /* FULLWIDTH HYPHEN-MINUS -> MINUS SIGN (全角ハイフン → マイナス記号) */
 };
 
 /*!
  * @brief 受け取ったUTF-8文字列を調べ、特定のコードポイントの文字の置き換えを行う
  *
- * 受け取ったUTF-8の文字列に含まれる文字を1つ1つしらべて、ms_to_jis_unicode_conv で
+ * 受け取ったUTF-8の文字列に含まれる文字を1つ1つ調べて、encoding_characters で
  * 定義されている特定のコードポイントの文字の変換を行う。
  *
  * '~'と'-'は、Windows環境(CP932)とLinux/UNIX環境(EUC-JP)でUTF-8に対応する
@@ -386,9 +417,8 @@ static const struct ms_to_jis_unicode_conv_t {
  */
 static void ms_to_jis_unicode(char *str)
 {
-    unsigned char *p;
-    for (p = (unsigned char *)str; *p; p++) {
-        int subseq_num = 0;
+    for (auto *p = (unsigned char *)str; *p; p++) {
+        auto subseq_num = 0;
         if (0x00 < *p && *p <= 0x7f) {
             continue;
         }
@@ -396,16 +426,17 @@ static void ms_to_jis_unicode(char *str)
         if ((*p & 0xe0) == 0xc0) {
             subseq_num = 1;
         }
+
         if ((*p & 0xf0) == 0xe0) {
-            size_t i;
-            for (i = 0; i < sizeof(ms_to_jis_unicode_conv) / sizeof(ms_to_jis_unicode_conv[0]); ++i) {
-                const struct ms_to_jis_unicode_conv_t *c = &ms_to_jis_unicode_conv[i];
-                if (memcmp(p, c->from, 3) == 0) {
-                    memcpy(p, c->to, 3);
+            for (const auto &converter : encoding_characters) {
+                if (converter.equals(p)) {
+                    converter.replace(p);
                 }
             }
+
             subseq_num = 2;
         }
+
         if ((*p & 0xf8) == 0xf0) {
             subseq_num = 3;
         }
@@ -511,6 +542,42 @@ static bool utf8_to_sys(char *utf8_str, char *sys_str_buffer, size_t sys_str_buf
 
     return true;
 
+#else
+    return false;
+#endif
+}
+
+/*!
+ * @brief システムの文字コードからUTF-8に変換する
+ * @param str システムの文字コードの文字列
+ * @return UTF-8に変換した文字列
+ *         変換に失敗した場合はstd::nullopt
+ */
+std::optional<std::string> sys_to_utf8(std::string_view str)
+{
+#if defined(EUC)
+    std::string utf8str(str.length() * 2 + 1, '\0');
+    const auto len = euc_to_utf8(str.data(), str.length(), utf8str.data(), utf8str.size());
+
+    return (len >= 0) ? std::make_optional(std::move(utf8str.erase(len))) : std::nullopt;
+#elif defined(SJIS) && defined(WINDOWS)
+    /* SJIS(CP932) -> UTF-16 */
+    std::vector<WCHAR> utf16buf(str.length());
+    const auto utf16_len = MultiByteToWideChar(932, 0, str.data(), str.size(), utf16buf.data(), utf16buf.size());
+    if (utf16_len == 0) {
+        return std::nullopt;
+    }
+
+    /* UTF-16 -> UTF-8 */
+    std::vector<char> utf8buf(str.length() * 2 + 1);
+    const auto utf8_len = WideCharToMultiByte(CP_UTF8, 0, utf16buf.data(), utf16_len, utf8buf.data(), utf8buf.size(), nullptr, nullptr);
+    if (utf8_len == 0) {
+        return std::nullopt;
+    }
+
+    return std::make_optional<std::string>(utf8buf.data(), utf8_len);
+#else
+    return std::nullopt;
 #endif
 }
 
index 4c2c45b..9225057 100644 (file)
@@ -1,15 +1,18 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
+#include <optional>
 #include <string>
 #include <string_view>
 
 #ifdef JP
 
-constexpr int JVERB_AND = 1;
-constexpr int JVERB_TO = 2;
-constexpr int JVERB_OR = 3;
-void jverb(concptr in, char *out, int flag);
+enum class JVerbConjugationType {
+    AND = 0,
+    TO = 1,
+    OR = 2,
+};
+std::string conjugate_jverb(std::string_view in, JVerbConjugationType type);
 
 std::string sindarin_to_kana(std::string_view sindarin);
 bool is_kinsoku(std::string_view ch);
@@ -17,6 +20,7 @@ void sjis2euc(char *str);
 void euc2sjis(char *str);
 byte codeconv(char *str);
 bool iskanji2(concptr s, int x);
+std::optional<std::string> sys_to_utf8(std::string_view str);
 void guess_convert_to_system_encoding(char *strbuf, int buflen);
 
 int lb_to_kg_integer(int x);
@@ -27,6 +31,25 @@ int utf8_to_euc(char *utf8_str, size_t utf8_str_len, char *euc_buf, size_t euc_b
 int euc_to_utf8(const char *euc_str, size_t euc_str_len, char *utf8_buf, size_t utf8_buf_len);
 #endif
 
+/*!
+ * @brief インチ→cm変換
+ */
+constexpr int inch_to_cm(int inch)
+{
+    return inch * 254 / 100;
+}
+
+/*!
+ * @brief ポンド→kg変換
+ *
+ * 体重表記用
+ * アイテムの重量は0.5kg単位にするためlb_to_kg_integer/fractionを使用する
+ */
+constexpr int lb_to_kg(int lb)
+{
+    return lb * 4536 / 10000;
+}
+
 #else
 
 constexpr bool is_kinsoku(std::string_view)
@@ -34,4 +57,9 @@ constexpr bool is_kinsoku(std::string_view)
     return false;
 }
 
+inline std::optional<std::string> sys_to_utf8(std::string_view str)
+{
+    return std::make_optional<std::string>(str);
+}
+
 #endif
index 3e5f610..9829532 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/h-basic.h"
 
index ab447d3..38bed85 100644 (file)
@@ -1,4 +1,4 @@
-#include "locale/utf-8.h"
+#include "locale/utf-8.h"
 
 /*!
  * @brief 文字列の最初の文字のUTF-8エンコーディングにおけるバイト長を返す
index 059e099..3fcc78c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b119ed9..f310bec 100644 (file)
@@ -1,4 +1,4 @@
-#include "lore/combat-types-setter.h"
+#include "lore/combat-types-setter.h"
 #include "lore/lore-util.h"
 #include "monster-attack/monster-attack-effect.h"
 #include "monster-attack/monster-attack-table.h"
@@ -7,7 +7,7 @@
 
 void set_monster_blow_method(lore_type *lore_ptr, int m)
 {
-    RaceBlowMethodType method = lore_ptr->r_ptr->blow[m].method;
+    RaceBlowMethodType method = lore_ptr->r_ptr->blows[m].method;
     lore_ptr->p = nullptr;
     lore_ptr->pc = TERM_WHITE;
     switch (method) {
@@ -110,7 +110,7 @@ void set_monster_blow_method(lore_type *lore_ptr, int m)
 
 void set_monster_blow_effect(lore_type *lore_ptr, int m)
 {
-    RaceBlowEffectType effect = lore_ptr->r_ptr->blow[m].effect;
+    RaceBlowEffectType effect = lore_ptr->r_ptr->blows[m].effect;
     lore_ptr->q = nullptr;
     lore_ptr->qc = TERM_WHITE;
     switch (effect) {
@@ -257,6 +257,10 @@ void set_monster_blow_effect(lore_type *lore_ptr, int m)
         lore_ptr->q = _("空腹を進行させる", "increase hunger");
         lore_ptr->qc = TERM_L_BLUE;
         break;
+    case RaceBlowEffectType::CHAOS:
+        lore_ptr->q = _("カオスを呼び起こす", "call chaotic.");
+        lore_ptr->qc = TERM_VIOLET;
+        break;
     case RaceBlowEffectType::FLAVOR:
         // フレーバー打撃には何の効果もないので付加説明もない。
         break;
index a0ebfa7..d2e5c60 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct lore_type;
 void set_monster_blow_method(lore_type *lore_ptr, int m);
index 4ae2050..de206f5 100644 (file)
@@ -1,4 +1,4 @@
-#include "lore/lore-calculator.h"
+#include "lore/lore-calculator.h"
 #include "game-option/cheat-options.h"
 #include "lore/lore-util.h"
 #include "monster-race/monster-race.h"
@@ -92,23 +92,25 @@ bool know_armour(MonsterRaceId r_idx, const bool know_everything)
  */
 bool know_damage(MonsterRaceId r_idx, int i)
 {
-    auto *r_ptr = &monraces_info[r_idx];
-    DEPTH level = r_ptr->level;
-    int32_t a = r_ptr->r_blows[i];
-
-    int32_t d1 = r_ptr->blow[i].d_dice;
-    int32_t d2 = r_ptr->blow[i].d_side;
-    int32_t d = d1 * d2;
+    const auto &monrace = monraces_info[r_idx];
+    auto level = monrace.level;
+    auto a = monrace.r_blows[i];
+    auto d1 = monrace.blows[i].d_dice;
+    auto d2 = monrace.blows[i].d_side;
+    auto d = d1 * d2;
 
     if (d >= ((4 + level) * MAX_UCHAR) / 80) {
         d = ((4 + level) * MAX_UCHAR - 1) / 80;
     }
+
     if ((4 + level) * a > 80 * d) {
         return true;
     }
-    if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
+
+    if (monrace.kind_flags.has_not(MonsterKindType::UNIQUE)) {
         return false;
     }
+
     if ((4 + level) * (2 * a) > 80 * d) {
         return true;
     }
index 9eb3082..7e6d971 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
index 90a4252..e480ab9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの思い出を記憶する処理
  * @date 2020/06/09
  * @author Hourier
@@ -14,6 +14,7 @@
 #include "system/monster-entity.h" //!< @todo 違和感、m_ptr は外から与えることとしたい.
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 
 template <class T>
 static int count_lore_mflag_group(const EnumClassFlagGroup<T> &flags, const EnumClassFlagGroup<T> &r_flags)
@@ -43,8 +44,8 @@ int lore_do_probe(PlayerType *player_ptr, MonsterRaceId r_idx)
     }
     r_ptr->r_wake = r_ptr->r_ignore = MAX_UCHAR;
 
-    for (int i = 0; i < 4; i++) {
-        if (r_ptr->blow[i].effect != RaceBlowEffectType::NONE || r_ptr->blow[i].method != RaceBlowMethodType::NONE) {
+    for (auto i = 0; i < 4; i++) {
+        if (r_ptr->blows[i].effect != RaceBlowEffectType::NONE || r_ptr->blows[i].method != RaceBlowMethodType::NONE) {
             if (r_ptr->r_blows[i] != MAX_UCHAR) {
                 n++;
             }
@@ -52,15 +53,21 @@ int lore_do_probe(PlayerType *player_ptr, MonsterRaceId r_idx)
         }
     }
 
-    byte tmp_byte = ((r_ptr->drop_flags.has(MonsterDropType::DROP_4D2) ? 8 : 0) + (r_ptr->drop_flags.has(MonsterDropType::DROP_3D2) ? 6 : 0) + (r_ptr->drop_flags.has(MonsterDropType::DROP_2D2) ? 4 : 0) + (r_ptr->drop_flags.has(MonsterDropType::DROP_1D2) ? 2 : 0) + (r_ptr->drop_flags.has(MonsterDropType::DROP_90) ? 1 : 0) + (r_ptr->drop_flags.has(MonsterDropType::DROP_60) ? 1 : 0));
+    using Mdt = MonsterDropType;
+    byte tmp_byte = (r_ptr->drop_flags.has(Mdt::DROP_4D2) ? 8 : 0);
+    tmp_byte += (r_ptr->drop_flags.has(Mdt::DROP_3D2) ? 6 : 0);
+    tmp_byte += (r_ptr->drop_flags.has(Mdt::DROP_2D2) ? 4 : 0);
+    tmp_byte += (r_ptr->drop_flags.has(Mdt::DROP_1D2) ? 2 : 0);
+    tmp_byte += (r_ptr->drop_flags.has(Mdt::DROP_90) ? 1 : 0);
+    tmp_byte += (r_ptr->drop_flags.has(Mdt::DROP_60) ? 1 : 0);
 
-    if (r_ptr->drop_flags.has_not(MonsterDropType::ONLY_GOLD)) {
+    if (r_ptr->drop_flags.has_not(Mdt::ONLY_GOLD)) {
         if (r_ptr->r_drop_item != tmp_byte) {
             n++;
         }
         r_ptr->r_drop_item = tmp_byte;
     }
-    if (r_ptr->drop_flags.has_not(MonsterDropType::ONLY_ITEM)) {
+    if (r_ptr->drop_flags.has_not(Mdt::ONLY_ITEM)) {
         if (r_ptr->r_drop_gold != tmp_byte) {
             n++;
         }
@@ -105,7 +112,7 @@ int lore_do_probe(PlayerType *player_ptr, MonsterRaceId r_idx)
     r_ptr->r_can_evolve = true;
 
     if (player_ptr->monster_race_idx == r_idx) {
-        player_ptr->window_flags |= (PW_MONSTER_LORE);
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
     }
 
     return n;
@@ -121,7 +128,7 @@ int lore_do_probe(PlayerType *player_ptr, MonsterRaceId r_idx)
 void lore_treasure(PlayerType *player_ptr, MONSTER_IDX m_idx, ITEM_NUMBER num_item, ITEM_NUMBER num_gold)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     if (!m_ptr->is_original_ap()) {
         return;
@@ -141,6 +148,6 @@ void lore_treasure(PlayerType *player_ptr, MONSTER_IDX m_idx, ITEM_NUMBER num_it
         r_ptr->r_drop_flags.set(MonsterDropType::DROP_GREAT);
     }
     if (player_ptr->monster_race_idx == m_ptr->r_idx) {
-        player_ptr->window_flags |= (PW_MONSTER_LORE);
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
     }
 }
index 32a58a8..f27434b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d8ecb9c..4523afb 100644 (file)
@@ -1,4 +1,4 @@
-#include "lore/lore-util.h"
+#include "lore/lore-util.h"
 #include "game-option/birth-options.h"
 #include "monster-attack/monster-attack-table.h"
 #include "monster-race/monster-race.h"
@@ -29,35 +29,28 @@ const who_word_definition Who::words = {
  */
 hook_c_roff_pf hook_c_roff = c_roff;
 
-lore_type *initialize_lore_type(lore_type *lore_ptr, MonsterRaceId r_idx, monster_lore_mode mode)
+lore_type::lore_type(MonsterRaceId r_idx, monster_lore_mode mode)
+    : r_idx(r_idx)
+    , mode(mode)
+    , msex(MSEX_NONE)
+    , method(RaceBlowMethodType::NONE)
 {
-#ifdef JP
-#else
-    lore_ptr->sin = false;
-#endif
-    lore_ptr->r_idx = r_idx;
-    lore_ptr->nightmare = ironman_nightmare && (mode != MONSTER_LORE_DEBUG);
-    lore_ptr->r_ptr = &monraces_info[r_idx];
-    lore_ptr->speed = lore_ptr->nightmare ? lore_ptr->r_ptr->speed + 5 : lore_ptr->r_ptr->speed;
-    lore_ptr->drop_gold = lore_ptr->r_ptr->r_drop_gold;
-    lore_ptr->drop_item = lore_ptr->r_ptr->r_drop_item;
-    lore_ptr->flags1 = (lore_ptr->r_ptr->flags1 & lore_ptr->r_ptr->r_flags1);
-    lore_ptr->flags2 = (lore_ptr->r_ptr->flags2 & lore_ptr->r_ptr->r_flags2);
-    lore_ptr->flags3 = (lore_ptr->r_ptr->flags3 & lore_ptr->r_ptr->r_flags3);
-    lore_ptr->ability_flags = (lore_ptr->r_ptr->ability_flags & lore_ptr->r_ptr->r_ability_flags);
-    lore_ptr->aura_flags = (lore_ptr->r_ptr->aura_flags & lore_ptr->r_ptr->r_aura_flags);
-    lore_ptr->behavior_flags = (lore_ptr->r_ptr->behavior_flags & lore_ptr->r_ptr->r_behavior_flags);
-    lore_ptr->drop_flags = (lore_ptr->r_ptr->drop_flags & lore_ptr->r_ptr->r_drop_flags);
-    lore_ptr->flags7 = (lore_ptr->r_ptr->flags7 & lore_ptr->r_ptr->flags7);
-    lore_ptr->resistance_flags = (lore_ptr->r_ptr->resistance_flags & lore_ptr->r_ptr->r_resistance_flags);
-    lore_ptr->feature_flags = (lore_ptr->r_ptr->feature_flags & lore_ptr->r_ptr->r_feature_flags);
-    lore_ptr->brightness_flags = lore_ptr->r_ptr->brightness_flags;
-    lore_ptr->reinforce = false;
-    lore_ptr->know_everything = false;
-    lore_ptr->mode = mode;
-    lore_ptr->old = false;
-    lore_ptr->count = 0;
-    return lore_ptr;
+    this->nightmare = ironman_nightmare && (mode != MONSTER_LORE_DEBUG);
+    this->r_ptr = &monraces_info[r_idx];
+    this->speed = this->nightmare ? this->r_ptr->speed + 5 : this->r_ptr->speed;
+    this->drop_gold = this->r_ptr->r_drop_gold;
+    this->drop_item = this->r_ptr->r_drop_item;
+    this->flags1 = (this->r_ptr->flags1 & this->r_ptr->r_flags1);
+    this->flags2 = (this->r_ptr->flags2 & this->r_ptr->r_flags2);
+    this->flags3 = (this->r_ptr->flags3 & this->r_ptr->r_flags3);
+    this->ability_flags = (this->r_ptr->ability_flags & this->r_ptr->r_ability_flags);
+    this->aura_flags = (this->r_ptr->aura_flags & this->r_ptr->r_aura_flags);
+    this->behavior_flags = (this->r_ptr->behavior_flags & this->r_ptr->r_behavior_flags);
+    this->drop_flags = (this->r_ptr->drop_flags & this->r_ptr->r_drop_flags);
+    this->flags7 = (this->r_ptr->flags7 & this->r_ptr->flags7);
+    this->resistance_flags = (this->r_ptr->resistance_flags & this->r_ptr->r_resistance_flags);
+    this->feature_flags = (this->r_ptr->feature_flags & this->r_ptr->r_feature_flags);
+    this->brightness_flags = this->r_ptr->brightness_flags;
 }
 
 /*!
index c7f0347..924b117 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "monster-attack/monster-attack-table.h"
 #include "monster-race/monster-aura-types.h"
@@ -24,13 +24,45 @@ enum monster_sex {
     MSEX_FEMALE = 2,
 };
 
+enum monster_lore_mode {
+    MONSTER_LORE_NONE,
+    MONSTER_LORE_NORMAL,
+    MONSTER_LORE_RESEARCH,
+    MONSTER_LORE_DEBUG
+};
+
 class MonsterRaceInfo;
 struct lore_type {
-#ifdef JP
-    char jverb_buf[64];
-#else
-    bool sin;
+    lore_type(MonsterRaceId r_idx, monster_lore_mode mode);
+
+#ifndef JP
+    bool sin = false;
 #endif
+
+    bool reinforce = false;
+    bool know_everything = false;
+    bool old = false;
+    int count = 0;
+    bool shoot = false;
+    bool rocket = false;
+    int vn = 0;
+    byte color[96]{};
+    concptr vp[96]{};
+    char tmp_msg[96][96]{};
+    bool breath = false;
+    bool magic = false;
+    int drop_quantity = 0;
+    concptr drop_quality = "";
+    concptr p = "";
+    byte pc = 0;
+    concptr q = "";
+    byte qc = 0;
+
+    MonsterRaceId r_idx;
+    BIT_FLAGS mode;
+    monster_sex msex;
+    RaceBlowMethodType method;
+
     bool nightmare;
     MonsterRaceInfo *r_ptr;
     byte speed;
@@ -39,6 +71,7 @@ struct lore_type {
     BIT_FLAGS flags1;
     BIT_FLAGS flags2;
     BIT_FLAGS flags3;
+    BIT_FLAGS flags7;
     EnumClassFlagGroup<MonsterAbilityType> ability_flags;
     EnumClassFlagGroup<MonsterAuraType> aura_flags;
     EnumClassFlagGroup<MonsterBehaviorType> behavior_flags;
@@ -48,43 +81,11 @@ struct lore_type {
     EnumClassFlagGroup<MonsterDropType> drop_flags;
     EnumClassFlagGroup<MonsterFeatureType> feature_flags;
     EnumClassFlagGroup<MonsterBrightnessType> brightness_flags;
-
-    BIT_FLAGS flags7;
-    bool reinforce;
-    bool know_everything;
-    BIT_FLAGS mode;
-    monster_sex msex;
-    bool old;
-    MonsterRaceId r_idx;
-    int vn;
-    byte color[96];
-    concptr vp[96];
-    char tmp_msg[96][96];
-    bool breath;
-    bool magic;
-    int drop_quantity;
-    concptr drop_quality;
-    concptr p;
-    byte pc;
-    concptr q;
-    byte qc;
-    RaceBlowMethodType method;
-    int count;
-    bool shoot = false;
-    bool rocket = false;
-};
-
-enum monster_lore_mode {
-    MONSTER_LORE_NONE,
-    MONSTER_LORE_NORMAL,
-    MONSTER_LORE_RESEARCH,
-    MONSTER_LORE_DEBUG
 };
 
 using hook_c_roff_pf = void (*)(TERM_COLOR attr, std::string_view str);
 extern hook_c_roff_pf hook_c_roff;
 
-lore_type *initialize_lore_type(lore_type *lore_ptr, MonsterRaceId r_idx, monster_lore_mode mode);
 void hooked_roff(std::string_view str);
 
 enum WHO_WORD_TYPE { WHO = 0,
index b2316ff..e453c5e 100644 (file)
@@ -1,4 +1,4 @@
-#include "lore/magic-types-setter.h"
+#include "lore/magic-types-setter.h"
 #include "lore/lore-calculator.h"
 #include "lore/lore-util.h"
 #include "monster-race/race-brightness-mask.h"
@@ -243,6 +243,12 @@ void set_ball_types(PlayerType *player_ptr, lore_type *lore_ptr)
         lore_ptr->vp[lore_ptr->vn] = lore_ptr->tmp_msg[lore_ptr->vn];
         lore_ptr->color[lore_ptr->vn++] = TERM_L_DARK;
     }
+
+    if (lore_ptr->ability_flags.has(MonsterAbilityType::BA_METEOR)) {
+        set_damage(player_ptr, lore_ptr, MonsterAbilityType::BA_METEOR, _("メテオスウォーム%s", "invoke meteor swarm%s"));
+        lore_ptr->vp[lore_ptr->vn] = lore_ptr->tmp_msg[lore_ptr->vn];
+        lore_ptr->color[lore_ptr->vn++] = TERM_UMBER;
+    }
 }
 
 void set_particular_types(PlayerType *player_ptr, lore_type *lore_ptr)
@@ -369,6 +375,18 @@ void set_bolt_types(PlayerType *player_ptr, lore_type *lore_ptr)
         lore_ptr->color[lore_ptr->vn++] = TERM_L_DARK;
     }
 
+    if (lore_ptr->ability_flags.has(MonsterAbilityType::BO_METEOR)) {
+        set_damage(player_ptr, lore_ptr, MonsterAbilityType::BO_METEOR, _("メテオストライク%s", "produce meteor strikes%s"));
+        lore_ptr->vp[lore_ptr->vn] = lore_ptr->tmp_msg[lore_ptr->vn];
+        lore_ptr->color[lore_ptr->vn++] = TERM_UMBER;
+    }
+
+    if (lore_ptr->ability_flags.has(MonsterAbilityType::BO_LITE)) {
+        set_damage(player_ptr, lore_ptr, MonsterAbilityType::BO_LITE, _("スターライトアロー%s", "produce starlight arrow%s"));
+        lore_ptr->vp[lore_ptr->vn] = lore_ptr->tmp_msg[lore_ptr->vn];
+        lore_ptr->color[lore_ptr->vn++] = TERM_YELLOW;
+    }
+
     if (lore_ptr->ability_flags.has(MonsterAbilityType::MISSILE)) {
         set_damage(player_ptr, lore_ptr, MonsterAbilityType::MISSILE, _("マジックミサイル%s", "produce magic missiles%s"));
         lore_ptr->vp[lore_ptr->vn] = lore_ptr->tmp_msg[lore_ptr->vn];
@@ -569,4 +587,9 @@ void set_summon_types(lore_type *lore_ptr)
         lore_ptr->vp[lore_ptr->vn] = _("ユニーク・モンスター召喚", "summon Unique Monsters");
         lore_ptr->color[lore_ptr->vn++] = TERM_VIOLET;
     }
+
+    if (lore_ptr->ability_flags.has(MonsterAbilityType::S_DEAD_UNIQUE)) {
+        lore_ptr->vp[lore_ptr->vn] = _("ユニーク・モンスター口寄せ", "animate Unique Monsters");
+        lore_ptr->color[lore_ptr->vn++] = TERM_VIOLET;
+    }
 }
index 0eb6632..4d7c19a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct lore_type;
 class PlayerType;
index a704139..944513b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの思い出表示に必要なフラグ類の処理
  * @date 2020/06/09
  * @author Hourier
@@ -14,6 +14,7 @@
 #include "monster-race/race-flags2.h"
 #include "monster-race/race-flags3.h"
 #include "monster-race/race-indice-types.h"
+#include "monster-race/race-sex-const.h"
 #include "player-ability/player-ability-types.h"
 #include "system/angband.h"
 #include "system/monster-race-info.h"
 static void set_msex_flags(lore_type *lore_ptr)
 {
     lore_ptr->msex = MSEX_NONE;
-    if (lore_ptr->r_ptr->flags1 & RF1_FEMALE) {
-        lore_ptr->msex = MSEX_FEMALE;
-        return;
-    }
-
-    if (lore_ptr->r_ptr->flags1 & RF1_MALE) {
+    if (is_male(*(lore_ptr->r_ptr))) {
         lore_ptr->msex = MSEX_MALE;
     }
+    if (is_female(*(lore_ptr->r_ptr))) {
+        lore_ptr->msex = MSEX_FEMALE;
+    }
 }
 
 static void set_flags1(lore_type *lore_ptr)
@@ -48,14 +47,6 @@ static void set_flags1(lore_type *lore_ptr)
         lore_ptr->flags1 |= (RF1_QUESTOR);
     }
 
-    if (lore_ptr->r_ptr->flags1 & RF1_MALE) {
-        lore_ptr->flags1 |= (RF1_MALE);
-    }
-
-    if (lore_ptr->r_ptr->flags1 & RF1_FEMALE) {
-        lore_ptr->flags1 |= (RF1_FEMALE);
-    }
-
     if (lore_ptr->r_ptr->flags1 & RF1_FRIENDS) {
         lore_ptr->flags1 |= (RF1_FRIENDS);
     }
@@ -144,8 +135,8 @@ static void set_race_flags(lore_type *lore_ptr)
  */
 void process_monster_lore(PlayerType *player_ptr, MonsterRaceId r_idx, monster_lore_mode mode)
 {
-    lore_type tmp_lore;
-    lore_type *lore_ptr = initialize_lore_type(&tmp_lore, r_idx, mode);
+    lore_type tmp_lore(r_idx, mode);
+    lore_type *lore_ptr = &tmp_lore;
 
     auto is_valid_reinforcer = [](const auto &reinforce) {
         auto [r_idx, dd, ds] = reinforce;
index a7c03d1..cbd1898 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "lore/lore-util.h"
 #include "system/angband.h"
index c7ca3fa..5ffbdce 100644 (file)
@@ -1,4 +1,4 @@
-/* File: maid-x11.c */
+/* File: maid-x11.c */
 
 /*
  * Copyright (c) 1997 Ben Harrison, and others
@@ -10,7 +10,7 @@
 
 #ifdef USE_X11
 
-#include "main/x11-gamma-builder.h"
+#include "main-unix/x11-gamma-builder.h"
 #include <math.h>
 
 /*
index e41bfcb..aae411a 100644 (file)
@@ -1,4 +1,4 @@
-/* File: main-cap.c */
+/* File: main-cap.c */
 
 /* Purpose: Support for "term.c" using "termcap" calls */
 
index 9023abd..79346c4 100644 (file)
 #include "system/grafmode.h"
 
 #ifdef MACH_O_COCOA
+
+/* Default creator signature */
+#ifndef ANGBAND_CREATOR
+# define ANGBAND_CREATOR 'H300'
+#endif
+
 /* Mac headers */
 #import "cocoa/AppDelegate.h"
 #import "cocoa/SoundAndMusic.h"
@@ -47,6 +53,7 @@
 #include "system/player-type-definition.h"
 #include "system/system-variables.h"
 #include "main/angband-initializer.h"
+#include "main-unix/unix-user-ids.h"
 #include "io/files-util.h"
 #include "io/input-key-acceptor.h"
 #include "world/world.h"
@@ -1750,21 +1757,19 @@ static void draw_image_tile(
 
 /**
  * Generate a mask for the subwindow flags. The mask is just a safety check to
- * make sure that our windows show and hide as expected.  This function allows
- * for future changes to the set of flags without needed to update it here
- * (unless the underlying types change).
+ * make sure that our windows show and hide as expected.
  */
-static uint32_t AngbandMaskForValidSubwindowFlags(void)
+static EnumClassFlagGroup<SubWindowRedrawingFlag> AngbandMaskForValidSubwindowFlags(void)
 {
-    int windowFlagBits = sizeof(*(window_flag)) * CHAR_BIT;
-    int maxBits = MIN( 32, windowFlagBits );
-    uint32_t mask = 0;
+    EnumClassFlagGroup<SubWindowRedrawingFlag> mask;
+    int maxBits = (int)(sizeof(window_flag_desc)
+        / sizeof(window_flag_desc[0]));
 
     for( int i = 0; i < maxBits; i++ )
     {
         if( window_flag_desc[i] != NULL )
         {
-            mask |= (1U << i);
+            mask.set(i2enum<SubWindowRedrawingFlag>(i));
         }
     }
 
@@ -1782,10 +1787,10 @@ static void AngbandUpdateWindowVisibility(void)
      * Because this function is called frequently, we'll make the mask static.
      * It doesn't change between calls, as the flags themselves are hardcoded
      */
-    static uint32_t validWindowFlagsMask = 0;
+    static EnumClassFlagGroup<SubWindowRedrawingFlag> validWindowFlagsMask;
     BOOL anyChanged = NO;
 
-    if( validWindowFlagsMask == 0 )
+    if( validWindowFlagsMask.none() )
     {
         validWindowFlagsMask = AngbandMaskForValidSubwindowFlags();
     }
@@ -1830,7 +1835,8 @@ static void AngbandUpdateWindowVisibility(void)
         }
         else
         {
-            BOOL termHasSubwindowFlags = ((window_flag[i] & validWindowFlagsMask) > 0);
+            BOOL termHasSubwindowFlags =
+                g_window_flags[i].has_any_of(validWindowFlagsMask);
 
             if( angbandContext.hasSubwindowFlags && !termHasSubwindowFlags )
             {
@@ -3937,7 +3943,7 @@ static void set_color_for_index(int idx)
  */
 static void record_current_savefile(void)
 {
-    NSString *savefileString = [[NSString stringWithCString:savefile encoding:NSMacOSRomanStringEncoding] lastPathComponent];
+    NSString *savefileString = [[NSString stringWithCString:savefile.native().data() encoding:NSMacOSRomanStringEncoding] lastPathComponent];
     if (savefileString)
     {
         NSUserDefaults *angbandDefs = [NSUserDefaults angbandDefaults];
@@ -5531,6 +5537,34 @@ static void init_windows(void)
 }
 
 /**
+ * Set HFS file type and creator codes on a path
+ */
+static void cocoa_file_open_hook(const std::filesystem::path &path, const FileOpenType ftype)
+{
+    @autoreleasepool {
+       NSString *pathString = [NSString stringWithUTF8String:path.native().data()];
+       if (pathString)
+        {
+           uint32_t mac_type = 'TEXT';
+            if (ftype == FileOpenType::RAW)
+                mac_type = 'DATA';
+            else if (ftype == FileOpenType::SAVE)
+                mac_type = 'HENG';
+
+           NSDictionary *attrs =
+               [NSDictionary dictionaryWithObjectsAndKeys:
+                             [NSNumber numberWithUnsignedLong:mac_type],
+                             NSFileHFSTypeCode,
+                             [NSNumber numberWithUnsignedLong:ANGBAND_CREATOR],
+                             NSFileHFSCreatorCode,
+                             nil];
+           [[NSFileManager defaultManager]
+               setAttributes:attrs ofItemAtPath:pathString error:NULL];
+       }
+    }
+}
+
+/**
  * ------------------------------------------------------------------------
  * Main program
  * ------------------------------------------------------------------------ */
@@ -5641,6 +5675,8 @@ static void init_windows(void)
            if ([fileURLs count] > 0 && [[fileURLs objectAtIndex:0] isFileURL])
            {
                NSURL* savefileURL = (NSURL *)[fileURLs objectAtIndex:0];
+               char t[1024];
+
                /*
                 * The path property doesn't do the right thing except for
                 * URLs with the file scheme. We had
@@ -5648,9 +5684,11 @@ static void init_windows(void)
                 * introduced until OS X 10.9.
                 */
                selectedSomething = [[savefileURL path]
-                                       getCString:savefile
-                                       maxLength:sizeof savefile
+                                       getCString:t
+                                       maxLength:sizeof(t)
                                        encoding:NSMacOSRomanStringEncoding];
+               savefile = std::filesystem::path(t,
+                       std::filesystem::path::native_format);
            }
        }
 
@@ -5691,6 +5729,9 @@ static void init_windows(void)
        plog_aux = hook_plog;
        quit_aux = hook_quit;
 
+       /* Hook in to the file open routine */
+       file_open_hook = cocoa_file_open_hook;
+
        /* Initialize file paths */
        prepare_paths_and_directories();
 
@@ -5707,8 +5748,10 @@ static void init_windows(void)
        /* init_display(); */
 
        /* Initialize some save file stuff */
-       p_ptr->player_euid = geteuid();
-       p_ptr->player_egid = getegid();
+       auto &ids = UnixUserIds::get_instance();
+       ids.set_user_id(getuid());
+       ids.set_effective_user_id(geteuid());
+       ids.set_effective_group_id(getegid());
 
        /*
         * Cause splash screen to be centered if the main window is bigger
@@ -5795,13 +5838,14 @@ static void init_windows(void)
         {
            /*
             * Another window is only usable after Term_init_cocoa() has
-            * been called for it.  For Angband, if window_flag[i] is nonzero
-            * then that has happened for window i.  For Hengband, that is
-            * not the case so also test angband_terms[i]->data.
+            * been called for it.  For Angband, if g_window_flags[i] has
+            * any bits set then that has happened for window i.  For
+            * Hengband, that is not the case so also test
+            * angband_terms[i]->data.
             */
             NSInteger subwindowNumber = tag - AngbandWindowMenuItemTagBase;
             return (angband_terms[subwindowNumber]->data != 0
-                   && window_flag[subwindowNumber] > 0);
+                   && !g_window_flags[subwindowNumber].none());
         }
 
         return NO;
@@ -6279,11 +6323,13 @@ static void init_windows(void)
     }
 
     /* Put it in savefile */
-    if (! [file getFileSystemRepresentation:savefile maxLength:sizeof savefile]) {
+    char t[1024];
+    if (! [file getFileSystemRepresentation:t maxLength:sizeof(t)]) {
        [[NSApplication sharedApplication]
            replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
        return;
     }
+    savefile = std::filesystem::path(t, std::filesystem::path::native_format);
 
     game_in_progress = YES;
 
index 163cd5d..1533959 100644 (file)
@@ -1,4 +1,4 @@
-/* File: main-gcu.c */
+/* File: main-gcu.c */
 
 /*
  * Copyright (c) 1997 Ben Harrison, and others
@@ -291,7 +291,7 @@ static term_data data[MAX_TERM_DATA];
 /* #define nonl() */
 /* #define nl() */
 
-static concptr ANGBAND_DIR_XTRA_SOUND;
+static std::filesystem::path ANGBAND_DIR_XTRA_SOUND;
 
 /*
  * todo 有効活用されていない疑惑
@@ -587,26 +587,17 @@ static bool check_file(concptr s)
  */
 static bool init_sound(void)
 {
-    /* Initialize once */
     if (can_use_sound) {
         return can_use_sound;
     }
 
-    int i;
-    char buf[1024];
-
-    /* Prepare the sounds */
-    for (i = 1; i < SOUND_MAX; i++) {
-        /* Extract name of sound file */
+    for (auto i = 1; i < SOUND_MAX; i++) {
         std::string wav = angband_sound_name[i];
         wav.append(".wav");
-
-        /* Access the sound */
-        path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_SOUND, wav);
-
-        /* Save the sound filename, if it exists */
-        if (check_file(buf)) {
-            sound_file[i] = string_make(buf);
+        const auto &path = path_build(ANGBAND_DIR_XTRA_SOUND, wav);
+        const auto &filename = path.string();
+        if (check_file(filename.data())) {
+            sound_file[i] = string_make(filename.data());
         }
     }
 
@@ -1244,10 +1235,7 @@ static void hook_quit(concptr str)
  */
 errr init_gcu(int argc, char *argv[])
 {
-    int i;
-
     int num_term = 4, next_win = 0;
-    char path[1024];
 
     /* Unused */
     (void)argc;
@@ -1255,36 +1243,22 @@ errr init_gcu(int argc, char *argv[])
 
     setlocale(LC_ALL, "");
 
-    /* Build the "sound" path */
-    path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound");
-
-    /* Allocate the path */
-    ANGBAND_DIR_XTRA_SOUND = string_make(path);
-
-    /* Extract the normal keymap */
+    ANGBAND_DIR_XTRA_SOUND = path_build(ANGBAND_DIR_XTRA, "sound");
     keymap_norm_prepare();
-
-    bool nobigscreen = false;
-
-    /* Parse args */
-    for (i = 1; i < argc; i++) {
+    auto nobigscreen = false;
+    for (auto i = 1; i < argc; i++) {
         if (prefix(argv[i], "-o")) {
             nobigscreen = true;
         }
     }
 
-    /* Initialize for others systems */
     if (initscr() == (WINDOW *)ERR) {
         return -1;
     }
 
-    /* Activate hooks */
     quit_aux = hook_quit;
     core_aux = hook_quit;
-
-    /* Hack -- Require large screen, or Quit with message */
-    i = ((LINES < MAIN_TERM_MIN_ROWS) || (COLS < MAIN_TERM_MIN_COLS));
-    if (i) {
+    if ((LINES < MAIN_TERM_MIN_ROWS) || (COLS < MAIN_TERM_MIN_COLS)) {
         quit_fmt("%s needs an %dx%d 'curses' screen", std::string(VARIANT_NAME).data(), MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
     }
 
@@ -1303,7 +1277,7 @@ errr init_gcu(int argc, char *argv[])
     /* Attempt to use customized colors */
     if (can_fix_color) {
         /* Prepare the color pairs */
-        for (i = 1; i <= 15; i++) {
+        for (auto i = 1; i <= 15; i++) {
             if (init_pair(i, i, 0) == ERR) {
                 quit("Color pair init failed");
             }
@@ -1391,7 +1365,7 @@ errr init_gcu(int argc, char *argv[])
     /*** Now prepare the term(s) ***/
     if (nobigscreen) {
         /* Create several terms */
-        for (i = 0; i < num_term; i++) {
+        for (auto i = 0; i < num_term; i++) {
             int rows, cols, y, x;
 
             /* Decide on size and position */
@@ -1481,7 +1455,7 @@ errr init_gcu(int argc, char *argv[])
         int next_term = 1;
         int term_ct = 1;
 
-        for (i = 1; i < argc; i++) {
+        for (auto i = 1; i < argc; i++) {
             if (streq(argv[i], "-spacer")) {
                 i++;
                 if (i >= argc) {
diff --git a/src/main-unix/unix-user-ids.cpp b/src/main-unix/unix-user-ids.cpp
new file mode 100644 (file)
index 0000000..76cf7a7
--- /dev/null
@@ -0,0 +1,49 @@
+/*!
+ * @brief UNIX用ユーザID定義
+ * @author Hourier
+ * @date 2023/05/27
+ */
+
+#include "main-unix/unix-user-ids.h"
+
+UnixUserIds UnixUserIds::instance{};
+
+UnixUserIds &UnixUserIds::get_instance()
+{
+    return instance;
+}
+
+int UnixUserIds::get_user_id() const
+{
+    return this->user_id;
+}
+
+void UnixUserIds::set_user_id(const int id)
+{
+    this->user_id = id;
+}
+
+void UnixUserIds::mod_user_id(const int increment)
+{
+    this->user_id += increment;
+}
+
+int UnixUserIds::get_effective_user_id() const
+{
+    return this->effective_user_id;
+}
+
+void UnixUserIds::set_effective_user_id(const int id)
+{
+    this->effective_user_id = id;
+}
+
+int UnixUserIds::get_effective_group_id() const
+{
+    return this->effective_group_id;
+}
+
+void UnixUserIds::set_effective_group_id(const int id)
+{
+    this->effective_group_id = id;
+}
diff --git a/src/main-unix/unix-user-ids.h b/src/main-unix/unix-user-ids.h
new file mode 100644 (file)
index 0000000..8b41af1
--- /dev/null
@@ -0,0 +1,27 @@
+#pragma once
+
+class UnixUserIds {
+public:
+    UnixUserIds(const UnixUserIds &) = delete;
+    UnixUserIds(UnixUserIds &&) = delete;
+    UnixUserIds &operator=(const UnixUserIds &) = delete;
+    UnixUserIds &operator=(UnixUserIds &&) = delete;
+    ~UnixUserIds() = default;
+
+    static UnixUserIds &get_instance();
+    int get_user_id() const;
+    void set_user_id(const int id);
+    void mod_user_id(const int increment);
+    int get_effective_user_id() const;
+    void set_effective_user_id(const int id);
+    int get_effective_group_id() const;
+    void set_effective_group_id(const int id);
+
+private:
+    UnixUserIds() = default;
+
+    static UnixUserIds instance;
+    int user_id = 0;
+    int effective_user_id = 0;
+    int effective_group_id = 0;
+};
similarity index 99%
rename from src/main/x11-gamma-builder.cpp
rename to src/main-unix/x11-gamma-builder.cpp
index 8340f28..a1bdda0 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file x11-gamma-builder.cpp
  * @brief X11環境 (の中でもmaid-x11を必要とする特殊な環境)でガンマ値を調整する
  * @date 2020/05/16
@@ -48,7 +48,7 @@
  * are left with "meaningful" values.
  */
 
-#include "main/x11-gamma-builder.h"
+#include "main-unix/x11-gamma-builder.h"
 #include "system/angband.h"
 
 /* Table of gamma values */
similarity index 92%
rename from src/main/x11-gamma-builder.h
rename to src/main-unix/x11-gamma-builder.h
index 4e5686a..6ec45f9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file x11-gamma-builder.h
  * @brief X11環境ガンマ値の調整処理ヘッダ
similarity index 95%
rename from src/main/x11-type-string.cpp
rename to src/main-unix/x11-type-string.cpp
index ab3a4e4..9723e38 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file x11-type-string.cpp
  * @brief X11用の文字列処理
  * @date 2020/06/14
@@ -6,7 +6,7 @@
  * @details Windowsでは使わない
  */
 
-#include "main/x11-type-string.h"
+#include "main-unix/x11-type-string.h"
 #include "term/gameterm.h"
 
 /*
similarity index 90%
rename from src/main/x11-type-string.h
rename to src/main-unix/x11-type-string.h
index c26350c..987be77 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file x11-type-string.h
  * @brief X11用の文字列処理ヘッダ
index 2e7f523..9ad355f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win.cpp
  * @brief Windows版固有実装(メインエントリポイント含む)
  * @date 2018/03/16
 #include "main-win/commandline-win.h"
 #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 "save/save.h"
 #include "system/angband.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/system-variables.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include <direct.h>
 #include <locale>
 #include <string>
+#include <string_view>
 #include <vector>
 
 /*
@@ -190,7 +193,7 @@ static HICON hIcon;
 /* bg */
 bg_mode current_bg_mode = bg_mode::BG_NONE;
 #define DEFAULT_BG_FILENAME "bg.bmp"
-char wallpaper_file[MAIN_WIN_MAX_PATH] = ""; //!< 壁紙ファイル名。
+std::filesystem::path wallpaper_path = ""; //!< 壁紙ファイル名。
 
 /*
  * Show sub-windows even when Hengband is not in focus
@@ -356,7 +359,7 @@ static void save_prefs_aux(int i)
     wsprintfA(buf, "%d", td->tile_hgt);
     WritePrivateProfileStringA(sec_name, "TileHgt", buf, ini_file);
 
-    WINDOWPLACEMENT lpwndpl;
+    WINDOWPLACEMENT lpwndpl{};
     lpwndpl.length = sizeof(WINDOWPLACEMENT);
     GetWindowPlacement(td->w, &lpwndpl);
 
@@ -418,17 +421,19 @@ static void save_prefs(void)
 
     wsprintfA(buf, "%d", current_bg_mode);
     WritePrivateProfileStringA("Angband", "BackGround", buf, ini_file);
-    WritePrivateProfileStringA("Angband", "BackGroundBitmap", wallpaper_file[0] != '\0' ? wallpaper_file : DEFAULT_BG_FILENAME, ini_file);
+    const auto &wallpaper_filename = wallpaper_path.string();
+    WritePrivateProfileStringA("Angband", "BackGroundBitmap", !wallpaper_path.empty() ? wallpaper_filename.data() : DEFAULT_BG_FILENAME, ini_file);
 
-    std::string angband_dir_str(ANGBAND_DIR.string());
+    auto angband_dir_str = ANGBAND_DIR.string();
     const auto path_length = angband_dir_str.length() - 4; // "\lib" を除く.
     angband_dir_str = angband_dir_str.substr(0, path_length);
-    const std::string savefile_str(savefile);
-    if (angband_dir_str == savefile_str) {
-        const auto relative_path = format(".\\%s", (savefile + path_length));
+    const auto savefile_str = savefile.string();
+    const auto savefile_dir_str = savefile_str.substr(0, path_length);
+    if (angband_dir_str == savefile_dir_str) {
+        const auto relative_path = format(".\\%s", (savefile_str.data() + path_length));
         WritePrivateProfileStringA("Angband", "SaveFile", relative_path.data(), ini_file);
     } else {
-        WritePrivateProfileStringA("Angband", "SaveFile", savefile, ini_file);
+        WritePrivateProfileStringA("Angband", "SaveFile", savefile_str.data(), ini_file);
     }
 
     strcpy(buf, keep_subwindows ? "1" : "0");
@@ -515,18 +520,21 @@ static void load_prefs(void)
     arg_music_volume_table_index = std::clamp<int>(GetPrivateProfileIntA("Angband", "MusicVolumeTableIndex", 0, ini_file), 0, main_win_music::VOLUME_TABLE.size() - 1);
     use_pause_music_inactive = (GetPrivateProfileIntA("Angband", "MusicPauseInactive", 0, ini_file) != 0);
     current_bg_mode = static_cast<bg_mode>(GetPrivateProfileIntA("Angband", "BackGround", 0, ini_file));
-    GetPrivateProfileStringA("Angband", "BackGroundBitmap", DEFAULT_BG_FILENAME, wallpaper_file, 1023, ini_file);
-    GetPrivateProfileStringA("Angband", "SaveFile", "", savefile, 1023, ini_file);
-
-    int n = strncmp(".\\", savefile, 2);
-    if (n == 0) {
+    char wallpaper_buf[1024]{};
+    GetPrivateProfileStringA("Angband", "BackGroundBitmap", DEFAULT_BG_FILENAME, wallpaper_buf, 1023, ini_file);
+    wallpaper_path = wallpaper_buf;
+    char savefile_buf[1024]{};
+    GetPrivateProfileStringA("Angband", "SaveFile", "", savefile_buf, 1023, ini_file);
+    if (strncmp(".\\", savefile_buf, 2) == 0) {
         std::string angband_dir_str(ANGBAND_DIR.string());
         const auto path_length = angband_dir_str.length() - 4; // "\lib" を除く.
         angband_dir_str = angband_dir_str.substr(0, path_length);
         char tmp[1024] = "";
         strncat(tmp, angband_dir_str.data(), path_length);
-        strncat(tmp, savefile + 2, strlen(savefile) - 2 + path_length);
-        strncpy(savefile, tmp, strlen(tmp));
+        strncat(tmp, savefile_buf + 2, std::string_view(savefile_buf).length() - 2 + path_length);
+        savefile = tmp;
+    } else {
+        savefile = savefile_buf;
     }
 
     keep_subwindows = (GetPrivateProfileIntA("Angband", "KeepSubwindows", 0, ini_file) != 0);
@@ -603,10 +611,11 @@ static bool change_bg_mode(bg_mode new_mode, bool show_error = false, bool force
     current_bg_mode = new_mode;
     if (current_bg_mode != bg_mode::BG_NONE) {
         init_background();
-        if (!load_bg(wallpaper_file)) {
+        if (!load_bg(wallpaper_path)) {
             current_bg_mode = bg_mode::BG_NONE;
             if (show_error) {
-                plog_fmt(_("壁紙用ファイル '%s' を読み込めません。", "Can't load the image file '%s'."), wallpaper_file);
+                const auto &wallaper_filename = wallpaper_path.string();
+                plog_fmt(_("壁紙用ファイル '%s' を読み込めません。", "Can't load the image file '%s'."), wallaper_filename.data());
             }
         }
     } else {
@@ -692,8 +701,7 @@ static errr term_force_font(term_data *td)
  */
 static void term_change_font(term_data *td)
 {
-    CHOOSEFONTW cf;
-    memset(&cf, 0, sizeof(cf));
+    CHOOSEFONTW cf{};
     cf.lStructSize = sizeof(cf);
     cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_NOVERTFONTS | CF_INITTOLOGFONTSTRUCT;
     cf.lpLogFont = &(td->lf);
@@ -1015,7 +1023,7 @@ static errr term_curs_win(int x, int y)
     tile_wid = td->tile_wid;
     tile_hgt = td->tile_hgt;
 
-    RECT rc;
+    RECT rc{};
     rc.left = x * tile_wid + td->size_ow1;
     rc.right = rc.left + tile_wid;
     rc.top = y * tile_hgt + td->size_oh1;
@@ -1039,7 +1047,7 @@ static errr term_bigcurs_win(int x, int y)
     tile_wid = td->tile_wid;
     tile_hgt = td->tile_hgt;
 
-    RECT rc;
+    RECT rc{};
     rc.left = x * tile_wid + td->size_ow1;
     rc.right = rc.left + 2 * tile_wid;
     rc.top = y * tile_hgt + td->size_oh1;
@@ -1059,7 +1067,7 @@ static errr term_bigcurs_win(int x, int y)
 static errr term_wipe_win(int x, int y, int n)
 {
     term_data *td = (term_data *)(game_term->data);
-    RECT rc;
+    RECT rc{};
     rc.left = x * td->tile_wid + td->size_ow1;
     rc.right = rc.left + n * td->tile_wid;
     rc.top = y * td->tile_hgt + td->size_oh1;
@@ -1393,8 +1401,9 @@ static void init_windows(void)
             td->dwExStyle, AngList, td->name, td->dwStyle, td->pos_x, td->pos_y, td->size_wid, td->size_hgt, HWND_DESKTOP, NULL, hInstance, NULL);
         my_td = NULL;
 
-        if (!td->w) {
+        if (td->w == NULL) {
             quit(_("サブウィンドウに作成に失敗しました", "Failed to create sub-window"));
+            return; // 静的解析対応.
         }
 
         td->size_hack = true;
@@ -1425,11 +1434,13 @@ static void init_windows(void)
     td = &data[0];
     my_td = td;
     td->w = CreateWindowExW(
-        td->dwExStyle, AppName, _(L"変愚蛮怒", td->name), td->dwStyle, td->pos_x, td->pos_y, td->size_wid, td->size_hgt, HWND_DESKTOP, NULL, hInstance, NULL);
+        td->dwExStyle, AppName, _(L"変愚蛮怒", td->name), td->dwStyle,
+        td->pos_x, td->pos_y, td->size_wid, td->size_hgt, HWND_DESKTOP, NULL, hInstance, NULL);
     my_td = NULL;
 
-    if (!td->w) {
+    if (td->w == NULL) {
         quit(_("メインウィンドウの作成に失敗しました", "Failed to create main window"));
+        return; // 静的解析対応.
     }
 
     /* Resize */
@@ -1556,7 +1567,7 @@ static void check_for_save_file(const std::string &savefile_option)
         return;
     }
 
-    strcpy(savefile, savefile_option.data());
+    savefile = savefile_option;
     validate_file(savefile);
     game_in_progress = true;
 }
@@ -1572,14 +1583,14 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
     }
 
     term_data *td;
-    OPENFILENAMEW ofn;
+    OPENFILENAMEW ofn{};
     switch (wCmd) {
     case IDM_FILE_NEW: {
         if (game_in_progress || movie_in_progress) {
             plog(_("プレイ中は新しいゲームを始めることができません!", "You can't start a new game while you're still playing!"));
         } else {
             game_in_progress = true;
-            savefile[0] = '\0';
+            savefile = "";
         }
 
         break;
@@ -1588,14 +1599,14 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
         if (game_in_progress || movie_in_progress) {
             plog(_("プレイ中はゲームをロードすることができません!", "You can't open a new game while you're still playing!"));
         } else {
-            memset(&ofn, 0, sizeof(ofn));
             ofn.lStructSize = sizeof(ofn);
             ofn.hwndOwner = data[0].w;
             ofn.lpstrFilter = L"Save Files (*.)\0*\0";
             ofn.nFilterIndex = 1;
             ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
-
-            if (get_open_filename(&ofn, ANGBAND_DIR_SAVE, savefile, MAIN_WIN_MAX_PATH)) {
+            const auto &filename = get_open_filename(&ofn, ANGBAND_DIR_SAVE, savefile, MAIN_WIN_MAX_PATH);
+            if (filename) {
+                savefile = *filename;
                 validate_file(savefile);
                 game_in_progress = true;
             }
@@ -1638,9 +1649,8 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
         break;
     }
     case IDM_FILE_SCORE: {
-        char buf[1024];
-        path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
-        highscore_fd = fd_open(buf, O_RDONLY);
+        const auto &path = path_build(ANGBAND_DIR_APEX, "scores.raw");
+        highscore_fd = fd_open(path, O_RDONLY);
         if (highscore_fd < 0) {
             msg_print("Score file unavailable.");
         } else {
@@ -1659,14 +1669,14 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
         if (game_in_progress || movie_in_progress) {
             plog(_("プレイ中はムービーをロードすることができません!", "You can't open a movie while you're playing!"));
         } else {
-            memset(&ofn, 0, sizeof(ofn));
             ofn.lStructSize = sizeof(ofn);
             ofn.hwndOwner = data[0].w;
             ofn.lpstrFilter = L"Angband Movie Files (*.amv)\0*.amv\0";
             ofn.nFilterIndex = 1;
             ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
-
-            if (get_open_filename(&ofn, ANGBAND_DIR_USER, savefile, MAIN_WIN_MAX_PATH)) {
+            const auto &filename = get_open_filename(&ofn, ANGBAND_DIR_USER, savefile, MAIN_WIN_MAX_PATH);
+            if (filename) {
+                savefile = *filename;
                 prepare_browse_movie_without_path_build(savefile);
                 movie_in_progress = true;
             }
@@ -1902,9 +1912,8 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
         break;
     }
     case IDM_OPTIONS_OPEN_MUSIC_DIR: {
-        std::vector<char> buf(MAIN_WIN_MAX_PATH);
-        path_build(&buf[0], MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
-        open_dir_in_explorer(&buf[0]);
+        const auto &path = path_build(ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
+        open_dir_in_explorer(path.string());
         break;
     }
     case IDM_OPTIONS_SOUND: {
@@ -1926,9 +1935,8 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
         break;
     }
     case IDM_OPTIONS_OPEN_SOUND_DIR: {
-        std::vector<char> buf(MAIN_WIN_MAX_PATH);
-        path_build(&buf[0], MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
-        open_dir_in_explorer(&buf[0]);
+        const auto &path = path_build(ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
+        open_dir_in_explorer(path.string());
         break;
     }
     case IDM_OPTIONS_NO_BG: {
@@ -1947,15 +1955,15 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd)
     }
         [[fallthrough]];
     case IDM_OPTIONS_OPEN_BG: {
-        memset(&ofn, 0, sizeof(ofn));
         ofn.lStructSize = sizeof(ofn);
         ofn.hwndOwner = data[0].w;
         ofn.lpstrFilter = L"Image Files (*.bmp;*.png;*.jpg;*.jpeg;)\0*.bmp;*.png;*.jpg;*.jpeg;\0";
         ofn.nFilterIndex = 1;
         ofn.lpstrTitle = _(L"壁紙を選んでね。", L"Choose wall paper.");
         ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
-
-        if (get_open_filename(&ofn, "", wallpaper_file, MAIN_WIN_MAX_PATH)) {
+        const auto &filename = get_open_filename(&ofn, "", wallpaper_path, MAIN_WIN_MAX_PATH);
+        if (filename) {
+            wallpaper_path = *filename;
             change_bg_mode(bg_mode::BG_ONE, true, true);
         }
         break;
@@ -2140,7 +2148,7 @@ static void fit_term_size_to_window(term_data *td, bool recalc_window_size = fal
         rebuild_term(td, recalc_window_size);
 
         if (!is_main_term(td)) {
-            p_ptr->window_flags = PW_ALL;
+            RedrawingFlagsUpdater::get_instance().fill_up_sub_flags();
             handle_stuff(p_ptr);
         }
     }
@@ -2304,8 +2312,6 @@ LRESULT PASCAL angband_window_procedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
         if (!mouse_down) {
             return 0;
         }
-        HGLOBAL hGlobal;
-        LPSTR lpStr;
         TERM_LEN dx = abs(oldx - mousex) + 1;
         TERM_LEN dy = abs(oldy - mousey) + 1;
         TERM_LEN ox = (oldx > mousex) ? mousex : oldx;
@@ -2319,13 +2325,13 @@ LRESULT PASCAL angband_window_procedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
 #else
         int sz = (dx + 2) * dy;
 #endif
-        hGlobal = GlobalAlloc(GHND, sz + 1);
-        if (hGlobal == NULL) {
+        const auto window_size = GlobalAlloc(GHND, sz + 1);
+        if (window_size == NULL) {
             return 0;
         }
-        lpStr = (LPSTR)GlobalLock(hGlobal);
 
-        for (int i = 0; i < dy; i++) {
+        auto global_lock = static_cast<LPSTR>(GlobalLock(window_size));
+        for (auto i = 0; (i < dy) && (global_lock != NULL); i++) {
 #ifdef JP
             const auto &scr = data[0].t.scr->c;
 
@@ -2348,27 +2354,32 @@ LRESULT PASCAL angband_window_procedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
                 if (s[j] == 127) {
                     s[j] = '#';
                 }
-                *lpStr++ = s[j];
+                *global_lock++ = s[j];
             }
 #else
             for (int j = 0; j < dx; j++) {
-                *lpStr++ = data[0].t.scr->c[oy + i][ox + j];
+                *global_lock++ = data[0].t.scr->c[oy + i][ox + j];
             }
 #endif
             if (dy > 1) {
-                *lpStr++ = '\r';
-                *lpStr++ = '\n';
+                *global_lock++ = '\r';
+                *global_lock++ = '\n';
             }
         }
 
-        GlobalUnlock(hGlobal);
-        if (OpenClipboard(hWnd) == 0) {
-            GlobalFree(hGlobal);
+        GlobalUnlock(window_size);
+        if (!OpenClipboard(hWnd)) {
+            GlobalFree(window_size);
             return 0;
         }
 
         EmptyClipboard();
-        SetClipboardData(CF_TEXT, hGlobal);
+        if (SetClipboardData(CF_TEXT, window_size) == NULL) {
+            CloseClipboard();
+            GlobalFree(window_size);
+            return 0;
+        }
+
         CloseClipboard();
         term_redraw();
         return 0;
@@ -2435,7 +2446,7 @@ LRESULT PASCAL angband_window_procedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPA
         if (p_ptr->chp < 0) {
             p_ptr->is_dead = false;
         }
-        exe_write_diary(p_ptr, DIARY_GAMESTART, 0, _("----ゲーム中断----", "---- Save and Exit Game ----"));
+        exe_write_diary(p_ptr, DiaryKind::GAMESTART, 0, _("----ゲーム中断----", "---- Save and Exit Game ----"));
 
         p_ptr->panic_save = 1;
         signals_ignore_tstp();
@@ -2648,19 +2659,16 @@ static void init_stuff()
     validate_dir(ANGBAND_DIR_DEBUG_SAVE, false);
     validate_dir(ANGBAND_DIR_USER, true);
     validate_dir(ANGBAND_DIR_XTRA, true);
-    path_build(path, sizeof(path), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
+    const auto &path_news = path_build(ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
+    validate_file(path_news);
 
-    validate_file(path);
-    path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "graf");
-    ANGBAND_DIR_XTRA_GRAF = string_make(path);
+    ANGBAND_DIR_XTRA_GRAF = path_build(ANGBAND_DIR_XTRA, "graf");
     validate_dir(ANGBAND_DIR_XTRA_GRAF, true);
 
-    path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound");
-    ANGBAND_DIR_XTRA_SOUND = string_make(path);
+    ANGBAND_DIR_XTRA_SOUND = path_build(ANGBAND_DIR_XTRA, "sound");
     validate_dir(ANGBAND_DIR_XTRA_SOUND, false);
 
-    path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "music");
-    ANGBAND_DIR_XTRA_MUSIC = string_make(path);
+    ANGBAND_DIR_XTRA_MUSIC = path_build(ANGBAND_DIR_XTRA, "music");
     validate_dir(ANGBAND_DIR_XTRA_MUSIC, false);
 
     for (i = 0; special_key_list[i]; ++i) {
@@ -2750,16 +2758,16 @@ static void register_wndclass(void)
 }
 
 /*!
- * @brief (Windows固有)Windowsアプリケーションとしてのエントリポイント
+ * @brief ゲームのメインルーチン
  */
-int WINAPI WinMain(
-    _In_ HINSTANCE hInst, [[maybe_unused]] _In_opt_ HINSTANCE hPrevInst, [[maybe_unused]] _In_ LPSTR lpCmdLine, [[maybe_unused]] _In_ int nCmdShow)
+int WINAPI game_main(_In_ HINSTANCE hInst)
 {
     setlocale(LC_ALL, "ja_JP");
     hInstance = hInst;
     if (is_already_running()) {
-        MessageBoxW(
-            NULL, _(L"変愚蛮怒はすでに起動しています。", L"Hengband is already running."), _(L"エラー!", L"Error"), MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
+        constexpr auto mes = _(L"変愚蛮怒はすでに起動しています。", L"Hengband is already running.");
+        constexpr auto caption = _(L"エラー!", L"Error");
+        MessageBoxW(NULL, mes, caption, MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
         return 0;
     }
 
@@ -2787,13 +2795,6 @@ int WINAPI WinMain(
     core_aux = quit_aux;
 
     init_stuff();
-
-    HDC hdc = GetDC(NULL);
-    if (GetDeviceCaps(hdc, BITSPIXEL) <= 8) {
-        quit(_("画面を16ビット以上のカラーモードにして下さい。", "Please switch to High Color (16-bit) or higher color mode."));
-    }
-    ReleaseDC(NULL, hdc);
-
     refresh_color_table();
     init_windows();
     change_graphics_mode(static_cast<graphics_mode>(arg_graphics));
@@ -2837,7 +2838,7 @@ int WINAPI WinMain(
     if (movie_in_progress) {
         // selected movie
         play_game(p_ptr, false, true);
-    } else if (savefile[0] == '\0') {
+    } else if (savefile.empty()) {
         // new game
         play_game(p_ptr, true, false);
     } else {
@@ -2848,4 +2849,19 @@ int WINAPI WinMain(
     quit(nullptr);
     return 0;
 }
+
+/*!
+ * @brief (Windows固有)Windowsアプリケーションとしてのエントリポイント
+ */
+int WINAPI WinMain(
+    _In_ HINSTANCE hInst, _In_opt_ HINSTANCE, _In_ LPSTR, _In_ int)
+{
+    try {
+        return game_main(hInst);
+    } catch (const std::exception &e) {
+        handle_unexpected_exception(e);
+        return 1;
+    }
+}
+
 #endif /* WINDOWS */
index 74a9e66..ac9de79 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file commandline-win.cpp
  * @brief Windows版固有実装(コマンドライン)
  */
index e81d555..d90e40a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file commandline-win.h
  * @brief Windows版固有実装(コマンドライン)ヘッダ
index 95a37b6..e2dac2f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file graphics-win.cpp
  * @brief Windows版固有実装(タイル、イメージファイルの読み込み)
  */
@@ -8,11 +8,7 @@
 #include "main-win/main-win-utils.h"
 #include "system/system-variables.h"
 #include "util/angband-files.h"
-
-#pragma warning(push)
-#pragma warning(disable : 4458)
 #include <gdiplus.h>
-#pragma warning(pop)
 
 // Flag set once "GDI+" has been initialized
 bool gdi_plus_started = false;
@@ -22,7 +18,7 @@ ULONG_PTR gdiplusToken;
 // interface object
 Graphics graphic{};
 
-concptr ANGBAND_DIR_XTRA_GRAF;
+std::filesystem::path ANGBAND_DIR_XTRA_GRAF;
 
 /*!
  * 現在使用中のタイルID(0ならば未使用)
@@ -57,7 +53,7 @@ static void finalize_gdi_plus()
     }
 }
 
-HBITMAP read_graphic(char *filename)
+HBITMAP read_graphic(const char *filename)
 {
     HBITMAP result = NULL;
     init_gdi_plus();
@@ -77,7 +73,6 @@ graphics_mode change_graphics(graphics_mode arg)
         return current_graphics_mode;
     }
 
-    char buf[MAIN_WIN_MAX_PATH];
     BYTE wid, hgt, twid, thgt, ox, oy;
     std::string name;
     std::string name_mask("");
@@ -121,8 +116,9 @@ graphics_mode change_graphics(graphics_mode arg)
         return current_graphics_mode;
     }
 
-    path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, name);
-    infGraph.hBitmap = read_graphic(buf);
+    const auto &path = path_build(ANGBAND_DIR_XTRA_GRAF, name);
+    const auto &filename = path.string();
+    infGraph.hBitmap = read_graphic(filename.data());
     if (!infGraph.hBitmap) {
         plog_fmt(_("ビットマップ '%s' を読み込めません。", "Cannot read bitmap file '%s'"), name.data());
         ANGBAND_GRAF = "ascii";
@@ -138,18 +134,22 @@ graphics_mode change_graphics(graphics_mode arg)
     infGraph.OffsetY = oy;
 
     if (name_mask.empty()) {
-        path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, name_mask);
-        infGraph.hBitmapMask = read_graphic(buf);
-        if (!infGraph.hBitmapMask) {
-            plog_fmt(_("ビットマップ '%s' を読み込めません。", "Cannot read bitmap file '%s'"), name_mask.data());
-            ANGBAND_GRAF = "ascii";
-            current_graphics_mode = graphics_mode::GRAPHICS_NONE;
-            return current_graphics_mode;
-        }
+        current_graphics_mode = arg;
+        return arg;
     }
 
-    current_graphics_mode = arg;
-    return arg;
+    const auto &path_mask = path_build(ANGBAND_DIR_XTRA_GRAF, name_mask);
+    const auto &filename_mask = path_mask.string();
+    infGraph.hBitmapMask = read_graphic(filename_mask.data());
+    if (infGraph.hBitmapMask) {
+        current_graphics_mode = arg;
+        return arg;
+    }
+
+    plog_fmt(_("ビットマップ '%s' を読み込めません。", "Cannot read bitmap file '%s'"), name_mask.data());
+    ANGBAND_GRAF = "ascii";
+    current_graphics_mode = graphics_mode::GRAPHICS_NONE;
+    return current_graphics_mode;
 }
 }
 
index 93a6edf..86638a9 100644 (file)
@@ -1,11 +1,11 @@
-#pragma once
+#pragma once
 /*!
  * @file graphics-win.h
  * @brief Windows版固有実装(タイル、イメージファイルの読み込み)ヘッダ
  */
 
 #include "system/h-type.h"
-
+#include <filesystem>
 #include <windows.h>
 
 /*
@@ -105,7 +105,7 @@ extern Graphics graphic;
 /*
  * Directory names
  */
-extern concptr ANGBAND_DIR_XTRA_GRAF;
+extern std::filesystem::path ANGBAND_DIR_XTRA_GRAF;
 
 /*!
  * @brief Creates a GDI bitmap from an image file
@@ -114,4 +114,4 @@ extern concptr ANGBAND_DIR_XTRA_GRAF;
  * @param filename an image file name
  * @return bitmap handle
  */
-HBITMAP read_graphic(char *filename);
+HBITMAP read_graphic(const char *filename);
index 9024d4c..e8def85 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-bg.cpp
  * @brief Windows版固有実装(壁紙)
  */
@@ -27,10 +27,11 @@ void delete_bg(void)
     }
 }
 
-bool load_bg(char *filename)
+bool load_bg(const std::filesystem::path &path)
 {
     delete_bg();
-    hBG = read_graphic(filename);
+    const auto &filename = path.string();
+    hBG = read_graphic(filename.data());
 
     return hBG != NULL;
 }
index 350d8f8..dfebbf3 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 
 #include "main-win/main-win-define.h"
-
+#include <filesystem>
 #include <windows.h>
 
 /*!
@@ -17,5 +17,5 @@ void load_bg_prefs(void);
 void finalize_bg();
 
 void delete_bg(void);
-bool load_bg(char *filename);
+bool load_bg(const std::filesystem::path &path);
 void draw_bg(HDC hdc, RECT *r);
index fd81123..a54ccd2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-cfg-reader.cpp
  * @brief Windows版固有実装(.cfgファイル処理)
  */
@@ -76,7 +76,7 @@ void CfgData::insert(int key1_type, int key2_val, cfg_values *value)
  * @param dir .cfgファイルのディレクトリ
  * @param files .cfgファイル名。複数指定可能で、最初に見つかったファイルから読み取る。
  */
-CfgReader::CfgReader(concptr dir, std::initializer_list<concptr> files)
+CfgReader::CfgReader(std::filesystem::path dir, std::initializer_list<concptr> files)
 {
     this->dir = dir;
     this->cfg_path = find_any_file(dir, files);
@@ -97,7 +97,6 @@ CfgData *CfgReader::read_sections(std::initializer_list<cfg_section> sections)
 
     char key_buf[80];
     char buf[MAIN_WIN_MAX_PATH];
-    char path[MAIN_WIN_MAX_PATH];
     char *tokens[SAMPLE_MAX];
 
     for (auto &section : sections) {
@@ -115,7 +114,7 @@ CfgData *CfgReader::read_sections(std::initializer_list<cfg_section> sections)
 #endif
                 const int num = tokenize_whitespace(buf, SAMPLE_MAX, tokens);
                 for (auto j = 0; j < num; j++) {
-                    path_build(path, MAIN_WIN_MAX_PATH, dir, tokens[j]);
+                    const auto &path = path_build(dir, tokens[j]);
                     if (check_file(path)) {
                         filenames->push_back(string_make(tokens[j]));
                     }
index 053263d..5113299 100644 (file)
@@ -1,7 +1,8 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <cstddef>
+#include <filesystem>
 #include <initializer_list>
 #include <unordered_map>
 #include <vector>
@@ -55,14 +56,14 @@ protected:
 
 class CfgReader {
 public:
-    CfgReader(concptr dir, std::initializer_list<concptr> files);
+    CfgReader(std::filesystem::path dir, std::initializer_list<concptr> files);
     CfgData *read_sections(std::initializer_list<cfg_section> sections);
-    concptr get_cfg_path()
+    std::string get_cfg_path()
     {
-        return cfg_path.data();
+        return cfg_path;
     }
 
 protected:
-    concptr dir;
+    std::filesystem::path dir;
     std::string cfg_path;
 };
index 5ef951a..6c8fee8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 // max. length of full pathname
 #define MAIN_WIN_MAX_PATH 1024
diff --git a/src/main-win/main-win-exception.cpp b/src/main-win/main-win-exception.cpp
new file mode 100644 (file)
index 0000000..c47f0a3
--- /dev/null
@@ -0,0 +1,43 @@
+#include "main-win/main-win-exception.h"
+#include "main-win/main-win-utils.h"
+#include "net/report-error.h"
+#include <sstream>
+
+/*!
+ * @brief 予期しない例外を処理する
+ *
+ * 予期しない例外が発生した場合、確認を取り例外のエラー情報を開発チームに送信する。
+ * その後、バグ報告ページを開くかどうか尋ね、開く場合はWebブラウザで開く。
+ *
+ * @param e 例外オブジェクト
+ */
+void handle_unexpected_exception(const std::exception &e)
+{
+    constexpr auto caption = _(L"予期しないエラー!", L"Unexpected error!");
+
+#if !defined(DISABLE_NET)
+    std::wstringstream report_confirm_msg_ss;
+    report_confirm_msg_ss
+        << to_wchar(e.what()).wc_str() << L"\n\n"
+        << _(L"開発チームにエラー情報を送信してよろしいですか?\n", L"Are you sure you want to send the error information to the development team?\n")
+        << _(L"※送信されるのはゲーム内の情報のみであり、個人情報が送信されることはありません。\n",
+               L"Only in-game information will be sent. No personal information will be sent.\n");
+
+    if (auto choice = MessageBoxW(NULL, report_confirm_msg_ss.str().data(), caption, MB_ICONEXCLAMATION | MB_YESNO | MB_ICONSTOP);
+        choice == IDYES) {
+        report_error(e.what());
+    }
+#endif
+
+    std::wstringstream issue_page_open_msg_ss;
+    issue_page_open_msg_ss
+        << _(L"エラー発生の詳しい状況を報告してくださると助かります。\n",
+               L"It would be helpful if you could report the detailed circumstances of the error.\n")
+        << _(L"バグ報告ページを開きますか?\n", L"Open bug report page?\n");
+
+    if (auto choice = MessageBoxW(NULL, issue_page_open_msg_ss.str().data(), caption, MB_ICONEXCLAMATION | MB_YESNO | MB_ICONSTOP);
+        choice == IDYES) {
+        constexpr auto url = "https://github.com/hengband/hengband/issues/new/choose";
+        ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
+    }
+};
diff --git a/src/main-win/main-win-exception.h b/src/main-win/main-win-exception.h
new file mode 100644 (file)
index 0000000..d328a3d
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <stdexcept>
+
+void handle_unexpected_exception(const std::exception &e);
index ae335a3..69b206a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-file-utils.cpp
  * @brief Windows版固有実装(ファイル関連処理)
  */
@@ -65,13 +65,12 @@ bool check_dir(const std::filesystem::path &s)
  */
 std::string find_any_file(const std::filesystem::path &dir, std::initializer_list<concptr> files)
 {
-    char path[MAIN_WIN_MAX_PATH];
-    for (concptr filename : files) {
-        path_build(path, MAIN_WIN_MAX_PATH, dir, filename);
+    for (const auto *filename : files) {
+        const auto &path = path_build(dir, filename);
         if (check_file(path)) {
-            return std::string(path);
+            return path.string();
         }
     }
 
-    return std::string();
+    return "";
 }
index 410a41d..ef286bd 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/h-type.h"
 #include <filesystem>
index 7855ff3..3793417 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-mci.cpp
  * @brief Windows版固有実装(BGM再生用のMCI)
  */
index 93b8d6d..28240e9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <windows.h>
 
index 79777a7..9a8d206 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Menu constants -- see "ang_jp.rc", "ang_eng.rc"
index 4d9e047..b8926e1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <windows.h>
 
index 9cb881f..8443bc6 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-music.cpp
  * @brief Windows版固有実装(BGM)
  */
@@ -28,12 +28,12 @@ bool use_pause_music_inactive = false;
 static int current_music_type = TERM_XTRA_MUSIC_MUTE;
 static int current_music_id = 0;
 // current filename being played
-static char current_music_path[MAIN_WIN_MAX_PATH];
+static std::filesystem::path current_music_path;
 
 /*
  * Directory name
  */
-concptr ANGBAND_DIR_XTRA_MUSIC;
+std::filesystem::path ANGBAND_DIR_XTRA_MUSIC;
 
 /*
  * "music.cfg" data
@@ -135,7 +135,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());
+    GetPrivateProfileStringA("Device", "type", "MPEGVideo", device_type, _countof(device_type), reader.get_cfg_path().data());
     mci_device_type = to_wchar(device_type).wc_str();
 
     // clang-format off
@@ -168,7 +168,7 @@ errr stop_music(void)
     mciSendCommandW(mci_open_parms.wDeviceID, MCI_CLOSE, MCI_WAIT, 0);
     current_music_type = TERM_XTRA_MUSIC_MUTE;
     current_music_id = 0;
-    strcpy(current_music_path, "\0");
+    current_music_path = "";
     return 0;
 }
 
@@ -190,20 +190,19 @@ errr play_music(int type, int val)
         return 1;
     } // no setting
 
-    char buf[MAIN_WIN_MAX_PATH];
-    path_build(buf, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, filename);
-
+    auto path_music = path_build(ANGBAND_DIR_XTRA_MUSIC, filename);
     if (current_music_type != TERM_XTRA_MUSIC_MUTE) {
-        if (0 == strcmp(current_music_path, buf)) {
+        if (current_music_path == path_music) {
             return 0;
         }
     } // now playing same file
 
     current_music_type = type;
     current_music_id = val;
-    strcpy(current_music_path, buf);
+    current_music_path = path_music;
 
-    to_wchar path(buf);
+    const auto &filename_music = path_music.string();
+    to_wchar path(filename_music.data());
     mci_open_parms.lpstrDeviceType = mci_device_type.data();
     mci_open_parms.lpstrElementName = path.wc_str();
     mciSendCommandW(mci_open_parms.wDeviceID, MCI_STOP, MCI_WAIT, 0);
index 3e09249..4a18680 100644 (file)
@@ -1,15 +1,14 @@
-#pragma once
+#pragma once
 
 #include "main-win/main-win-cfg-reader.h"
-#include "system/h-type.h"
-
 #include "main/music-definitions-table.h"
-
+#include "system/h-type.h"
 #include <array>
+#include <filesystem>
 #include <windows.h>
 
 extern bool use_pause_music_inactive;
-extern concptr ANGBAND_DIR_XTRA_MUSIC;
+extern std::filesystem::path ANGBAND_DIR_XTRA_MUSIC;
 extern CfgData *music_cfg_data;
 
 namespace main_win_music {
index 8bfa27a..e7309a2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-sound.cpp
  * @brief Windows版固有実装(効果音)
  */
 #include "main-win/main-win-file-utils.h"
 #include "main-win/main-win-utils.h"
 #include "main-win/wav-reader.h"
-#include "util/angband-files.h"
-
 #include "main/sound-definitions-table.h"
-
+#include "util/angband-files.h"
 #include <memory>
-#include <queue>
-
 #include <mmsystem.h>
+#include <queue>
 
 /*
  * Directory name
  */
-concptr ANGBAND_DIR_XTRA_SOUND;
+std::filesystem::path ANGBAND_DIR_XTRA_SOUND;
 
 /*
  * "sound.cfg" data
@@ -253,16 +250,16 @@ void finalize_sound(void)
  * @retval 1 設定なし
  * @retval -1 PlaySoundの戻り値が正常終了以外
  */
-errr play_sound(int val, int volume)
+int play_sound(int val, int volume)
 {
     auto filename = sound_cfg_data->get_rand(TERM_XTRA_SOUND, val);
     if (!filename) {
         return 1;
     }
 
-    char buf[MAIN_WIN_MAX_PATH];
-    path_build(buf, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_SOUND, filename);
-    if (play_sound_impl(buf, volume)) {
+    auto path = path_build(ANGBAND_DIR_XTRA_SOUND, filename);
+    auto filename_sound = path.string();
+    if (play_sound_impl(filename_sound.data(), volume)) {
         return 0;
     }
 
index 41e4fa4..040ea9d 100644 (file)
@@ -1,15 +1,15 @@
-#pragma once
+#pragma once
 
 #include "main-win/main-win-cfg-reader.h"
-#include "system/h-type.h"
 #include <array>
+#include <filesystem>
 
-extern concptr ANGBAND_DIR_XTRA_SOUND;
+extern std::filesystem::path ANGBAND_DIR_XTRA_SOUND;
 extern CfgData *sound_cfg_data;
 
 void load_sound_prefs(void);
 void finalize_sound(void);
-errr play_sound(int val, int volume);
+int play_sound(int val, int volume);
 
 /*! 音量 100%,90%,…,10% それぞれに割り当てる実際の値(効果音の音声データの振幅を volume/SOUND_VOLUME_MAX 倍する) */
 constexpr std::array<int, 10> SOUND_VOLUME_TABLE = { { 1000, 800, 600, 450, 350, 250, 170, 100, 50, 20 } };
index dd16ef9..afd1cbc 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-term.cpp
  * @brief Windows版固有実装(ターミナル)
  */
index 4c76198..e83f8ae 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file main-win-term.h
  * @brief Windows版固有実装(ターミナル)ヘッダ
index 8fc1eaf..dc20931 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-tokenizer.cpp
  * @brief Windows版固有実装(トークン分割)
  */
index 580e03b..2f4e9f2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/h-type.h"
 
index 4a79619..55402fe 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file main-win-utils.cpp
  * @brief Windows版固有実装(ユーティリティー)
  */
@@ -37,9 +37,7 @@ bool is_already_running(void)
 void save_screen_as_html(HWND hWnd)
 {
     std::vector<WCHAR> buf(MAIN_WIN_MAX_PATH + 1);
-    OPENFILENAMEW ofnw;
-
-    memset(&ofnw, 0, sizeof(ofnw));
+    OPENFILENAMEW ofnw{};
     ofnw.lStructSize = sizeof(ofnw);
     ofnw.hwndOwner = hWnd;
     ofnw.lpstrFilter = L"HTML Files (*.html)\0*.html\0";
@@ -52,7 +50,7 @@ void save_screen_as_html(HWND hWnd)
     ofnw.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
 
     if (GetSaveFileNameW(&ofnw)) {
-        do_cmd_save_screen_html_aux(to_multibyte(&buf[0]).c_str(), 0);
+        exe_cmd_save_screen_html(to_multibyte(&buf[0]).c_str(), false);
     }
 }
 
@@ -60,48 +58,39 @@ void save_screen_as_html(HWND hWnd)
  * @brief 対象ファイルを選択した状態でエクスプローラーを開く
  * @param filename 対象ファイル
  */
-void open_dir_in_explorer(char *filename)
+void open_dir_in_explorer(std::string_view filename)
 {
-    std::string str = "/select," + std::string(filename);
-    ShellExecuteW(NULL, NULL, L"explorer.exe", to_wchar(str.data()).wc_str(), NULL, SW_SHOWNORMAL);
+    std::stringstream ss;
+    ss << "/select," << filename;
+    ShellExecuteW(NULL, NULL, L"explorer.exe", to_wchar(ss.str().data()).wc_str(), NULL, SW_SHOWNORMAL);
 }
 
 /*!
  * @brief GetOpenFileNameW APIのラッパー
- * @details
- * ワイド文字列版のAPIを使用するが、選択ファイルのパスをマルチバイト文字列で受け取る。
  * @param ofn GetOpenFileNameWに指定するOPENFILENAMEW構造体へのポインタ。
  * lpstrFile、nMaxFileメンバの設定は無視される(関数内で上書きするため)。
- * @param dirname GetOpenFileNameWに指定する初期フォルダパス。
- * NULL以外を指定した場合、ワイド文字列に変換しlpstrInitialDirに設定される。
- * @param filename 選択ファイルパス設定先バッファへのポインタ
- * @param max_name_size filenameのバッファサイズ
- * @retval true filenameに選択されたファイルのパスが設定されている。
- * @retval false ファイル選択がキャンセルされた。
+ * @param path_dir GetOpenFileNameWに指定する初期フォルダパス。
+ * @param path_file 初期選択ファイルパス
+ * @param max_name_size 選択ファイルパスの最大長
+ * @return 選択されたファイルパス。選択をキャンセルした場合はstd::nullopt。
  */
-bool get_open_filename(OPENFILENAMEW *ofn, const std::filesystem::path &dirname, char *filename, DWORD max_name_size)
+std::optional<std::filesystem::path> get_open_filename(OPENFILENAMEW *ofn, const std::filesystem::path &path_dir, const std::filesystem::path &path_file, DWORD max_name_size)
 {
     std::vector<WCHAR> buf(max_name_size);
-    wcscpy(&buf[0], to_wchar(filename).wc_str());
-    const char *dir = nullptr;
-    const auto &dirname_str = dirname.string();
-    if (dirname_str != "") {
-        dir = dirname_str.data();
-    }
+    const auto path_file_str = path_file.wstring();
+    const auto path_dir_str = path_dir.wstring();
 
-    to_wchar wc_dir(dir);
+    if (path_file_str.length() < buf.size()) {
+        std::copy(path_file_str.begin(), path_file_str.end(), buf.begin());
+    }
 
-    // Overwrite struct data
-    ofn->lpstrFile = &buf[0];
-    ofn->nMaxFile = max_name_size - 1;
-    ofn->lpstrInitialDir = wc_dir.wc_str();
+    ofn->lpstrFile = buf.data();
+    ofn->nMaxFile = buf.size();
+    ofn->lpstrInitialDir = path_dir_str.empty() ? nullptr : path_dir_str.data();
 
-    // call API
     if (GetOpenFileNameW(ofn)) {
-        // to multibyte
-        strncpy_s(filename, max_name_size, to_multibyte(&buf[0]).c_str(), _TRUNCATE);
-        return true;
+        return std::make_optional<std::filesystem::path>(buf.data());
     }
 
-    return false;
+    return std::nullopt;
 }
index 43b14be..5911455 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file main-win-utils.h
  * @brief Windows版固有実装(ユーティリティー)ヘッダ
@@ -7,6 +7,8 @@
 #include "system/angband.h"
 #include <filesystem>
 #include <optional>
+#include <string>
+#include <string_view>
 #include <vector>
 #include <windows.h>
 
@@ -38,7 +40,7 @@ public:
 
     WCHAR *wc_str()
     {
-        return buf.has_value() ? (*buf).data() : NULL;
+        return buf ? (*buf).data() : NULL;
     }
 
 protected:
@@ -73,7 +75,7 @@ public:
 
     char *c_str()
     {
-        return buf.has_value() ? (*buf).data() : NULL;
+        return buf ? (*buf).data() : NULL;
     }
 
 protected:
@@ -82,5 +84,5 @@ protected:
 
 bool is_already_running(void);
 void save_screen_as_html(HWND hWnd);
-void open_dir_in_explorer(char *filename);
-bool get_open_filename(OPENFILENAMEW *ofn, const std::filesystem::path &dirname, char *filename, DWORD max_name_size);
+void open_dir_in_explorer(std::string_view filename);
+std::optional<std::filesystem::path> get_open_filename(OPENFILENAMEW *ofn, const std::filesystem::path &path_dir, const std::filesystem::path &path_file, DWORD max_name_size);
index 18a9d4c..58c3eee 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file wav-reader.cpp
  * @brief Windows版固有実装(WAVファイル読込)
  */
index 16f1ada..8534afd 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file wav-reader.h
  * @brief Windows版固有実装(WAVファイル読込)ヘッダ
index b60548e..2f49cd6 100644 (file)
@@ -1,4 +1,4 @@
-/* File: main-x11.c */
+/* File: main-x11.c */
 
 /*
  * Copyright (c) 1997 Ben Harrison, and others
@@ -95,9 +95,9 @@
 #include "io/files-util.h"
 #include "locale/japanese.h"
 #include "locale/utf-8.h"
+#include "main-unix/x11-type-string.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
-#include "main/x11-type-string.h"
 #include "system/angband.h"
 #include "system/system-variables.h"
 #include "term/gameterm.h"
 #include "util/int-char-converter.h"
 #include "util/string-processor.h"
 #include <algorithm>
+#include <memory>
+#include <span>
+#include <string>
 
 /*
  * Available graphic modes
 #include <X11/Xft/Xft.h>
 #endif
 
-#include <memory>
-#include <string>
-
 /*
  * Include some helpful X11 code.
  */
@@ -888,7 +888,7 @@ static void Infofnt_init_data(concptr name)
 }
 
 #ifdef USE_XFT
-static void Infofnt_text_std_xft_draw_str(int x, int y, concptr str, concptr str_end)
+static void Infofnt_text_std_xft_draw_str(int px, int py, const XftColor &fg, concptr str, concptr str_end)
 {
     int offset = 0;
     while (str < str_end) {
@@ -898,11 +898,25 @@ static void Infofnt_text_std_xft_draw_str(int x, int y, concptr str, concptr str
             return;
         }
 
-        XftDrawStringUtf8(Infowin->draw, &Infoclr->fg, Infofnt->info, x + Infofnt->wid * offset, y, (const FcChar8 *)str, byte_len);
+        XftDrawStringUtf8(Infowin->draw, &fg, Infofnt->info, px + Infofnt->wid * offset, py, (const FcChar8 *)str, byte_len);
         offset += (byte_len > 1 ? 2 : 1);
         str += byte_len;
     }
 }
+
+static void Infofnt_text_std_xft(int x, int y, int len, const XftColor &fg, const XftColor &bg, const char *str, int utf8_len)
+{
+    auto *draw = Infowin->draw;
+
+    const auto py = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
+    const auto px = (x * Infofnt->wid) + Infowin->ox;
+
+    XRectangle r{ 0, 0, static_cast<unsigned short>(Infofnt->wid * len), static_cast<unsigned short>(Infofnt->hgt) };
+    XftDrawSetClipRectangles(draw, px, py - Infofnt->asc, &r, 1);
+    XftDrawRect(draw, &bg, px, py - Infofnt->asc, r.width, r.height);
+    Infofnt_text_std_xft_draw_str(px, py, fg, str, str + utf8_len);
+    XftDrawSetClip(draw, 0);
+}
 #endif
 
 /*
@@ -918,8 +932,11 @@ static errr Infofnt_text_std(int x, int y, concptr str, int len)
         len = strlen(str);
     }
 
+#ifndef USE_XFT
     y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
     x = (x * Infofnt->wid) + Infowin->ox;
+#endif
+
     if (Infofnt->mono) {
 #ifndef USE_XFT
         int i;
@@ -937,17 +954,7 @@ static errr Infofnt_text_std(int x, int y, concptr str, int len)
 #endif
 
 #ifdef USE_XFT
-        XftDraw *draw = Infowin->draw;
-
-        XRectangle r;
-        r.x = 0;
-        r.y = 0;
-        r.width = Infofnt->wid * len;
-        r.height = Infofnt->hgt;
-        XftDrawSetClipRectangles(draw, x, y - Infofnt->asc, &r, 1);
-        XftDrawRect(draw, &Infoclr->bg, x, y - Infofnt->asc, Infofnt->wid * len, Infofnt->hgt);
-        Infofnt_text_std_xft_draw_str(x, y, _(utf8_buf, str), _(utf8_buf + utf8_len, str + len));
-        XftDrawSetClip(draw, 0);
+        Infofnt_text_std_xft(x, y, len, Infoclr->fg, Infoclr->bg, _(utf8_buf, str), _(utf8_len, len));
 #else
         XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info, Infoclr->gc, x, y, _(utf8_buf, str), _(utf8_len, len));
 #endif
@@ -1174,7 +1181,7 @@ static void react_keypress(XKeyEvent *xev)
 
     send_keys(msg);
 
-    if (n && !macro__pat.empty() && (macro_find_exact(msg) < 0)) {
+    if (n && !macro_patterns.empty() && (macro_find_exact(msg) < 0)) {
         macro_add(msg, buf);
     }
 }
@@ -1208,6 +1215,65 @@ static void sort_co_ord(co_ord *min, co_ord *max, const co_ord *b, const co_ord
     max->y = std::max(a->y, b->y);
 }
 
+#ifdef USE_XFT
+template <class T, class D>
+auto make_unique_ptr_with_deleter(T *p, D d) noexcept
+{
+    return std::unique_ptr<T, D>(p, std::move(d));
+}
+
+/*!
+ * @brief 矩形領域の枠を描画する
+ *
+ * ドラッグ時の選択範囲の表示に使用する。
+ *
+ * @param x 矩形領域の左上のX座標(ピクセル単位)
+ * @param y 矩形領域の左上のY座標(ピクセル単位)
+ * @param widht 矩形領域の幅(ピクセル単位)
+ * @param height 矩形領域の高さ(ピクセル単位)
+ */
+static void draw_rectangle_frame(int x, int y, int width, int height)
+{
+    auto gc = make_unique_ptr_with_deleter(XCreateGC(Metadpy->dpy, Infowin->win, 0, NULL),
+        [dpy = Metadpy->dpy](GC gc) { XFreeGC(dpy, gc); });
+
+    XSetForeground(Metadpy->dpy, gc.get(), WhitePixel(Metadpy->dpy, DefaultScreen(Metadpy->dpy)));
+    XDrawLine(Metadpy->dpy, Infowin->win, gc.get(), x, y, x + width, y);
+    XDrawLine(Metadpy->dpy, Infowin->win, gc.get(), x, y, x, y + height);
+    XDrawLine(Metadpy->dpy, Infowin->win, gc.get(), x + width, y, x + width, y + height);
+    XDrawLine(Metadpy->dpy, Infowin->win, gc.get(), x, y + height, x + width, y + height);
+}
+#endif
+
+#ifdef USE_XFT
+static void draw_cursor_xft(int x, int y, int len)
+{
+    // term_what() では中央寄せ時に座標がずれるので直接取得
+    const std::span<const char> cursor_chars(&game_term->scr->c[y][x], len);
+
+#ifdef JP
+    char utf8_buf[16];
+    const auto utf8_len = euc_to_utf8(cursor_chars.data(), cursor_chars.size(), utf8_buf, sizeof(utf8_buf));
+    if (utf8_len < 0) {
+        return;
+    }
+#endif
+    Infofnt_text_std_xft(x, y, len, Infoclr->bg, Infoclr->fg, _(utf8_buf, cursor_chars.data()), _(utf8_len, len));
+}
+#endif
+
+static void draw_cursor(int x, int y, int len)
+{
+#ifdef USE_XFT
+    draw_cursor_xft(x, y, len);
+#else
+    square_to_pixel(&x, &y, x, y);
+    const auto width = Infofnt->wid * len;
+    const auto height = Infofnt->hgt;
+    XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, width, height);
+#endif
+}
+
 /*
  * Remove the selection by redrawing it.
  */
@@ -1226,7 +1292,7 @@ static void mark_selection_mark(int x1, int y1, int x2, int y2)
     square_to_pixel(&x1, &y1, x1, y1);
     square_to_pixel(&x2, &y2, x2, y2);
 #ifdef USE_XFT
-    XftDrawRect(Infowin->draw, &clr[2]->fg, x1, y1, x2 - x1 + Infofnt->wid - 1, y2 - y1 + Infofnt->hgt - 1);
+    draw_rectangle_frame(x1, y1, x2 - x1 + Infofnt->wid - 1, y2 - y1 + Infofnt->hgt - 1);
 #else
     XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1, x2 - x1 + Infofnt->wid - 1, y2 - y1 + Infofnt->hgt - 1);
 #endif
@@ -1799,16 +1865,14 @@ static bool check_file(concptr s)
  */
 static void init_sound(void)
 {
-    int i;
-    char buf[1024];
-    char dir_xtra_sound[1024];
-    path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
-    for (i = 1; i < SOUND_MAX; i++) {
+    const auto &dir_xtra_sound = path_build(ANGBAND_DIR_XTRA, "sound");
+    for (auto i = 1; i < SOUND_MAX; i++) {
         std::string wav = angband_sound_name[i];
         wav.append(".wav");
-        path_build(buf, sizeof(buf), dir_xtra_sound, wav);
-        if (check_file(buf)) {
-            sound_file[i] = string_make(buf);
+        const auto &path = path_build(dir_xtra_sound, wav);
+        const auto &filename = path.string();
+        if (check_file(filename.data())) {
+            sound_file[i] = string_make(filename.data());
         }
     }
 
@@ -1939,7 +2003,7 @@ static errr game_term_curs_x11(int x, int y)
 #endif
     } else {
         Infoclr_set(xor_.get());
-        Infofnt_text_non(x, y, " ", 1);
+        draw_cursor(x, y, 1);
     }
 
     return 0;
@@ -1962,7 +2026,7 @@ static errr game_term_bigcurs_x11(int x, int y)
 #endif
     } else {
         Infoclr_set(xor_.get());
-        Infofnt_text_non(x, y, "  ", 2);
+        draw_cursor(x, y, 2);
     }
 
     return 0;
@@ -2388,8 +2452,6 @@ errr init_x11(int argc, char *argv[])
     int num_term = 3;
 
 #ifndef USE_XFT
-    char filename[1024];
-
     int pict_wid = 0;
     int pict_hgt = 0;
 
@@ -2517,24 +2579,29 @@ errr init_x11(int argc, char *argv[])
     }
 
 #ifndef USE_XFT
+    char filename[1024]{};
     switch (arg_graphics) {
-    case GRAPHICS_ORIGINAL:
-        path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
-        if (0 == fd_close(fd_open(filename, O_RDONLY))) {
+    case GRAPHICS_ORIGINAL: {
+        const auto &path = path_build(ANGBAND_DIR_XTRA, "graf/8x8.bmp");
+        if (0 == fd_close(fd_open(path, O_RDONLY))) {
             use_graphics = true;
             pict_wid = pict_hgt = 8;
             ANGBAND_GRAF = "old";
+            angband_strcpy(filename, path.string().data(), sizeof(filename));
         }
         break;
-    case GRAPHICS_ADAM_BOLT:
-        path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
-        if (0 == fd_close(fd_open(filename, O_RDONLY))) {
+    }
+    case GRAPHICS_ADAM_BOLT: {
+        const auto &path = path_build(ANGBAND_DIR_XTRA, "graf/16x16.bmp");
+        if (0 == fd_close(fd_open(path, O_RDONLY))) {
             use_graphics = true;
             pict_wid = pict_hgt = 16;
             ANGBAND_GRAF = "new";
+            angband_strcpy(filename, path.string().data(), sizeof(filename));
         }
         break;
     }
+    }
 
     if (use_graphics) {
         Display *dpy = Metadpy->dpy;
index 19349a5..ea4f35b 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * Copyright (c) 1997 Ben Harrison, and others
  *
  * This software may be copied and distributed for educational, research,
 #include "core/scores.h"
 #include "game-option/runtime-arguments.h"
 #include "io/files-util.h"
-#include "io/inet.h"
 #include "io/record-play-movie.h"
 #include "io/signal-handlers.h"
 #include "io/uid-checker.h"
+#include "main-unix/unix-user-ids.h"
 #include "main/angband-initializer.h"
 #include "player/process-name.h"
 #include "system/angband-version.h"
@@ -224,121 +224,85 @@ static bool parse_long_opt(const char *opt)
  */
 int main(int argc, char *argv[])
 {
-    int i;
-
-    bool done = false;
-    bool new_game = false;
-    int show_score = 0;
+    auto done = false;
+    auto new_game = false;
+    auto show_score = 0;
     concptr mstr = nullptr;
-    bool args = true;
-
-    /* Save the "program name" XXX XXX XXX */
+    auto args = true;
     argv0 = argv[0];
 
 #ifdef SET_UID
-
     /* Default permissions on files */
     (void)umask(022);
-
 #endif
 
-    /* Get the file paths */
     init_stuff();
-
+    auto &ids = UnixUserIds::get_instance();
 #ifdef SET_UID
-
-    /* Get the user id (?) */
-    p_ptr->player_uid = getuid();
-
+    ids.set_user_id(getuid());
 #ifdef VMS
-    /* Mega-Hack -- Factor group id */
-    p_ptr->player_uid += (getgid() * 1000);
+    ids.mod_user_id(getgid() * 1000);
 #endif
 
-#ifdef SAFE_SETUID
-
-#ifdef _POSIX_SAVED_IDS
-
-    /* Save some info for later */
-    p_ptr->player_euid = geteuid();
-    p_ptr->player_egid = getegid();
-
+#if defined(SAFE_SETUID) && defined(_POSIX_SAVED_IDS)
+    ids.set_effective_user_id(geteuid());
+    ids.set_effective_group_id(getegid());
 #endif
 
-#endif
-
-#endif
+#endif /* SET_UID */
 
-    /* Drop permissions */
     safe_setuid_drop();
-
 #ifdef SET_UID
-
-    /* Acquire the "user name" as a default player name */
-    user_name(p_ptr->name, p_ptr->player_uid);
-
+    user_name(p_ptr->name, ids.get_user_id());
 #ifdef PRIVATE_USER_PATH
-
     /* Create a directory for the user's files; handled by init.c. */
     create_needed_dirs();
-
 #endif /* PRIVATE_USER_PATH */
-
 #endif /* SET_UID */
 
-    /* Process the command line arguments */
-    bool browsing_movie = false;
-    for (i = 1; args && (i < argc); i++) {
-        /* Require proper options */
+    auto browsing_movie = false;
+    for (auto i = 1; args && (i < argc); i++) {
         if (argv[i][0] != '-') {
             display_usage(argv[0]);
             continue;
         }
 
-        /* Analyze option */
-        bool is_usage_needed = false;
+        auto is_usage_needed = false;
         switch (argv[i][1]) {
         case 'N':
-        case 'n': {
+        case 'n':
             new_game = true;
             break;
-        }
         case 'B':
-        case 'b': {
+        case 'b':
             arg_music = true;
             break;
-        }
         case 'V':
-        case 'v': {
+        case 'v':
             arg_sound = true;
             break;
-        }
         case 'G':
-        case 'g': {
-            /* HACK - Graphics mode switches on the original tiles */
+        case 'g':
             arg_graphics = GRAPHICS_ORIGINAL;
             break;
-        }
         case 'R':
-        case 'r': {
+        case 'r':
             arg_force_roguelike = true;
             break;
-        }
         case 'O':
-        case 'o': {
+        case 'o':
             arg_force_original = true;
             break;
-        }
         case 'S':
-        case 's': {
+        case 's':
             show_score = atoi(&argv[i][2]);
             if (show_score <= 0) {
                 show_score = 10;
             }
+
             break;
-        }
         case 'u':
-        case 'U': {
+        case 'U':
             if (!argv[i][2]) {
                 is_usage_needed = true;
                 break;
@@ -346,8 +310,7 @@ int main(int argc, char *argv[])
 
             strcpy(p_ptr->name, &argv[i][2]);
             break;
-        }
-        case 'm': {
+        case 'm':
             if (!argv[i][2]) {
                 is_usage_needed = true;
                 break;
@@ -355,17 +318,14 @@ int main(int argc, char *argv[])
 
             mstr = &argv[i][2];
             break;
-        }
-        case 'M': {
+        case 'M':
             arg_monochrome = true;
             break;
-        }
         case 'd':
-        case 'D': {
+        case 'D':
             change_path(&argv[i][2]);
             break;
-        }
-        case 'x': {
+        case 'x':
             if (!argv[i][2]) {
                 is_usage_needed = true;
                 break;
@@ -374,8 +334,7 @@ int main(int argc, char *argv[])
             prepare_browse_movie_with_path_build(&argv[i][2]);
             browsing_movie = true;
             break;
-        }
-        case '-': {
+        case '-':
             if (argv[i][2] == '\0') {
                 argv[i] = argv[0];
                 argc = argc - i;
@@ -384,13 +343,12 @@ int main(int argc, char *argv[])
             } else {
                 is_usage_needed = parse_long_opt(argv[i]);
             }
+
             break;
-        }
-        default: {
+        default:
             is_usage_needed = true;
             break;
         }
-        }
 
         if (!is_usage_needed) {
             continue;
@@ -399,20 +357,15 @@ int main(int argc, char *argv[])
         display_usage(argv[0]);
     }
 
-    /* Hack -- Forget standard args */
     if (args) {
         argc = 1;
         argv[1] = nullptr;
     }
 
-    /* Process the player name */
     process_player_name(p_ptr, true);
-
-    /* Install "quit" hook */
     quit_aux = quit_hook;
 
 #ifdef USE_X11
-    /* Attempt to use the "main-x11.c" support */
     if (!done && (!mstr || (streq(mstr, "x11")))) {
         extern errr init_x11(int, char **);
         if (0 == init_x11(argc, argv)) {
@@ -423,7 +376,6 @@ int main(int argc, char *argv[])
 #endif
 
 #ifdef USE_GCU
-    /* Attempt to use the "main-gcu.c" support */
     if (!done && (!mstr || (streq(mstr, "gcu")))) {
         extern errr init_gcu(int, char **);
         if (0 == init_gcu(argc, argv)) {
@@ -434,7 +386,6 @@ int main(int argc, char *argv[])
 #endif
 
 #ifdef USE_CAP
-    /* Attempt to use the "main-cap.c" support */
     if (!done && (!mstr || (streq(mstr, "cap")))) {
         extern errr init_cap(int, char **);
         if (0 == init_cap(argc, argv)) {
@@ -444,36 +395,24 @@ int main(int argc, char *argv[])
     }
 #endif
 
-    /* Make sure we have a display! */
     if (!done) {
         quit("Unable to prepare any 'display module'!");
     }
 
-    /* Hack -- If requested, display scores and quit */
     if (show_score > 0) {
         display_scores(0, show_score);
     }
 
-    /* Catch nasty signals */
     signals_init();
 
     {
         TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
-
-        /* Initialize */
         init_angband(p_ptr, false);
-
-        /* Wait for response */
         pause_line(MAIN_TERM_MIN_ROWS - 1);
     }
 
-    /* Play the game */
     play_game(p_ptr, new_game, browsing_movie);
-
-    /* Quit */
     quit(nullptr);
-
-    /* Exit */
     return 0;
 }
 
index 1380400..7e7ee9e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file angband-headers.cpp
  * @brief ゲームデータのグローバルヘッダ情報定義
  */
index 4277609..49123f3 100644 (file)
@@ -1,16 +1,17 @@
-#pragma once
+#pragma once
 /*!
  * @file angband-headers.h
  * @brief ゲームデータのグローバルヘッダ情報ヘッダ
  */
 
 #include "system/angband.h"
+#include "util/sha256.h"
 
 /*!
  * @brief 各初期データ用ヘッダ構造体 / Template file header information (see "init.c").
  */
 struct angband_header {
-    byte checksum; //!< Checksum of "info" records
+    util::SHA256::Digest digest; //!< Checksum of "info" records
     uint16_t info_num; //!< このinfoのデータ数
 };
 
index b194500..e365a5a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file angband-initializer.cpp
  * @brief 変愚蛮怒のシステム初期化
  * @date 2014/01/28
@@ -103,8 +103,7 @@ void init_file_paths(const std::filesystem::path &libpath, const std::filesystem
     struct tm *t = localtime(&now);
     char tmp[128];
     strftime(tmp, sizeof(tmp), "%Y-%m-%d-%H-%M-%S", t);
-    path_build(debug_savefile, sizeof(debug_savefile), ANGBAND_DIR_DEBUG_SAVE, tmp);
-
+    debug_savefile = path_build(ANGBAND_DIR_DEBUG_SAVE, tmp);
     remove_old_debug_savefiles();
 }
 
@@ -195,7 +194,7 @@ void create_needed_dirs(void)
  */
 static void init_note_term(concptr str)
 {
-    term_erase(0, 23, 255);
+    term_erase(0, 23);
     term_putstr(20, 23, -1, TERM_WHITE, str);
     term_fresh();
 }
@@ -250,12 +249,11 @@ static void put_title()
  */
 void init_angband(PlayerType *player_ptr, bool no_term)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
-    auto fd = fd_open(buf, O_RDONLY);
+    const auto &path_news = path_build(ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
+    auto fd = fd_open(path_news, O_RDONLY);
     if (fd < 0) {
         std::string why = _("'", "Cannot access the '");
-        why.append(buf);
+        why.append(path_news.string());
         why.append(_("'ファイルにアクセスできません!", "' file!"));
         init_angband_aux(why);
     }
@@ -263,10 +261,10 @@ void init_angband(PlayerType *player_ptr, bool no_term)
     (void)fd_close(fd);
     if (!no_term) {
         term_clear();
-        path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
-        auto *fp = angband_fopen(buf, FileOpenMode::READ);
+        auto *fp = angband_fopen(path_news, FileOpenMode::READ);
         if (fp) {
             int i = 0;
+            char buf[1024]{};
             while (0 == angband_fgets(fp, buf, sizeof(buf))) {
                 term_putstr(0, i++, -1, TERM_WHITE, buf);
             }
@@ -277,15 +275,16 @@ void init_angband(PlayerType *player_ptr, bool no_term)
         term_flush();
     }
 
-    path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
-    fd = fd_open(buf, O_RDONLY);
+    const auto &path_score = path_build(ANGBAND_DIR_APEX, "scores.raw");
+    fd = fd_open(path_score, O_RDONLY);
     if (fd < 0) {
-        safe_setuid_grab(player_ptr);
-        fd = fd_make(buf, true);
+        safe_setuid_grab();
+        fd = fd_make(path_score, true);
         safe_setuid_drop();
         if (fd < 0) {
+            const auto &filename_score = path_score.string();
             std::string why = _("'", "Cannot create the '");
-            why.append(buf);
+            why.append(filename_score);
             why.append(_("'ファイルを作成できません!", "' file!"));
             init_angband_aux(why);
         }
@@ -367,10 +366,12 @@ void init_angband(PlayerType *player_ptr, bool no_term)
 
     init_note(_("[データの初期化中... (その他)]", "[Initializing arrays... (other)]"));
     init_other(player_ptr);
-    init_note(_("[データの初期化中... (アロケーション)]", "[Initializing arrays... (alloc)]"));
-    init_alloc();
+    init_note(_("[データの初期化中... (モンスターアロケーション)]", "[Initializing arrays... (monsters alloc)]"));
+    init_monsters_alloc();
+    init_note(_("[データの初期化中... (アイテムアロケーション)]", "[Initializing arrays... (items alloc)]"));
+    init_items_alloc();
     init_note(_("[ユーザー設定ファイルを初期化しています...]", "[Initializing user pref files...]"));
     process_pref_file(player_ptr, "pref.prf");
-    process_pref_file(player_ptr, std::string("pref-").append(ANGBAND_SYS).append(".prf").data());
+    process_pref_file(player_ptr, std::string("pref-").append(ANGBAND_SYS).append(".prf"));
     init_note(_("[初期化終了]", "[Initialization complete]"));
 }
index 137ba6f..84c0243 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file angband-initializer.h
  * @brief 変愚蛮怒のシステム初期化処理ヘッダファイル
index 5a8fdd9..3b5b712 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file game-data-initializer.cpp
  * @brief 変愚蛮怒のゲームデータ初期化定義
  */
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "util/angband-files.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "view/display-messages.h"
 #include "world/world.h"
 #include <algorithm>
@@ -56,14 +56,12 @@ void init_other(PlayerType *player_ptr)
     }
 
     max_dlv.assign(dungeons_info.size(), {});
-    floor_ptr->grid_array.assign(MAX_HGT, std::vector<grid_type>(MAX_WID));
+    floor_ptr->grid_array.assign(MAX_HGT, std::vector<Grid>(MAX_WID));
     init_gf_colors();
 
-    macro__pat.assign(MACRO_MAX, {});
-    macro__act.assign(MACRO_MAX, {});
-    macro__buf.assign(FILE_READ_BUFF_SIZE, {});
-    quark_init();
-
+    macro_patterns.assign(MACRO_MAX, {});
+    macro_actions.assign(MACRO_MAX, {});
+    macro_buffers.assign(FILE_READ_BUFF_SIZE, {});
     for (auto i = 0; option_info[i].o_desc; i++) {
         int os = option_info[i].o_set;
         int ob = option_info[i].o_bit;
@@ -71,38 +69,62 @@ void init_other(PlayerType *player_ptr)
             continue;
         }
 
-        option_mask[os] |= (1UL << ob);
+        g_option_masks[os] |= (1UL << ob);
         if (option_info[i].o_norm) {
-            set_bits(option_flag[os], 1U << ob);
+            set_bits(g_option_flags[os], 1U << ob);
         } else {
-            reset_bits(option_flag[os], 1U << ob);
+            reset_bits(g_option_flags[os], 1U << ob);
         }
     }
 
-    for (auto n = 0; n < 8; n++) {
+    for (auto &window_mask : g_window_masks) {
         for (auto i = 0; i < 32; i++) {
             if (window_flag_desc[i]) {
-                set_bits(window_mask[n], 1U << i);
+                window_mask.set(i2enum<SubWindowRedrawingFlag>(i));
             }
         }
     }
 
-    /*
-     *  Set the "default" window flags
-     *  Window 1 : Display messages
-     *  Window 2 : Display inven/equip
-     */
-    window_flag[1] = 1U << A_MAX;
-    window_flag[2] = 1U << 0;
-    (void)format("%s (%s).", "Mr.Hoge", MAINTAINER);
+    g_window_flags[1].clear();
+    g_window_flags[1].set(SubWindowRedrawingFlag::MESSAGE);
+    g_window_flags[2].clear();
+    g_window_flags[2].set(SubWindowRedrawingFlag::INVENTORY);
 }
 
 /*!
- * @brief オブジェクト配列を初期化する /
- * Initialize some other arrays
- * @return エラーコード
+ * @brief モンスター生成テーブルを初期化する
+ */
+void init_monsters_alloc()
+{
+    std::vector<const MonsterRaceInfo *> elements;
+    for (const auto &[r_idx, r_ref] : monraces_info) {
+        if (MonsterRace(r_ref.idx).is_valid()) {
+            elements.push_back(&r_ref);
+        }
+    }
+
+    std::sort(elements.begin(), elements.end(),
+        [](const MonsterRaceInfo *r1_ptr, const MonsterRaceInfo *r2_ptr) {
+            return r1_ptr->level < r2_ptr->level;
+        });
+
+    alloc_race_table.clear();
+    for (const auto r_ptr : elements) {
+        if (r_ptr->rarity == 0) {
+            continue;
+        }
+
+        const auto index = static_cast<short>(r_ptr->idx);
+        const auto level = r_ptr->level;
+        const auto prob = static_cast<PROB>(100 / r_ptr->rarity);
+        alloc_race_table.push_back({ index, level, prob, prob });
+    }
+}
+
+/*!
+ * @brief アイテム生成テーブルを初期化する
  */
-static void init_object_alloc()
+void init_items_alloc()
 {
     short num[MAX_DEPTH]{};
     auto alloc_kind_size = 0;
@@ -143,37 +165,3 @@ static void init_object_alloc()
         }
     }
 }
-
-/*!
- * @brief モンスター配列と生成テーブルを初期化する /
- * Initialize some other arrays
- * @return エラーコード
- */
-void init_alloc(void)
-{
-    std::vector<const MonsterRaceInfo *> elements;
-    for (const auto &[r_idx, r_ref] : monraces_info) {
-        if (MonsterRace(r_ref.idx).is_valid()) {
-            elements.push_back(&r_ref);
-        }
-    }
-
-    std::sort(elements.begin(), elements.end(),
-        [](const MonsterRaceInfo *r1_ptr, const MonsterRaceInfo *r2_ptr) {
-            return r1_ptr->level < r2_ptr->level;
-        });
-
-    alloc_race_table.clear();
-    for (const auto r_ptr : elements) {
-        if (r_ptr->rarity == 0) {
-            continue;
-        }
-
-        const auto index = static_cast<short>(r_ptr->idx);
-        const auto level = r_ptr->level;
-        const auto prob = static_cast<PROB>(100 / r_ptr->rarity);
-        alloc_race_table.push_back({ index, level, prob, prob });
-    }
-
-    init_object_alloc();
-}
index 5cb155b..effa2c2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file game-data-initializer.h
  * @brief 変愚蛮怒のゲームデータ初期化ヘッダファイル
@@ -8,4 +8,5 @@
 
 class PlayerType;
 void init_other(PlayerType *player_ptr);
-void init_alloc(void);
+void init_monsters_alloc();
+void init_items_alloc();
index 0c5a8b7..23c4a08 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file info-initializer.cpp
  * @brief 変愚蛮怒のゲームデータ解析処理定義
  */
@@ -78,7 +78,7 @@ constexpr bool is_vector_v = is_vector<T>::value;
  */
 static void init_header(angband_header *head, IDX num = 0)
 {
-    head->checksum = 0;
+    head->digest = {};
     head->info_num = (IDX)num;
 }
 
@@ -96,10 +96,8 @@ static void init_header(angband_header *head, IDX num = 0)
 template <typename InfoType>
 static errr init_info(std::string_view filename, angband_header &head, InfoType &info, Parser parser, Retoucher retouch = nullptr)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, filename);
-
-    auto *fp = angband_fopen(buf, FileOpenMode::READ);
+    const auto &path = path_build(ANGBAND_DIR_EDIT, filename);
+    auto *fp = angband_fopen(path, FileOpenMode::READ);
     if (!fp) {
         quit_fmt(_("'%s'ファイルをオープンできません。", "Cannot open '%s' file."), filename.data());
     }
@@ -110,14 +108,15 @@ static errr init_info(std::string_view filename, angband_header &head, InfoType
         info.assign(head.info_num, value_type{});
     }
 
-    const auto err = init_info_txt(fp, buf, &head, parser);
+    char buf[1024]{};
+    const auto &[error_code, error_line] = init_info_txt(fp, buf, &head, parser);
     angband_fclose(fp);
-    if (err) {
-        const auto oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : _("未知の", "unknown"));
+    if (error_code != PARSE_ERROR_NONE) {
+        const auto oops = (((error_code > 0) && (error_code < PARSE_ERROR_MAX)) ? err_str[error_code] : _("未知の", "unknown"));
 #ifdef JP
         msg_format("'%s'ファイルの %d 行目にエラー。", filename.data(), error_line);
 #else
-        msg_format("Error %d at line %d of '%s'.", err, error_line, filename.data());
+        msg_format("Error %d at line %d of '%s'.", error_code, error_line, filename.data());
 #endif
         msg_format(_("レコード %d は '%s' エラーがあります。", "Record %d contains a '%s' error."), error_idx, oops);
         msg_format(_("構文 '%s'。", "Parsing '%s'."), buf);
@@ -206,7 +205,8 @@ errr init_terrains_info()
     init_header(&terrains_header);
     auto *parser = parse_terrains_info;
     auto *retoucher = retouch_terrains_info;
-    return init_info("TerrainDefinitions.txt", terrains_header, terrains_info, parser, retoucher);
+    auto &terrains = TerrainList::get_instance();
+    return init_info("TerrainDefinitions.txt", terrains_header, terrains.get_raw_vector(), parser, retoucher);
 }
 
 /*!
@@ -273,8 +273,7 @@ static bool read_wilderness_definition(std::ifstream &ifs)
  */
 bool init_wilderness()
 {
-    char path[1024]{};
-    path_build(path, sizeof(path), ANGBAND_DIR_EDIT, WILDERNESS_DEFINITION);
+    const auto &path = path_build(ANGBAND_DIR_EDIT, WILDERNESS_DEFINITION);
     std::ifstream ifs(path);
     if (!ifs) {
         return false;
index 8395d0d..fa317e0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file info-initializer.h
  * @brief 変愚蛮怒のゲームデータ解析処理ヘッダ
index f5cb8c4..0155e4f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file init-error-messages-table.cpp
  * @brief 変愚蛮怒のゲームデータ解析エラー名定義
  */
index bb23d5c..868bf21 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file init-error-messages-table.h
  * @brief 変愚蛮怒のゲームデータ解析エラー名ヘッダ
index 3515e48..b1fa6fb 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file music-definitions-table.cpp
  * @brief 設定ファイル用のBGM名定義
  */
index 38860a1..78b2feb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file music-definitions-table.h
  * @brief 設定ファイル用のBGM名定義ヘッダ
index 7a690b2..b5a40cc 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file scene-table-floor.cpp
  * @brief フロアの状況に応じたBGM設定処理実装
  */
@@ -6,6 +6,7 @@
 #include "main/scene-table-floor.h"
 #include "dungeon/quest.h"
 #include "main/music-definitions-table.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
@@ -32,7 +33,7 @@ static bool scene_basic(PlayerType *player_ptr, scene_type *value)
         return true;
     }
 
-    if (player_ptr->phase_out) {
+    if (AngbandSystem::get_instance().is_phase_out()) {
         value->type = TERM_XTRA_MUSIC_BASIC;
         value->val = MUSIC_BASIC_BATTLE;
         return true;
@@ -43,7 +44,8 @@ static bool scene_basic(PlayerType *player_ptr, scene_type *value)
 
 static bool scene_quest(PlayerType *player_ptr, scene_type *value)
 {
-    const QuestId quest_id = quest_number(player_ptr, player_ptr->current_floor_ptr->dun_level);
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto quest_id = floor.get_quest_id();
     const bool enable = (inside_quest(quest_id));
     if (enable) {
         value->type = TERM_XTRA_MUSIC_QUEST;
@@ -55,7 +57,8 @@ static bool scene_quest(PlayerType *player_ptr, scene_type *value)
 
 static bool scene_quest_basic(PlayerType *player_ptr, scene_type *value)
 {
-    const QuestId quest_id = quest_number(player_ptr, player_ptr->current_floor_ptr->dun_level);
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto quest_id = floor.get_quest_id();
     const bool enable = (inside_quest(quest_id));
     if (enable) {
         value->type = TERM_XTRA_MUSIC_BASIC;
@@ -119,10 +122,11 @@ static bool scene_dungeon_feeling(PlayerType *player_ptr, scene_type *value)
 
 static bool scene_dungeon(PlayerType *player_ptr, scene_type *value)
 {
-    const bool enable = (player_ptr->dungeon_idx > 0);
+    const auto *floor_ptr = player_ptr->current_floor_ptr;
+    const bool enable = (floor_ptr->dungeon_idx > 0);
     if (enable) {
         value->type = TERM_XTRA_MUSIC_DUNGEON;
-        value->val = player_ptr->dungeon_idx;
+        value->val = floor_ptr->dungeon_idx;
     }
     return enable;
 }
index 9c6a902..0e5a825 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file scene-table-floor.h
  * @brief フロアの状況に応じたBGM設定処理ヘッダ
index 0838e21..da9b70f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file scene-table-monster.cpp
  * @brief モンスターの遭遇状況に応じたBGM設定処理実装
  */
@@ -88,8 +88,8 @@ static bool is_high_rate(PlayerType *player_ptr, MONSTER_IDX m_idx1, MONSTER_IDX
     auto floor_ptr = player_ptr->current_floor_ptr;
     auto m_ptr1 = &floor_ptr->m_list[m_idx1];
     auto m_ptr2 = &floor_ptr->m_list[m_idx2];
-    auto ap_r_ptr1 = &monraces_info[m_ptr1->ap_r_idx];
-    auto ap_r_ptr2 = &monraces_info[m_ptr2->ap_r_idx];
+    auto ap_r_ptr1 = &m_ptr1->get_appearance_monrace();
+    auto ap_r_ptr2 = &m_ptr2->get_appearance_monrace();
 
     /* Unique monsters first */
     if (ap_r_ptr1->kind_flags.has(MonsterKindType::UNIQUE) != ap_r_ptr2->kind_flags.has(MonsterKindType::UNIQUE)) {
@@ -140,7 +140,7 @@ static void update_target_monster(PlayerType *player_ptr, MONSTER_IDX m_idx)
 
         if (do_dwap) {
             auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-            MonsterRaceInfo *ap_r_ptr = &monraces_info[m_ptr->ap_r_idx];
+            auto *ap_r_ptr = &m_ptr->get_appearance_monrace();
             scene_target_monster.m_idx = m_idx;
             scene_target_monster.ap_r_ptr = ap_r_ptr;
             scene_target_monster.last_seen = get_game_turn();
@@ -245,7 +245,7 @@ void refresh_scene_monster(PlayerType *player_ptr, const std::vector<MONSTER_IDX
                 clear_scene_target_monster();
             } else {
                 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[scene_target_monster.m_idx];
-                MonsterRaceInfo *ap_r_ptr = &monraces_info[m_ptr->ap_r_idx];
+                auto *ap_r_ptr = &m_ptr->get_appearance_monrace();
                 if (ap_r_ptr != scene_target_monster.ap_r_ptr) {
                     // 死亡、チェンジモンスター、etc.
                     clear_scene_target_monster();
index 46f431b..9691e36 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file scene-table-monster.h
  * @brief モンスターの遭遇状況に応じたBGM設定処理ヘッダ
index a5805fa..0800a37 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file scene-table.cpp
  * @brief BGM選曲の基本処理部分実装
  */
index 56577ff..7f30e6b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file scene-table.h
  * @brief BGM選曲の基本処理部分ヘッダ
index 8575790..9a18de4 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file sound-definitions-table.cpp
  * @brief 設定ファイル用の効果音名定義
  */
index da6a5d8..c0765c4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file sound-definitions-table.h
  * @brief 設定ファイル用の効果音名定義ヘッダ
index 99eb5f4..6a6fa29 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file sound-of-music.cpp
  * @brief BGM及び効果音のterm出力処理実装
  */
index 7f20954..60b31b0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file sound-of-music.h
  * @brief BGM及び効果音のterm出力処理ヘッダ
index 56c2a8c..a94c60d 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/arena-info-table.h"
+#include "market/arena-info-table.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-indice-types.h"
 #include "object/tval-types.h"
index f47f9e4..86651df 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/baseitem-info.h"
 #include <vector>
index 8237d5b..c1b3d6a 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/arena.h"
+#include "market/arena.h"
 #include "cmd-building/cmd-building.h"
 #include "core/asking-player.h"
 #include "core/show-file.h"
@@ -10,6 +10,7 @@
 #include "market/arena-info-table.h"
 #include "market/building-actions-table.h"
 #include "market/building-util.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags-resistance.h"
 #include "monster/monster-util.h"
 #include "player-base/player-class.h"
 #include "status/buff-setter.h"
+#include "system/angband-exceptions.h"
+#include "system/angband-system.h"
 #include "system/building-type-definition.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/int-char-converter.h"
 #include <algorithm>
 #include <numeric>
 
+namespace {
+enum class ArenaRecord {
+    FENGFUANG,
+    POWER_WYRM,
+    METAL_BABBLE,
+};
+}
+
 /*!
  * @brief 優勝時のメッセージを表示し、賞金を与える
  * @param player_ptr プレイヤーへの参照ポインタ
@@ -58,33 +70,36 @@ static bool process_ostensible_arena_victory(PlayerType *player_ptr)
 }
 
 /*!
- * @brief はぐれメタルとの対戦
+ * @brief 対戦相手の確認
  * @param player_ptr プレイヤーへの参照ポインタ
- * @return まだパワー・ワイアーム以下を倒していないならFALSE、倒していたらTRUE
+ * @return 最後に倒した対戦相手 (鳳凰以下は一律で鳳凰)
  */
-static bool battle_metal_babble(PlayerType *player_ptr)
+static ArenaRecord check_arena_record(PlayerType *player_ptr)
 {
     if (player_ptr->arena_number <= MAX_ARENA_MONS) {
-        return false;
+        return ArenaRecord::FENGFUANG;
     }
 
-    if (player_ptr->arena_number >= MAX_ARENA_MONS + 2) {
-        msg_print(_("あなたはアリーナに入り、しばらくの間栄光にひたった。", "You enter the arena briefly and bask in your glory."));
-        msg_print(nullptr);
-        return true;
+    if (player_ptr->arena_number < MAX_ARENA_MONS + 2) {
+        return ArenaRecord::POWER_WYRM;
     }
 
+    return ArenaRecord::METAL_BABBLE;
+}
+
+static bool check_battle_metal_babble(PlayerType *player_ptr)
+{
     msg_print(_("君のために最強の挑戦者を用意しておいた。", "The strongest challenger is waiting for you."));
     msg_print(nullptr);
-    if (!get_check(_("挑戦するかね?", "Do you fight? "))) {
+    if (!input_check(_("挑戦するかね?", "Do you fight? "))) {
         msg_print(_("残念だ。", "We are disappointed."));
-        return true;
+        return false;
     }
 
     msg_print(_("死ぬがよい。", "Die, maggots."));
     msg_print(nullptr);
 
-    player_ptr->exit_bldg = false;
+    w_ptr->set_arena(false);
     reset_tim_flags(player_ptr);
 
     /* Save the surface floor as saved floor */
@@ -92,33 +107,44 @@ static bool battle_metal_babble(PlayerType *player_ptr)
 
     player_ptr->current_floor_ptr->inside_arena = true;
     player_ptr->leaving = true;
-    player_ptr->leave_bldg = true;
     return true;
 }
 
-static void go_to_arena(PlayerType *player_ptr)
+/*!
+ * @brief アリーナへの入場処理
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @return アリーナへ入場するか否か
+ */
+static bool go_to_arena(PlayerType *player_ptr)
 {
     if (process_ostensible_arena_victory(player_ptr)) {
-        return;
+        return false;
     }
 
-    if (battle_metal_babble(player_ptr)) {
-        return;
+    const auto arena_record = check_arena_record(player_ptr);
+    if (arena_record == ArenaRecord::METAL_BABBLE) {
+        msg_print(_("あなたはアリーナに入り、しばらくの間栄光にひたった。", "You enter the arena briefly and bask in your glory."));
+        msg_print(nullptr);
+        return false;
+    }
+
+    if ((arena_record == ArenaRecord::POWER_WYRM) && !check_battle_metal_babble(player_ptr)) {
+        return false;
     }
 
     if (player_ptr->riding && !PlayerClass(player_ptr).is_tamer()) {
         msg_print(_("ペットに乗ったままではアリーナへ入れさせてもらえなかった。", "You don't have permission to enter with pet."));
         msg_print(nullptr);
-        return;
+        return false;
     }
 
-    player_ptr->exit_bldg = false;
+    w_ptr->set_arena(false);
     reset_tim_flags(player_ptr);
     prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS);
 
     player_ptr->current_floor_ptr->inside_arena = true;
     player_ptr->leaving = true;
-    player_ptr->leave_bldg = true;
+    return true;
 }
 
 static void see_arena_poster(PlayerType *player_ptr)
@@ -133,13 +159,10 @@ static void see_arena_poster(PlayerType *player_ptr)
         return;
     }
 
-    MonsterRaceInfo *r_ptr;
-    r_ptr = &monraces_info[arena_info[player_ptr->arena_number].r_idx];
-    concptr name = r_ptr->name.data();
-    msg_format(_("%s に挑戦するものはいないか?", "Do I hear any challenges against: %s"), name);
-
+    auto *r_ptr = &monraces_info[arena_info[player_ptr->arena_number].r_idx];
+    msg_format(_("%s に挑戦するものはいないか?", "Do I hear any challenges against: %s"), r_ptr->name.data());
     player_ptr->monster_race_idx = arena_info[player_ptr->arena_number].r_idx;
-    player_ptr->window_flags |= (PW_MONSTER_LORE);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
     handle_stuff(player_ptr);
 }
 
@@ -148,22 +171,21 @@ static void see_arena_poster(PlayerType *player_ptr)
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param cmd 闘技場処理のID
  */
-void arena_comm(PlayerType *player_ptr, int cmd)
+bool arena_comm(PlayerType *player_ptr, int cmd)
 {
     switch (cmd) {
     case BACT_ARENA:
-        go_to_arena(player_ptr);
-        return;
+        return go_to_arena(player_ptr);
     case BACT_POSTER:
         see_arena_poster(player_ptr);
-        return;
+        return false;
     case BACT_ARENA_RULES:
         screen_save();
-
-        /* Peruse the on_defeat_arena_monster help file */
-        (void)show_file(player_ptr, true, _("arena_j.txt", "arena.txt"), nullptr, 0, 0);
+        (void)show_file(player_ptr, true, _("arena_j.txt", "arena.txt"), 0, 0);
         screen_load();
-        break;
+        return false;
+    default:
+        THROW_EXCEPTION(std::logic_error, "Invalid building action is specified!");
     }
 }
 
@@ -204,12 +226,12 @@ void update_gambling_monsters(PlayerType *player_ptr)
             int j;
             while (true) {
                 get_mon_num_prep(player_ptr, monster_can_entry_arena, nullptr);
-                r_idx = get_mon_num(player_ptr, 0, mon_level, GMN_ARENA);
+                r_idx = get_mon_num(player_ptr, 0, mon_level, PM_ARENA);
                 if (!MonsterRace(r_idx).is_valid()) {
                     continue;
                 }
 
-                if (monraces_info[r_idx].kind_flags.has(MonsterKindType::UNIQUE) || (monraces_info[r_idx].flags7 & RF7_UNIQUE2)) {
+                if (monraces_info[r_idx].kind_flags.has(MonsterKindType::UNIQUE) || monraces_info[r_idx].population_flags.has(MonsterPopulationType::ONLY_ONE)) {
                     if ((monraces_info[r_idx].level + 10) > mon_level) {
                         continue;
                     }
@@ -266,11 +288,6 @@ void update_gambling_monsters(PlayerType *player_ptr)
  */
 bool monster_arena_comm(PlayerType *player_ptr)
 {
-    PRICE maxbet;
-    PRICE wager;
-    char out_val[MAX_MONSTER_NAME];
-    concptr p;
-
     if ((w_ptr->game_turn - w_ptr->arena_start_turn) > TURNS_PER_TICK * 250) {
         update_gambling_monsters(player_ptr);
         w_ptr->arena_start_turn = w_ptr->game_turn;
@@ -289,17 +306,19 @@ bool monster_arena_comm(PlayerType *player_ptr)
     clear_bldg(4, 10);
 
     prt(_("モンスター                                                     倍率", "Monsters                                                       Odds"), 4, 4);
-    for (int i = 0; i < 4; i++) {
-        auto *r_ptr = &monraces_info[battle_mon_list[i]];
+    for (auto i = 0; i < 4; i++) {
+        const auto &monrace = monraces_info[battle_mon_list[i]];
         std::string name;
-        if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
-            name = _(r_ptr->name, "Fake ");
-            name.append(_("もどき", r_ptr->name));
+        if (monrace.kind_flags.has(MonsterKindType::UNIQUE)) {
+            name = _(monrace.name, "Fake ");
+            name.append(_("もどき", monrace.name));
         } else {
-            name = r_ptr->name;
+            name = monrace.name;
             name.append(_("      ", ""));
         }
-        prt(format(_("%d) %-58s  %4ld.%02ld倍", "%d) %-58s  %4ld.%02ld"), i + 1, name.data(), (long int)mon_odds[i] / 100, (long int)mon_odds[i] % 100), 5 + i, 1);
+
+        constexpr auto fmt = _("%d) %-58s  %4ld.%02ld倍", "%d) %-58s  %4ld.%02ld");
+        prt(format(fmt, i + 1, name.data(), (long int)mon_odds[i] / 100, (long int)mon_odds[i] % 100), 5 + i, 1);
     }
 
     prt(_("どれに賭けますか:", "Which monster: "), 0, 0);
@@ -329,54 +348,31 @@ bool monster_arena_comm(PlayerType *player_ptr)
         }
     }
 
-    maxbet = player_ptr->lev * 200;
-
-    /* We can't bet more than we have */
+    auto maxbet = player_ptr->lev * 200;
     maxbet = std::min(maxbet, player_ptr->au);
-
-    /*
-     * Get the wager
-     * Use get_string() because we may need more than
-     * the int16_t value returned by get_quantity().
-     */
-    out_val[0] = '\0';
-    if (!get_string(format(_("賭け金 (1-%ld)?", "Your wager (1-%ld) ? "), (long int)maxbet), out_val, 32)) {
+    constexpr auto prompt = _("賭け金?", "Your wager? ");
+    const auto wager = input_integer(prompt, 1, maxbet, 1);
+    if (!wager) {
         screen_load();
         return false;
     }
 
-    for (p = out_val; *p == ' '; p++) {
-        ;
-    }
-
-    wager = atol(p);
     if (wager > player_ptr->au) {
         msg_print(_("おい!金が足りないじゃないか!出ていけ!", "Hey! You don't have the gold - get out of here!"));
-
         msg_print(nullptr);
         screen_load();
         return false;
-    } else if (wager > maxbet) {
-        msg_format(_("%ldゴールドだけ受けよう。残りは取っときな。", "I'll take %ld gold of that. Keep the rest."), (long int)maxbet);
-
-        wager = maxbet;
-    } else if (wager < 1) {
-        msg_print(_("OK、1ゴールドでいこう。", "Ok, we'll start with 1 gold."));
-        wager = 1;
     }
 
     msg_print(nullptr);
-    battle_odds = std::max(wager + 1, wager * battle_odds / 100);
-    kakekin = wager;
-    player_ptr->au -= wager;
+    battle_odds = std::max(*wager + 1, *wager * battle_odds / 100);
+    kakekin = *wager;
+    player_ptr->au -= *wager;
     reset_tim_flags(player_ptr);
 
     prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS);
-
-    player_ptr->phase_out = true;
+    AngbandSystem::get_instance().set_phase_out(true);
     player_ptr->leaving = true;
-    player_ptr->leave_bldg = true;
-
     screen_load();
     return true;
 }
index da09489..9896b67 100644 (file)
@@ -1,6 +1,6 @@
-#pragma once
+#pragma once
 
 class PlayerType;
-void arena_comm(PlayerType *player_ptr, int cmd);
+bool arena_comm(PlayerType *player_ptr, int cmd);
 void update_gambling_monsters(PlayerType *player_ptr);
 bool monster_arena_comm(PlayerType *player_ptr);
index d809f4c..5e16b21 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/bounty-prize-table.h"
+#include "market/bounty-prize-table.h"
 #include "object/tval-types.h"
 #include "sv-definition/sv-potion-types.h"
 #include "sv-definition/sv-scroll-types.h"
index 803bb81..63f3223 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 賞金首の報酬テーブル
  * @author Hourier
  * @date 2022/11/04
index 0dd5665..f538730 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 8b78c03..4eb5594 100644 (file)
@@ -1,9 +1,8 @@
-#include "market/bounty.h"
+#include "market/bounty.h"
 #include "autopick/autopick.h"
 #include "avatar/avatar.h"
 #include "cmd-building/cmd-building.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "flavor/flavor-describer.h"
 #include "game-option/cheat-options.h"
@@ -12,6 +11,7 @@
 #include "io/input-key-acceptor.h"
 #include "market/bounty-prize-table.h"
 #include "market/building-util.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
@@ -32,6 +32,7 @@
 #include "system/item-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "term/z-form.h"
@@ -48,6 +49,7 @@
 bool exchange_cash(PlayerType *player_ptr)
 {
     auto change = false;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     for (INVENTORY_IDX i = 0; i <= INVEN_SUB_HAND; i++) {
         const auto item_ptr = &player_ptr->inventory_list[i];
         const auto r_idx_of_item = static_cast<MonsterRaceId>(item_ptr->pval);
@@ -57,32 +59,32 @@ bool exchange_cash(PlayerType *player_ptr)
 
         change = true;
         const auto item_name = describe_flavor(player_ptr, item_ptr, 0);
-        if (!get_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
+        if (!input_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
             continue;
         }
 
         msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(1000000L * item_ptr->number));
         player_ptr->au += 1000000L * item_ptr->number;
-        player_ptr->redraw |= (PR_GOLD);
+        rfu.set_flag(MainWindowRedrawingFlag::GOLD);
         vary_item(player_ptr, i, -item_ptr->number);
     }
 
     for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
         const auto item_ptr = &player_ptr->inventory_list[i];
         const auto r_idx_of_item = static_cast<MonsterRaceId>(item_ptr->pval);
-        if ((item_ptr->bi_key != BaseitemKey(ItemKindType::CORPSE, SV_CORPSE)) || (r_idx_of_item != MonsterRaceId::TSUCHINOKO)) {
+        if (!item_ptr->is_corpse() || (r_idx_of_item != MonsterRaceId::TSUCHINOKO)) {
             continue;
         }
 
         change = true;
         const auto item_name = describe_flavor(player_ptr, item_ptr, 0);
-        if (!get_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
+        if (!input_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
             continue;
         }
 
         msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(200000L * item_ptr->number));
         player_ptr->au += 200000L * item_ptr->number;
-        player_ptr->redraw |= (PR_GOLD);
+        rfu.set_flag(MainWindowRedrawingFlag::GOLD);
         vary_item(player_ptr, i, -item_ptr->number);
     }
 
@@ -95,33 +97,33 @@ bool exchange_cash(PlayerType *player_ptr)
 
         change = true;
         const auto item_name = describe_flavor(player_ptr, item_ptr, 0);
-        if (!get_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
+        if (!input_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
             continue;
         }
 
         msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(100000L * item_ptr->number));
         player_ptr->au += 100000L * item_ptr->number;
-        player_ptr->redraw |= (PR_GOLD);
+        rfu.set_flag(MainWindowRedrawingFlag::GOLD);
         vary_item(player_ptr, i, -item_ptr->number);
     }
 
     for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
         const auto item_ptr = &player_ptr->inventory_list[i];
         const auto r_idx_of_item = static_cast<MonsterRaceId>(item_ptr->pval);
-        if ((item_ptr->bi_key != BaseitemKey(ItemKindType::CORPSE, SV_CORPSE)) || (monraces_info[r_idx_of_item].name != monraces_info[w_ptr->today_mon].name)) {
+        if (!item_ptr->is_corpse() || (monraces_info[r_idx_of_item].name != monraces_info[w_ptr->today_mon].name)) {
             continue;
         }
 
         change = true;
         const auto item_name = describe_flavor(player_ptr, item_ptr, 0);
-        if (!get_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
+        if (!input_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
             continue;
         }
 
         constexpr auto mes = _("賞金 %ld$を手に入れた。", "You get %ldgp.");
         msg_format(mes, (long int)((monraces_info[w_ptr->today_mon].level * 50 + 100) * item_ptr->number));
         player_ptr->au += (monraces_info[w_ptr->today_mon].level * 50 + 100) * item_ptr->number;
-        player_ptr->redraw |= (PR_GOLD);
+        rfu.set_flag(MainWindowRedrawingFlag::GOLD);
         vary_item(player_ptr, i, -item_ptr->number);
     }
 
@@ -134,14 +136,14 @@ bool exchange_cash(PlayerType *player_ptr)
 
         change = true;
         const auto item_name = describe_flavor(player_ptr, item_ptr, 0);
-        if (!get_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
+        if (!input_check(format(_("%s を換金しますか?", "Convert %s into money? "), item_name.data()))) {
             continue;
         }
 
         constexpr auto mes = _("賞金 %ld$を手に入れた。", "You get %ldgp.");
         msg_format(mes, (long int)((monraces_info[w_ptr->today_mon].level * 30 + 60) * item_ptr->number));
         player_ptr->au += (monraces_info[w_ptr->today_mon].level * 30 + 60) * item_ptr->number;
-        player_ptr->redraw |= (PR_GOLD);
+        rfu.set_flag(MainWindowRedrawingFlag::GOLD);
         vary_item(player_ptr, i, -item_ptr->number);
     }
 
@@ -157,11 +159,11 @@ bool exchange_cash(PlayerType *player_ptr)
                 continue;
             }
 
-            INVENTORY_IDX item_new;
+            INVENTORY_IDX inventory_new;
             ItemEntity forge;
 
             const auto item_name = describe_flavor(player_ptr, item_ptr, 0);
-            if (!get_check(format(_("%sを渡しますか?", "Hand %s over? "), item_name.data()))) {
+            if (!input_check(format(_("%sを渡しますか?", "Hand %s over? "), item_name.data()))) {
                 continue;
             }
 
@@ -178,18 +180,18 @@ bool exchange_cash(PlayerType *player_ptr)
             ItemMagicApplier(player_ptr, &forge, player_ptr->current_floor_ptr->object_level, AM_NO_FIXED_ART).execute();
 
             object_aware(player_ptr, &forge);
-            object_known(&forge);
+            forge.mark_as_known();
 
             /*
              * Hand it --- Assume there is an empty slot.
              * Since a corpse is handed at first,
              * there is at least one empty slot.
              */
-            item_new = store_item_to_inventory(player_ptr, &forge);
+            inventory_new = store_item_to_inventory(player_ptr, &forge);
             const auto got_item_name = describe_flavor(player_ptr, &forge, 0);
-            msg_format(_("%s(%c)を貰った。", "You get %s (%c). "), got_item_name.data(), index_to_label(item_new));
+            msg_format(_("%s(%c)を貰った。", "You get %s (%c). "), got_item_name.data(), index_to_label(inventory_new));
 
-            autopick_alter_item(player_ptr, item_new, false);
+            autopick_alter_item(player_ptr, inventory_new, false);
             handle_stuff(player_ptr);
             change = true;
         }
@@ -287,18 +289,18 @@ void determine_daily_bounty(PlayerType *player_ptr, bool conv_old)
     get_mon_num_prep_bounty(player_ptr);
 
     while (true) {
-        w_ptr->today_mon = get_mon_num(player_ptr, std::min(max_dl / 2, 40), max_dl, GMN_ARENA);
+        w_ptr->today_mon = get_mon_num(player_ptr, std::min(max_dl / 2, 40), max_dl, PM_ARENA);
         MonsterRaceInfo *r_ptr;
         r_ptr = &monraces_info[w_ptr->today_mon];
 
         if (cheat_hear) {
-            msg_format("日替わり候補: %s ", r_ptr->name.data());
+            msg_format(_("日替わり候補: %s ", "Today's candidate: %s "), r_ptr->name.data());
         }
 
         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
             continue;
         }
-        if (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL) || any_bits(r_ptr->flags7, RF7_UNIQUE2)) {
+        if (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL) || r_ptr->population_flags.has(MonsterPopulationType::ONLY_ONE)) {
             continue;
         }
         if (r_ptr->flags2 & RF2_MULTIPLY) {
@@ -323,20 +325,20 @@ void determine_daily_bounty(PlayerType *player_ptr, bool conv_old)
 void determine_bounty_uniques(PlayerType *player_ptr)
 {
     get_mon_num_prep_bounty(player_ptr);
-
-    auto is_suitable_for_bounty = [](MonsterRaceId r_idx) {
-        const auto &r_ref = monraces_info[r_idx];
-        bool is_suitable = r_ref.kind_flags.has(MonsterKindType::UNIQUE);
-        is_suitable &= r_ref.drop_flags.has_any_of({ MonsterDropType::DROP_CORPSE, MonsterDropType::DROP_SKELETON });
-        is_suitable &= r_ref.rarity <= 100;
-        is_suitable &= !no_questor_or_bounty_uniques(r_idx);
+    const auto &monraces = MonraceList::get_instance();
+    auto is_suitable_for_bounty = [&monraces](MonsterRaceId r_idx) {
+        const auto &monrace = monraces[r_idx];
+        auto is_suitable = monrace.kind_flags.has(MonsterKindType::UNIQUE);
+        is_suitable &= monrace.drop_flags.has_any_of({ MonsterDropType::DROP_CORPSE, MonsterDropType::DROP_SKELETON });
+        is_suitable &= monrace.rarity <= 100;
+        is_suitable &= !monraces.can_unify_separate(r_idx);
         return is_suitable;
     };
 
     // 賞金首とするモンスターの種族IDのリストを生成
     std::vector<MonsterRaceId> bounty_r_idx_list;
     while (bounty_r_idx_list.size() < std::size(w_ptr->bounties)) {
-        auto r_idx = get_mon_num(player_ptr, 0, MAX_DEPTH - 1, GMN_ARENA);
+        auto r_idx = get_mon_num(player_ptr, 0, MAX_DEPTH - 1, PM_ARENA);
         if (!is_suitable_for_bounty(r_idx)) {
             continue;
         }
index 64176f1..757bca7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 588ad7d..484eff3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Buildings actions
@@ -8,10 +8,10 @@ enum ba_actions {
     BACT_RESEARCH_ITEM = 1,
     BACT_TOWN_HISTORY = 2,
     BACT_RACE_LEGENDS = 3,
-    BACT_GREET_KING = 4,
+    BACT_XXX_UNUSED_4 = 4,
     BACT_KING_LEGENDS = 5,
     BACT_QUEST = 6,
-    BACT_XXX_UNUSED = 7,
+    BACT_XXX_UNUSED_7 = 7,
     BACT_POSTER = 8,
     BACT_ARENA_RULES = 9,
     BACT_ARENA = 10,
index c3f2b22..fda3090 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/building-craft-armor.h"
+#include "market/building-craft-armor.h"
 #include "io/input-key-acceptor.h"
 #include "market/building-util.h"
 #include "term/screen-processor.h"
@@ -9,20 +9,20 @@
  * @details
  * Calculate and display the dodge-rate and the protection-rate
  * based on AC
- * @param iAC プレイヤーのAC。
+ * @param ac プレイヤーのAC。
  * @return 常にTRUEを返す。
  */
-bool eval_ac(ARMOUR_CLASS iAC)
+bool eval_ac(short ac)
 {
-    const GAME_TEXT memo[] = _("ダメージ軽減率とは、敵の攻撃が当たった時そのダメージを\n"
-                               "何パーセント軽減するかを示します。\n"
-                               "ダメージ軽減は通常の直接攻撃(種類が「攻撃する」と「粉砕する」の物)\n"
-                               "に対してのみ効果があります。\n \n"
-                               "敵のレベルとは、その敵が通常何階に現れるかを示します。\n \n"
-                               "回避率は敵の直接攻撃を何パーセントの確率で避けるかを示し、\n"
-                               "敵のレベルとあなたのACによって決定されます。\n \n"
-                               "ダメージ期待値とは、敵の100ポイントの通常攻撃に対し、\n"
-                               "回避率とダメージ軽減率を考慮したダメージの期待値を示します。\n",
+    constexpr auto memo = _("ダメージ軽減率とは、敵の攻撃が当たった時そのダメージを\n"
+                            "何パーセント軽減するかを示します。\n"
+                            "ダメージ軽減は通常の直接攻撃(種類が「攻撃する」と「粉砕する」の物)\n"
+                            "に対してのみ効果があります。\n \n"
+                            "敵のレベルとは、その敵が通常何階に現れるかを示します。\n \n"
+                            "回避率は敵の直接攻撃を何パーセントの確率で避けるかを示し、\n"
+                            "敵のレベルとあなたのACによって決定されます。\n \n"
+                            "ダメージ期待値とは、敵の100ポイントの通常攻撃に対し、\n"
+                            "回避率とダメージ軽減率を考慮したダメージの期待値を示します。\n",
         "'Protection Rate' means how much damage is reduced by your armor.\n"
         "Note that the Protection rate is effective only against normal "
         "'attack' and 'shatter' type melee attacks, "
@@ -33,19 +33,16 @@ bool eval_ac(ARMOUR_CLASS iAC)
         "'Average Damage' indicates the expected amount of damage "
         "when you are attacked by normal melee attacks with power=100.");
 
-    int protection;
-    TERM_LEN col, row = 2;
-    DEPTH lvl;
-
-    if (iAC < 0) {
-        iAC = 0;
+    if (ac < 0) {
+        ac = 0;
     }
 
-    protection = 100 * std::min<short>(iAC, 150) / 250;
+    const auto protection = 100 * std::min<short>(ac, 150) / 250;
     screen_save();
     clear_bldg(0, 22);
 
-    put_str(format(_("あなたの現在のAC: %3d", "Your current AC : %3d"), iAC), row++, 0);
+    auto row = 2;
+    put_str(format(_("あなたの現在のAC: %3d", "Your current AC : %3d"), ac), row++, 0);
     put_str(format(_("ダメージ軽減率  : %3d%%", "Protection rate : %3d%%"), protection), row++, 0);
     row++;
 
@@ -53,19 +50,16 @@ bool eval_ac(ARMOUR_CLASS iAC)
     put_str(_("回避率          :", "Dodge Rate      :"), row + 1, 0);
     put_str(_("ダメージ期待値  :", "Average Damage  :"), row + 2, 0);
 
-    for (col = 17 + 1, lvl = 0; lvl <= 100; lvl += 10, col += 5) {
-        int quality = 60 + lvl * 3; /* attack quality with power 60 */
-        int dodge; /* 回避率(%) */
-        int average; /* ダメージ期待値 */
-
+    for (auto col = 17 + 1, lvl = 0; lvl <= 100; lvl += 10, col += 5) {
+        auto quality = 60 + lvl * 3; /* attack quality with power 60 */
         put_str(format("%3d", lvl), row + 0, col);
 
         /* 回避率を計算 */
-        dodge = 5 + (std::min(100, 100 * (iAC * 3 / 4) / quality) * 9 + 5) / 10;
+        auto dodge = 5 + (std::min(100, 100 * (ac * 3 / 4) / quality) * 9 + 5) / 10;
         put_str(format("%3d%%", dodge), row + 1, col);
 
         /* 100点の攻撃に対してのダメージ期待値を計算 */
-        average = (100 - dodge) * (100 - protection) / 100;
+        auto average = (100 - dodge) * (100 - protection) / 100;
         put_str(format("%3d", average), row + 2, col);
     }
 
index 4641048..5505f26 100644 (file)
@@ -1,5 +1,3 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
-
-bool eval_ac(ARMOUR_CLASS iAC);
+bool eval_ac(short ac);
index 3951639..7b78a15 100644 (file)
@@ -1,9 +1,7 @@
-#include "market/building-craft-fix.h"
-#include "artifact/artifact-info.h"
+#include "market/building-craft-fix.h"
 #include "artifact/fixed-art-types.h"
 #include "artifact/random-art-effects.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -16,7 +14,6 @@
 #include "object-hook/hook-weapon.h"
 #include "object/item-tester-hooker.h"
 #include "object/item-use-flags.h"
-#include "object/object-flags.h"
 #include "object/object-kind-hook.h"
 #include "object/object-value.h"
 #include "racial/racial-android.h"
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include <utility>
+#include <vector>
 
 /*!
  * @brief 修復材料のオブジェクトから修復対象に特性を移植する。
  */
 static void give_one_ability_of_object(ItemEntity *to_ptr, ItemEntity *from_ptr)
 {
-    auto to_flags = object_flags(to_ptr);
-    auto from_flags = object_flags(from_ptr);
+    const auto to_flags = to_ptr->get_flags();
+    const auto from_flags = from_ptr->get_flags();
 
-    int n = 0;
-    tr_type cand[TR_FLAG_MAX];
+    std::vector<tr_type> candidates;
     for (int i = 0; i < TR_FLAG_MAX; i++) {
         switch (i) {
         case TR_IGNORE_ACID:
@@ -64,17 +62,17 @@ static void give_one_ability_of_object(ItemEntity *to_ptr, ItemEntity *from_ptr)
             auto tr_flag = i2enum<tr_type>(i);
             if (from_flags.has(tr_flag) && to_flags.has_not(tr_flag)) {
                 if (!(TR_PVAL_FLAG_MASK.has(tr_flag) && (from_ptr->pval < 1))) {
-                    cand[n++] = tr_flag;
+                    candidates.push_back(tr_flag);
                 }
             }
         }
     }
 
-    if (n <= 0) {
+    if (candidates.empty()) {
         return;
     }
 
-    auto tr_idx = cand[randint0(n)];
+    const auto tr_idx = rand_choice(candidates);
     to_ptr->art_flags.set(tr_idx);
     if (TR_PVAL_FLAG_MASK.has(tr_idx)) {
         to_ptr->pval = std::max<short>(to_ptr->pval, 1);
@@ -88,28 +86,29 @@ static void give_one_ability_of_object(ItemEntity *to_ptr, ItemEntity *from_ptr)
     }
 }
 
-static std::pair<bool, ItemEntity *> select_repairing_broken_weapon(PlayerType *player_ptr, const int row, short *item)
+static std::pair<short, ItemEntity *> select_repairing_broken_weapon(PlayerType *player_ptr, const int row)
 {
     prt(_("修復には材料となるもう1つの武器が必要です。", "Hand one material weapon to repair a broken weapon."), row, 2);
     prt(_("材料に使用した武器はなくなります!", "The material weapon will disappear after repairing!!"), row + 1, 2);
     constexpr auto q = _("どの折れた武器を修復しますか?", "Repair which broken weapon? ");
     constexpr auto s = _("修復できる折れた武器がありません。", "You have no broken weapon to repair.");
-    auto *o_ptr = choose_object(player_ptr, item, q, s, (USE_INVEN | USE_EQUIP), FuncItemTester(&ItemEntity::is_broken_weapon));
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_EQUIP), FuncItemTester(&ItemEntity::is_broken_weapon));
     if (o_ptr == nullptr) {
-        return { false, nullptr };
+        return { i_idx, nullptr };
     }
 
     if (!o_ptr->is_ego() && !o_ptr->is_fixed_or_random_artifact()) {
         msg_format(_("それは直してもしょうがないぜ。", "It is worthless to repair."));
-        return { false, o_ptr };
+        return { i_idx, o_ptr };
     }
 
     if (o_ptr->number > 1) {
         msg_format(_("一度に複数を修復することはできません!", "They are too many to repair at once!"));
-        return { false, o_ptr };
+        return { i_idx, o_ptr };
     }
 
-    return { true, o_ptr };
+    return { i_idx, o_ptr };
 }
 
 static void display_reparing_weapon(PlayerType *player_ptr, ItemEntity *o_ptr, const int row)
@@ -139,22 +138,21 @@ static PRICE repair_broken_weapon_aux(PlayerType *player_ptr, PRICE bcost)
 {
     clear_bldg(0, 22);
     auto row = 7;
-    short item;
-    const auto &[selection, o_ptr] = select_repairing_broken_weapon(player_ptr, row, &item);
-    if (!selection) {
+    const auto &[i_idx, o_ptr] = select_repairing_broken_weapon(player_ptr, row);
+    if (o_ptr == nullptr) {
         return 0;
     }
 
     display_reparing_weapon(player_ptr, o_ptr, row);
-    const auto q = _("材料となる武器は?", "Which weapon for material? ");
-    const auto s = _("材料となる武器がありません。", "You have no material for the repair.");
+    constexpr auto q = _("材料となる武器は?", "Which weapon for material? ");
+    constexpr auto s = _("材料となる武器がありません。", "You have no material for the repair.");
     short mater;
     auto *mo_ptr = choose_object(player_ptr, &mater, q, s, (USE_INVEN | USE_EQUIP), FuncItemTester(&ItemEntity::is_orthodox_melee_weapons));
     if (!mo_ptr) {
         return 0;
     }
 
-    if (mater == item) {
+    if (mater == i_idx) {
         msg_print(_("クラインの壷じゃない!", "This is not a Klein bottle!"));
         return 0;
     }
@@ -162,7 +160,7 @@ static PRICE repair_broken_weapon_aux(PlayerType *player_ptr, PRICE bcost)
     const auto item_name = describe_flavor(player_ptr, mo_ptr, OD_NAME_ONLY);
     prt(format(_("材料とする武器: %s", "Material : %s"), item_name.data()), row + 4, 2);
     const auto cost = bcost + object_value_real(o_ptr) * 2;
-    if (!get_check(format(_("$%dかかりますがよろしいですか? ", "Costs %d gold, okay? "), cost))) {
+    if (!input_check(format(_("$%dかかりますがよろしいですか? ", "Costs %d gold, okay? "), cost))) {
         return 0;
     }
 
@@ -281,7 +279,7 @@ static PRICE repair_broken_weapon_aux(PlayerType *player_ptr, PRICE bcost)
         }
 
         give_one_ability_of_object(o_ptr, mo_ptr);
-        if (activation_index(o_ptr) == RandomArtActType::NONE) {
+        if (!o_ptr->has_activation()) {
             one_activation(o_ptr);
         }
 
@@ -301,7 +299,7 @@ static PRICE repair_broken_weapon_aux(PlayerType *player_ptr, PRICE bcost)
     inven_item_increase(player_ptr, mater, -1);
     inven_item_optimize(player_ptr, mater);
 
-    player_ptr->update |= PU_BONUS;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return cost;
 }
index 2b22b2f..b4a88f1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 2235da3..3db937b 100644 (file)
@@ -1,8 +1,7 @@
-#include "market/building-craft-weapon.h"
+#include "market/building-craft-weapon.h"
 #include "artifact/fixed-art-types.h"
 #include "combat/attack-accuracy.h"
 #include "combat/shoot.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "object-hook/hook-weapon.h"
 #include "object/item-tester-hooker.h"
 #include "object/item-use-flags.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "realm/realm-hex-numbers.h"
 #include "spell-realm/spells-hex.h"
 #include "sv-definition/sv-weapon-types.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "term/z-form.h"
@@ -133,7 +132,7 @@ static void compare_weapon_aux(PlayerType *player_ptr, ItemEntity *o_ptr, int co
     int vorpal_div = 1;
     int dmg_bonus = o_ptr->to_d + player_ptr->to_d[0];
 
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
     if (o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) {
         dokubari = true;
     }
@@ -314,7 +313,7 @@ static void list_weapon(PlayerType *player_ptr, ItemEntity *o_ptr, TERM_LEN row,
     const auto eff_ds = o_ptr->ds + player_ptr->to_ds[0];
     const auto hit_reliability = player_ptr->skill_thn + (player_ptr->to_h[0] + o_ptr->to_h) * BTH_PLUS_ADJ;
     const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
-    c_put_str(TERM_YELLOW, item_name.data(), row, col);
+    c_put_str(TERM_YELLOW, item_name, row, col);
     put_str(format(_("攻撃回数: %d", "Number of Blows: %d"), player_ptr->num_blow[0]), row + 1, col);
 
     put_str(_("命中率:  0  50 100 150 200 (敵のAC)", "To Hit:  0  50 100 150 200 (AC)"), row + 2, col);
@@ -349,9 +348,8 @@ static void list_weapon(PlayerType *player_ptr, ItemEntity *o_ptr, TERM_LEN row,
  */
 PRICE compare_weapons(PlayerType *player_ptr, PRICE bcost)
 {
-    ItemEntity *o_ptr[2];
+    ItemEntity *o_ptr[2]{};
     ItemEntity orig_weapon;
-    ItemEntity *i_ptr;
     TERM_LEN row = 2;
     TERM_LEN wid = 38, mgn = 2;
     bool old_character_xtra = w_ptr->character_xtra;
@@ -361,14 +359,15 @@ PRICE compare_weapons(PlayerType *player_ptr, PRICE bcost)
 
     screen_save();
     clear_bldg(0, 22);
-    i_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND];
+    auto *i_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND];
     (&orig_weapon)->copy_from(i_ptr);
 
-    concptr q = _("第一の武器は?", "What is your first weapon? ");
-    concptr s = _("比べるものがありません。", "You have nothing to compare.");
+    constexpr auto first_q = _("第一の武器は?", "What is your first weapon? ");
+    constexpr auto first_s = _("比べるものがありません。", "You have nothing to compare.");
 
-    OBJECT_IDX item;
-    o_ptr[0] = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | IGNORE_BOTHHAND_SLOT), FuncItemTester(&ItemEntity::is_orthodox_melee_weapons));
+    short i_idx_first;
+    constexpr auto options = USE_EQUIP | USE_INVEN | IGNORE_BOTHHAND_SLOT;
+    o_ptr[0] = choose_object(player_ptr, &i_idx_first, first_q, first_s, options, FuncItemTester(&ItemEntity::is_orthodox_melee_weapons));
     if (!o_ptr[0]) {
         screen_load();
         return 0;
@@ -376,7 +375,7 @@ PRICE compare_weapons(PlayerType *player_ptr, PRICE bcost)
 
     int n = 1;
     total = bcost;
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     while (true) {
         clear_bldg(0, 22);
         w_ptr->character_xtra = true;
@@ -386,7 +385,7 @@ PRICE compare_weapons(PlayerType *player_ptr, PRICE bcost)
                 i_ptr->copy_from(o_ptr[i]);
             }
 
-            player_ptr->update |= PU_BONUS;
+            rfu.set_flag(StatusRecalculatingFlag::BONUS);
             handle_stuff(player_ptr);
 
             list_weapon(player_ptr, o_ptr[i], row, col);
@@ -394,7 +393,7 @@ PRICE compare_weapons(PlayerType *player_ptr, PRICE bcost)
             i_ptr->copy_from(&orig_weapon);
         }
 
-        player_ptr->update |= PU_BONUS;
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
         handle_stuff(player_ptr);
 
         w_ptr->character_xtra = old_character_xtra;
@@ -420,10 +419,10 @@ PRICE compare_weapons(PlayerType *player_ptr, PRICE bcost)
             continue;
         }
 
-        q = _("第二の武器は?", "What is your second weapon? ");
-        s = _("比べるものがありません。", "You have nothing to compare.");
-        OBJECT_IDX item2;
-        ItemEntity *i2_ptr = choose_object(player_ptr, &item2, q, s, (USE_EQUIP | USE_INVEN | IGNORE_BOTHHAND_SLOT), FuncItemTester(&ItemEntity::is_orthodox_melee_weapons));
+        constexpr auto q = _("第二の武器は?", "What is your second weapon? ");
+        constexpr auto s = _("比べるものがありません。", "You have nothing to compare.");
+        short i_idx_second;
+        auto *i2_ptr = choose_object(player_ptr, &i_idx_second, q, s, (USE_EQUIP | USE_INVEN | IGNORE_BOTHHAND_SLOT), FuncItemTester(&ItemEntity::is_orthodox_melee_weapons));
         if (!i2_ptr) {
             continue;
         }
index 5452dac..50c1057 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e87b04c..4845aea 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/building-enchanter.h"
+#include "market/building-enchanter.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "floor/floor-object.h"
@@ -29,11 +29,11 @@ bool enchant_item(PlayerType *player_ptr, PRICE cost, HIT_PROB to_hit, int to_da
     prt(format(_("現在のあなたの技量だと、+%d まで改良できます。", "  Based on your skill, we can improve up to +%d."), maxenchant), 5, 0);
     prt(format(_(" 改良の料金は一個につき$%d です。", "  The price for the service is %d gold per item."), cost), 7, 0);
 
-    const auto q = _("どのアイテムを改良しますか?", "Improve which item? ");
-    const auto s = _("改良できるものがありません。", "You have nothing to improve.");
+    constexpr auto q = _("どのアイテムを改良しますか?", "Improve which item? ");
+    constexpr auto s = _("改良できるものがありません。", "You have nothing to improve.");
 
-    OBJECT_IDX item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_EQUIP | IGNORE_BOTHHAND_SLOT), item_tester);
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_EQUIP | IGNORE_BOTHHAND_SLOT), item_tester);
     if (!o_ptr) {
         return false;
     }
@@ -47,21 +47,21 @@ bool enchant_item(PlayerType *player_ptr, PRICE cost, HIT_PROB to_hit, int to_da
 
     bool okay = false;
     for (int i = 0; i < to_hit; i++) {
-        if ((o_ptr->to_h < maxenchant) && enchant_equipment(player_ptr, o_ptr, 1, (ENCH_TOHIT | ENCH_FORCE))) {
+        if ((o_ptr->to_h < maxenchant) && enchant_equipment(o_ptr, 1, (ENCH_TOHIT | ENCH_FORCE))) {
             okay = true;
             break;
         }
     }
 
     for (int i = 0; i < to_dam; i++) {
-        if ((o_ptr->to_d < maxenchant) && enchant_equipment(player_ptr, o_ptr, 1, (ENCH_TODAM | ENCH_FORCE))) {
+        if ((o_ptr->to_d < maxenchant) && enchant_equipment(o_ptr, 1, (ENCH_TODAM | ENCH_FORCE))) {
             okay = true;
             break;
         }
     }
 
     for (int i = 0; i < to_ac; i++) {
-        if ((o_ptr->to_a < maxenchant) && enchant_equipment(player_ptr, o_ptr, 1, (ENCH_TOAC | ENCH_FORCE))) {
+        if ((o_ptr->to_a < maxenchant) && enchant_equipment(o_ptr, 1, (ENCH_TOAC | ENCH_FORCE))) {
             okay = true;
             break;
         }
@@ -83,7 +83,7 @@ bool enchant_item(PlayerType *player_ptr, PRICE cost, HIT_PROB to_hit, int to_da
 #endif
 
     player_ptr->au -= total_cost;
-    if (item >= INVEN_MAIN_HAND) {
+    if (i_idx >= INVEN_MAIN_HAND) {
         calc_android_exp(player_ptr);
     }
     return true;
index 43ebbe6..e5d8e00 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index a7c1eff..e20dd17 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/building-initializer.h"
+#include "market/building-initializer.h"
 #include "floor/floor-town.h"
 #include "io/files-util.h"
 #include "object/object-kind-hook.h"
  */
 static int count_town_numbers()
 {
-    char towns_path[1024]{};
-    path_build(towns_path, sizeof(towns_path), ANGBAND_DIR_EDIT, "towns");
+    const auto &path = path_build(ANGBAND_DIR_EDIT, "towns");
     std::set<std::string> unique_towns;
-    for (const auto &entry : std::filesystem::directory_iterator(towns_path)) {
+    for (const auto &entry : std::filesystem::directory_iterator(path)) {
         const auto &filename = entry.path().filename().string();
         if (!filename.ends_with(".txt")) {
             continue;
@@ -49,9 +48,9 @@ void init_towns(void)
     const auto town_numbers = count_town_numbers();
     towns_info = std::vector<town_type>(town_numbers);
     for (auto i = 1; i < town_numbers; i++) {
-        towns_info[i].store = std::vector<store_type>(MAX_STORES);
+        auto &town = towns_info[i];
         for (auto sst : STORE_SALE_TYPE_LIST) {
-            auto *store_ptr = &towns_info[i].store[enum2i(sst)];
+            auto *store_ptr = &town.stores[sst];
             if ((i > 1) && (sst == StoreSaleType::MUSEUM || sst == StoreSaleType::HOME)) {
                 continue;
             }
@@ -81,21 +80,21 @@ void init_towns(void)
  */
 void init_buildings(void)
 {
-    for (auto i = 0; i < MAX_BLDG; i++) {
-        building[i].name[0] = '\0';
-        building[i].owner_name[0] = '\0';
-        building[i].owner_race[0] = '\0';
+    for (auto i = 0; i < MAX_BUILDINGS; i++) {
+        buildings[i].name[0] = '\0';
+        buildings[i].owner_name[0] = '\0';
+        buildings[i].owner_race[0] = '\0';
         for (auto j = 0; j < 8; j++) {
-            building[i].act_names[j][0] = '\0';
-            building[i].member_costs[j] = 0;
-            building[i].other_costs[j] = 0;
-            building[i].letters[j] = 0;
-            building[i].actions[j] = 0;
-            building[i].action_restr[j] = 0;
+            buildings[i].act_names[j][0] = '\0';
+            buildings[i].member_costs[j] = 0;
+            buildings[i].other_costs[j] = 0;
+            buildings[i].letters[j] = 0;
+            buildings[i].actions[j] = 0;
+            buildings[i].action_restr[j] = 0;
         }
 
-        building[i].member_class.assign(PLAYER_CLASS_TYPE_MAX, static_cast<short>(PlayerClassType::WARRIOR));
-        building[i].member_race.assign(MAX_RACES, static_cast<short>(PlayerRaceType::HUMAN));
-        building[i].member_realm.assign(MAX_MAGIC + 1, 0);
+        buildings[i].member_class.assign(PLAYER_CLASS_TYPE_MAX, static_cast<short>(PlayerClassType::WARRIOR));
+        buildings[i].member_race.assign(MAX_RACES, static_cast<short>(PlayerRaceType::HUMAN));
+        buildings[i].member_realm.assign(MAX_MAGIC + 1, 0);
     }
 }
index 80af857..6b14700 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 void init_towns(void);
 void init_buildings(void);
index c8d9476..af7c84e 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/building-monster.h"
+#include "market/building-monster.h"
 #include "core/asking-player.h"
 #include "core/stuff-handler.h"
 #include "game-option/game-play-options.h"
@@ -32,16 +32,11 @@ bool research_mon(PlayerType *player_ptr)
     bool all = false;
     bool uniq = false;
     bool norm = false;
-    char temp[MAX_MONSTER_NAME] = "";
-
     screen_save();
-
-    char sym;
-    if (!get_com(
-            _("モンスターの文字を入力して下さい(記号 or ^A全,^Uユ,^N非ユ,^M名前):", "Enter character to be identified(^A:All,^U:Uniqs,^N:Non uniqs,^M:Name): "),
-            &sym, false))
-
-    {
+    constexpr auto prompt = _("モンスターの文字を入力して下さい(記号 or ^A全,^Uユ,^N非ユ,^M名前):",
+        "Enter character to be identified(^A:All,^U:Uniqs,^N:Non uniqs,^M:Name): ");
+    const auto sym = input_command(prompt, false);
+    if (!sym) {
         screen_load();
         return false;
     }
@@ -53,8 +48,8 @@ bool research_mon(PlayerType *player_ptr)
         }
     }
 
-    /* XTRA HACK WHATSEARCH */
     std::string buf;
+    std::string monster_name("");
     if (sym == KTRL('A')) {
         all = true;
         buf = _("全モンスターのリスト", "Full monster list.");
@@ -66,59 +61,52 @@ bool research_mon(PlayerType *player_ptr)
         buf = _("ユニーク外モンスターのリスト", "Non-unique monster list.");
     } else if (sym == KTRL('M')) {
         all = true;
-        if (!get_string(_("名前(英語の場合小文字で可)", "Enter name:"), temp, 70)) {
-            temp[0] = 0;
+        const auto monster_name_opt = input_string(_("名前(英語の場合小文字で可)", "Enter name:"), MAX_MONSTER_NAME);
+        if (!monster_name_opt) {
             screen_load();
-
             return false;
         }
 
-        buf = format(_("名前:%sにマッチ", "Monsters' names with \"%s\""), temp);
+        monster_name = *monster_name_opt;
+        buf = format(_("名前:%sにマッチ", "Monsters' names with \"%s\""), monster_name.data());
     } else if (ident_info[ident_i]) {
-        buf = format("%c - %s.", sym, ident_info[ident_i] + 2);
+        buf = format("%c - %s.", *sym, ident_info[ident_i] + 2);
     } else {
-        buf = format("%c - %s", sym, _("無効な文字", "Unknown Symbol"));
+        buf = format("%c - %s", *sym, _("無効な文字", "Unknown Symbol"));
     }
 
-    /* Display the result */
     prt(buf, 16, 10);
-
-    /* Allocate the "who" array */
-    std::vector<MonsterRaceId> who;
-
-    /* Collect matching monsters */
-    for (const auto &[r_idx, r_ref] : monraces_info) {
-        /* Empty monster */
-        if (!MonsterRace(r_ref.idx).is_valid() || r_ref.name.empty()) {
+    std::vector<MonsterRaceId> monraces;
+    for (const auto &[monrace_id, monrace] : monraces_info) {
+        if (!MonsterRace(monrace_id).is_valid()) {
             continue;
         }
 
-        /* XTRA HACK WHATSEARCH */
         /* Require non-unique monsters if needed */
-        if (norm && r_ref.kind_flags.has(MonsterKindType::UNIQUE)) {
+        if (norm && monrace.kind_flags.has(MonsterKindType::UNIQUE)) {
             continue;
         }
 
         /* Require unique monsters if needed */
-        if (uniq && r_ref.kind_flags.has_not(MonsterKindType::UNIQUE)) {
+        if (uniq && monrace.kind_flags.has_not(MonsterKindType::UNIQUE)) {
             continue;
         }
 
         /* 名前検索 */
-        if (temp[0]) {
-            for (int xx = 0; temp[xx] && xx < 80; xx++) {
+        if (!monster_name.empty()) {
+            for (size_t xx = 0; (xx < monster_name.length()); xx++) {
 #ifdef JP
-                if (iskanji(temp[xx])) {
+                if (iskanji(monster_name[xx])) {
                     xx++;
                     continue;
                 }
 #endif
-                if (isupper(temp[xx])) {
-                    temp[xx] = (char)tolower(temp[xx]);
+                if (isupper(monster_name[xx])) {
+                    monster_name[xx] = (char)tolower(monster_name[xx]);
                 }
             }
 
-            std::string temp2 = _(r_ref.E_name, r_ref.name);
+            std::string temp2 = _(monrace.E_name, monrace.name);
             for (auto &ch : temp2) {
                 if (isupper(ch)) {
                     ch = static_cast<char>(tolower(ch));
@@ -126,17 +114,17 @@ bool research_mon(PlayerType *player_ptr)
             }
 
 #ifdef JP
-            if (angband_strstr(temp2.data(), temp) || angband_strstr(r_ref.name.data(), temp))
+            if (str_find(temp2, monster_name) || str_find(monrace.name, monster_name))
 #else
-            if (angband_strstr(temp2.data(), temp))
+            if (str_find(temp2, monster_name))
 #endif
-                who.push_back(r_ref.idx);
-        } else if (all || (r_ref.d_char == sym)) {
-            who.push_back(r_ref.idx);
+                monraces.push_back(monrace_id);
+        } else if (all || (monrace.d_char == sym)) {
+            monraces.push_back(monrace_id);
         }
     }
 
-    if (who.empty()) {
+    if (monraces.empty()) {
         screen_load();
 
         return false;
@@ -146,21 +134,21 @@ bool research_mon(PlayerType *player_ptr)
     char query = 'y';
 
     if (why) {
-        ang_sort(player_ptr, who.data(), &why, who.size(), ang_sort_comp_hook, ang_sort_swap_hook);
+        ang_sort(player_ptr, monraces.data(), &why, monraces.size(), ang_sort_comp_hook, ang_sort_swap_hook);
     }
 
     uint i;
     static int old_sym = '\0';
     static uint old_i = 0;
-    if (old_sym == sym && old_i < who.size()) {
+    if (old_sym == sym && old_i < monraces.size()) {
         i = old_i;
     } else {
-        i = who.size() - 1;
+        i = monraces.size() - 1;
     }
 
     notpicked = true;
     while (notpicked) {
-        auto r_idx = who[i];
+        auto r_idx = monraces[i];
         roff_top(r_idx);
         term_addstr(-1, TERM_WHITE, _(" ['r'思い出, ' 'で続行, ESC]", " [(r)ecall, ESC, space to continue]"));
         while (true) {
@@ -170,7 +158,7 @@ bool research_mon(PlayerType *player_ptr)
                 handle_stuff(player_ptr);
                 screen_roff(player_ptr, r_idx, MONSTER_LORE_RESEARCH);
                 notpicked = false;
-                old_sym = sym;
+                old_sym = *sym;
                 old_i = i;
             }
 
@@ -187,7 +175,7 @@ bool research_mon(PlayerType *player_ptr)
         }
 
         if (query == '-') {
-            if (++i == who.size()) {
+            if (++i == monraces.size()) {
                 i = 0;
                 if (!expand_list) {
                     break;
@@ -198,7 +186,7 @@ bool research_mon(PlayerType *player_ptr)
         }
 
         if (i-- == 0) {
-            i = who.size() - 1;
+            i = monraces.size() - 1;
             if (!expand_list) {
                 break;
             }
index 55aac38..9626a47 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool research_mon(PlayerType *player_ptr);
index bda0ca3..6f02fb2 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/building-quest.h"
+#include "market/building-quest.h"
 #include "cmd-building/cmd-building.h"
 #include "core/asking-player.h"
 #include "dungeon/quest.h"
@@ -100,7 +100,7 @@ void castle_quest(PlayerType *player_ptr)
 
         put_str(_("このクエストは放棄することができます。", "You can give up this quest."), 12, 0);
 
-        if (!get_check(_("二度と受けられなくなりますが放棄しますか?", "Are you sure to give up this quest? "))) {
+        if (!input_check(_("二度と受けられなくなりますが放棄しますか?", "Are you sure to give up this quest? "))) {
             return;
         }
 
index 6c090a6..c060dfe 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void castle_quest(PlayerType *player_ptr);
index b268307..4cd9f23 100644 (file)
@@ -1,7 +1,6 @@
-#include "market/building-recharger.h"
+#include "market/building-recharger.h"
 #include "autopick/autopick.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -17,6 +16,7 @@
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "view/display-messages.h"
 
@@ -36,10 +36,10 @@ void building_recharge(PlayerType *player_ptr)
     msg_flag = false;
     clear_bldg(4, 18);
     prt(_("  再充填の費用はアイテムの種類によります。", "  The prices of recharge depend on the type."), 6, 0);
-    const auto q = _("どのアイテムに魔力を充填しますか? ", "Recharge which item? ");
-    const auto s = _("魔力を充填すべきアイテムがない。", "You have nothing to recharge.");
-    OBJECT_IDX item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::can_recharge));
+    constexpr auto q = _("どのアイテムに魔力を充填しますか? ", "Recharge which item? ");
+    constexpr auto s = _("魔力を充填すべきアイテムがない。", "You have nothing to recharge.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::can_recharge));
     if (o_ptr == nullptr) {
         return;
     }
@@ -51,12 +51,12 @@ void building_recharge(PlayerType *player_ptr)
     if (!o_ptr->is_known()) {
         msg_format(_("充填する前に鑑定されている必要があります!", "The item must be identified first!"));
         msg_print(nullptr);
-        if ((player_ptr->au >= 50) && get_check(_("$50で鑑定しますか? ", "Identify for 50 gold? "))) {
+        if ((player_ptr->au >= 50) && input_check(_("$50で鑑定しますか? ", "Identify for 50 gold? "))) {
             player_ptr->au -= 50;
             identify_item(player_ptr, o_ptr);
             const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
             msg_format(_("%s です。", "You have: %s."), item_name.data());
-            autopick_alter_item(player_ptr, item, false);
+            autopick_alter_item(player_ptr, i_idx, false);
             building_prt_gold(player_ptr);
         }
 
@@ -117,9 +117,9 @@ void building_recharge(PlayerType *player_ptr)
 
     if (tval == ItemKindType::ROD) {
 #ifdef JP
-        if (get_check(format("そのロッドを$%d で再充填しますか?", price)))
+        if (input_check(format("そのロッドを$%d で再充填しますか?", price)))
 #else
-        if (get_check(format("Recharge the %s for %d gold? ", ((o_ptr->number > 1) ? "rods" : "rod"), price)))
+        if (input_check(format("Recharge the %s for %d gold? ", ((o_ptr->number > 1) ? "rods" : "rod"), price)))
 #endif
 
         {
@@ -136,7 +136,7 @@ void building_recharge(PlayerType *player_ptr)
         }
 
         const auto mes = _("一回分$%d で何回分充填しますか?", "Add how many charges for %d gold apiece? ");
-        const auto charges = get_quantity(format(mes, price), std::min(player_ptr->au / price, max_charges));
+        const auto charges = input_quantity(std::min(player_ptr->au / price, max_charges), format(mes, price));
         if (charges < 1) {
             return;
         }
@@ -152,8 +152,13 @@ void building_recharge(PlayerType *player_ptr)
 #else
     msg_format("%s^ %s recharged for %d gold.", item_name.data(), ((o_ptr->number > 1) ? "were" : "was"), price);
 #endif
-    player_ptr->update |= (PU_COMBINATION | PU_REORDER);
-    player_ptr->window_flags |= (PW_INVENTORY);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags);
+    rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
     player_ptr->au -= price;
 }
 
@@ -223,7 +228,7 @@ void building_recharge_all(PlayerType *player_ptr)
         return;
     }
 
-    if (!get_check(format(_("すべてのアイテムを $%d で再充填しますか?", "Recharge all items for %d gold? "), total_cost))) {
+    if (!input_check(format(_("すべてのアイテムを $%d で再充填しますか?", "Recharge all items for %d gold? "), total_cost))) {
         return;
     }
 
@@ -264,7 +269,12 @@ void building_recharge_all(PlayerType *player_ptr)
 
     msg_format(_("$%d で再充填しました。", "You pay %d gold."), total_cost);
     msg_print(nullptr);
-    player_ptr->update |= (PU_COMBINATION | PU_REORDER);
-    player_ptr->window_flags |= (PW_INVENTORY);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags);
+    rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
     player_ptr->au -= total_cost;
 }
index 9197c06..d7c4561 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void building_recharge(PlayerType *player_ptr);
index 1577f0b..3a36d5a 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/building-service.h"
+#include "market/building-service.h"
 #include "cmd-building/cmd-building.h"
 #include "player-base/player-class.h"
 #include "realm/realm-names-table.h"
index 7d21803..0e87f93 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct building_type;
 class PlayerType;
index cb383ef..3243ad0 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/building-util.h"
+#include "market/building-util.h"
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
index 34e5756..f6f0d5e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void clear_bldg(int min_row, int max_row);
index 546f21a..d147c8b 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/play-gamble.h"
+#include "market/play-gamble.h"
 #include "avatar/avatar.h"
 #include "core/asking-player.h"
 #include "core/show-file.h"
  * @brief カジノ1プレイごとのメインルーチン / gamble_comm
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param cmd プレイするゲームID
- * @return プレイ成立やルール説明のみ等ならTRUE、賭け金不足で不成立ならFALSE
  */
-bool gamble_comm(PlayerType *player_ptr, int cmd)
+void gamble_comm(PlayerType *player_ptr, int cmd)
 {
-    int i;
-    int roll1, roll2, roll3, choice, odds, win;
-    int32_t wager;
-    int32_t maxbet;
-    int32_t oldgold;
-
-    char out_val[160] = "", again;
-    concptr p;
-
     screen_save();
-
     if (cmd == BACT_GAMBLE_RULES) {
-        (void)show_file(player_ptr, true, _("jgambling.txt", "gambling.txt"), nullptr, 0, 0);
+        (void)show_file(player_ptr, true, _("jgambling.txt", "gambling.txt"), 0, 0);
         screen_load();
-        return true;
+        return;
     }
 
     if (player_ptr->au < 1) {
         msg_print(_("おい!おまえ一文なしじゃないか!こっから出ていけ!", "Hey! You don't have gold - get out of here!"));
         msg_print(nullptr);
         screen_load();
-        return false;
+        return;
     }
 
     clear_bldg(5, 23);
-    maxbet = player_ptr->lev * 200;
+    auto maxbet = player_ptr->lev * 200;
     maxbet = std::min(maxbet, player_ptr->au);
-
-    /*
-     * Use get_string() because we may need more than
-     * the int16_t value returned by get_quantity().
-     */
-    if (!get_string(format(_("賭け金 (1-%ld)?", "Your wager (1-%ld) ? "), (long int)maxbet), out_val, 32)) {
+    constexpr auto prompt = _("賭け金?", "Your wager ?");
+    const auto wager = input_integer(prompt, 1, maxbet, 1);
+    if (!wager) {
         msg_print(nullptr);
         screen_load();
-        return true;
+        return;
     }
 
-    for (p = out_val; *p == ' '; p++) {
-        ;
-    }
-
-    wager = atol(p);
     if (wager > player_ptr->au) {
         msg_print(_("おい!金が足りないじゃないか!出ていけ!", "Hey! You don't have the gold - get out of here!"));
         msg_print(nullptr);
         screen_load();
-        return false;
-    } else if (wager > maxbet) {
-        msg_format(_("%ldゴールドだけ受けよう。残りは取っときな。", "I'll take %ld gold of that. Keep the rest."), (long int)maxbet);
-        wager = maxbet;
-    } else if (wager < 1) {
-        msg_print(_("OK、1ゴールドからはじめよう。", "Ok, we'll start with 1 gold."));
-        wager = 1;
+        return;
     }
-    msg_print(nullptr);
-    win = 0;
-    odds = 0;
-    oldgold = player_ptr->au;
 
-    prt(format(_("ゲーム前の所持金: %9ld", "Gold before game: %9ld"), (long int)oldgold), 20, 2);
-    prt(format(_("現在の掛け金:     %9ld", "Current Wager:    %9ld"), (long int)wager), 21, 2);
-
-    do {
-        player_ptr->au -= wager;
+    msg_print(nullptr);
+    auto win = 0;
+    auto odds = 0;
+    auto oldgold = player_ptr->au;
+    prt(format(_("ゲーム前の所持金: %9d", "Gold before game: %9d"), oldgold), 20, 2);
+    prt(format(_("現在の掛け金:     %9d", "Current Wager:    %9d"), *wager), 21, 2);
+    while (true) {
+        player_ptr->au -= *wager;
         switch (cmd) {
-        case BACT_IN_BETWEEN: /* Game of In-Between */
+        case BACT_IN_BETWEEN: {
             c_put_str(TERM_GREEN, _("イン・ビトイーン", "In Between"), 5, 2);
-
             odds = 4;
             win = 0;
-            roll1 = randint1(10);
-            roll2 = randint1(10);
-            choice = randint1(10);
-
+            auto roll1 = randint1(10);
+            auto roll2 = randint1(10);
+            auto choice = randint1(10);
             prt(format(_("黒ダイス: %d        黒ダイス: %d", "Black die: %d       Black Die: %d"), roll1, roll2), 8, 3);
-
             prt(format(_("赤ダイス: %d", "Red die: %d"), choice), 11, 14);
             if (((choice > roll1) && (choice < roll2)) || ((choice < roll1) && (choice > roll2))) {
                 win = 1;
             }
+
             break;
-        case BACT_CRAPS: /* Game of Craps */
+        }
+        case BACT_CRAPS: {
             c_put_str(TERM_GREEN, _("クラップス", "Craps"), 5, 2);
-
             win = 3;
             odds = 2;
-            roll1 = randint1(6);
-            roll2 = randint1(6);
-            roll3 = roll1 + roll2;
-            choice = roll3;
+            auto roll1 = randint1(6);
+            auto roll2 = randint1(6);
+            auto roll3 = roll1 + roll2;
+            auto choice = roll3;
             prt(format(_("1振りめ: %d %d      Total: %d", "First roll: %d %d    Total: %d"), roll1, roll2, roll3), 7, 5);
             if ((roll3 == 7) || (roll3 == 11)) {
                 win = 1;
-            } else if ((roll3 == 2) || (roll3 == 3) || (roll3 == 12)) {
-                win = 0;
-            } else {
-                do {
-                    msg_print(_("なにかキーを押すともう一回振ります。", "Hit any key to roll again"));
+                break;
+            }
 
-                    msg_print(nullptr);
-                    roll1 = randint1(6);
-                    roll2 = randint1(6);
-                    roll3 = roll1 + roll2;
-                    prt(format(_("出目: %d %d          合計:      %d", "Roll result: %d %d   Total:     %d"), roll1, roll2, roll3), 8, 5);
-                    if (roll3 == choice) {
-                        win = 1;
-                    } else if (roll3 == 7) {
-                        win = 0;
-                    }
-                } while ((win != 1) && (win != 0));
+            if ((roll3 == 2) || (roll3 == 3) || (roll3 == 12)) {
+                win = 0;
+                break;
             }
 
-            break;
+            do {
+                msg_print(_("なにかキーを押すともう一回振ります。", "Hit any key to roll again"));
 
-        case BACT_SPIN_WHEEL: /* Spin the Wheel Game */
+                msg_print(nullptr);
+                roll1 = randint1(6);
+                roll2 = randint1(6);
+                roll3 = roll1 + roll2;
+                prt(format(_("出目: %d %d          合計:      %d", "Roll result: %d %d   Total:     %d"), roll1, roll2, roll3), 8, 5);
+                if (roll3 == choice) {
+                    win = 1;
+                } else if (roll3 == 7) {
+                    win = 0;
+                }
+            } while ((win != 1) && (win != 0));
+            break;
+        }
+        case BACT_SPIN_WHEEL: {
             win = 0;
             odds = 9;
             c_put_str(TERM_GREEN, _("ルーレット", "Wheel"), 5, 2);
-
             prt("0  1  2  3  4  5  6  7  8  9", 7, 5);
             prt("--------------------------------", 8, 3);
-            strcpy(out_val, "");
-            get_string(_("何番? (0-9): ", "Pick a number (0-9): "), out_val, 32);
+            while (true) {
+                const auto choice = input_integer(_("何番?", "Pick a number"), 0, 9);
+                if (!choice) {
+                    continue;
+                }
 
-            for (p = out_val; iswspace(*p); p++) {
-                ;
-            }
-            choice = atol(p);
-            if (choice < 0) {
-                msg_print(_("0番にしとくぜ。", "I'll put you down for 0."));
-                choice = 0;
-            } else if (choice > 9) {
-                msg_print(_("OK、9番にしとくぜ。", "Ok, I'll put you down for 9."));
-                choice = 9;
-            }
-            msg_print(nullptr);
-            roll1 = randint0(10);
-            prt(format(_("ルーレットは回り、止まった。勝者は %d番だ。", "The wheel spins to a stop and the winner is %d"), roll1), 13, 3);
-            prt("", 9, 0);
-            prt("*", 9, (3 * roll1 + 5));
-            if (roll1 == choice) {
-                win = 1;
+                msg_print(nullptr);
+                auto roll1 = randint0(10);
+                prt(format(_("ルーレットは回り、止まった。勝者は %d番だ。", "The wheel spins to a stop and the winner is %d"), roll1), 13, 3);
+                prt("", 9, 0);
+                prt("*", 9, (3 * roll1 + 5));
+                if (roll1 == choice) {
+                    win = 1;
+                }
+
+                break;
             }
-            break;
 
-        case BACT_DICE_SLOTS: /* The Dice Slots */
+            break;
+        }
+        case BACT_DICE_SLOTS: {
             c_put_str(TERM_GREEN, _("ダイス・スロット", "Dice Slots"), 5, 2);
             c_put_str(TERM_YELLOW, _("レモン   レモン            2", "Lemon    Lemon             2"), 6, 37);
             c_put_str(TERM_YELLOW, _("レモン   レモン   レモン   5", "Lemon    Lemon    Lemon    5"), 7, 37);
@@ -179,30 +149,33 @@ bool gamble_comm(PlayerType *player_ptr, int cmd)
             c_put_str(TERM_RED, _("チェリー チェリー チェリー 1000", "Cherry   Cherry   Cherry   1000"), 12, 37);
 
             win = 0;
-            roll1 = randint1(21);
-            for (i = 6; i > 0; i--) {
+            auto roll1 = randint1(21);
+            for (auto i = 6; i > 0; i--) {
                 if ((roll1 - i) < 1) {
                     roll1 = 7 - i;
                     break;
                 }
                 roll1 -= i;
             }
-            roll2 = randint1(21);
-            for (i = 6; i > 0; i--) {
+
+            auto roll2 = randint1(21);
+            for (auto i = 6; i > 0; i--) {
                 if ((roll2 - i) < 1) {
                     roll2 = 7 - i;
                     break;
                 }
                 roll2 -= i;
             }
-            choice = randint1(21);
-            for (i = 6; i > 0; i--) {
+
+            auto choice = randint1(21);
+            for (auto i = 6; i > 0; i--) {
                 if ((choice - i) < 1) {
                     choice = 7 - i;
                     break;
                 }
                 choice -= i;
             }
+
             put_str("/--------------------------\\", 7, 2);
             prt("\\--------------------------/", 17, 2);
             display_fruit(8, 3, roll1 - 1);
@@ -230,47 +203,55 @@ bool gamble_comm(PlayerType *player_ptr, int cmd)
                     odds = 1000;
                     break;
                 }
-            } else if ((roll1 == 1) && (roll2 == 1)) {
+
+                break;
+            }
+
+            if ((roll1 == 1) && (roll2 == 1)) {
                 win = 1;
                 odds = 2;
             }
+
             break;
+        }
         case BACT_POKER:
             win = 0;
             odds = do_poker();
             if (odds) {
                 win = 1;
             }
+
             break;
         }
 
         if (win) {
             prt(_("あなたの勝ち", "YOU WON"), 16, 37);
-
-            player_ptr->au += odds * wager;
-
+            player_ptr->au += odds * *wager;
             prt(format(_("倍率: %d", "Payoff: %d"), odds), 17, 37);
         } else {
             prt(_("あなたの負け", "You Lost"), 16, 37);
             prt("", 17, 37);
         }
 
-        prt(format(_("現在の所持金:     %9ld", "Current Gold:     %9ld"), (long int)player_ptr->au), 22, 2);
+        prt(format(_("現在の所持金:     %9d", "Current Gold:     %9d"), player_ptr->au), 22, 2);
         prt(_("もう一度(Y/N)?", "Again(Y/N)?"), 18, 37);
-
         move_cursor(18, 52);
-        again = inkey();
+        auto again = inkey();
         prt("", 16, 37);
         prt("", 17, 37);
         prt("", 18, 37);
         if (wager > player_ptr->au) {
             msg_print(_("おい!金が足りないじゃないか!ここから出て行け!", "Hey! You don't have the gold - get out of here!"));
             msg_print(nullptr);
-
-            /* Get out here */
             break;
         }
-    } while ((again == 'y') || (again == 'Y'));
+
+        if ((again == 'y') || (again == 'Y')) {
+            continue;
+        }
+
+        break;
+    }
 
     prt("", 18, 37);
     if (player_ptr->au >= oldgold) {
@@ -283,5 +264,4 @@ bool gamble_comm(PlayerType *player_ptr, int cmd)
 
     msg_print(nullptr);
     screen_load();
-    return true;
 }
index 0090cc6..2096399 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
-bool gamble_comm(PlayerType *player_ptr, int cmd);
+void gamble_comm(PlayerType *player_ptr, int cmd);
index baa5580..2fc7f8a 100644 (file)
@@ -1,4 +1,4 @@
-#include "market/poker.h"
+#include "market/poker.h"
 #include "io/input-key-acceptor.h"
 #include "system/angband.h"
 #include "term/screen-processor.h"
index 1c6eb46..5d7d70e 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 int do_poker(void);
index e376a86..e540890 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター同士の打撃後処理 / Melee post-process.
  * @date 2014/01/17
  * @author
@@ -12,7 +12,6 @@
 
 #include "melee/melee-postprocess.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "effect/attribute-types.h"
 #include "floor/cave.h"
 #include "floor/geometry.h"
 #include "player-info/class-info.h"
 #include "player-info/race-types.h"
 #include "player/player-personality-types.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
+#include <string>
 
 // Melee-post-process-type
 struct mam_pp_type {
+    mam_pp_type(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, std::string_view note, MONSTER_IDX who);
     MONSTER_IDX m_idx;
     MonsterEntity *m_ptr;
-    bool seen;
-    GAME_TEXT m_name[160];
     int dam;
-    bool known; /* Can the player be aware of this attack? */
-    concptr note;
     bool *dead;
     bool *fear;
+    std::string note;
     MONSTER_IDX who;
+    bool seen;
+    bool known; /* Can the player be aware of this attack? */
+    std::string m_name;
 };
 
-mam_pp_type *initialize_mam_pp_type(
-    PlayerType *player_ptr, mam_pp_type *mam_pp_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, concptr note, MONSTER_IDX who)
+mam_pp_type::mam_pp_type(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, std::string_view note, MONSTER_IDX who)
+    : m_idx(m_idx)
+    , m_ptr(&player_ptr->current_floor_ptr->m_list[m_idx])
+    , dam(dam)
+    , dead(dead)
+    , fear(fear)
+    , note(note)
+    , who(who)
 {
-    mam_pp_ptr->m_idx = m_idx;
-    mam_pp_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    mam_pp_ptr->seen = is_seen(player_ptr, mam_pp_ptr->m_ptr);
-    mam_pp_ptr->dam = dam;
-    mam_pp_ptr->known = mam_pp_ptr->m_ptr->cdis <= MAX_PLAYER_SIGHT;
-    mam_pp_ptr->dead = dead;
-    mam_pp_ptr->fear = fear;
-    mam_pp_ptr->note = note;
-    mam_pp_ptr->who = who;
-    return mam_pp_ptr;
+    this->seen = is_seen(player_ptr, this->m_ptr);
+    this->known = this->m_ptr->cdis <= MAX_PLAYER_SIGHT;
+    this->m_name = monster_desc(player_ptr, m_ptr, 0);
 }
 
 static void prepare_redraw(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
@@ -81,12 +83,13 @@ static void prepare_redraw(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
         return;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == mam_pp_ptr->m_idx) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (player_ptr->riding == mam_pp_ptr->m_idx) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 }
 
@@ -102,7 +105,7 @@ static bool process_invulnerability(mam_pp_type *mam_pp_ptr)
     }
 
     if (mam_pp_ptr->seen) {
-        msg_format(_("%s^はダメージを受けない。", "%s^ is unharmed."), mam_pp_ptr->m_name);
+        msg_format(_("%s^はダメージを受けない。", "%s^ is unharmed."), mam_pp_ptr->m_name.data());
     }
 
     return true;
@@ -115,7 +118,7 @@ static bool process_invulnerability(mam_pp_type *mam_pp_ptr)
  */
 static bool process_all_resistances(mam_pp_type *mam_pp_ptr)
 {
-    auto *r_ptr = &monraces_info[mam_pp_ptr->m_ptr->r_idx];
+    auto *r_ptr = &mam_pp_ptr->m_ptr->get_monrace();
     if (r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_ALL)) {
         return false;
     }
@@ -132,7 +135,7 @@ static bool process_all_resistances(mam_pp_type *mam_pp_ptr)
     }
 
     if (mam_pp_ptr->seen) {
-        msg_format(_("%s^はダメージを受けない。", "%s^ is unharmed."), mam_pp_ptr->m_name);
+        msg_format(_("%s^はダメージを受けない。", "%s^ is unharmed."), mam_pp_ptr->m_name.data());
     }
 
     return true;
@@ -152,27 +155,27 @@ static void print_monster_dead_by_monster(PlayerType *player_ptr, mam_pp_type *m
         return;
     }
 
-    angband_strcpy(mam_pp_ptr->m_name, monster_desc(player_ptr, mam_pp_ptr->m_ptr, MD_TRUE_NAME).data(), sizeof(mam_pp_ptr->m_name));
+    mam_pp_ptr->m_name = monster_desc(player_ptr, mam_pp_ptr->m_ptr, MD_TRUE_NAME);
     if (!mam_pp_ptr->seen) {
         player_ptr->current_floor_ptr->monster_noise = true;
         return;
     }
 
-    if (mam_pp_ptr->note) {
-        sound_type kill_sound = monster_living(mam_pp_ptr->m_ptr->r_idx) ? SOUND_KILL : SOUND_N_KILL;
+    if (!mam_pp_ptr->note.empty()) {
+        sound_type kill_sound = mam_pp_ptr->m_ptr->has_living_flag() ? SOUND_KILL : SOUND_N_KILL;
         sound(kill_sound);
-        msg_format(_("%s^%s", "%s^%s"), mam_pp_ptr->m_name, mam_pp_ptr->note);
+        msg_format(_("%s^%s", "%s^%s"), mam_pp_ptr->m_name.data(), mam_pp_ptr->note.data());
         return;
     }
 
-    if (!monster_living(mam_pp_ptr->m_ptr->r_idx)) {
+    if (!mam_pp_ptr->m_ptr->has_living_flag()) {
         sound(SOUND_N_KILL);
-        msg_format(_("%s^は破壊された。", "%s^ is destroyed."), mam_pp_ptr->m_name);
+        msg_format(_("%s^は破壊された。", "%s^ is destroyed."), mam_pp_ptr->m_name.data());
         return;
     }
 
     sound(SOUND_KILL);
-    msg_format(_("%s^は殺された。", "%s^ is killed."), mam_pp_ptr->m_name);
+    msg_format(_("%s^は殺された。", "%s^ is killed."), mam_pp_ptr->m_name.data());
 }
 
 /*!
@@ -183,12 +186,15 @@ static void print_monster_dead_by_monster(PlayerType *player_ptr, mam_pp_type *m
  */
 static bool check_monster_hp(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
 {
-    auto *r_ptr = &monraces_info[mam_pp_ptr->m_ptr->r_idx];
+    const auto &monrace = mam_pp_ptr->m_ptr->get_monrace();
     if (mam_pp_ptr->m_ptr->hp < 0) {
         return false;
     }
 
-    if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(r_ptr->flags1, RF1_QUESTOR) || (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL))) && !player_ptr->phase_out) {
+    auto is_like_unique = monrace.kind_flags.has(MonsterKindType::UNIQUE);
+    is_like_unique |= any_bits(monrace.flags1, RF1_QUESTOR);
+    is_like_unique |= monrace.population_flags.has(MonsterPopulationType::NAZGUL);
+    if (is_like_unique && !AngbandSystem::get_instance().is_phase_out()) {
         mam_pp_ptr->m_ptr->hp = 1;
         return false;
     }
@@ -225,8 +231,8 @@ static void cancel_fear_by_pain(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
  */
 static void make_monster_fear(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
 {
-    auto *r_ptr = &monraces_info[mam_pp_ptr->m_ptr->r_idx];
-    if (mam_pp_ptr->m_ptr->is_fearful() || ((r_ptr->flags3 & RF3_NO_FEAR) == 0)) {
+    auto *r_ptr = &mam_pp_ptr->m_ptr->get_monrace();
+    if (mam_pp_ptr->m_ptr->is_fearful() || (r_ptr->resistance_flags.has_not(MonsterResistanceType::NO_FEAR))) {
         return;
     }
 
@@ -252,13 +258,13 @@ static void fall_off_horse_by_melee(PlayerType *player_ptr, mam_pp_type *mam_pp_
         return;
     }
 
-    angband_strcpy(mam_pp_ptr->m_name, monster_desc(player_ptr, mam_pp_ptr->m_ptr, 0).data(), sizeof(mam_pp_ptr->m_name));
+    mam_pp_ptr->m_name = monster_desc(player_ptr, mam_pp_ptr->m_ptr, 0);
     if (mam_pp_ptr->m_ptr->hp > mam_pp_ptr->m_ptr->maxhp / 3) {
         mam_pp_ptr->dam = (mam_pp_ptr->dam + 1) / 2;
     }
 
     if (process_fall_off_horse(player_ptr, (mam_pp_ptr->dam > 200) ? 200 : mam_pp_ptr->dam, false)) {
-        msg_format(_("%s^に振り落とされた!", "You have been thrown off from %s!"), mam_pp_ptr->m_name);
+        msg_format(_("%s^に振り落とされた!", "You have been thrown off from %s!"), mam_pp_ptr->m_name.data());
     }
 }
 
@@ -273,13 +279,12 @@ static void fall_off_horse_by_melee(PlayerType *player_ptr, mam_pp_type *mam_pp_
  * @param who 打撃を行ったモンスターの参照ID
  * @todo 打撃が当たった時の後処理 (爆発持ちのモンスターを爆発させる等)なので、関数名を変更する必要あり
  */
-void mon_take_hit_mon(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, concptr note, MONSTER_IDX who)
+void mon_take_hit_mon(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, std::string_view note, MONSTER_IDX who)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    mam_pp_type tmp_mam_pp;
-    mam_pp_type *mam_pp_ptr = initialize_mam_pp_type(player_ptr, &tmp_mam_pp, m_idx, dam, dead, fear, note, who);
-    angband_strcpy(mam_pp_ptr->m_name, monster_desc(player_ptr, m_ptr, 0).data(), sizeof(mam_pp_ptr->m_name));
+    mam_pp_type tmp_mam_pp(player_ptr, m_idx, dam, dead, fear, note, who);
+    mam_pp_type *mam_pp_ptr = &tmp_mam_pp;
     prepare_redraw(player_ptr, mam_pp_ptr);
     (void)set_monster_csleep(player_ptr, m_idx, 0);
 
@@ -301,7 +306,7 @@ void mon_take_hit_mon(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *
     make_monster_fear(player_ptr, mam_pp_ptr);
     if ((dam > 0) && !m_ptr->is_pet() && !m_ptr->is_friendly() && (mam_pp_ptr->who != m_idx)) {
         const auto &m_ref = floor_ptr->m_list[who];
-        if (m_ref.is_pet() && !player_bold(player_ptr, m_ptr->target_y, m_ptr->target_x)) {
+        if (m_ref.is_pet() && !player_ptr->is_located_at({ m_ptr->target_y, m_ptr->target_x })) {
             set_target(m_ptr, m_ref.fy, m_ref.fx);
         }
     }
index e58129a..b033b43 100644 (file)
@@ -1,7 +1,8 @@
-#pragma once
+#pragma once
 
 #include "combat/combat-options-type.h"
 #include "system/angband.h"
+#include <string_view>
 
 class PlayerType;
-void mon_take_hit_mon(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, concptr note, MONSTER_IDX who);
+void mon_take_hit_mon(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, std::string_view note, MONSTER_IDX who);
index 768124f..3e575ad 100644 (file)
@@ -1,4 +1,4 @@
-#include "melee/melee-spell-flags-checker.h"
+#include "melee/melee-spell-flags-checker.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "effect/effect-characteristics.h"
 #include "floor/geometry.h"
@@ -12,7 +12,6 @@
 #include "monster-race/race-flags3.h"
 #include "monster-race/race-flags7.h"
 #include "monster-race/race-indice-types.h"
-#include "monster/monster-info.h"
 #include "monster/monster-status.h"
 #include "mspell/mspell-checker.h"
 #include "mspell/mspell-judgement.h"
@@ -20,6 +19,7 @@
 #include "pet/pet-util.h"
 #include "player-base/player-class.h"
 #include "spell-kind/spells-world.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -28,7 +28,6 @@
 #include "system/player-type-definition.h"
 #include "target/projection-path-calculator.h"
 #include "util/bit-flags-calculator.h"
-
 #include <iterator>
 
 static void decide_melee_spell_target(PlayerType *player_ptr, melee_spell_type *ms_ptr)
@@ -46,25 +45,25 @@ static void decide_melee_spell_target(PlayerType *player_ptr, melee_spell_type *
 
 static void decide_indirection_melee_spell(PlayerType *player_ptr, melee_spell_type *ms_ptr)
 {
-    const auto &m_ref = *ms_ptr->m_ptr;
-    if ((ms_ptr->target_idx != 0) || (m_ref.target_y == 0)) {
+    const auto &monster_from = *ms_ptr->m_ptr;
+    if ((ms_ptr->target_idx != 0) || (monster_from.target_y == 0)) {
         return;
     }
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    ms_ptr->target_idx = floor_ptr->grid_array[m_ref.target_y][m_ref.target_x].m_idx;
+    ms_ptr->target_idx = floor_ptr->grid_array[monster_from.target_y][monster_from.target_x].m_idx;
     if (ms_ptr->target_idx == 0) {
         return;
     }
 
     ms_ptr->t_ptr = &floor_ptr->m_list[ms_ptr->target_idx];
-    const auto &t_ref = *ms_ptr->t_ptr;
-    if ((ms_ptr->m_idx == ms_ptr->target_idx) || ((ms_ptr->target_idx != player_ptr->pet_t_m_idx) && !are_enemies(player_ptr, m_ref, t_ref))) {
+    const auto &monster_to = *ms_ptr->t_ptr;
+    if ((ms_ptr->m_idx == ms_ptr->target_idx) || ((ms_ptr->target_idx != player_ptr->pet_t_m_idx) && !monster_from.is_hostile_to_melee(monster_to))) {
         ms_ptr->target_idx = 0;
         return;
     }
 
-    if (projectable(player_ptr, m_ref.fy, m_ref.fx, t_ref.fy, t_ref.fx)) {
+    if (projectable(player_ptr, monster_from.fy, monster_from.fx, monster_to.fy, monster_to.fx)) {
         return;
     }
 
@@ -80,7 +79,7 @@ static bool check_melee_spell_projection(PlayerType *player_ptr, melee_spell_typ
     int start;
     int plus = 1;
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (player_ptr->phase_out) {
+    if (AngbandSystem::get_instance().is_phase_out()) {
         start = randint1(floor_ptr->m_max - 1) + floor_ptr->m_max;
         if (randint0(2)) {
             plus = -1;
@@ -97,11 +96,11 @@ static bool check_melee_spell_projection(PlayerType *player_ptr, melee_spell_typ
 
         ms_ptr->target_idx = dummy;
         ms_ptr->t_ptr = &floor_ptr->m_list[ms_ptr->target_idx];
-        const auto &m_ref = *ms_ptr->m_ptr;
-        const auto &t_ref = *ms_ptr->t_ptr;
-        const auto is_enemies = are_enemies(player_ptr, m_ref, t_ref);
-        const auto is_projectable = projectable(player_ptr, m_ref.fy, m_ref.fx, t_ref.fy, t_ref.fx);
-        if (!t_ref.is_valid() || (ms_ptr->m_idx == ms_ptr->target_idx) || !is_enemies || !is_projectable) {
+        const auto &monster_from = *ms_ptr->m_ptr;
+        const auto &monster_to = *ms_ptr->t_ptr;
+        const auto is_enemies = monster_from.is_hostile_to_melee(monster_to);
+        const auto is_projectable = projectable(player_ptr, monster_from.fy, monster_from.fx, monster_to.fy, monster_to.fx);
+        if (!monster_to.is_valid() || (ms_ptr->m_idx == ms_ptr->target_idx) || !is_enemies || !is_projectable) {
             continue;
         }
 
@@ -117,13 +116,15 @@ static void check_darkness(PlayerType *player_ptr, melee_spell_type *ms_ptr)
         return;
     }
 
-    bool vs_ninja = PlayerClass(player_ptr).equals(PlayerClassType::NINJA) && !ms_ptr->t_ptr->is_hostile();
-    bool can_use_lite_area = vs_ninja && ms_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD) && ms_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::HURT_LITE) && ms_ptr->r_ptr->brightness_flags.has_none_of(dark_mask);
+    const auto vs_ninja = PlayerClass(player_ptr).equals(PlayerClassType::NINJA) && !ms_ptr->t_ptr->is_hostile();
+    auto can_use_lite_area = vs_ninja && ms_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD);
+    can_use_lite_area &= ms_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::HURT_LITE);
+    can_use_lite_area &= ms_ptr->r_ptr->brightness_flags.has_none_of(dark_mask);
     if (ms_ptr->r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) {
         return;
     }
 
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    if (player_ptr->current_floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         ms_ptr->ability_flags.reset(MonsterAbilityType::DARKNESS);
         return;
     }
@@ -142,9 +143,9 @@ static void check_stupid(melee_spell_type *ms_ptr)
     ms_ptr->ability_flags &= RF_ABILITY_NOMAGIC_MASK;
 }
 
-static void check_arena(PlayerType *player_ptr, melee_spell_type *ms_ptr)
+static void check_arena(const FloorType &floor, melee_spell_type *ms_ptr)
 {
-    if (!player_ptr->current_floor_ptr->inside_arena && !player_ptr->phase_out) {
+    if (!floor.inside_arena && !AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -162,12 +163,15 @@ static void check_melee_spell_distance(PlayerType *player_ptr, melee_spell_type
         return;
     }
 
-    POSITION real_y = ms_ptr->y;
-    POSITION real_x = ms_ptr->x;
+    auto real_y = ms_ptr->y;
+    auto real_x = ms_ptr->x;
     get_project_point(player_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, &real_y, &real_x, 0L);
-    if (!projectable(player_ptr, real_y, real_x, player_ptr->y, player_ptr->x) && ms_ptr->ability_flags.has(MonsterAbilityType::BA_LITE) && (distance(real_y, real_x, player_ptr->y, player_ptr->x) <= 4) && los(player_ptr, real_y, real_x, player_ptr->y, player_ptr->x)) {
+    auto should_preserve = !projectable(player_ptr, real_y, real_x, player_ptr->y, player_ptr->x);
+    should_preserve &= ms_ptr->ability_flags.has(MonsterAbilityType::BA_LITE);
+    should_preserve &= distance(real_y, real_x, player_ptr->y, player_ptr->x) <= 4;
+    should_preserve &= los(player_ptr, real_y, real_x, player_ptr->y, player_ptr->x);
+    if (should_preserve) {
         ms_ptr->ability_flags.reset(MonsterAbilityType::BA_LITE);
-
         return;
     }
 
@@ -181,6 +185,17 @@ static void check_melee_spell_distance(PlayerType *player_ptr, melee_spell_type
         return;
     }
 
+    auto ball_when_powerful_rad4 = {
+        MonsterAbilityType::BA_ACID,
+        MonsterAbilityType::BA_ELEC,
+        MonsterAbilityType::BA_FIRE,
+        MonsterAbilityType::BA_COLD
+    };
+    auto *r_ptr = &ms_ptr->m_ptr->get_monrace();
+    if (any_bits(r_ptr->flags2, RF2_POWERFUL)) {
+        ms_ptr->ability_flags.reset(ball_when_powerful_rad4);
+    }
+
     ms_ptr->ability_flags.reset(RF_ABILITY_BIG_BALL_MASK);
 }
 
@@ -331,7 +346,8 @@ static void check_smart(PlayerType *player_ptr, melee_spell_type *ms_ptr)
         ms_ptr->ability_flags &= RF_ABILITY_INT_MASK;
     }
 
-    if (ms_ptr->ability_flags.has(MonsterAbilityType::TELE_LEVEL) && is_teleport_level_ineffective(player_ptr, (ms_ptr->target_idx == player_ptr->riding) ? 0 : ms_ptr->target_idx)) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if (ms_ptr->ability_flags.has(MonsterAbilityType::TELE_LEVEL) && floor.can_teleport_level((ms_ptr->target_idx != player_ptr->riding) ? ms_ptr->target_idx != 0 : false)) {
         ms_ptr->ability_flags.reset(MonsterAbilityType::TELE_LEVEL);
     }
 }
@@ -374,8 +390,8 @@ bool check_melee_spell_set(PlayerType *player_ptr, melee_spell_type *ms_ptr)
 
     check_darkness(player_ptr, ms_ptr);
     check_stupid(ms_ptr);
-    check_arena(player_ptr, ms_ptr);
-    if (player_ptr->phase_out && !one_in_(3)) {
+    check_arena(*player_ptr->current_floor_ptr, ms_ptr);
+    if (AngbandSystem::get_instance().is_phase_out() && !one_in_(3)) {
         ms_ptr->ability_flags.reset(MonsterAbilityType::HEAL);
     }
 
index 42fc274..56e0d44 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct melee_spell_type;
 class PlayerType;
index 8db8993..02fc206 100644 (file)
@@ -1,7 +1,6 @@
-#include "melee/melee-spell-util.h"
+#include "melee/melee-spell-util.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h"
-#include "floor/cave.h"
 #include "floor/geometry.h"
 #include "monster-race/monster-race.h"
 #include "monster/monster-info.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 
-melee_spell_type *initialize_melee_spell_type(PlayerType *player_ptr, melee_spell_type *ms_ptr, MONSTER_IDX m_idx)
+melee_spell_type::melee_spell_type(PlayerType *player_ptr, MONSTER_IDX m_idx)
+    : m_idx(m_idx)
+    , thrown_spell(MonsterAbilityType::MAX)
 {
-    ms_ptr->m_idx = m_idx;
-    ms_ptr->y = 0;
-    ms_ptr->x = 0;
-    ms_ptr->target_idx = 0;
-    ms_ptr->thrown_spell = MonsterAbilityType::MAX;
-    ms_ptr->dam = 0;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    ms_ptr->m_ptr = &floor_ptr->m_list[m_idx];
-    ms_ptr->t_ptr = nullptr;
-    ms_ptr->r_ptr = &monraces_info[ms_ptr->m_ptr->r_idx];
-    ms_ptr->see_m = is_seen(player_ptr, ms_ptr->m_ptr);
-    ms_ptr->maneable = player_has_los_bold(player_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx);
-    ms_ptr->pet = ms_ptr->m_ptr->is_pet();
-    const auto &dungeon = dungeons_info[player_ptr->dungeon_idx];
-    const auto is_in_dungeon = floor_ptr->is_in_dungeon();
-    const auto is_in_random_quest = inside_quest(floor_ptr->quest_number) && !QuestType::is_fixed(floor_ptr->quest_number);
-    ms_ptr->in_no_magic_dungeon = dungeon.flags.has(DungeonFeatureType::NO_MAGIC) && is_in_dungeon && !is_in_random_quest;
-    return ms_ptr;
+    auto &floor = *player_ptr->current_floor_ptr;
+    this->m_ptr = &floor.m_list[m_idx];
+    this->t_ptr = nullptr;
+    this->r_ptr = &this->m_ptr->get_monrace();
+    this->see_m = is_seen(player_ptr, this->m_ptr);
+    this->maneable = floor.has_los({ this->m_ptr->fy, this->m_ptr->fx });
+    this->pet = this->m_ptr->is_pet();
+    const auto &dungeon = floor.get_dungeon_definition();
+    const auto is_in_dungeon = floor.is_in_dungeon();
+    const auto is_in_random_quest = floor.is_in_quest() && !QuestType::is_fixed(floor.quest_number);
+    this->in_no_magic_dungeon = dungeon.flags.has(DungeonFeatureType::NO_MAGIC) && is_in_dungeon && !is_in_random_quest;
 }
index 72452b4..ab17c7b 100644 (file)
@@ -1,26 +1,28 @@
-#pragma once
-
-#include <vector>
+#pragma once
 
 #include "monster-race/race-ability-flags.h"
 #include "system/angband.h"
 #include "util/flag-group.h"
+#include <string>
+#include <vector>
 
 class MonsterRaceInfo;
 class MonsterEntity;
+class PlayerType;
 struct melee_spell_type {
+    melee_spell_type(PlayerType *player_ptr, MONSTER_IDX m_idx);
+
+    POSITION y = 0;
+    POSITION x = 0;
+    MONSTER_IDX target_idx = 0;
+    int dam = 0;
+    std::vector<MonsterAbilityType> spells{};
+    bool can_remember = false;
+    EnumClassFlagGroup<MonsterAbilityType> ability_flags{};
+    std::string m_name = "";
+
     MONSTER_IDX m_idx;
-    POSITION y;
-    POSITION x;
-    MONSTER_IDX target_idx;
     MonsterAbilityType thrown_spell;
-    int dam;
-    std::vector<MonsterAbilityType> spells;
-    GAME_TEXT m_name[160];
-#ifdef JP
-#else
-    char m_poss[160];
-#endif
 
     MonsterEntity *m_ptr;
     MonsterEntity *t_ptr;
@@ -29,9 +31,4 @@ struct melee_spell_type {
     bool maneable;
     bool pet;
     bool in_no_magic_dungeon;
-    bool can_remember;
-    EnumClassFlagGroup<MonsterAbilityType> ability_flags;
 };
-
-class PlayerType;
-melee_spell_type *initialize_melee_spell_type(PlayerType *player_ptr, melee_spell_type *ms_ptr, MONSTER_IDX m_idx);
index f04813f..c314ec3 100644 (file)
@@ -1,6 +1,5 @@
-#include "melee/melee-spell.h"
+#include "melee/melee-spell.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "melee/melee-spell-flags-checker.h"
 #include "melee/melee-spell-util.h"
 #include "monster-race/monster-race.h"
@@ -18,6 +17,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "util/string-processor.h"
@@ -40,7 +40,7 @@ static bool try_melee_spell(PlayerType *player_ptr, melee_spell_type *ms_ptr)
 
     disturb(player_ptr, true, true);
     if (ms_ptr->see_m) {
-        msg_format(_("%s^は呪文を唱えようとしたが失敗した。", "%s^ tries to cast a spell, but fails."), ms_ptr->m_name);
+        msg_format(_("%s^は呪文を唱えようとしたが失敗した。", "%s^ tries to cast a spell, but fails."), ms_ptr->m_name.data());
     }
 
     return true;
@@ -53,7 +53,7 @@ static bool disturb_melee_spell(PlayerType *player_ptr, melee_spell_type *ms_ptr
     }
 
     if (ms_ptr->see_m) {
-        msg_format(_("反魔法バリアが%s^の呪文をかき消した。", "Anti magic barrier cancels the spell which %s^ casts."), ms_ptr->m_name);
+        msg_format(_("反魔法バリアが%s^の呪文をかき消した。", "Anti magic barrier cancels the spell which %s^ casts."), ms_ptr->m_name.data());
     }
 
     return true;
@@ -80,8 +80,7 @@ static void process_special_melee_spell(PlayerType *player_ptr, melee_spell_type
 
     mane_data->mane_list.push_back({ ms_ptr->thrown_spell, ms_ptr->dam });
     mane_data->new_mane = true;
-
-    player_ptr->redraw |= PR_IMITATION;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::IMITATION);
 }
 
 static void process_rememberance(melee_spell_type *ms_ptr)
@@ -97,17 +96,6 @@ static void process_rememberance(melee_spell_type *ms_ptr)
     }
 }
 
-static void describe_melee_spell(PlayerType *player_ptr, melee_spell_type *ms_ptr)
-{
-    /* Get the monster name (or "it") */
-    angband_strcpy(ms_ptr->m_name, monster_desc(player_ptr, ms_ptr->m_ptr, 0x00).data(), sizeof(ms_ptr->m_name));
-#ifdef JP
-#else
-    /* Get the monster possessive ("his"/"her"/"its") */
-    angband_strcpy(ms_ptr->m_poss, monster_desc(player_ptr, ms_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE).data(), sizeof(ms_ptr->m_poss));
-#endif
-}
-
 /*!
  * @brief モンスターが敵モンスターに特殊能力を使う処理のメインルーチン /
  * Monster tries to 'cast a spell' (or breath, etc) at another monster.
@@ -119,14 +107,14 @@ static void describe_melee_spell(PlayerType *player_ptr, melee_spell_type *ms_pt
  */
 bool monst_spell_monst(PlayerType *player_ptr, MONSTER_IDX m_idx)
 {
-    melee_spell_type tmp_ms;
-    melee_spell_type *ms_ptr = initialize_melee_spell_type(player_ptr, &tmp_ms, m_idx);
+    melee_spell_type tmp_ms(player_ptr, m_idx);
+    melee_spell_type *ms_ptr = &tmp_ms;
     if (!check_melee_spell_set(player_ptr, ms_ptr)) {
         return false;
     }
 
-    describe_melee_spell(player_ptr, ms_ptr);
-    ms_ptr->thrown_spell = ms_ptr->spells[randint0(ms_ptr->spells.size())];
+    ms_ptr->m_name = monster_desc(player_ptr, ms_ptr->m_ptr, 0x00);
+    ms_ptr->thrown_spell = rand_choice(ms_ptr->spells);
     if (player_ptr->riding && (m_idx == player_ptr->riding)) {
         disturb(player_ptr, true, true);
     }
index 81304df..48d6edb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 2b6b390..713b7e2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター同士が乱闘を起こした時の攻撃種別をスイッチングする
  * @date 2020/05/30
  * @author Hourier
@@ -6,14 +6,44 @@
 
 #include "melee/melee-switcher.h"
 #include "core/disturbance.h"
+#include "dungeon/quest.h"
 #include "melee/melee-util.h"
 #include "monster-attack/monster-attack-effect.h"
+#include "monster-race/monster-race.h"
+#include "monster-race/race-flags-resistance.h"
+#include "monster-race/race-kind-flags.h"
+#include "monster/monster-info.h"
 #include "monster/monster-status-setter.h"
 #include "spell-kind/earthquake.h"
+#include "spell-kind/spells-polymorph.h"
+#include "spell-kind/spells-teleport.h"
+#include "spell/spells-util.h"
+#include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
+#include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 #include "view/display-messages.h"
 
+/*!
+ * @brief モンスターがカオス属性へ耐性を示すかどうか
+ */
+static bool monster_has_chaos_resist(PlayerType *player_ptr, MonsterEntity *m_ptr)
+{
+    auto r_info = m_ptr->get_monrace();
+    if (r_info.resistance_flags.has(MonsterResistanceType::RESIST_CHAOS)) {
+        if (is_original_ap_and_seen(player_ptr, m_ptr)) {
+            r_info.r_resistance_flags.set(MonsterResistanceType::RESIST_CHAOS);
+        }
+        return true;
+    } else if (r_info.kind_flags.has(MonsterKindType::DEMON) && one_in_(3)) {
+        if (is_original_ap_and_seen(player_ptr, m_ptr)) {
+            r_info.r_kind_flags.set(MonsterKindType::DEMON);
+        }
+        return true;
+    }
+    return false;
+}
+
 void describe_melee_method(PlayerType *player_ptr, mam_type *mam_ptr)
 {
     switch (mam_ptr->method) {
@@ -244,6 +274,45 @@ void decide_monster_attack_effect(PlayerType *player_ptr, mam_type *mam_ptr)
     case RaceBlowEffectType::HUNGRY:
         mam_ptr->pt = AttributeType::HUNGRY;
         break;
+    case RaceBlowEffectType::CHAOS: {
+        const auto has_resist = monster_has_chaos_resist(player_ptr, mam_ptr->t_ptr);
+        if (has_resist) {
+            mam_ptr->damage *= 3;
+            mam_ptr->damage /= randint1(6) + 6;
+        }
+
+        if (randint1(5) < 3) {
+            mam_ptr->pt = AttributeType::HYPODYNAMIA;
+            mam_ptr->attribute = BlowEffectType::HEAL;
+            break;
+        }
+        if (one_in_(250)) {
+            const auto *floor_ptr = player_ptr->current_floor_ptr;
+            if (floor_ptr->is_in_dungeon() && (!floor_ptr->is_in_quest() || !QuestType::is_fixed(floor_ptr->quest_number))) {
+                if (mam_ptr->damage > 23) {
+                    msg_print(_("カオスの力でダンジョンが崩れ始める!", "The dungeon tumbles by the chaotic power!"));
+                    earthquake(player_ptr, mam_ptr->m_ptr->fy, mam_ptr->m_ptr->fx, 8, mam_ptr->m_idx);
+                }
+            }
+        }
+        if (!one_in_(10)) {
+            if (!has_resist) {
+                mam_ptr->pt = AttributeType::CONFUSION;
+            }
+            break;
+        }
+
+        if (!has_resist) {
+            if (one_in_(2)) {
+                msg_format(_(("%s^はどこかへ消えていった!"), ("%s^ disappears!")), mam_ptr->t_name);
+                teleport_away(player_ptr, mam_ptr->t_idx, 50, TELEPORT_PASSIVE);
+            } else {
+                if (polymorph_monster(player_ptr, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx)) {
+                    msg_format(_("%s^は変化した!", "%s^ changes!"), mam_ptr->t_name);
+                }
+            }
+        }
+    } break;
     case RaceBlowEffectType::FLAVOR:
         // フレーバー打撃には何の効果もない。
         mam_ptr->pt = AttributeType::NONE;
index 2c5d59a..4b438ed 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class BlowEffectType {
     NONE = 0,
index 606674b..5e9509a 100644 (file)
@@ -1,4 +1,4 @@
-#include "melee/melee-util.h"
+#include "melee/melee-util.h"
 #include "floor/geometry.h"
 #include "grid/grid.h"
 #include "melee/melee-switcher.h"
@@ -26,8 +26,8 @@ mam_type *initialize_mam_type(PlayerType *player_ptr, mam_type *mam_ptr, MONSTER
     mam_ptr->explode = false;
     mam_ptr->touched = false;
 
-    auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[mam_ptr->t_ptr->r_idx];
+    auto *r_ptr = &mam_ptr->m_ptr->get_monrace();
+    auto *tr_ptr = &mam_ptr->t_ptr->get_monrace();
     mam_ptr->ac = tr_ptr->ac;
     mam_ptr->rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);
     mam_ptr->blinked = false;
index 10aa63f..d385a8c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "monster-attack/monster-attack-effect.h"
index 9238e4c..e638350 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター同士が乱闘する処理
  * @date 2020/05/23
  * @author Hourier
@@ -8,7 +8,6 @@
 #include "combat/attack-accuracy.h"
 #include "combat/hallucination-attacks-table.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 
 static void heal_monster_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
 {
-    if (!monster_living(mam_ptr->t_ptr->r_idx) || (mam_ptr->damage <= 2)) {
+    if (!mam_ptr->t_ptr->has_living_flag() || (mam_ptr->damage <= 2)) {
         return;
     }
 
@@ -51,12 +51,13 @@ static void heal_monster_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
         mam_ptr->m_ptr->hp = mam_ptr->m_ptr->maxhp;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == mam_ptr->m_idx) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (player_ptr->riding == mam_ptr->m_idx) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     if (mam_ptr->see_m && did_heal) {
@@ -66,7 +67,7 @@ static void heal_monster_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
 
 static void process_blow_effect(PlayerType *player_ptr, mam_type *mam_ptr)
 {
-    auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
+    auto *r_ptr = &mam_ptr->m_ptr->get_monrace();
     switch (mam_ptr->attribute) {
     case BlowEffectType::FEAR:
         project(player_ptr, mam_ptr->m_idx, 0, mam_ptr->t_ptr->fy, mam_ptr->t_ptr->fx, mam_ptr->damage,
@@ -86,8 +87,8 @@ static void process_blow_effect(PlayerType *player_ptr, mam_type *mam_ptr)
 
 static void aura_fire_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
 {
-    auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[mam_ptr->t_ptr->r_idx];
+    auto *r_ptr = &mam_ptr->m_ptr->get_monrace();
+    auto *tr_ptr = &mam_ptr->t_ptr->get_monrace();
     if (tr_ptr->aura_flags.has_not(MonsterAuraType::FIRE) || !MonsterRace(mam_ptr->m_ptr->r_idx).is_valid()) {
         return;
     }
@@ -105,19 +106,21 @@ static void aura_fire_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
         tr_ptr->aura_flags.set(MonsterAuraType::FIRE);
     }
 
-    project(player_ptr, mam_ptr->t_idx, 0, mam_ptr->m_ptr->fy, mam_ptr->m_ptr->fx, damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17)), AttributeType::FIRE,
-        PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
+    const auto dam = damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17));
+    constexpr auto flags = PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED;
+    project(player_ptr, mam_ptr->t_idx, 0, mam_ptr->m_ptr->fy, mam_ptr->m_ptr->fx, dam, AttributeType::FIRE, flags);
 }
 
 static void aura_cold_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
 {
-    auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[mam_ptr->t_ptr->r_idx];
-    if (tr_ptr->aura_flags.has_not(MonsterAuraType::COLD) || !MonsterRace(mam_ptr->m_ptr->r_idx).is_valid()) {
+    const auto *m_ptr = mam_ptr->m_ptr;
+    auto *r_ptr = &m_ptr->get_monrace();
+    auto *tr_ptr = &mam_ptr->t_ptr->get_monrace();
+    if (tr_ptr->aura_flags.has_not(MonsterAuraType::COLD) || !MonsterRace(m_ptr->r_idx).is_valid()) {
         return;
     }
 
-    if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_COLD_MASK) && is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr)) {
+    if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_COLD_MASK) && is_original_ap_and_seen(player_ptr, m_ptr)) {
         r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_COLD_MASK);
         return;
     }
@@ -126,23 +129,25 @@ static void aura_cold_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
         msg_format(_("%s^は突然寒くなった!", "%s^ is suddenly very cold!"), mam_ptr->m_name);
     }
 
-    if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr)) {
+    if (m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr)) {
         tr_ptr->aura_flags.set(MonsterAuraType::COLD);
     }
 
-    project(player_ptr, mam_ptr->t_idx, 0, mam_ptr->m_ptr->fy, mam_ptr->m_ptr->fx, damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17)), AttributeType::COLD,
-        PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
+    const auto dam = damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17));
+    constexpr auto flags = PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED;
+    project(player_ptr, mam_ptr->t_idx, 0, m_ptr->fy, m_ptr->fx, dam, AttributeType::COLD, flags);
 }
 
 static void aura_elec_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
 {
-    auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[mam_ptr->t_ptr->r_idx];
-    if (tr_ptr->aura_flags.has_not(MonsterAuraType::ELEC) || !MonsterRace(mam_ptr->m_ptr->r_idx).is_valid()) {
+    const auto *m_ptr = mam_ptr->m_ptr;
+    auto *r_ptr = &m_ptr->get_monrace();
+    auto *tr_ptr = &mam_ptr->t_ptr->get_monrace();
+    if (tr_ptr->aura_flags.has_not(MonsterAuraType::ELEC) || !MonsterRace(m_ptr->r_idx).is_valid()) {
         return;
     }
 
-    if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_ELEC_MASK) && is_original_ap_and_seen(player_ptr, mam_ptr->m_ptr)) {
+    if (r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_ELEC_MASK) && is_original_ap_and_seen(player_ptr, m_ptr)) {
         r_ptr->r_resistance_flags.set(r_ptr->resistance_flags & RFR_EFF_IM_ELEC_MASK);
         return;
     }
@@ -151,12 +156,13 @@ static void aura_elec_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
         msg_format(_("%s^は電撃を食らった!", "%s^ gets zapped!"), mam_ptr->m_name);
     }
 
-    if (mam_ptr->m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr)) {
+    if (m_ptr->ml && is_original_ap_and_seen(player_ptr, mam_ptr->t_ptr)) {
         tr_ptr->aura_flags.set(MonsterAuraType::ELEC);
     }
 
-    project(player_ptr, mam_ptr->t_idx, 0, mam_ptr->m_ptr->fy, mam_ptr->m_ptr->fx, damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17)), AttributeType::ELEC,
-        PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED);
+    const auto dam = damroll(1 + ((tr_ptr->level) / 26), 1 + ((tr_ptr->level) / 17));
+    constexpr auto flags = PROJECT_KILL | PROJECT_STOP | PROJECT_AIMED;
+    project(player_ptr, mam_ptr->t_idx, 0, m_ptr->fy, m_ptr->fx, dam, AttributeType::ELEC, flags);
 }
 
 static bool check_same_monster(PlayerType *player_ptr, mam_type *mam_ptr)
@@ -165,12 +171,12 @@ static bool check_same_monster(PlayerType *player_ptr, mam_type *mam_ptr)
         return false;
     }
 
-    auto *r_ptr = &monraces_info[mam_ptr->m_ptr->r_idx];
+    auto *r_ptr = &mam_ptr->m_ptr->get_monrace();
     if (r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_BLOW)) {
         return false;
     }
 
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
+    if (player_ptr->current_floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::NO_MELEE)) {
         return false;
     }
 
@@ -183,12 +189,13 @@ static void redraw_health_bar(PlayerType *player_ptr, mam_type *mam_ptr)
         return;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == mam_ptr->t_idx) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (player_ptr->riding == mam_ptr->t_idx) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 }
 
@@ -201,14 +208,14 @@ static void describe_silly_melee(mam_type *mam_ptr)
 
 #ifdef JP
     if (mam_ptr->do_silly_attack) {
-        mam_ptr->act = silly_attacks2[randint0(MAX_SILLY_ATTACK)];
+        mam_ptr->act = rand_choice(silly_attacks2);
     }
 
     strnfmt(temp, sizeof(temp), mam_ptr->act, mam_ptr->t_name);
     msg_format("%s^は%s", mam_ptr->m_name, temp);
 #else
     if (mam_ptr->do_silly_attack) {
-        mam_ptr->act = silly_attacks[randint0(MAX_SILLY_ATTACK)];
+        mam_ptr->act = rand_choice(silly_attacks);
         strnfmt(temp, sizeof(temp), "%s %s.", mam_ptr->act, mam_ptr->t_name);
     } else {
         strnfmt(temp, sizeof(temp), mam_ptr->act, mam_ptr->t_name);
@@ -241,7 +248,8 @@ static void process_monster_attack_effect(PlayerType *player_ptr, mam_type *mam_
 
 static void process_melee(PlayerType *player_ptr, mam_type *mam_ptr)
 {
-    if (mam_ptr->effect != RaceBlowEffectType::NONE && !check_hit_from_monster_to_monster(mam_ptr->power, mam_ptr->rlev, mam_ptr->ac, mam_ptr->m_ptr->get_remaining_stun())) {
+    const auto remaining_stun = mam_ptr->m_ptr->get_remaining_stun();
+    if (mam_ptr->effect != RaceBlowEffectType::NONE && !check_hit_from_monster_to_monster(mam_ptr->power, mam_ptr->rlev, mam_ptr->ac, remaining_stun)) {
         describe_monster_missed_monster(player_ptr, mam_ptr);
         return;
     }
@@ -298,14 +306,20 @@ static void explode_monster_by_melee(PlayerType *player_ptr, mam_type *mam_ptr)
 void repeat_melee(PlayerType *player_ptr, mam_type *mam_ptr)
 {
     const auto *m_ptr = mam_ptr->m_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     for (int ap_cnt = 0; ap_cnt < MAX_NUM_BLOWS; ap_cnt++) {
-        mam_ptr->effect = r_ptr->blow[ap_cnt].effect;
-        mam_ptr->method = r_ptr->blow[ap_cnt].method;
-        mam_ptr->d_dice = r_ptr->blow[ap_cnt].d_dice;
-        mam_ptr->d_side = r_ptr->blow[ap_cnt].d_side;
+        mam_ptr->effect = r_ptr->blows[ap_cnt].effect;
+        mam_ptr->method = r_ptr->blows[ap_cnt].method;
+        mam_ptr->d_dice = r_ptr->blows[ap_cnt].d_dice;
+        mam_ptr->d_side = r_ptr->blows[ap_cnt].d_side;
+
+        if (!m_ptr->is_valid()) {
+            break;
+        }
 
-        if (!m_ptr->is_valid() || (mam_ptr->t_ptr->fx != mam_ptr->x_saver) || (mam_ptr->t_ptr->fy != mam_ptr->y_saver) || mam_ptr->method == RaceBlowMethodType::NONE) {
+        const auto x_saver = mam_ptr->t_ptr->fx != mam_ptr->x_saver;
+        const auto y_saver = mam_ptr->t_ptr->fy != mam_ptr->y_saver;
+        if (x_saver || y_saver || mam_ptr->method == RaceBlowMethodType::NONE) {
             break;
         }
 
@@ -344,8 +358,8 @@ bool monst_attack_monst(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t
         return false;
     }
 
-    angband_strcpy(mam_ptr->m_name, monster_desc(player_ptr, mam_ptr->m_ptr, 0).data(), sizeof(mam_ptr->m_name));
-    angband_strcpy(mam_ptr->t_name, monster_desc(player_ptr, mam_ptr->t_ptr, 0).data(), sizeof(mam_ptr->t_name));
+    angband_strcpy(mam_ptr->m_name, monster_desc(player_ptr, mam_ptr->m_ptr, 0), sizeof(mam_ptr->m_name));
+    angband_strcpy(mam_ptr->t_name, monster_desc(player_ptr, mam_ptr->t_ptr, 0), sizeof(mam_ptr->t_name));
     if (!mam_ptr->see_either && mam_ptr->known) {
         player_ptr->current_floor_ptr->monster_noise = true;
     }
index 0c7c20c..f37d4ff 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 83c4b00..a1632f1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Some things which induce learning
index f8b6c41..133d913 100644 (file)
@@ -1,8 +1,7 @@
-#include "mind/mind-archer.h"
+#include "mind/mind-archer.h"
 #include "action/action-limited.h"
 #include "autopick/autopick.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "flavor/flavor-describer.h"
 #include "floor/cave.h"
 #include "floor/floor-object.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/target-getter.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
+#include <string>
 
 enum ammo_creation_type {
     AMMO_NONE = 0,
@@ -51,19 +52,18 @@ static bool select_ammo_creation_type(ammo_creation_type &type, PLAYER_LEVEL ple
         }
     }
 
-    concptr com;
+    std::string prompt;
     if (plev >= 20) {
-        com = _("[S]弾, [A]矢, [B]クロスボウの矢 :", "Create [S]hots, Create [A]rrow or Create [B]olt ?");
+        prompt = _("[S]弾, [A]矢, [B]クロスボウの矢 :", "Create [S]hots, Create [A]rrow or Create [B]olt ?");
     } else if (plev >= 10) {
-        com = _("[S]弾, [A]矢:", "Create [S]hots or Create [A]rrow ?");
+        prompt = _("[S]弾, [A]矢:", "Create [S]hots or Create [A]rrow ?");
     } else {
-        com = _("[S]弾:", "Create [S]hots ?");
+        prompt = _("[S]弾:", "Create [S]hots ?");
     }
 
     while (type == AMMO_NONE) {
-        char ch;
-
-        if (!get_com(com, &ch, true)) {
+        const auto ch = input_command(prompt, true);
+        if (!ch) {
             return false;
         }
 
@@ -106,30 +106,29 @@ bool create_ammo(PlayerType *player_ptr)
 
     switch (ext) {
     case AMMO_SHOT: {
-        DIRECTION dir;
-        if (!get_rep_dir(player_ptr, &dir, false)) {
+        int dir;
+        if (!get_rep_dir(player_ptr, &dir)) {
             return false;
         }
 
-        POSITION y = player_ptr->y + ddy[dir];
-        POSITION x = player_ptr->x + ddx[dir];
-        auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-        if (terrains_info[g_ptr->get_feat_mimic()].flags.has_not(TerrainCharacteristics::CAN_DIG)) {
+        const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+        const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+        if (grid.get_terrain_mimic().flags.has_not(TerrainCharacteristics::CAN_DIG)) {
             msg_print(_("そこには岩石がない。", "You need a pile of rubble."));
             return false;
         }
 
-        if (!g_ptr->cave_has_flag(TerrainCharacteristics::CAN_DIG) || !g_ptr->cave_has_flag(TerrainCharacteristics::HURT_ROCK)) {
+        if (!grid.cave_has_flag(TerrainCharacteristics::CAN_DIG) || !grid.cave_has_flag(TerrainCharacteristics::HURT_ROCK)) {
             msg_print(_("硬すぎて崩せなかった。", "You failed to make ammo."));
             return true;
         }
 
         ItemEntity forge;
         auto *q_ptr = &forge;
-        q_ptr->prep(lookup_baseitem_id({ ItemKindType::SHOT, (OBJECT_SUBTYPE_VALUE)m_bonus(1, player_ptr->lev) + 1 }));
+        q_ptr->prep(lookup_baseitem_id({ ItemKindType::SHOT, m_bonus(1, player_ptr->lev) + 1 }));
         q_ptr->number = (byte)rand_range(15, 30);
         object_aware(player_ptr, q_ptr);
-        object_known(q_ptr);
+        q_ptr->mark_as_known();
         ItemMagicApplier(player_ptr, q_ptr, player_ptr->lev, AM_NO_FIXED_ART).execute();
         q_ptr->discount = 99;
         int16_t slot = store_item_to_inventory(player_ptr, q_ptr);
@@ -139,15 +138,15 @@ bool create_ammo(PlayerType *player_ptr)
             autopick_alter_item(player_ptr, slot, false);
         }
 
-        cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_ROCK);
-        player_ptr->update |= PU_FLOW;
+        cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::HURT_ROCK);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
         return true;
     }
     case AMMO_ARROW: {
-        concptr q = _("どのアイテムから作りますか? ", "Convert which item? ");
-        concptr s = _("材料を持っていない。", "You have no item to convert.");
-        OBJECT_IDX item;
-        auto *q_ptr = choose_object(player_ptr, &item, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::is_convertible));
+        constexpr auto q = _("どのアイテムから作りますか? ", "Convert which item? ");
+        constexpr auto s = _("材料を持っていない。", "You have no item to convert.");
+        short i_idx;
+        auto *q_ptr = choose_object(player_ptr, &i_idx, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::is_convertible));
         if (!q_ptr) {
             return false;
         }
@@ -157,12 +156,12 @@ bool create_ammo(PlayerType *player_ptr)
         q_ptr->prep(lookup_baseitem_id({ ItemKindType::ARROW, static_cast<short>(m_bonus(1, player_ptr->lev) + 1) }));
         q_ptr->number = (byte)rand_range(5, 10);
         object_aware(player_ptr, q_ptr);
-        object_known(q_ptr);
+        q_ptr->mark_as_known();
         ItemMagicApplier(player_ptr, q_ptr, player_ptr->lev, AM_NO_FIXED_ART).execute();
         q_ptr->discount = 99;
         const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
         msg_print(_(format("%sを作った。", item_name.data()), "You make some ammo."));
-        vary_item(player_ptr, item, -1);
+        vary_item(player_ptr, i_idx, -1);
         int16_t slot = store_item_to_inventory(player_ptr, q_ptr);
         if (slot >= 0) {
             autopick_alter_item(player_ptr, slot, false);
@@ -171,10 +170,10 @@ bool create_ammo(PlayerType *player_ptr)
         return true;
     }
     case AMMO_BOLT: {
-        concptr q = _("どのアイテムから作りますか? ", "Convert which item? ");
-        concptr s = _("材料を持っていない。", "You have no item to convert.");
-        OBJECT_IDX item;
-        auto *q_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::is_convertible));
+        constexpr auto q = _("どのアイテムから作りますか? ", "Convert which item? ");
+        constexpr auto s = _("材料を持っていない。", "You have no item to convert.");
+        short i_idx;
+        auto *q_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::is_convertible));
         if (!q_ptr) {
             return false;
         }
@@ -184,12 +183,12 @@ bool create_ammo(PlayerType *player_ptr)
         q_ptr->prep(lookup_baseitem_id({ ItemKindType::BOLT, static_cast<short>(m_bonus(1, player_ptr->lev) + 1) }));
         q_ptr->number = (byte)rand_range(4, 8);
         object_aware(player_ptr, q_ptr);
-        object_known(q_ptr);
+        q_ptr->mark_as_known();
         ItemMagicApplier(player_ptr, q_ptr, player_ptr->lev, AM_NO_FIXED_ART).execute();
         q_ptr->discount = 99;
         const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
         msg_print(_(format("%sを作った。", item_name.data()), "You make some ammo."));
-        vary_item(player_ptr, item, -1);
+        vary_item(player_ptr, i_idx, -1);
         int16_t slot = store_item_to_inventory(player_ptr, q_ptr);
         if (slot >= 0) {
             autopick_alter_item(player_ptr, slot, false);
index a6a1f79..2040c83 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool create_ammo(PlayerType *player_ptr);
index bec510e..3a78390 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/mind-berserker.h"
+#include "mind/mind-berserker.h"
 #include "action/movement-execution.h"
 #include "cmd-action/cmd-attack.h"
 #include "floor/geometry.h"
@@ -36,7 +36,7 @@ bool cast_berserk_spell(PlayerType *player_ptr, MindBerserkerType spell)
             return false;
         }
 
-        if (!get_direction(player_ptr, &dir, false, false) || (dir == 5)) {
+        if (!get_direction(player_ptr, &dir) || (dir == 5)) {
             return false;
         }
 
@@ -62,7 +62,7 @@ bool cast_berserk_spell(PlayerType *player_ptr, MindBerserkerType spell)
         break;
     }
     case MindBerserkerType::SMASH_TRAP: {
-        if (!get_direction(player_ptr, &dir, false, false)) {
+        if (!get_direction(player_ptr, &dir)) {
             return false;
         }
 
index 939ce45..15eb501 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MindBerserkerType : int;
 class PlayerType;
index 462de3f..c79b8ea 100644 (file)
@@ -1,10 +1,9 @@
-#include "mind/mind-blue-mage.h"
+#include "mind/mind-blue-mage.h"
 #include "action/action-limited.h"
 #include "avatar/avatar.h"
 #include "blue-magic/blue-magic-caster.h"
 #include "blue-magic/learnt-power-getter.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/window-redrawer.h"
 #include "game-option/disturbance-options.h"
 #include "game-option/input-options.h"
@@ -19,6 +18,7 @@
 #include "status/bad-status-setter.h"
 #include "status/base-status.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-stun.h"
 #include "timed-effect/timed-effects.h"
@@ -36,11 +36,11 @@ bool do_cmd_cast_learned(PlayerType *player_ptr)
     }
 
     auto selected_spell = get_learned_power(player_ptr);
-    if (!selected_spell.has_value()) {
+    if (!selected_spell) {
         return false;
     }
 
-    const auto &spell = monster_powers.at(selected_spell.value());
+    const auto &spell = monster_powers.at(*selected_spell);
     const auto need_mana = mod_need_mana(player_ptr, spell.smana, 0, REALM_NONE);
     if (need_mana > player_ptr->csp) {
         msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
@@ -48,7 +48,7 @@ bool do_cmd_cast_learned(PlayerType *player_ptr)
             return false;
         }
 
-        if (!get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "))) {
+        if (!input_check(_("それでも挑戦しますか? ", "Attempt it anyway? "))) {
             return false;
         }
     }
@@ -62,12 +62,12 @@ bool do_cmd_cast_learned(PlayerType *player_ptr)
 
         msg_print(_("魔法をうまく唱えられなかった。", "You failed to concentrate hard enough!"));
         sound(SOUND_FAIL);
-        if (RF_ABILITY_SUMMON_MASK.has(selected_spell.value())) {
-            cast_learned_spell(player_ptr, selected_spell.value(), false);
+        if (RF_ABILITY_SUMMON_MASK.has(*selected_spell)) {
+            cast_learned_spell(player_ptr, *selected_spell, false);
         }
     } else {
         sound(SOUND_ZAP);
-        if (!cast_learned_spell(player_ptr, selected_spell.value(), true)) {
+        if (!cast_learned_spell(player_ptr, *selected_spell, true)) {
             return false;
         }
     }
@@ -89,7 +89,12 @@ bool do_cmd_cast_learned(PlayerType *player_ptr)
     }
 
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-    player_ptr->redraw |= PR_MP;
-    player_ptr->window_flags |= PW_PLAYER | PW_SPELL;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags);
     return true;
 }
index f7bd9e0..cfe2362 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <array>
 
index 35a2b9e..8e79a38 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 騎兵のレイシャルパワー処理
  * @date 2020/05/16
  * @author Hourier
@@ -15,6 +15,7 @@
 #include "monster/smart-learn-types.h"
 #include "pet/pet-fall-off.h"
 #include "player/player-skill.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
@@ -38,7 +39,7 @@ bool rodeo(PlayerType *player_ptr)
     }
 
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     const auto m_name = monster_desc(player_ptr, m_ptr, 0);
     msg_format(_("%sに乗った。", "You ride on %s."), m_name.data());
 
@@ -55,7 +56,7 @@ bool rodeo(PlayerType *player_ptr)
         rlev = 60 + (rlev - 60) / 2;
     }
     if ((randint1(player_ptr->skill_exp[PlayerSkillKindType::RIDING] / 120 + player_ptr->lev * 2 / 3) > rlev) && one_in_(2) &&
-        !player_ptr->current_floor_ptr->inside_arena && !player_ptr->phase_out && !(r_ptr->flags7 & (RF7_GUARDIAN)) && !(r_ptr->flags1 & (RF1_QUESTOR)) &&
+        !player_ptr->current_floor_ptr->inside_arena && !AngbandSystem::get_instance().is_phase_out() && !(r_ptr->flags7 & (RF7_GUARDIAN)) && !(r_ptr->flags1 & (RF1_QUESTOR)) &&
         (rlev < player_ptr->lev * 3 / 2 + randint0(player_ptr->lev / 5))) {
         msg_format(_("%sを手なずけた。", "You tame %s."), m_name.data());
         set_pet(player_ptr, m_ptr);
index 638ba66..ca5b2d3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool rodeo(PlayerType *player_ptr);
index de5d70a..e3990af 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/mind-chaos-warrior.h"
+#include "mind/mind-chaos-warrior.h"
 #include "floor/floor-object.h"
 #include "object-enchant/object-boost.h"
 #include "object-enchant/object-ego.h"
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include <span>
 
 void acquire_chaos_weapon(PlayerType *player_ptr)
 {
+    constexpr static auto weapons = {
+        SV_DAGGER,
+        SV_DAGGER,
+        SV_MAIN_GAUCHE,
+        SV_MAIN_GAUCHE,
+        SV_TANTO,
+        SV_RAPIER,
+        SV_RAPIER,
+        SV_SMALL_SWORD,
+        SV_SMALL_SWORD,
+        SV_BASILLARD, // LV10
+        SV_BASILLARD,
+        SV_SHORT_SWORD,
+        SV_SHORT_SWORD,
+        SV_SHORT_SWORD,
+        SV_SABRE,
+        SV_SABRE,
+        SV_CUTLASS,
+        SV_CUTLASS,
+        SV_WAKIZASHI,
+        SV_KHOPESH, // LV20
+        SV_TULWAR,
+        SV_BROAD_SWORD,
+        SV_LONG_SWORD,
+        SV_LONG_SWORD,
+        SV_SCIMITAR,
+        SV_SCIMITAR,
+        SV_NINJATO,
+        SV_KATANA,
+        SV_BASTARD_SWORD,
+        SV_BASTARD_SWORD, // LV30
+        SV_GREAT_SCIMITAR,
+        SV_CLAYMORE,
+        SV_ESPADON,
+        SV_TWO_HANDED_SWORD,
+        SV_FLAMBERGE,
+        SV_NO_DACHI,
+        SV_EXECUTIONERS_SWORD,
+        SV_ZWEIHANDER,
+        SV_HAYABUSA,
+        SV_BLADE_OF_CHAOS, // LV40
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS,
+        SV_BLADE_OF_CHAOS, // LV50
+    };
+
+    std::span<const sv_sword_type> candidates(weapons.begin(), player_ptr->lev);
+    const auto sval = rand_choice(candidates);
+
     ItemEntity forge;
     auto *q_ptr = &forge;
-    auto dummy = ItemKindType::SWORD;
-    OBJECT_SUBTYPE_VALUE dummy2;
-    switch (randint1(player_ptr->lev)) {
-    case 0:
-    case 1:
-        dummy2 = SV_DAGGER;
-        break;
-    case 2:
-    case 3:
-        dummy2 = SV_MAIN_GAUCHE;
-        break;
-    case 4:
-        dummy2 = SV_TANTO;
-        break;
-    case 5:
-    case 6:
-        dummy2 = SV_RAPIER;
-        break;
-    case 7:
-    case 8:
-        dummy2 = SV_SMALL_SWORD;
-        break;
-    case 9:
-    case 10:
-        dummy2 = SV_BASILLARD;
-        break;
-    case 11:
-    case 12:
-    case 13:
-        dummy2 = SV_SHORT_SWORD;
-        break;
-    case 14:
-    case 15:
-        dummy2 = SV_SABRE;
-        break;
-    case 16:
-    case 17:
-        dummy2 = SV_CUTLASS;
-        break;
-    case 18:
-        dummy2 = SV_WAKIZASHI;
-        break;
-    case 19:
-        dummy2 = SV_KHOPESH;
-        break;
-    case 20:
-        dummy2 = SV_TULWAR;
-        break;
-    case 21:
-        dummy2 = SV_BROAD_SWORD;
-        break;
-    case 22:
-    case 23:
-        dummy2 = SV_LONG_SWORD;
-        break;
-    case 24:
-    case 25:
-        dummy2 = SV_SCIMITAR;
-        break;
-    case 26:
-        dummy2 = SV_NINJATO;
-        break;
-    case 27:
-        dummy2 = SV_KATANA;
-        break;
-    case 28:
-    case 29:
-        dummy2 = SV_BASTARD_SWORD;
-        break;
-    case 30:
-        dummy2 = SV_GREAT_SCIMITAR;
-        break;
-    case 31:
-        dummy2 = SV_CLAYMORE;
-        break;
-    case 32:
-        dummy2 = SV_ESPADON;
-        break;
-    case 33:
-        dummy2 = SV_TWO_HANDED_SWORD;
-        break;
-    case 34:
-        dummy2 = SV_FLAMBERGE;
-        break;
-    case 35:
-        dummy2 = SV_NO_DACHI;
-        break;
-    case 36:
-        dummy2 = SV_EXECUTIONERS_SWORD;
-        break;
-    case 37:
-        dummy2 = SV_ZWEIHANDER;
-        break;
-    case 38:
-        dummy2 = SV_HAYABUSA;
-        break;
-    default:
-        dummy2 = SV_BLADE_OF_CHAOS;
-    }
 
-    q_ptr->prep(lookup_baseitem_id({ dummy, dummy2 }));
+    q_ptr->prep(lookup_baseitem_id({ ItemKindType::SWORD, sval }));
     q_ptr->to_h = 3 + randint1(player_ptr->current_floor_ptr->dun_level) % 10;
     q_ptr->to_d = 3 + randint1(player_ptr->current_floor_ptr->dun_level) % 10;
     one_resistance(q_ptr);
index 8053e2f..d787808 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void acquire_chaos_weapon(PlayerType *player_ptr);
index 4e03692..e8388dd 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 元素使いの魔法系統
  */
 
@@ -9,7 +9,6 @@
 #include "cmd-action/cmd-spell.h"
 #include "cmd-io/cmd-gameoption.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "effect/effect-characteristics.h"
@@ -63,6 +62,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/grid-selector.h"
 #include "target/target-getter.h"
 #include "term/screen-processor.h"
@@ -200,7 +200,7 @@ static element_type_list element_types = {
 /*!
  * @brief 元素魔法呪文定義
  */
-static element_power_list element_powers = {
+static const element_power_list element_powers = {
     { ElementSpells::BOLT_1ST,   { 0, {  1,  1,  15, _("%sの矢", "%s Bolt") }}},
     { ElementSpells::MON_DETECT, { 0, {  2,  2,  20, _("モンスター感知", "Detect Monsters") }}},
     { ElementSpells::PERCEPT,    { 0, {  5,  5,  50, _("擬似鑑定", "Psychometry") }}},
@@ -461,7 +461,7 @@ static std::string get_element_effect_info(PlayerType *player_ptr, int spell_idx
 static bool cast_element_spell(PlayerType *player_ptr, SPELL_IDX spell_idx)
 {
     auto spell = i2enum<ElementSpells>(spell_idx);
-    auto power = element_powers.at(spell);
+    auto &power = element_powers.at(spell);
     AttributeType typ;
     DIRECTION dir;
     PLAYER_LEVEL plev = player_ptr->lev;
@@ -576,7 +576,7 @@ static bool cast_element_spell(PlayerType *player_ptr, SPELL_IDX spell_idx)
                 if (!cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
                     continue;
                 }
-                if (!player_bold(player_ptr, y, x)) {
+                if (!player_ptr->is_located_at({ y, x })) {
                     break;
                 }
             }
@@ -684,8 +684,6 @@ static bool get_element_power(PlayerType *player_ptr, SPELL_IDX *sn, bool only_b
     TERM_LEN y = 1;
     TERM_LEN x = 10;
     PLAYER_LEVEL plev = player_ptr->lev;
-    char choice;
-    char out_val[160];
     COMMAND_CODE code;
     bool flag, redraw;
     int menu_line = (use_menu ? 1 : 0);
@@ -708,26 +706,31 @@ static bool get_element_power(PlayerType *player_ptr, SPELL_IDX *sn, bool only_b
         }
     }
 
+    std::string fmt;
     if (only_browse) {
-        (void)strnfmt(out_val, 78, _("(%s^ %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? "), p, I2A(0),
-            I2A(num - 1), p);
+        fmt = _("(%s^ %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? ");
     } else {
-        (void)strnfmt(
-            out_val, 78, _("(%s^ %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? "), p, I2A(0), I2A(num - 1), p);
+        fmt = _("(%s^ %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? ");
     }
 
+    const auto prompt = format(fmt.data(), p, I2A(0), I2A(num - 1), p);
     if (use_menu && !only_browse) {
         screen_save();
     }
 
     int elem;
     mind_type spell;
-    choice = (always_show_list || use_menu) ? ESCAPE : 1;
+    auto choice = (always_show_list || use_menu) ? ESCAPE : 1;
     while (!flag) {
         if (choice == ESCAPE) {
             choice = ' ';
-        } else if (!get_com(out_val, &choice, true)) {
-            break;
+        } else {
+            const auto new_choice = input_command(prompt, true);
+            if (!new_choice) {
+                break;
+            }
+
+            choice = *new_choice;
         }
 
         auto should_redraw_cursor = true;
@@ -762,7 +765,7 @@ static bool get_element_power(PlayerType *player_ptr, SPELL_IDX *sn, bool only_b
             }
         }
 
-        int spell_max = enum2i(ElementSpells::MAX);
+        constexpr auto spell_max = enum2i(ElementSpells::MAX);
         if ((choice == ' ') || (choice == '*') || (choice == '?') || (use_menu && should_redraw_cursor)) {
             if (!redraw || use_menu) {
                 redraw = true;
@@ -796,8 +799,8 @@ static bool get_element_power(PlayerType *player_ptr, SPELL_IDX *sn, bool only_b
                         desc = format("  %c) ", I2A(i));
                     }
 
-                    concptr s = get_element_name(player_ptr->element, elem);
-                    std::string name = format(spell.name, s);
+                    const auto s = get_element_name(player_ptr->element, elem);
+                    const auto name = format(spell.name, s);
                     desc.append(format("%-30s%2d %4d %3d%%%s", name.data(), spell.min_lev, mana_cost, chance, comment.data()));
                     prt(desc, y + i + 1, x);
                 }
@@ -827,7 +830,7 @@ static bool get_element_power(PlayerType *player_ptr, SPELL_IDX *sn, bool only_b
         screen_load();
     }
 
-    set_bits(player_ptr->window_flags, PW_SPELL);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::SPELL);
     handle_stuff(player_ptr);
     if (!flag) {
         return false;
@@ -855,7 +858,7 @@ static bool check_element_mp_sufficiency(PlayerType *player_ptr, int mana_cost)
         return false;
     }
 
-    return get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
+    return input_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
 }
 
 /*!
@@ -882,14 +885,19 @@ static bool try_cast_element_spell(PlayerType *player_ptr, SPELL_IDX spell_idx,
     if (randint1(100) < chance / 2) {
         int plev = player_ptr->lev;
         msg_print(_("元素の力が制御できない氾流となって解放された!", "The elemental power surges from you in an uncontrollable torrent!"));
-        project(player_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + plev / 10, player_ptr->y, player_ptr->x, plev * 2, get_element_types(player_ptr->element)[0],
-            PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
+        const auto element = get_element_types(player_ptr->element)[0];
+        constexpr auto flags = PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM;
+        project(player_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + plev / 10, player_ptr->y, player_ptr->x, plev * 2, element, flags);
         player_ptr->csp = std::max(0, player_ptr->csp - player_ptr->msp * 10 / (20 + randint1(10)));
 
         PlayerEnergy(player_ptr).set_player_turn_energy(100);
-        set_bits(player_ptr->redraw, PR_MP);
-        set_bits(player_ptr->window_flags, PW_PLAYER | PW_SPELL);
-
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::MP);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::PLAYER,
+            SubWindowRedrawingFlag::SPELL,
+        };
+        rfu.set_flags(flags_swrf);
         return false;
     }
 
@@ -936,8 +944,13 @@ void do_cmd_element(PlayerType *player_ptr)
     }
 
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
-    set_bits(player_ptr->redraw, PR_MP);
-    set_bits(player_ptr->window_flags, PW_PLAYER | PW_SPELL);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
@@ -955,12 +968,12 @@ void do_cmd_element_browse(PlayerType *player_ptr)
             return;
         }
 
-        term_erase(12, 21, 255);
-        term_erase(12, 20, 255);
-        term_erase(12, 19, 255);
-        term_erase(12, 18, 255);
-        term_erase(12, 17, 255);
-        term_erase(12, 16, 255);
+        term_erase(12, 21);
+        term_erase(12, 20);
+        term_erase(12, 19);
+        term_erase(12, 18);
+        term_erase(12, 17);
+        term_erase(12, 16);
         display_wrap_around(get_element_tip(player_ptr, n), 62, 17, 15);
 
         prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);
@@ -1003,7 +1016,7 @@ bool is_elemental_genocide_effective(MonsterRaceInfo *r_ptr, AttributeType type)
         }
         break;
     case AttributeType::CONFUSION:
-        if (any_bits(r_ptr->flags3, RF3_NO_CONF)) {
+        if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
             return false;
         }
         break;
@@ -1030,7 +1043,7 @@ bool is_elemental_genocide_effective(MonsterRaceInfo *r_ptr, AttributeType type)
  * @param em_ptr 魔法効果情報への参照ポインタ
  * @return 効果処理を続けるかどうか
  */
-ProcessResult effect_monster_elemental_genocide(PlayerType *player_ptr, effect_monster_type *em_ptr)
+ProcessResult effect_monster_elemental_genocide(PlayerType *player_ptr, EffectMonster *em_ptr)
 {
     auto type = get_element_type(player_ptr->element, 0);
     auto name = get_element_name(player_ptr->element, 0);
@@ -1157,7 +1170,7 @@ static int get_element_realm(PlayerType *player_ptr, int is, int n)
     int os = cs;
     int k;
 
-    std::string buf = format(_("領域を選んで下さい(%c-%c) ('='初期オプション設定): ", "Choose a realm (%c-%c) ('=' for options): "), I2A(0), I2A(n - 1));
+    const auto buf = format(_("領域を選んで下さい(%c-%c) ('='初期オプション設定): ", "Choose a realm (%c-%c) ('=' for options): "), I2A(0), I2A(n - 1));
 
     while (true) {
         display_realm_cursor(os, n, TERM_WHITE);
@@ -1222,7 +1235,7 @@ byte select_element_realm(PlayerType *player_ptr)
 {
     clear_from(10);
 
-    int realm_max = enum2i(ElementRealmType::MAX);
+    constexpr auto realm_max = enum2i(ElementRealmType::MAX);
     int realm_idx = 1;
     int row = 16;
     while (1) {
@@ -1242,7 +1255,7 @@ byte select_element_realm(PlayerType *player_ptr)
         auto realm = i2enum<ElementRealmType>(realm_idx);
         display_wrap_around(element_texts.at(realm), 74, row, 3);
 
-        if (get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y)) {
+        if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::DEFAULT_Y)) {
             break;
         }
 
index d90cc1a..f5d6416 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
@@ -16,7 +16,7 @@ enum class ElementRealmType {
 };
 
 class PlayerType;
-struct effect_monster_type;
+class EffectMonster;
 struct rc_type;
 
 concptr get_element_title(int realm_idx);
@@ -24,7 +24,7 @@ AttributeType get_element_type(int realm_idx, int n);
 concptr get_element_name(int realm_idx, int n);
 void do_cmd_element(PlayerType *player_ptr);
 void do_cmd_element_browse(PlayerType *player_ptr);
-ProcessResult effect_monster_elemental_genocide(PlayerType *player_ptr, effect_monster_type *em_ptr);
+ProcessResult effect_monster_elemental_genocide(PlayerType *player_ptr, EffectMonster *em_ptr);
 bool has_element_resist(PlayerType *player_ptr, ElementRealmType realm, PLAYER_LEVEL lev);
 byte select_element_realm(PlayerType *player_ptr);
 void switch_element_racial(PlayerType *player_ptr, rc_type *rc_ptr);
index cab710b..cae647b 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/mind-explanations-table.h"
+#include "mind/mind-explanations-table.h"
 
 /*! 特殊技能の一覧テーブル */
 mind_power const mind_powers[MAX_MINDKINDS] = {
index ea8ba1e..466d0a3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 9380125..9748830 100644 (file)
@@ -1,8 +1,6 @@
-#include "mind/mind-force-trainer.h"
+#include "mind/mind-force-trainer.h"
 #include "avatar/avatar.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "effect/attribute-types.h"
 #include "effect/spells-effect-util.h"
@@ -34,6 +32,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
 #include "target/target-getter.h"
@@ -89,7 +88,7 @@ bool clear_mind(PlayerType *player_ptr)
         player_ptr->csp_frac = 0;
     }
 
-    player_ptr->redraw |= (PR_MP);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
     return true;
 }
 
@@ -139,7 +138,8 @@ void set_lightspeed(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
 }
 
@@ -176,8 +176,7 @@ bool set_tim_sh_force(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_sh_touki = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -185,6 +184,7 @@ bool set_tim_sh_force(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
+
     handle_stuff(player_ptr);
     return true;
 }
@@ -220,7 +220,7 @@ bool shock_power(PlayerType *player_ptr)
     POSITION oy = y, ox = x;
     MONSTER_IDX m_idx = player_ptr->current_floor_ptr->grid_array[y][x].m_idx;
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     const auto m_name = monster_desc(player_ptr, m_ptr, 0);
 
     if (randint1(r_ptr->level * 3 / 2) > randint0(dam / 2) + dam / 2) {
@@ -256,7 +256,7 @@ bool shock_power(PlayerType *player_ptr)
     lite_spot(player_ptr, ty, tx);
 
     if (r_ptr->brightness_flags.has_any_of(ld_mask)) {
-        player_ptr->update |= (PU_MONSTER_LITE);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 
     return true;
@@ -277,6 +277,7 @@ bool cast_force_spell(PlayerType *player_ptr, MindForceTrainerType spell)
         boost /= 2;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     switch (spell) {
     case MindForceTrainerType::SMALL_FORCE_BALL:
         if (!get_aim_dir(player_ptr, &dir)) {
@@ -305,7 +306,7 @@ bool cast_force_spell(PlayerType *player_ptr, MindForceTrainerType spell)
     case MindForceTrainerType::IMPROVE_FORCE:
         msg_print(_("気を練った。", "You improved the Force."));
         set_current_ki(player_ptr, false, 70 + plev);
-        player_ptr->update |= (PU_BONUS);
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
         if (randint1(get_current_ki(player_ptr)) > (plev * 4 + 120)) {
             msg_print(_("気が暴走した!", "The Force exploded!"));
             fire_ball(player_ptr, AttributeType::MANA, 0, get_current_ki(player_ptr) / 2, 10);
@@ -334,8 +335,11 @@ bool cast_force_spell(PlayerType *player_ptr, MindForceTrainerType spell)
             return false;
         }
 
-        MONSTER_IDX m_idx = player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx;
-        if ((m_idx == 0) || !player_has_los_bold(player_ptr, target_row, target_col) || !projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
+        const Pos2D pos(target_row, target_col);
+        const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+        const auto m_idx = grid.m_idx;
+        const auto is_projectable = projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col);
+        if ((m_idx == 0) || !grid.has_los() || !is_projectable) {
             break;
         }
 
@@ -376,6 +380,6 @@ bool cast_force_spell(PlayerType *player_ptr, MindForceTrainerType spell)
     }
 
     set_current_ki(player_ptr, true, 0);
-    player_ptr->update |= PU_BONUS;
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     return true;
 }
index 2f5aef7..2c34f12 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 0b2ca94..0c594b9 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/mind-hobbit.h"
+#include "mind/mind-hobbit.h"
 #include "floor/floor-object.h"
 #include "object/object-kind-hook.h"
 #include "sv-definition/sv-food-types.h"
index b16c3e3..3d1d5bc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool create_ration(PlayerType *player_ptr);
index 1d743f0..f64a2df 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/mind-info.h"
+#include "mind/mind-info.h"
 #include "cmd-action/cmd-spell.h"
 #include "locale/japanese.h"
 #include "mind/mind-force-trainer.h"
index 4d32868..8449724 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 
index 04c1e61..440a35c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 魔力喰い処理
  * @date 2020/06/27
  * @author Hourier
 bool eat_magic(PlayerType *player_ptr, int power)
 {
     byte fail_type = 1;
-    const auto q = _("どのアイテムから魔力を吸収しますか?", "Drain which item? ");
-    const auto s = _("魔力を吸収できるアイテムがありません。", "You have nothing to drain.");
-    short item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::can_recharge));
+    constexpr auto q = _("どのアイテムから魔力を吸収しますか?", "Drain which item? ");
+    constexpr auto s = _("魔力を吸収できるアイテムがありません。", "You have nothing to drain.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::can_recharge));
     if (o_ptr == nullptr) {
         return false;
     }
@@ -67,7 +67,7 @@ bool eat_magic(PlayerType *player_ptr, int power)
                 player_ptr->csp += lev / 2;
                 o_ptr->pval--;
 
-                if ((tval == ItemKindType::STAFF) && (item >= 0) && (o_ptr->number > 1)) {
+                if ((tval == ItemKindType::STAFF) && (i_idx >= 0) && (o_ptr->number > 1)) {
                     ItemEntity forge;
                     ItemEntity *q_ptr;
                     q_ptr = &forge;
@@ -76,7 +76,7 @@ bool eat_magic(PlayerType *player_ptr, int power)
                     q_ptr->number = 1;
                     o_ptr->pval++;
                     o_ptr->number--;
-                    item = store_item_to_inventory(player_ptr, q_ptr);
+                    i_idx = store_item_to_inventory(player_ptr, q_ptr);
 
                     msg_print(_("杖をまとめなおした。", "You unstack your staff."));
                 }
@@ -184,7 +184,7 @@ bool eat_magic(PlayerType *player_ptr, int power)
             msg_format(_("乱暴な魔法のために%sが壊れた!", "Wild magic consumes your %s!"), item_name.data());
         }
 
-        vary_item(player_ptr, item, -1);
+        vary_item(player_ptr, i_idx, -1);
     }
 
     if (fail_type == 3) {
@@ -194,7 +194,7 @@ bool eat_magic(PlayerType *player_ptr, int power)
             msg_format(_("乱暴な魔法のために%sが壊れた!", "Wild magic consumes your %s!"), item_name.data());
         }
 
-        vary_item(player_ptr, item, -999);
+        vary_item(player_ptr, i_idx, -999);
     }
 
     return redraw_player(player_ptr);
index 7133fb8..607fcdd 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool eat_magic(PlayerType *player_ptr, int power);
index 539a38e..86f4bf4 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/mind-magic-eater.h"
+#include "mind/mind-magic-eater.h"
 #include "flavor/flavor-describer.h"
 #include "floor/floor-object.h"
 #include "inventory/inventory-object.h"
  */
 bool import_magic_device(PlayerType *player_ptr)
 {
-    const auto q = _("どのアイテムの魔力を取り込みますか? ", "Gain power of which item? ");
-    const auto s = _("魔力を取り込めるアイテムがない。", "There's nothing with power to absorb.");
-    OBJECT_IDX item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::can_recharge));
+    constexpr auto q = _("どのアイテムの魔力を取り込みますか? ", "Gain power of which item? ");
+    constexpr auto s = _("魔力を取り込めるアイテムがない。", "There's nothing with power to absorb.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, USE_INVEN | USE_FLOOR, FuncItemTester(&ItemEntity::can_recharge));
     if (o_ptr == nullptr) {
         return false;
     }
@@ -47,7 +47,7 @@ bool import_magic_device(PlayerType *player_ptr)
 
     auto magic_eater_data = PlayerClass(player_ptr).get_specific_data<magic_eater_data_type>();
     const auto tval = bi_key.tval();
-    auto &target_item = magic_eater_data->get_item_group(tval)[bi_key.sval().value()];
+    auto &target_item = magic_eater_data->get_item_group(tval)[*bi_key.sval()];
     auto pval = o_ptr->pval;
     if (tval == ItemKindType::ROD) {
         target_item.count = std::min<byte>(target_item.count + o_ptr->number, 99);
@@ -76,7 +76,7 @@ bool import_magic_device(PlayerType *player_ptr)
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
     msg_format(_("%sの魔力を取り込んだ。", "You absorb magic of %s."), item_name.data());
 
-    vary_item(player_ptr, item, -999);
+    vary_item(player_ptr, i_idx, -999);
     PlayerEnergy(player_ptr).set_player_turn_energy(100);
     return true;
 }
index f225504..06260d8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool import_magic_device(PlayerType *player_ptr);
index 4fb6fa9..64a055b 100644 (file)
@@ -1,10 +1,9 @@
-#include "mind/mind-magic-resistance.h"
+#include "mind/mind-magic-resistance.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "game-option/disturbance-options.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -40,8 +39,8 @@ bool set_resist_magic(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->resist_magic = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -49,7 +48,8 @@ bool set_resist_magic(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
index 7e365c2..3d259cf 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 5125eed..32593da 100644 (file)
@@ -1,7 +1,6 @@
-#include "mind/mind-mindcrafter.h"
+#include "mind/mind-mindcrafter.h"
 #include "autopick/autopick.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
@@ -35,6 +34,7 @@
 #include "status/sight-setter.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-getter.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
  */
 bool psychometry(PlayerType *player_ptr)
 {
-    concptr q = _("どのアイテムを調べますか?", "Meditate on which item? ");
-    concptr s = _("調べるアイテムがありません。", "You have nothing appropriate.");
-    ItemEntity *o_ptr;
-    OBJECT_IDX item;
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
+    constexpr auto q = _("どのアイテムを調べますか?", "Meditate on which item? ");
+    constexpr auto s = _("調べるアイテムがありません。", "You have nothing appropriate.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
     if (!o_ptr) {
         return false;
     }
@@ -84,8 +83,20 @@ bool psychometry(PlayerType *player_ptr)
     o_ptr->feeling = feel;
     o_ptr->marked.set(OmType::TOUCHED);
 
-    set_bits(player_ptr->update, PU_COMBINATION | PU_REORDER);
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
 
     bool okay = false;
     switch (o_ptr->bi_key.tval()) {
@@ -118,7 +129,7 @@ bool psychometry(PlayerType *player_ptr)
         break;
     }
 
-    autopick_alter_item(player_ptr, item, (bool)(okay && destroy_feeling));
+    autopick_alter_item(player_ptr, i_idx, (bool)(okay && destroy_feeling));
     return true;
 }
 
index 14dfc19..b9b44d8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool psychometry(PlayerType *player_ptr);
index f5c6a05..84f29bb 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 鏡使いの鏡魔法コマンド処理
  * @date 2022/03/07
  * @author Hourier
@@ -7,8 +7,6 @@
 
 #include "mind/mind-mirror-master.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
@@ -17,7 +15,6 @@
 #include "effect/effect-monster.h"
 #include "effect/effect-processor.h"
 #include "effect/spells-effect-util.h"
-#include "floor/cave.h"
 #include "floor/geometry.h"
 #include "game-option/disturbance-options.h"
 #include "game-option/map-screen-options.h"
 #include "status/body-improvement.h"
 #include "status/buff-setter.h"
 #include "status/sight-setter.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/grid-selector.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-getter.h"
@@ -67,24 +66,38 @@ bool check_multishadow(PlayerType *player_ptr)
  */
 bool binding_field(PlayerType *player_ptr, int dam)
 {
-    POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
+    /* 鏡はもっと少ない */
+    int mirror_x[10]{};
+    int mirror_y[10]{};
     int mirror_num = 0; /* 鏡の数 */
 
     /* 三角形の頂点 */
-    POSITION point_x[3];
-    POSITION point_y[3];
+    int point_x[3]{};
+    int point_y[3]{};
 
     /* Default target of monsterspell is player */
     monster_target_y = player_ptr->y;
     monster_target_x = player_ptr->x;
 
-    for (POSITION x = 0; x < player_ptr->current_floor_ptr->width; x++) {
-        for (POSITION y = 0; y < player_ptr->current_floor_ptr->height; y++) {
-            if (player_ptr->current_floor_ptr->grid_array[y][x].is_mirror() && distance(player_ptr->y, player_ptr->x, y, x) <= get_max_range(player_ptr) && distance(player_ptr->y, player_ptr->x, y, x) != 0 && player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
-                mirror_y[mirror_num] = y;
-                mirror_x[mirror_num] = x;
-                mirror_num++;
+    const auto max_range = AngbandSystem::get_instance().get_max_range();
+    const auto &floor = *player_ptr->current_floor_ptr;
+    for (auto x = 0; x < floor.width; x++) {
+        for (auto y = 0; y < floor.height; y++) {
+            const Pos2D pos(y, x);
+            const auto &grid = floor.get_grid(pos);
+            if (!grid.is_mirror()) {
+                continue;
+            }
+
+            const auto dist = distance(player_ptr->y, player_ptr->x, pos.y, pos.x);
+            const auto is_projectable = projectable(player_ptr, player_ptr->y, player_ptr->x, pos.y, pos.x);
+            if ((dist == 0) || (dist > max_range) || !grid.has_los() || !is_projectable) {
+                continue;
             }
+
+            mirror_y[mirror_num] = y;
+            mirror_x[mirror_num] = x;
+            mirror_num++;
         }
     }
 
@@ -124,14 +137,25 @@ bool binding_field(PlayerType *player_ptr, int dam)
 
     for (y = y1; y <= y2; y++) {
         for (x = x1; x <= x2; x++) {
-            if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
-                if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
-                    if (!(player_ptr->effects()->blindness()->is_blind()) && panel_contains(y, x)) {
-                        print_bolt_pict(player_ptr, y, x, y, x, AttributeType::MANA);
-                        move_cursor_relative(y, x);
-                        term_fresh();
-                        term_xtra(TERM_XTRA_DELAY, delay_factor);
-                    }
+            const Pos2D pos(y, x);
+            if ((centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) < 0)) {
+                continue;
+            }
+
+            if ((centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) < 0)) {
+                continue;
+            }
+
+            if ((centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) < 0)) {
+                continue;
+            }
+
+            if (floor.has_los(pos) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+                if (!(player_ptr->effects()->blindness()->is_blind()) && panel_contains(y, x)) {
+                    print_bolt_pict(player_ptr, y, x, y, x, AttributeType::MANA);
+                    move_cursor_relative(y, x);
+                    term_fresh();
+                    term_xtra(TERM_XTRA_DELAY, delay_factor);
                 }
             }
         }
@@ -139,30 +163,64 @@ bool binding_field(PlayerType *player_ptr, int dam)
 
     for (y = y1; y <= y2; y++) {
         for (x = x1; x <= x2; x++) {
-            if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
-                if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
-                    (void)affect_feature(player_ptr, 0, 0, y, x, dam, AttributeType::MANA);
-                }
+            const Pos2D pos(y, x);
+            if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) < 0) {
+                continue;
+            }
+
+            if (centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) < 0) {
+                continue;
+            }
+
+            if (centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) < 0) {
+                continue;
+            }
+
+            if (floor.has_los(pos) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+                (void)affect_feature(player_ptr, 0, 0, y, x, dam, AttributeType::MANA);
             }
         }
     }
 
     for (y = y1; y <= y2; y++) {
         for (x = x1; x <= x2; x++) {
-            if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
-                if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
-                    (void)affect_item(player_ptr, 0, 0, y, x, dam, AttributeType::MANA);
-                }
+            const Pos2D pos(y, x);
+            if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) < 0) {
+                continue;
+            }
+
+            if (centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) < 0) {
+                continue;
+            }
+
+            if (centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) < 0) {
+                continue;
+            }
+
+            if (floor.has_los(pos) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+                (void)affect_item(player_ptr, 0, 0, y, x, dam, AttributeType::MANA);
             }
         }
     }
 
     for (y = y1; y <= y2; y++) {
         for (x = x1; x <= x2; x++) {
-            if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
-                if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
-                    (void)affect_monster(player_ptr, 0, 0, y, x, dam, AttributeType::MANA, (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), true);
-                }
+            const Pos2D pos(y, x);
+            if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) < 0) {
+                continue;
+            }
+
+            if (centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) < 0) {
+                continue;
+            }
+
+            if (centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) < 0) {
+                continue;
+            }
+
+            if (floor.has_los(pos) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+                constexpr auto flags = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP;
+                (void)affect_monster(player_ptr, 0, 0, y, x, dam, AttributeType::MANA, flags, true);
             }
         }
     }
@@ -221,8 +279,8 @@ bool set_multishadow(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->multishadow = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -230,7 +288,8 @@ bool set_multishadow(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -268,8 +327,8 @@ bool set_dustrobe(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->dustrobe = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -277,7 +336,8 @@ bool set_dustrobe(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -417,7 +477,7 @@ bool cast_mirror_spell(PlayerType *player_ptr, MindMirrorMasterType spell)
             return false;
         }
 
-        SpellsMirrorMaster(player_ptr).super_ray(dir, damroll(11 + (plev - 5) / 4, 8));
+        SpellsMirrorMaster(player_ptr).super_ray(dir, 150 + randint1(2 * plev));
         break;
     case MindMirrorMasterType::ILLUSION_LIGHT:
         tmp = g_ptr->is_mirror() ? 4 : 3;
index 8a047da..e9a51a9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 023a147..5650cc4 100644 (file)
@@ -1,7 +1,5 @@
-#include "mind/mind-monk.h"
+#include "mind/mind-monk.h"
 #include "action/action-limited.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "io/input-key-acceptor.h"
 #include "mind/stances-table.h"
 #include "player-base/player-class.h"
@@ -10,6 +8,7 @@
 #include "player/special-defense-types.h"
 #include "status/action-setter.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/int-char-converter.h"
@@ -24,8 +23,9 @@ static void set_stance(PlayerType *player_ptr, const MonkStanceType new_stance)
         return;
     }
 
-    player_ptr->update |= PU_BONUS;
-    player_ptr->redraw |= PR_ACTION;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(MainWindowRedrawingFlag::ACTION);
     msg_format(_("%sの構えをとった。", "You assume the %s stance."), monk_stances[enum2i(new_stance) - 1].desc);
     pc.set_monk_stance(new_stance);
 }
@@ -87,7 +87,7 @@ bool choose_monk_stance(PlayerType *player_ptr)
     }
 
     set_stance(player_ptr, new_stance);
-    player_ptr->redraw |= PR_ACTION;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
     screen_load();
     return true;
 }
index 4c3b4c0..a6bc729 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool choose_monk_stance(PlayerType *player_ptr);
index c0b3d71..8a8944b 100644 (file)
@@ -1,9 +1,8 @@
-#include "mind/mind-ninja.h"
+#include "mind/mind-ninja.h"
 #include "cmd-action/cmd-attack.h"
 #include "cmd-item/cmd-throw.h"
 #include "combat/combat-options-type.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
@@ -26,7 +25,7 @@
 #include "monster/monster-update.h"
 #include "object-enchant/trc-types.h"
 #include "object/object-kind-hook.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "player-base/player-class.h"
 #include "player-info/equipment-info.h"
 #include "player-info/ninja-data-type.h"
@@ -54,6 +53,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
@@ -99,10 +99,11 @@ bool kawarimi(PlayerType *player_ptr, bool success)
         return false;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (!success && one_in_(3)) {
         msg_print(_("変わり身失敗!逃げられなかった。", "Kawarimi failed! You couldn't run away."));
         ninja_data->kawarimi = false;
-        player_ptr->redraw |= (PR_TIMED_EFFECT);
+        rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
         return false;
     }
 
@@ -124,7 +125,7 @@ bool kawarimi(PlayerType *player_ptr, bool success)
     }
 
     ninja_data->kawarimi = false;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     return true;
 }
 
@@ -166,20 +167,19 @@ bool rush_attack(PlayerType *player_ptr, bool *mdeath)
         return true;
     }
 
-    ty = player_ptr->y;
-    tx = player_ptr->x;
-    bool tmp_mdeath = false;
-    bool moved = false;
+    auto y = player_ptr->y;
+    auto x = player_ptr->x;
+    auto tmp_mdeath = false;
+    auto moved = false;
     for (const auto &[ny, nx] : path_g) {
-        MonsterEntity *m_ptr;
-
-        if (is_cave_empty_bold(player_ptr, ny, nx) && player_can_enter(player_ptr, floor_ptr->grid_array[ny][nx].feat, 0)) {
-            ty = ny;
-            tx = nx;
+        const auto &grid_new = floor_ptr->get_grid({ ny, nx });
+        if (is_cave_empty_bold(player_ptr, ny, nx) && player_can_enter(player_ptr, grid_new.feat, 0)) {
+            y = ny;
+            x = nx;
             continue;
         }
 
-        if (!floor_ptr->grid_array[ny][nx].m_idx) {
+        if (!grid_new.m_idx) {
             if (tm_idx) {
                 msg_print(_("失敗!", "Failed!"));
             } else {
@@ -189,25 +189,26 @@ bool rush_attack(PlayerType *player_ptr, bool *mdeath)
             break;
         }
 
-        if (!player_bold(player_ptr, ty, tx)) {
-            teleport_player_to(player_ptr, ty, tx, TELEPORT_NONMAGICAL);
+        const Pos2D p_pos(y, x);
+        if (!player_ptr->is_located_at(p_pos)) {
+            teleport_player_to(player_ptr, y, x, TELEPORT_NONMAGICAL);
         }
-        update_monster(player_ptr, floor_ptr->grid_array[ny][nx].m_idx, true);
 
-        m_ptr = &floor_ptr->m_list[floor_ptr->grid_array[ny][nx].m_idx];
-        if (tm_idx != floor_ptr->grid_array[ny][nx].m_idx) {
+        update_monster(player_ptr, grid_new.m_idx, true);
+        const auto *m_ptr = &floor_ptr->m_list[grid_new.m_idx];
+        if (tm_idx != grid_new.m_idx) {
 #ifdef JP
             msg_format("%s%sが立ちふさがっている!", tm_idx ? "別の" : "", m_ptr->ml ? "モンスター" : "何か");
 #else
             msg_format("There is %s in the way!", m_ptr->ml ? (tm_idx ? "another monster" : "a monster") : "someone");
 #endif
-        } else if (!player_bold(player_ptr, ty, tx)) {
+        } else if (!player_ptr->is_located_at(p_pos)) {
             const auto m_name = monster_desc(player_ptr, m_ptr, 0);
             msg_format(_("素早く%sの懐に入り込んだ!", "You quickly jump in and attack %s!"), m_name.data());
         }
 
-        if (!player_bold(player_ptr, ty, tx)) {
-            teleport_player_to(player_ptr, ty, tx, TELEPORT_NONMAGICAL);
+        if (!player_ptr->is_located_at(p_pos)) {
+            teleport_player_to(player_ptr, y, x, TELEPORT_NONMAGICAL);
         }
         moved = true;
         tmp_mdeath = do_cmd_attack(player_ptr, ny, nx, HISSATSU_NYUSIN);
@@ -215,8 +216,8 @@ bool rush_attack(PlayerType *player_ptr, bool *mdeath)
         break;
     }
 
-    if (!moved && !player_bold(player_ptr, ty, tx)) {
-        teleport_player_to(player_ptr, ty, tx, TELEPORT_NONMAGICAL);
+    if (!moved && !player_ptr->is_located_at({ y, x })) {
+        teleport_player_to(player_ptr, y, x, TELEPORT_NONMAGICAL);
     }
 
     if (mdeath) {
@@ -232,7 +233,7 @@ bool rush_attack(PlayerType *player_ptr, bool *mdeath)
  */
 void process_surprise_attack(PlayerType *player_ptr, player_attack_type *pa_ptr)
 {
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     if (!has_melee_weapon(player_ptr, enum2i(INVEN_MAIN_HAND) + pa_ptr->hand) || player_ptr->is_icky_wield[pa_ptr->hand]) {
         return;
     }
@@ -309,10 +310,9 @@ bool hayagake(PlayerType *player_ptr)
         return true;
     }
 
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-
-    if (f_ptr->flags.has_not(TerrainCharacteristics::PROJECT) || (!player_ptr->levitation && f_ptr->flags.has(TerrainCharacteristics::DEEP))) {
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(player_ptr->get_position());
+    const auto &terrain = grid.get_terrain();
+    if (terrain.flags.has_not(TerrainCharacteristics::PROJECT) || (!player_ptr->levitation && terrain.flags.has(TerrainCharacteristics::DEEP))) {
         msg_print(_("ここでは素早く動けない。", "You cannot run in here."));
     } else {
         set_action(player_ptr, ACTION_HAYAGAKE);
@@ -360,11 +360,12 @@ bool set_superstealth(PlayerType *player_ptr, bool set)
     if (!notice) {
         return false;
     }
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
 
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
+
     return true;
 }
 
@@ -409,7 +410,7 @@ bool cast_ninja_spell(PlayerType *player_ptr, MindNinjaType spell)
         if (ninja_data && !ninja_data->kawarimi) {
             msg_print(_("敵の攻撃に対して敏感になった。", "You are now prepared to evade any attacks."));
             ninja_data->kawarimi = true;
-            player_ptr->redraw |= (PR_TIMED_EFFECT);
+            RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
         }
 
         break;
@@ -508,7 +509,7 @@ bool cast_ninja_spell(PlayerType *player_ptr, MindNinjaType spell)
             int attempts = 1000;
             while (attempts--) {
                 scatter(player_ptr, &y, &x, player_ptr->y, player_ptr->x, 4, PROJECT_NONE);
-                if (!player_bold(player_ptr, y, x)) {
+                if (!player_ptr->is_located_at({ y, x })) {
                     break;
                 }
             }
index 286c2a9..5c43b02 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct player_attack_type;
 class PlayerType;
index 7fe11af..e8b0ca6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MindBerserkerType : int {
     DETECT_MANACE = 0,
index 84adc9d..3fbed74 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/mind-power-getter.h"
+#include "mind/mind-power-getter.h"
 #include "core/asking-player.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
@@ -15,6 +15,7 @@
 #include "player-info/equipment-info.h"
 #include "player/player-status-table.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "timed-effect/player-stun.h"
@@ -24,6 +25,7 @@
 
 MindPowerGetter::MindPowerGetter(PlayerType *player_ptr)
     : player_ptr(player_ptr)
+    , use_mind(MindKindType::MINDCRAFTER)
     , menu_line(use_menu ? 1 : 0)
 {
 }
@@ -59,13 +61,13 @@ bool MindPowerGetter::get_mind_power(SPELL_IDX *sn, bool only_browse)
         }
     }
 
-    char out_val[160];
+    std::string prompt;
     if (only_browse) {
-        (void)strnfmt(out_val, 78, _("(%s^ %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? "),
-            this->mind_description, I2A(0), I2A(this->num - 1), this->mind_description);
+        constexpr auto fmt = _("(%s^ %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? ");
+        prompt = format(fmt, this->mind_description, I2A(0), I2A(this->num - 1), this->mind_description);
     } else {
-        (void)strnfmt(out_val, 78, _("(%s^ %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? "),
-            this->mind_description, I2A(0), I2A(this->num - 1), this->mind_description);
+        constexpr auto fmt = _("(%s^ %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? ");
+        prompt = format(fmt, this->mind_description, I2A(0), I2A(this->num - 1), this->mind_description);
     }
 
     if (use_menu && !only_browse) {
@@ -73,12 +75,12 @@ bool MindPowerGetter::get_mind_power(SPELL_IDX *sn, bool only_browse)
     }
 
     this->choice = (always_show_list || use_menu) ? ESCAPE : 1;
-    decide_mind_choice(out_val, only_browse);
+    this->decide_mind_choice(prompt, only_browse);
     if (this->redraw && !only_browse) {
         screen_load();
     }
 
-    this->player_ptr->window_flags |= PW_SPELL;
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::SPELL);
     handle_stuff(this->player_ptr);
     if (!this->flag) {
         return false;
@@ -140,13 +142,18 @@ bool MindPowerGetter::select_spell_index(SPELL_IDX *sn)
     return mind_ptr->info[*sn].min_lev <= this->player_ptr->lev;
 }
 
-bool MindPowerGetter::decide_mind_choice(char *out_val, const bool only_browse)
+bool MindPowerGetter::decide_mind_choice(std::string_view prompt, const bool only_browse)
 {
     while (!this->flag) {
         if (this->choice == ESCAPE) {
             this->choice = ' ';
-        } else if (!get_com(out_val, &this->choice, true)) {
-            break;
+        } else {
+            const auto command = input_command(prompt, true);
+            if (!command) {
+                break;
+            }
+
+            this->choice = *command;
         }
 
         if (!interpret_mind_key_input(only_browse)) {
index 1e1fafa..28280bd 100644 (file)
@@ -1,7 +1,8 @@
-#pragma once
+#pragma once
 
 #include "mind/mind-types.h"
 #include "system/angband.h"
+#include <string_view>
 
 struct mind_power;
 struct mind_type;
@@ -13,7 +14,6 @@ public:
     bool get_mind_power(SPELL_IDX *sn, bool only_browse);
 
 private:
-    PlayerType *player_ptr;
     SPELL_IDX index = 0;
     int num = 0;
     TERM_LEN y = 1;
@@ -24,15 +24,17 @@ private:
     const mind_type *spell = nullptr;
     bool flag = false;
     bool redraw = false;
-    MindKindType use_mind;
-    int menu_line;
     const mind_power *mind_ptr = nullptr;
     PERCENTAGE chance = 0;
     int mana_cost = 0;
 
+    PlayerType *player_ptr;
+    MindKindType use_mind;
+    int menu_line;
+
     void select_mind_description();
     bool select_spell_index(SPELL_IDX *sn);
-    bool decide_mind_choice(char *out_val, const bool only_browse);
+    bool decide_mind_choice(std::string_view prompt, const bool only_browse);
     bool interpret_mind_key_input(const bool only_browse);
     bool display_minds_chance(const bool only_browse);
     void display_each_mind_chance();
index f9ce8a0..ab7cd3b 100644 (file)
@@ -1,5 +1,4 @@
-#include "mind/mind-priest.h"
-#include "core/player-update-types.h"
+#include "mind/mind-priest.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "object-hook/hook-weapon.h"
 #include "object/item-tester-hooker.h"
 #include "object/item-use-flags.h"
-#include "object/object-flags.h"
 #include "racial/racial-android.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
  */
 bool bless_weapon(PlayerType *player_ptr)
 {
-    concptr q = _("どのアイテムを祝福しますか?", "Bless which weapon? ");
-    concptr s = _("祝福できる武器がありません。", "You have no weapon to bless.");
+    constexpr auto q = _("どのアイテムを祝福しますか?", "Bless which weapon? ");
+    constexpr auto s = _("祝福できる武器がありません。", "You have no weapon to bless.");
 
-    OBJECT_IDX item;
+    short i_idx;
     constexpr BIT_FLAGS options = USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, options, FuncItemTester(&ItemEntity::is_weapon));
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, FuncItemTester(&ItemEntity::is_weapon));
     if (!o_ptr) {
         return false;
     }
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, OD_OMIT_PREFIX | OD_NAME_ONLY);
-    auto flags = object_flags(o_ptr);
+    const auto item_flags = o_ptr->get_flags();
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (o_ptr->is_cursed()) {
         auto can_disturb_blessing = o_ptr->curse_flags.has(CurseTraitType::HEAVY_CURSE) && (randint1(100) < 33);
-        can_disturb_blessing |= flags.has(TR_ADD_L_CURSE);
-        can_disturb_blessing |= flags.has(TR_ADD_H_CURSE);
+        can_disturb_blessing |= item_flags.has(TR_ADD_L_CURSE);
+        can_disturb_blessing |= item_flags.has(TR_ADD_H_CURSE);
         can_disturb_blessing |= o_ptr->curse_flags.has(CurseTraitType::PERSISTENT_CURSE);
         can_disturb_blessing |= o_ptr->curse_flags.has(CurseTraitType::PERMA_CURSE);
         if (can_disturb_blessing) {
 #ifdef JP
             msg_format("%sを覆う黒いオーラは祝福を跳ね返した!", item_name.data());
 #else
-            msg_format("The black aura on %s %s disrupts the blessing!", ((item >= 0) ? "your" : "the"), item_name.data());
+            msg_format("The black aura on %s %s disrupts the blessing!", ((i_idx >= 0) ? "your" : "the"), item_name.data());
 #endif
 
             return true;
@@ -56,13 +56,18 @@ bool bless_weapon(PlayerType *player_ptr)
 #ifdef JP
         msg_format("%s から邪悪なオーラが消えた。", item_name.data());
 #else
-        msg_format("A malignant aura leaves %s %s.", ((item >= 0) ? "your" : "the"), item_name.data());
+        msg_format("A malignant aura leaves %s %s.", ((i_idx >= 0) ? "your" : "the"), item_name.data());
 #endif
         o_ptr->curse_flags.clear();
         set_bits(o_ptr->ident, IDENT_SENSE);
         o_ptr->feeling = FEEL_NONE;
-        set_bits(player_ptr->update, PU_BONUS);
-        set_bits(player_ptr->window_flags, PW_EQUIPMENT | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::EQUIPMENT,
+            SubWindowRedrawingFlag::FLOOR_ITEMS,
+            SubWindowRedrawingFlag::FOUND_ITEMS,
+        };
+        rfu.set_flags(flags);
     }
 
     /*
@@ -73,11 +78,11 @@ bool bless_weapon(PlayerType *player_ptr)
      * artifact weapon they find. Ego weapons and normal weapons
      * can be blessed automatically.
      */
-    if (flags.has(TR_BLESSED)) {
+    if (item_flags.has(TR_BLESSED)) {
 #ifdef JP
         msg_format("%s は既に祝福されている。", item_name.data());
 #else
-        msg_format("%s %s %s blessed already.", ((item >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "were" : "was"));
+        msg_format("%s %s %s blessed already.", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "were" : "was"));
 #endif
         return true;
     }
@@ -86,7 +91,7 @@ bool bless_weapon(PlayerType *player_ptr)
 #ifdef JP
         msg_format("%sは輝いた!", item_name.data());
 #else
-        msg_format("%s %s shine%s!", ((item >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
+        msg_format("%s %s shine%s!", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
 #endif
         o_ptr->art_flags.set(TR_BLESSED);
         o_ptr->discount = 99;
@@ -130,13 +135,19 @@ bool bless_weapon(PlayerType *player_ptr)
 #ifdef JP
             msg_format("%s は劣化した!", item_name.data());
 #else
-            msg_format("%s %s %s disenchanted!", ((item >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "were" : "was"));
+            msg_format("%s %s %s disenchanted!", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "were" : "was"));
 #endif
         }
     }
 
-    set_bits(player_ptr->update, PU_BONUS);
-    set_bits(player_ptr->window_flags, PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
     calc_android_exp(player_ptr);
     return true;
 }
index 6fbfa43..2295e67 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool bless_weapon(PlayerType *player_ptr);
index 2d478ca..4ecc04c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 剣術家のレイシャルパワー処理
  * @date 2020/05/16
  * @author Hourier
@@ -8,8 +8,6 @@
 #include "action/action-limited.h"
 #include "avatar/avatar.h"
 #include "cmd-action/cmd-attack.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "inventory/inventory-slot-types.h"
 #include "io/input-key-acceptor.h"
 #include "mind/stances-table.h"
@@ -25,7 +23,7 @@
 #include "monster/monster-status.h"
 #include "object-enchant/tr-types.h"
 #include "pet/pet-util.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "player-base/player-class.h"
 #include "player-info/samurai-data-type.h"
 #include "player/attack-defense-types.h"
@@ -35,6 +33,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "timed-effect/player-cut.h"
@@ -46,6 +45,7 @@
 #include "view/display-messages.h"
 
 struct samurai_slaying_type {
+    samurai_slaying_type(MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr, combat_options mode, MonsterRaceInfo *r_ptr);
     MULTIPLY mult;
     TrFlags flags;
     MonsterEntity *m_ptr;
@@ -53,15 +53,13 @@ struct samurai_slaying_type {
     MonsterRaceInfo *r_ptr;
 };
 
-static samurai_slaying_type *initialize_samurai_slaying_type(
-    samurai_slaying_type *samurai_slaying_ptr, MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr, combat_options mode, MonsterRaceInfo *r_ptr)
+samurai_slaying_type::samurai_slaying_type(MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr, combat_options mode, MonsterRaceInfo *r_ptr)
+    : mult(mult)
+    , flags(flags)
+    , m_ptr(m_ptr)
+    , mode(mode)
+    , r_ptr(r_ptr)
 {
-    samurai_slaying_ptr->mult = mult;
-    samurai_slaying_ptr->flags = flags;
-    samurai_slaying_ptr->m_ptr = m_ptr;
-    samurai_slaying_ptr->mode = mode;
-    samurai_slaying_ptr->r_ptr = r_ptr;
-    return samurai_slaying_ptr;
 }
 
 /*!
@@ -155,7 +153,7 @@ static void hissatsu_zanma_ken(samurai_slaying_type *samurai_slaying_ptr)
         return;
     }
 
-    if (!monster_living(samurai_slaying_ptr->m_ptr->r_idx) && samurai_slaying_ptr->r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
+    if (!samurai_slaying_ptr->m_ptr->has_living_flag() && samurai_slaying_ptr->r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
         if (samurai_slaying_ptr->mult < 15) {
             samurai_slaying_ptr->mult = 25;
         } else if (samurai_slaying_ptr->mult < 50) {
@@ -276,7 +274,7 @@ static void hissatsu_lightning_eagle(PlayerType *player_ptr, samurai_slaying_typ
 static void hissatsu_bloody_maelstroem(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
 {
     auto player_cut = player_ptr->effects()->cut();
-    if ((samurai_slaying_ptr->mode == HISSATSU_SEKIRYUKA) && player_cut->is_cut() && monster_living(samurai_slaying_ptr->m_ptr->r_idx)) {
+    if ((samurai_slaying_ptr->mode == HISSATSU_SEKIRYUKA) && player_cut->is_cut() && samurai_slaying_ptr->m_ptr->has_living_flag()) {
         auto tmp = std::min<short>(100, std::max<short>(10, player_cut->current() / 10));
         if (samurai_slaying_ptr->mult < tmp) {
             samurai_slaying_ptr->mult = tmp;
@@ -325,9 +323,9 @@ static void hissatsu_keiun_kininken(PlayerType *player_ptr, samurai_slaying_type
  */
 MULTIPLY mult_hissatsu(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr, combat_options mode)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    samurai_slaying_type tmp_slaying;
-    samurai_slaying_type *samurai_slaying_ptr = initialize_samurai_slaying_type(&tmp_slaying, mult, flags, m_ptr, mode, r_ptr);
+    auto *r_ptr = &m_ptr->get_monrace();
+    samurai_slaying_type tmp_slaying(mult, flags, m_ptr, mode, r_ptr);
+    samurai_slaying_type *samurai_slaying_ptr = &tmp_slaying;
     hissatsu_burning_strike(player_ptr, samurai_slaying_ptr);
     hissatsu_serpent_tongue(player_ptr, samurai_slaying_ptr);
     hissatsu_zanma_ken(samurai_slaying_ptr);
@@ -366,7 +364,7 @@ void concentration(PlayerType *player_ptr)
         player_ptr->csp_frac = 0;
     }
 
-    player_ptr->redraw |= PR_MP;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
 }
 
 /*!
@@ -436,15 +434,24 @@ bool choose_samurai_stance(PlayerType *player_ptr)
     }
 
     set_action(player_ptr, ACTION_SAMURAI_STANCE);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (PlayerClass(player_ptr).samurai_stance_is(new_stance)) {
         msg_print(_("構え直した。", "You reassume a stance."));
     } else {
-        player_ptr->update |= (PU_BONUS | PU_MONSTER_STATUSES);
+        static constexpr auto flags_srf = {
+            StatusRecalculatingFlag::BONUS,
+            StatusRecalculatingFlag::MONSTER_STATUSES,
+        };
+        rfu.set_flags(flags_srf);
         msg_format(_("%sの型で構えた。", "You assume the %s stance."), samurai_stances[enum2i(new_stance) - 1].desc);
         PlayerClass(player_ptr).set_samurai_stance(new_stance);
     }
 
-    player_ptr->redraw |= (PR_ACTION | PR_TIMED_EFFECT);
+    static constexpr auto flags = {
+        MainWindowRedrawingFlag::ACTION,
+        MainWindowRedrawingFlag::TIMED_EFFECT,
+    };
+    rfu.set_flags(flags);
     screen_load();
     return true;
 }
@@ -494,8 +501,8 @@ void mineuchi(PlayerType *player_ptr, player_attack_type *pa_ptr)
     pa_ptr->attack_damage = 0;
     anger_monster(player_ptr, pa_ptr->m_ptr);
 
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
-    if ((r_ptr->flags3 & (RF3_NO_STUN))) {
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
+    if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_STUN)) {
         msg_format(_("%s には効果がなかった。", "%s is not effected."), pa_ptr->m_name);
         return;
     }
@@ -518,7 +525,8 @@ void mineuchi(PlayerType *player_ptr, player_attack_type *pa_ptr)
  */
 void musou_counterattack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
 {
-    if ((!player_ptr->counter && !PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU)) || !monap_ptr->alive || player_ptr->is_dead || !monap_ptr->m_ptr->ml || (player_ptr->csp <= 7)) {
+    const auto is_musou = PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU);
+    if ((!player_ptr->counter && !is_musou) || !monap_ptr->alive || player_ptr->is_dead || !monap_ptr->m_ptr->ml || (player_ptr->csp <= 7)) {
         return;
     }
 
@@ -527,5 +535,5 @@ void musou_counterattack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
     msg_format(_("%s^に反撃した!", "You counterattacked %s!"), m_target_name.data());
     do_cmd_attack(player_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, HISSATSU_COUNTER);
     monap_ptr->fear = false;
-    player_ptr->redraw |= (PR_MP);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
 }
index 4d7c6b6..2aed0ab 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b97146d..d956272 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief スナイパー技能の実装 / Sniping
  * @date 2014/01/18
  * @author
@@ -9,8 +9,6 @@
 #include "action/action-limited.h"
 #include "cmd-action/cmd-shoot.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "floor/geometry.h"
@@ -33,6 +31,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "term/z-form.h"
@@ -128,13 +127,25 @@ static snipe_power const snipe_powers[MAX_SNIPE_POWERS] = {
 #endif
 };
 
+void SniperData::reset_concentration_flag()
+{
+    this->reset_concent = false;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags);
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
+}
+
 /*!
  * @brief スナイパーの集中度加算
  * @return 集中度を加算した場合は true、そうでなければ false
  */
 static bool snipe_concentrate(PlayerType *player_ptr)
 {
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     if (!sniper_data) {
         return false;
     }
@@ -144,10 +155,7 @@ static bool snipe_concentrate(PlayerType *player_ptr)
     }
 
     msg_format(_("集中した。(集中度 %d)", "You concentrate deeply. (lvl %d)"), sniper_data->concent);
-    sniper_data->reset_concent = false;
-
-    player_ptr->update |= (PU_BONUS | PU_MONSTER_STATUSES);
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    sniper_data->reset_concentration_flag();
     return true;
 }
 
@@ -158,7 +166,7 @@ static bool snipe_concentrate(PlayerType *player_ptr)
  */
 void reset_concentration(PlayerType *player_ptr, bool msg)
 {
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     if (!sniper_data) {
         return;
     }
@@ -168,10 +176,7 @@ void reset_concentration(PlayerType *player_ptr, bool msg)
     }
 
     sniper_data->concent = 0;
-    sniper_data->reset_concent = false;
-
-    player_ptr->update |= (PU_BONUS | PU_MONSTER_STATUSES);
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    sniper_data->reset_concentration_flag();
 }
 
 /*!
@@ -181,7 +186,7 @@ void reset_concentration(PlayerType *player_ptr, bool msg)
  */
 int boost_concentration_damage(PlayerType *player_ptr, int tdam)
 {
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     const auto sniper_concent = sniper_data ? sniper_data->concent : 0;
 
     tdam = tdam * (10 + sniper_concent) / 10;
@@ -206,7 +211,7 @@ void display_snipe_list(PlayerType *player_ptr)
     put_str(_("名前", "Name"), y, x + 5);
     put_str(_("Lv   MP", "Lv Mana"), y, x + 35);
 
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
 
     for (i = 0; i < MAX_SNIPE_POWERS; i++) {
         /* Access the available spell */
@@ -247,8 +252,6 @@ static int get_snipe_power(PlayerType *player_ptr, COMMAND_CODE *sn, bool only_b
     TERM_LEN y = 1;
     TERM_LEN x = 20;
     PLAYER_LEVEL plev = player_ptr->lev;
-    char choice;
-    char out_val[160];
     concptr p = _("射撃術", "power");
     snipe_power spell;
     bool flag, redraw;
@@ -258,7 +261,7 @@ static int get_snipe_power(PlayerType *player_ptr, COMMAND_CODE *sn, bool only_b
     /* Assume cancelled */
     *sn = (-1);
 
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
 
     /* Repeat previous command */
     /* Get the spell, if available */
@@ -279,21 +282,25 @@ static int get_snipe_power(PlayerType *player_ptr, COMMAND_CODE *sn, bool only_b
         }
     }
 
-    /* Build a prompt (accept all spells) */
+    std::string fmt;
     if (only_browse) {
-        (void)strnfmt(
-            out_val, 78, _("(%s^ %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? "), p, I2A(0), I2A(num), p);
+        fmt = _("(%s^ %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? ");
     } else {
-        (void)strnfmt(
-            out_val, 78, _("(%s^ %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? "), p, I2A(0), I2A(num), p);
+        fmt = _("(%s^ %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%s^s %c-%c, *=List, ESC=exit) Use which %s? ");
     }
 
-    choice = always_show_list ? ESCAPE : 1;
+    const auto prompt = format(fmt.data(), p, I2A(0), I2A(num), p);
+    auto choice = always_show_list ? ESCAPE : '\1';
     while (!flag) {
         if (choice == ESCAPE) {
             choice = ' ';
-        } else if (!get_com(out_val, &choice, false)) {
-            break;
+        } else {
+            const auto new_choice = input_command(prompt);
+            if (!new_choice) {
+                break;
+            }
+
+            choice = *new_choice;
         }
 
         /* Request redraw */
@@ -313,7 +320,7 @@ static int get_snipe_power(PlayerType *player_ptr, COMMAND_CODE *sn, bool only_b
                 /* Dump the spells */
                 for (i = 0; i < MAX_SNIPE_POWERS; i++) {
                     term_color_type tcol = TERM_WHITE;
-                    term_erase(x, y + i + 1, 255);
+                    term_erase(x, y + i + 1);
 
                     /* Access the spell */
                     spell = snipe_powers[i];
@@ -363,7 +370,7 @@ static int get_snipe_power(PlayerType *player_ptr, COMMAND_CODE *sn, bool only_b
         screen_load();
     }
 
-    player_ptr->window_flags |= (PW_SPELL);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::SPELL);
     handle_stuff(player_ptr);
 
     /* Abort if needed */
@@ -389,10 +396,10 @@ static int get_snipe_power(PlayerType *player_ptr, COMMAND_CODE *sn, bool only_b
  */
 MULTIPLY calc_snipe_damage_with_slay(PlayerType *player_ptr, MULTIPLY mult, MonsterEntity *m_ptr, SPELL_IDX snipe_type)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     bool seen = is_seen(player_ptr, m_ptr);
 
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     const auto sniper_concent = sniper_data ? sniper_data->concent : 0;
 
     switch (snipe_type) {
@@ -597,31 +604,38 @@ static bool cast_sniper_spell(PlayerType *player_ptr, int spell)
  */
 void do_cmd_snipe(PlayerType *player_ptr)
 {
-    COMMAND_CODE n = 0;
-    bool cast;
-
     if (cmd_limit_confused(player_ptr)) {
         return;
     }
+
     if (cmd_limit_image(player_ptr)) {
         return;
     }
+
     if (cmd_limit_stun(player_ptr)) {
         return;
     }
 
+    COMMAND_CODE n = 0;
     if (!get_snipe_power(player_ptr, &n, false)) {
         return;
     }
 
-    cast = cast_sniper_spell(player_ptr, n);
-
-    if (!cast) {
+    if (!cast_sniper_spell(player_ptr, n)) {
         return;
     }
-    player_ptr->redraw |= (PR_HP | PR_MP);
-    player_ptr->window_flags |= (PW_PLAYER);
-    player_ptr->window_flags |= (PW_SPELL);
+
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
+    rfu.set_flags(flags_mwrf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::SPELL,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
@@ -640,11 +654,11 @@ void do_cmd_snipe_browse(PlayerType *player_ptr)
         }
 
         /* Clear lines, position cursor  (really should use strlen here) */
-        term_erase(12, 22, 255);
-        term_erase(12, 21, 255);
-        term_erase(12, 20, 255);
-        term_erase(12, 19, 255);
-        term_erase(12, 18, 255);
+        term_erase(12, 22);
+        term_erase(12, 21);
+        term_erase(12, 20);
+        term_erase(12, 19);
+        term_erase(12, 18);
 
         display_wrap_around(snipe_tips[n], 62, 19, 15);
     }
index d56ba7c..0ccc5a5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 8a68b90..9304b4d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MindKindType {
     MINDCRAFTER = 0, /*!< 特殊能力: 超能力 */
index c5d4061..2ba9ad2 100644 (file)
@@ -1,16 +1,22 @@
-#include "mind/mind-warrior-mage.h"
-#include "core/player-redraw-types.h"
+#include "mind/mind-warrior-mage.h"
 #include "hpmp/hp-mp-processor.h"
 #include "player/player-damage.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 bool comvert_hp_to_mp(PlayerType *player_ptr)
 {
-    int gain_sp = take_hit(player_ptr, DAMAGE_USELIFE, player_ptr->lev, _("HPからMPへの無謀な変換", "thoughtless conversion from HP to SP")) / 5;
+    constexpr auto mes = _("HPからMPへの無謀な変換", "thoughtless conversion from HP to SP");
+    auto gain_sp = take_hit(player_ptr, DAMAGE_USELIFE, player_ptr->lev, mes) / 5;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags = {
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
     if (!gain_sp) {
         msg_print(_("変換に失敗した。", "You failed to convert."));
-        player_ptr->redraw |= (PR_HP | PR_MP);
+        rfu.set_flags(flags);
         return true;
     }
 
@@ -20,7 +26,7 @@ bool comvert_hp_to_mp(PlayerType *player_ptr)
         player_ptr->csp_frac = 0;
     }
 
-    player_ptr->redraw |= (PR_HP | PR_MP);
+    rfu.set_flags(flags);
     return true;
 }
 
@@ -33,6 +39,10 @@ bool comvert_mp_to_hp(PlayerType *player_ptr)
         msg_print(_("変換に失敗した。", "You failed to convert."));
     }
 
-    player_ptr->redraw |= (PR_HP | PR_MP);
+    static constexpr auto flags = {
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     return true;
 }
index 840c00d..e5ca4e3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool comvert_hp_to_mp(PlayerType *player_ptr);
index 119754e..a8ef612 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/mind-warrior.h"
+#include "mind/mind-warrior.h"
 #include "cmd-action/cmd-attack.h"
 #include "floor/geometry.h"
 #include "spell-kind/spells-teleport.h"
@@ -16,7 +16,7 @@
 bool hit_and_away(PlayerType *player_ptr)
 {
     DIRECTION dir;
-    if (!get_direction(player_ptr, &dir, false, false)) {
+    if (!get_direction(player_ptr, &dir)) {
         return false;
     }
     POSITION y = player_ptr->y + ddy[dir];
@@ -45,7 +45,7 @@ bool sword_dancing(PlayerType *player_ptr)
 {
     DIRECTION dir;
     POSITION y = 0, x = 0;
-    grid_type *g_ptr;
+    Grid *g_ptr;
     for (int i = 0; i < 6; i++) {
         dir = randint0(8);
         y = player_ptr->y + ddy_ddd[dir];
index da44de8..c81a27d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool hit_and_away(PlayerType *player_ptr);
index d4f0b4a..5ede516 100644 (file)
@@ -1,8 +1,7 @@
-#include "mind/mind-weaponsmith.h"
+#include "mind/mind-weaponsmith.h"
 #include "action/action-limited.h"
 #include "autopick/autopick.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -21,6 +20,7 @@
 #include "smith/smith-types.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "term/z-form.h"
@@ -30,6 +30,7 @@
 #include "view/display-util.h"
 #include <algorithm>
 #include <sstream>
+#include <string>
 
 static concptr const kaji_tips[5] = {
 #ifdef JP
@@ -104,6 +105,17 @@ static void display_essence(PlayerType *player_ptr)
     return;
 }
 
+static void set_smith_redrawing_flags()
+{
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags);
+    rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
+}
+
 /*!
  * @brief エッセンスの抽出処理
  * @param player_ptr プレイヤーへの参照ポインタ
@@ -113,15 +125,16 @@ static void drain_essence(PlayerType *player_ptr)
     auto q = _("どのアイテムから抽出しますか?", "Extract from which item? ");
     auto s = _("抽出できるアイテムがありません。", "You have nothing you can extract from.");
 
-    OBJECT_IDX item;
-    auto o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), FuncItemTester(&ItemEntity::is_weapon_armour_ammo));
+    short i_idx;
+    constexpr auto options = USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT;
+    auto o_ptr = choose_object(player_ptr, &i_idx, q, s, options, FuncItemTester(&ItemEntity::is_weapon_armour_ammo));
     if (!o_ptr) {
         return;
     }
 
     if (o_ptr->is_known() && !o_ptr->is_nameless()) {
         const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
-        if (!get_check(format(_("本当に%sから抽出してよろしいですか?", "Really extract from %s? "), item_name.data()))) {
+        if (!input_check(format(_("本当に%sから抽出してよろしいですか?", "Really extract from %s? "), item_name.data()))) {
             return;
         }
     }
@@ -143,9 +156,8 @@ static void drain_essence(PlayerType *player_ptr)
     }
 
     /* Apply autodestroy/inscription to the drained item */
-    autopick_alter_item(player_ptr, item, true);
-    player_ptr->update |= (PU_COMBINATION | PU_REORDER);
-    player_ptr->window_flags |= (PW_INVENTORY);
+    autopick_alter_item(player_ptr, i_idx, true);
+    set_smith_redrawing_flags();
 }
 
 /*!
@@ -215,17 +227,17 @@ static COMMAND_CODE choose_essence(void)
     } else {
         screen_save();
         while (!mode) {
-            int i;
-
-            for (i = 0; i < mode_max; i++) {
+            for (short i = 0; i < mode_max; i++) {
                 prt(format("  %c) %s", 'a' + i, menu_name[i]), 2 + i, 14);
             }
 
-            if (!get_com(_("何を付加しますか:", "Command :"), &choice, true)) {
+            const auto new_choice = input_command(_("何を付加しますか:", "Command :"), true);
+            if (!new_choice) {
                 screen_load();
                 return 0;
             }
 
+            choice = *new_choice;
             if (isupper(choice)) {
                 choice = (char)tolower(choice);
             }
@@ -304,12 +316,6 @@ static void display_smith_effect_list(const Smith &smith, const std::vector<Smit
  */
 static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
 {
-    OBJECT_IDX item;
-    bool flag;
-    char choice;
-    concptr q, s;
-    ItemEntity *o_ptr;
-    char out_val[160];
     int menu_line = (use_menu ? 1 : 0);
 
     Smith smith(player_ptr);
@@ -322,31 +328,32 @@ static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
 
     COMMAND_CODE i = -1;
     COMMAND_CODE effect_idx;
-
+    bool flag;
     if (!repeat_pull(&effect_idx) || effect_idx < 0 || effect_idx >= smith_effect_list_max) {
         flag = false;
 
         screen_save();
 
         while (!flag) {
+            std::string prompt;
             if (page_max > 1) {
-                std::string page_str = format("%d/%d", page + 1, page_max);
-                strnfmt(out_val, 78, _("(SPACEで次ページ, ESCで中断) どの能力を付加しますか? %s", "(SPACE=next, ESC=exit) Add which ability? %s"), page_str.data());
+                const auto page_str = format("%d/%d", page + 1, page_max);
+                prompt = format(_("(SPACEで次ページ, ESCで中断) どの能力を付加しますか? %s", "(SPACE=next, ESC=exit) Add which ability? %s"), page_str.data());
             } else {
-                strnfmt(out_val, 78, _("(ESCで中断) どの能力を付加しますか?", "(ESC=exit) Add which ability? "));
+                prompt = format(_("(ESCで中断) どの能力を付加しますか?", "(ESC=exit) Add which ability? "));
             }
 
             display_smith_effect_list(smith, smith_effect_list, menu_line, page * effect_num_per_page, effect_num_per_page);
 
             const auto page_effect_num = std::min<int>(effect_num_per_page, smith_effect_list.size() - (page * effect_num_per_page));
-
-            if (!get_com(out_val, &choice, false)) {
+            const auto choice = input_command(prompt);
+            if (!choice) {
                 break;
             }
 
             auto should_redraw_cursor = true;
             if (use_menu) {
-                switch (choice) {
+                switch (*choice) {
                 case '0': {
                     screen_load();
                     return;
@@ -411,7 +418,7 @@ static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
             }
 
             if (!use_menu) {
-                i = A2I(choice);
+                i = A2I(*choice);
             }
 
             effect_idx = page * effect_num_per_page + i;
@@ -438,10 +445,10 @@ static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
 
     auto item_tester = Smith::get_item_tester(effect);
 
-    q = _("どのアイテムを改良しますか?", "Improve which item? ");
-    s = _("改良できるアイテムがありません。", "You have nothing to improve.");
-
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
+    constexpr auto q = _("どのアイテムを改良しますか?", "Improve which item? ");
+    constexpr auto s = _("改良できるアイテムがありません。", "You have nothing to improve.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
     if (!o_ptr) {
         return;
     }
@@ -457,6 +464,7 @@ static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
         return;
     }
 
+    constexpr auto prompt = _("いくつ付加しますか?", "Enchant how many?");
     const auto attribute_flags = Smith::get_effect_tr_flags(effect);
     auto add_essence_count = 1;
     if (attribute_flags.has_any_of(TR_PVAL_FLAG_MASK)) {
@@ -464,28 +472,29 @@ static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
             msg_print(_("このアイテムの能力修正を強化することはできない。", "You cannot increase magic number of this item."));
             return;
         } else if (attribute_flags.has(TR_BLOWS)) {
-            if ((o_ptr->pval > 1) && !get_check(_("修正値は1になります。よろしいですか?", "The magic number of this weapon will become 1. Are you sure? "))) {
+            if ((o_ptr->pval > 1) && !input_check(_("修正値は1になります。よろしいですか?", "The magic number of this weapon will become 1. Are you sure? "))) {
                 return;
             }
             o_ptr->pval = 1;
         } else if (o_ptr->pval == 0) {
-            char tmp_val[8] = "1";
-            auto limit = std::min(5, smith.get_addable_count(effect, o_ptr));
-
-            if (!get_string(format(_("いくつ付加しますか? (1-%d): ", "Enchant how many? (1-%d): "), limit), tmp_val, 1)) {
+            const auto limit = std::min(5, smith.get_addable_count(effect, o_ptr));
+            const auto num_enchants = input_numerics<short>(prompt, 1, limit, 1);
+            if (!num_enchants) {
                 return;
             }
-            o_ptr->pval = static_cast<PARAMETER_VALUE>(std::clamp(atoi(tmp_val), 1, limit));
+
+            o_ptr->pval = *num_enchants;
         }
 
         add_essence_count = o_ptr->pval;
     } else if (effect == SmithEffectType::SLAY_GLOVE) {
-        char tmp_val[8] = "1";
         const auto max_val = player_ptr->lev / 7 + 3;
-        if (!get_string(format(_("いくつ付加しますか? (1-%d):", "Enchant how many? (1-%d):"), max_val), tmp_val, 2)) {
+        const auto num_enchants = input_numerics(prompt, 1, max_val, 1);
+        if (!num_enchants) {
             return;
         }
-        add_essence_count = std::clamp(atoi(tmp_val), 1, max_val);
+
+        add_essence_count = *num_enchants;
     }
 
     msg_format(_("エッセンスを%d個使用します。", "It will take %d essences."), use_essence * add_essence_count);
@@ -505,8 +514,7 @@ static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
     auto effect_name = Smith::get_effect_name(effect);
 
     _(msg_format("%sに%sの能力を付加しました。", item_name.data(), effect_name), msg_format("You have added ability of %s to %s.", effect_name, item_name.data()));
-    player_ptr->update |= (PU_COMBINATION | PU_REORDER);
-    player_ptr->window_flags |= (PW_INVENTORY);
+    set_smith_redrawing_flags();
 }
 
 /*!
@@ -514,16 +522,16 @@ static void add_essence(PlayerType *player_ptr, SmithCategoryType mode)
  */
 static void erase_essence(PlayerType *player_ptr)
 {
-    const auto q = _("どのアイテムのエッセンスを消去しますか?", "Remove from which item? ");
-    const auto s = _("エッセンスを付加したアイテムがありません。", "You have nothing with added essence to remove.");
-    OBJECT_IDX item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::is_smith));
+    constexpr auto q = _("どのアイテムのエッセンスを消去しますか?", "Remove from which item? ");
+    constexpr auto s = _("エッセンスを付加したアイテムがありません。", "You have nothing with added essence to remove.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::is_smith));
     if (!o_ptr) {
         return;
     }
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
-    if (!get_check(format(_("よろしいですか? [%s]", "Are you sure? [%s]"), item_name.data()))) {
+    if (!input_check(format(_("よろしいですか? [%s]", "Are you sure? [%s]"), item_name.data()))) {
         return;
     }
 
@@ -532,8 +540,7 @@ static void erase_essence(PlayerType *player_ptr)
     Smith(player_ptr).erase_essence(o_ptr);
 
     msg_print(_("エッセンスを取り去った。", "You removed all essence you have added."));
-    player_ptr->update |= (PU_COMBINATION | PU_REORDER);
-    player_ptr->window_flags |= (PW_INVENTORY);
+    set_smith_redrawing_flags();
 }
 
 /*!
@@ -543,32 +550,33 @@ static void erase_essence(PlayerType *player_ptr)
 void do_cmd_kaji(PlayerType *player_ptr, bool only_browse)
 {
     COMMAND_CODE mode = 0;
-    char choice;
-
     COMMAND_CODE menu_line = (use_menu ? 1 : 0);
-
     if (!only_browse) {
         if (cmd_limit_confused(player_ptr)) {
             return;
         }
+
         if (cmd_limit_blind(player_ptr)) {
             return;
         }
+
         if (cmd_limit_image(player_ptr)) {
             return;
         }
     }
 
-    if (!(repeat_pull(&mode) && 1 <= mode && mode <= 5)) {
+    if (!(repeat_pull(&mode) && (1 <= mode) && (mode <= 5))) {
         if (only_browse) {
             screen_save();
         }
+
         do {
             if (!only_browse) {
                 screen_save();
             }
+
             if (use_menu) {
-                while (!mode) {
+                while (mode == 0) {
 #ifdef JP
                     prt(format(" %s エッセンス一覧", (menu_line == 1) ? "》" : "  "), 2, 14);
                     prt(format(" %s エッセンス抽出", (menu_line == 2) ? "》" : "  "), 3, 14);
@@ -584,7 +592,7 @@ void do_cmd_kaji(PlayerType *player_ptr, bool only_browse)
                     prt(format(" %s Enchant weapon/armor", (menu_line == 5) ? "> " : "  "), 6, 14);
                     prt(format("Choose command from menu."), 0, 0);
 #endif
-                    choice = inkey();
+                    const auto choice = inkey();
                     switch (choice) {
                     case ESCAPE:
                     case 'z':
@@ -608,29 +616,26 @@ void do_cmd_kaji(PlayerType *player_ptr, bool only_browse)
                         mode = menu_line;
                         break;
                     }
+
                     if (menu_line > 5) {
                         menu_line -= 5;
                     }
                 }
-            }
-
-            else {
-                while (!mode) {
+            } else {
+                while (mode == 0) {
                     prt(_("  a) エッセンス一覧", "  a) List essences"), 2, 14);
                     prt(_("  b) エッセンス抽出", "  b) Extract essence"), 3, 14);
                     prt(_("  c) エッセンス消去", "  c) Remove essence"), 4, 14);
                     prt(_("  d) エッセンス付加", "  d) Add essence"), 5, 14);
                     prt(_("  e) 武器/防具強化", "  e) Enchant weapon/armor"), 6, 14);
-#ifdef JP
-                    if (!get_com(format("どの能力を%sますか:", only_browse ? "調べ" : "使い"), &choice, true))
-#else
-                    if (!get_com("Command :", &choice, true))
-#endif
-                    {
+                    std::string prompt = _(format("どの能力を%sますか:", only_browse ? "調べ" : "使い"), "Command :");
+                    const auto choice = input_command(prompt, true);
+                    if (!choice) {
                         screen_load();
                         return;
                     }
-                    switch (choice) {
+
+                    switch (*choice) {
                     case 'A':
                     case 'a':
                         mode = 1;
@@ -656,23 +661,26 @@ void do_cmd_kaji(PlayerType *player_ptr, bool only_browse)
             }
 
             if (only_browse) {
-                /* Clear lines, position cursor  (really should use strlen here) */
-                term_erase(14, 21, 255);
-                term_erase(14, 20, 255);
-                term_erase(14, 19, 255);
-                term_erase(14, 18, 255);
-                term_erase(14, 17, 255);
-                term_erase(14, 16, 255);
-
-                display_wrap_around(kaji_tips[mode - 1], 62, 17, 15);
+                term_erase(14, 21);
+                term_erase(14, 20);
+                term_erase(14, 19);
+                term_erase(14, 18);
+                term_erase(14, 17);
+                term_erase(14, 16);
+                if (mode > 0) {
+                    display_wrap_around(kaji_tips[mode - 1], 62, 17, 15);
+                }
+
                 mode = 0;
             }
+
             if (!only_browse) {
                 screen_load();
             }
         } while (only_browse);
         repeat_push(mode);
     }
+
     switch (mode) {
     case 1:
         display_essence(player_ptr);
@@ -688,6 +696,7 @@ void do_cmd_kaji(PlayerType *player_ptr, bool only_browse)
         if (mode == 0) {
             break;
         }
+
         add_essence(player_ptr, i2enum<SmithCategoryType>(mode));
         break;
     case 5:
index 0c26dca..c7ddc8a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_kaji(PlayerType *player_ptr, bool only_browse);
index 3f67fc1..23bc1ed 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 素手で攻撃することに補正のある職業 (修行僧、狂戦士、練気術師)の打撃処理
  * @date 2020/05/23
  * @author Hourier
@@ -20,7 +20,7 @@
 #include "monster-race/race-flags3.h"
 #include "monster/monster-status-setter.h"
 #include "monster/monster-status.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "player-base/player-class.h"
 #include "player-info/monk-data-type.h"
 #include "player/attack-defense-types.h"
  */
 static int calc_stun_resistance(player_attack_type *pa_ptr)
 {
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     int resist_stun = 0;
     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
         resist_stun += 88;
     }
 
-    if (r_ptr->flags3 & RF3_NO_STUN) {
+    if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_STUN)) {
         resist_stun += 66;
     }
 
-    if (r_ptr->flags3 & RF3_NO_CONF) {
+    if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
         resist_stun += 33;
     }
 
-    if (r_ptr->flags3 & RF3_NO_SLEEP) {
+    if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_SLEEP)) {
         resist_stun += 33;
     }
 
@@ -106,7 +106,7 @@ static int select_blow(PlayerType *player_ptr, player_attack_type *pa_ptr, int m
     const martial_arts *old_ptr = &ma_blows[0];
     for (int times = 0; times < max_blow_selection_times; times++) {
         do {
-            pa_ptr->ma_ptr = &ma_blows[randint0(MAX_MA)];
+            pa_ptr->ma_ptr = &rand_choice(ma_blows);
             if (PlayerClass(player_ptr).equals(PlayerClassType::FORCETRAINER) && (pa_ptr->ma_ptr->min_level > 1)) {
                 min_level = pa_ptr->ma_ptr->min_level + 3;
             } else {
@@ -140,9 +140,9 @@ static int select_blow(PlayerType *player_ptr, player_attack_type *pa_ptr, int m
 static int process_monk_additional_effect(player_attack_type *pa_ptr, int *stun_effect)
 {
     int special_effect = 0;
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     if (pa_ptr->ma_ptr->effect == MA_KNEE) {
-        if (r_ptr->flags1 & RF1_MALE) {
+        if (is_male(*r_ptr)) {
             msg_format(_("%sに金的膝蹴りをくらわした!", "You hit %s in the groin with your knee!"), pa_ptr->m_name);
             sound(SOUND_PAIN);
             special_effect = MA_KNEE;
@@ -202,7 +202,7 @@ static WEIGHT calc_monk_attack_weight(PlayerType *player_ptr)
  */
 static void process_attack_vital_spot(PlayerType *player_ptr, player_attack_type *pa_ptr, int *stun_effect, int *resist_stun, const int special_effect)
 {
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     if ((special_effect == MA_KNEE) && ((pa_ptr->attack_damage + player_ptr->to_d[pa_ptr->hand]) < pa_ptr->m_ptr->hp)) {
         msg_format(_("%s^は苦痛にうめいている!", "%s^ moans in agony!"), pa_ptr->m_name);
         *stun_effect = 7 + randint1(13);
@@ -229,7 +229,7 @@ static void process_attack_vital_spot(PlayerType *player_ptr, player_attack_type
  */
 static void print_stun_effect(PlayerType *player_ptr, player_attack_type *pa_ptr, const int stun_effect, const int resist_stun)
 {
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     if (stun_effect && ((pa_ptr->attack_damage + player_ptr->to_d[pa_ptr->hand]) < pa_ptr->m_ptr->hp)) {
         if (player_ptr->lev > randint1(r_ptr->level + resist_stun + 10)) {
             if (set_monster_stunned(player_ptr, pa_ptr->g_ptr->m_idx, stun_effect + pa_ptr->m_ptr->get_remaining_stun())) {
@@ -269,7 +269,7 @@ void process_monk_attack(PlayerType *player_ptr, player_attack_type *pa_ptr)
 bool double_attack(PlayerType *player_ptr)
 {
     DIRECTION dir;
-    if (!get_rep_dir(player_ptr, &dir, false)) {
+    if (!get_rep_dir(player_ptr, &dir)) {
         return false;
     }
     POSITION y = player_ptr->y + ddy[dir];
index 999d785..4aa11a3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct player_attack_type;
 class PlayerType;
index 2ea2420..6bdad9d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum snipe_type {
     SP_NONE = 0,
index b6a9686..e69a7f0 100644 (file)
@@ -1,4 +1,4 @@
-#include "mind/stances-table.h"
+#include "mind/stances-table.h"
 
 /*!
  * @brief 修行僧の構え能力テーブル
index 06b5d63..213e274 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player/special-defense-types.h"
 #include "system/angband.h"
index 1c3209b..58a8933 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-attack/insults-moans.h"
+#include "monster-attack/insults-moans.h"
 
 /*! モンスターの侮辱行為メッセージテーブル / Hack -- possible "insult" messages */
 concptr desc_insult[MAX_INSULTS] = {
index a52e5ae..01a3381 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 21dab62..174d39c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの打撃種別を記述すると共に、切り傷/朦朧値を追加する
  * @date 2020/05/31
  * @author Hourier
 static void show_jaian_song(MonsterAttackPlayer *monap_ptr)
 {
 #ifdef JP
-    switch (randint1(15)) {
-    case 1:
-    case 6:
-    case 11:
-        monap_ptr->act = "「♪お~れはジャイアン~~ガ~キだいしょう~」";
-        break;
-    case 2:
-        monap_ptr->act = "「♪て~んかむ~てきのお~とこだぜ~~」";
-        break;
-    case 3:
-        monap_ptr->act = "「♪の~び太スネ夫はメじゃないよ~~」";
-        break;
-    case 4:
-        monap_ptr->act = "「♪け~んかスポ~ツ~どんとこい~」";
-        break;
-    case 5:
-        monap_ptr->act = "「♪うた~も~~う~まいぜ~まかしとけ~」";
-        break;
-    case 7:
-        monap_ptr->act = "「♪ま~ちいちば~んのに~んきもの~~」";
-        break;
-    case 8:
-        monap_ptr->act = "「♪べんきょうしゅくだいメじゃないよ~~」";
-        break;
-    case 9:
-        monap_ptr->act = "「♪きはやさし~くて~ち~からもち~」";
-        break;
-    case 10:
-        monap_ptr->act = "「♪かお~も~~スタイルも~バツグンさ~」";
-        break;
-    case 12:
-        monap_ptr->act = "「♪がっこうい~ちの~あ~ばれんぼう~~」";
-        break;
-    case 13:
-        monap_ptr->act = "「♪ド~ラもドラミもメじゃないよ~~」";
-        break;
-    case 14:
-        monap_ptr->act = "「♪よじげんぽけっと~な~くたって~」";
-        break;
-    case 15:
-        monap_ptr->act = "「♪あし~の~~ながさ~は~まけないぜ~」";
-        break;
-    }
+    constexpr static auto songs = {
+        "「♪お~れはジャイアン~~ガ~キだいしょう~」",
+        "「♪て~んかむ~てきのお~とこだぜ~~」",
+        "「♪の~び太スネ夫はメじゃないよ~~」",
+        "「♪け~んかスポ~ツ~どんとこい~」",
+        "「♪うた~も~~う~まいぜ~まかしとけ~」",
+        "「♪お~れはジャイアン~~ガ~キだいしょう~」",
+        "「♪ま~ちいちば~んのに~んきもの~~」",
+        "「♪べんきょうしゅくだいメじゃないよ~~」",
+        "「♪きはやさし~くて~ち~からもち~」",
+        "「♪かお~も~~スタイルも~バツグンさ~」",
+        "「♪お~れはジャイアン~~ガ~キだいしょう~」",
+        "「♪がっこうい~ちの~あ~ばれんぼう~~」",
+        "「♪ド~ラもドラミもメじゃないよ~~」",
+        "「♪よじげんぽけっと~な~くたって~」",
+        "「♪あし~の~~ながさ~は~まけないぜ~」",
+    };
+
+    monap_ptr->act = rand_choice(songs);
 #else
     monap_ptr->act = "horribly sings 'I AM GIAAAAAN. THE BOOOSS OF THE KIIIIDS.'";
 #endif
@@ -236,7 +212,7 @@ void describe_monster_attack_method(MonsterAttackPlayer *monap_ptr)
 #ifdef JP
         monap_ptr->abbreviate = -1;
 #endif
-        monap_ptr->act = desc_moan[randint0(4)];
+        monap_ptr->act = rand_choice(desc_moan);
         sound(SOUND_MOAN);
         break;
     }
index 16dc6f5..6fb7b17 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class MonsterAttackPlayer;
 void describe_monster_attack_method(MonsterAttackPlayer *monap_ptr);
index b31470a..ce1ff7b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @note モンスターの攻撃効果 / New monster blow effects
@@ -45,6 +45,7 @@ enum class RaceBlowEffectType : int {
     STUN = 35, /*!< モンスターの攻撃効果: 朦朧とさせる*/
     FLAVOR = 36, /*!< モンスターの攻撃効果: フレーバー(メッセージ表示のみ) */
     HUNGRY = 37, /*!< モンスターの攻撃効果: 空腹を進行させる*/
+    CHAOS = 38, /*!< モンスターの攻撃効果: カオスを呼び起こす*/
 
     MAX, /*!< 最大値 */
 };
index 89be1d2..2030bae 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-attack/monster-attack-lose.h"
+#include "monster-attack/monster-attack-lose.h"
 #include "mind/mind-mirror-master.h"
 #include "monster-attack/monster-attack-player.h"
 #include "monster-attack/monster-attack-status.h"
index a3e0e5b..9ff3941 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class MonsterAttackPlayer;
 class PlayerType;
index e29c62f..c72ec67 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターからプレイヤーへの直接攻撃処理
  * @date 2020/05/23
  * @author Hourier
@@ -13,7 +13,6 @@
 #include "combat/combat-options-type.h"
 #include "combat/hallucination-attacks-table.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/geometry.h"
 #include "inventory/inventory-slot-types.h"
@@ -53,6 +52,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-cut.h"
 #include "timed-effect/player-hallucination.h"
 #include "timed-effect/player-stun.h"
@@ -85,10 +85,10 @@ void MonsterAttackPlayer::make_attack_normal()
         return;
     }
 
-    auto *r_ptr = &monraces_info[this->m_ptr->r_idx];
+    auto *r_ptr = &this->m_ptr->get_monrace();
     this->rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);
-    angband_strcpy(this->m_name, monster_desc(this->player_ptr, this->m_ptr, 0).data(), sizeof(this->m_name));
-    angband_strcpy(this->ddesc, monster_desc(this->player_ptr, this->m_ptr, MD_WRONGDOER_NAME).data(), sizeof(this->ddesc));
+    angband_strcpy(this->m_name, monster_desc(this->player_ptr, this->m_ptr, 0), sizeof(this->m_name));
+    angband_strcpy(this->ddesc, monster_desc(this->player_ptr, this->m_ptr, MD_WRONGDOER_NAME), sizeof(this->ddesc));
     if (PlayerClass(this->player_ptr).samurai_stance_is(SamuraiStanceType::IAI)) {
         msg_print(_("相手が襲いかかる前に素早く武器を振るった。", format("You took sen, drew and cut in one motion before %s moved.", this->m_name)));
         if (do_cmd_attack(this->player_ptr, this->m_ptr->fy, this->m_ptr->fx, HISSATSU_IAI)) {
@@ -126,12 +126,12 @@ int MonsterAttackPlayer::stat_value(const int raw)
 
 bool MonsterAttackPlayer::check_no_blow()
 {
-    auto *r_ptr = &monraces_info[this->m_ptr->r_idx];
+    auto *r_ptr = &this->m_ptr->get_monrace();
     if (r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_BLOW)) {
         return false;
     }
 
-    if (dungeons_info[this->player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
+    if (this->player_ptr->current_floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::NO_MELEE)) {
         return false;
     }
 
@@ -144,15 +144,15 @@ bool MonsterAttackPlayer::check_no_blow()
  */
 bool MonsterAttackPlayer::process_monster_blows()
 {
-    auto *r_ptr = &monraces_info[this->m_ptr->r_idx];
+    auto *r_ptr = &this->m_ptr->get_monrace();
     for (auto ap_cnt = 0; ap_cnt < MAX_NUM_BLOWS; ap_cnt++) {
         this->obvious = false;
         this->damage = 0;
         this->act = nullptr;
-        this->effect = r_ptr->blow[ap_cnt].effect;
-        this->method = r_ptr->blow[ap_cnt].method;
-        this->d_dice = r_ptr->blow[ap_cnt].d_dice;
-        this->d_side = r_ptr->blow[ap_cnt].d_side;
+        this->effect = r_ptr->blows[ap_cnt].effect;
+        this->method = r_ptr->blows[ap_cnt].method;
+        this->d_dice = r_ptr->blows[ap_cnt].d_dice;
+        this->d_side = r_ptr->blows[ap_cnt].d_side;
 
         if (!this->check_monster_continuous_attack()) {
             break;
@@ -219,7 +219,7 @@ bool MonsterAttackPlayer::check_monster_continuous_attack()
         return false;
     }
 
-    auto *r_ptr = &monraces_info[this->m_ptr->r_idx];
+    auto *r_ptr = &this->m_ptr->get_monrace();
     if (this->m_ptr->is_pet() && r_ptr->kind_flags.has(MonsterKindType::UNIQUE) && (this->method == RaceBlowMethodType::EXPLODE)) {
         this->method = RaceBlowMethodType::HIT;
         this->d_dice /= 10;
@@ -268,7 +268,7 @@ bool MonsterAttackPlayer::process_monster_attack_hit()
  */
 bool MonsterAttackPlayer::effect_protecion_from_evil()
 {
-    auto *r_ptr = &monraces_info[this->m_ptr->r_idx];
+    auto *r_ptr = &this->m_ptr->get_monrace();
     if ((this->player_ptr->protevil <= 0) || r_ptr->kind_flags.has_not(MonsterKindType::EVIL) || (this->player_ptr->lev < this->rlev) || ((randint0(100) + this->player_ptr->lev) <= 50)) {
         return false;
     }
@@ -297,7 +297,7 @@ void MonsterAttackPlayer::describe_silly_attacks()
 #ifdef JP
         this->abbreviate = -1;
 #endif
-        this->act = silly_attacks[randint0(MAX_SILLY_ATTACK)];
+        this->act = rand_choice(silly_attacks);
     }
 
 #ifdef JP
@@ -395,7 +395,7 @@ void MonsterAttackPlayer::monster_explode()
 
     sound(SOUND_EXPLODE);
     MonsterDamageProcessor mdp(this->player_ptr, this->m_idx, this->m_ptr->hp + 1, &this->fear, AttributeType::NONE);
-    if (mdp.mon_take_hit(nullptr)) {
+    if (mdp.mon_take_hit("")) {
         this->blinked = false;
         this->alive = false;
     }
@@ -465,7 +465,7 @@ void MonsterAttackPlayer::gain_armor_exp()
         return;
     }
 
-    auto *r_ptr = &monraces_info[this->m_ptr->r_idx];
+    auto *r_ptr = &this->m_ptr->get_monrace();
     auto target_level = r_ptr->level;
     short increment = 0;
     if ((cur / 100) < target_level) {
@@ -474,7 +474,7 @@ void MonsterAttackPlayer::gain_armor_exp()
     }
 
     this->player_ptr->skill_exp[PlayerSkillKindType::SHIELD] = std::min<short>(max, cur + increment);
-    this->player_ptr->update |= (PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 /*!
@@ -490,7 +490,7 @@ void MonsterAttackPlayer::increase_blow_type_seen(const int ap_cnt)
         return;
     }
 
-    auto *r_ptr = &monraces_info[this->m_ptr->r_idx];
+    auto *r_ptr = &this->m_ptr->get_monrace();
     if (!this->obvious && (this->damage == 0) && (r_ptr->r_blows[ap_cnt] <= 10)) {
         return;
     }
@@ -507,7 +507,7 @@ void MonsterAttackPlayer::postprocess_monster_blows()
     spell_hex.eyes_on_eyes();
     musou_counterattack(this->player_ptr, this);
     spell_hex.thief_teleport();
-    auto *r_ptr = &monraces_info[this->m_ptr->r_idx];
+    auto *r_ptr = &this->m_ptr->get_monrace();
     if (this->player_ptr->is_dead && (r_ptr->r_deaths < MAX_SHORT) && !this->player_ptr->current_floor_ptr->inside_arena) {
         r_ptr->r_deaths++;
     }
index 39e5cf6..d5ddf1b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの攻撃に関する処理
  * @date 2020/03/08
  * @author Hourier
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
  * @param m_idx モンスターID
- * @param ny 移動後の、モンスターのY座標
- * @param nx 移動後の、モンスターのX座標
+ * @param pos モンスターの移動先座標
  * @details
  * 反攻撃の洞窟など、直接攻撃ができない場所では処理をスキップする
  */
-void exe_monster_attack_to_player(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, POSITION ny, POSITION nx)
+void exe_monster_attack_to_player(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, const Pos2D &pos)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (!turn_flags_ptr->do_move || !player_bold(player_ptr, ny, nx)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto *m_ptr = &floor.m_list[m_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
+    if (!turn_flags_ptr->do_move || !player_ptr->is_located_at(pos)) {
         return;
     }
 
@@ -50,7 +50,7 @@ void exe_monster_attack_to_player(PlayerType *player_ptr, turn_flags *turn_flags
         turn_flags_ptr->do_move = false;
     }
 
-    if (turn_flags_ptr->do_move && dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE) && !m_ptr->is_confused()) {
+    if (turn_flags_ptr->do_move && floor.get_dungeon_definition().flags.has(DungeonFeatureType::NO_MELEE) && !m_ptr->is_confused()) {
         if (r_ptr->behavior_flags.has_not(MonsterBehaviorType::STUPID)) {
             turn_flags_ptr->do_move = false;
         } else if (is_original_ap_and_seen(player_ptr, m_ptr)) {
@@ -75,10 +75,11 @@ void exe_monster_attack_to_player(PlayerType *player_ptr, turn_flags *turn_flags
  * @param m_idx モンスターID
  * @param g_ptr グリッドへの参照ポインタ
  */
-static bool exe_monster_attack_to_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, grid_type *g_ptr)
+static bool exe_monster_attack_to_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, Grid *g_ptr)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto *m_ptr = &floor.m_list[m_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     MonsterEntity *y_ptr;
     y_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
     if (r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_BLOW)) {
@@ -95,7 +96,7 @@ static bool exe_monster_attack_to_monster(PlayerType *player_ptr, MONSTER_IDX m_
     if (monst_attack_monst(player_ptr, m_idx, g_ptr->m_idx)) {
         return true;
     }
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::NO_MELEE)) {
+    if (floor.get_dungeon_definition().flags.has_not(DungeonFeatureType::NO_MELEE)) {
         return false;
     }
     if (m_ptr->is_confused()) {
@@ -121,33 +122,29 @@ static bool exe_monster_attack_to_monster(PlayerType *player_ptr, MONSTER_IDX m_
  * @param can_cross モンスターが地形を踏破できるならばTRUE
  * @return ターン消費が発生したらTRUE
  */
-bool process_monster_attack_to_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, grid_type *g_ptr, bool can_cross)
+bool process_monster_attack_to_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, Grid *g_ptr, bool can_cross)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    MonsterEntity *y_ptr;
-    y_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
     if (!turn_flags_ptr->do_move || (g_ptr->m_idx == 0)) {
         return false;
     }
 
-    MonsterRaceInfo *z_ptr = &monraces_info[y_ptr->r_idx];
     turn_flags_ptr->do_move = false;
-
-    bool do_kill_body = r_ptr->behavior_flags.has(MonsterBehaviorType::KILL_BODY) && r_ptr->behavior_flags.has_not(MonsterBehaviorType::NEVER_BLOW);
-    do_kill_body &= (r_ptr->mexp * r_ptr->level > z_ptr->mexp * z_ptr->level);
+    const auto &monster_from = player_ptr->current_floor_ptr->m_list[m_idx];
+    const auto &monrace_from = monster_from.get_monrace();
+    const auto &monster_to = player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
+    const auto &monrace_to = monster_to.get_monrace();
+    auto do_kill_body = monrace_from.behavior_flags.has(MonsterBehaviorType::KILL_BODY) && monrace_from.behavior_flags.has_not(MonsterBehaviorType::NEVER_BLOW);
+    do_kill_body &= (monrace_from.mexp * monrace_from.level > monrace_to.mexp * monrace_to.level);
     do_kill_body &= (g_ptr->m_idx != player_ptr->riding);
-
-    if (do_kill_body || are_enemies(player_ptr, *m_ptr, *y_ptr) || m_ptr->is_confused()) {
+    if (do_kill_body || monster_from.is_hostile_to_melee(monster_to) || monster_from.is_confused()) {
         return exe_monster_attack_to_monster(player_ptr, m_idx, g_ptr);
     }
 
-    bool do_move_body = r_ptr->behavior_flags.has(MonsterBehaviorType::MOVE_BODY) && r_ptr->behavior_flags.has_not(MonsterBehaviorType::NEVER_MOVE);
-    do_move_body &= (r_ptr->mexp > z_ptr->mexp);
+    auto do_move_body = monrace_from.behavior_flags.has(MonsterBehaviorType::MOVE_BODY) && monrace_from.behavior_flags.has_not(MonsterBehaviorType::NEVER_MOVE);
+    do_move_body &= (monrace_from.mexp > monrace_to.mexp);
     do_move_body &= can_cross;
     do_move_body &= (g_ptr->m_idx != player_ptr->riding);
-    do_move_body &= monster_can_cross_terrain(player_ptr, player_ptr->current_floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, z_ptr, 0);
-
+    do_move_body &= monster_can_cross_terrain(player_ptr, player_ptr->current_floor_ptr->grid_array[monster_from.fy][monster_from.fx].feat, &monrace_to, 0);
     if (do_move_body) {
         turn_flags_ptr->do_move = true;
         turn_flags_ptr->did_move_body = true;
index 62afc43..4378fca 100644 (file)
@@ -1,10 +1,10 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
+#include "util/point-2d.h"
 
-struct grid_type;
-;
+class Grid;
 class PlayerType;
 struct turn_flags;
-void exe_monster_attack_to_player(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, POSITION ny, POSITION nx);
-bool process_monster_attack_to_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, grid_type *g_ptr, bool can_cross);
+void exe_monster_attack_to_player(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, const Pos2D &pos);
+bool process_monster_attack_to_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, Grid *g_ptr, bool can_cross);
index 2b364f3..badeabf 100644 (file)
@@ -1,11 +1,10 @@
-/*!
+/*!
  * @brief プレイヤーのステータス (麻痺等)に影響を与えるモンスターの打撃処理
  * @date 2020/05/31
  * @author Hourier
  */
 
 #include "monster-attack/monster-attack-status.h"
-#include "core/player-update-types.h"
 #include "mind/mind-mirror-master.h"
 #include "monster-attack/monster-attack-player.h"
 #include "monster-race/monster-race.h"
@@ -53,7 +52,7 @@ void process_terrify_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_p
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (has_resist_fear(player_ptr)) {
         msg_print(_("しかし恐怖に侵されなかった!", "You stand your ground!"));
         monap_ptr->obvious = true;
@@ -77,7 +76,7 @@ void process_paralyze_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (player_ptr->free_act) {
         msg_print(_("しかし効果がなかった!", "You are unaffected!"));
         monap_ptr->obvious = true;
@@ -129,49 +128,13 @@ void process_stun_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
         return;
     }
 
-    auto *r_ptr = &monraces_info[monap_ptr->m_ptr->r_idx];
+    auto *r_ptr = &monap_ptr->m_ptr->get_monrace();
     if (BadStatusSetter(player_ptr).mod_stun(10 + randint1(r_ptr->level / 4))) {
         monap_ptr->obvious = true;
     }
 }
 
-/*!
- * @brief 時間逆転攻撃による能力低下
- * @param player_ptr プレイヤーへの参照ポインタ
- * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
- */
-static void describe_disability(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
-{
-    int stat = randint0(6);
-    switch (stat) {
-    case A_STR:
-        monap_ptr->act = _("強く", "strong");
-        break;
-    case A_INT:
-        monap_ptr->act = _("聡明で", "bright");
-        break;
-    case A_WIS:
-        monap_ptr->act = _("賢明で", "wise");
-        break;
-    case A_DEX:
-        monap_ptr->act = _("器用で", "agile");
-        break;
-    case A_CON:
-        monap_ptr->act = _("健康で", "hale");
-        break;
-    case A_CHR:
-        monap_ptr->act = _("美しく", "beautiful");
-        break;
-    }
-
-    msg_format(_("あなたは以前ほど%sなくなってしまった...。", "You're not as %s as you used to be..."), monap_ptr->act);
-    player_ptr->stat_cur[stat] = (player_ptr->stat_cur[stat] * 3) / 4;
-    if (player_ptr->stat_cur[stat] < 3) {
-        player_ptr->stat_cur[stat] = 3;
-    }
-}
-
-void process_monster_attack_time(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
+void process_monster_attack_time(PlayerType *player_ptr)
 {
     if (has_resist_time(player_ptr) || check_multishadow(player_ptr)) {
         return;
@@ -194,19 +157,10 @@ void process_monster_attack_time(PlayerType *player_ptr, MonsterAttackPlayer *mo
     case 7:
     case 8:
     case 9:
-        describe_disability(player_ptr, monap_ptr);
-        player_ptr->update |= (PU_BONUS);
+        msg_print(player_ptr->decrease_ability_random());
         break;
     case 10:
-        msg_print(_("あなたは以前ほど力強くなくなってしまった...。", "You're not as powerful as you used to be..."));
-        for (auto i = 0; i < A_MAX; i++) {
-            player_ptr->stat_cur[i] = (player_ptr->stat_cur[i] * 7) / 8;
-            if (player_ptr->stat_cur[i] < 3) {
-                player_ptr->stat_cur[i] = 3;
-            }
-        }
-
-        player_ptr->update |= PU_BONUS;
+        msg_print(player_ptr->decrease_ability_all());
         break;
     }
 }
index 4292910..5258927 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -9,4 +9,4 @@ void process_terrify_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_p
 void process_paralyze_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr);
 void process_lose_all_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr);
 void process_stun_attack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr);
-void process_monster_attack_time(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr);
+void process_monster_attack_time(PlayerType *player_ptr);
index 7b64e5d..166c8c5 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターからプレイヤーへの直接攻撃をその種別において振り分ける
  * @date 2020/05/31
  * @author Hourier
@@ -6,6 +6,7 @@
  */
 
 #include "monster-attack/monster-attack-switcher.h"
+#include "dungeon/quest.h"
 #include "inventory/inventory-slot-types.h"
 #include "mind/drs-types.h"
 #include "mind/mind-mirror-master.h"
 #include "monster-attack/monster-eating.h"
 #include "monster/monster-status.h"
 #include "monster/monster-update.h"
+#include "mutation/mutation-investor-remover.h"
 #include "player/player-damage.h"
 #include "player/player-status-flags.h"
 #include "player/player-status-resist.h"
 #include "player/player-status.h"
 #include "spell-kind/earthquake.h"
 #include "spell-kind/spells-equipment.h"
+#include "spell-kind/spells-teleport.h"
 #include "status/bad-status-setter.h"
 #include "status/base-status.h"
 #include "status/element-resistance.h"
 #include "status/experience.h"
+#include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
@@ -245,7 +249,7 @@ static void calc_blow_time(PlayerType *player_ptr, MonsterAttackPlayer *monap_pt
         return;
     }
 
-    process_monster_attack_time(player_ptr, monap_ptr);
+    process_monster_attack_time(player_ptr);
     if (has_resist_time(player_ptr)) {
         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
     }
@@ -533,6 +537,73 @@ void switch_monster_blow_to_player(PlayerType *player_ptr, MonsterAttackPlayer *
     case RaceBlowEffectType::HUNGRY:
         calc_blow_hungry(player_ptr, monap_ptr);
         break;
+    case RaceBlowEffectType::CHAOS: {
+        update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_CHAOS);
+        monap_ptr->damage = monap_ptr->damage * calc_chaos_damage_rate(player_ptr, CALC_RAND) / 100;
+        monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
+
+        const auto has_chaos_resist = has_resist_chaos(player_ptr);
+
+        if (!has_chaos_resist) {
+            monap_ptr->obvious = true;
+        }
+        if (randint1(5) < 3) {
+            monap_ptr->obvious = true;
+            if (!has_chaos_resist) {
+                if (player_ptr->is_dead || check_multishadow(player_ptr)) {
+                    return;
+                }
+
+                int32_t d = damroll(60, 6) + (player_ptr->exp / 100) * MON_DRAIN_LIFE;
+
+                bool resist_drain = check_drain_hp(player_ptr, d);
+                process_drain_life(player_ptr, monap_ptr, resist_drain);
+            }
+            break;
+        }
+        if (one_in_(250)) {
+            monap_ptr->obvious = true;
+            const auto *floor_ptr = player_ptr->current_floor_ptr;
+            if (floor_ptr->is_in_dungeon() && (!floor_ptr->is_in_quest() || !QuestType::is_fixed(floor_ptr->quest_number))) {
+                if (monap_ptr->damage > 23 || monap_ptr->explode) {
+                    msg_print(_("カオスの力でダンジョンが崩れ始める!", "The dungeon tumbles by the chaotic power!"));
+                    earthquake(player_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, 8, monap_ptr->m_idx);
+                    break;
+                }
+            }
+        }
+        if (!one_in_(10)) {
+            if (player_ptr->is_dead) {
+                return;
+            }
+            monap_ptr->obvious = true;
+
+            if (!has_chaos_resist && !has_resist_conf(player_ptr) && !check_multishadow(player_ptr) && BadStatusSetter(player_ptr).mod_confusion(3 + randint1(monap_ptr->rlev))) {
+                monap_ptr->obvious = true;
+            }
+            break;
+        }
+
+        if (one_in_(2)) {
+            if (player_ptr->is_dead) {
+                return;
+            }
+            monap_ptr->obvious = true;
+
+            if (!has_chaos_resist && player_ptr->anti_tele == 0) {
+                msg_print(_("突然体が浮きだした!", "Your body floats suddenly!"));
+                teleport_player(player_ptr, 50, TELEPORT_PASSIVE);
+            }
+        } else if (!has_chaos_resist) {
+            if (player_ptr->is_dead) {
+                return;
+            }
+            monap_ptr->obvious = true;
+
+            msg_print(_("あなたの身体はカオスの力で捻じ曲げられた!", "Your body is twisted by chaos!"));
+            (void)gain_mutation(player_ptr, 0);
+        }
+    } break;
 
     case RaceBlowEffectType::MAX:
         break;
index aec7744..77b5f12 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class MonsterAttackPlayer;
 class PlayerType;
index a26d683..e5c1597 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-attack/monster-attack-table.h"
+#include "monster-attack/monster-attack-table.h"
 #include "effect/attribute-types.h"
 #include "monster-attack/monster-attack-effect.h"
 
index cf5dfd7..2d10346 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "monster-attack/monster-attack-effect.h"
index 9dd8dc1..a97f5f7 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーのHP/MP、アイテム、お金・明かりの残りターン、充填魔力を盗んだり減少させたりする処理
  * @date 2020/05/31
  * @author Hourier
@@ -6,8 +6,6 @@
 
 #include "monster-attack/monster-eating.h"
 #include "avatar/avatar.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -29,6 +27,7 @@
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/player-paralysis.h"
 #include "timed-effect/timed-effects.h"
@@ -74,8 +73,9 @@ void process_eat_gold(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
         chg_virtue(player_ptr, Virtue::SACRIFICE, 2);
     }
 
-    player_ptr->redraw |= (PR_GOLD);
-    player_ptr->window_flags |= (PW_PLAYER);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::GOLD);
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
     monap_ptr->blinked = true;
 }
 
@@ -210,7 +210,7 @@ void process_eat_lite(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
         monap_ptr->obvious = true;
     }
 
-    player_ptr->window_flags |= (PW_EQUIPMENT);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::EQUIPMENT);
 }
 
 /*!
@@ -252,17 +252,22 @@ bool process_un_power(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
     recovery = std::min(recovery, monap_ptr->m_ptr->maxhp - monap_ptr->m_ptr->hp);
     monap_ptr->m_ptr->hp += recovery;
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == monap_ptr->m_idx) {
-        player_ptr->redraw |= PR_HEALTH;
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (player_ptr->riding == monap_ptr->m_idx) {
-        player_ptr->redraw |= PR_UHEALTH;
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     monap_ptr->o_ptr->pval = !is_magic_mastery || (monap_ptr->o_ptr->pval == 1) ? 0 : monap_ptr->o_ptr->pval - drain;
-    player_ptr->update |= PU_COMBINATION | PU_REORDER;
-    player_ptr->window_flags |= PW_INVENTORY;
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags);
+    rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
     return true;
 }
 
@@ -299,12 +304,13 @@ void process_drain_life(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr,
         monap_ptr->m_ptr->hp = monap_ptr->m_ptr->maxhp;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == monap_ptr->m_idx) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (player_ptr->riding == monap_ptr->m_idx) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     if (monap_ptr->m_ptr->ml && did_heal) {
@@ -326,7 +332,7 @@ void process_drain_mana(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
         player_ptr->csp_frac = 0;
     }
 
-    player_ptr->redraw |= (PR_MP);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
 }
 
 /*!
index b5b418c..a63d703 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index eb4d05c..cd13cd1 100644 (file)
@@ -1,9 +1,10 @@
-#include "monster-floor/monster-death-util.h"
+#include "monster-floor/monster-death-util.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
 #include "monster-race/race-indice-types.h"
 #include "monster/monster-info.h"
 #include "monster/smart-learn-types.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
@@ -19,7 +20,7 @@
  * Used to allocate proper treasure when "Creeping coins" die
  * Note the use of actual "monster names"
  */
-static OBJECT_SUBTYPE_VALUE get_coin_type(MonsterRaceId r_idx)
+static int get_coin_type(MonsterRaceId r_idx)
 {
     switch (r_idx) {
     case MonsterRaceId::COPPER_COINS:
@@ -38,16 +39,19 @@ static OBJECT_SUBTYPE_VALUE get_coin_type(MonsterRaceId r_idx)
     }
 }
 
-monster_death_type *initialize_monster_death_type(PlayerType *player_ptr, monster_death_type *md_ptr, MONSTER_IDX m_idx, bool drop_item)
+MonsterDeath::MonsterDeath(FloorType &floor, MONSTER_IDX m_idx, bool drop_item)
+    : m_idx(m_idx)
+    , m_ptr(&floor.m_list[m_idx])
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    md_ptr->m_idx = m_idx;
-    md_ptr->m_ptr = &floor_ptr->m_list[m_idx];
-    md_ptr->r_ptr = &monraces_info[md_ptr->m_ptr->r_idx];
-    md_ptr->do_gold = (md_ptr->r_ptr->drop_flags.has_none_of({ MonsterDropType::ONLY_ITEM, MonsterDropType::DROP_GOOD, MonsterDropType::DROP_GREAT }));
-    md_ptr->do_item = (md_ptr->r_ptr->drop_flags.has_not(MonsterDropType::ONLY_GOLD) || md_ptr->r_ptr->drop_flags.has_any_of({ MonsterDropType::DROP_GOOD, MonsterDropType::DROP_GREAT }));
-    md_ptr->cloned = md_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::CLONED);
-    md_ptr->force_coin = get_coin_type(md_ptr->m_ptr->r_idx);
-    md_ptr->drop_chosen_item = drop_item && !md_ptr->cloned && !floor_ptr->inside_arena && !player_ptr->phase_out && !md_ptr->m_ptr->is_pet();
-    return md_ptr;
+    this->r_ptr = &this->m_ptr->get_monrace();
+    this->do_gold = this->r_ptr->drop_flags.has_none_of({
+        MonsterDropType::ONLY_ITEM,
+        MonsterDropType::DROP_GOOD,
+        MonsterDropType::DROP_GREAT,
+    });
+    this->do_item = this->r_ptr->drop_flags.has_not(MonsterDropType::ONLY_GOLD);
+    this->do_item |= this->r_ptr->drop_flags.has_any_of({ MonsterDropType::DROP_GOOD, MonsterDropType::DROP_GREAT });
+    this->cloned = this->m_ptr->mflag2.has(MonsterConstantFlagType::CLONED);
+    this->force_coin = get_coin_type(this->m_ptr->r_idx);
+    this->drop_chosen_item = drop_item && !this->cloned && !floor.inside_arena && !AngbandSystem::get_instance().is_phase_out() && !this->m_ptr->is_pet();
 }
index 6a4306d..e43762e 100644 (file)
@@ -1,10 +1,14 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
+// @todo PlayerType に依存するオブジェクトメソッドを追加予定.
+class FloorType;
 class MonsterEntity;
 class MonsterRaceInfo;
-struct monster_death_type {
+class MonsterDeath {
+public:
+    MonsterDeath(FloorType &floor, MONSTER_IDX m_idx, bool drop_item);
     MONSTER_IDX m_idx;
     MonsterEntity *m_ptr;
     MonsterRaceInfo *r_ptr;
@@ -13,10 +17,7 @@ struct monster_death_type {
     bool cloned;
     int force_coin;
     bool drop_chosen_item;
-    POSITION md_y;
-    POSITION md_x;
-    uint32_t mo_mode;
+    POSITION md_y = 0;
+    POSITION md_x = 0;
+    uint32_t mo_mode = 0;
 };
-
-class PlayerType;
-monster_death_type *initialize_monster_death_type(PlayerType *player_ptr, monster_death_type *md_ptr, MONSTER_IDX m_idx, bool drop_item);
index a0708b5..f6b024e 100644 (file)
@@ -1,9 +1,7 @@
-#include "monster-floor/monster-death.h"
+#include "monster-floor/monster-death.h"
 #include "artifact/fixed-art-generator.h"
 #include "artifact/fixed-art-types.h"
 #include "cmd-building/cmd-building.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "dungeon/quest-completion-checker.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
@@ -37,6 +35,7 @@
 #include "player/patron.h"
 #include "sv-definition/sv-other-types.h"
 #include "sv-definition/sv-scroll-types.h"
+#include "system/angband-system.h"
 #include "system/artifact-type-definition.h"
 #include "system/building-type-definition.h"
 #include "system/dungeon-info.h"
@@ -45,6 +44,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/system-variables.h"
 #include "timed-effect/player-hallucination.h"
 #include "timed-effect/timed-effects.h"
 #include "world/world.h"
 #include <algorithm>
 
-static void write_pet_death(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void write_pet_death(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     md_ptr->md_y = md_ptr->m_ptr->fy;
     md_ptr->md_x = md_ptr->m_ptr->fx;
     if (record_named_pet && md_ptr->m_ptr->is_named_pet()) {
         const auto m_name = monster_desc(player_ptr, md_ptr->m_ptr, MD_INDEF_VISIBLE);
-        exe_write_diary(player_ptr, DIARY_NAMED_PET, 3, m_name.data());
+        exe_write_diary(player_ptr, DiaryKind::NAMED_PET, 3, m_name);
     }
 }
 
-static void on_dead_explosion(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_explosion(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
-    for (int i = 0; i < 4; i++) {
-        if (md_ptr->r_ptr->blow[i].method != RaceBlowMethodType::EXPLODE) {
+    for (const auto &blow : md_ptr->r_ptr->blows) {
+        if (blow.method != RaceBlowMethodType::EXPLODE) {
             continue;
         }
 
         BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
-        AttributeType typ = mbe_info[enum2i(md_ptr->r_ptr->blow[i].effect)].explode_type;
-        DICE_NUMBER d_dice = md_ptr->r_ptr->blow[i].d_dice;
-        DICE_SID d_side = md_ptr->r_ptr->blow[i].d_side;
+        AttributeType typ = mbe_info[enum2i(blow.effect)].explode_type;
+        DICE_NUMBER d_dice = blow.d_dice;
+        DICE_SID d_side = blow.d_side;
         int damage = damroll(d_dice, d_side);
         (void)project(player_ptr, md_ptr->m_idx, 3, md_ptr->md_y, md_ptr->md_x, damage, typ, flg);
         break;
     }
 }
 
-static void on_defeat_arena_monster(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_defeat_arena_monster(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     if (!floor_ptr->inside_arena || md_ptr->m_ptr->is_pet()) {
         return;
     }
 
-    player_ptr->exit_bldg = true;
+    w_ptr->set_arena(true);
     if (player_ptr->arena_number > MAX_ARENA_MONS) {
         msg_print(_("素晴らしい!君こそ真の勝利者だ。", "You are a Genuine Champion!"));
     } else {
@@ -114,15 +114,15 @@ static void on_defeat_arena_monster(PlayerType *player_ptr, monster_death_type *
     }
 
     const auto m_name = monster_desc(player_ptr, md_ptr->m_ptr, MD_WRONGDOER_NAME);
-    exe_write_diary(player_ptr, DIARY_ARENA, player_ptr->arena_number, m_name.data());
+    exe_write_diary(player_ptr, DiaryKind::ARENA, player_ptr->arena_number, m_name);
 }
 
-static void drop_corpse(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void drop_corpse(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     bool is_drop_corpse = one_in_(md_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) ? 1 : 4);
     is_drop_corpse &= md_ptr->r_ptr->drop_flags.has_any_of({ MonsterDropType::DROP_CORPSE, MonsterDropType::DROP_SKELETON });
-    is_drop_corpse &= !(floor_ptr->inside_arena || player_ptr->phase_out || md_ptr->cloned || ((md_ptr->m_ptr->r_idx == w_ptr->today_mon) && md_ptr->m_ptr->is_pet()));
+    is_drop_corpse &= !(floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out() || md_ptr->cloned || ((md_ptr->m_ptr->r_idx == w_ptr->today_mon) && md_ptr->m_ptr->is_pet()));
     if (!is_drop_corpse) {
         return;
     }
@@ -158,7 +158,7 @@ static void drop_corpse(PlayerType *player_ptr, monster_death_type *md_ptr)
  * @param md_ptr モンスター死亡構造体への参照ポインタ
  * @return 何かドロップするならドロップしたアーティファクトのID、何もドロップしないなら0
  */
-static void drop_artifact_from_unique(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void drop_artifact_from_unique(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     for (const auto &[a_idx, chance] : md_ptr->r_ptr->drop_artifacts) {
         if (!w_ptr->wizard && (randint0(100) >= chance)) {
@@ -178,7 +178,7 @@ static void drop_artifact_from_unique(PlayerType *player_ptr, monster_death_type
  * @param a_ix ドロップを試みるアーティファクトID
  * @return ドロップするならtrue
  */
-bool drop_single_artifact(PlayerType *player_ptr, monster_death_type *md_ptr, FixedArtifactId a_idx)
+bool drop_single_artifact(PlayerType *player_ptr, MonsterDeath *md_ptr, FixedArtifactId a_idx)
 {
     auto &artifact = ArtifactsInfo::get_instance().get_artifact(a_idx);
     if (artifact.is_generated) {
@@ -188,9 +188,9 @@ bool drop_single_artifact(PlayerType *player_ptr, monster_death_type *md_ptr, Fi
     return create_named_art(player_ptr, a_idx, md_ptr->md_y, md_ptr->md_x);
 }
 
-static short drop_dungeon_final_artifact(PlayerType *player_ptr, monster_death_type *md_ptr)
+static short drop_dungeon_final_artifact(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
-    const auto &dungeon = dungeons_info[player_ptr->dungeon_idx];
+    const auto &dungeon = player_ptr->current_floor_ptr->get_dungeon_definition();
     const auto has_reward = dungeon.final_object > 0;
     const auto bi_id = has_reward ? dungeon.final_object : lookup_baseitem_id({ ItemKindType::SCROLL, SV_SCROLL_ACQUIREMENT });
     if (dungeon.final_artifact == FixedArtifactId::NONE) {
@@ -208,14 +208,16 @@ static short drop_dungeon_final_artifact(PlayerType *player_ptr, monster_death_t
     return dungeon.final_object ? bi_id : 0;
 }
 
-static void drop_artifacts(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void drop_artifacts(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     if (!md_ptr->drop_chosen_item) {
         return;
     }
 
     drop_artifact_from_unique(player_ptr, md_ptr);
-    if (((md_ptr->r_ptr->flags7 & RF7_GUARDIAN) == 0) || (dungeons_info[player_ptr->dungeon_idx].final_guardian != md_ptr->m_ptr->r_idx)) {
+    const auto *floor_ptr = player_ptr->current_floor_ptr;
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    if (((md_ptr->r_ptr->flags7 & RF7_GUARDIAN) == 0) || (dungeon.final_guardian != md_ptr->m_ptr->r_idx)) {
         return;
     }
 
@@ -224,14 +226,14 @@ static void drop_artifacts(PlayerType *player_ptr, monster_death_type *md_ptr)
         ItemEntity forge;
         auto *q_ptr = &forge;
         q_ptr->prep(bi_id);
-        ItemMagicApplier(player_ptr, q_ptr, player_ptr->current_floor_ptr->object_level, AM_NO_FIXED_ART | AM_GOOD).execute();
+        ItemMagicApplier(player_ptr, q_ptr, floor_ptr->object_level, AM_NO_FIXED_ART | AM_GOOD).execute();
         (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
     }
 
-    msg_format(_("あなたは%sを制覇した!", "You have conquered %s!"), dungeons_info[player_ptr->dungeon_idx].name.data());
+    msg_format(_("あなたは%sを制覇した!", "You have conquered %s!"), dungeon.name.data());
 }
 
-static void decide_drop_quality(monster_death_type *md_ptr)
+static void decide_drop_quality(MonsterDeath *md_ptr)
 {
     md_ptr->mo_mode = 0L;
     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_GOOD)) {
@@ -243,7 +245,7 @@ static void decide_drop_quality(monster_death_type *md_ptr)
     }
 }
 
-static int decide_drop_numbers(PlayerType *player_ptr, monster_death_type *md_ptr, const bool drop_item)
+static int decide_drop_numbers(MonsterDeath *md_ptr, const bool drop_item, const bool inside_arena)
 {
     int drop_numbers = 0;
     if (md_ptr->r_ptr->drop_flags.has(MonsterDropType::DROP_60) && (randint0(100) < 60)) {
@@ -274,7 +276,7 @@ static int decide_drop_numbers(PlayerType *player_ptr, monster_death_type *md_pt
         drop_numbers = 0;
     }
 
-    if (md_ptr->m_ptr->is_pet() || player_ptr->phase_out || player_ptr->current_floor_ptr->inside_arena) {
+    if (md_ptr->m_ptr->is_pet() || AngbandSystem::get_instance().is_phase_out() || inside_arena) {
         drop_numbers = 0;
     }
 
@@ -289,7 +291,7 @@ static int decide_drop_numbers(PlayerType *player_ptr, monster_death_type *md_pt
     return drop_numbers;
 }
 
-static void drop_items_golds(PlayerType *player_ptr, monster_death_type *md_ptr, int drop_numbers)
+static void drop_items_golds(PlayerType *player_ptr, MonsterDeath *md_ptr, int drop_numbers)
 {
     int dump_item = 0;
     int dump_gold = 0;
@@ -330,10 +332,10 @@ static void drop_items_golds(PlayerType *player_ptr, monster_death_type *md_ptr,
 static void on_defeat_last_boss(PlayerType *player_ptr)
 {
     w_ptr->total_winner = true;
-    add_winner_class(player_ptr->pclass);
-    player_ptr->redraw |= PR_TITLE;
+    w_ptr->add_winner_class(player_ptr->pclass);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TITLE);
     play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_FINAL_QUEST_CLEAR);
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, _("見事に変愚蛮怒の勝利者となった!", "finally became *WINNER* of Hengband!"));
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, _("見事に変愚蛮怒の勝利者となった!", "finally became *WINNER* of Hengband!"));
     patron_list[player_ptr->chaos_patron].admire(player_ptr);
     msg_print(_("*** おめでとう ***", "*** CONGRATULATIONS ***"));
     msg_print(_("あなたはゲームをコンプリートしました。", "You have won the game!"));
@@ -374,28 +376,29 @@ void monster_death(PlayerType *player_ptr, MONSTER_IDX m_idx, bool drop_item, At
  */
 void monster_death(PlayerType *player_ptr, MONSTER_IDX m_idx, bool drop_item, AttributeFlags attribute_flags)
 {
-    monster_death_type tmp_md;
-    monster_death_type *md_ptr = initialize_monster_death_type(player_ptr, &tmp_md, m_idx, drop_item);
+    auto &floor = *player_ptr->current_floor_ptr;
+    MonsterDeath tmp_md(floor, m_idx, drop_item);
+    MonsterDeath *md_ptr = &tmp_md;
     if (w_ptr->timewalk_m_idx && w_ptr->timewalk_m_idx == m_idx) {
         w_ptr->timewalk_m_idx = 0;
     }
 
     // プレイヤーしかユニークを倒せないのでここで時間を記録
     if (md_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) && md_ptr->m_ptr->mflag2.has_not(MonsterConstantFlagType::CLONED)) {
-        update_playtime();
+        w_ptr->update_playtime();
         md_ptr->r_ptr->defeat_time = w_ptr->play_time;
         md_ptr->r_ptr->defeat_level = player_ptr->lev;
     }
 
     if (md_ptr->r_ptr->brightness_flags.has_any_of(ld_mask)) {
-        player_ptr->update |= PU_MONSTER_LITE;
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 
     write_pet_death(player_ptr, md_ptr);
     on_dead_explosion(player_ptr, md_ptr);
     if (md_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON)) {
         choose_new_monster(player_ptr, m_idx, true, MonsterRaceId::CHAMELEON);
-        md_ptr->r_ptr = &monraces_info[md_ptr->m_ptr->r_idx];
+        md_ptr->r_ptr = &md_ptr->m_ptr->get_monrace();
     }
 
     QuestCompletionChecker(player_ptr, md_ptr->m_ptr).complete();
@@ -409,40 +412,13 @@ void monster_death(PlayerType *player_ptr, MONSTER_IDX m_idx, bool drop_item, At
     decide_drop_quality(md_ptr);
     switch_special_death(player_ptr, md_ptr, attribute_flags);
     drop_artifacts(player_ptr, md_ptr);
-    int drop_numbers = decide_drop_numbers(player_ptr, md_ptr, drop_item);
+    int drop_numbers = decide_drop_numbers(md_ptr, drop_item, floor.inside_arena);
     coin_type = md_ptr->force_coin;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    floor_ptr->object_level = (floor_ptr->dun_level + md_ptr->r_ptr->level) / 2;
+    floor.object_level = (floor.dun_level + md_ptr->r_ptr->level) / 2;
     drop_items_golds(player_ptr, md_ptr, drop_numbers);
-    if (((md_ptr->r_ptr->flags1 & RF1_QUESTOR) == 0) || player_ptr->phase_out || (md_ptr->m_ptr->r_idx != MonsterRaceId::SERPENT) || md_ptr->cloned) {
+    if (((md_ptr->r_ptr->flags1 & RF1_QUESTOR) == 0) || AngbandSystem::get_instance().is_phase_out() || (md_ptr->m_ptr->r_idx != MonsterRaceId::SERPENT) || md_ptr->cloned) {
         return;
     }
 
     on_defeat_last_boss(player_ptr);
 }
-
-/*!
- * @brief モンスターを撃破した際の述語メッセージを返す /
- * Return monster death string
- * @param r_ptr 撃破されたモンスターの種族情報を持つ構造体の参照ポインタ
- * @return 撃破されたモンスターの述語
- */
-concptr extract_note_dies(MonsterRaceId r_idx)
-{
-    const auto &r_ref = monraces_info[r_idx];
-    const auto explode = std::any_of(std::begin(r_ref.blow), std::end(r_ref.blow), [](const auto &blow) { return blow.method == RaceBlowMethodType::EXPLODE; });
-
-    if (monster_living(r_idx)) {
-        if (explode) {
-            return _("は爆発して死んだ。", " explodes and dies.");
-        }
-
-        return _("は死んだ。", " dies.");
-    }
-
-    if (explode) {
-        return _("は爆発して粉々になった。", " explodes into tiny shreds.");
-    }
-
-    return _("を倒した。", " is destroyed.");
-}
index c6a0a9d..1b2462c 100644 (file)
@@ -1,13 +1,11 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
-#include "monster-floor/monster-death-util.h"
 #include "system/angband.h"
 
 enum class FixedArtifactId : short;
-enum class MonsterRaceId : int16_t;
 class PlayerType;
+class MonsterDeath;
 void monster_death(PlayerType *player_ptr, MONSTER_IDX m_idx, bool drop_item, AttributeFlags attribute_flags);
 void monster_death(PlayerType *player_ptr, MONSTER_IDX m_idx, bool drop_item, AttributeType type);
-bool drop_single_artifact(PlayerType *player_ptr, monster_death_type *md_ptr, FixedArtifactId a_idx);
-concptr extract_note_dies(MonsterRaceId r_idx);
+bool drop_single_artifact(PlayerType *player_ptr, MonsterDeath *md_ptr, FixedArtifactId a_idx);
index a946fb3..3d3b01c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの移動方向を決定する処理
  * @date 2020/03/08
  * @author Hourier
@@ -16,6 +16,7 @@
 #include "pet/pet-util.h"
 #include "player/player-status-flags.h"
 #include "spell/range-calc.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
@@ -32,7 +33,7 @@
  */
 static bool decide_pet_approch_direction(PlayerType *player_ptr, MonsterEntity *m_ptr, MonsterEntity *t_ptr)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (!m_ptr->is_pet()) {
         return false;
     }
@@ -61,7 +62,7 @@ static void decide_enemy_approch_direction(PlayerType *player_ptr, MONSTER_IDX m
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     for (int i = start; ((i < start + floor_ptr->m_max) && (i > start - floor_ptr->m_max)); i += plus) {
         MONSTER_IDX dummy = (i % floor_ptr->m_max);
         if (dummy == 0) {
@@ -69,8 +70,7 @@ static void decide_enemy_approch_direction(PlayerType *player_ptr, MONSTER_IDX m
         }
 
         MONSTER_IDX t_idx = dummy;
-        MonsterEntity *t_ptr;
-        t_ptr = &floor_ptr->m_list[t_idx];
+        auto *t_ptr = &floor_ptr->m_list[t_idx];
         if (t_ptr == m_ptr) {
             continue;
         }
@@ -80,7 +80,7 @@ static void decide_enemy_approch_direction(PlayerType *player_ptr, MONSTER_IDX m
         if (decide_pet_approch_direction(player_ptr, m_ptr, t_ptr)) {
             continue;
         }
-        if (!are_enemies(player_ptr, *m_ptr, *t_ptr)) {
+        if (!m_ptr->is_hostile_to_melee(*t_ptr)) {
             continue;
         }
 
@@ -116,7 +116,7 @@ bool get_enemy_dir(PlayerType *player_ptr, MONSTER_IDX m_idx, int *mm)
     auto *m_ptr = &floor_ptr->m_list[m_idx];
 
     POSITION x = 0, y = 0;
-    if (player_ptr->riding_t_m_idx && player_bold(player_ptr, m_ptr->fy, m_ptr->fx)) {
+    if (player_ptr->riding_t_m_idx && player_ptr->is_located_at({ m_ptr->fy, m_ptr->fx })) {
         y = floor_ptr->m_list[player_ptr->riding_t_m_idx].fy;
         x = floor_ptr->m_list[player_ptr->riding_t_m_idx].fx;
     } else if (m_ptr->is_pet() && player_ptr->pet_t_m_idx) {
@@ -125,7 +125,7 @@ bool get_enemy_dir(PlayerType *player_ptr, MONSTER_IDX m_idx, int *mm)
     } else {
         int start;
         int plus = 1;
-        if (player_ptr->phase_out) {
+        if (AngbandSystem::get_instance().is_phase_out()) {
             start = randint1(floor_ptr->m_max - 1) + floor_ptr->m_max;
             if (randint0(2)) {
                 plus = -1;
@@ -158,7 +158,7 @@ bool get_enemy_dir(PlayerType *player_ptr, MONSTER_IDX m_idx, int *mm)
  */
 static bool random_walk(PlayerType *player_ptr, DIRECTION *mm, MonsterEntity *m_ptr)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->behavior_flags.has_all_of({ MonsterBehaviorType::RAND_MOVE_50, MonsterBehaviorType::RAND_MOVE_25 }) && (randint0(100) < 75)) {
         if (is_original_ap_and_seen(player_ptr, m_ptr)) {
             r_ptr->r_behavior_flags.set({ MonsterBehaviorType::RAND_MOVE_50, MonsterBehaviorType::RAND_MOVE_25 });
@@ -236,7 +236,7 @@ static bool decide_pet_movement_direction(MonsterSweepGrid *msd)
 bool decide_monster_movement_direction(PlayerType *player_ptr, DIRECTION *mm, MONSTER_IDX m_idx, bool aware)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     if (m_ptr->is_confused() || !aware) {
         mm[0] = mm[1] = mm[2] = mm[3] = 5;
index b51b732..0c9ab23 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 5cc76b7..f10d461 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-floor/monster-dist-offsets.h"
+#include "monster-floor/monster-dist-offsets.h"
 
 /*
  * Hack -- Precompute a bunch of calls to distance() in find_safety() and
index c1b32a0..1c8e5c2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index cef7859..08b06e6 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * todo 後で再分割する
  * @brief モンスター生成処理
  * @date 2020/06/10
@@ -69,9 +69,9 @@ static MONSTER_IDX place_monster_m_idx = 0;
  */
 bool mon_scatter(PlayerType *player_ptr, MonsterRaceId r_idx, POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION max_dist)
 {
-    POSITION place_x[MON_SCAT_MAXD];
-    POSITION place_y[MON_SCAT_MAXD];
-    int num[MON_SCAT_MAXD];
+    int place_x[MON_SCAT_MAXD]{};
+    int place_y[MON_SCAT_MAXD]{};
+    int num[MON_SCAT_MAXD]{};
 
     if (max_dist >= MON_SCAT_MAXD) {
         return false;
@@ -155,7 +155,7 @@ bool multiply_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool clone, BIT
         mode |= PM_NO_PET;
     }
 
-    if (!place_monster_aux(player_ptr, m_idx, y, x, m_ptr->r_idx, (mode | PM_NO_KAGE | PM_MULTIPLY))) {
+    if (!place_specific_monster(player_ptr, m_idx, y, x, m_ptr->r_idx, (mode | PM_NO_KAGE | PM_MULTIPLY))) {
         return false;
     }
 
@@ -281,7 +281,7 @@ static bool place_monster_can_escort(PlayerType *player_ptr, MonsterRaceId r_idx
 }
 
 /*!
- * @brief 一般的なモンスター生成処理のサブルーチン / Attempt to place a monster of the given race at the given location
+ * @brief 特定モンスターを生成する
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param who 召喚主のモンスター情報ID
  * @param y 生成地点y座標
@@ -289,8 +289,9 @@ static bool place_monster_can_escort(PlayerType *player_ptr, MonsterRaceId r_idx
  * @param r_idx 生成するモンスターの種族ID
  * @param mode 生成オプション
  * @return 生成に成功したらtrue
+ * @details 護衛も一緒に生成する
  */
-bool place_monster_aux(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSITION x, MonsterRaceId r_idx, BIT_FLAGS mode)
+bool place_specific_monster(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSITION x, MonsterRaceId r_idx, BIT_FLAGS mode)
 {
     auto *r_ptr = &monraces_info[r_idx];
 
@@ -362,19 +363,19 @@ bool place_monster_aux(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSI
 }
 
 /*!
- * @brief 一般的なモンスター生成処理のメインルーチン / Attempt to place a monster of the given race at the given location
+ * @brief フロア相当のモンスターを1体生成する
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param y 生成地点y座標
  * @param x 生成地点x座標
  * @param mode 生成オプション
  * @return 生成に成功したらtrue
  */
-bool place_monster(PlayerType *player_ptr, POSITION y, POSITION x, BIT_FLAGS mode)
+bool place_random_monster(PlayerType *player_ptr, POSITION y, POSITION x, BIT_FLAGS mode)
 {
     get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), get_monster_hook2(player_ptr, y, x));
     MonsterRaceId r_idx;
     do {
-        r_idx = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->monster_level, 0);
+        r_idx = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->monster_level, PM_NONE);
     } while ((mode & PM_NO_QUEST) && (monraces_info[r_idx].flags8 & RF8_NO_QUEST));
 
     if (!MonsterRace(r_idx).is_valid()) {
@@ -385,7 +386,7 @@ bool place_monster(PlayerType *player_ptr, POSITION y, POSITION x, BIT_FLAGS mod
         mode |= PM_JURAL;
     }
 
-    return place_monster_aux(player_ptr, 0, y, x, r_idx, mode);
+    return place_specific_monster(player_ptr, 0, y, x, r_idx, mode);
 }
 
 static std::optional<MonsterRaceId> select_horde_leader_r_idx(PlayerType *player_ptr)
@@ -393,7 +394,7 @@ static std::optional<MonsterRaceId> select_horde_leader_r_idx(PlayerType *player
     const auto *floor_ptr = player_ptr->current_floor_ptr;
 
     for (auto attempts = 1000; attempts > 0; --attempts) {
-        auto r_idx = get_mon_num(player_ptr, 0, floor_ptr->monster_level, 0);
+        auto r_idx = get_mon_num(player_ptr, 0, floor_ptr->monster_level, PM_NONE);
         if (!MonsterRace(r_idx).is_valid()) {
             return std::nullopt;
         }
@@ -423,8 +424,8 @@ bool alloc_horde(PlayerType *player_ptr, POSITION y, POSITION x, summon_specific
 {
     get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), get_monster_hook2(player_ptr, y, x));
 
-    auto r_idx = select_horde_leader_r_idx(player_ptr);
-    if (!r_idx.has_value()) {
+    const auto r_idx = select_horde_leader_r_idx(player_ptr);
+    if (!r_idx) {
         return false;
     }
 
@@ -433,7 +434,7 @@ bool alloc_horde(PlayerType *player_ptr, POSITION y, POSITION x, summon_specific
             return false;
         }
 
-        if (place_monster_aux(player_ptr, 0, y, x, r_idx.value(), 0L)) {
+        if (place_specific_monster(player_ptr, 0, y, x, *r_idx, 0L)) {
             break;
         }
     }
@@ -454,7 +455,7 @@ bool alloc_horde(PlayerType *player_ptr, POSITION y, POSITION x, summon_specific
         return true;
     }
 
-    auto *r_ptr = &monraces_info[r_idx.value()];
+    auto *r_ptr = &monraces_info[*r_idx];
     if (floor_ptr->m_list[m_idx].mflag2.has(MonsterConstantFlagType::CHAMELEON)) {
         r_ptr = &monraces_info[floor_ptr->m_list[m_idx].r_idx];
     }
@@ -472,10 +473,11 @@ bool alloc_horde(PlayerType *player_ptr, POSITION y, POSITION x, summon_specific
  */
 bool alloc_guardian(PlayerType *player_ptr, bool def_val)
 {
-    MonsterRaceId guardian = dungeons_info[player_ptr->dungeon_idx].final_guardian;
     auto *floor_ptr = player_ptr->current_floor_ptr;
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    MonsterRaceId guardian = dungeon.final_guardian;
     bool is_guardian_applicable = MonsterRace(guardian).is_valid();
-    is_guardian_applicable &= dungeons_info[player_ptr->dungeon_idx].maxdepth == floor_ptr->dun_level;
+    is_guardian_applicable &= dungeon.maxdepth == floor_ptr->dun_level;
     is_guardian_applicable &= monraces_info[guardian].cur_num < monraces_info[guardian].max_num;
     if (!is_guardian_applicable) {
         return def_val;
@@ -495,7 +497,7 @@ bool alloc_guardian(PlayerType *player_ptr, bool def_val)
             continue;
         }
 
-        if (place_monster_aux(player_ptr, 0, oy, ox, guardian, (PM_ALLOW_GROUP | PM_NO_KAGE | PM_NO_PET))) {
+        if (place_specific_monster(player_ptr, 0, oy, ox, guardian, (PM_ALLOW_GROUP | PM_NO_KAGE | PM_NO_PET))) {
             return true;
         }
 
@@ -507,23 +509,22 @@ bool alloc_guardian(PlayerType *player_ptr, bool def_val)
 
 /*!
  * @brief ダンジョンの初期配置モンスターを生成1回生成する / Attempt to allocate a random monster in the dungeon.
- * @param dis プレイヤーから離れるべき最距離
+ * @param dis プレイヤーから離れるべき最距離
  * @param mode 生成オプション
+ * @param summon_specific 特定モンスター種別を生成するための関数ポインタ
+ * @param max_dis プレイヤーから離れるべき最大距離 (デバッグ用)
  * @return 生成に成功したらtrue
- * @details
- * Place the monster at least "dis" distance from the player.
- * Use "slp" to choose the initial "sleep" status
- * Use "floor_ptr->monster_level" for the monster level
  */
-bool alloc_monster(PlayerType *player_ptr, POSITION dis, BIT_FLAGS mode, summon_specific_pf summon_specific)
+bool alloc_monster(PlayerType *player_ptr, int min_dis, BIT_FLAGS mode, summon_specific_pf summon_specific, int max_dis)
 {
     if (alloc_guardian(player_ptr, false)) {
         return true;
     }
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    POSITION y = 0, x = 0;
-    int attempts_left = 10000;
+    auto y = 0;
+    auto x = 0;
+    auto attempts_left = 10000;
     while (attempts_left--) {
         y = randint0(floor_ptr->height);
         x = randint0(floor_ptr->width);
@@ -538,7 +539,8 @@ bool alloc_monster(PlayerType *player_ptr, POSITION dis, BIT_FLAGS mode, summon_
             }
         }
 
-        if (distance(y, x, player_ptr->y, player_ptr->x) > dis) {
+        const auto dist = distance(y, x, player_ptr->y, player_ptr->x);
+        if ((min_dis < dist) && (dist <= max_dis)) {
             break;
         }
     }
@@ -556,7 +558,7 @@ bool alloc_monster(PlayerType *player_ptr, POSITION dis, BIT_FLAGS mode, summon_
             return true;
         }
     } else {
-        if (place_monster(player_ptr, y, x, (mode | PM_ALLOW_GROUP))) {
+        if (place_random_monster(player_ptr, y, x, (mode | PM_ALLOW_GROUP))) {
             return true;
         }
     }
index 7ce00d8..ed06deb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -9,8 +9,8 @@ typedef bool (*summon_specific_pf)(PlayerType *, MONSTER_IDX, POSITION, POSITION
 
 bool mon_scatter(PlayerType *player_ptr, MonsterRaceId r_idx, POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION max_dist);
 bool multiply_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool clone, BIT_FLAGS mode);
-bool place_monster_aux(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSITION x, MonsterRaceId r_idx, BIT_FLAGS mode);
-bool place_monster(PlayerType *player_ptr, POSITION y, POSITION x, BIT_FLAGS mode);
+bool place_specific_monster(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSITION x, MonsterRaceId r_idx, BIT_FLAGS mode);
+bool place_random_monster(PlayerType *player_ptr, POSITION y, POSITION x, BIT_FLAGS mode);
 bool alloc_horde(PlayerType *player_ptr, POSITION y, POSITION x, summon_specific_pf summon_specific);
 bool alloc_guardian(PlayerType *player_ptr, bool def_val);
-bool alloc_monster(PlayerType *player_ptr, POSITION dis, BIT_FLAGS mode, summon_specific_pf summon_specific);
+bool alloc_monster(PlayerType *player_ptr, int min_dis, BIT_FLAGS mode, summon_specific_pf summon_specific, int max_dis = 65535);
index f559f24..0a42174 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-floor/monster-lite-util.h"
+#include "monster-floor/monster-lite-util.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "util/bit-flags-calculator.h"
index f52a21c..0d229e5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index a880f35..e5b40c7 100644 (file)
@@ -1,5 +1,4 @@
-#include "monster-floor/monster-lite.h"
-#include "core/player-update-types.h"
+#include "monster-floor/monster-lite.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/cave.h"
 #include "grid/feature-flag-types.h"
 #include "player-base/player-class.h"
 #include "player-info/ninja-data-type.h"
 #include "player/special-defense-types.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/point-2d.h"
 #include "view/display-messages.h"
 #include "world/world.h"
@@ -33,7 +34,7 @@
 static void update_monster_lite(
     PlayerType *const player_ptr, std::vector<Pos2D> &points, const POSITION y, const POSITION x, const monster_lite_type *const ml_ptr)
 {
-    grid_type *g_ptr;
+    Grid *g_ptr;
     int dpf, d;
     POSITION midpoint;
     g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
@@ -92,7 +93,7 @@ static void update_monster_lite(
 static void update_monster_dark(
     PlayerType *const player_ptr, std::vector<Pos2D> &points, const POSITION y, const POSITION x, const monster_lite_type *const ml_ptr)
 {
-    grid_type *g_ptr;
+    Grid *g_ptr;
     int midpoint, dpf, d;
     g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
     if ((g_ptr->info & (CAVE_LITE | CAVE_MNLT | CAVE_MNDK | CAVE_VIEW)) != CAVE_VIEW) {
@@ -152,10 +153,11 @@ void update_mon_lite(PlayerType *player_ptr)
     std::vector<Pos2D> points;
 
     void (*add_mon_lite)(PlayerType *, std::vector<Pos2D> &, const POSITION, const POSITION, const monster_lite_type *);
-    int dis_lim = (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS) && !player_ptr->see_nocto) ? (MAX_PLAYER_SIGHT / 2 + 1) : (MAX_PLAYER_SIGHT + 3);
     auto *floor_ptr = player_ptr->current_floor_ptr;
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    auto dis_lim = (dungeon.flags.has(DungeonFeatureType::DARKNESS) && !player_ptr->see_nocto) ? (MAX_PLAYER_SIGHT / 2 + 1) : (MAX_PLAYER_SIGHT + 3);
     for (int i = 0; i < floor_ptr->mon_lite_n; i++) {
-        grid_type *g_ptr;
+        Grid *g_ptr;
         g_ptr = &floor_ptr->grid_array[floor_ptr->mon_lite_y[i]][floor_ptr->mon_lite_x[i]];
         g_ptr->info |= (g_ptr->info & CAVE_MNLT) ? CAVE_TEMP : CAVE_XTRA;
         g_ptr->info &= ~(CAVE_MNLT | CAVE_MNDK);
@@ -166,7 +168,7 @@ void update_mon_lite(PlayerType *player_ptr)
         MonsterRaceInfo *r_ptr;
         for (int i = 1; i < floor_ptr->m_max; i++) {
             m_ptr = &floor_ptr->m_list[i];
-            r_ptr = &monraces_info[m_ptr->r_idx];
+            r_ptr = &m_ptr->get_monrace();
             if (!m_ptr->is_valid() || (m_ptr->cdis > dis_lim)) {
                 continue;
             }
@@ -194,18 +196,20 @@ void update_mon_lite(PlayerType *player_ptr)
 
             TerrainCharacteristics f_flag;
             if (rad > 0) {
-                if (r_ptr->brightness_flags.has_none_of({ MonsterBrightnessType::SELF_LITE_1, MonsterBrightnessType::SELF_LITE_2 }) && (m_ptr->is_asleep() || (!floor_ptr->dun_level && is_daytime()) || player_ptr->phase_out)) {
+                auto should_lite = r_ptr->brightness_flags.has_none_of({ MonsterBrightnessType::SELF_LITE_1, MonsterBrightnessType::SELF_LITE_2 });
+                should_lite &= (m_ptr->is_asleep() || (!floor_ptr->dun_level && w_ptr->is_daytime()) || AngbandSystem::get_instance().is_phase_out());
+                if (should_lite) {
                     continue;
                 }
 
-                if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+                if (dungeon.flags.has(DungeonFeatureType::DARKNESS)) {
                     rad = 1;
                 }
 
                 add_mon_lite = update_monster_lite;
                 f_flag = TerrainCharacteristics::LOS;
             } else {
-                if (r_ptr->brightness_flags.has_none_of({ MonsterBrightnessType::SELF_DARK_1, MonsterBrightnessType::SELF_DARK_2 }) && (m_ptr->is_asleep() || (!floor_ptr->dun_level && !is_daytime()))) {
+                if (r_ptr->brightness_flags.has_none_of({ MonsterBrightnessType::SELF_DARK_1, MonsterBrightnessType::SELF_DARK_2 }) && (m_ptr->is_asleep() || (!floor_ptr->dun_level && !w_ptr->is_daytime()))) {
                     continue;
                 }
 
@@ -229,7 +233,7 @@ void update_mon_lite(PlayerType *player_ptr)
                 continue;
             }
 
-            grid_type *g_ptr;
+            Grid *g_ptr;
             if (cave_has_flag_bold(player_ptr->current_floor_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx, f_flag)) {
                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx + 1, ml_ptr);
                 add_mon_lite(player_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx, ml_ptr);
@@ -304,7 +308,7 @@ void update_mon_lite(PlayerType *player_ptr)
     for (int i = 0; i < floor_ptr->mon_lite_n; i++) {
         POSITION fx = floor_ptr->mon_lite_x[i];
         POSITION fy = floor_ptr->mon_lite_y[i];
-        grid_type *g_ptr;
+        Grid *g_ptr;
         g_ptr = &floor_ptr->grid_array[fy][fx];
         if (g_ptr->info & CAVE_TEMP) {
             if ((g_ptr->info & (CAVE_VIEW | CAVE_MNLT)) == CAVE_VIEW) {
@@ -319,9 +323,9 @@ void update_mon_lite(PlayerType *player_ptr)
 
     floor_ptr->mon_lite_n = 0;
     for (size_t i = 0; i < end_temp; i++) {
-        const auto [fy, fx] = points[i];
+        const auto &[fy, fx] = points[i];
 
-        grid_type *const g_ptr = &floor_ptr->grid_array[fy][fx];
+        Grid *const g_ptr = &floor_ptr->grid_array[fy][fx];
         if (g_ptr->info & CAVE_MNLT) {
             if ((g_ptr->info & (CAVE_VIEW | CAVE_TEMP)) == CAVE_VIEW) {
                 cave_note_and_redraw_later(floor_ptr, fy, fx);
@@ -336,11 +340,11 @@ void update_mon_lite(PlayerType *player_ptr)
     }
 
     for (size_t i = end_temp; i < size(points); i++) {
-        const auto [y, x] = points[i];
+        const auto &[y, x] = points[i];
         floor_ptr->grid_array[y][x].info &= ~(CAVE_TEMP | CAVE_XTRA);
     }
 
-    player_ptr->update |= PU_DELAY_VISIBILITY;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::DELAY_VISIBILITY);
     player_ptr->monlite = (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_MNLT) != 0;
     auto ninja_data = PlayerClass(player_ptr).get_specific_data<ninja_data_type>();
     if (!ninja_data || !ninja_data->s_stealth) {
@@ -369,7 +373,7 @@ void update_mon_lite(PlayerType *player_ptr)
 void clear_mon_lite(FloorType *floor_ptr)
 {
     for (int i = 0; i < floor_ptr->mon_lite_n; i++) {
-        grid_type *g_ptr;
+        Grid *g_ptr;
         g_ptr = &floor_ptr->grid_array[floor_ptr->mon_lite_y[i]][floor_ptr->mon_lite_x[i]];
         g_ptr->info &= ~(CAVE_MNLT | CAVE_MNDK);
     }
index c335830..a1edb41 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class FloorType;
 class PlayerType;
index a8ce46b..3260a11 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの移動に関する処理
  * @date 2020/03/08
  * @author Hourier
@@ -6,7 +6,6 @@
 
 #include "monster-floor/monster-move.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
 #include "monster/monster-update.h"
 #include "pet/pet-util.h"
 #include "player/player-status-flags.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/projection-path-calculator.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
-static bool check_hp_for_feat_destruction(TerrainType *f_ptr, MonsterEntity *m_ptr)
+static bool check_hp_for_terrain_destruction(const TerrainType &terrain, const MonsterEntity &monster)
 {
-    return f_ptr->flags.has_not(TerrainCharacteristics::GLASS) || monraces_info[m_ptr->r_idx].behavior_flags.has(MonsterBehaviorType::STUPID) || (m_ptr->hp >= std::max(m_ptr->maxhp / 3, 200));
+    auto can_destroy = terrain.flags.has_not(TerrainCharacteristics::GLASS);
+    can_destroy |= monster.get_monrace().behavior_flags.has(MonsterBehaviorType::STUPID);
+    can_destroy |= monster.hp >= std::max(monster.maxhp / 3, 200);
+    return can_destroy;
 }
 
 /*!
  * @brief モンスターによる壁の透過・破壊を行う
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param m_ptr モンスターへの参照ポインタ
- * @param ny モンスターのY座標
- * @param nx モンスターのX座標
+ * @param monster モンスターへの参照
+ * @param pos モンスターの移動先座標
  * @param can_cross モンスターが地形を踏破できるならばTRUE
  * @return 透過も破壊もしなかった場合はFALSE、それ以外はTRUE
  */
-static bool process_wall(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, POSITION ny, POSITION nx, bool can_cross)
+static bool process_wall(PlayerType *player_ptr, turn_flags *turn_flags_ptr, const MonsterEntity &monster, const Pos2D &pos, bool can_cross)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
-    TerrainType *f_ptr;
-    f_ptr = &terrains_info[g_ptr->feat];
-    if (player_bold(player_ptr, ny, nx)) {
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
+    if (player_ptr->is_located_at(pos)) {
         turn_flags_ptr->do_move = true;
         return true;
     }
 
-    if (g_ptr->m_idx > 0) {
+    if (grid.m_idx > 0) {
         turn_flags_ptr->do_move = true;
         return true;
     }
 
-    if (r_ptr->feature_flags.has(MonsterFeatureType::KILL_WALL) && (can_cross ? f_ptr->flags.has_not(TerrainCharacteristics::LOS) : !turn_flags_ptr->is_riding_mon) && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI) && f_ptr->flags.has_not(TerrainCharacteristics::PERMANENT) && check_hp_for_feat_destruction(f_ptr, m_ptr)) {
+    using Mft = MonsterFeatureType;
+    using Tc = TerrainCharacteristics;
+    const auto &monrace = monster.get_monrace();
+    auto can_kill_wall = monrace.feature_flags.has(Mft::KILL_WALL);
+    can_kill_wall &= can_cross ? terrain.flags.has_not(Tc::LOS) : !turn_flags_ptr->is_riding_mon;
+    can_kill_wall &= terrain.flags.has(Tc::HURT_DISI);
+    can_kill_wall &= terrain.flags.has_not(Tc::PERMANENT);
+    can_kill_wall &= check_hp_for_terrain_destruction(terrain, monster);
+    if (can_kill_wall) {
         turn_flags_ptr->do_move = true;
         if (!can_cross) {
             turn_flags_ptr->must_alter_to_move = true;
@@ -90,7 +98,7 @@ static bool process_wall(PlayerType *player_ptr, turn_flags *turn_flags_ptr, Mon
     }
 
     turn_flags_ptr->do_move = true;
-    if ((r_ptr->feature_flags.has(MonsterFeatureType::PASS_WALL)) && (!turn_flags_ptr->is_riding_mon || has_pass_wall(player_ptr)) && f_ptr->flags.has(TerrainCharacteristics::CAN_PASS)) {
+    if ((monrace.feature_flags.has(Mft::PASS_WALL)) && (!turn_flags_ptr->is_riding_mon || has_pass_wall(player_ptr)) && terrain.flags.has(Tc::CAN_PASS)) {
         turn_flags_ptr->did_pass_wall = true;
     }
 
@@ -101,31 +109,33 @@ static bool process_wall(PlayerType *player_ptr, turn_flags *turn_flags_ptr, Mon
  * @brief モンスターが普通のドアを開ける処理
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
- * @param m_ptr モンスターへの参照ポインタ
- * @param ny モンスターのY座標
- * @param nx ã\83¢ã\83³ã\82¹ã\82¿ã\83¼ã\81®X座æ¨\99
- * @return ここではドアを開けず、ガラスのドアを開ける可能性があるならTRUE
+ * @param monster モンスターへの参照
+ * @param pos モンスターの移動先座標
+ * @return ã\83\89ã\82¢ã\82\92æ\89\93ã\81¡ç ´ã\82\8bã\81ªã\82\89ã\81\93ã\81\93ã\81§ã\81®å\87¦ç\90\86ã\81¯å®\9fè¡\8cã\81\9bã\81\9atrueã\80\81é\96\8bã\81\91ã\82\8bã\81 ã\81\91ã\81ªã\82\89é\96\8bã\81\91ã\81¦falseã\82\92è¿\94ã\81\99
+ * @todo 関数名と処理内容が不一致、後で直す
  */
-static bool bash_normal_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, POSITION ny, POSITION nx)
+static bool bash_normal_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr, const MonsterEntity &monster, const Pos2D &pos)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
-    TerrainType *f_ptr;
-    f_ptr = &terrains_info[g_ptr->feat];
+    const auto &monrace = monster.get_monrace();
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
     turn_flags_ptr->do_move = false;
-    if ((r_ptr->behavior_flags.has_not(MonsterBehaviorType::OPEN_DOOR)) || f_ptr->flags.has_not(TerrainCharacteristics::OPEN) || (m_ptr->is_pet() && ((player_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0))) {
+    using Tc = TerrainCharacteristics;
+    auto can_bash = monrace.behavior_flags.has_not(MonsterBehaviorType::OPEN_DOOR);
+    can_bash |= terrain.flags.has_not(Tc::OPEN);
+    can_bash |= monster.is_pet() && ((player_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0);
+    if (can_bash) {
         return true;
     }
 
-    if (f_ptr->power == 0) {
+    if (terrain.power == 0) {
         turn_flags_ptr->did_open_door = true;
         turn_flags_ptr->do_turn = true;
         return false;
     }
 
-    if (randint0(m_ptr->hp / 10) > f_ptr->power) {
-        cave_alter_feat(player_ptr, ny, nx, TerrainCharacteristics::DISARM);
+    if (randint0(monster.hp / 10) > terrain.power) {
+        cave_alter_feat(player_ptr, pos.y, pos.x, Tc::DISARM);
         turn_flags_ptr->do_turn = true;
         return false;
     }
@@ -137,22 +147,27 @@ static bool bash_normal_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr,
  * @brief モンスターがガラスのドアを開ける処理
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
- * @param m_ptr モンスターへの参照ポインタ
- * @param g_ptr グリッドへの参照ポインタ
- * @param f_ptr 地形への参照ポインタ
+ * @param monster モンスターへの参照
+ * @param terrain 地形への参照
+ * @param may_bash ドアを打ち破るならtrue、開けるだけならfalse
+ * @todo 関数名と処理内容が不一致、後で直す
  */
-static void bash_glass_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, TerrainType *f_ptr, bool may_bash)
+static void bash_glass_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr, const MonsterEntity &monster, const TerrainType &terrain, bool may_bash)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (!may_bash || (r_ptr->behavior_flags.has_not(MonsterBehaviorType::BASH_DOOR)) || f_ptr->flags.has_not(TerrainCharacteristics::BASH) || (m_ptr->is_pet() && ((player_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0))) {
+    const auto &monrace = monster.get_monrace();
+    auto can_bash = may_bash;
+    can_bash &= monrace.behavior_flags.has(MonsterBehaviorType::BASH_DOOR);
+    can_bash &= terrain.flags.has(TerrainCharacteristics::BASH);
+    can_bash &= !monster.is_pet() || any_bits(player_ptr->pet_extra_flags, PF_OPEN_DOORS);
+    if (!can_bash) {
         return;
     }
 
-    if (!check_hp_for_feat_destruction(f_ptr, m_ptr) || (randint0(m_ptr->hp / 10) <= f_ptr->power)) {
+    if (!check_hp_for_terrain_destruction(terrain, monster) || (randint0(monster.hp / 10) <= terrain.power)) {
         return;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::GLASS)) {
+    if (terrain.flags.has(TerrainCharacteristics::GLASS)) {
         msg_print(_("ガラスが砕ける音がした!", "You hear glass breaking!"));
     } else {
         msg_print(_("ドアを叩き開ける音がした!", "You hear a door burst open!"));
@@ -171,40 +186,44 @@ static void bash_glass_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr,
  * @brief モンスターによるドアの開放・破壊を行う
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
- * @param m_ptr モンスターへの参照ポインタ
- * @param ny モンスターのY座標
- * @param nx モンスターのX座標
+ * @param monster モンスターへの参照
+ * @param pos モンスターの移動先座標
  * @return モンスターが死亡した場合のみFALSE
  */
-static bool process_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, POSITION ny, POSITION nx)
+static bool process_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr, const MonsterEntity &monster, const Pos2D &pos)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    const auto &g_ref = player_ptr->current_floor_ptr->grid_array[ny][nx];
-    if (!is_closed_door(player_ptr, g_ref.feat)) {
+    auto &monrace = monster.get_monrace();
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    if (!is_closed_door(player_ptr, grid.feat)) {
         return true;
     }
 
-    auto *terrain_ptr = &terrains_info[g_ref.feat];
-    auto may_bash = bash_normal_door(player_ptr, turn_flags_ptr, m_ptr, ny, nx);
-    bash_glass_door(player_ptr, turn_flags_ptr, m_ptr, terrain_ptr, may_bash);
+    auto &terrain = grid.get_terrain();
+    auto may_bash = bash_normal_door(player_ptr, turn_flags_ptr, monster, pos);
+    bash_glass_door(player_ptr, turn_flags_ptr, monster, terrain, may_bash);
     if (!turn_flags_ptr->did_open_door && !turn_flags_ptr->did_bash_door) {
         return true;
     }
 
-    const auto is_open = feat_state(player_ptr->current_floor_ptr, g_ref.feat, TerrainCharacteristics::OPEN) == g_ref.feat;
-    if (turn_flags_ptr->did_bash_door && ((randint0(100) < 50) || is_open || terrain_ptr->flags.has(TerrainCharacteristics::GLASS))) {
-        cave_alter_feat(player_ptr, ny, nx, TerrainCharacteristics::BASH);
-        if (!m_ptr->is_valid()) {
-            player_ptr->update |= (PU_FLOW);
-            player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
-            if (is_original_ap_and_seen(player_ptr, m_ptr)) {
-                r_ptr->r_behavior_flags.set(MonsterBehaviorType::BASH_DOOR);
+    const auto is_open = feat_state(player_ptr->current_floor_ptr, grid.feat, TerrainCharacteristics::OPEN) == grid.feat;
+    if (turn_flags_ptr->did_bash_door && ((randint0(100) < 50) || is_open || terrain.flags.has(TerrainCharacteristics::GLASS))) {
+        cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::BASH);
+        if (!monster.is_valid()) {
+            auto &rfu = RedrawingFlagsUpdater::get_instance();
+            rfu.set_flag(StatusRecalculatingFlag::FLOW);
+            static constexpr auto flags = {
+                SubWindowRedrawingFlag::OVERHEAD,
+                SubWindowRedrawingFlag::DUNGEON,
+            };
+            rfu.set_flags(flags);
+            if (is_original_ap_and_seen(player_ptr, &monster)) {
+                monrace.r_behavior_flags.set(MonsterBehaviorType::BASH_DOOR);
             }
 
             return false;
         }
     } else {
-        cave_alter_feat(player_ptr, ny, nx, TerrainCharacteristics::OPEN);
+        cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::OPEN);
     }
 
     turn_flags_ptr->do_view = true;
@@ -216,33 +235,34 @@ static bool process_door(PlayerType *player_ptr, turn_flags *turn_flags_ptr, Mon
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
  * @param m_ptr モンスターへの参照ポインタ
- * @param ny モンスターのY座標
- * @param nx モンスターのX座標
- * @return ルーンのある/なし
+ * @param pos モンスターの移動先座標
+ * @return ルーンに侵入できるか否か
  */
-static bool process_protection_rune(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, POSITION ny, POSITION nx)
+static bool process_protection_rune(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, const Pos2D &pos)
 {
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (!turn_flags_ptr->do_move || !g_ptr->is_rune_protection() || ((r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_BLOW)) && player_bold(player_ptr, ny, nx))) {
+    auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &monrace = m_ptr->get_monrace();
+    auto can_enter = turn_flags_ptr->do_move;
+    can_enter &= grid.is_rune_protection();
+    can_enter &= (monrace.behavior_flags.has_not(MonsterBehaviorType::NEVER_BLOW)) || !player_ptr->is_located_at(pos);
+    if (!can_enter) {
         return false;
     }
 
     turn_flags_ptr->do_move = false;
-    if (m_ptr->is_pet() || (randint1(BREAK_RUNE_PROTECTION) >= r_ptr->level)) {
+    if (m_ptr->is_pet() || (randint1(BREAK_RUNE_PROTECTION) >= monrace.level)) {
         return true;
     }
 
-    if (g_ptr->is_mark()) {
+    if (grid.is_mark()) {
         msg_print(_("守りのルーンが壊れた!", "The rune of protection is broken!"));
     }
 
-    g_ptr->info &= ~(CAVE_MARK);
-    g_ptr->info &= ~(CAVE_OBJECT);
-    g_ptr->mimic = 0;
+    grid.info &= ~(CAVE_MARK);
+    grid.info &= ~(CAVE_OBJECT);
+    grid.mimic = 0;
     turn_flags_ptr->do_move = true;
-    note_spot(player_ptr, ny, nx);
+    note_spot(player_ptr, pos.y, pos.x);
     return true;
 }
 
@@ -251,16 +271,17 @@ static bool process_protection_rune(PlayerType *player_ptr, turn_flags *turn_fla
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
  * @param m_ptr モンスターへの参照ポインタ
- * @param ny モンスターのY座標
- * @param nx モンスターのX座標
+ * @param pos モンスターの移動先座標
  * @return モンスターが死亡した場合のみFALSE
  */
-static bool process_explosive_rune(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, POSITION ny, POSITION nx)
+static bool process_explosive_rune(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, const Pos2D &pos)
 {
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (!turn_flags_ptr->do_move || !g_ptr->is_rune_explosion() || ((r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_BLOW)) && player_bold(player_ptr, ny, nx))) {
+    auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &monrace = m_ptr->get_monrace();
+    auto should_explode = turn_flags_ptr->do_move;
+    should_explode &= grid.is_rune_explosion();
+    should_explode &= (monrace.behavior_flags.has_not(MonsterBehaviorType::NEVER_BLOW)) || !player_ptr->is_located_at(pos);
+    if (!should_explode) {
         return true;
     }
 
@@ -269,22 +290,22 @@ static bool process_explosive_rune(PlayerType *player_ptr, turn_flags *turn_flag
         return true;
     }
 
-    if (randint1(BREAK_RUNE_EXPLOSION) > r_ptr->level) {
-        if (g_ptr->info & CAVE_MARK) {
+    if (randint1(BREAK_RUNE_EXPLOSION) > monrace.level) {
+        if (grid.info & CAVE_MARK) {
             msg_print(_("ルーンが爆発した!", "The rune explodes!"));
             BIT_FLAGS project_flags = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI;
-            project(player_ptr, 0, 2, ny, nx, 2 * (player_ptr->lev + damroll(7, 7)), AttributeType::MANA, project_flags);
+            project(player_ptr, 0, 2, pos.y, pos.x, 2 * (player_ptr->lev + damroll(7, 7)), AttributeType::MANA, project_flags);
         }
     } else {
         msg_print(_("爆発のルーンは解除された。", "An explosive rune was disarmed."));
     }
 
-    g_ptr->info &= ~(CAVE_MARK);
-    g_ptr->info &= ~(CAVE_OBJECT);
-    g_ptr->mimic = 0;
+    grid.info &= ~(CAVE_MARK);
+    grid.info &= ~(CAVE_OBJECT);
+    grid.mimic = 0;
 
-    note_spot(player_ptr, ny, nx);
-    lite_spot(player_ptr, ny, nx);
+    note_spot(player_ptr, pos.y, pos.x);
+    lite_spot(player_ptr, pos.y, pos.x);
 
     if (!m_ptr->is_valid()) {
         return false;
@@ -298,44 +319,45 @@ static bool process_explosive_rune(PlayerType *player_ptr, turn_flags *turn_flag
  * @brief モンスターが壁を掘った後続処理を実行する
  * @param player_ptr プレイヤーへの参照ポインタ
  * @turn_flags_ptr ターン経過処理フラグへの参照ポインタ
- * @param m_ptr モンスターへの参照ポインタ
- * @param ny モンスターのY座標
- * @param nx モンスターのX座標
+ * @param monster モンスターへの参照
+ * @param pos モンスターの移動先座標
  * @return モンスターが死亡した場合のみFALSE
  */
-static bool process_post_dig_wall(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr, POSITION ny, POSITION nx)
+static bool process_post_dig_wall(PlayerType *player_ptr, turn_flags *turn_flags_ptr, const MonsterEntity &monster, const Pos2D &pos)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
-    TerrainType *f_ptr;
-    f_ptr = &terrains_info[g_ptr->feat];
+    auto &monrace = monster.get_monrace();
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
     if (!turn_flags_ptr->did_kill_wall || !turn_flags_ptr->do_move) {
         return true;
     }
 
     constexpr auto chance_sound = 20;
     if (one_in_(chance_sound)) {
-        if (f_ptr->flags.has(TerrainCharacteristics::GLASS)) {
+        if (terrain.flags.has(TerrainCharacteristics::GLASS)) {
             msg_print(_("何かの砕ける音が聞こえる。", "There is a crashing sound."));
         } else {
             msg_print(_("ギシギシいう音が聞こえる。", "There is a grinding sound."));
         }
     }
 
-    cave_alter_feat(player_ptr, ny, nx, TerrainCharacteristics::HURT_DISI);
+    cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::HURT_DISI);
 
-    if (!m_ptr->is_valid()) {
-        player_ptr->update |= (PU_FLOW);
-        player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
-        if (is_original_ap_and_seen(player_ptr, m_ptr)) {
-            r_ptr->r_feature_flags.set(MonsterFeatureType::KILL_WALL);
+    if (!monster.is_valid()) {
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(StatusRecalculatingFlag::FLOW);
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::OVERHEAD,
+            SubWindowRedrawingFlag::DUNGEON,
+        };
+        rfu.set_flags(flags);
+        if (is_original_ap_and_seen(player_ptr, &monster)) {
+            monrace.r_feature_flags.set(MonsterFeatureType::KILL_WALL);
         }
 
         return false;
     }
 
-    f_ptr = &terrains_info[g_ptr->feat];
     turn_flags_ptr->do_view = true;
     turn_flags_ptr->do_turn = true;
     return true;
@@ -347,13 +369,12 @@ static bool process_post_dig_wall(PlayerType *player_ptr, turn_flags *turn_flags
  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
  * @param m_idx モンスターID
  * @param mm モンスターの移動方向
- * @param oy 移動前の、モンスターのY座標
- * @param ox 移動前の、モンスターのX座標
+ * @param pos モンスターの移動前座標
  * @param count 移動回数 (のはず todo)
  * @return 移動が阻害される何か (ドア等)があったらFALSE
  * @todo 少し長いが、これといってブロックとしてまとまった部分もないので暫定でこのままとする
  */
-bool process_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, DIRECTION *mm, POSITION oy, POSITION ox, int *count)
+bool process_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, DIRECTION *mm, const Pos2D &pos, int *count)
 {
     for (int i = 0; mm[i]; i++) {
         int d = mm[i];
@@ -361,48 +382,46 @@ bool process_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr
             d = ddd[randint0(8)];
         }
 
-        POSITION ny = oy + ddy[d];
-        POSITION nx = ox + ddx[d];
-        if (!in_bounds2(player_ptr->current_floor_ptr, ny, nx)) {
+        const Pos2D pos_neighbor(pos.y + ddy[d], pos.x + ddx[d]);
+        if (!in_bounds2(player_ptr->current_floor_ptr, pos_neighbor.y, pos_neighbor.x)) {
             continue;
         }
 
-        grid_type *g_ptr;
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
-        bool can_cross = monster_can_cross_terrain(player_ptr, g_ptr->feat, r_ptr, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0);
+        auto &grid = player_ptr->current_floor_ptr->get_grid(pos_neighbor);
+        auto &monster = player_ptr->current_floor_ptr->m_list[m_idx];
+        auto &monrace = monster.get_monrace();
+        bool can_cross = monster_can_cross_terrain(player_ptr, grid.feat, &monrace, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0);
 
-        if (!process_wall(player_ptr, turn_flags_ptr, m_ptr, ny, nx, can_cross)) {
-            if (!process_door(player_ptr, turn_flags_ptr, m_ptr, ny, nx)) {
+        if (!process_wall(player_ptr, turn_flags_ptr, monster, pos_neighbor, can_cross)) {
+            if (!process_door(player_ptr, turn_flags_ptr, monster, pos_neighbor)) {
                 return false;
             }
         }
 
-        if (!process_protection_rune(player_ptr, turn_flags_ptr, m_ptr, ny, nx)) {
-            if (!process_explosive_rune(player_ptr, turn_flags_ptr, m_ptr, ny, nx)) {
+        if (!process_protection_rune(player_ptr, turn_flags_ptr, &monster, pos_neighbor)) {
+            if (!process_explosive_rune(player_ptr, turn_flags_ptr, &monster, pos_neighbor)) {
                 return false;
             }
         }
 
-        exe_monster_attack_to_player(player_ptr, turn_flags_ptr, m_idx, ny, nx);
-        if (process_monster_attack_to_monster(player_ptr, turn_flags_ptr, m_idx, g_ptr, can_cross)) {
+        exe_monster_attack_to_player(player_ptr, turn_flags_ptr, m_idx, pos_neighbor);
+        if (process_monster_attack_to_monster(player_ptr, turn_flags_ptr, m_idx, &grid, can_cross)) {
             return false;
         }
 
         if (turn_flags_ptr->is_riding_mon) {
-            const auto &m_ref = player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-            if (!player_ptr->riding_ryoute && !m_ref.is_fearful()) {
+            const auto &monster_riding = player_ptr->current_floor_ptr->m_list[player_ptr->riding];
+            if (!player_ptr->riding_ryoute && !monster_riding.is_fearful()) {
                 turn_flags_ptr->do_move = false;
             }
         }
 
-        if (!process_post_dig_wall(player_ptr, turn_flags_ptr, m_ptr, ny, nx)) {
+        if (!process_post_dig_wall(player_ptr, turn_flags_ptr, monster, pos_neighbor)) {
             return false;
         }
 
-        if (turn_flags_ptr->must_alter_to_move && r_ptr->feature_flags.has(MonsterFeatureType::AQUATIC)) {
-            if (!monster_can_cross_terrain(player_ptr, g_ptr->feat, r_ptr, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0)) {
+        if (turn_flags_ptr->must_alter_to_move && monrace.feature_flags.has(MonsterFeatureType::AQUATIC)) {
+            if (!monster_can_cross_terrain(player_ptr, grid.feat, &monrace, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0)) {
                 turn_flags_ptr->do_move = false;
             }
         }
@@ -411,9 +430,9 @@ bool process_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr
             turn_flags_ptr->do_move = false;
         }
 
-        if (turn_flags_ptr->do_move && r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_MOVE)) {
-            if (is_original_ap_and_seen(player_ptr, m_ptr)) {
-                r_ptr->r_behavior_flags.set(MonsterBehaviorType::NEVER_MOVE);
+        if (turn_flags_ptr->do_move && monrace.behavior_flags.has(MonsterBehaviorType::NEVER_MOVE)) {
+            if (is_original_ap_and_seen(player_ptr, &monster)) {
+                monrace.r_behavior_flags.set(MonsterBehaviorType::NEVER_MOVE);
             }
 
             turn_flags_ptr->do_move = false;
@@ -428,35 +447,35 @@ bool process_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr
         }
 
         turn_flags_ptr->do_turn = true;
-        const auto &terrain_ref = terrains_info[g_ptr->feat];
-        auto can_recover_energy = terrain_ref.flags.has(TerrainCharacteristics::TREE);
-        can_recover_energy &= r_ptr->feature_flags.has_not(MonsterFeatureType::CAN_FLY);
-        can_recover_energy &= r_ptr->wilderness_flags.has_not(MonsterWildernessType::WILD_WOOD);
+        const auto &terrain = grid.get_terrain();
+        auto can_recover_energy = terrain.flags.has(TerrainCharacteristics::TREE);
+        can_recover_energy &= monrace.feature_flags.has_not(MonsterFeatureType::CAN_FLY);
+        can_recover_energy &= monrace.wilderness_flags.has_not(MonsterWildernessType::WILD_WOOD);
         if (can_recover_energy) {
-            m_ptr->energy_need += ENERGY_NEED();
+            monster.energy_need += ENERGY_NEED();
         }
 
-        if (!update_riding_monster(player_ptr, turn_flags_ptr, m_idx, oy, ox, ny, nx)) {
+        if (!update_riding_monster(player_ptr, turn_flags_ptr, m_idx, pos.y, pos.x, pos_neighbor.y, pos_neighbor.x)) {
             break;
         }
 
-        const auto &ap_r_ref = monraces_info[m_ptr->ap_r_idx];
-        const auto is_projectable = projectable(player_ptr, player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx);
-        const auto can_see = disturb_near && m_ptr->mflag.has(MonsterTemporaryFlagType::VIEW) && is_projectable;
+        const auto &ap_r_ref = monster.get_appearance_monrace();
+        const auto is_projectable = projectable(player_ptr, player_ptr->y, player_ptr->x, monster.fy, monster.fx);
+        const auto can_see = disturb_near && monster.mflag.has(MonsterTemporaryFlagType::VIEW) && is_projectable;
         const auto is_high_level = disturb_high && (ap_r_ref.r_tkills > 0) && (ap_r_ref.level >= player_ptr->lev);
-        if (m_ptr->ml && (disturb_move || can_see || is_high_level)) {
-            if (m_ptr->is_hostile()) {
+        if (monster.ml && (disturb_move || can_see || is_high_level)) {
+            if (monster.is_hostile()) {
                 disturb(player_ptr, false, true);
             }
         }
 
-        bool is_takable_or_killable = !g_ptr->o_idx_list.empty();
-        is_takable_or_killable &= r_ptr->behavior_flags.has_any_of({ MonsterBehaviorType::TAKE_ITEM, MonsterBehaviorType::KILL_ITEM });
+        bool is_takable_or_killable = !grid.o_idx_list.empty();
+        is_takable_or_killable &= monrace.behavior_flags.has_any_of({ MonsterBehaviorType::TAKE_ITEM, MonsterBehaviorType::KILL_ITEM });
 
         bool is_pickup_items = (player_ptr->pet_extra_flags & PF_PICKUP_ITEMS) != 0;
-        is_pickup_items &= r_ptr->behavior_flags.has(MonsterBehaviorType::TAKE_ITEM);
+        is_pickup_items &= monrace.behavior_flags.has(MonsterBehaviorType::TAKE_ITEM);
 
-        is_takable_or_killable &= !m_ptr->is_pet() || is_pickup_items;
+        is_takable_or_killable &= !monster.is_pet() || is_pickup_items;
         if (!is_takable_or_killable) {
             if (turn_flags_ptr->do_turn) {
                 break;
@@ -465,7 +484,7 @@ bool process_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr
             continue;
         }
 
-        update_object_by_monster_movement(player_ptr, turn_flags_ptr, m_idx, ny, nx);
+        update_object_by_monster_movement(player_ptr, turn_flags_ptr, m_idx, pos_neighbor.y, pos_neighbor.x);
         if (turn_flags_ptr->do_turn) {
             break;
         }
@@ -483,23 +502,23 @@ static bool can_speak(const MonsterRaceInfo &ap_r_ref, MonsterSpeakType mon_spea
     return can_speak_all || can_speak_specific;
 }
 
-static std::string_view get_speak_filename(MonsterEntity *m_ptr)
+static std::string_view get_speak_filename(const MonsterEntity &monster)
 {
-    const auto &ap_r_ref = monraces_info[m_ptr->ap_r_idx];
-    if (m_ptr->is_fearful() && can_speak(ap_r_ref, MonsterSpeakType::SPEAK_FEAR)) {
+    const auto &ap_monrace = monster.get_appearance_monrace();
+    if (monster.is_fearful() && can_speak(ap_monrace, MonsterSpeakType::SPEAK_FEAR)) {
         return _("monfear_j.txt", "monfear.txt");
     }
 
     constexpr auto monspeak_txt(_("monspeak_j.txt", "monspeak.txt"));
-    if (m_ptr->is_pet() && can_speak(ap_r_ref, MonsterSpeakType::SPEAK_BATTLE)) {
+    if (monster.is_pet() && can_speak(ap_monrace, MonsterSpeakType::SPEAK_BATTLE)) {
         return monspeak_txt;
     }
 
-    if (m_ptr->is_friendly() && can_speak(ap_r_ref, MonsterSpeakType::SPEAK_FRIEND)) {
+    if (monster.is_friendly() && can_speak(ap_monrace, MonsterSpeakType::SPEAK_FRIEND)) {
         return _("monfrien_j.txt", "monfrien.txt");
     }
 
-    if (can_speak(ap_r_ref, MonsterSpeakType::SPEAK_BATTLE)) {
+    if (can_speak(ap_monrace, MonsterSpeakType::SPEAK_BATTLE)) {
         return monspeak_txt;
     }
 
@@ -516,33 +535,34 @@ static std::string_view get_speak_filename(MonsterEntity *m_ptr)
  */
 void process_speak_sound(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION oy, POSITION ox, bool aware)
 {
-    if (player_ptr->phase_out) {
+    if (AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &monster = floor.m_list[m_idx];
     constexpr auto chance_noise = 20;
-    if (m_ptr->ap_r_idx == MonsterRaceId::CYBER && one_in_(chance_noise) && !m_ptr->ml && (m_ptr->cdis <= MAX_PLAYER_SIGHT)) {
+    if (monster.ap_r_idx == MonsterRaceId::CYBER && one_in_(chance_noise) && !monster.ml && (monster.cdis <= MAX_PLAYER_SIGHT)) {
         if (disturb_minor) {
             disturb(player_ptr, false, false);
         }
         msg_print(_("重厚な足音が聞こえた。", "You hear heavy steps."));
     }
 
-    auto can_speak = monraces_info[m_ptr->ap_r_idx].speak_flags.any();
+    const auto can_speak = monster.get_appearance_monrace().speak_flags.any();
     constexpr auto chance_speak = 8;
-    if (!can_speak || !aware || !one_in_(chance_speak) || !player_has_los_bold(player_ptr, oy, ox) || !projectable(player_ptr, oy, ox, player_ptr->y, player_ptr->x)) {
+    if (!can_speak || !aware || !one_in_(chance_speak) || !floor.has_los({ oy, ox }) || !projectable(player_ptr, oy, ox, player_ptr->y, player_ptr->x)) {
         return;
     }
 
-    const auto m_name = m_ptr->ml ? monster_desc(player_ptr, m_ptr, 0) : std::string(_("それ", "It"));
-    auto filename = get_speak_filename(m_ptr);
+    const auto m_name = monster.ml ? monster_desc(player_ptr, &monster, 0) : std::string(_("それ", "It"));
+    auto filename = get_speak_filename(monster);
     if (filename.empty()) {
         return;
     }
 
-    const auto monmessage = get_random_line(filename.data(), enum2i(m_ptr->ap_r_idx));
-    if (monmessage.has_value()) {
+    const auto monmessage = get_random_line(filename.data(), enum2i(monster.ap_r_idx));
+    if (monmessage) {
         msg_format(_("%s^%s", "%s^ %s"), m_name.data(), monmessage->data());
     }
 }
index a990b57..b08ce5a 100644 (file)
@@ -1,6 +1,7 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
+#include "util/point-2d.h"
 
 constexpr auto BREAK_RUNE_PROTECTION = 550; /*!< 守りのルーンの強靭度 / Rune of protection resistance */
 constexpr auto BREAK_RUNE_EXPLOSION = 299; /*!< 爆発のルーンの発動しやすさ / For explosive runes */
@@ -8,7 +9,7 @@ constexpr auto BREAK_RUNE_EXPLOSION = 299; /*!< 爆発のルーンの発動し
 class MonsterEntity;
 class PlayerType;
 struct turn_flags;
-bool process_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, DIRECTION *mm, POSITION oy, POSITION ox, int *count);
+bool process_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, DIRECTION *mm, const Pos2D &pos, int *count);
 void process_speak_sound(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION oy, POSITION ox, bool aware);
 void set_target(MonsterEntity *m_ptr, POSITION y, POSITION x);
 void reset_target(MonsterEntity *m_ptr);
index 8ad3488..c3f5d7e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターが移動した結果、床のアイテムに重なった時の処理と、モンスターがアイテムを落とす処理
  * @date 2020/03/07
  * @author Hourier
@@ -7,7 +7,6 @@
 #include "monster-floor/monster-object.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
-#include "floor/cave.h"
 #include "floor/floor-object.h"
 #include "floor/geometry.h"
 #include "monster-race/monster-race.h"
@@ -21,7 +20,6 @@
 #include "monster/monster-processor-util.h"
 #include "monster/smart-learn-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/object-mark-types.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -29,6 +27,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include <string_view>
@@ -131,12 +130,13 @@ static void update_object_flags(const TrFlags &flags, EnumClassFlagGroup<Monster
 static void monster_pickup_object(PlayerType *player_ptr, turn_flags *turn_flags_ptr, const MONSTER_IDX m_idx, ItemEntity *o_ptr, const bool is_unpickable_object,
     const POSITION ny, const POSITION nx, std::string_view m_name, std::string_view o_name, const OBJECT_IDX this_o_idx)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &monster = floor.m_list[m_idx];
+    const auto &monrace = monster.get_monrace();
     if (is_unpickable_object) {
-        if (turn_flags_ptr->do_take && r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) {
+        if (turn_flags_ptr->do_take && monrace.behavior_flags.has(MonsterBehaviorType::STUPID)) {
             turn_flags_ptr->did_take_item = true;
-            if (m_ptr->ml && player_can_see_bold(player_ptr, ny, nx)) {
+            if (monster.ml && player_can_see_bold(player_ptr, ny, nx)) {
                 msg_format(_("%s^は%sを拾おうとしたが、だめだった。", "%s^ tries to pick up %s, but fails."), m_name.data(), o_name.data());
             }
         }
@@ -155,17 +155,17 @@ static void monster_pickup_object(PlayerType *player_ptr, turn_flags *turn_flags
         o_ptr->marked &= { OmType::TOUCHED };
         o_ptr->iy = o_ptr->ix = 0;
         o_ptr->held_m_idx = m_idx;
-        m_ptr->hold_o_idx_list.add(player_ptr->current_floor_ptr, this_o_idx);
-        player_ptr->window_flags |= PW_FOUND_ITEMS;
+        monster.hold_o_idx_list.add(player_ptr->current_floor_ptr, this_o_idx);
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::FOUND_ITEMS);
         return;
     }
 
-    if (m_ptr->is_pet()) {
+    if (monster.is_pet()) {
         return;
     }
 
     turn_flags_ptr->did_kill_item = true;
-    if (player_has_los_bold(player_ptr, ny, nx)) {
+    if (floor.has_los({ ny, nx })) {
         msg_format(_("%s^が%sを破壊した。", "%s^ destroys %s."), m_name.data(), o_name.data());
     }
 
@@ -183,7 +183,7 @@ static void monster_pickup_object(PlayerType *player_ptr, turn_flags *turn_flags
 void update_object_by_monster_movement(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, POSITION ny, POSITION nx)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
     turn_flags_ptr->do_take = r_ptr->behavior_flags.has(MonsterBehaviorType::TAKE_ITEM);
     for (auto it = g_ptr->o_idx_list.begin(); it != g_ptr->o_idx_list.end();) {
@@ -199,7 +199,7 @@ void update_object_by_monster_movement(PlayerType *player_ptr, turn_flags *turn_
             }
         }
 
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
         const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
         const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_HIDDEN);
         update_object_flags(flags, flg_monster_kind, flgr);
index a7b2e35..7e924af 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f83ce3e..9c5b03d 100644 (file)
@@ -1,5 +1,4 @@
-#include "monster-floor/monster-remover.h"
-#include "core/player-update-types.h"
+#include "monster-floor/monster-remover.h"
 #include "core/stuff-handler.h"
 #include "floor/cave.h"
 #include "floor/floor-object.h"
@@ -18,6 +17,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 
 /*!
@@ -31,12 +31,12 @@ void delete_monster_idx(PlayerType *player_ptr, MONSTER_IDX i)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[i];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     POSITION y = m_ptr->fy;
     POSITION x = m_ptr->fx;
 
-    m_ptr->get_real_r_ref().cur_num--;
+    m_ptr->get_real_monrace().cur_num--;
     if (r_ptr->flags2 & (RF2_MULTIPLY)) {
         floor_ptr->num_repro--;
     }
@@ -100,39 +100,18 @@ void delete_monster_idx(PlayerType *player_ptr, MONSTER_IDX i)
     floor_ptr->m_cnt--;
     lite_spot(player_ptr, y, x);
     if (r_ptr->brightness_flags.has_any_of(ld_mask)) {
-        player_ptr->update |= (PU_MONSTER_LITE);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 }
 
 /*!
- * @brief プレイヤーのフロア離脱に伴う全モンスター配列の消去 / Delete/Remove all the monsters when the player leaves the level
+ * @brief プレイヤーのフロア離脱に伴う全モンスター配列の消去
  * @param player_ptr プレイヤーへの参照ポインタ
- * @details
- * This is an efficient method of simulating multiple calls to the
- * "delete_monster()" function, with no visual effects.
+ * @details 視覚効果なしでdelete_monster() をフロア全体に対して呼び出す.
  */
 void wipe_monsters_list(PlayerType *player_ptr)
 {
-    if (!monraces_info[MonsterRaceId::BANORLUPART].max_num) {
-        if (monraces_info[MonsterRaceId::BANOR].max_num) {
-            monraces_info[MonsterRaceId::BANOR].max_num = 0;
-            monraces_info[MonsterRaceId::BANOR].r_pkills++;
-            monraces_info[MonsterRaceId::BANOR].r_akills++;
-            if (monraces_info[MonsterRaceId::BANOR].r_tkills < MAX_SHORT) {
-                monraces_info[MonsterRaceId::BANOR].r_tkills++;
-            }
-        }
-
-        if (monraces_info[MonsterRaceId::LUPART].max_num) {
-            monraces_info[MonsterRaceId::LUPART].max_num = 0;
-            monraces_info[MonsterRaceId::LUPART].r_pkills++;
-            monraces_info[MonsterRaceId::LUPART].r_akills++;
-            if (monraces_info[MonsterRaceId::LUPART].r_tkills < MAX_SHORT) {
-                monraces_info[MonsterRaceId::LUPART].r_tkills++;
-            }
-        }
-    }
-
+    MonraceList::get_instance().defeat_separated_uniques();
     auto *floor_ptr = player_ptr->current_floor_ptr;
     for (int i = floor_ptr->m_max - 1; i >= 1; i--) {
         auto *m_ptr = &floor_ptr->m_list[i];
@@ -174,7 +153,7 @@ void wipe_monsters_list(PlayerType *player_ptr)
  */
 void delete_monster(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    grid_type *g_ptr;
+    Grid *g_ptr;
     auto *floor_ptr = player_ptr->current_floor_ptr;
     if (!in_bounds(floor_ptr, y, x)) {
         return;
index 5a69da7..5f7746e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index bc61d11..35332cd 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの逃走に関する処理
  * @date 2020/03/08
  * @author Hourier
@@ -7,7 +7,6 @@
 #include "monster-floor/monster-runaway.h"
 #include "core/disturbance.h"
 #include "dungeon/quest-completion-checker.h"
-#include "floor/cave.h"
 #include "grid/grid.h"
 #include "monster-floor/monster-remover.h"
 #include "monster-race/monster-race.h"
@@ -19,6 +18,7 @@
 #include "monster/monster-info.h"
 #include "monster/monster-processor-util.h"
 #include "pet/pet-fall-off.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
@@ -56,15 +56,15 @@ static void escape_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, M
     }
 
     if (turn_flags_ptr->see_m) {
-        const auto flags = {
+        static constexpr auto flags = {
             MonsterSpeakType::SPEAK_ALL,
             MonsterSpeakType::SPEAK_BATTLE,
             MonsterSpeakType::SPEAK_FEAR,
         };
 
-        auto speak = monraces_info[m_ptr->r_idx].speak_flags.has_any_of(flags);
+        auto speak = m_ptr->get_monrace().speak_flags.has_any_of(flags);
         speak &= !is_acting_monster(m_ptr->r_idx);
-        speak &= player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx);
+        speak &= player_ptr->current_floor_ptr->has_los({ m_ptr->fy, m_ptr->fx });
         speak &= projectable(player_ptr, m_ptr->fy, m_ptr->fx, player_ptr->y, player_ptr->x);
         if (speak) {
             msg_format(_("%s^「ピンチだ!退却させてもらう!」", "%s^ says 'It is the pinch! I will retreat'."), m_name);
@@ -90,10 +90,10 @@ static void escape_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, M
 bool runaway_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     bool can_runaway = m_ptr->is_pet() || m_ptr->is_friendly();
     can_runaway &= (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) || (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL));
-    can_runaway &= !player_ptr->phase_out;
+    can_runaway &= !AngbandSystem::get_instance().is_phase_out();
     if (!can_runaway) {
         return false;
     }
index e175cb1..dd09b56 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b86d389..07bf514 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの逃走・隠匿に関する処理
  * @date 2020/03/08
  * @author Hourier
@@ -42,8 +42,8 @@ static coordinate_candidate sweep_safe_coordinate(PlayerType *player_ptr, MONSTE
             continue;
         }
 
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
-        grid_type *g_ptr;
+        auto *r_ptr = &m_ptr->get_monrace();
+        Grid *g_ptr;
         g_ptr = &floor_ptr->grid_array[y][x];
 
         BIT_FLAGS16 riding_mode = (m_idx == player_ptr->riding) ? CEM_RIDING : 0;
@@ -133,7 +133,7 @@ bool find_safety(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITI
 static void sweep_hiding_candidate(
     PlayerType *player_ptr, MonsterEntity *m_ptr, const POSITION *y_offsets, const POSITION *x_offsets, coordinate_candidate *candidate)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     for (POSITION i = 0, dx = x_offsets[0], dy = y_offsets[0]; dx != 0 || dy != 0; i++, dx = x_offsets[i], dy = y_offsets[i]) {
         POSITION y = m_ptr->fy + dy;
         POSITION x = m_ptr->fx + dx;
index 4663bc1..1692903 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index ea4fd11..1d4dfc7 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-floor/monster-summon.h"
+#include "monster-floor/monster-summon.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/geometry.h"
 #include "floor/wild.h"
@@ -48,8 +48,9 @@ static bool summon_specific_okay(PlayerType *player_ptr, MonsterRaceId r_idx)
         return false;
     }
 
+    auto &floor = *player_ptr->current_floor_ptr;
     if (summon_specific_who > 0) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[summon_specific_who];
+        auto *m_ptr = &floor.m_list[summon_specific_who];
         if (monster_has_hostile_align(player_ptr, m_ptr, 0, 0, r_ptr)) {
             return false;
         }
@@ -67,16 +68,17 @@ static bool summon_specific_okay(PlayerType *player_ptr, MonsterRaceId r_idx)
         return true;
     }
 
-    if ((summon_specific_who < 0) && (r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL))) && monster_has_hostile_align(player_ptr, nullptr, 10, -10, r_ptr)) {
+    const auto is_like_unique = r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL));
+    if ((summon_specific_who < 0) && is_like_unique && monster_has_hostile_align(player_ptr, nullptr, 10, -10, r_ptr)) {
         return false;
     }
 
-    if ((r_ptr->flags7 & RF7_CHAMELEON) && dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::CHAMELEON)) {
+    if ((r_ptr->flags7 & RF7_CHAMELEON) && floor.get_dungeon_definition().flags.has(DungeonFeatureType::CHAMELEON)) {
         return true;
     }
 
     if (summon_specific_who > 0) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[summon_specific_who];
+        auto *m_ptr = &floor.m_list[summon_specific_who];
         return check_summon_specific(player_ptr, m_ptr->r_idx, r_idx);
     } else {
         return check_summon_specific(player_ptr, MonsterRaceId::PLAYER, r_idx);
@@ -143,7 +145,7 @@ bool summon_specific(PlayerType *player_ptr, MONSTER_IDX who, POSITION y1, POSIT
     get_mon_num_prep(player_ptr, summon_specific_okay, get_monster_hook2(player_ptr, y, x));
 
     DEPTH dlev = get_dungeon_or_wilderness_level(player_ptr);
-    MonsterRaceId r_idx = get_mon_num(player_ptr, 0, (dlev + lev) / 2 + 5, 0);
+    MonsterRaceId r_idx = get_mon_num(player_ptr, 0, (dlev + lev) / 2 + 5, mode);
     if (!MonsterRace(r_idx).is_valid()) {
         summon_specific_type = SUMMON_NONE;
         return false;
@@ -153,7 +155,7 @@ bool summon_specific(PlayerType *player_ptr, MONSTER_IDX who, POSITION y1, POSIT
         mode |= PM_NO_KAGE;
     }
 
-    if (!place_monster_aux(player_ptr, who, y, x, r_idx, mode)) {
+    if (!place_specific_monster(player_ptr, who, y, x, r_idx, mode)) {
         summon_specific_type = SUMMON_NONE;
         return false;
     }
@@ -202,5 +204,5 @@ bool summon_named_creature(PlayerType *player_ptr, MONSTER_IDX who, POSITION oy,
         return false;
     }
 
-    return place_monster_aux(player_ptr, who, y, x, r_idx, (mode | PM_NO_KAGE));
+    return place_specific_monster(player_ptr, who, y, x, r_idx, (mode | PM_NO_KAGE));
 }
index 7c09c37..8577ef9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f8166c0..cbfd43f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの移動方向を走査する処理
  * @date 2020/03/08
  * @author Hourier
@@ -50,25 +50,27 @@ MonsterSweepGrid::MonsterSweepGrid(PlayerType *player_ptr, MONSTER_IDX m_idx, DI
  */
 bool MonsterSweepGrid::get_movable_grid()
 {
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto *m_ptr = &floor_ptr->m_list[this->m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    POSITION y = 0;
-    POSITION x = 0;
+    auto &floor = *this->player_ptr->current_floor_ptr;
+    const auto &monster_from = floor.m_list[this->m_idx];
+    auto &monrace = monster_from.get_monrace();
+    auto y = 0;
+    auto x = 0;
     auto y2 = this->player_ptr->y;
     auto x2 = this->player_ptr->x;
     this->will_run = this->mon_will_run();
-    const auto no_flow = m_ptr->mflag2.has(MonsterConstantFlagType::NOFLOW) && (floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].get_cost(r_ptr) > 2);
-    this->can_pass_wall = r_ptr->feature_flags.has(MonsterFeatureType::PASS_WALL) && ((this->m_idx != this->player_ptr->riding) || has_pass_wall(this->player_ptr));
-    if (!this->will_run && m_ptr->target_y) {
-        int t_m_idx = floor_ptr->grid_array[m_ptr->target_y][m_ptr->target_x].m_idx;
+    Pos2D pos_monster_from(monster_from.fy, monster_from.fx);
+    const auto no_flow = monster_from.mflag2.has(MonsterConstantFlagType::NOFLOW) && (floor.get_grid(pos_monster_from).get_cost(&monrace) > 2);
+    this->can_pass_wall = monrace.feature_flags.has(MonsterFeatureType::PASS_WALL) && ((this->m_idx != this->player_ptr->riding) || has_pass_wall(this->player_ptr));
+    if (!this->will_run && monster_from.target_y) {
+        Pos2D pos_target(monster_from.target_y, monster_from.target_x);
+        int t_m_idx = floor.get_grid(pos_target).m_idx;
         if (t_m_idx > 0) {
-            const auto is_enemies = are_enemies(this->player_ptr, *m_ptr, floor_ptr->m_list[t_m_idx]);
-            const auto is_los = los(this->player_ptr, m_ptr->fy, m_ptr->fx, m_ptr->target_y, m_ptr->target_x);
-            const auto is_projectable = projectable(this->player_ptr, m_ptr->fy, m_ptr->fx, m_ptr->target_y, m_ptr->target_x);
+            const auto is_enemies = monster_from.is_hostile_to_melee(floor.m_list[t_m_idx]);
+            const auto is_los = los(this->player_ptr, monster_from.fy, monster_from.fx, monster_from.target_y, monster_from.target_x);
+            const auto is_projectable = projectable(this->player_ptr, monster_from.fy, monster_from.fx, monster_from.target_y, monster_from.target_x);
             if (is_enemies && is_los && is_projectable) {
-                y = m_ptr->fy - m_ptr->target_y;
-                x = m_ptr->fx - m_ptr->target_x;
+                y = monster_from.fy - monster_from.target_y;
+                x = monster_from.fx - monster_from.target_x;
                 this->done = true;
             }
         }
@@ -77,8 +79,8 @@ bool MonsterSweepGrid::get_movable_grid()
     this->check_hiding_grid(&y, &x, &y2, &x2);
     if (!this->done) {
         this->sweep_movable_grid(&y2, &x2, no_flow);
-        y = m_ptr->fy - y2;
-        x = m_ptr->fx - x2;
+        y = monster_from.fy - y2;
+        x = monster_from.fx - x2;
     }
 
     this->search_pet_runnable_grid(&y, &x, no_flow);
@@ -98,7 +100,7 @@ bool MonsterSweepGrid::get_movable_grid()
 bool MonsterSweepGrid::mon_will_run()
 {
     auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (m_ptr->is_pet()) {
         return (this->player_ptr->pet_follow_distance < 0) && (m_ptr->cdis <= (0 - this->player_ptr->pet_follow_distance));
     }
@@ -138,7 +140,7 @@ void MonsterSweepGrid::check_hiding_grid(POSITION *y, POSITION *x, POSITION *y2,
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[this->m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (this->done || this->will_run || !m_ptr->is_hostile() || none_bits(r_ptr->flags1, RF1_FRIENDS)) {
         return;
     }
@@ -251,27 +253,29 @@ void MonsterSweepGrid::search_pet_runnable_grid(POSITION *y, POSITION *x, bool n
  */
 void MonsterSweepGrid::sweep_movable_grid(POSITION *yp, POSITION *xp, bool no_flow)
 {
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto *m_ptr = &floor_ptr->m_list[this->m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto &floor = *this->player_ptr->current_floor_ptr;
+    auto &monster = floor.m_list[this->m_idx];
+    auto &monrace = monster.get_monrace();
     if (!this->check_movable_grid(yp, xp, no_flow)) {
         return;
     }
 
-    auto y1 = m_ptr->fy;
-    auto x1 = m_ptr->fx;
-    auto *g_ptr = &floor_ptr->grid_array[y1][x1];
-    if (player_has_los_bold(this->player_ptr, y1, x1) && projectable(this->player_ptr, this->player_ptr->y, this->player_ptr->x, y1, x1)) {
-        if ((distance(y1, x1, this->player_ptr->y, this->player_ptr->x) == 1) || (r_ptr->freq_spell > 0) || (g_ptr->get_cost(r_ptr) > 5)) {
+    auto y1 = monster.fy;
+    auto x1 = monster.fx;
+    const Pos2D pos(y1, x1);
+    const auto &grid = floor.get_grid(pos);
+    if (grid.has_los() && projectable(this->player_ptr, this->player_ptr->y, this->player_ptr->x, y1, x1)) {
+        if ((distance(y1, x1, this->player_ptr->y, this->player_ptr->x) == 1) || (monrace.freq_spell > 0) || (grid.get_cost(&monrace) > 5)) {
             return;
         }
     }
 
     auto use_scent = false;
-    if (g_ptr->get_cost(r_ptr)) {
+    if (grid.get_cost(&monrace)) {
         this->best = 999;
-    } else if (g_ptr->when) {
-        if (floor_ptr->grid_array[this->player_ptr->y][this->player_ptr->x].when - g_ptr->when > 127) {
+    } else if (grid.when) {
+        const auto p_pos = this->player_ptr->get_position();
+        if (floor.get_grid(p_pos).when - grid.when > 127) {
             return;
         }
 
@@ -317,7 +321,7 @@ bool MonsterSweepGrid::sweep_ranged_attack_grid(POSITION *yp, POSITION *xp)
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[this->m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     auto y1 = m_ptr->fy;
     auto x1 = m_ptr->fx;
     if (projectable(this->player_ptr, y1, x1, this->player_ptr->y, this->player_ptr->x)) {
@@ -334,19 +338,18 @@ bool MonsterSweepGrid::sweep_ranged_attack_grid(POSITION *yp, POSITION *xp)
     }
 
     for (auto i = 7; i >= 0; i--) {
-        auto y = y1 + ddy_ddd[i];
-        auto x = x1 + ddx_ddd[i];
-        if (!in_bounds2(floor_ptr, y, x)) {
+        const Pos2D pos(y1 + ddy_ddd[i], x1 + ddx_ddd[i]);
+        if (!in_bounds2(floor_ptr, pos.y, pos.x)) {
             continue;
         }
 
-        if (player_bold(this->player_ptr, y, x)) {
+        if (this->player_ptr->is_located_at(pos)) {
             return false;
         }
 
-        auto *g_ptr = &floor_ptr->grid_array[y][x];
-        this->cost = (int)g_ptr->get_cost(r_ptr);
-        if (!this->is_best_cost(y, x, now_cost)) {
+        const auto &grid = floor_ptr->get_grid(pos);
+        this->cost = grid.get_cost(r_ptr);
+        if (!this->is_best_cost(pos.y, pos.x, now_cost)) {
             continue;
         }
 
@@ -406,7 +409,7 @@ bool MonsterSweepGrid::sweep_runnable_away_grid(POSITION *yp, POSITION *xp)
     auto gx = 0;
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[this->m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     auto fy = m_ptr->fy;
     auto fx = m_ptr->fx;
     auto y1 = fy - *yp;
index fc54341..bb50655 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 689a11e..8de1ef9 100644 (file)
@@ -1,11 +1,10 @@
-/*!
+/*!
  * @brief モンスターをフロアに1体配置する処理
  * @date 2020/06/13
  * @author Hourier
  */
 
 #include "monster-floor/one-monster-placer.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "dungeon/quest.h"
 #include "effect/attribute-types.h"
 #include "monster/monster-util.h"
 #include "object/warning.h"
 #include "player/player-status.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include "wizard/wizard-messages.h"
@@ -66,22 +67,17 @@ static bool is_friendly_idx(PlayerType *player_ptr, MONSTER_IDX m_idx)
  */
 static bool monster_hook_tanuki(PlayerType *player_ptr, MonsterRaceId r_idx)
 {
-    auto *r_ptr = &monraces_info[r_idx];
-    bool unselectable = r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
-    unselectable |= any_bits(r_ptr->flags2, RF2_MULTIPLY);
-    unselectable |= r_ptr->behavior_flags.has(MonsterBehaviorType::FRIENDLY);
-    unselectable |= r_ptr->feature_flags.has(MonsterFeatureType::AQUATIC);
-    unselectable |= any_bits(r_ptr->flags7, RF7_CHAMELEON);
+    const auto &monrace = monraces_info[r_idx];
+    bool unselectable = monrace.kind_flags.has(MonsterKindType::UNIQUE);
+    unselectable |= any_bits(monrace.flags2, RF2_MULTIPLY);
+    unselectable |= monrace.behavior_flags.has(MonsterBehaviorType::FRIENDLY);
+    unselectable |= monrace.feature_flags.has(MonsterFeatureType::AQUATIC);
+    unselectable |= any_bits(monrace.flags7, RF7_CHAMELEON);
+    unselectable |= monrace.is_explodable();
     if (unselectable) {
         return false;
     }
 
-    for (int i = 0; i < 4; i++) {
-        if (r_ptr->blow[i].method == RaceBlowMethodType::EXPLODE) {
-            return false;
-        }
-    }
-
     auto hook_pf = get_monster_hook(player_ptr);
     return (*hook_pf)(player_ptr, r_idx);
 }
@@ -107,7 +103,7 @@ static MonsterRaceId initial_r_appearance(PlayerType *player_ptr, MonsterRaceId
     int attempts = 1000;
     DEPTH min = std::min(floor_ptr->base_level - 5, 50);
     while (--attempts) {
-        auto ap_r_idx = get_mon_num(player_ptr, 0, floor_ptr->base_level + 10, 0);
+        auto ap_r_idx = get_mon_num(player_ptr, 0, floor_ptr->base_level + 10, PM_NONE);
         if (monraces_info[ap_r_idx].level >= min) {
             return ap_r_idx;
         }
@@ -122,52 +118,50 @@ static MonsterRaceId initial_r_appearance(PlayerType *player_ptr, MonsterRaceId
  * @param r_idx 生成モンスター種族
  * @return ユニークの生成が不可能な条件ならFALSE、それ以外はTRUE
  */
-static bool check_unique_placeable(PlayerType *player_ptr, MonsterRaceId r_idx)
+static bool check_unique_placeable(const FloorType &floor, MonsterRaceId r_idx, BIT_FLAGS mode)
 {
-    if (player_ptr->phase_out) {
+    if (AngbandSystem::get_instance().is_phase_out()) {
         return true;
     }
 
-    auto *r_ptr = &monraces_info[r_idx];
-    if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) && (r_ptr->cur_num >= r_ptr->max_num)) {
-        return false;
+    if (any_bits(mode, PM_CLONE)) {
+        return true;
     }
 
-    if (any_bits(r_ptr->flags7, RF7_UNIQUE2) && (r_ptr->cur_num >= 1)) {
+    auto *r_ptr = &monraces_info[r_idx];
+    auto is_unique = r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL);
+    is_unique &= r_ptr->cur_num >= r_ptr->max_num;
+    if (is_unique) {
         return false;
     }
 
-    if (r_idx == MonsterRaceId::BANORLUPART) {
-        if (monraces_info[MonsterRaceId::BANOR].cur_num > 0) {
-            return false;
-        }
-        if (monraces_info[MonsterRaceId::LUPART].cur_num > 0) {
-            return false;
-        }
+    if (r_ptr->population_flags.has(MonsterPopulationType::ONLY_ONE) && (r_ptr->cur_num >= 1)) {
+        return false;
     }
 
-    if (any_bits(r_ptr->flags1, RF1_FORCE_DEPTH) && (player_ptr->current_floor_ptr->dun_level < r_ptr->level) && (!ironman_nightmare || any_bits(r_ptr->flags1, RF1_QUESTOR))) {
+    if (!MonraceList::get_instance().is_selectable(r_idx)) {
         return false;
     }
 
-    return true;
+    const auto is_deep = any_bits(r_ptr->flags1, RF1_FORCE_DEPTH) && (floor.dun_level < r_ptr->level);
+    const auto is_questor = !ironman_nightmare || any_bits(r_ptr->flags1, RF1_QUESTOR);
+    return !is_deep || !is_questor;
 }
 
 /*!
  * @brief クエスト内に生成可能か評価する
- * @param player_ptr プレイヤーへの参照ポインタ
+ * @param floor フロアへの参照
  * @param r_idx 生成モンスター種族
  * @return 生成が可能ならTRUE、不可能ならFALSE
  */
-static bool check_quest_placeable(PlayerType *player_ptr, MonsterRaceId r_idx)
+static bool check_quest_placeable(const FloorType &floor, MonsterRaceId r_idx)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!inside_quest(quest_number(player_ptr, floor_ptr->dun_level))) {
+    if (!inside_quest(floor.get_quest_id())) {
         return true;
     }
 
     const auto &quest_list = QuestList::get_instance();
-    QuestId number = quest_number(player_ptr, floor_ptr->dun_level);
+    QuestId number = floor.get_quest_id();
     const auto *q_ptr = &quest_list[number];
     if ((q_ptr->type != QuestKindType::KILL_LEVEL) && (q_ptr->type != QuestKindType::RANDOM)) {
         return true;
@@ -176,10 +170,10 @@ static bool check_quest_placeable(PlayerType *player_ptr, MonsterRaceId r_idx)
         return true;
     }
     int number_mon = 0;
-    for (int i2 = 0; i2 < floor_ptr->width; ++i2) {
-        for (int j2 = 0; j2 < floor_ptr->height; j2++) {
-            auto quest_monster = (floor_ptr->grid_array[j2][i2].m_idx > 0);
-            quest_monster &= (floor_ptr->m_list[floor_ptr->grid_array[j2][i2].m_idx].r_idx == q_ptr->r_idx);
+    for (int i2 = 0; i2 < floor.width; ++i2) {
+        for (int j2 = 0; j2 < floor.height; j2++) {
+            auto quest_monster = (floor.grid_array[j2][i2].m_idx > 0);
+            quest_monster &= (floor.m_list[floor.grid_array[j2][i2].m_idx].r_idx == q_ptr->r_idx);
             if (quest_monster) {
                 number_mon++;
             }
@@ -270,20 +264,20 @@ static void warn_unique_generation(PlayerType *player_ptr, MonsterRaceId r_idx)
  */
 bool place_monster_one(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSITION x, MonsterRaceId r_idx, BIT_FLAGS mode)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto *g_ptr = &floor.grid_array[y][x];
     auto *r_ptr = &monraces_info[r_idx];
     concptr name = r_ptr->name.data();
 
-    if (player_ptr->wild_mode || !in_bounds(floor_ptr, y, x) || !MonsterRace(r_idx).is_valid() || r_ptr->name.empty()) {
+    if (player_ptr->wild_mode || !in_bounds(&floor, y, x) || !MonsterRace(r_idx).is_valid()) {
         return false;
     }
 
-    if (none_bits(mode, PM_IGNORE_TERRAIN) && (pattern_tile(floor_ptr, y, x) || !monster_can_enter(player_ptr, y, x, r_ptr, 0))) {
+    if (none_bits(mode, PM_IGNORE_TERRAIN) && (pattern_tile(&floor, y, x) || !monster_can_enter(player_ptr, y, x, r_ptr, 0))) {
         return false;
     }
 
-    if (!check_unique_placeable(player_ptr, r_idx) || !check_quest_placeable(player_ptr, r_idx) || !check_procection_rune(player_ptr, r_idx, y, x)) {
+    if (!check_unique_placeable(floor, r_idx, mode) || !check_quest_placeable(floor, r_idx) || !check_procection_rune(player_ptr, r_idx, y, x)) {
         return false;
     }
 
@@ -292,28 +286,28 @@ bool place_monster_one(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSI
         reset_bits(mode, PM_KAGE);
     }
 
-    g_ptr->m_idx = m_pop(floor_ptr);
+    g_ptr->m_idx = m_pop(&floor);
     hack_m_idx_ii = g_ptr->m_idx;
     if (!g_ptr->m_idx) {
         return false;
     }
 
     MonsterEntity *m_ptr;
-    m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
+    m_ptr = &floor.m_list[g_ptr->m_idx];
     m_ptr->r_idx = r_idx;
     m_ptr->ap_r_idx = initial_r_appearance(player_ptr, r_idx, mode);
 
     m_ptr->mflag.clear();
     m_ptr->mflag2.clear();
-    if (any_bits(mode, PM_MULTIPLY) && (who > 0) && !floor_ptr->m_list[who].is_original_ap()) {
-        m_ptr->ap_r_idx = floor_ptr->m_list[who].ap_r_idx;
-        if (floor_ptr->m_list[who].mflag2.has(MonsterConstantFlagType::KAGE)) {
+    if (any_bits(mode, PM_MULTIPLY) && (who > 0) && !floor.m_list[who].is_original_ap()) {
+        m_ptr->ap_r_idx = floor.m_list[who].ap_r_idx;
+        if (floor.m_list[who].mflag2.has(MonsterConstantFlagType::KAGE)) {
             m_ptr->mflag2.set(MonsterConstantFlagType::KAGE);
         }
     }
 
     if ((who > 0) && r_ptr->kind_flags.has_none_of(alignment_mask)) {
-        m_ptr->sub_align = floor_ptr->m_list[who].sub_align;
+        m_ptr->sub_align = floor.m_list[who].sub_align;
     } else {
         m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
         if (r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
@@ -326,7 +320,7 @@ bool place_monster_one(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSI
 
     m_ptr->fy = y;
     m_ptr->fx = x;
-    m_ptr->current_floor_ptr = floor_ptr;
+    m_ptr->current_floor_ptr = &floor;
 
     for (int cmi = 0; cmi < MAX_MTIMED; cmi++) {
         m_ptr->mtimed[cmi] = 0;
@@ -337,7 +331,7 @@ bool place_monster_one(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSI
     m_ptr->nickname.clear();
     m_ptr->exp = 0;
 
-    if (who > 0 && floor_ptr->m_list[who].is_pet()) {
+    if (who > 0 && floor.m_list[who].is_pet()) {
         set_bits(mode, PM_FORCE_PET);
         m_ptr->parent_m_idx = who;
     } else {
@@ -346,7 +340,7 @@ bool place_monster_one(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSI
 
     if (any_bits(r_ptr->flags7, RF7_CHAMELEON)) {
         choose_new_monster(player_ptr, g_ptr->m_idx, true, MonsterRace::empty_id());
-        r_ptr = &monraces_info[m_ptr->r_idx];
+        r_ptr = &m_ptr->get_monrace();
         m_ptr->mflag2.set(MonsterConstantFlagType::CHAMELEON);
         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE) && (who <= 0)) {
             m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
@@ -399,7 +393,7 @@ bool place_monster_one(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSI
 
     m_ptr->dealt_damage = 0;
 
-    m_ptr->mspeed = get_mspeed(floor_ptr, r_ptr);
+    m_ptr->mspeed = get_mspeed(&floor, r_ptr);
 
     if (any_bits(mode, PM_HASTE)) {
         (void)set_monster_fast(player_ptr, g_ptr->m_idx, 100);
@@ -419,25 +413,26 @@ bool place_monster_one(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSI
         m_ptr->mflag.set(MonsterTemporaryFlagType::BORN);
     }
 
-    if (r_ptr->brightness_flags.has_any_of(self_ld_mask)) {
-        set_bits(player_ptr->update, PU_MONSTER_LITE);
-    } else if (r_ptr->brightness_flags.has_any_of(has_ld_mask) && !m_ptr->is_asleep()) {
-        set_bits(player_ptr->update, PU_MONSTER_LITE);
+    auto is_awake_lightning_monster = r_ptr->brightness_flags.has_any_of(self_ld_mask);
+    is_awake_lightning_monster |= r_ptr->brightness_flags.has_any_of(has_ld_mask) && !m_ptr->is_asleep();
+    if (is_awake_lightning_monster) {
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
+
     update_monster(player_ptr, g_ptr->m_idx, true);
 
-    m_ptr->get_real_r_ref().cur_num++;
+    m_ptr->get_real_monrace().cur_num++;
 
     /*
      * Memorize location of the unique monster in saved floors.
      * A unique monster move from old saved floor.
      */
     if (w_ptr->character_dungeon && (r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL))) {
-        m_ptr->get_real_r_ref().floor_id = player_ptr->floor_id;
+        m_ptr->get_real_monrace().floor_id = player_ptr->floor_id;
     }
 
     if (any_bits(r_ptr->flags2, RF2_MULTIPLY)) {
-        floor_ptr->num_repro++;
+        floor.num_repro++;
     }
 
     warn_unique_generation(player_ptr, r_idx);
index 3e76fb1..2293dcc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 002b691..452e664 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Bit flags for the place_monster_???() (etc)
@@ -19,4 +19,6 @@ enum place_monster_type {
     PM_JURAL = 0x00000800, /*!< モンスター生成フラグ: ジュラル星人として誤認生成する */
     PM_NO_QUEST = 0x00001000, /*!< モンスター生成フラグ: クエスト除外モンスターを生成しない */
     PM_CLONE = 0x00002000, /*!< モンスター生成フラグ: クローンとして生成する */
+    PM_ARENA = 0x00004000, /*!< モンスター生成フラグ: アリーナ用の生成 */
+
 };
index 5ea5b9d..fe6033f 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-floor/quantum-effect.h"
+#include "monster-floor/quantum-effect.h"
 #include "effect/attribute-types.h"
 #include "floor/line-of-sight.h"
 #include "monster-floor/monster-death.h"
@@ -85,7 +85,7 @@ static void produce_quantum_effect(PlayerType *player_ptr, MONSTER_IDX m_idx, bo
 bool process_quantum_effect(PlayerType *player_ptr, MONSTER_IDX m_idx, bool see_m)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->kind_flags.has_not(MonsterKindType::QUANTUM)) {
         return false;
     }
index 88c54e9..76f8841 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e22521e..60239df 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター死亡時の特殊処理switch (一般的な処理もdefaultで実施)
  * @date 2020/08/21
  * @author Hourier
@@ -35,6 +35,7 @@
 #include "sv-definition/sv-other-types.h"
 #include "sv-definition/sv-protector-types.h"
 #include "sv-definition/sv-weapon-types.h"
+#include "system/angband-system.h"
 #include "system/artifact-type-definition.h"
 #include "system/baseitem-info.h"
 #include "system/floor-type-definition.h"
@@ -49,7 +50,7 @@
  * @param md_ptr モンスター撃破構造体への参照ポインタ
  * @return 撃破モンスターがPETであればPM_FORCE_PETを、CLONEであればPM_CLONEを立てる
  */
-static BIT_FLAGS dead_mode(monster_death_type *md_ptr)
+static BIT_FLAGS dead_mode(MonsterDeath *md_ptr)
 {
     bool pet = md_ptr->m_ptr->is_pet();
     bool clone = md_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::CLONED);
@@ -70,10 +71,10 @@ static BIT_FLAGS dead_mode(monster_death_type *md_ptr)
  * @param radius 召喚半径 (モンスターが死亡した座標から半径何マス以内に召喚させるか)
  * @param message 召喚時のメッセージ
  */
-static void summon_self(PlayerType *player_ptr, monster_death_type *md_ptr, summon_type type, int probability, POSITION radius, concptr message)
+static void summon_self(PlayerType *player_ptr, MonsterDeath *md_ptr, summon_type type, int probability, POSITION radius, concptr message)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (floor_ptr->inside_arena || player_ptr->phase_out || one_in_(probability)) {
+    if (floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out() || one_in_(probability)) {
         return;
     }
 
@@ -95,9 +96,9 @@ static void summon_self(PlayerType *player_ptr, monster_death_type *md_ptr, summ
     }
 }
 
-static void on_dead_pink_horror(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_pink_horror(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
-    if (player_ptr->current_floor_ptr->inside_arena || player_ptr->phase_out) {
+    if (player_ptr->current_floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -119,7 +120,7 @@ static void on_dead_pink_horror(PlayerType *player_ptr, monster_death_type *md_p
     }
 }
 
-static void on_dead_bloodletter(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_bloodletter(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     if (!md_ptr->drop_chosen_item || (randint1(100) >= 15)) {
         return;
@@ -132,7 +133,7 @@ static void on_dead_bloodletter(PlayerType *player_ptr, monster_death_type *md_p
     (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
 }
 
-static void on_dead_raal(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_raal(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     if (!md_ptr->drop_chosen_item || (floor_ptr->dun_level <= 9)) {
@@ -157,39 +158,39 @@ static void on_dead_raal(PlayerType *player_ptr, monster_death_type *md_ptr)
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param md_ptr モンスター撃破構造体への参照ポインタ
  */
-static void on_dead_dawn(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_dawn(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     summon_self(player_ptr, md_ptr, SUMMON_DAWN, 7, 20, _("新たな戦士が現れた!", "A new warrior steps forth!"));
 }
 
-static void on_dead_sacred_treasures(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_sacred_treasures(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     if ((player_ptr->ppersonality != PERSONALITY_LAZY) || !md_ptr->drop_chosen_item) {
         return;
     }
 
-    FixedArtifactId a_idx = FixedArtifactId::NONE;
-    ArtifactType *a_ptr = nullptr;
-    do {
-        switch (randint0(3)) {
-        case 0:
-            a_idx = FixedArtifactId::NAMAKE_HAMMER;
-            break;
-        case 1:
-            a_idx = FixedArtifactId::NAMAKE_BOW;
-            break;
-        case 2:
-            a_idx = FixedArtifactId::NAMAKE_ARMOR;
-            break;
-        }
+    constexpr static auto namake_equipments = {
+        FixedArtifactId::NAMAKE_HAMMER,
+        FixedArtifactId::NAMAKE_BOW,
+        FixedArtifactId::NAMAKE_ARMOR
+    };
 
-        a_ptr = &ArtifactsInfo::get_instance().get_artifact(a_idx);
-    } while (a_ptr->is_generated);
+    std::vector<FixedArtifactId> candidates;
+    std::copy_if(namake_equipments.begin(), namake_equipments.end(), std::back_inserter(candidates),
+        [](FixedArtifactId a_idx) {
+            const auto &artifact = ArtifactsInfo::get_instance().get_artifact(a_idx);
+            return !artifact.is_generated;
+        });
 
+    if (candidates.empty()) {
+        return;
+    }
+
+    const auto a_idx = rand_choice(candidates);
     create_named_art(player_ptr, a_idx, md_ptr->md_y, md_ptr->md_x);
 }
 
-static void on_dead_serpent(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_serpent(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     if (!md_ptr->drop_chosen_item) {
         return;
@@ -208,7 +209,7 @@ static void on_dead_serpent(PlayerType *player_ptr, monster_death_type *md_ptr)
     (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
 }
 
-static void on_dead_death_sword(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_death_sword(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     if (!md_ptr->drop_chosen_item) {
         return;
@@ -220,7 +221,7 @@ static void on_dead_death_sword(PlayerType *player_ptr, monster_death_type *md_p
     (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
 }
 
-static void on_dead_can_angel(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_can_angel(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     bool is_drop_can = md_ptr->drop_chosen_item;
     bool is_silver = md_ptr->m_ptr->r_idx == MonsterRaceId::A_SILVER;
@@ -237,9 +238,9 @@ static void on_dead_can_angel(PlayerType *player_ptr, monster_death_type *md_ptr
     (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
 }
 
-static void on_dead_aqua_illusion(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_aqua_illusion(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
-    if (player_ptr->current_floor_ptr->inside_arena || player_ptr->phase_out) {
+    if (player_ptr->current_floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -267,14 +268,14 @@ static void on_dead_aqua_illusion(PlayerType *player_ptr, monster_death_type *md
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param md_ptr モンスター撃破構造体への参照ポインタ
  */
-static void on_dead_totem_moai(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_totem_moai(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     summon_self(player_ptr, md_ptr, SUMMON_TOTEM_MOAI, 8, 5, _("新たなモアイが現れた!", "A new moai steps forth!"));
 }
 
-static void on_dead_dragon_centipede(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_dragon_centipede(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
-    if (player_ptr->current_floor_ptr->inside_arena || player_ptr->phase_out) {
+    if (player_ptr->current_floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -329,7 +330,7 @@ static bool make_equipment(PlayerType *player_ptr, ItemEntity *q_ptr, const BIT_
  * 最初のアイテム生成でいきなり☆が生成された場合を除き、中途半端な☆ (例:呪われている)は生成しない.
  * このルーチンで★は生成されないので、★生成フラグのキャンセルも不要
  */
-static void on_dead_random_artifact(PlayerType *player_ptr, monster_death_type *md_ptr, bool (*object_hook_pf)(short bi_id))
+static void on_dead_random_artifact(PlayerType *player_ptr, MonsterDeath *md_ptr, bool (*object_hook_pf)(short bi_id))
 {
     ItemEntity forge;
     auto *q_ptr = &forge;
@@ -369,7 +370,7 @@ static void on_dead_random_artifact(PlayerType *player_ptr, monster_death_type *
  * @brief マニマニのあくま撃破時メッセージ
  * @todo 死亡時の特殊メッセージを表示するだけの処理を複数作るなら、switch/case文に分けられるように汎用化すること
  */
-static void on_dead_manimani(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_manimani(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     if (!is_seen(player_ptr, md_ptr->m_ptr)) {
         return;
@@ -378,7 +379,7 @@ static void on_dead_manimani(PlayerType *player_ptr, monster_death_type *md_ptr)
     msg_print(_("どこからか声が聞こえる…「ハロー! そして…グッドバイ!」", "Heard a voice from somewhere... 'Hello! And... good bye!'"));
 }
 
-static void drop_specific_item_on_dead(PlayerType *player_ptr, monster_death_type *md_ptr, bool (*object_hook_pf)(short bi_id))
+static void drop_specific_item_on_dead(PlayerType *player_ptr, MonsterDeath *md_ptr, bool (*object_hook_pf)(short bi_id))
 {
     ItemEntity forge;
     auto *q_ptr = &forge;
@@ -388,9 +389,9 @@ static void drop_specific_item_on_dead(PlayerType *player_ptr, monster_death_typ
     (void)drop_near(player_ptr, q_ptr, -1, md_ptr->md_y, md_ptr->md_x);
 }
 
-static void on_dead_chest_mimic(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_chest_mimic(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
-    if (player_ptr->current_floor_ptr->inside_arena || player_ptr->phase_out) {
+    if (player_ptr->current_floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -431,7 +432,7 @@ static void on_dead_chest_mimic(PlayerType *player_ptr, monster_death_type *md_p
     }
 }
 
-static void on_dead_mimics(PlayerType *player_ptr, monster_death_type *md_ptr)
+static void on_dead_mimics(PlayerType *player_ptr, MonsterDeath *md_ptr)
 {
     if (!md_ptr->drop_chosen_item) {
         return;
@@ -485,7 +486,7 @@ static void on_dead_mimics(PlayerType *player_ptr, monster_death_type *md_ptr)
     }
 }
 
-static void on_dead_swordfish(PlayerType *player_ptr, monster_death_type *md_ptr, AttributeFlags attribute_flags)
+static void on_dead_swordfish(PlayerType *player_ptr, MonsterDeath *md_ptr, AttributeFlags attribute_flags)
 {
     if (attribute_flags.has_not(AttributeType::COLD) || !md_ptr->drop_chosen_item || (randint1(100) >= 10)) {
         return;
@@ -494,7 +495,7 @@ static void on_dead_swordfish(PlayerType *player_ptr, monster_death_type *md_ptr
     drop_single_artifact(player_ptr, md_ptr, FixedArtifactId::FROZEN_SWORDFISH);
 }
 
-void switch_special_death(PlayerType *player_ptr, monster_death_type *md_ptr, AttributeFlags attribute_flags)
+void switch_special_death(PlayerType *player_ptr, MonsterDeath *md_ptr, AttributeFlags attribute_flags)
 {
     switch (md_ptr->m_ptr->r_idx) {
     case MonsterRaceId::PINK_HORROR:
@@ -546,12 +547,18 @@ void switch_special_death(PlayerType *player_ptr, monster_death_type *md_ptr, At
         on_dead_dragon_centipede(player_ptr, md_ptr);
         return;
     case MonsterRaceId::CAIT_SITH:
+        if (player_ptr->current_floor_ptr->dun_level <= 0) {
+            return;
+        }
         drop_specific_item_on_dead(player_ptr, md_ptr, kind_is_boots);
         return;
     case MonsterRaceId::YENDOR_WIZARD_1:
         on_dead_random_artifact(player_ptr, md_ptr, kind_is_amulet);
         return;
     case MonsterRaceId::YENDOR_WIZARD_2:
+        if (player_ptr->current_floor_ptr->dun_level <= 0) {
+            return;
+        }
         drop_specific_item_on_dead(player_ptr, md_ptr, kind_is_amulet);
         return;
     case MonsterRaceId::MANIMANI:
index f827af0..81663c0 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 #include "effect/attribute-types.h"
 #include "system/angband.h"
 
-struct monster_death_type;
+class MonsterDeath;
 class PlayerType;
-void switch_special_death(PlayerType *player_ptr, monster_death_type *md_ptr, AttributeFlags attribute_flags);
+void switch_special_death(PlayerType *player_ptr, MonsterDeath *md_ptr, AttributeFlags attribute_flags);
index f8ff02b..6af6400 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @brief モンスターがまとっているオーラ定義.
index 96068a2..52c4524 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-race/monster-kind-mask.h"
+#include "monster-race/monster-kind-mask.h"
 
 const EnumClassFlagGroup<MonsterKindType> alignment_mask = {
     MonsterKindType::GOOD, MonsterKindType::EVIL
index ab4c8e8..d5adc62 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "monster-race/race-kind-flags.h"
 #include "system/angband.h"
index ada1deb..221fc37 100644 (file)
@@ -1,6 +1,8 @@
-#include "monster-race/monster-race-hook.h"
+#include "monster-race/monster-race-hook.h"
+#include "dungeon/quest.h"
 #include "monster-attack/monster-attack-effect.h"
 #include "monster-attack/monster-attack-table.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-ability-mask.h"
 #include "monster-race/race-flags-resistance.h"
@@ -37,7 +39,7 @@ EnumClassFlagGroup<MonsterAbilityType> vault_aux_dragon_mask4;
 void vault_prep_clone(PlayerType *player_ptr)
 {
     get_mon_num_prep(player_ptr, vault_aux_simple, nullptr);
-    vault_aux_race = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->dun_level + 10, 0);
+    vault_aux_race = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->dun_level + 10, PM_NONE);
     get_mon_num_prep(player_ptr, nullptr, nullptr);
 }
 
@@ -48,7 +50,7 @@ void vault_prep_clone(PlayerType *player_ptr)
 void vault_prep_symbol(PlayerType *player_ptr)
 {
     get_mon_num_prep(player_ptr, vault_aux_simple, nullptr);
-    MonsterRaceId r_idx = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->dun_level + 10, 0);
+    MonsterRaceId r_idx = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->dun_level + 10, PM_NONE);
     get_mon_num_prep(player_ptr, nullptr, nullptr);
     vault_aux_char = monraces_info[r_idx].d_char;
 }
@@ -63,26 +65,22 @@ void vault_prep_dragon(PlayerType *player_ptr)
     (void)player_ptr;
 
     vault_aux_dragon_mask4.clear();
-    switch (randint0(6)) {
-    case 0: /* Black */
-        vault_aux_dragon_mask4.set(MonsterAbilityType::BR_ACID);
-        break;
-    case 1: /* Blue */
-        vault_aux_dragon_mask4.set(MonsterAbilityType::BR_ELEC);
-        break;
-    case 2: /* Red */
-        vault_aux_dragon_mask4.set(MonsterAbilityType::BR_FIRE);
-        break;
-    case 3: /* White */
-        vault_aux_dragon_mask4.set(MonsterAbilityType::BR_COLD);
-        break;
-    case 4: /* Green */
-        vault_aux_dragon_mask4.set(MonsterAbilityType::BR_POIS);
-        break;
-    default: /* Multi-hued */
-        vault_aux_dragon_mask4.set({ MonsterAbilityType::BR_ACID, MonsterAbilityType::BR_ELEC, MonsterAbilityType::BR_FIRE, MonsterAbilityType::BR_COLD, MonsterAbilityType::BR_POIS });
-        break;
+
+    constexpr static auto breath_list = {
+        MonsterAbilityType::BR_ACID, /* Black */
+        MonsterAbilityType::BR_ELEC, /* Blue */
+        MonsterAbilityType::BR_FIRE, /* Red */
+        MonsterAbilityType::BR_COLD, /* White */
+        MonsterAbilityType::BR_POIS, /* Green */
+    };
+
+    if (one_in_(6)) {
+        /* Multi-hued */
+        vault_aux_dragon_mask4.set(breath_list);
+        return;
     }
+
+    vault_aux_dragon_mask4.set(rand_choice(breath_list));
 }
 
 /*!
@@ -130,13 +128,13 @@ bool mon_hook_quest(PlayerType *player_ptr, MonsterRaceId r_idx)
  */
 bool mon_hook_dungeon(PlayerType *player_ptr, MonsterRaceId r_idx)
 {
-    const auto &floor_ref = *player_ptr->current_floor_ptr;
-    if (!floor_ref.is_in_dungeon() && !inside_quest(floor_ref.quest_number)) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if (!floor.is_in_dungeon() && !floor.is_in_quest()) {
         return true;
     }
 
     auto *r_ptr = &monraces_info[r_idx];
-    dungeon_type *d_ptr = &dungeons_info[player_ptr->dungeon_idx];
+    dungeon_type *d_ptr = &floor.get_dungeon_definition();
     if (r_ptr->wilderness_flags.has(MonsterWildernessType::WILD_ONLY)) {
         return d_ptr->mon_wilderness_flags.has(MonsterWildernessType::WILD_MOUNTAIN) && r_ptr->wilderness_flags.has(MonsterWildernessType::WILD_MOUNTAIN);
     }
@@ -789,45 +787,6 @@ bool vault_aux_dark_elf(PlayerType *player_ptr, MonsterRaceId r_idx)
 }
 
 /*!
- * @brief モンスターが生命体かどうかを返す
- * Is the monster "alive"?
- * @param r_ptr 判定するモンスターの種族情報構造体参照ポインタ
- * @return 生命体ならばTRUEを返す
- * @details
- * Used to determine the message to print for a killed monster.
- * ("dies", "destroyed")
- */
-bool monster_living(MonsterRaceId r_idx)
-{
-    auto *r_ptr = &monraces_info[r_idx];
-    return r_ptr->kind_flags.has_none_of({ MonsterKindType::DEMON, MonsterKindType::UNDEAD, MonsterKindType::NONLIVING });
-}
-
-/*!
- * @brief モンスターが特殊能力上、賞金首から排除する必要があるかどうかを返す。
- * Is the monster "alive"? / Is this monster declined to be questor or bounty?
- * @param r_idx モンスターの種族ID
- * @return 賞金首に加えられないならばTRUEを返す
- * @details
- * 実質バーノール=ルパート用。
- */
-bool no_questor_or_bounty_uniques(MonsterRaceId r_idx)
-{
-    switch (r_idx) {
-        /*
-         * Decline them to be questor or bounty because they use
-         * special motion "split and combine"
-         */
-    case MonsterRaceId::BANORLUPART:
-    case MonsterRaceId::BANOR:
-    case MonsterRaceId::LUPART:
-        return true;
-    default:
-        return false;
-    }
-}
-
-/*!
  * @brief バルログが死体を食べられるモンスターかの判定 / Hook function for human corpses
  * @param r_idx モンスターID
  * @return 死体を食べられるならTRUEを返す。
@@ -899,27 +858,24 @@ bool monster_can_entry_arena(PlayerType *player_ptr, MonsterRaceId r_idx)
     (void)player_ptr;
 
     int dam = 0;
-    auto *r_ptr = &monraces_info[r_idx];
-    bool unselectable = r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_MOVE);
-    unselectable |= any_bits(r_ptr->flags2, RF2_MULTIPLY);
-    unselectable |= r_ptr->kind_flags.has(MonsterKindType::QUANTUM) && r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE);
-    unselectable |= r_ptr->feature_flags.has(MonsterFeatureType::AQUATIC);
-    unselectable |= any_bits(r_ptr->flags7, RF7_CHAMELEON);
+    const auto &monrace = monraces_info[r_idx];
+    bool unselectable = monrace.behavior_flags.has(MonsterBehaviorType::NEVER_MOVE);
+    unselectable |= any_bits(monrace.flags2, RF2_MULTIPLY);
+    unselectable |= monrace.kind_flags.has(MonsterKindType::QUANTUM) && monrace.kind_flags.has_not(MonsterKindType::UNIQUE);
+    unselectable |= monrace.feature_flags.has(MonsterFeatureType::AQUATIC);
+    unselectable |= any_bits(monrace.flags7, RF7_CHAMELEON);
+    unselectable |= monrace.is_explodable();
     if (unselectable) {
         return false;
     }
 
-    for (int i = 0; i < 4; i++) {
-        if (r_ptr->blow[i].method == RaceBlowMethodType::EXPLODE) {
-            return false;
-        }
-
-        if (r_ptr->blow[i].effect != RaceBlowEffectType::DR_MANA) {
-            dam += r_ptr->blow[i].d_dice;
+    for (const auto &blow : monrace.blows) {
+        if (blow.effect != RaceBlowEffectType::DR_MANA) {
+            dam += blow.d_dice;
         }
     }
 
-    if (!dam && r_ptr->ability_flags.has_none_of(RF_ABILITY_BOLT_MASK | RF_ABILITY_BEAM_MASK | RF_ABILITY_BALL_MASK | RF_ABILITY_BREATH_MASK)) {
+    if (!dam && monrace.ability_flags.has_none_of(RF_ABILITY_BOLT_MASK | RF_ABILITY_BEAM_MASK | RF_ABILITY_BALL_MASK | RF_ABILITY_BREATH_MASK)) {
         return false;
     }
 
@@ -957,7 +913,7 @@ bool item_monster_okay(PlayerType *player_ptr, MonsterRaceId r_idx)
         return false;
     }
 
-    if (any_bits(r_ptr->flags7, RF7_UNIQUE2)) {
+    if (r_ptr->population_flags.has(MonsterPopulationType::ONLY_ONE)) {
         return false;
     }
 
@@ -975,5 +931,11 @@ bool item_monster_okay(PlayerType *player_ptr, MonsterRaceId r_idx)
  */
 bool vault_monster_okay(PlayerType *player_ptr, MonsterRaceId r_idx)
 {
-    return mon_hook_dungeon(player_ptr, r_idx) && monraces_info[r_idx].kind_flags.has_not(MonsterKindType::UNIQUE) && none_bits(monraces_info[r_idx].flags7, RF7_UNIQUE2) && monraces_info[r_idx].resistance_flags.has_not(MonsterResistanceType::RESIST_ALL) && monraces_info[r_idx].feature_flags.has_not(MonsterFeatureType::AQUATIC);
+    const auto &monrace = monraces_info[r_idx];
+    auto is_valid = mon_hook_dungeon(player_ptr, r_idx);
+    is_valid &= monrace.kind_flags.has_not(MonsterKindType::UNIQUE);
+    is_valid &= monrace.population_flags.has_not(MonsterPopulationType::ONLY_ONE);
+    is_valid &= monrace.resistance_flags.has_not(MonsterResistanceType::RESIST_ALL);
+    is_valid &= monrace.feature_flags.has_not(MonsterFeatureType::AQUATIC);
+    return is_valid;
 }
index 682afbe..8f88249 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -55,8 +55,6 @@ bool vault_aux_dark_elf(PlayerType *player_ptr, MonsterRaceId r_idx);
 
 bool vault_monster_okay(PlayerType *player_ptr, MonsterRaceId r_idx);
 
-bool monster_living(MonsterRaceId r_idx);
-bool no_questor_or_bounty_uniques(MonsterRaceId r_idx);
 bool monster_hook_human(PlayerType *player_ptr, MonsterRaceId r_idx);
 bool get_nightmare(PlayerType *player_ptr, MonsterRaceId r_idx);
 bool monster_is_fishing_target(PlayerType *player_ptr, MonsterRaceId r_idx);
index 781cac9..647b642 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-race/monster-race.h"
+#include "monster-race/monster-race.h"
 #include "monster-race/race-flags-resistance.h"
 #include "monster-race/race-flags1.h"
 #include "monster-race/race-indice-types.h"
index a7277b6..2603112 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 9f0028b..7c9ba2c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterAbilityType {
     SHRIEK = 0, /*!< モンスター能力: 叫ぶ / Shriek for help */
@@ -99,11 +99,15 @@ enum class MonsterAbilityType {
     S_HI_DRAGON = 93, /* Summon Ancient Dragon */
     S_AMBERITES = 94, /* Summon Amberites */
     S_UNIQUE = 95, /* Summon Unique Monster */
+    S_DEAD_UNIQUE = 96, /* Summon Dead Unique Monster */
     BO_VOID = 97, /*!< モンスター能力: ヴォイド・ボルト / Void Bolt */
     BO_ABYSS = 98, /*!< モンスター能力: アビス・ボルト / Abyss Bolt */
     BR_VOID = 99, /*!< モンスター能力: 虚無のブレス / Breathe Void */
     BR_ABYSS = 100, /*!< モンスター能力: 深淵のブレス / Breathe Abyss */
     BA_VOID = 101, /*!< モンスター能力: 虚無のボール / Void Ball */
     BA_ABYSS = 102, /*!< モンスター能力: 深淵のボール / Abyss Ball */
+    BA_METEOR = 103, /*!< モンスター能力: 隕石のボール / Meteor Ball */
+    BO_METEOR = 104, /*!< モンスター能力: 隕石のボルト / Meteor Bolt */
+    BO_LITE = 105, /*!< モンスター能力: 光のボルト(スターライトアロー) / Starlight arrow */
     MAX,
 };
index 9e5df37..e3ba4ff 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-race/race-ability-mask.h"
+#include "monster-race/race-ability-mask.h"
 
 // clang-format off
 /* "summon" spells currently "summon" spells are included in "intelligent" and "indirect" */
@@ -7,6 +7,7 @@ const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_SUMMON_MASK = {
     MonsterAbilityType::S_ANT, MonsterAbilityType::S_SPIDER, MonsterAbilityType::S_HOUND, MonsterAbilityType::S_HYDRA,
     MonsterAbilityType::S_ANGEL, MonsterAbilityType::S_DEMON, MonsterAbilityType::S_UNDEAD, MonsterAbilityType::S_DRAGON,
     MonsterAbilityType::S_HI_UNDEAD, MonsterAbilityType::S_HI_DRAGON, MonsterAbilityType::S_AMBERITES, MonsterAbilityType::S_UNIQUE,
+    MonsterAbilityType::S_DEAD_UNIQUE,
 };
 
 /* Choose "intelligent" spells when desperate Including "summon" spells */
@@ -30,9 +31,9 @@ const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_RIDING_MASK = {
  */
 const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_BOLT_MASK = {
     MonsterAbilityType::ROCKET, MonsterAbilityType::SHOOT, MonsterAbilityType::BO_ACID, MonsterAbilityType::BO_ELEC,
-    MonsterAbilityType::BO_FIRE, MonsterAbilityType::BO_COLD, MonsterAbilityType::BO_NETH, MonsterAbilityType::BO_WATE,
-    MonsterAbilityType::BO_MANA, MonsterAbilityType::BO_PLAS, MonsterAbilityType::BO_ICEE, MonsterAbilityType::BO_VOID,
-    MonsterAbilityType::BO_ABYSS, MonsterAbilityType::MISSILE,
+    MonsterAbilityType::BO_FIRE, MonsterAbilityType::BO_COLD, MonsterAbilityType::BO_NETH, MonsterAbilityType::BO_LITE,
+    MonsterAbilityType::BO_WATE, MonsterAbilityType::BO_MANA, MonsterAbilityType::BO_PLAS, MonsterAbilityType::BO_ICEE,
+    MonsterAbilityType::BO_VOID, MonsterAbilityType::BO_ABYSS, MonsterAbilityType::BO_METEOR, MonsterAbilityType::MISSILE,
 };
 
 /*
@@ -49,7 +50,7 @@ const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_BEAM_MASK = {
  */
 const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_BIG_BALL_MASK = {
     MonsterAbilityType::BA_CHAO, MonsterAbilityType::BA_LITE, MonsterAbilityType::BA_DARK, MonsterAbilityType::BA_WATE,
-    MonsterAbilityType::BA_MANA, MonsterAbilityType::BA_VOID, MonsterAbilityType::BA_ABYSS,
+    MonsterAbilityType::BA_MANA, MonsterAbilityType::BA_VOID, MonsterAbilityType::BA_ABYSS,MonsterAbilityType::BA_METEOR,
 };
 
 /*
@@ -98,3 +99,36 @@ const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_NOMAGIC_MASK =
     EnumClassFlagGroup<MonsterAbilityType>(RF_ABILITY_BREATH_MASK).set({
     MonsterAbilityType::SHRIEK, MonsterAbilityType::ROCKET, MonsterAbilityType::SHOOT, MonsterAbilityType::SPECIAL,
 });
+
+const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_ATTACK_SPELLS_MASK =
+    (RF_ABILITY_BALL_MASK |
+        RF_ABILITY_BEAM_MASK |
+        RF_ABILITY_BOLT_MASK)
+        .set(/* "Cause wounds" spells */
+            {
+                MonsterAbilityType::CAUSE_1,
+                MonsterAbilityType::CAUSE_2,
+                MonsterAbilityType::CAUSE_3,
+                MonsterAbilityType::CAUSE_4,
+                MonsterAbilityType::HAND_DOOM });
+
+const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_ANNOY_SPELLS_MASK = {
+    MonsterAbilityType::SHRIEK,
+    MonsterAbilityType::DRAIN_MANA,
+    MonsterAbilityType::MIND_BLAST,
+    MonsterAbilityType::BRAIN_SMASH,
+    MonsterAbilityType::CAUSE_1,
+    MonsterAbilityType::CAUSE_2,
+    MonsterAbilityType::CAUSE_3,
+    MonsterAbilityType::CAUSE_4,
+    MonsterAbilityType::SCARE,
+    MonsterAbilityType::BLIND,
+    MonsterAbilityType::CONF,
+    MonsterAbilityType::SLOW,
+    MonsterAbilityType::HOLD,
+    MonsterAbilityType::TELE_TO,
+    MonsterAbilityType::TELE_LEVEL,
+    MonsterAbilityType::TRAPS,
+    MonsterAbilityType::FORGET,
+    MonsterAbilityType::RAISE_DEAD,
+};
index cdf5086..10ac563 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "monster-race/race-ability-flags.h"
 #include "util/flag-group.h"
@@ -14,3 +14,5 @@ extern const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_BALL_MASK;
 extern const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_ATTACK_MASK;
 extern const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_INDIRECT_MASK;
 extern const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_NOMAGIC_MASK;
+extern const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_ATTACK_SPELLS_MASK;
+extern const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_ANNOY_SPELLS_MASK;
index ffb7cb4..9ad42f2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterBehaviorType {
     NEVER_BLOW = 0,
index 8fdf261..2243e92 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterBrightnessType {
     HAS_LITE_1 = 0, /* Monster carries light */
index e2c6ac6..4e000cc 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-race/race-brightness-mask.h"
+#include "monster-race/race-brightness-mask.h"
 
 const EnumClassFlagGroup<MonsterBrightnessType> lite_mask = {
     MonsterBrightnessType::HAS_LITE_1,
index a02c990..39b0c88 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include "monster-race/race-brightness-flags.h"
 #include "util/flag-group.h"
 
index 6068dd5..dd95afb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterDropType {
     ONLY_GOLD = 0,
index 1432729..4aa6ad3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterFeatureType {
     AQUATIC = 0,
index 6c173b0..8e77998 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-race/race-feature-mask.h"
+#include "monster-race/race-feature-mask.h"
 
 const EnumClassFlagGroup<MonsterFeatureType> feature_lore_flags2 = {
     MonsterFeatureType::PASS_WALL,
index bac5054..9f328cd 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "monster-race/race-feature-flags.h"
 #include "util/flag-group.h"
index 99cb460..fc18ffc 100644 (file)
@@ -52,5 +52,12 @@ enum class MonsterResistanceType {
     RESIST_ABYSS = 48, /* Resist abyss */
     HURT_VOID_MAGIC = 49, /* Hurt badly by void */
     RESIST_VOID_MAGIC = 50, /* Resist void */
+    HURT_METEOR = 51, /* Hurt badly by meteor */
+    RESIST_METEOR = 52, /* Resist meteor */
+    NO_FEAR = 53, /* Cannot be scared */
+    NO_STUN = 54, /* Cannot be stunned */
+    NO_CONF = 55, /* Cannot be confused and resist confusion */
+    NO_SLEEP = 56, /* Cannot be slept */
+    NO_INSTANTLY_DEATH = 57, /*Cannot be instantly kill*/
     MAX, /* Max of Resistances */
 };
index b2092d2..fb8ae0d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum race_flags1 {
     RF1_UNIQUE = 0x00000001, /*!< モンスター特性: ユニーク / Unique Monster */
index 7326220..08d0ac7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum race_flags2 {
     RF2_STUPID = 0x00000001, /*!< モンスター特性: 愚かな行動を取る / Monster is stupid */
index 0dc9c5c..bb46891 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum race_flags3 {
     RF3_ORC = 0x00000001, /*!< モンスター特性: オーク / Orc */
@@ -29,8 +29,8 @@ enum race_flags3 {
     RF3_XXX25 = 0x02000000, /*!< モンスター特性: 未使用 / XXX */
     RF3_XXX26 = 0x04000000, /*!< モンスター特性: 未使用 / XXX */
     RF3_XXX27 = 0x08000000, /*!< モンスター特性: 未使用 / XXX */
-    RF3_NO_FEAR = 0x10000000, /*!< モンスター特性: 恐怖しない / Cannot be scared */
-    RF3_NO_STUN = 0x20000000, /*!< モンスター特性: 朦朧としない / Cannot be stunned */
-    RF3_NO_CONF = 0x40000000, /*!< モンスター特性: 混乱しない / Cannot be confused and resist confusion */
-    RF3_NO_SLEEP = 0x80000000, /*!< モンスター特性: 眠らない / Cannot be slept */
+    RF3_XXX28 = 0x10000000, /*!< モンスター特性: 未使用 / XXX */
+    RF3_XXX29 = 0x20000000, /*!< モンスター特性: 未使用 / XXX */
+    RF3_XXX30 = 0x40000000, /*!< モンスター特性: 未使用 / XXX */
+    RF3_XXX31 = 0x80000000, /*!< モンスター特性: 未使用 / XXX */
 };
index 65816ad..795af3b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum race_flags7 {
     RF7_AQUATIC = 0x00000001, /* Aquatic monster */
index 3bc355f..6cf37f1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum race_flags8 : uint32_t {
     RF8_WILD_ONLY = 0x00000001,
index b1fcd07..6fced2d 100644 (file)
@@ -1,7 +1,8 @@
-#pragma once
+#pragma once
 
 enum class MonsterRaceId : int16_t {
     PLAYER = 0,
+    FILTHY_URCHIN = 1,
     BEGGAR = 12,
     LEPER = 13,
     LION_HEART = 19,
index 6da3fdd..b9a2fb4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterKindType {
     UNIQUE = 0,
index b74e1c2..e65718b 100644 (file)
@@ -1,6 +1,7 @@
-#pragma once
+#pragma once
 
 enum class MonsterPopulationType {
     NAZGUL = 0,
+    ONLY_ONE = 1,
     MAX,
 };
index a686720..746b2ea 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster-race/race-resistance-mask.h"
+#include "monster-race/race-resistance-mask.h"
 
 const EnumClassFlagGroup<MonsterResistanceType> RFR_EFF_IM_ACID_MASK = {
     MonsterResistanceType::IMMUNE_ACID,
index 9030dce..e075684 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "monster-race/race-flags-resistance.h"
 #include "util/flag-group.h"
diff --git a/src/monster-race/race-sex-const.cpp b/src/monster-race/race-sex-const.cpp
new file mode 100644 (file)
index 0000000..4d79ed2
--- /dev/null
@@ -0,0 +1,42 @@
+#include "monster-race/race-sex-const.h"
+#include "system/monster-race-info.h"
+
+/*!
+ * @brief 性別が男性を含むか否かを判定
+ * @param 性別の変数
+ * @return 男性を含むか否か
+ */
+bool is_male(const MonsterSex sex)
+{
+    return sex == MonsterSex::MALE;
+}
+
+/*!
+ * @brief 性別が男性を含むか否かを判定
+ * @param 判定するモンスターの参照
+ * @return 男性を含むか否か
+ */
+bool is_male(const MonsterRaceInfo &monrace)
+{
+    return is_male(monrace.sex);
+}
+
+/*!
+ * @brief 性別が女性を含むか否かを判定
+ * @param 性別の変数
+ * @return 女性を含むか否か
+ */
+bool is_female(const MonsterSex sex)
+{
+    return sex == MonsterSex::FEMALE;
+}
+
+/*!
+ *@brief 性別が女性を含むか否かを判定
+ * @param 判定するモンスターの参照
+ *@return 女性を含むか否か
+ */
+bool is_female(const MonsterRaceInfo &monrace)
+{
+    return is_female(monrace.sex);
+}
diff --git a/src/monster-race/race-sex-const.h b/src/monster-race/race-sex-const.h
new file mode 100644 (file)
index 0000000..3e02fe3
--- /dev/null
@@ -0,0 +1,14 @@
+#pragma once
+
+class MonsterRaceInfo;
+
+enum class MonsterSex {
+    NONE = 0,
+    MALE = 1,
+    FEMALE = 2,
+};
+
+bool is_male(const MonsterSex sex);
+bool is_male(const MonsterRaceInfo &monrace);
+bool is_female(const MonsterSex sex);
+bool is_female(const MonsterRaceInfo &monrace);
index f7cf6cf..142d396 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterSpeakType {
     SPEAK_ALL = 0, /* SPEAK_BATTLE, SPEAK_FEAR, SPEAK_FRIEND, SPEAK_DEATH */
index 7714972..6444a9b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterVisualType {
     CLEAR = 0,
index f6c7237..e22fffd 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterWildernessType {
     WILD_ONLY = 0,
index f63104a..2ae4790 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file horror-descriptions.cpp
  * @brief エルドリッチホラーの形容詞テーブル定義
  * @date 2023/04/29
index 0e92f91..d139a29 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 #include <vector>
index 01825ba..857ba56 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster/monster-compaction.h"
+#include "monster/monster-compaction.h"
 #include "core/stuff-handler.h"
 #include "game-option/play-record-options.h"
 #include "io/write-diary.h"
@@ -36,7 +36,7 @@ static void compact_monsters_aux(PlayerType *player_ptr, MONSTER_IDX i1, MONSTER
 
     POSITION y = m_ptr->fy;
     POSITION x = m_ptr->fx;
-    grid_type *g_ptr;
+    Grid *g_ptr;
     g_ptr = &floor_ptr->grid_array[y][x];
     g_ptr->m_idx = i2;
 
@@ -113,7 +113,7 @@ void compact_monsters(PlayerType *player_ptr, int size)
         int cur_dis = 5 * (20 - cnt);
         for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
             auto *m_ptr = &floor_ptr->m_list[i];
-            auto *r_ptr = &monraces_info[m_ptr->r_idx];
+            auto *r_ptr = &m_ptr->get_monrace();
             if (!m_ptr->is_valid()) {
                 continue;
             }
@@ -142,7 +142,7 @@ void compact_monsters(PlayerType *player_ptr, int size)
 
             if (record_named_pet && m_ptr->is_named_pet()) {
                 const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-                exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_COMPACT, m_name.data());
+                exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_COMPACT, m_name);
             }
 
             delete_monster_idx(player_ptr, i);
index 1b8e0f6..ad33f5a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void compact_monsters(PlayerType *player_ptr, int size);
index 87ea61e..14da949 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief モンスターがダメージを受けた時の処理と経験値の加算処理
  * @date 2021/08/04
  * @author Hourier
@@ -6,7 +6,6 @@
 
 #include "monster/monster-damage.h"
 #include "avatar/avatar-changer.h"
-#include "core/player-redraw-types.h"
 #include "core/speed-table.h"
 #include "core/stuff-handler.h"
 #include "game-option/birth-options.h"
 #include "player/special-defense-types.h"
 #include "spell-kind/spells-random.h"
 #include "status/experience.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-hallucination.h"
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include "world/world.h"
-#include <algorithm>
 #include <optional>
+#include <sstream>
 #include <string>
 
 /*
@@ -92,7 +93,7 @@ MonsterDamageProcessor::MonsterDamageProcessor(PlayerType *player_ptr, MONSTER_I
  * @brief モンスターのHPをダメージに応じて減算する /
  * @return モンスターが生きていればfalse、死んだらtrue
  */
-bool MonsterDamageProcessor::mon_take_hit(concptr note)
+bool MonsterDamageProcessor::mon_take_hit(std::string_view note)
 {
     auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
     auto exp_mon = *m_ptr;
@@ -136,10 +137,10 @@ bool MonsterDamageProcessor::genocide_chaos_patron()
     return this->m_idx == 0;
 }
 
-bool MonsterDamageProcessor::process_dead_exp_virtue(concptr note, MonsterEntity *exp_mon)
+bool MonsterDamageProcessor::process_dead_exp_virtue(std::string_view note, MonsterEntity *exp_mon)
 {
     auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
-    auto &r_ref = m_ptr->get_real_r_ref();
+    auto &r_ref = m_ptr->get_real_monrace();
     if (m_ptr->hp >= 0) {
         return false;
     }
@@ -156,7 +157,9 @@ bool MonsterDamageProcessor::process_dead_exp_virtue(concptr note, MonsterEntity
     AvatarChanger ac(player_ptr, m_ptr);
     ac.change_virtue();
     if (r_ref.kind_flags.has(MonsterKindType::UNIQUE) && record_destroy_uniq) {
-        exe_write_diary(this->player_ptr, DIARY_UNIQUE, 0, std::string(r_ref.name).append(m_ptr->mflag2.has(MonsterConstantFlagType::CLONED) ? _("(クローン)", "(Clone)") : "").data());
+        std::stringstream ss;
+        ss << r_ref.name << (m_ptr->mflag2.has(MonsterConstantFlagType::CLONED) ? _("(クローン)", "(Clone)") : "");
+        exe_write_diary(this->player_ptr, DiaryKind::UNIQUE, 0, ss.str());
     }
 
     sound(SOUND_KILL);
@@ -187,8 +190,8 @@ void MonsterDamageProcessor::death_special_flag_monster()
     }
 
     if (m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON)) {
-        auto &real_r_ref = m_ptr->get_real_r_ref();
-        r_idx = m_ptr->get_real_r_idx();
+        auto &real_r_ref = m_ptr->get_real_monrace();
+        r_idx = m_ptr->get_real_monrace_id();
         if (real_r_ref.r_sights < MAX_SHORT) {
             real_r_ref.r_sights++;
         }
@@ -217,80 +220,16 @@ void MonsterDamageProcessor::death_special_flag_monster()
 void MonsterDamageProcessor::death_unique_monster(MonsterRaceId r_idx)
 {
     monraces_info[r_idx].max_num = 0;
-    std::vector<MonsterRaceId> combined_unique_vec;
-    if (!check_combined_unique(r_idx, &combined_unique_vec)) {
-        return;
-    }
-
-    combined_uniques uniques;
-    const int one_unit = 3;
-    for (auto i = 0U; i < combined_unique_vec.size(); i += one_unit) {
-        auto unique = std::make_tuple(combined_unique_vec[i], combined_unique_vec[i + 1], combined_unique_vec[i + 2]);
-        uniques.push_back(unique);
-    }
-
-    this->death_combined_uniques(r_idx, uniques);
-}
-
-/*
- * @brief 死亡したモンスターが分裂/合体を行う特殊ユニークか否かの判定処理
- * @param r_idx 死亡したモンスターの種族番号
- * @param united_uniques 分裂/合体を行う特殊ユニーク
- * @details 合体後、合体前1、合体前2 の順にpush_backすること
- */
-bool MonsterDamageProcessor::check_combined_unique(const MonsterRaceId r_idx, std::vector<MonsterRaceId> *combined_unique_vec)
-{
-    combined_unique_vec->push_back(MonsterRaceId::BANORLUPART);
-    combined_unique_vec->push_back(MonsterRaceId::BANOR);
-    combined_unique_vec->push_back(MonsterRaceId::LUPART);
-
-    for (const auto &unique : *combined_unique_vec) {
-        if (r_idx == unique) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-/*!
- * @brief 分裂/合体を行う特殊ユニークの死亡処理
- * @details 分裂/合体が A = B + C という図式の時、Aが死亡した場合BとCも死亡処理を行う。
- * BもしくはCが死亡した場合、Aの死亡処理を行う。
- * @param r_idx 実際に死亡したモンスターの種族ID
- * @param combined_uniques 分裂/合体を行う特殊ユニークのリスト
- */
-void MonsterDamageProcessor::death_combined_uniques(const MonsterRaceId r_idx, const combined_uniques &combined_uniques)
-{
-    auto death_r_idx = [](MonsterRaceId r_idx) {
-        auto &r_ref = monraces_info[r_idx];
-        r_ref.max_num = 0;
-        r_ref.r_pkills++;
-        r_ref.r_akills++;
-        if (r_ref.r_tkills < MAX_SHORT) {
-            r_ref.r_tkills++;
-        }
-    };
-
-    for (auto [united, split1, split2] : combined_uniques) {
-        if ((r_idx == split1) || (r_idx == split2)) {
-            death_r_idx(united);
-            continue;
-        }
-
-        if (r_idx != united) {
-            continue;
-        }
-
-        death_r_idx(split1);
-        death_r_idx(split2);
+    auto &monraces = MonraceList::get_instance();
+    if (monraces.can_unify_separate(r_idx)) {
+        monraces.kill_unified_unique(r_idx);
     }
 }
 
 void MonsterDamageProcessor::increase_kill_numbers()
 {
     auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
-    auto &r_ref = m_ptr->get_real_r_ref();
+    auto &r_ref = m_ptr->get_real_monrace();
     auto is_hallucinated = this->player_ptr->effects()->hallucination()->is_hallucinated();
     if (((m_ptr->ml == 0) || is_hallucinated) && r_ref.kind_flags.has_not(MonsterKindType::UNIQUE)) {
         return;
@@ -314,7 +253,7 @@ void MonsterDamageProcessor::increase_kill_numbers()
 void MonsterDamageProcessor::death_amberites(std::string_view m_name)
 {
     auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
-    const auto &r_ref = m_ptr->get_real_r_ref();
+    const auto &r_ref = m_ptr->get_real_monrace();
     if (r_ref.kind_flags.has_not(MonsterKindType::AMBERITE) || one_in_(2)) {
         return;
     }
@@ -332,13 +271,13 @@ void MonsterDamageProcessor::death_amberites(std::string_view m_name)
 void MonsterDamageProcessor::dying_scream(std::string_view m_name)
 {
     auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
-    const auto &r_ref = m_ptr->get_real_r_ref();
+    const auto &r_ref = m_ptr->get_real_monrace();
     if (r_ref.speak_flags.has_none_of({ MonsterSpeakType::SPEAK_ALL, MonsterSpeakType::SPEAK_DEATH })) {
         return;
     }
 
     const auto death_mes = get_random_line(_("mondeath_j.txt", "mondeath.txt"), enum2i(m_ptr->r_idx));
-    if (death_mes.has_value()) {
+    if (death_mes) {
         msg_format("%s^ %s", m_name.data(), death_mes->data());
     }
 
@@ -349,13 +288,12 @@ void MonsterDamageProcessor::dying_scream(std::string_view m_name)
 #endif
 }
 
-void MonsterDamageProcessor::show_kill_message(concptr note, std::string_view m_name)
+void MonsterDamageProcessor::show_kill_message(std::string_view note, std::string_view m_name)
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[this->m_idx];
-    const auto &r_ref = m_ptr->get_real_r_ref();
-    if (note != nullptr) {
-        msg_format("%s^%s", m_name.data(), note);
+    if (!note.empty()) {
+        msg_format("%s^%s", m_name.data(), note.data());
         return;
     }
 
@@ -366,11 +304,11 @@ void MonsterDamageProcessor::show_kill_message(concptr note, std::string_view m_
         return;
     }
 
-    const auto explode = std::any_of(std::begin(r_ref.blow), std::end(r_ref.blow), [](const auto &blow) { return blow.method == RaceBlowMethodType::EXPLODE; });
-
-    if (monster_living(m_ptr->r_idx)) {
-        if (explode) {
-            msg_format(_("%sは爆発して死んだ。", "%s^ explodes and dies."), m_name.data());
+    const auto is_explodable = m_ptr->is_explodable();
+    const auto died_mes = m_ptr->get_died_message();
+    if (m_ptr->has_living_flag()) {
+        if (is_explodable) {
+            this->show_explosion_message(died_mes, m_name);
             return;
         }
 
@@ -380,8 +318,8 @@ void MonsterDamageProcessor::show_kill_message(concptr note, std::string_view m_
         return;
     }
 
-    if (explode) {
-        msg_format(_("%sは爆発して粉々になった。", "%s^ explodes into tiny shreds."), m_name.data());
+    if (is_explodable) {
+        this->show_explosion_message(died_mes, m_name);
         return;
     }
 
@@ -390,11 +328,20 @@ void MonsterDamageProcessor::show_kill_message(concptr note, std::string_view m_
     msg_format(mes, m_name.data());
 }
 
+void MonsterDamageProcessor::show_explosion_message(std::string_view died_mes, std::string_view m_name)
+{
+    std::stringstream ss;
+    ss << _(m_name, format("%s^", m_name.data()));
+    ss << died_mes;
+    msg_print(ss.str());
+    return;
+}
+
 void MonsterDamageProcessor::show_bounty_message(std::string_view m_name)
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[this->m_idx];
-    const auto &r_ref = m_ptr->get_real_r_ref();
+    const auto &r_ref = m_ptr->get_real_monrace();
     if (r_ref.kind_flags.has_not(MonsterKindType::UNIQUE) || m_ptr->mflag2.has(MonsterConstantFlagType::CLONED) || vanilla_town) {
         return;
     }
@@ -422,8 +369,8 @@ void MonsterDamageProcessor::show_bounty_message(std::string_view m_name)
  */
 void MonsterDamageProcessor::get_exp_from_mon(MonsterEntity *m_ptr, int exp_dam)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (!m_ptr->is_valid() || m_ptr->is_pet() || this->player_ptr->phase_out) {
+    auto *r_ptr = &m_ptr->get_monrace();
+    if (!m_ptr->is_valid() || m_ptr->is_pet() || AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -442,8 +389,12 @@ void MonsterDamageProcessor::get_exp_from_mon(MonsterEntity *m_ptr, int exp_dam)
     s64b_mul(&div_h, &div_l, 0, r_ptr->hdice * (ironman_nightmare ? 2 : 1) * compensation);
 
     /* Special penalty in the wilderness */
-    if (!this->player_ptr->current_floor_ptr->dun_level && (r_ptr->wilderness_flags.has_not(MonsterWildernessType::WILD_ONLY) || r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE))) {
-        s64b_mul(&div_h, &div_l, 0, 5);
+    if (!this->player_ptr->current_floor_ptr->is_in_dungeon()) {
+        auto is_dungeon_monster = r_ptr->wilderness_flags.has_not(MonsterWildernessType::WILD_ONLY);
+        is_dungeon_monster |= r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE);
+        if (is_dungeon_monster) {
+            s64b_mul(&div_h, &div_l, 0, 5);
+        }
     }
 
     /* Do ENERGY_DIVISION first to prevent overflaw */
@@ -482,12 +433,13 @@ void MonsterDamageProcessor::get_exp_from_mon(MonsterEntity *m_ptr, int exp_dam)
 
 void MonsterDamageProcessor::set_redraw()
 {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (this->player_ptr->health_who == this->m_idx) {
-        this->player_ptr->redraw |= PR_HEALTH;
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (this->player_ptr->riding == this->m_idx) {
-        this->player_ptr->redraw |= PR_UHEALTH;
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 }
 
@@ -500,7 +452,7 @@ void MonsterDamageProcessor::summon_special_unique()
     auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
     bool is_special_summon = m_ptr->r_idx == MonsterRaceId::IKETA;
     is_special_summon |= m_ptr->r_idx == MonsterRaceId::DOPPIO;
-    if (!is_special_summon || this->player_ptr->current_floor_ptr->inside_arena || this->player_ptr->phase_out) {
+    if (!is_special_summon || this->player_ptr->current_floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         delete_monster_idx(this->player_ptr, this->m_idx);
         return;
     }
@@ -545,8 +497,8 @@ void MonsterDamageProcessor::add_monster_fear()
         }
     }
 
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (m_ptr->is_fearful() || any_bits(r_ptr->flags3, RF3_NO_FEAR)) {
+    auto *r_ptr = &m_ptr->get_monrace();
+    if (m_ptr->is_fearful() || r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
         return;
     }
 
index 6059027..ffa3776 100644 (file)
@@ -1,9 +1,10 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "monster-race/race-indice-types.h"
 #include "system/angband.h"
 #include "util/flag-group.h"
+#include <string_view>
 #include <tuple>
 #include <vector>
 
@@ -11,13 +12,12 @@ enum class MonsterRaceId : int16_t;
 class MonsterRaceInfo;
 class MonsterEntity;
 class PlayerType;
-typedef std::vector<std::tuple<MonsterRaceId, MonsterRaceId, MonsterRaceId>> combined_uniques;
 class MonsterDamageProcessor {
 public:
     MonsterDamageProcessor(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *fear, AttributeType type);
     MonsterDamageProcessor(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *fear, AttributeFlags attribute_flags);
     virtual ~MonsterDamageProcessor() = default;
-    bool mon_take_hit(concptr note);
+    bool mon_take_hit(std::string_view note);
 
 private:
     PlayerType *player_ptr;
@@ -27,15 +27,14 @@ private:
     AttributeFlags attribute_flags{};
     void get_exp_from_mon(MonsterEntity *m_ptr, int exp_dam);
     bool genocide_chaos_patron();
-    bool process_dead_exp_virtue(concptr note, MonsterEntity *exp_mon);
+    bool process_dead_exp_virtue(std::string_view note, MonsterEntity *exp_mon);
     void death_special_flag_monster();
     void death_unique_monster(MonsterRaceId r_idx);
-    bool check_combined_unique(const MonsterRaceId r_idx, std::vector<MonsterRaceId> *combined_uniques);
-    void death_combined_uniques(const MonsterRaceId r_idx, const combined_uniques &combined_uniques);
     void increase_kill_numbers();
     void death_amberites(std::string_view m_name);
     void dying_scream(std::string_view m_name);
-    void show_kill_message(concptr note, std::string_view m_name);
+    void show_kill_message(std::string_view note, std::string_view m_name);
+    void show_explosion_message(std::string_view died_mes, std::string_view m_name);
     void show_bounty_message(std::string_view m_name);
     void set_redraw();
     void summon_special_unique();
index c4b0491..0ecfbe0 100644 (file)
@@ -1,11 +1,13 @@
-#include "monster/monster-describer.h"
+#include "monster/monster-describer.h"
 #include "io/files-util.h"
 #include "locale/english.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
+#include "monster-race/race-sex-const.h"
 #include "monster/monster-description-types.h"
 #include "monster/monster-flag-types.h"
 #include "monster/monster-info.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
@@ -13,7 +15,6 @@
 #include "timed-effect/player-hallucination.h"
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 #include <optional>
@@ -27,15 +28,12 @@ static int get_monster_pronoun_kind(const MonsterRaceInfo &monrace, const bool p
     if (!pron) {
         return 0x00;
     }
-
-    if (any_bits(monrace.flags1, RF1_FEMALE)) {
+    if (monrace.sex == MonsterSex::FEMALE) {
         return 0x20;
     }
-
-    if (any_bits(monrace.flags1, RF1_MALE)) {
+    if (monrace.sex == MonsterSex::MALE) {
         return 0x10;
     }
-
     return 0x00;
 }
 
@@ -103,24 +101,24 @@ static std::optional<std::string> decide_monster_personal_pronoun(const MonsterE
         return std::nullopt;
     }
 
-    const auto &monrace = monraces_info[monster.ap_r_idx];
+    const auto &monrace = monster.get_appearance_monrace();
     const auto kind = get_monster_pronoun_kind(monrace, pron);
     return get_monster_personal_pronoun(kind, mode);
 }
 
 static std::optional<std::string> get_monster_self_pronoun(const MonsterEntity &monster, const BIT_FLAGS mode)
 {
-    const auto &monrace = monraces_info[monster.ap_r_idx];
+    const auto &monrace = monster.get_appearance_monrace();
     constexpr BIT_FLAGS self = MD_POSSESSIVE | MD_OBJECTIVE;
     if (!match_bits(mode, self, self)) {
         return std::nullopt;
     }
 
-    if (any_bits(monrace.flags1, RF1_FEMALE)) {
+    if (monrace.sex == MonsterSex::FEMALE) {
         return _("彼女自身", "herself");
     }
 
-    if (any_bits(monrace.flags1, RF1_MALE)) {
+    if (monrace.sex == MonsterSex::MALE) {
         return _("彼自身", "himself");
     }
 
@@ -129,16 +127,16 @@ static std::optional<std::string> get_monster_self_pronoun(const MonsterEntity &
 
 static std::string get_describing_monster_name(const MonsterEntity &monster, const bool is_hallucinated, const BIT_FLAGS mode)
 {
-    const auto &monrace = monraces_info[monster.ap_r_idx];
+    const auto &monrace = monster.get_appearance_monrace();
     if (!is_hallucinated || any_bits(mode, MD_IGNORE_HALLU)) {
-        return any_bits(mode, MD_TRUE_NAME) ? monster.get_real_r_ref().name : monrace.name;
+        return any_bits(mode, MD_TRUE_NAME) ? monster.get_real_monrace().name : monrace.name;
     }
 
     if (one_in_(2)) {
         constexpr auto filename = _("silly_j.txt", "silly.txt");
         const auto silly_name = get_random_line(filename, enum2i(monster.r_idx));
-        if (silly_name.has_value()) {
-            return silly_name.value();
+        if (silly_name) {
+            return *silly_name;
         }
     }
 
@@ -146,7 +144,7 @@ static std::string get_describing_monster_name(const MonsterEntity &monster, con
     do {
         auto r_idx = MonsterRace::pick_one_at_random();
         hallu_race = &monraces_info[r_idx];
-    } while (hallu_race->name.empty() || hallu_race->kind_flags.has(MonsterKindType::UNIQUE));
+    } while (hallu_race->kind_flags.has(MonsterKindType::UNIQUE));
     return hallu_race->name;
 }
 
@@ -171,7 +169,7 @@ static std::string replace_monster_name_undefined(std::string_view name)
 
 static std::optional<std::string> get_fake_monster_name(const PlayerType &player, const MonsterEntity &monster, const std::string &name, const BIT_FLAGS mode)
 {
-    const auto &monrace = monraces_info[monster.ap_r_idx];
+    const auto &monrace = monster.get_appearance_monrace();
     const auto is_hallucinated = player.effects()->hallucination()->is_hallucinated();
     if (monrace.kind_flags.has_not(MonsterKindType::UNIQUE) || (is_hallucinated && none_bits(mode, MD_IGNORE_HALLU))) {
         return std::nullopt;
@@ -181,7 +179,7 @@ static std::optional<std::string> get_fake_monster_name(const PlayerType &player
         return _(replace_monster_name_undefined(name), format("%s?", name.data()));
     }
 
-    if (player.phase_out && !(player.riding && (&player.current_floor_ptr->m_list[player.riding] == &monster))) {
+    if (AngbandSystem::get_instance().is_phase_out() && !(player.riding && (&player.current_floor_ptr->m_list[player.riding] == &monster))) {
         return format(_("%sもどき", "fake %s"), name.data());
     }
 
@@ -191,8 +189,8 @@ static std::optional<std::string> get_fake_monster_name(const PlayerType &player
 static std::string describe_non_pet(const PlayerType &player, const MonsterEntity &monster, const std::string &name, const BIT_FLAGS mode)
 {
     const auto fake_name = get_fake_monster_name(player, monster, name, mode);
-    if (fake_name.has_value()) {
-        return fake_name.value();
+    if (fake_name) {
+        return *fake_name;
     }
 
     if (any_bits(mode, MD_INDEF_VISIBLE)) {
@@ -209,7 +207,7 @@ static std::string describe_non_pet(const PlayerType &player, const MonsterEntit
     }
 
     std::stringstream ss;
-    if (monster.is_pet()) {
+    if (monster.is_pet() && none_bits(mode, MD_NO_OWNER)) {
         ss << _("あなたの", "your ");
     } else {
         ss << _("", "the ");
@@ -225,7 +223,7 @@ static std::string add_cameleon_name(const MonsterEntity &monster, const BIT_FLA
         return "";
     }
 
-    const auto &monrace = monraces_info[monster.ap_r_idx];
+    const auto &monrace = monster.get_appearance_monrace();
     if (monrace.kind_flags.has(MonsterKindType::UNIQUE)) {
         return _("(カメレオンの王)", "(Chameleon Lord)");
     }
@@ -242,13 +240,13 @@ static std::string add_cameleon_name(const MonsterEntity &monster, const BIT_FLA
 std::string monster_desc(PlayerType *player_ptr, const MonsterEntity *m_ptr, BIT_FLAGS mode)
 {
     const auto pronoun = decide_monster_personal_pronoun(*m_ptr, mode);
-    if (pronoun.has_value()) {
-        return pronoun.value();
+    if (pronoun) {
+        return *pronoun;
     }
 
     const auto pronoun_self = get_monster_self_pronoun(*m_ptr, mode);
-    if (pronoun_self.has_value()) {
-        return pronoun_self.value();
+    if (pronoun_self) {
+        return *pronoun_self;
     }
 
     const auto is_hallucinated = player_ptr->effects()->hallucination()->is_hallucinated();
@@ -270,7 +268,7 @@ std::string monster_desc(PlayerType *player_ptr, const MonsterEntity *m_ptr, BIT
 
     ss << add_cameleon_name(*m_ptr, mode);
     if (any_bits(mode, MD_IGNORE_HALLU) && !m_ptr->is_original_ap()) {
-        ss << "(" << monraces_info[m_ptr->r_idx].name << ")";
+        ss << "(" << m_ptr->get_monrace().name << ")";
     }
 
     if (any_bits(mode, MD_POSSESSIVE)) {
index bdf778f..e7b39ea 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
index 6096aaf..d01868a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum monsetr_description_type {
     MD_NONE = 0x00000000,
@@ -12,6 +12,7 @@ enum monsetr_description_type {
     MD_ASSUME_VISIBLE = 0x00000080, /* Assume the monster is visible */
     MD_TRUE_NAME = 0x00000100, /* Chameleon's true name */
     MD_IGNORE_HALLU = 0x00000200, /* Ignore hallucination, and penetrate shape change */
+    MD_NO_OWNER = 0x00000400, /* Do not indicate the pet's owner as in "your" */
 };
 
 #define MD_WRONGDOER_NAME (MD_IGNORE_HALLU | MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE) /* 加害明記向け */
index 2ee55e4..3494c43 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterTemporaryFlagType {
     VIEW = 0, /* Monster is in line of sight */
index f15bcd8..e882f7d 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター情報の記述 / describe monsters (using monster memory)
  * @date 2013/12/11
  * @author
@@ -55,11 +55,10 @@ void set_friendly(MonsterEntity *m_ptr)
  * @param mode オプション
  * @return 踏破可能ならばTRUEを返す
  */
-bool monster_can_cross_terrain(PlayerType *player_ptr, FEAT_IDX feat, MonsterRaceInfo *r_ptr, BIT_FLAGS16 mode)
+bool monster_can_cross_terrain(PlayerType *player_ptr, FEAT_IDX feat, const MonsterRaceInfo *r_ptr, BIT_FLAGS16 mode)
 {
-    auto *f_ptr = &terrains_info[feat];
-
-    if (f_ptr->flags.has(TerrainCharacteristics::PATTERN)) {
+    const auto &terrain = TerrainList::get_instance()[feat];
+    if (terrain.flags.has(TerrainCharacteristics::PATTERN)) {
         if (!(mode & CEM_RIDING)) {
             if (r_ptr->feature_flags.has_not(MonsterFeatureType::CAN_FLY)) {
                 return false;
@@ -71,29 +70,29 @@ bool monster_can_cross_terrain(PlayerType *player_ptr, FEAT_IDX feat, MonsterRac
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::CAN_FLY) && r_ptr->feature_flags.has(MonsterFeatureType::CAN_FLY)) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_FLY) && r_ptr->feature_flags.has(MonsterFeatureType::CAN_FLY)) {
         return true;
     }
-    if (f_ptr->flags.has(TerrainCharacteristics::CAN_SWIM) && r_ptr->feature_flags.has(MonsterFeatureType::CAN_SWIM)) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_SWIM) && r_ptr->feature_flags.has(MonsterFeatureType::CAN_SWIM)) {
         return true;
     }
-    if (f_ptr->flags.has(TerrainCharacteristics::CAN_PASS)) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_PASS)) {
         if (r_ptr->feature_flags.has(MonsterFeatureType::PASS_WALL) && (!(mode & CEM_RIDING) || has_pass_wall(player_ptr))) {
             return true;
         }
     }
 
-    if (f_ptr->flags.has_not(TerrainCharacteristics::MOVE)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::MOVE)) {
         return false;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::MOUNTAIN) && (r_ptr->wilderness_flags.has(MonsterWildernessType::WILD_MOUNTAIN))) {
+    if (terrain.flags.has(TerrainCharacteristics::MOUNTAIN) && (r_ptr->wilderness_flags.has(MonsterWildernessType::WILD_MOUNTAIN))) {
         return true;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::WATER)) {
+    if (terrain.flags.has(TerrainCharacteristics::WATER)) {
         if (r_ptr->feature_flags.has_not(MonsterFeatureType::AQUATIC)) {
-            if (f_ptr->flags.has(TerrainCharacteristics::DEEP)) {
+            if (terrain.flags.has(TerrainCharacteristics::DEEP)) {
                 return false;
             } else if (r_ptr->aura_flags.has(MonsterAuraType::FIRE)) {
                 return false;
@@ -103,31 +102,31 @@ bool monster_can_cross_terrain(PlayerType *player_ptr, FEAT_IDX feat, MonsterRac
         return false;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::LAVA)) {
+    if (terrain.flags.has(TerrainCharacteristics::LAVA)) {
         if (r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_FIRE_MASK)) {
             return false;
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::COLD_PUDDLE)) {
+    if (terrain.flags.has(TerrainCharacteristics::COLD_PUDDLE)) {
         if (r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_COLD_MASK)) {
             return false;
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::ELEC_PUDDLE)) {
+    if (terrain.flags.has(TerrainCharacteristics::ELEC_PUDDLE)) {
         if (r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_ELEC_MASK)) {
             return false;
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::ACID_PUDDLE)) {
+    if (terrain.flags.has(TerrainCharacteristics::ACID_PUDDLE)) {
         if (r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_ACID_MASK)) {
             return false;
         }
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::POISON_PUDDLE)) {
+    if (terrain.flags.has(TerrainCharacteristics::POISON_PUDDLE)) {
         if (r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_POISON_MASK)) {
             return false;
         }
@@ -148,72 +147,16 @@ bool monster_can_cross_terrain(PlayerType *player_ptr, FEAT_IDX feat, MonsterRac
  */
 bool monster_can_enter(PlayerType *player_ptr, POSITION y, POSITION x, MonsterRaceInfo *r_ptr, BIT_FLAGS16 mode)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    if (player_bold(player_ptr, y, x)) {
+    const Pos2D pos(y, x);
+    auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    if (player_ptr->is_located_at(pos)) {
         return false;
     }
-    if (g_ptr->m_idx) {
+    if (grid.m_idx) {
         return false;
     }
 
-    return monster_can_cross_terrain(player_ptr, g_ptr->feat, r_ptr, mode);
-}
-
-/*!
- * @brief モンスターの属性の基づいた敵対関係の有無を返す(サブルーチン)
- * Check if this monster has "hostile" alignment (aux)
- * @param sub_align1 モンスター1のサブフラグ
- * @param sub_align2 モンスター2のサブフラグ
- * @return 敵対関係にあるならばTRUEを返す
- */
-static bool check_hostile_align(byte sub_align1, byte sub_align2)
-{
-    if (sub_align1 != sub_align2) {
-        if (((sub_align1 & SUB_ALIGN_EVIL) && (sub_align2 & SUB_ALIGN_GOOD)) || ((sub_align1 & SUB_ALIGN_GOOD) && (sub_align2 & SUB_ALIGN_EVIL))) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-/*!
- * @brief モンスターの属性の基づいた敵対関係の有無を返す
- * Check if two monsters are enemies
- * @param m_ptr モンスター1の構造体参照ポインタ
- * @param n_ptr モンスター2の構造体参照ポインタ
- * @return 敵対関係にあるならばTRUEを返す
- */
-bool are_enemies(PlayerType *player_ptr, const MonsterEntity &m1_ref, const MonsterEntity &m2_ref)
-{
-    if (player_ptr->phase_out) {
-        if (m1_ref.is_pet() || m2_ref.is_pet()) {
-            return false;
-        }
-        return true;
-    }
-
-    const auto &r1_ref = monraces_info[m1_ref.r_idx];
-    const auto &r2_ref = monraces_info[m2_ref.r_idx];
-    const auto is_m1_wild = r1_ref.wilderness_flags.has_any_of({ MonsterWildernessType::WILD_TOWN, MonsterWildernessType::WILD_ALL });
-    const auto is_m2_wild = r2_ref.wilderness_flags.has_any_of({ MonsterWildernessType::WILD_TOWN, MonsterWildernessType::WILD_ALL });
-    if (is_m1_wild && is_m2_wild) {
-        if (!m1_ref.is_pet() && !m2_ref.is_pet()) {
-            return false;
-        }
-    }
-
-    if (check_hostile_align(m1_ref.sub_align, m2_ref.sub_align)) {
-        if (m1_ref.mflag2.has_not(MonsterConstantFlagType::CHAMELEON) || m2_ref.mflag2.has_not(MonsterConstantFlagType::CHAMELEON)) {
-            return true;
-        }
-    }
-
-    if (m1_ref.is_hostile() != m2_ref.is_hostile()) {
-        return true;
-    }
-
-    return false;
+    return monster_can_cross_terrain(player_ptr, grid.feat, r_ptr, mode);
 }
 
 /*!
@@ -228,7 +171,7 @@ bool are_enemies(PlayerType *player_ptr, const MonsterEntity &m1_ref, const Mons
  * @details
  * If user is player, m_ptr == nullptr.
  */
-bool monster_has_hostile_align(PlayerType *player_ptr, MonsterEntity *m_ptr, int pa_good, int pa_evil, MonsterRaceInfo *r_ptr)
+bool monster_has_hostile_align(PlayerType *player_ptr, MonsterEntity *m_ptr, int pa_good, int pa_evil, const MonsterRaceInfo *r_ptr)
 {
     byte sub_align1 = SUB_ALIGN_NEUTRAL;
     byte sub_align2 = SUB_ALIGN_NEUTRAL;
@@ -254,11 +197,7 @@ bool monster_has_hostile_align(PlayerType *player_ptr, MonsterEntity *m_ptr, int
         sub_align2 |= SUB_ALIGN_GOOD;
     }
 
-    if (check_hostile_align(sub_align1, sub_align2)) {
-        return true;
-    }
-
-    return false;
+    return MonsterEntity::check_sub_alignments(sub_align1, sub_align2);
 }
 
 bool is_original_ap_and_seen(PlayerType *player_ptr, const MonsterEntity *m_ptr)
index 5c542f7..82c2a96 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
@@ -12,9 +12,8 @@ enum class MonsterRaceId : int16_t;
 class MonsterRaceInfo;
 class MonsterEntity;
 class PlayerType;
-bool monster_can_cross_terrain(PlayerType *player_ptr, FEAT_IDX feat, MonsterRaceInfo *r_ptr, BIT_FLAGS16 mode);
+bool monster_can_cross_terrain(PlayerType *player_ptr, FEAT_IDX feat, const MonsterRaceInfo *r_ptr, BIT_FLAGS16 mode);
 bool monster_can_enter(PlayerType *player_ptr, POSITION y, POSITION x, MonsterRaceInfo *r_ptr, BIT_FLAGS16 mode);
-bool are_enemies(PlayerType *player_ptr, const MonsterEntity &m1_ref, const MonsterEntity &m2_ref);
-bool monster_has_hostile_align(PlayerType *player_ptr, MonsterEntity *m_ptr, int pa_good, int pa_evil, MonsterRaceInfo *r_ptr);
+bool monster_has_hostile_align(PlayerType *player_ptr, MonsterEntity *m_ptr, int pa_good, int pa_evil, const MonsterRaceInfo *r_ptr);
 bool is_original_ap_and_seen(PlayerType *player_ptr, const MonsterEntity *m_ptr);
 std::string monster_name(PlayerType *player_ptr, MONSTER_IDX m_idx);
index 734868d..31018c6 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター処理 / misc code for monsters
  * @date 2014/07/08
  * @author
@@ -10,7 +10,6 @@
  */
 
 #include "monster/monster-list.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/cave.h"
@@ -21,6 +20,7 @@
 #include "game-option/cheat-options.h"
 #include "grid/grid.h"
 #include "monster-floor/monster-summon.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-kind-mask.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-brightness-mask.h"
@@ -42,6 +42,8 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
+#include "util/bit-flags-calculator.h"
 #include "util/probability-table.h"
 #include "view/display-messages.h"
 #include "world/world.h"
@@ -92,7 +94,7 @@ MONSTER_IDX m_pop(FloorType *floor_ptr)
  * @return 選択されたモンスター生成種族
  * @details nasty生成 (ゲーム内経過日数に応じて、現在フロアより深いフロアのモンスターを出現させる仕様)は
  */
-MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS option)
+MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS mode)
 {
     /* town max_level : same delay as 10F, no nasty mons till day18 */
     auto delay = static_cast<int>(std::sqrt(max_level * 10000)) + (max_level * 5);
@@ -115,7 +117,9 @@ MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_lev
     constexpr auto max_depth_nasty_monster = 25;
     auto chance_nasty = std::max(max_num_nasty_monsters, chance_nasty_monster - over_days / 2);
     auto nasty_level = std::min(max_depth_nasty_monster, over_days / 3);
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::MAZE)) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &dungeon = floor.get_dungeon_definition();
+    if (dungeon.flags.has(DungeonFeatureType::MAZE)) {
         chance_nasty = std::min(chance_nasty / 2, chance_nasty - 10);
         if (chance_nasty < 2) {
             chance_nasty = 2;
@@ -126,7 +130,7 @@ MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_lev
     }
 
     /* Boost the max_level */
-    if ((option & GMN_ARENA) || dungeons_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::BEGINNER)) {
+    if (any_bits(mode, PM_ARENA) || dungeon.flags.has_not(DungeonFeatureType::BEGINNER)) {
         /* Nightmare mode allows more out-of depth monsters */
         if (ironman_nightmare && !randint0(chance_nasty)) {
             /* What a bizarre calculation */
@@ -143,6 +147,7 @@ MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_lev
     ProbabilityTable<int> prob_table;
 
     /* Process probabilities */
+    const auto &monraces = MonraceList::get_instance();
     for (auto i = 0U; i < alloc_race_table.size(); i++) {
         const auto &entry = alloc_race_table[i];
         if (entry.level < min_level) {
@@ -153,22 +158,17 @@ MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_lev
         } // sorted by depth array,
         auto r_idx = i2enum<MonsterRaceId>(entry.index);
         auto r_ptr = &monraces_info[r_idx];
-        if (!(option & GMN_ARENA) && !chameleon_change_m_idx) {
-            if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) && (r_ptr->cur_num >= r_ptr->max_num)) {
+        if (none_bits(mode, PM_ARENA) && !chameleon_change_m_idx) {
+            if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) && (r_ptr->cur_num >= r_ptr->max_num) && none_bits(mode, PM_CLONE)) {
                 continue;
             }
 
-            if ((r_ptr->flags7 & (RF7_UNIQUE2)) && (r_ptr->cur_num >= 1)) {
+            if (r_ptr->population_flags.has(MonsterPopulationType::ONLY_ONE) && (r_ptr->cur_num >= 1)) {
                 continue;
             }
 
-            if (r_idx == MonsterRaceId::BANORLUPART) {
-                if (monraces_info[MonsterRaceId::BANOR].cur_num > 0) {
-                    continue;
-                }
-                if (monraces_info[MonsterRaceId::LUPART].cur_num > 0) {
-                    continue;
-                }
+            if (!monraces.is_selectable(r_idx)) {
+                continue;
             }
         }
 
@@ -214,7 +214,7 @@ static bool monster_hook_chameleon_lord(PlayerType *player_ptr, MonsterRaceId r_
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *r_ptr = &monraces_info[r_idx];
     auto *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
-    MonsterRaceInfo *old_r_ptr = &monraces_info[m_ptr->r_idx];
+    MonsterRaceInfo *old_r_ptr = &m_ptr->get_monrace();
 
     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
         return false;
@@ -227,7 +227,7 @@ static bool monster_hook_chameleon_lord(PlayerType *player_ptr, MonsterRaceId r_
         return false;
     }
 
-    if ((r_ptr->blow[0].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[1].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[2].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[3].method == RaceBlowMethodType::EXPLODE)) {
+    if (m_ptr->is_explodable()) {
         return false;
     }
 
@@ -259,7 +259,7 @@ static bool monster_hook_chameleon(PlayerType *player_ptr, MonsterRaceId r_idx)
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *r_ptr = &monraces_info[r_idx];
     auto *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
-    MonsterRaceInfo *old_r_ptr = &monraces_info[m_ptr->r_idx];
+    MonsterRaceInfo *old_r_ptr = &m_ptr->get_monrace();
 
     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
         return false;
@@ -271,7 +271,7 @@ static bool monster_hook_chameleon(PlayerType *player_ptr, MonsterRaceId r_idx)
         return false;
     }
 
-    if ((r_ptr->blow[0].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[1].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[2].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[3].method == RaceBlowMethodType::EXPLODE)) {
+    if (m_ptr->is_explodable()) {
         return false;
     }
 
@@ -313,7 +313,7 @@ void choose_new_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool born, Mo
     MonsterRaceInfo *r_ptr;
 
     bool old_unique = false;
-    if (monraces_info[m_ptr->r_idx].kind_flags.has(MonsterKindType::UNIQUE)) {
+    if (m_ptr->get_monrace().kind_flags.has(MonsterKindType::UNIQUE)) {
         old_unique = true;
     }
     if (old_unique && (r_idx == MonsterRaceId::CHAMELEON)) {
@@ -341,7 +341,7 @@ void choose_new_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool born, Mo
             level = floor_ptr->dun_level;
         }
 
-        if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::CHAMELEON)) {
+        if (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::CHAMELEON)) {
             level += 2 + randint1(3);
         }
 
@@ -361,7 +361,7 @@ void choose_new_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool born, Mo
 
     auto old_r_idx = m_ptr->r_idx;
     if (monraces_info[old_r_idx].brightness_flags.has_any_of(ld_mask) || r_ptr->brightness_flags.has_any_of(ld_mask)) {
-        player_ptr->update |= (PU_MONSTER_LITE);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 
     if (born) {
index 6293e34..e8a9082 100644 (file)
@@ -1,16 +1,14 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-#define GMN_ARENA 0x00000001 //!< 賭け闘技場向け生成
-
 enum class MonsterRaceId : int16_t;
 class FloorType;
 class MonsterRaceInfo;
 class PlayerType;
 MONSTER_IDX m_pop(FloorType *floor_ptr);
 
-MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS option);
+MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS mode);
 void choose_new_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool born, MonsterRaceId r_idx);
 byte get_mspeed(FloorType *player_ptr, MonsterRaceInfo *r_ptr);
 int get_monster_crowd_number(FloorType *floor_ptr, MONSTER_IDX m_idx);
index 4f7ba63..795431a 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster/monster-pain-describer.h"
+#include "monster/monster-pain-describer.h"
 #include "monster-race/monster-race.h"
 #include "monster/monster-describer.h"
 #include "system/floor-type-definition.h"
@@ -28,8 +28,8 @@ struct pain_message_type {
 static auto d_char_is_any_of(concptr symbols)
 {
     return [symbols](const MonsterEntity &monster) {
-        const auto &m_info = monraces_info[monster.r_idx];
-        return angband_strchr(symbols, m_info.d_char) != nullptr;
+        const auto &monrace = monster.get_monrace();
+        return angband_strchr(symbols, monrace.d_char) != nullptr;
     };
 }
 
@@ -65,8 +65,8 @@ static const std::vector<pain_message_type> pain_messages{
             { 0, _("はくしゃくしゃになった。", " crumples.") },
         } },
     { [](const MonsterEntity &monster) {
-        const auto &m_info = monraces_info[monster.r_idx];
-        return d_char_is_any_of("JMR")(monster) || !isalpha(m_info.d_char); },
+        const auto &monrace = monster.get_monrace();
+        return d_char_is_any_of("JMR")(monster) || !isalpha(monrace.d_char); },
         {
             { 95, _("はほとんど気にとめていない。", " barely notices.") },
             { 75, _("はシーッと鳴いた。", " hisses.") },
index 8725ada..bd7f639 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f95db14..463606f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief monster-processのための構造体群初期化処理と共通性の極めて高い処理
  * @date 2020/03/07
  * @author Hourier
@@ -35,31 +35,6 @@ turn_flags *init_turn_flags(MONSTER_IDX riding_idx, MONSTER_IDX m_idx, turn_flag
     turn_flags_ptr->did_kill_wall = false;
     return turn_flags_ptr;
 }
-
-/*!
- * @brief old_race_flags_ptr の初期化
- */
-old_race_flags *init_old_race_flags(old_race_flags *old_race_flags_ptr)
-{
-    old_race_flags_ptr->old_r_flags1 = 0L;
-    old_race_flags_ptr->old_r_flags2 = 0L;
-    old_race_flags_ptr->old_r_flags3 = 0L;
-    old_race_flags_ptr->old_r_resistance_flags.clear();
-    old_race_flags_ptr->old_r_ability_flags.clear();
-    old_race_flags_ptr->old_r_behavior_flags.clear();
-    old_race_flags_ptr->old_r_kind_flags.clear();
-    old_race_flags_ptr->old_r_drop_flags.clear();
-    old_race_flags_ptr->old_r_feature_flags.clear();
-
-    old_race_flags_ptr->old_r_blows0 = 0;
-    old_race_flags_ptr->old_r_blows1 = 0;
-    old_race_flags_ptr->old_r_blows2 = 0;
-    old_race_flags_ptr->old_r_blows3 = 0;
-
-    old_race_flags_ptr->old_r_cast_spell = 0;
-    return old_race_flags_ptr;
-}
-
 /*!
  * @brief coordinate_candidate の初期化
  * @param なし
@@ -281,32 +256,30 @@ void store_moves_val(int *mm, int y, int x)
 
 /*!
  * @brief 古いモンスター情報の保存
- * @param monster_race_idx モンスターID
- * @param old_race_flags_ptr モンスターフラグへの参照ポインタ
+ * @param monrace_id モンスター種族ID
  */
-void save_old_race_flags(MonsterRaceId monster_race_idx, old_race_flags *old_race_flags_ptr)
+old_race_flags::old_race_flags(MonsterRaceId monrace_id)
 {
-    if (!MonsterRace(monster_race_idx).is_valid()) {
+    if (!MonsterRace(monrace_id).is_valid()) {
         return;
     }
 
-    MonsterRaceInfo *r_ptr;
-    r_ptr = &monraces_info[monster_race_idx];
+    const auto &monrace = monraces_info[monrace_id];
 
-    old_race_flags_ptr->old_r_flags1 = r_ptr->r_flags1;
-    old_race_flags_ptr->old_r_flags2 = r_ptr->r_flags2;
-    old_race_flags_ptr->old_r_flags3 = r_ptr->r_flags3;
-    old_race_flags_ptr->old_r_resistance_flags = r_ptr->r_resistance_flags;
-    old_race_flags_ptr->old_r_ability_flags = r_ptr->r_ability_flags;
-    old_race_flags_ptr->old_r_behavior_flags = r_ptr->r_behavior_flags;
-    old_race_flags_ptr->old_r_kind_flags = r_ptr->r_kind_flags;
-    old_race_flags_ptr->old_r_drop_flags = r_ptr->r_drop_flags;
-    old_race_flags_ptr->old_r_feature_flags = r_ptr->r_feature_flags;
+    this->old_r_flags1 = monrace.r_flags1;
+    this->old_r_flags2 = monrace.r_flags2;
+    this->old_r_flags3 = monrace.r_flags3;
+    this->old_r_ability_flags = monrace.r_ability_flags;
+    this->old_r_behavior_flags = monrace.r_behavior_flags;
+    this->old_r_kind_flags = monrace.r_kind_flags;
+    this->old_r_resistance_flags = monrace.r_resistance_flags;
+    this->old_r_drop_flags = monrace.r_drop_flags;
+    this->old_r_feature_flags = monrace.r_feature_flags;
 
-    old_race_flags_ptr->old_r_blows0 = r_ptr->r_blows[0];
-    old_race_flags_ptr->old_r_blows1 = r_ptr->r_blows[1];
-    old_race_flags_ptr->old_r_blows2 = r_ptr->r_blows[2];
-    old_race_flags_ptr->old_r_blows3 = r_ptr->r_blows[3];
+    this->old_r_blows0 = monrace.r_blows[0];
+    this->old_r_blows1 = monrace.r_blows[1];
+    this->old_r_blows2 = monrace.r_blows[2];
+    this->old_r_blows3 = monrace.r_blows[3];
 
-    old_race_flags_ptr->old_r_cast_spell = r_ptr->r_cast_spell;
+    this->old_r_cast_spell = monrace.r_cast_spell;
 }
index 3df776d..487b52c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief monster-processのための構造体群
  * @date 2020/03/07
  * @author Hourier
@@ -36,24 +36,27 @@ struct turn_flags {
     bool did_kill_wall;
 };
 
+// @details ダミーIDが渡されるとオブジェクトが生焼けになるので、ヘッダ側で全て初期化しておく.
 struct old_race_flags {
-    BIT_FLAGS old_r_flags1;
-    BIT_FLAGS old_r_flags2;
-    BIT_FLAGS old_r_flags3;
-    BIT_FLAGS old_r_flagsr;
-    EnumClassFlagGroup<MonsterAbilityType> old_r_ability_flags;
-    EnumClassFlagGroup<MonsterBehaviorType> old_r_behavior_flags;
-    EnumClassFlagGroup<MonsterKindType> old_r_kind_flags;
-    EnumClassFlagGroup<MonsterResistanceType> old_r_resistance_flags;
-    EnumClassFlagGroup<MonsterDropType> old_r_drop_flags;
-    EnumClassFlagGroup<MonsterFeatureType> old_r_feature_flags;
+    old_race_flags(MonsterRaceId monrace_id);
 
-    byte old_r_blows0;
-    byte old_r_blows1;
-    byte old_r_blows2;
-    byte old_r_blows3;
+    BIT_FLAGS old_r_flags1 = 0;
+    BIT_FLAGS old_r_flags2 = 0;
+    BIT_FLAGS old_r_flags3 = 0;
+    BIT_FLAGS old_r_flagsr = 0;
+    EnumClassFlagGroup<MonsterAbilityType> old_r_ability_flags{};
+    EnumClassFlagGroup<MonsterBehaviorType> old_r_behavior_flags{};
+    EnumClassFlagGroup<MonsterKindType> old_r_kind_flags{};
+    EnumClassFlagGroup<MonsterResistanceType> old_r_resistance_flags{};
+    EnumClassFlagGroup<MonsterDropType> old_r_drop_flags{};
+    EnumClassFlagGroup<MonsterFeatureType> old_r_feature_flags{};
 
-    byte old_r_cast_spell;
+    byte old_r_blows0 = 0;
+    byte old_r_blows1 = 0;
+    byte old_r_blows2 = 0;
+    byte old_r_blows3 = 0;
+
+    byte old_r_cast_spell = 0;
 };
 
 struct coordinate_candidate {
@@ -64,9 +67,7 @@ struct coordinate_candidate {
 
 class MonsterEntity;
 turn_flags *init_turn_flags(MONSTER_IDX riding_idx, MONSTER_IDX m_idx, turn_flags *turn_flags_ptr);
-old_race_flags *init_old_race_flags(old_race_flags *old_race_flags_ptr);
 coordinate_candidate init_coordinate_candidate(void);
 
 void store_enemy_approch_direction(int *mm, POSITION y, POSITION x);
 void store_moves_val(int *mm, int y, int x);
-void save_old_race_flags(MonsterRaceId monster_race_idx, old_race_flags *old_race_flags_ptr);
index c0e5e7f..a89c479 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの特殊技能とターン経過処理 (移動等)/ Monster spells and movement for passaging a turn
  * @date 2014/01/17
  * @author
@@ -15,7 +15,6 @@
 #include "monster/monster-processor.h"
 #include "avatar/avatar.h"
 #include "cmd-io/cmd-dump.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "floor/cave.h"
 #include "floor/geometry.h"
 #include "player/special-defense-types.h"
 #include "spell-realm/spells-hex.h"
 #include "spell/summon-types.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "view/display-messages.h"
 
@@ -115,7 +116,7 @@ bool decide_process_continue(PlayerType *player_ptr, MonsterEntity *m_ptr);
 void process_monster(PlayerType *player_ptr, MONSTER_IDX m_idx)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     turn_flags tmp_flags;
     turn_flags *turn_flags_ptr = init_turn_flags(player_ptr->riding, m_idx, &tmp_flags);
     turn_flags_ptr->see_m = is_seen(player_ptr, m_ptr);
@@ -123,11 +124,27 @@ void process_monster(PlayerType *player_ptr, MONSTER_IDX m_idx)
     decide_drop_from_monster(player_ptr, m_idx, turn_flags_ptr->is_riding_mon);
     if (m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON) && one_in_(13) && !m_ptr->is_asleep()) {
         choose_new_monster(player_ptr, m_idx, false, MonsterRace::empty_id());
-        r_ptr = &monraces_info[m_ptr->r_idx];
+        r_ptr = &m_ptr->get_monrace();
     }
 
     turn_flags_ptr->aware = process_stealth(player_ptr, m_idx);
-    if (vanish_summoned_children(player_ptr, m_idx, turn_flags_ptr->see_m) || process_quantum_effect(player_ptr, m_idx, turn_flags_ptr->see_m) || explode_grenade(player_ptr, m_idx) || runaway_monster(player_ptr, turn_flags_ptr, m_idx) || !awake_monster(player_ptr, m_idx)) {
+    if (vanish_summoned_children(player_ptr, m_idx, turn_flags_ptr->see_m)) {
+        return;
+    }
+
+    if (process_quantum_effect(player_ptr, m_idx, turn_flags_ptr->see_m)) {
+        return;
+    }
+
+    if (explode_grenade(player_ptr, m_idx)) {
+        return;
+    }
+
+    if (runaway_monster(player_ptr, turn_flags_ptr, m_idx)) {
+        return;
+    }
+
+    if (!awake_monster(player_ptr, m_idx)) {
         return;
     }
 
@@ -136,7 +153,7 @@ void process_monster(PlayerType *player_ptr, MONSTER_IDX m_idx)
     }
 
     if (turn_flags_ptr->is_riding_mon) {
-        player_ptr->update |= PU_BONUS;
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     }
 
     process_angar(player_ptr, m_idx, turn_flags_ptr->see_m);
@@ -162,7 +179,7 @@ void process_monster(PlayerType *player_ptr, MONSTER_IDX m_idx)
     }
 
     int count = 0;
-    if (!process_monster_movement(player_ptr, turn_flags_ptr, m_idx, mm, oy, ox, &count)) {
+    if (!process_monster_movement(player_ptr, turn_flags_ptr, m_idx, mm, { oy, ox }, &count)) {
         return;
     }
 
@@ -182,7 +199,8 @@ void process_monster(PlayerType *player_ptr, MONSTER_IDX m_idx)
         }
     }
 
-    update_player_type(player_ptr, turn_flags_ptr, r_ptr);
+    update_map_flags(turn_flags_ptr);
+    update_lite_flags(turn_flags_ptr, r_ptr);
     update_monster_race_flags(player_ptr, turn_flags_ptr, m_ptr);
 
     if (!process_monster_fear(player_ptr, turn_flags_ptr, m_idx)) {
@@ -208,7 +226,7 @@ bool process_stealth(PlayerType *player_ptr, MONSTER_IDX m_idx)
     }
 
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     int tmp = player_ptr->lev * 6 + (player_ptr->skill_stl + 10) * 4;
     if (player_ptr->monlite) {
         tmp /= 3;
@@ -234,7 +252,7 @@ bool process_stealth(PlayerType *player_ptr, MONSTER_IDX m_idx)
 void decide_drop_from_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool is_riding_mon)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (!is_riding_mon || ((r_ptr->flags7 & RF7_RIDING) != 0)) {
         return;
     }
@@ -276,7 +294,7 @@ bool vanish_summoned_children(PlayerType *player_ptr, MONSTER_IDX m_idx, bool se
 
     if (record_named_pet && m_ptr->is_named_pet()) {
         const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-        exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_LOSE_PARENT, m_name.data());
+        exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_LOSE_PARENT, m_name);
     }
 
     delete_monster_idx(player_ptr, m_idx);
@@ -292,7 +310,7 @@ bool vanish_summoned_children(PlayerType *player_ptr, MONSTER_IDX m_idx, bool se
 bool awake_monster(PlayerType *player_ptr, MONSTER_IDX m_idx)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (!m_ptr->is_asleep()) {
         return true;
     }
@@ -322,22 +340,22 @@ bool awake_monster(PlayerType *player_ptr, MONSTER_IDX m_idx)
  */
 void process_angar(PlayerType *player_ptr, MONSTER_IDX m_idx, bool see_m)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    bool gets_angry = false;
-    if (m_ptr->is_friendly() && has_aggravate(player_ptr)) {
+    auto &monster = player_ptr->current_floor_ptr->m_list[m_idx];
+    const auto &monrace = monster.get_monrace();
+    auto gets_angry = monster.is_friendly() && has_aggravate(player_ptr);
+    const auto should_aggravate = monster.is_pet();
+    auto has_hostile = monrace.kind_flags.has(MonsterKindType::UNIQUE) || (monrace.population_flags.has(MonsterPopulationType::NAZGUL));
+    has_hostile &= monster_has_hostile_align(player_ptr, nullptr, 10, -10, &monrace);
+    const auto has_resist_all = monrace.resistance_flags.has(MonsterResistanceType::RESIST_ALL);
+    if (should_aggravate && (has_hostile || has_resist_all)) {
         gets_angry = true;
     }
 
-    if (m_ptr->is_pet() && (((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL))) && monster_has_hostile_align(player_ptr, nullptr, 10, -10, r_ptr)) || r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL))) {
-        gets_angry = true;
-    }
-
-    if (player_ptr->phase_out || !gets_angry) {
+    if (AngbandSystem::get_instance().is_phase_out() || !gets_angry) {
         return;
     }
 
-    const auto m_name = monster_desc(player_ptr, m_ptr, m_ptr->is_pet() ? MD_ASSUME_VISIBLE : 0);
+    const auto m_name = monster_desc(player_ptr, &monster, monster.is_pet() ? MD_ASSUME_VISIBLE : 0);
 
     /* When riding a hostile alignment pet */
     if (player_ptr->riding == m_idx) {
@@ -353,11 +371,11 @@ void process_angar(PlayerType *player_ptr, MONSTER_IDX m_idx, bool see_m)
         msg_format(_("あなたは振り落とされた。", "You have fallen."));
     }
 
-    if (m_ptr->is_pet() || see_m) {
+    if (monster.is_pet() || see_m) {
         msg_format(_("%s^は突然敵にまわった!", "%s^ suddenly becomes hostile!"), m_name.data());
     }
 
-    set_hostile(player_ptr, m_ptr);
+    monster.set_hostile();
 }
 
 /*!
@@ -386,8 +404,14 @@ bool explode_grenade(PlayerType *player_ptr, MONSTER_IDX m_idx)
 void process_special(PlayerType *player_ptr, MONSTER_IDX m_idx)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (r_ptr->ability_flags.has_not(MonsterAbilityType::SPECIAL) || (m_ptr->r_idx != MonsterRaceId::OHMU) || player_ptr->current_floor_ptr->inside_arena || player_ptr->phase_out || (r_ptr->freq_spell == 0) || (randint1(100) > r_ptr->freq_spell)) {
+    auto *r_ptr = &m_ptr->get_monrace();
+    auto can_do_special = r_ptr->ability_flags.has(MonsterAbilityType::SPECIAL);
+    can_do_special &= m_ptr->r_idx == MonsterRaceId::OHMU;
+    can_do_special &= !player_ptr->current_floor_ptr->inside_arena;
+    can_do_special &= !AngbandSystem::get_instance().is_phase_out();
+    can_do_special &= r_ptr->freq_spell != 0;
+    can_do_special &= randint1(100) <= r_ptr->freq_spell;
+    if (!can_do_special) {
         return;
     }
 
@@ -419,7 +443,7 @@ void process_special(PlayerType *player_ptr, MONSTER_IDX m_idx)
 bool decide_monster_multiplication(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION oy, POSITION ox)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (((r_ptr->flags2 & RF2_MULTIPLY) == 0) || (player_ptr->current_floor_ptr->num_repro >= MAX_REPRODUCTION)) {
         return false;
     }
@@ -464,18 +488,20 @@ bool decide_monster_multiplication(PlayerType *player_ptr, MONSTER_IDX m_idx, PO
  */
 bool cast_spell(PlayerType *player_ptr, MONSTER_IDX m_idx, bool aware)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if ((r_ptr->freq_spell == 0) || (randint1(100) > r_ptr->freq_spell)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &monster_from = floor.m_list[m_idx];
+    const auto &monrace = monster_from.get_monrace();
+    if ((monrace.freq_spell == 0) || (randint1(100) > monrace.freq_spell)) {
         return false;
     }
 
     bool counterattack = false;
-    if (m_ptr->target_y) {
-        MONSTER_IDX t_m_idx = player_ptr->current_floor_ptr->grid_array[m_ptr->target_y][m_ptr->target_x].m_idx;
-        const auto &target_ref = player_ptr->current_floor_ptr->m_list[t_m_idx];
-        const auto is_projectable = projectable(player_ptr, m_ptr->fy, m_ptr->fx, m_ptr->target_y, m_ptr->target_x);
-        if (t_m_idx && are_enemies(player_ptr, *m_ptr, target_ref) && is_projectable) {
+    if (monster_from.target_y) {
+        Pos2D pos(monster_from.target_y, monster_from.target_x);
+        const auto t_m_idx = floor.get_grid(pos).m_idx;
+        const auto &monster_to = floor.m_list[t_m_idx];
+        const auto is_projectable = projectable(player_ptr, monster_from.fy, monster_from.fx, monster_from.target_y, monster_from.target_x);
+        if (t_m_idx && monster_from.is_hostile_to_melee(monster_to) && is_projectable) {
             counterattack = true;
         }
     }
@@ -554,14 +580,13 @@ bool process_monster_fear(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MO
  */
 void process_monsters(PlayerType *player_ptr)
 {
-    old_race_flags tmp_flags;
-    old_race_flags *old_race_flags_ptr = init_old_race_flags(&tmp_flags);
+    const auto old_monrace_id = player_ptr->monster_race_idx;
+    old_race_flags tmp_flags(old_monrace_id);
+    old_race_flags *old_race_flags_ptr = &tmp_flags;
     player_ptr->current_floor_ptr->monster_noise = false;
-    MonsterRaceId old_monster_race_idx = player_ptr->monster_race_idx;
-    save_old_race_flags(player_ptr->monster_race_idx, old_race_flags_ptr);
     sweep_monster_process(player_ptr);
     hack_m_idx = 0;
-    if (!MonsterRace(player_ptr->monster_race_idx).is_valid() || (player_ptr->monster_race_idx != old_monster_race_idx)) {
+    if (!MonsterRace(player_ptr->monster_race_idx).is_valid() || (player_ptr->monster_race_idx != old_monrace_id)) {
         return;
     }
 
@@ -624,17 +649,18 @@ void sweep_monster_process(PlayerType *player_ptr)
  */
 bool decide_process_continue(PlayerType *player_ptr, MonsterEntity *m_ptr)
 {
-    MonsterRaceInfo *r_ptr;
-    r_ptr = &monraces_info[m_ptr->r_idx];
+    const auto &monrace = m_ptr->get_monrace();
     if (!player_ptr->no_flowed) {
         m_ptr->mflag2.reset(MonsterConstantFlagType::NOFLOW);
     }
 
-    if (m_ptr->cdis <= (m_ptr->is_pet() ? (r_ptr->aaf > MAX_PLAYER_SIGHT ? MAX_PLAYER_SIGHT : r_ptr->aaf) : r_ptr->aaf)) {
+    if (m_ptr->cdis <= (m_ptr->is_pet() ? (monrace.aaf > MAX_PLAYER_SIGHT ? MAX_PLAYER_SIGHT : monrace.aaf) : monrace.aaf)) {
         return true;
     }
 
-    if ((m_ptr->cdis <= MAX_PLAYER_SIGHT || player_ptr->phase_out) && (player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx) || has_aggravate(player_ptr))) {
+    auto should_continue = (m_ptr->cdis <= MAX_PLAYER_SIGHT) || AngbandSystem::get_instance().is_phase_out();
+    should_continue &= player_ptr->current_floor_ptr->has_los({ m_ptr->fy, m_ptr->fx }) || has_aggravate(player_ptr);
+    if (should_continue) {
         return true;
     }
 
index 076c5d4..87cd41e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index de1f5f1..d698ac5 100644 (file)
@@ -1,13 +1,10 @@
-#include "monster/monster-status-setter.h"
+#include "monster/monster-status-setter.h"
 #include "avatar/avatar.h"
 #include "cmd-visual/cmd-draw.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "dungeon/quest-completion-checker.h"
-#include "floor/cave.h"
 #include "monster-floor/monster-move.h"
 #include "monster-race/monster-kind-mask.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags7.h"
 #include "monster-race/race-indice-types.h"
 #include "monster/monster-describer.h"
-#include "monster/monster-info.h"
 #include "monster/monster-processor.h"
 #include "monster/monster-status.h" //!< @todo 相互依存. 後で何とかする.
 #include "monster/monster-util.h"
 #include "monster/smart-learn-types.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "view/display-messages.h"
 #include "world/world.h"
+#include <string>
 
 /*!
  * @brief モンスターをペットにする
@@ -38,39 +37,25 @@ void set_pet(PlayerType *player_ptr, MonsterEntity *m_ptr)
 {
     QuestCompletionChecker(player_ptr, m_ptr).complete();
     m_ptr->mflag2.set(MonsterConstantFlagType::PET);
-    if (monraces_info[m_ptr->r_idx].kind_flags.has_none_of(alignment_mask)) {
+    if (m_ptr->get_monrace().kind_flags.has_none_of(alignment_mask)) {
         m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
     }
 }
 
 /*!
- * @brief モンスターを敵に回す
- * Makes the monster hostile towards the player
- * @param m_ptr モンスター情報構造体の参照ポインタ
- */
-void set_hostile(PlayerType *player_ptr, MonsterEntity *m_ptr)
-{
-    if (player_ptr->phase_out) {
-        return;
-    }
-
-    m_ptr->mflag2.reset({ MonsterConstantFlagType::PET, MonsterConstantFlagType::FRIENDLY });
-}
-
-/*!
  * @brief モンスターを怒らせる
  * Anger the monster
  * @param m_ptr モンスター情報構造体の参照ポインタ
  */
 void anger_monster(PlayerType *player_ptr, MonsterEntity *m_ptr)
 {
-    if (player_ptr->phase_out || !m_ptr->is_friendly()) {
+    if (AngbandSystem::get_instance().is_phase_out() || !m_ptr->is_friendly()) {
         return;
     }
 
     const auto m_name = monster_desc(player_ptr, m_ptr, 0);
     msg_format(_("%s^は怒った!", "%s^ gets angry!"), m_name.data());
-    set_hostile(player_ptr, m_ptr);
+    m_ptr->set_hostile();
     chg_virtue(player_ptr, Virtue::INDIVIDUALISM, 1);
     chg_virtue(player_ptr, Virtue::HONOUR, -1);
     chg_virtue(player_ptr, Virtue::JUSTICE, -1);
@@ -123,18 +108,19 @@ bool set_monster_csleep(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
         return false;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (m_ptr->ml) {
         if (player_ptr->health_who == m_idx) {
-            player_ptr->redraw |= PR_HEALTH;
+            rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
         }
 
         if (player_ptr->riding == m_idx) {
-            player_ptr->redraw |= PR_UHEALTH;
+            rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
         }
     }
 
-    if (monraces_info[m_ptr->r_idx].brightness_flags.has_any_of(has_ld_mask)) {
-        player_ptr->update |= PU_MONSTER_LITE;
+    if (m_ptr->get_monrace().brightness_flags.has_any_of(has_ld_mask)) {
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 
     return true;
@@ -173,7 +159,7 @@ bool set_monster_fast(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
     }
 
     if ((player_ptr->riding == m_idx) && !player_ptr->leaving) {
-        player_ptr->update |= PU_BONUS;
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     }
 
     return true;
@@ -207,7 +193,7 @@ bool set_monster_slow(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
     }
 
     if ((player_ptr->riding == m_idx) && !player_ptr->leaving) {
-        player_ptr->update |= PU_BONUS;
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     }
 
     return true;
@@ -309,12 +295,13 @@ bool set_monster_monfear(PlayerType *player_ptr, MONSTER_IDX m_idx, int v)
     }
 
     if (m_ptr->ml) {
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
         if (player_ptr->health_who == m_idx) {
-            player_ptr->redraw |= PR_HEALTH;
+            rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
         }
 
         if (player_ptr->riding == m_idx) {
-            player_ptr->redraw |= PR_UHEALTH;
+            rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
         }
     }
 
@@ -358,12 +345,13 @@ bool set_monster_invulner(PlayerType *player_ptr, MONSTER_IDX m_idx, int v, bool
     }
 
     if (m_ptr->ml) {
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
         if (player_ptr->health_who == m_idx) {
-            player_ptr->redraw |= PR_HEALTH;
+            rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
         }
 
         if (player_ptr->riding == m_idx) {
-            player_ptr->redraw |= PR_UHEALTH;
+            rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
         }
     }
 
@@ -377,34 +365,35 @@ bool set_monster_invulner(PlayerType *player_ptr, MONSTER_IDX m_idx, int v, bool
  * @param who 時間停止を行う敵の種族番号
  * @param vs_player TRUEならば時間停止開始処理を行う
  * @return 時間停止が行われている状態ならばTRUEを返す
+ * @details monster_desc() は視認外のモンスターについて「何か」と返してくるので、この関数ではLOSや透明視等を判定する必要はない
  */
 bool set_monster_timewalk(PlayerType *player_ptr, int num, MonsterRaceId who, bool vs_player)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[hack_m_idx];
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto *m_ptr = &floor.m_list[hack_m_idx];
     if (w_ptr->timewalk_m_idx) {
         return false;
     }
 
     if (vs_player) {
         const auto m_name = monster_desc(player_ptr, m_ptr, 0);
-
-        concptr mes;
+        std::string mes;
         switch (who) {
         case MonsterRaceId::DIO:
-            mes = _("「『ザ・ワールド』! 時は止まった!」", "%s yells 'The World! Time has stopped!'");
+            mes = _("「『ザ・ワールド』! 時は止まった!」", format("%s yells 'The World! Time has stopped!'", m_name.data()));
             break;
         case MonsterRaceId::WONG:
-            mes = _("「時よ!」", "%s yells 'Time!'");
+            mes = _("「時よ!」", format("%s yells 'Time!'", m_name.data()));
             break;
         case MonsterRaceId::DIAVOLO:
-            mes = _("『キング・クリムゾン』!", "%s yells 'King Crison!'");
+            mes = _("『キング・クリムゾン』!", format("%s yells 'King Crison!'", m_name.data()));
             break;
         default:
-            mes = "hek!";
+            mes = format(_("%sは時を止めた!", "%s stops the time!"), m_name.data());
             break;
         }
 
-        msg_format(mes, m_name.data());
+        msg_print(mes);
         msg_print(nullptr);
     }
 
@@ -426,12 +415,19 @@ bool set_monster_timewalk(PlayerType *player_ptr, int num, MonsterRaceId who, bo
         }
     }
 
-    player_ptr->redraw |= PR_MAP;
-    player_ptr->update |= PU_MONSTER_STATUSES;
-    player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags);
     w_ptr->timewalk_m_idx = 0;
-    if (vs_player || (player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx) && projectable(player_ptr, player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx))) {
-        concptr mes;
+    auto should_output_message = floor.has_los({ m_ptr->fy, m_ptr->fx });
+    should_output_message &= projectable(player_ptr, player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx);
+    if (vs_player || should_output_message) {
+        std::string mes;
         switch (who) {
         case MonsterRaceId::DIAVOLO:
             mes = _("これが我が『キング・クリムゾン』の能力! 『時間を消し去って』飛び越えさせた…!!",
index 6090b5d..99e7dc0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -7,7 +7,6 @@ class MonsterEntity;
 class PlayerType;
 void set_friendly(MonsterEntity *m_ptr);
 void set_pet(PlayerType *player_ptr, MonsterEntity *m_ptr);
-void set_hostile(PlayerType *player_ptr, MonsterEntity *m_ptr);
 void anger_monster(PlayerType *player_ptr, MonsterEntity *m_ptr);
 bool set_monster_csleep(PlayerType *player_ptr, MONSTER_IDX m_idx, int v);
 bool set_monster_fast(PlayerType *player_ptr, MONSTER_IDX m_idx, int v);
index 1c33dc6..dfed6d7 100644 (file)
@@ -1,8 +1,6 @@
-#include "monster/monster-status.h"
+#include "monster/monster-status.h"
 #include "autopick/autopick-pref-processor.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
-#include "floor/cave.h"
 #include "floor/geometry.h"
 #include "game-option/birth-options.h"
 #include "game-option/text-display-options.h"
 #include "monster/monster-list.h"
 #include "monster/monster-status-setter.h" //!< @todo 相互依存. 後で何とかする.
 #include "monster/monster-update.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/player-hallucination.h"
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include "world/world.h"
-
 #if JP
 #else
 #include "monster/monster-description-types.h"
@@ -45,7 +44,7 @@ static uint32_t csleep_noise;
 bool monster_is_powerful(FloorType *floor_ptr, MONSTER_IDX m_idx)
 {
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     return any_bits(r_ptr->flags2, RF2_POWERFUL);
 }
 
@@ -57,7 +56,7 @@ bool monster_is_powerful(FloorType *floor_ptr, MONSTER_IDX m_idx)
 DEPTH monster_level_idx(FloorType *floor_ptr, MONSTER_IDX m_idx)
 {
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     return (r_ptr->level >= 1) ? r_ptr->level : 1;
 }
 
@@ -73,7 +72,7 @@ DEPTH monster_level_idx(FloorType *floor_ptr, MONSTER_IDX m_idx)
  */
 int mon_damage_mod(PlayerType *player_ptr, MonsterEntity *m_ptr, int dam, bool is_psy_spear)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL) && dam > 0) {
         dam /= 100;
         if ((dam == 0) && one_in_(3)) {
@@ -164,10 +163,11 @@ void mproc_init(FloorType *floor_ptr)
  */
 static void process_monsters_mtimed_aux(PlayerType *player_ptr, MONSTER_IDX m_idx, int mtimed_idx)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto *m_ptr = &floor.m_list[m_idx];
     switch (mtimed_idx) {
     case MTIMED_CSLEEP: {
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
         auto is_wakeup = false;
         if (m_ptr->cdis < MAX_MONSTER_SENSING) {
             /* Handle "sensing radius" */
@@ -176,7 +176,7 @@ static void process_monsters_mtimed_aux(PlayerType *player_ptr, MONSTER_IDX m_id
             }
 
             /* Handle "sight" and "aggravation" */
-            else if ((m_ptr->cdis <= MAX_PLAYER_SIGHT) && (player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx))) {
+            else if ((m_ptr->cdis <= MAX_PLAYER_SIGHT) && floor.has_los({ m_ptr->fy, m_ptr->fx })) {
                 is_wakeup = true;
             }
         }
@@ -261,7 +261,7 @@ static void process_monsters_mtimed_aux(PlayerType *player_ptr, MONSTER_IDX m_id
         break;
 
     case MTIMED_STUNNED: {
-        int rlev = monraces_info[m_ptr->r_idx].level;
+        int rlev = m_ptr->get_monrace().level;
 
         /* Recover from stun */
         if (set_monster_stunned(player_ptr, m_idx, (randint0(10000) <= rlev * rlev) ? 0 : (m_ptr->get_remaining_stun() - 1))) {
@@ -277,7 +277,7 @@ static void process_monsters_mtimed_aux(PlayerType *player_ptr, MONSTER_IDX m_id
 
     case MTIMED_CONFUSED: {
         /* Reduce the confusion */
-        if (!set_monster_confused(player_ptr, m_idx, m_ptr->get_remaining_confusion() - randint1(monraces_info[m_ptr->r_idx].level / 20 + 1))) {
+        if (!set_monster_confused(player_ptr, m_idx, m_ptr->get_remaining_confusion() - randint1(m_ptr->get_monrace().level / 20 + 1))) {
             break;
         }
 
@@ -292,7 +292,7 @@ static void process_monsters_mtimed_aux(PlayerType *player_ptr, MONSTER_IDX m_id
 
     case MTIMED_MONFEAR: {
         /* Reduce the fear */
-        if (!set_monster_monfear(player_ptr, m_idx, m_ptr->get_remaining_fear() - randint1(monraces_info[m_ptr->r_idx].level / 20 + 1))) {
+        if (!set_monster_monfear(player_ptr, m_idx, m_ptr->get_remaining_fear() - randint1(m_ptr->get_monrace().level / 20 + 1))) {
             break;
         }
 
@@ -401,10 +401,10 @@ void monster_gain_exp(PlayerType *player_ptr, MONSTER_IDX m_idx, MonsterRaceId s
         return;
     }
 
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     auto *s_ptr = &monraces_info[s_idx];
 
-    if (player_ptr->phase_out || (r_ptr->next_exp == 0)) {
+    if (AngbandSystem::get_instance().is_phase_out() || (r_ptr->next_exp == 0)) {
         return;
     }
 
@@ -422,9 +422,10 @@ void monster_gain_exp(PlayerType *player_ptr, MONSTER_IDX m_idx, MonsterRaceId s
         return;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (m_ptr->exp < r_ptr->next_exp) {
         if (m_idx == player_ptr->riding) {
-            player_ptr->update |= PU_BONUS;
+            rfu.set_flag(StatusRecalculatingFlag::BONUS);
         }
 
         return;
@@ -436,16 +437,16 @@ void monster_gain_exp(PlayerType *player_ptr, MONSTER_IDX m_idx, MonsterRaceId s
     auto old_sub_align = m_ptr->sub_align;
 
     /* Hack -- Reduce the racial counter of previous monster */
-    m_ptr->get_real_r_ref().cur_num--;
+    m_ptr->get_real_monrace().cur_num--;
 
     const auto m_name = monster_desc(player_ptr, m_ptr, 0);
     m_ptr->r_idx = r_ptr->next_r_idx;
 
     /* Count the monsters on the level */
-    m_ptr->get_real_r_ref().cur_num++;
+    m_ptr->get_real_monrace().cur_num++;
 
     m_ptr->ap_r_idx = m_ptr->r_idx;
-    r_ptr = &monraces_info[m_ptr->r_idx];
+    r_ptr = &m_ptr->get_monrace();
 
     m_ptr->max_maxhp = any_bits(r_ptr->flags1, RF1_FORCE_MAXHP) ? maxroll(r_ptr->hdice, r_ptr->hside) : damroll(r_ptr->hdice, r_ptr->hside);
     if (ironman_nightmare) {
@@ -485,7 +486,7 @@ void monster_gain_exp(PlayerType *player_ptr, MONSTER_IDX m_idx, MonsterRaceId s
                 do {
                     auto r_idx = MonsterRace::pick_one_at_random();
                     hallucinated_race = &monraces_info[r_idx];
-                } while (hallucinated_race->name.empty() || hallucinated_race->kind_flags.has(MonsterKindType::UNIQUE));
+                } while (hallucinated_race->kind_flags.has(MonsterKindType::UNIQUE));
                 auto mes_evolution = _("%sは%sに進化した。", "%s^ evolved into %s.");
                 auto mes_degeneration = _("%sは%sに退化した。", "%s^ degenerated into %s.");
                 auto mes = randint0(2) == 0 ? mes_evolution : mes_degeneration;
@@ -507,6 +508,6 @@ void monster_gain_exp(PlayerType *player_ptr, MONSTER_IDX m_idx, MonsterRaceId s
     lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
 
     if (m_idx == player_ptr->riding) {
-        player_ptr->update |= PU_BONUS;
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
     }
 }
index bc38adf..6d08d86 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f11a7aa..5ef4f7f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum monster_timed_effect_type {
     MTIMED_CSLEEP = 0, /* Monster is sleeping */
index b46a26b..e49e01e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター情報のアップデート処理
  * @date 2020/03/08
  * @author Hourier
@@ -6,11 +6,8 @@
 
 #include "monster/monster-update.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "dungeon/dungeon-flag-types.h"
-#include "floor/cave.h"
 #include "floor/geometry.h"
 #include "game-option/birth-options.h"
 #include "game-option/disturbance-options.h"
 #include "player/player-status-flags.h"
 #include "player/special-defense-types.h"
 #include "status/element-resistance.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/player-hallucination.h"
@@ -99,20 +98,36 @@ bool update_riding_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, M
 }
 
 /*!
- * @brief updateフィールドを更新する
- * @param player_ptr プレイヤーへの参照ポインタ
+ * @brief マップ及びミニマップの更新フラグをセットする
  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
  */
-void update_player_type(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterRaceInfo *r_ptr)
+void update_map_flags(turn_flags *turn_flags_ptr)
 {
-    auto except_has_lite = EnumClassFlagGroup<MonsterBrightnessType>(self_ld_mask).set({ MonsterBrightnessType::HAS_DARK_1, MonsterBrightnessType::HAS_DARK_2 });
-    if (turn_flags_ptr->do_view) {
-        player_ptr->update |= PU_FLOW;
-        player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    if (!turn_flags_ptr->do_view) {
+        return;
     }
 
-    if (turn_flags_ptr->do_move && (r_ptr->brightness_flags.has_any_of(except_has_lite) || (r_ptr->brightness_flags.has_any_of({ MonsterBrightnessType::HAS_LITE_1, MonsterBrightnessType::HAS_LITE_2 }) && !player_ptr->phase_out))) {
-        player_ptr->update |= PU_MONSTER_LITE;
+    rfu.set_flag(StatusRecalculatingFlag::FLOW);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags);
+}
+
+/*!
+ * @brief モンスターの光源フラグに基づいてフロアの光源状態更新フラグをセットする
+ * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
+ * @param r_ptr モンスター種族への参照ポインタ
+ */
+void update_lite_flags(turn_flags *turn_flags_ptr, MonsterRaceInfo *r_ptr)
+{
+    using Mbt = MonsterBrightnessType;
+    const auto has_lite = r_ptr->brightness_flags.has_any_of({ Mbt::HAS_LITE_1, Mbt::HAS_LITE_2 });
+    const auto except_has_lite = EnumClassFlagGroup<Mbt>(self_ld_mask).set({ Mbt::HAS_DARK_1, Mbt::HAS_DARK_2 });
+    if (turn_flags_ptr->do_move && (r_ptr->brightness_flags.has_any_of(except_has_lite) || (has_lite && !AngbandSystem::get_instance().is_phase_out()))) {
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 }
 
@@ -124,7 +139,7 @@ void update_player_type(PlayerType *player_ptr, turn_flags *turn_flags_ptr, Mons
  */
 void update_monster_race_flags(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (!is_original_ap_and_seen(player_ptr, m_ptr)) {
         return;
     }
@@ -175,19 +190,20 @@ void update_player_window(PlayerType *player_ptr, old_race_flags *old_race_flags
         (old_race_flags_ptr->old_r_blows3 != r_ptr->r_blows[3]) || (old_race_flags_ptr->old_r_cast_spell != r_ptr->r_cast_spell) ||
         (old_race_flags_ptr->old_r_behavior_flags != r_ptr->r_behavior_flags) || (old_race_flags_ptr->old_r_kind_flags != r_ptr->r_kind_flags) ||
         (old_race_flags_ptr->old_r_drop_flags != r_ptr->r_drop_flags) || (old_race_flags_ptr->old_r_feature_flags != r_ptr->r_feature_flags)) {
-        player_ptr->window_flags |= PW_MONSTER_LORE;
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
     }
 }
 
 static um_type *initialize_um_type(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx, bool full)
 {
-    um_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
+    auto &floor = *player_ptr->current_floor_ptr;
+    um_ptr->m_ptr = &floor.m_list[m_idx];
     um_ptr->do_disturb = disturb_move;
     um_ptr->fy = um_ptr->m_ptr->fy;
     um_ptr->fx = um_ptr->m_ptr->fx;
     um_ptr->flag = false;
     um_ptr->easy = false;
-    um_ptr->in_darkness = dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS) && !player_ptr->see_nocto;
+    um_ptr->in_darkness = floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS) && !player_ptr->see_nocto;
     um_ptr->full = full;
     return um_ptr;
 }
@@ -215,11 +231,11 @@ static POSITION decide_updated_distance(PlayerType *player_ptr, um_type *um_ptr)
 
 static void update_smart_stupid_flags(MonsterRaceInfo *r_ptr)
 {
-    if (r_ptr->r_behavior_flags.has(MonsterBehaviorType::SMART)) {
+    if (r_ptr->behavior_flags.has(MonsterBehaviorType::SMART)) {
         r_ptr->r_behavior_flags.set(MonsterBehaviorType::SMART);
     }
 
-    if (r_ptr->r_behavior_flags.has(MonsterBehaviorType::STUPID)) {
+    if (r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) {
         r_ptr->r_behavior_flags.set(MonsterBehaviorType::STUPID);
     }
 }
@@ -234,7 +250,7 @@ static void update_smart_stupid_flags(MonsterRaceInfo *r_ptr)
 static bool update_weird_telepathy(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx)
 {
     auto *m_ptr = um_ptr->m_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if ((r_ptr->flags2 & RF2_WEIRD_MIND) == 0) {
         return false;
     }
@@ -256,7 +272,7 @@ static bool update_weird_telepathy(PlayerType *player_ptr, um_type *um_ptr, MONS
 static void update_telepathy_sight(PlayerType *player_ptr, um_type *um_ptr, MONSTER_IDX m_idx)
 {
     auto *m_ptr = um_ptr->m_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU)) {
         um_ptr->flag = true;
         um_ptr->m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
@@ -294,7 +310,7 @@ static void update_telepathy_sight(PlayerType *player_ptr, um_type *um_ptr, MONS
 static void update_specific_race_telepathy(PlayerType *player_ptr, um_type *um_ptr)
 {
     auto *m_ptr = um_ptr->m_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     auto is_hallucinated = player_ptr->effects()->hallucination()->is_hallucinated();
     if ((player_ptr->esp_animal) && r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
         um_ptr->flag = true;
@@ -376,7 +392,7 @@ static void update_specific_race_telepathy(PlayerType *player_ptr, um_type *um_p
         }
     }
 
-    if ((player_ptr->esp_nonliving) && (r_ptr->kind_flags.has(MonsterKindType::NONLIVING) && r_ptr->kind_flags.has_none_of({ MonsterKindType::DEMON, MonsterKindType::UNDEAD }))) {
+    if ((player_ptr->esp_nonliving) && r_ptr->kind_flags.has(MonsterKindType::NONLIVING) && r_ptr->kind_flags.has_none_of({ MonsterKindType::DEMON, MonsterKindType::UNDEAD })) {
         um_ptr->flag = true;
         m_ptr->mflag.set(MonsterTemporaryFlagType::ESP);
         if (m_ptr->is_original_ap() && !is_hallucinated) {
@@ -399,7 +415,7 @@ static bool check_cold_blood(PlayerType *player_ptr, um_type *um_ptr, const POSI
         return false;
     }
 
-    auto *r_ptr = &monraces_info[um_ptr->m_ptr->r_idx];
+    auto *r_ptr = &um_ptr->m_ptr->get_monrace();
     if (any_bits(r_ptr->flags2, RF2_COLD_BLOOD) && r_ptr->aura_flags.has_not(MonsterAuraType::FIRE)) {
         return false;
     }
@@ -415,7 +431,7 @@ static bool check_invisible(PlayerType *player_ptr, um_type *um_ptr)
         return false;
     }
 
-    auto *r_ptr = &monraces_info[um_ptr->m_ptr->r_idx];
+    auto *r_ptr = &um_ptr->m_ptr->get_monrace();
     if (r_ptr->flags2 & RF2_INVISIBLE) {
         if (player_ptr->see_inv) {
             um_ptr->easy = true;
@@ -438,7 +454,7 @@ static void decide_sight_invisible_monster(PlayerType *player_ptr, um_type *um_p
 {
     POSITION distance = decide_updated_distance(player_ptr, um_ptr);
     auto *m_ptr = um_ptr->m_ptr;
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     m_ptr->mflag.reset(MonsterTemporaryFlagType::ESP);
 
@@ -451,11 +467,11 @@ static void decide_sight_invisible_monster(PlayerType *player_ptr, um_type *um_p
         update_specific_race_telepathy(player_ptr, um_ptr);
     }
 
-    if (!player_has_los_bold(player_ptr, um_ptr->fy, um_ptr->fx) || player_ptr->effects()->blindness()->is_blind()) {
+    if (!player_ptr->current_floor_ptr->has_los({ um_ptr->fy, um_ptr->fx }) || player_ptr->effects()->blindness()->is_blind()) {
         return;
     }
 
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     if (sniper_data && (sniper_data->concent >= CONCENT_RADAR_THRESHOLD)) {
         um_ptr->easy = true;
         um_ptr->flag = true;
@@ -494,16 +510,17 @@ static void update_invisible_monster(PlayerType *player_ptr, um_type *um_ptr, MO
     m_ptr->ml = true;
     lite_spot(player_ptr, um_ptr->fy, um_ptr->fx);
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == m_idx) {
-        player_ptr->redraw |= PR_HEALTH;
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (player_ptr->riding == m_idx) {
-        player_ptr->redraw |= PR_UHEALTH;
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     if (!player_ptr->effects()->hallucination()->is_hallucinated()) {
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
         if ((m_ptr->ap_r_idx == MonsterRaceId::KAGE) && (monraces_info[MonsterRaceId::KAGE].r_sights < MAX_SHORT)) {
             monraces_info[MonsterRaceId::KAGE].r_sights++;
         } else if (m_ptr->is_original_ap() && (r_ptr->r_sights < MAX_SHORT)) {
@@ -511,7 +528,7 @@ static void update_invisible_monster(PlayerType *player_ptr, um_type *um_ptr, MO
         }
     }
 
-    if (w_ptr->is_loading_now && w_ptr->character_dungeon && !player_ptr->phase_out && monraces_info[m_ptr->ap_r_idx].flags2 & RF2_ELDRITCH_HORROR) {
+    if (w_ptr->is_loading_now && w_ptr->character_dungeon && !AngbandSystem::get_instance().is_phase_out() && m_ptr->get_appearance_monrace().flags2 & RF2_ELDRITCH_HORROR) {
         m_ptr->mflag.set(MonsterTemporaryFlagType::SANITY_BLAST);
     }
 
@@ -533,12 +550,13 @@ static void update_visible_monster(PlayerType *player_ptr, um_type *um_ptr, MONS
     um_ptr->m_ptr->ml = false;
     lite_spot(player_ptr, um_ptr->fy, um_ptr->fx);
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == m_idx) {
-        player_ptr->redraw |= PR_HEALTH;
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
 
     if (player_ptr->riding == m_idx) {
-        player_ptr->redraw |= PR_UHEALTH;
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     if (um_ptr->do_disturb && (disturb_pets || um_ptr->m_ptr->is_hostile())) {
@@ -572,7 +590,7 @@ void update_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool full)
     um_type tmp_um;
     um_type *um_ptr = initialize_um_type(player_ptr, &tmp_um, m_idx, full);
     if (disturb_high) {
-        MonsterRaceInfo *ap_r_ptr = &monraces_info[um_ptr->m_ptr->ap_r_idx];
+        auto *ap_r_ptr = &um_ptr->m_ptr->get_appearance_monrace();
         if (ap_r_ptr->r_tkills && ap_r_ptr->level >= player_ptr->lev) {
             um_ptr->do_disturb = true;
         }
@@ -626,7 +644,7 @@ void update_monsters(PlayerType *player_ptr, bool full)
 void update_smart_learn(PlayerType *player_ptr, MONSTER_IDX m_idx, int what)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (!smart_learn || (r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) || ((r_ptr->behavior_flags.has_not(MonsterBehaviorType::SMART)) && (randint0(100) < 50))) {
         return;
     }
index 52eb90d..f8f9e08 100644 (file)
@@ -1,15 +1,16 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 class MonsterRaceInfo;
 class MonsterEntity;
 struct old_race_flags;
-;
+
 class PlayerType;
 struct turn_flags;
 bool update_riding_monster(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, POSITION oy, POSITION ox, POSITION ny, POSITION nx);
-void update_player_type(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterRaceInfo *r_ptr);
+void update_map_flags(turn_flags *turn_flags_ptr);
+void update_lite_flags(turn_flags *turn_flags_ptr, MonsterRaceInfo *r_ptr);
 void update_monster_race_flags(PlayerType *player_ptr, turn_flags *turn_flags_ptr, MonsterEntity *m_ptr);
 void update_player_window(PlayerType *player_ptr, old_race_flags *old_race_flags_ptr);
 void update_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool full);
index d736937..6a8c9f9 100644 (file)
@@ -1,4 +1,4 @@
-#include "monster/monster-util.h"
+#include "monster/monster-util.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h"
 #include "floor/wild.h"
@@ -12,6 +12,7 @@
 #include "monster-race/race-indice-types.h"
 #include "spell/summon-types.h"
 #include "system/alloc-entries.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -75,13 +76,13 @@ static bool is_possible_monster_or(const EnumClassFlagGroup<T> &r_flags, const E
 
 /*!
  * @brief 指定されたモンスター種族がダンジョンの制限にかかるかどうかをチェックする / Some dungeon types restrict the possible monsters.
- * @param player_ptr プレイヤーへの参照ポインタ
+ * @param floor_ptr フロアへの参照ポインタ
  * @param r_idx チェックするモンスター種族ID
  * @return 召喚条件が一致するならtrue / Return TRUE is the monster is OK and FALSE otherwise
  */
-static bool restrict_monster_to_dungeon(PlayerType *player_ptr, MonsterRaceId r_idx)
+static bool restrict_monster_to_dungeon(const FloorType *floor_ptr, MonsterRaceId r_idx)
 {
-    const auto *d_ptr = &dungeons_info[player_ptr->dungeon_idx];
+    const auto *d_ptr = &floor_ptr->get_dungeon_definition();
     const auto *r_ptr = &monraces_info[r_idx];
     if (d_ptr->flags.has(DungeonFeatureType::CHAMELEON)) {
         if (chameleon_change_m_idx) {
@@ -105,7 +106,6 @@ static bool restrict_monster_to_dungeon(PlayerType *player_ptr, MonsterRaceId r_
         }
     }
 
-    auto *floor_ptr = player_ptr->current_floor_ptr;
     if (d_ptr->flags.has(DungeonFeatureType::BEGINNER)) {
         if (r_ptr->level > floor_ptr->dun_level) {
             return false;
@@ -138,6 +138,8 @@ static bool restrict_monster_to_dungeon(PlayerType *player_ptr, MonsterRaceId r_
             is_possible_monster_and(r_ptr->population_flags, d_ptr->mon_population_flags),
             is_possible_monster_and(r_ptr->speak_flags, d_ptr->mon_speak_flags),
             is_possible_monster_and(r_ptr->brightness_flags, d_ptr->mon_brightness_flags),
+            is_male(d_ptr->mon_sex) ? is_male(r_ptr->sex) : true,
+            is_female(d_ptr->mon_sex) ? is_female(r_ptr->sex) : true,
         };
 
         auto result = std::all_of(is_possible.begin(), is_possible.end(), [](const auto &v) { return v; });
@@ -163,6 +165,8 @@ static bool restrict_monster_to_dungeon(PlayerType *player_ptr, MonsterRaceId r_
             is_possible_monster_or(r_ptr->population_flags, d_ptr->mon_population_flags),
             is_possible_monster_or(r_ptr->speak_flags, d_ptr->mon_speak_flags),
             is_possible_monster_or(r_ptr->brightness_flags, d_ptr->mon_brightness_flags),
+            is_male(d_ptr->mon_sex) ? is_male(r_ptr->sex) : true,
+            is_female(d_ptr->mon_sex) ? is_female(r_ptr->sex) : true,
         };
 
         auto result = std::any_of(is_possible.begin(), is_possible.end(), [](const auto &v) { return v; });
@@ -182,7 +186,8 @@ static bool restrict_monster_to_dungeon(PlayerType *player_ptr, MonsterRaceId r_
  */
 monsterrace_hook_type get_monster_hook(PlayerType *player_ptr)
 {
-    if ((player_ptr->current_floor_ptr->dun_level > 0) || (inside_quest(player_ptr->current_floor_ptr->quest_number))) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if ((floor.dun_level > 0) || (floor.is_in_quest())) {
         return (monsterrace_hook_type)mon_hook_dungeon;
     }
 
@@ -217,12 +222,13 @@ monsterrace_hook_type get_monster_hook(PlayerType *player_ptr)
  */
 monsterrace_hook_type get_monster_hook2(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    auto *f_ptr = &terrains_info[player_ptr->current_floor_ptr->grid_array[y][x].feat];
-    if (f_ptr->flags.has(TerrainCharacteristics::WATER)) {
-        return f_ptr->flags.has(TerrainCharacteristics::DEEP) ? (monsterrace_hook_type)mon_hook_deep_water : (monsterrace_hook_type)mon_hook_shallow_water;
+    const Pos2D pos(y, x);
+    const auto &terrain = player_ptr->current_floor_ptr->get_grid(pos).get_terrain();
+    if (terrain.flags.has(TerrainCharacteristics::WATER)) {
+        return terrain.flags.has(TerrainCharacteristics::DEEP) ? (monsterrace_hook_type)mon_hook_deep_water : (monsterrace_hook_type)mon_hook_shallow_water;
     }
 
-    if (f_ptr->flags.has(TerrainCharacteristics::LAVA)) {
+    if (terrain.flags.has(TerrainCharacteristics::LAVA)) {
         return (monsterrace_hook_type)mon_hook_lava;
     }
 
@@ -251,6 +257,7 @@ static errr do_get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_t
     int prob2_total = 0; // 重みの総和
 
     // モンスター生成テーブルの各要素について重みを修正する。
+    const auto &system = AngbandSystem::get_instance();
     for (auto i = 0U; i < alloc_race_table.size(); i++) {
         alloc_entry *const entry = &alloc_race_table[i];
         const auto entry_r_idx = i2enum<MonsterRaceId>(entry->index);
@@ -271,7 +278,7 @@ static errr do_get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_t
         }
 
         // 原則生成禁止するものたち(フェイズアウト状態 / カメレオンの変身先 / ダンジョンの主召喚 は例外)。
-        if (!player_ptr->phase_out && !chameleon_change_m_idx && summon_specific_type != SUMMON_GUARDIANS) {
+        if (!system.is_phase_out() && !chameleon_change_m_idx && summon_specific_type != SUMMON_GUARDIANS) {
             // クエストモンスターは生成禁止。
             if (r_ptr->flags1 & RF1_QUESTOR) {
                 continue;
@@ -288,7 +295,7 @@ static errr do_get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_t
             }
 
             // クエスト内でRES_ALLの生成を禁止する (殲滅系クエストの詰み防止)
-            if (inside_quest(player_ptr->current_floor_ptr->quest_number) && r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
+            if (player_ptr->current_floor_ptr->is_in_quest() && r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
                 continue;
             }
         }
@@ -303,13 +310,13 @@ static errr do_get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_t
             //   * フェイズアウト状態でない
             //   * 1階かそれより深いところにいる
             //   * ランダムクエスト中でない
-            const bool in_random_quest = inside_quest(floor_ptr->quest_number) && !QuestType::is_fixed(floor_ptr->quest_number);
-            const bool cond = !player_ptr->phase_out && floor_ptr->dun_level > 0 && !in_random_quest;
+            const bool in_random_quest = floor_ptr->is_in_quest() && !QuestType::is_fixed(floor_ptr->quest_number);
+            const bool cond = !system.is_phase_out() && floor_ptr->dun_level > 0 && !in_random_quest;
 
-            if (cond && !restrict_monster_to_dungeon(player_ptr, entry_r_idx)) {
+            if (cond && !restrict_monster_to_dungeon(floor_ptr, entry_r_idx)) {
                 // ダンジョンによる制約に掛かった場合、重みを special_div/64 倍する。
                 // 丸めは確率的に行う。
-                const int numer = entry->prob2 * dungeons_info[player_ptr->dungeon_idx].special_div;
+                const int numer = entry->prob2 * floor_ptr->get_dungeon_definition().special_div;
                 const int q = numer / 64;
                 const int r = numer % 64;
                 entry->prob2 = (PROB)(randint0(64) < r ? q + 1 : q);
index 07e237e..e2459a2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 51ceee0..294b284 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class MonsterSmartLearnType {
     RES_ACID = 0, /*!< モンスターの学習フラグ: プレイヤーに酸耐性あり */
index 61a83da..5a2f54d 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターのスペル振り分け処理 / Spell launch by a monster
  * @date 2014/07/14
  * @author Habu
@@ -83,6 +83,7 @@ static MonsterSpellResult monspell_to_player_impl(PlayerType *player_ptr, Monste
     case MonsterAbilityType::BA_DARK:
     case MonsterAbilityType::BA_VOID:
     case MonsterAbilityType::BA_ABYSS:
+    case MonsterAbilityType::BA_METEOR:
          return MSpellBall(player_ptr, m_idx, ms_type, 4, MONSTER_TO_PLAYER).shoot(y, x);
 
     case MonsterAbilityType::DRAIN_MANA: return spell_RF5_DRAIN_MANA(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER);  /* RF5_DRAIN_MANA */
@@ -107,6 +108,8 @@ static MonsterSpellResult monspell_to_player_impl(PlayerType *player_ptr, Monste
     case MonsterAbilityType::BO_ICEE:
     case MonsterAbilityType::BO_VOID:
     case MonsterAbilityType::BO_ABYSS:
+    case MonsterAbilityType::BO_METEOR:
+    case MonsterAbilityType::BO_LITE:
     case MonsterAbilityType::MISSILE: 
         return MSpellBolt(player_ptr, m_idx, ms_type, MONSTER_TO_PLAYER).shoot(y,x);
 
@@ -147,6 +150,7 @@ static MonsterSpellResult monspell_to_player_impl(PlayerType *player_ptr, Monste
     case MonsterAbilityType::S_HI_DRAGON: return spell_RF6_S_HI_DRAGON(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_HI_DRAGON */
     case MonsterAbilityType::S_AMBERITES: return spell_RF6_S_AMBERITES(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_AMBERITES */
     case MonsterAbilityType::S_UNIQUE: return spell_RF6_S_UNIQUE(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_UNIQUE */
+    case MonsterAbilityType::S_DEAD_UNIQUE: return spell_RF6_S_DEAD_UNIQUE(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_DEAD_UNIQUE */
     default: break;
     }
     // clang-format on
@@ -214,6 +218,7 @@ static MonsterSpellResult monspell_to_monster_impl(
     case MonsterAbilityType::BA_DARK:
     case MonsterAbilityType::BA_VOID:
     case MonsterAbilityType::BA_ABYSS:
+    case MonsterAbilityType::BA_METEOR:
          return MSpellBall(player_ptr, m_idx, t_idx, ms_type, 4, MONSTER_TO_MONSTER).shoot(y, x);
 
     case MonsterAbilityType::DRAIN_MANA: return spell_RF5_DRAIN_MANA(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_DRAIN_MANA */
@@ -238,6 +243,8 @@ static MonsterSpellResult monspell_to_monster_impl(
     case MonsterAbilityType::BO_ICEE:
     case MonsterAbilityType::BO_VOID:
     case MonsterAbilityType::BO_ABYSS:
+    case MonsterAbilityType::BO_METEOR:
+    case MonsterAbilityType::BO_LITE:
     case MonsterAbilityType::MISSILE: 
          return MSpellBolt(player_ptr, m_idx, t_idx, ms_type, MONSTER_TO_MONSTER).shoot(y, x);
 
@@ -278,6 +285,7 @@ static MonsterSpellResult monspell_to_monster_impl(
     case MonsterAbilityType::S_HI_DRAGON: return spell_RF6_S_HI_DRAGON(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_HI_DRAGON */
     case MonsterAbilityType::S_AMBERITES: return spell_RF6_S_AMBERITES(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_AMBERITES */
     case MonsterAbilityType::S_UNIQUE: return spell_RF6_S_UNIQUE(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_UNIQUE */
+    case MonsterAbilityType::S_DEAD_UNIQUE: return spell_RF6_S_DEAD_UNIQUE(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_DEAD_UNIQUE */
     default: break;
     }
     // clang-format on
index dc0306b..e86d885 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3e6a6d3..1483e7f 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/element-resistance-checker.h"
+#include "mspell/element-resistance-checker.h"
 #include "game-option/birth-options.h"
 #include "monster-race/race-ability-flags.h"
 #include "monster/smart-learn-types.h"
 void add_cheat_remove_flags_element(PlayerType *player_ptr, msr_type *msr_ptr)
 {
     if (has_resist_acid(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_ACID);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_ACID);
     }
 
     if (is_oppose_acid(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::OPP_ACID);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::OPP_ACID);
     }
 
     if (has_immune_acid(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::IMM_ACID);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::IMM_ACID);
     }
 
     if (has_resist_elec(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_ELEC);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_ELEC);
     }
 
     if (is_oppose_elec(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::OPP_ELEC);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::OPP_ELEC);
     }
 
     if (has_immune_elec(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::IMM_ELEC);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::IMM_ELEC);
     }
 
     if (has_resist_fire(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_FIRE);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_FIRE);
     }
 
     if (is_oppose_fire(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::OPP_FIRE);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::OPP_FIRE);
     }
 
     if (has_immune_fire(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::IMM_FIRE);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::IMM_FIRE);
     }
 
     if (has_resist_cold(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_COLD);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_COLD);
     }
 
     if (is_oppose_cold(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::OPP_COLD);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::OPP_COLD);
     }
 
     if (has_immune_cold(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::IMM_COLD);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::IMM_COLD);
     }
 
     if (has_resist_pois(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_POIS);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_POIS);
     }
 
     if (is_oppose_pois(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::OPP_POIS);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::OPP_POIS);
     }
 }
 
 static void check_acid_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has(MonsterSmartLearnType::IMM_ACID)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::IMM_ACID)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::BR_ACID);
         msr_ptr->ability_flags.reset(MonsterAbilityType::BA_ACID);
         msr_ptr->ability_flags.reset(MonsterAbilityType::BO_ACID);
         return;
     }
 
-    if (msr_ptr->smart.has_all_of({ MonsterSmartLearnType::OPP_ACID, MonsterSmartLearnType::RES_ACID })) {
+    if (msr_ptr->smart_flags.has_all_of({ MonsterSmartLearnType::OPP_ACID, MonsterSmartLearnType::RES_ACID })) {
         if (int_outof(msr_ptr->r_ptr, 80)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_ACID);
         }
@@ -92,7 +92,7 @@ static void check_acid_resistance(msr_type *msr_ptr)
         return;
     }
 
-    if (msr_ptr->smart.has_any_of({ MonsterSmartLearnType::OPP_ACID, MonsterSmartLearnType::RES_ACID })) {
+    if (msr_ptr->smart_flags.has_any_of({ MonsterSmartLearnType::OPP_ACID, MonsterSmartLearnType::RES_ACID })) {
         if (int_outof(msr_ptr->r_ptr, 30)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_ACID);
         }
@@ -109,14 +109,14 @@ static void check_acid_resistance(msr_type *msr_ptr)
 
 static void check_elec_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has(MonsterSmartLearnType::IMM_ELEC)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::IMM_ELEC)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::BR_ELEC);
         msr_ptr->ability_flags.reset(MonsterAbilityType::BA_ELEC);
         msr_ptr->ability_flags.reset(MonsterAbilityType::BO_ELEC);
         return;
     }
 
-    if (msr_ptr->smart.has_all_of({ MonsterSmartLearnType::OPP_ELEC, MonsterSmartLearnType::RES_ELEC })) {
+    if (msr_ptr->smart_flags.has_all_of({ MonsterSmartLearnType::OPP_ELEC, MonsterSmartLearnType::RES_ELEC })) {
         if (int_outof(msr_ptr->r_ptr, 80)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_ELEC);
         }
@@ -132,7 +132,7 @@ static void check_elec_resistance(msr_type *msr_ptr)
         return;
     }
 
-    if (msr_ptr->smart.has_any_of({ MonsterSmartLearnType::OPP_ELEC, MonsterSmartLearnType::RES_ELEC })) {
+    if (msr_ptr->smart_flags.has_any_of({ MonsterSmartLearnType::OPP_ELEC, MonsterSmartLearnType::RES_ELEC })) {
         if (int_outof(msr_ptr->r_ptr, 30)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_ELEC);
         }
@@ -149,14 +149,14 @@ static void check_elec_resistance(msr_type *msr_ptr)
 
 static void check_fire_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has(MonsterSmartLearnType::IMM_FIRE)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::IMM_FIRE)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::BR_FIRE);
         msr_ptr->ability_flags.reset(MonsterAbilityType::BA_FIRE);
         msr_ptr->ability_flags.reset(MonsterAbilityType::BO_FIRE);
         return;
     }
 
-    if (msr_ptr->smart.has_all_of({ MonsterSmartLearnType::OPP_FIRE, MonsterSmartLearnType::RES_FIRE })) {
+    if (msr_ptr->smart_flags.has_all_of({ MonsterSmartLearnType::OPP_FIRE, MonsterSmartLearnType::RES_FIRE })) {
         if (int_outof(msr_ptr->r_ptr, 80)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_FIRE);
         }
@@ -172,7 +172,7 @@ static void check_fire_resistance(msr_type *msr_ptr)
         return;
     }
 
-    if (msr_ptr->smart.has_any_of({ MonsterSmartLearnType::OPP_FIRE, MonsterSmartLearnType::RES_FIRE })) {
+    if (msr_ptr->smart_flags.has_any_of({ MonsterSmartLearnType::OPP_FIRE, MonsterSmartLearnType::RES_FIRE })) {
         if (int_outof(msr_ptr->r_ptr, 30)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_FIRE);
         }
@@ -189,7 +189,7 @@ static void check_fire_resistance(msr_type *msr_ptr)
 
 static void check_cold_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has(MonsterSmartLearnType::IMM_COLD)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::IMM_COLD)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::BR_COLD);
         msr_ptr->ability_flags.reset(MonsterAbilityType::BA_COLD);
         msr_ptr->ability_flags.reset(MonsterAbilityType::BO_COLD);
@@ -197,7 +197,7 @@ static void check_cold_resistance(msr_type *msr_ptr)
         return;
     }
 
-    if (msr_ptr->smart.has_all_of({ MonsterSmartLearnType::OPP_COLD, MonsterSmartLearnType::RES_COLD })) {
+    if (msr_ptr->smart_flags.has_all_of({ MonsterSmartLearnType::OPP_COLD, MonsterSmartLearnType::RES_COLD })) {
         if (int_outof(msr_ptr->r_ptr, 80)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_COLD);
         }
@@ -217,7 +217,7 @@ static void check_cold_resistance(msr_type *msr_ptr)
         return;
     }
 
-    if (msr_ptr->smart.has_any_of({ MonsterSmartLearnType::OPP_COLD, MonsterSmartLearnType::RES_COLD })) {
+    if (msr_ptr->smart_flags.has_any_of({ MonsterSmartLearnType::OPP_COLD, MonsterSmartLearnType::RES_COLD })) {
         if (int_outof(msr_ptr->r_ptr, 30)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_COLD);
         }
@@ -238,7 +238,7 @@ static void check_cold_resistance(msr_type *msr_ptr)
 
 static void check_pois_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has_all_of({ MonsterSmartLearnType::OPP_POIS, MonsterSmartLearnType::RES_POIS })) {
+    if (msr_ptr->smart_flags.has_all_of({ MonsterSmartLearnType::OPP_POIS, MonsterSmartLearnType::RES_POIS })) {
         if (int_outof(msr_ptr->r_ptr, 80)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_POIS);
         }
@@ -258,7 +258,7 @@ static void check_pois_resistance(msr_type *msr_ptr)
         return;
     }
 
-    if (msr_ptr->smart.has_any_of({ MonsterSmartLearnType::OPP_POIS, MonsterSmartLearnType::RES_POIS })) {
+    if (msr_ptr->smart_flags.has_any_of({ MonsterSmartLearnType::OPP_POIS, MonsterSmartLearnType::RES_POIS })) {
         if (int_outof(msr_ptr->r_ptr, 30)) {
             msr_ptr->ability_flags.reset(MonsterAbilityType::BR_POIS);
         }
index 57fc84f..e2b51bf 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct msr_type;
 class PlayerType;
index 624dce2..8cc8331 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/high-resistance-checker.h"
+#include "mspell/high-resistance-checker.h"
 #include "monster-race/race-ability-flags.h"
 #include "monster/smart-learn-types.h"
 #include "mspell/smart-mspell-util.h"
 void add_cheat_remove_flags_others(PlayerType *player_ptr, msr_type *msr_ptr)
 {
     if (has_resist_neth(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_NETH);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_NETH);
     }
 
     if (has_resist_lite(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_LITE);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_LITE);
     }
 
     if (has_resist_dark(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_DARK);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_DARK);
     }
 
     if (has_resist_fear(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_FEAR);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_FEAR);
     }
 
     if (has_resist_conf(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_CONF);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_CONF);
     }
 
     if (has_resist_chaos(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_CHAOS);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_CHAOS);
     }
 
     if (has_resist_disen(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_DISEN);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_DISEN);
     }
 
     if (has_resist_blind(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_BLIND);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_BLIND);
     }
 
     if (has_resist_nexus(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_NEXUS);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_NEXUS);
     }
 
     if (has_resist_sound(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_SOUND);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_SOUND);
     }
 
     if (has_resist_shard(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::RES_SHARD);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::RES_SHARD);
     }
 
     if (has_reflect(player_ptr)) {
-        msr_ptr->smart.set(MonsterSmartLearnType::IMM_REFLECT);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::IMM_REFLECT);
     }
 
     if (player_ptr->free_act) {
-        msr_ptr->smart.set(MonsterSmartLearnType::IMM_FREE);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::IMM_FREE);
     }
 
     if (!player_ptr->msp) {
-        msr_ptr->smart.set(MonsterSmartLearnType::IMM_MANA);
+        msr_ptr->smart_flags.set(MonsterSmartLearnType::IMM_MANA);
     }
 }
 
 static void check_nether_resistance(PlayerType *player_ptr, msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has_not(MonsterSmartLearnType::RES_NETH)) {
+    if (msr_ptr->smart_flags.has_not(MonsterSmartLearnType::RES_NETH)) {
         return;
     }
 
@@ -94,7 +94,7 @@ static void check_nether_resistance(PlayerType *player_ptr, msr_type *msr_ptr)
 
 static void check_lite_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has_not(MonsterSmartLearnType::RES_LITE)) {
+    if (msr_ptr->smart_flags.has_not(MonsterSmartLearnType::RES_LITE)) {
         return;
     }
 
@@ -109,7 +109,7 @@ static void check_lite_resistance(msr_type *msr_ptr)
 
 static void check_dark_resistance(PlayerType *player_ptr, msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has_not(MonsterSmartLearnType::RES_DARK)) {
+    if (msr_ptr->smart_flags.has_not(MonsterSmartLearnType::RES_DARK)) {
         return;
     }
 
@@ -130,7 +130,7 @@ static void check_dark_resistance(PlayerType *player_ptr, msr_type *msr_ptr)
 
 static void check_conf_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has_not(MonsterSmartLearnType::RES_CONF)) {
+    if (msr_ptr->smart_flags.has_not(MonsterSmartLearnType::RES_CONF)) {
         return;
     }
 
@@ -142,7 +142,7 @@ static void check_conf_resistance(msr_type *msr_ptr)
 
 static void check_chaos_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has_not(MonsterSmartLearnType::RES_CHAOS)) {
+    if (msr_ptr->smart_flags.has_not(MonsterSmartLearnType::RES_CHAOS)) {
         return;
     }
 
@@ -157,7 +157,7 @@ static void check_chaos_resistance(msr_type *msr_ptr)
 
 static void check_nexus_resistance(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has_not(MonsterSmartLearnType::RES_NEXUS)) {
+    if (msr_ptr->smart_flags.has_not(MonsterSmartLearnType::RES_NEXUS)) {
         return;
     }
 
@@ -170,7 +170,7 @@ static void check_nexus_resistance(msr_type *msr_ptr)
 
 static void check_reflection(msr_type *msr_ptr)
 {
-    if (msr_ptr->smart.has_not(MonsterSmartLearnType::IMM_REFLECT)) {
+    if (msr_ptr->smart_flags.has_not(MonsterSmartLearnType::IMM_REFLECT)) {
         return;
     }
 
@@ -228,36 +228,36 @@ void check_high_resistances(PlayerType *player_ptr, msr_type *msr_ptr)
     check_nether_resistance(player_ptr, msr_ptr);
     check_lite_resistance(msr_ptr);
     check_dark_resistance(player_ptr, msr_ptr);
-    if (msr_ptr->smart.has(MonsterSmartLearnType::RES_FEAR)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::RES_FEAR)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::SCARE);
     }
 
     check_conf_resistance(msr_ptr);
     check_chaos_resistance(msr_ptr);
-    if (msr_ptr->smart.has(MonsterSmartLearnType::RES_DISEN) && int_outof(msr_ptr->r_ptr, 40)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::RES_DISEN) && int_outof(msr_ptr->r_ptr, 40)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::BR_DISE);
     }
 
-    if (msr_ptr->smart.has(MonsterSmartLearnType::RES_BLIND)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::RES_BLIND)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::BLIND);
     }
 
     check_nexus_resistance(msr_ptr);
-    if (msr_ptr->smart.has(MonsterSmartLearnType::RES_SOUND) && int_outof(msr_ptr->r_ptr, 50)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::RES_SOUND) && int_outof(msr_ptr->r_ptr, 50)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::BR_SOUN);
     }
 
-    if (msr_ptr->smart.has(MonsterSmartLearnType::RES_SHARD) && int_outof(msr_ptr->r_ptr, 40)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::RES_SHARD) && int_outof(msr_ptr->r_ptr, 40)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::BR_SHAR);
     }
 
     check_reflection(msr_ptr);
-    if (msr_ptr->smart.has(MonsterSmartLearnType::IMM_FREE)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::IMM_FREE)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::HOLD);
         msr_ptr->ability_flags.reset(MonsterAbilityType::SLOW);
     }
 
-    if (msr_ptr->smart.has(MonsterSmartLearnType::IMM_MANA)) {
+    if (msr_ptr->smart_flags.has(MonsterSmartLearnType::IMM_MANA)) {
         msr_ptr->ability_flags.reset(MonsterAbilityType::DRAIN_MANA);
     }
 }
index 506d675..5d5998a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct msr_type;
 class PlayerType;
index 47cebfd..dad14dc 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/improper-mspell-remover.h"
+#include "mspell/improper-mspell-remover.h"
 #include "game-option/birth-options.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags2.h"
@@ -31,8 +31,8 @@ static void add_cheat_remove_flags(PlayerType *player_ptr, msr_type *msr_ptr)
  */
 void remove_bad_spells(MONSTER_IDX m_idx, PlayerType *player_ptr, EnumClassFlagGroup<MonsterAbilityType> &ability_flags)
 {
-    msr_type tmp_msr;
-    msr_type *msr_ptr = initialize_msr_type(player_ptr, &tmp_msr, m_idx, ability_flags);
+    msr_type tmp_msr(player_ptr, m_idx, ability_flags);
+    auto *msr_ptr = &tmp_msr;
     if (msr_ptr->r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) {
         return;
     }
@@ -48,11 +48,11 @@ void remove_bad_spells(MONSTER_IDX m_idx, PlayerType *player_ptr, EnumClassFlagG
             m_ptr->smart.clear();
         }
 
-        msr_ptr->smart = m_ptr->smart;
+        msr_ptr->smart_flags = m_ptr->smart;
     }
 
     add_cheat_remove_flags(player_ptr, msr_ptr);
-    if (msr_ptr->smart.none()) {
+    if (msr_ptr->smart_flags.none()) {
         return;
     }
 
index ba8ebe9..dc50657 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 588b020..db73546 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/monster-power-table.h"
+#include "mspell/monster-power-table.h"
 #include "monster-race/race-ability-flags.h"
 #include "player-ability/player-ability-types.h"
 
@@ -54,6 +54,7 @@ const std::map<MonsterAbilityType, const monster_power> monster_powers = {
     { MonsterAbilityType::BA_DARK, { 40, 42, 90, 550, 95, A_INT, _("暗黒の嵐", "darkness storm") } },
     { MonsterAbilityType::BA_VOID, { 38, 41, 85, 400, 90, A_INT, _("虚無の嵐", "void ball") } },
     { MonsterAbilityType::BA_ABYSS, { 39, 42, 85, 400, 90, A_INT, _("深淵の嵐", "abyss ball") } },
+    { MonsterAbilityType::BA_METEOR, { 45, 50, 90, 600, 95, A_INT, _("メテオスウォーム", "meteor swarm") } },
     { MonsterAbilityType::DRAIN_MANA, { 10, 5, 50, 0, 25, A_INT, _("魔力吸収", "drain mana") } },
     { MonsterAbilityType::MIND_BLAST, { 25, 10, 60, 0, 30, A_INT, _("精神攻撃", "mind blast") } },
     { MonsterAbilityType::BRAIN_SMASH, { 30, 14, 65, 0, 30, A_INT, _("脳攻撃", "brain smash") } },
@@ -73,6 +74,8 @@ const std::map<MonsterAbilityType, const monster_power> monster_powers = {
     { MonsterAbilityType::BO_ICEE, { 25, 16, 60, 186, 60, A_INT, _("極寒の矢", "ice bolt") } },
     { MonsterAbilityType::BO_VOID, { 35, 31, 80, 342, 70, A_INT, _("ヴォイド・ボルト", "void bolt") } },
     { MonsterAbilityType::BO_ABYSS, { 35, 33, 80, 342, 70, A_INT, _("アビス・ボルト", "abyss bolt") } },
+    { MonsterAbilityType::BO_METEOR, { 30, 28, 90, 400, 80, A_INT, _("メテオストライク", "meteor strike") } },
+    { MonsterAbilityType::BO_LITE, { 20, 25, 75, 300, 65, A_INT, _("スターライトアロー", "starlight arrow") } },
     { MonsterAbilityType::MISSILE, { 3, 1, 25, 12, 20, A_INT, _("マジック・ミサイル", "magic missile") } },
     { MonsterAbilityType::SCARE, { 5, 3, 35, 0, 20, A_INT, _("恐慌", "scare") } },
     { MonsterAbilityType::BLIND, { 10, 5, 40, 0, 20, A_INT, _("盲目", "blind") } },
@@ -112,6 +115,7 @@ const std::map<MonsterAbilityType, const monster_power> monster_powers = {
     { MonsterAbilityType::S_HI_DRAGON, { 46, 90, 85, 0, 45, A_INT, _("古代ドラゴンの召喚", "summon Ancient Dragon") } },
     { MonsterAbilityType::S_AMBERITES, { 48, 120, 90, 0, 50, A_INT, _("アンバーの王族の召喚", "summon Lords of Amber") } },
     { MonsterAbilityType::S_UNIQUE, { 50, 150, 95, 0, 50, A_INT, _("ユニークモンスターの召喚", "summon Unique Monsters") } },
+    { MonsterAbilityType::S_DEAD_UNIQUE, { 50, 150, 95, 0, 50, A_INT, _("ユニークモンスターの口寄せ", "summon Dead Unique Monsters") } },
 };
 
 /*!
@@ -162,6 +166,7 @@ const std::map<MonsterAbilityType, concptr> monster_powers_short = {
     { MonsterAbilityType::BA_WATE, _("ウォーター", "Water") },
     { MonsterAbilityType::BA_MANA, _("魔力の嵐", "Mana storm") },
     { MonsterAbilityType::BA_DARK, _("暗黒の嵐", "Darkness storm") },
+    { MonsterAbilityType::BA_METEOR, _("メテオ・スウォーム", "Meteor Swarm") },
     { MonsterAbilityType::BA_VOID, _("虚無", "Void") },
     { MonsterAbilityType::BA_ABYSS, _("深淵", "Abyss") },
     { MonsterAbilityType::DRAIN_MANA, _("魔力吸収", "Drain mana") },
@@ -222,4 +227,5 @@ const std::map<MonsterAbilityType, concptr> monster_powers_short = {
     { MonsterAbilityType::S_HI_DRAGON, _("古代ドラゴン", "Ancient Dragon") },
     { MonsterAbilityType::S_AMBERITES, _("アンバーの王族", "Lords of Amber") },
     { MonsterAbilityType::S_UNIQUE, _("ユニーク", "Unique monsters") },
+    { MonsterAbilityType::S_DEAD_UNIQUE, _("黄泉のユニーク", "Dead unique monsters") },
 };
index a836075..c5a7f1f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 06f427c..081f659 100644 (file)
@@ -1,23 +1,19 @@
-#include "mspell/mspell-attack-util.h"
+#include "mspell/mspell-attack-util.h"
 #include "monster-race/monster-race.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 
-msa_type *initialize_msa_type(PlayerType *player_ptr, msa_type *msa_ptr, MONSTER_IDX m_idx)
+msa_type::msa_type(PlayerType *player_ptr, MONSTER_IDX m_idx)
+    : m_idx(m_idx)
+    , m_ptr(&player_ptr->current_floor_ptr->m_list[m_idx])
+    , x(player_ptr->x)
+    , y(player_ptr->y)
+    , do_spell(DO_SPELL_NONE)
+    , thrown_spell(MonsterAbilityType::MAX)
 {
-    msa_ptr->m_idx = m_idx;
-    msa_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    msa_ptr->r_ptr = &monraces_info[msa_ptr->m_ptr->r_idx];
-    msa_ptr->no_inate = randint0(100) >= (msa_ptr->r_ptr->freq_spell * 2);
-    msa_ptr->ability_flags = msa_ptr->r_ptr->ability_flags;
-    msa_ptr->x = player_ptr->x;
-    msa_ptr->y = player_ptr->y;
-    msa_ptr->x_br_lite = 0;
-    msa_ptr->y_br_lite = 0;
-    msa_ptr->do_spell = DO_SPELL_NONE;
-    msa_ptr->dam = 0;
-    msa_ptr->thrown_spell = MonsterAbilityType::MAX;
-    return msa_ptr;
+    this->r_ptr = &this->m_ptr->get_monrace();
+    this->no_inate = randint0(100) >= (this->r_ptr->freq_spell * 2);
+    this->ability_flags = this->r_ptr->ability_flags;
 }
index 195bf6b..ad3602b 100644 (file)
@@ -1,10 +1,9 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 #include "monster-race/race-ability-flags.h"
+#include "system/angband.h"
 #include "util/flag-group.h"
-
+#include <string>
 #include <vector>
 
 enum mspell_lite_type {
@@ -17,26 +16,28 @@ enum mspell_lite_type {
 // Monster Spell Attack.
 class MonsterEntity;
 class MonsterRaceInfo;
+class PlayerType;
 struct msa_type {
+    msa_type(PlayerType *player_ptr, MONSTER_IDX m_idx);
+
+    POSITION x_br_lite = 0;
+    POSITION y_br_lite = 0;
+    bool in_no_magic_dungeon = false;
+    bool success = false;
+    std::vector<MonsterAbilityType> mspells{};
+    std::string m_name = "";
+    bool can_remember = false;
+    int dam = 0;
+    DEPTH rlev = 0;
+
     MONSTER_IDX m_idx;
     MonsterEntity *m_ptr;
-    MonsterRaceInfo *r_ptr;
-    bool no_inate;
-    EnumClassFlagGroup<MonsterAbilityType> ability_flags;
     POSITION x;
     POSITION y;
-    POSITION x_br_lite;
-    POSITION y_br_lite;
     mspell_lite_type do_spell;
-    bool in_no_magic_dungeon;
-    bool success;
-    std::vector<MonsterAbilityType> mspells;
     MonsterAbilityType thrown_spell;
-    GAME_TEXT m_name[MAX_NLEN];
-    bool can_remember;
-    int dam;
-    DEPTH rlev;
-};
 
-class PlayerType;
-msa_type *initialize_msa_type(PlayerType *player_ptr, msa_type *msa_ptr, MONSTER_IDX m_idx);
+    MonsterRaceInfo *r_ptr;
+    bool no_inate;
+    EnumClassFlagGroup<MonsterAbilityType> ability_flags;
+};
index d398dd1..489887c 100644 (file)
@@ -1,7 +1,6 @@
-#include "mspell/mspell-attack.h"
+#include "mspell/mspell-attack.h"
 #include "blue-magic/blue-magic-checker.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h"
 #include "floor/cave.h"
 #include "player/attack-defense-types.h"
 #include "spell-kind/spells-world.h"
 #include "spell-realm/spells-hex.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 #include "world/world.h"
+#include <iterator>
 #ifdef JP
 #else
 #include "monster/monster-description-types.h"
 #endif
 
-#include <iterator>
-
 static void set_no_magic_mask(msa_type *msa_ptr)
 {
     if (!msa_ptr->no_inate) {
@@ -58,7 +58,10 @@ static void set_no_magic_mask(msa_type *msa_ptr)
 static void check_mspell_stupid(PlayerType *player_ptr, msa_type *msa_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    msa_ptr->in_no_magic_dungeon = dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MAGIC) && floor_ptr->dun_level && (!inside_quest(floor_ptr->quest_number) || QuestType::is_fixed(floor_ptr->quest_number));
+    auto is_in_no_magic_dungeon = floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::NO_MAGIC);
+    is_in_no_magic_dungeon &= floor_ptr->is_in_dungeon();
+    is_in_no_magic_dungeon &= !floor_ptr->is_in_quest() || QuestType::is_fixed(floor_ptr->quest_number);
+    msa_ptr->in_no_magic_dungeon = is_in_no_magic_dungeon;
     if (!msa_ptr->in_no_magic_dungeon || (msa_ptr->r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID))) {
         return;
     }
@@ -66,7 +69,7 @@ static void check_mspell_stupid(PlayerType *player_ptr, msa_type *msa_ptr)
     msa_ptr->ability_flags &= RF_ABILITY_NOMAGIC_MASK;
 }
 
-static void check_mspell_smart(PlayerType *player_ptr, msa_type *msa_ptr)
+static void check_mspell_smart(const FloorType &floor, msa_type *msa_ptr)
 {
     if (msa_ptr->r_ptr->behavior_flags.has_not(MonsterBehaviorType::SMART)) {
         return;
@@ -76,14 +79,14 @@ static void check_mspell_smart(PlayerType *player_ptr, msa_type *msa_ptr)
         msa_ptr->ability_flags &= RF_ABILITY_INT_MASK;
     }
 
-    if (msa_ptr->ability_flags.has(MonsterAbilityType::TELE_LEVEL) && is_teleport_level_ineffective(player_ptr, 0)) {
+    if (msa_ptr->ability_flags.has(MonsterAbilityType::TELE_LEVEL) && floor.can_teleport_level()) {
         msa_ptr->ability_flags.reset(MonsterAbilityType::TELE_LEVEL);
     }
 }
 
-static void check_mspell_arena(PlayerType *player_ptr, msa_type *msa_ptr)
+static void check_mspell_arena(const FloorType &floor, msa_type *msa_ptr)
 {
-    if (!player_ptr->current_floor_ptr->inside_arena && !player_ptr->phase_out) {
+    if (!floor.inside_arena && !AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -104,7 +107,8 @@ static bool check_mspell_non_stupid(PlayerType *player_ptr, msa_type *msa_ptr)
         msa_ptr->ability_flags.reset(MonsterAbilityType::DRAIN_MANA);
     }
 
-    if (msa_ptr->ability_flags.has_any_of(RF_ABILITY_BOLT_MASK) && !clean_shot(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, player_ptr->y, player_ptr->x, false)) {
+    if (msa_ptr->ability_flags.has_any_of(RF_ABILITY_BOLT_MASK) &&
+        !clean_shot(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, player_ptr->y, player_ptr->x, false)) {
         msa_ptr->ability_flags.reset(RF_ABILITY_BOLT_MASK);
     }
 
@@ -116,7 +120,8 @@ static bool check_mspell_non_stupid(PlayerType *player_ptr, msa_type *msa_ptr)
         msa_ptr->ability_flags.reset(MonsterAbilityType::RAISE_DEAD);
     }
 
-    if (msa_ptr->ability_flags.has(MonsterAbilityType::SPECIAL) && (msa_ptr->m_ptr->r_idx == MonsterRaceId::ROLENTO) && !summon_possible(player_ptr, msa_ptr->y, msa_ptr->x)) {
+    if (msa_ptr->ability_flags.has(MonsterAbilityType::SPECIAL) && (msa_ptr->m_ptr->r_idx == MonsterRaceId::ROLENTO) &&
+        !summon_possible(player_ptr, msa_ptr->y, msa_ptr->x)) {
         msa_ptr->ability_flags.reset(MonsterAbilityType::SPECIAL);
     }
 
@@ -128,11 +133,6 @@ static void set_mspell_list(msa_type *msa_ptr)
     EnumClassFlagGroup<MonsterAbilityType>::get_flags(msa_ptr->ability_flags, std::back_inserter(msa_ptr->mspells));
 }
 
-static void describe_mspell_monster(PlayerType *player_ptr, msa_type *msa_ptr)
-{
-    angband_strcpy(msa_ptr->m_name, monster_desc(player_ptr, msa_ptr->m_ptr, 0x00).data(), sizeof(msa_ptr->m_name));
-}
-
 static bool switch_do_spell(PlayerType *player_ptr, msa_type *msa_ptr)
 {
     switch (msa_ptr->do_spell) {
@@ -168,7 +168,7 @@ static bool check_mspell_continuation(PlayerType *player_ptr, msa_type *msa_ptr)
     }
 
     remove_bad_spells(msa_ptr->m_idx, player_ptr, msa_ptr->ability_flags);
-    check_mspell_arena(player_ptr, msa_ptr);
+    check_mspell_arena(*player_ptr->current_floor_ptr, msa_ptr);
     if (msa_ptr->ability_flags.none() || !check_mspell_non_stupid(player_ptr, msa_ptr)) {
         return false;
     }
@@ -178,7 +178,7 @@ static bool check_mspell_continuation(PlayerType *player_ptr, msa_type *msa_ptr)
         return false;
     }
 
-    describe_mspell_monster(player_ptr, msa_ptr);
+    msa_ptr->m_name = monster_desc(player_ptr, msa_ptr->m_ptr, 0x00);
     if (!switch_do_spell(player_ptr, msa_ptr) || (msa_ptr->thrown_spell == MonsterAbilityType::MAX)) {
         return false;
     }
@@ -195,12 +195,12 @@ static bool check_mspell_unexploded(PlayerType *player_ptr, msa_type *msa_ptr)
 
     if (!spell_is_inate(msa_ptr->thrown_spell) && (msa_ptr->in_no_magic_dungeon || (msa_ptr->m_ptr->get_remaining_stun() && one_in_(2)) || (randint0(100) < fail_rate))) {
         disturb(player_ptr, true, true);
-        msg_format(_("%s^は呪文を唱えようとしたが失敗した。", "%s^ tries to cast a spell, but fails."), msa_ptr->m_name);
+        msg_format(_("%s^は呪文を唱えようとしたが失敗した。", "%s^ tries to cast a spell, but fails."), msa_ptr->m_name.data());
         return true;
     }
 
     if (!spell_is_inate(msa_ptr->thrown_spell) && SpellHex(player_ptr).check_hex_barrier(msa_ptr->m_idx, HEX_ANTI_MAGIC)) {
-        msg_format(_("反魔法バリアが%s^の呪文をかき消した。", "Anti magic barrier cancels the spell which %s^ casts."), msa_ptr->m_name);
+        msg_format(_("反魔法バリアが%s^の呪文をかき消した。", "Anti magic barrier cancels the spell which %s^ casts."), msa_ptr->m_name.data());
         return true;
     }
 
@@ -219,8 +219,7 @@ static bool check_thrown_mspell(PlayerType *player_ptr, msa_type *msa_ptr)
     msa_ptr->can_remember = is_original_ap_and_seen(player_ptr, msa_ptr->m_ptr);
 
     // ターゲットがプレイヤー位置なら直接射線が通っているので常に届く。
-    bool direct = player_bold(player_ptr, msa_ptr->y, msa_ptr->x);
-    if (direct) {
+    if (player_ptr->is_located_at({ msa_ptr->y, msa_ptr->x })) {
         return true;
     }
 
@@ -269,7 +268,7 @@ static bool check_thrown_mspell(PlayerType *player_ptr, msa_type *msa_ptr)
 static void check_mspell_imitation(PlayerType *player_ptr, msa_type *msa_ptr)
 {
     const auto seen = (!player_ptr->effects()->blindness()->is_blind() && msa_ptr->m_ptr->ml);
-    const auto can_imitate = player_has_los_bold(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx);
+    const auto can_imitate = player_ptr->current_floor_ptr->has_los({ msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx });
     PlayerClass pc(player_ptr);
     if (!seen || !can_imitate || (w_ptr->timewalk_m_idx != 0) || !pc.equals(PlayerClassType::IMITATOR)) {
         return;
@@ -288,7 +287,7 @@ static void check_mspell_imitation(PlayerType *player_ptr, msa_type *msa_ptr)
 
     mane_data->mane_list.push_back({ msa_ptr->thrown_spell, msa_ptr->dam });
     mane_data->new_mane = true;
-    player_ptr->redraw |= PR_IMITATION;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::IMITATION);
 }
 
 static void remember_mspell(msa_type *msa_ptr)
@@ -312,15 +311,18 @@ static void remember_mspell(msa_type *msa_ptr)
  */
 bool make_attack_spell(PlayerType *player_ptr, MONSTER_IDX m_idx)
 {
-    msa_type tmp_msa;
-    msa_type *msa_ptr = initialize_msa_type(player_ptr, &tmp_msa, m_idx);
+    msa_type tmp_msa(player_ptr, m_idx);
+    msa_type *msa_ptr = &tmp_msa;
     if (msa_ptr->m_ptr->is_confused()) {
         reset_target(msa_ptr->m_ptr);
         return false;
     }
 
     const auto &m_ref = *msa_ptr->m_ptr;
-    if (m_ref.mflag.has(MonsterTemporaryFlagType::PREVENT_MAGIC) || !m_ref.is_hostile() || ((m_ref.cdis > get_max_range(player_ptr)) && !m_ref.target_y)) {
+    auto should_prevent = m_ref.mflag.has(MonsterTemporaryFlagType::PREVENT_MAGIC);
+    should_prevent |= !m_ref.is_hostile();
+    should_prevent |= (m_ref.cdis > AngbandSystem::get_instance().get_max_range()) && !m_ref.target_y;
+    if (should_prevent) {
         return false;
     }
 
@@ -334,7 +336,7 @@ bool make_attack_spell(PlayerType *player_ptr, MONSTER_IDX m_idx)
     set_no_magic_mask(msa_ptr);
     decide_lite_area(player_ptr, msa_ptr);
     check_mspell_stupid(player_ptr, msa_ptr);
-    check_mspell_smart(player_ptr, msa_ptr);
+    check_mspell_smart(*player_ptr->current_floor_ptr, msa_ptr);
     if (!check_mspell_continuation(player_ptr, msa_ptr)) {
         return false;
     }
index 9f7ef0a..04fb970 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 2be4805..e4a2fdd 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-attack/abstract-mspell.h"
+#include "mspell/mspell-attack/abstract-mspell.h"
 #include "monster/monster-update.h"
 #include "mspell/mspell-damage-calculator.h"
 #include "mspell/mspell-util.h"
index 458da19..a67cd7b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/effect-processor.h"
 #include "monster-race/race-ability-flags.h"
index dc83850..b07be7e 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-attack/mspell-ball.h"
+#include "mspell/mspell-attack/mspell-ball.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-processor.h"
 #include "main/sound-of-music.h"
@@ -110,7 +110,11 @@ const std::unordered_map<MonsterAbilityType, MSpellData> ball_list = {
     { MonsterAbilityType::BA_ABYSS, { { _("%s^が何かを力強くつぶやいた。", "%s^ mumbles powerfully."),
                                           _("%s^が深淵の嵐の呪文を念じた。", "%s^ invokes a abyss storm."),
                                           _("%s^が%sに対して深淵の嵐の呪文を念じた。", "%s^ invokes a void abyss upon %s.") },
-                                        AttributeType::ABYSS, DRS_DARK } }
+                                        AttributeType::ABYSS, DRS_DARK } },
+    { MonsterAbilityType::BA_METEOR, { { _("%s^が何かを力強くつぶやいた。", "%s^ mumbles powerfully."),
+                                           _("%s^がメテオスウォームの呪文を念じた。", "%s^ invokes a meteor swarm."),
+                                           _("%s^が%sに対してメテオスウォームの呪文を念じた。", "%s^ invokes a meteor swarm upon %s.") },
+                                         AttributeType::METEOR } }
 };
 
 MSpellBall::MSpellBall(PlayerType *player_ptr, MONSTER_IDX m_idx, MonsterAbilityType ability, POSITION rad, int target_type)
index 8b05613..610b355 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index ad4f0e9..fe0c7a5 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-attack/mspell-bolt.h"
+#include "mspell/mspell-attack/mspell-bolt.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-processor.h"
 #include "main/sound-definitions-table.h"
@@ -75,6 +75,14 @@ const std::unordered_map<MonsterAbilityType, MSpellData> bolt_list = {
                                           _("%s^がアビス・ボルトの呪文を唱えた。", "%s^ casts a abyss bolt."),
                                           _("%s^が%sに向かってアビス・ボルトの呪文を唱えた。", "%s^ casts a abyss bolt at %s.") },
                                         AttributeType::ABYSS, DRS_REFLECT } },
+    { MonsterAbilityType::BO_METEOR, { { _("%s^が何かをつぶやいた。", "%s^ mumbles."),
+                                           _("%s^がメテオストライクの呪文を唱えた。", "%s^ casts a meteor strike."),
+                                           _("%s^が%sに向かってメテオストライクの呪文を唱えた。", "%s^ casts a meteor strike at %s.") },
+                                         AttributeType::METEOR, DRS_REFLECT } },
+    { MonsterAbilityType::BO_LITE, { { _("%s^が何かをつぶやいた。", "%s^ mumbles."),
+                                         _("%s^がスターライトアローを放った。", "%s^ fires a starlight arrow."),
+                                         _("%s^が%sに向かってスターライトアローを放った。", "%s^ fires a starlight arrow at %s.") },
+                                       AttributeType::LITE, DRS_REFLECT } },
     { MonsterAbilityType::MISSILE, { { _("%s^が何かをつぶやいた。", "%s^ mumbles."),
                                          _("%s^がマジック・ミサイルの呪文を唱えた。", "%s^ casts a magic missile."),
                                          _("%s^が%sに向かってマジック・ミサイルの呪文を唱えた。", "%s^ casts a magic missile at %s.") },
index 6b25341..626254b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 61fb5f0..77dda1a 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-attack/mspell-breath.h"
+#include "mspell/mspell-attack/mspell-breath.h"
 #include "core/disturbance.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-processor.h"
index 1afd775..77a74f0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3eb35a2..cf78859 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-attack/mspell-curse.h"
+#include "mspell/mspell-attack/mspell-curse.h"
 #include "core/disturbance.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-processor.h"
index 83b87ed..e3d8f21 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 10f22a0..dc797a9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ボルトでもボールでもブレスでもなく、ダメージを与える特殊なスペルの実行 /
  * Performing special spells that take damage, not bolts, balls or breaths
  * @date 2020/05/16
index 6f656ee..00e300f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "mspell/mspell-attack/abstract-mspell.h"
 #include "system/angband.h"
index 49d9c79..8890222 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター魔法の実装 / Monster spells (attack player)
  * @date 2014/01/17
  * @author
@@ -12,7 +12,6 @@
 #include "mspell/mspell-checker.h"
 #include "blue-magic/blue-magic-checker.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h"
 #include "effect/attribute-types.h"
@@ -46,6 +45,7 @@
 #include "spell-kind/spells-world.h"
 #include "spell-realm/spells-hex.h"
 #include "spell/range-calc.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -105,7 +105,7 @@ bool raise_possible(PlayerType *player_ptr, MonsterEntity *m_ptr)
     POSITION x = m_ptr->fx;
     auto *floor_ptr = player_ptr->current_floor_ptr;
     for (POSITION xx = x - 5; xx <= x + 5; xx++) {
-        grid_type *g_ptr;
+        Grid *g_ptr;
         for (POSITION yy = y - 5; yy <= y + 5; yy++) {
             if (distance(y, x, yy, xx) > 5) {
                 continue;
@@ -156,25 +156,27 @@ bool raise_possible(PlayerType *player_ptr, MonsterEntity *m_ptr)
 bool clean_shot(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, bool is_friend)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    projection_path grid_g(player_ptr, get_max_range(player_ptr), y1, x1, y2, x2, 0);
+    projection_path grid_g(player_ptr, AngbandSystem::get_instance().get_max_range(), y1, x1, y2, x2, 0);
     if (grid_g.path_num() == 0) {
         return false;
     }
 
-    const auto [last_y, last_x] = grid_g.back();
+    const auto &[last_y, last_x] = grid_g.back();
     if ((last_y != y2) || (last_x != x2)) {
         return false;
     }
 
     for (const auto &[y, x] : grid_g) {
-        if ((floor_ptr->grid_array[y][x].m_idx > 0) && (y != y2 || x != x2)) {
-            auto *m_ptr = &floor_ptr->m_list[floor_ptr->grid_array[y][x].m_idx];
+        const Pos2D pos(y, x);
+        const auto &grid = floor_ptr->get_grid(pos);
+        if ((grid.m_idx > 0) && (y != y2 || x != x2)) {
+            auto *m_ptr = &floor_ptr->m_list[grid.m_idx];
             if (is_friend == m_ptr->is_pet()) {
                 return false;
             }
         }
 
-        if (player_bold(player_ptr, y, x) && is_friend) {
+        if (player_ptr->is_located_at(pos) && is_friend) {
             return false;
         }
     }
@@ -265,7 +267,7 @@ ProjectResult ball(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m
 ProjectResult breath(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, AttributeType typ, int dam_hp, POSITION rad, int target_type)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_BREATH;
     if (target_type == MONSTER_TO_PLAYER) {
         flg |= PROJECT_PLAYER;
index c46b081..b521e00 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 13c4790..0ec899a 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-damage-calculator.h"
+#include "mspell/mspell-damage-calculator.h"
 #include "game-option/birth-options.h"
 #include "inventory/inventory-slot-types.h"
 #include "monster-race/monster-race.h"
@@ -243,6 +243,11 @@ static int monspell_damage_base(
         dice_num = 10;
         dice_side = 10;
         break;
+    case MonsterAbilityType::BA_METEOR:
+        dam = 50 + rlev * 5 / 2;
+        dice_num = 3;
+        dice_side = rlev;
+        break;
     case MonsterAbilityType::DRAIN_MANA:
         dam = rlev;
         div = 1;
@@ -337,6 +342,16 @@ static int monspell_damage_base(
         dice_num = 13;
         dice_side = 14;
         break;
+    case MonsterAbilityType::BO_METEOR:
+        dam = 30 + rlev * 2;
+        dice_num = 1;
+        dice_side = rlev;
+        break;
+    case MonsterAbilityType::BO_LITE:
+        dam = powerful ? 60 : 40;
+        dice_num = 1;
+        dice_side = powerful ? rlev * 4 : rlev * 2;
+        break;
     case MonsterAbilityType::MISSILE:
         dam = (rlev / 3);
         dice_num = 2;
@@ -428,6 +443,8 @@ static int monspell_damage_base(
         return -1;
     case MonsterAbilityType::S_UNIQUE:
         return -1;
+    case MonsterAbilityType::S_DEAD_UNIQUE:
+        return -1;
     case MonsterAbilityType::MAX:
         return -1;
     }
@@ -447,11 +464,11 @@ void monspell_shoot_dice(MonsterRaceInfo *r_ptr, int *dd, int *ds)
     int n = 0; /* Number of blows */
     const int max_blows = 4;
     for (int m = 0; m < max_blows; m++) {
-        if (r_ptr->blow[m].method != RaceBlowMethodType::NONE) {
+        if (r_ptr->blows[m].method != RaceBlowMethodType::NONE) {
             n++;
         } /* Count blows */
 
-        if (r_ptr->blow[m].method == RaceBlowMethodType::SHOOT) {
+        if (r_ptr->blows[m].method == RaceBlowMethodType::SHOOT) {
             p = m; /* Remember position */
             break;
         }
@@ -466,8 +483,8 @@ void monspell_shoot_dice(MonsterRaceInfo *r_ptr, int *dd, int *ds)
         (*dd) = 0;
         (*ds) = 0;
     } else {
-        (*dd) = r_ptr->blow[p].d_dice;
-        (*ds) = r_ptr->blow[p].d_side;
+        (*dd) = r_ptr->blows[p].d_dice;
+        (*ds) = r_ptr->blows[p].d_side;
     }
 }
 
@@ -483,7 +500,7 @@ int monspell_damage(PlayerType *player_ptr, MonsterAbilityType ms_type, MONSTER_
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
     int hp = (TYPE == DAM_ROLL) ? m_ptr->hp : m_ptr->max_maxhp;
     int shoot_dd, shoot_ds;
index ac153f7..87ca1fa 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index cd268af..1225378 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-data.h"
+#include "mspell/mspell-data.h"
 #include "effect/attribute-types.h"
 #include "monster/monster-update.h"
 #include "mspell/mspell-util.h"
index 19475cb..280a983 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "mind/drs-types.h"
 #include "system/angband.h"
index b08b7e8..c6256b6 100644 (file)
@@ -1,7 +1,5 @@
-#include "mspell/mspell-dispel.h"
+#include "mspell/mspell-dispel.h"
 #include "blue-magic/blue-magic-checker.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "core/window-redrawer.h"
 #include "mind/mind-force-trainer.h"
@@ -29,6 +27,7 @@
 #include "status/sight-setter.h"
 #include "status/temporary-resistance.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -96,9 +95,24 @@ static void dispel_player(PlayerType *player_ptr)
         }
 
         player_ptr->action = ACTION_NONE;
-        player_ptr->update |= (PU_BONUS | PU_HP | PU_MONSTER_STATUSES);
-        player_ptr->redraw |= (PR_MAP | PR_TIMED_EFFECT | PR_ACTION);
-        player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        static constexpr auto flags_srf = {
+            StatusRecalculatingFlag::BONUS,
+            StatusRecalculatingFlag::HP,
+            StatusRecalculatingFlag::MONSTER_STATUSES,
+        };
+        rfu.set_flags(flags_srf);
+        static constexpr auto flags_mwrf = {
+            MainWindowRedrawingFlag::MAP,
+            MainWindowRedrawingFlag::TIMED_EFFECT,
+            MainWindowRedrawingFlag::ACTION,
+        };
+        rfu.set_flags(flags_mwrf);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::OVERHEAD,
+            SubWindowRedrawingFlag::DUNGEON,
+        };
+        rfu.set_flags(flags_swrf);
         player_ptr->energy_need += ENERGY_NEED();
     }
 }
index eb88584..0e74fdb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e8b7634..ebaab55 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief フロアの一定範囲に効果を及ぼす (悲鳴、テレポート等)スペルの効果
  * @date 2020/05/16
  * @author Hourier
@@ -7,7 +7,6 @@
 #include "mspell/mspell-floor.h"
 #include "blue-magic/blue-magic-checker.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
@@ -42,6 +41,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
@@ -127,7 +127,7 @@ MonsterSpellResult spell_RF6_BLINK(PlayerType *player_ptr, MONSTER_IDX m_idx, in
     teleport_away(player_ptr, m_idx, 10, TELEPORT_SPONTANEOUS);
 
     if (target_type == MONSTER_TO_PLAYER) {
-        player_ptr->update |= (PU_MONSTER_STATUSES);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
     }
 
     return res;
@@ -181,8 +181,8 @@ MonsterSpellResult spell_RF6_TELE_TO(PlayerType *player_ptr, MONSTER_IDX m_idx,
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    auto *t_ptr = &floor_ptr->m_list[t_idx];
+    auto *tr_ptr = &t_ptr->get_monrace();
 
     mspell_cast_msg_simple msg(_("%s^があなたを引き戻した。", "%s^ commands you to return."),
         _("%s^が%sを引き戻した。", "%s^ commands %s to return."));
@@ -252,7 +252,7 @@ MonsterSpellResult spell_RF6_TELE_AWAY(PlayerType *player_ptr, MONSTER_IDX m_idx
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
 
     mspell_cast_msg_simple msg(_("%s^にテレポートさせられた。", "%s^ teleports you away."),
         _("%s^は%sをテレポートさせた。", "%s^ teleports %s away."));
@@ -331,7 +331,7 @@ MonsterSpellResult spell_RF6_TELE_LEVEL(PlayerType *player_ptr, MONSTER_IDX m_id
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
     bool resist, saving_throw;
 
@@ -389,7 +389,7 @@ MonsterSpellResult spell_RF6_DARKNESS(PlayerType *player_ptr, POSITION y, POSITI
     concptr msg_done;
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     bool can_use_lite_area = false;
     bool monster_to_monster = target_type == MONSTER_TO_MONSTER;
     bool monster_to_player = target_type == MONSTER_TO_PLAYER;
index 993478d..5645c41 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 361e8f9..623c91a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスター魔法の実装(対モンスター処理) / Monster spells (attack monster)
  * @date 2014/01/17
  * @author
@@ -19,7 +19,6 @@
 #include "main/sound-definitions-table.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags-resistance.h"
-#include "monster/monster-info.h"
 #include "monster/monster-status.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
@@ -31,6 +30,7 @@
 #include "realm/realm-song-numbers.h"
 #include "spell-realm/spells-song.h"
 #include "spell/range-calc.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
  */
 bool direct_beam(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, MonsterEntity *m_ptr)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    projection_path grid_g(player_ptr, get_max_range(player_ptr), y1, x1, y2, x2, PROJECT_THRU);
+    auto &floor = *player_ptr->current_floor_ptr;
+    projection_path grid_g(player_ptr, AngbandSystem::get_instance().get_max_range(), y1, x1, y2, x2, PROJECT_THRU);
     if (grid_g.path_num()) {
         return false;
     }
 
-    bool hit2 = false;
-    bool is_friend = m_ptr->is_pet();
+    auto hit2 = false;
+    auto is_friend = m_ptr->is_pet();
     for (const auto &[y, x] : grid_g) {
-        const auto &g_ref = floor_ptr->grid_array[y][x];
+        const Pos2D pos(y, x);
+        const auto &grid = floor.get_grid(pos);
         if (y == y2 && x == x2) {
             hit2 = true;
-        } else if (is_friend && g_ref.m_idx > 0 && !are_enemies(player_ptr, *m_ptr, floor_ptr->m_list[g_ref.m_idx])) {
+        } else if (is_friend && grid.m_idx > 0 && !m_ptr->is_hostile_to_melee(floor.m_list[grid.m_idx])) {
             return false;
         }
 
-        if (is_friend && player_bold(player_ptr, y, x)) {
+        if (is_friend && player_ptr->is_located_at(pos)) {
             return false;
         }
     }
 
-    if (!hit2) {
-        return false;
-    }
-    return true;
+    return hit2;
 }
 
 /*!
@@ -107,8 +105,8 @@ bool breath_direct(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2
         break;
     }
 
-    projection_path grid_g(player_ptr, get_max_range(player_ptr), y1, x1, y2, x2, flg);
-    int i = 0;
+    projection_path grid_g(player_ptr, AngbandSystem::get_instance().get_max_range(), y1, x1, y2, x2, flg);
+    auto path_n = 0;
     POSITION y = y1;
     POSITION x = x1;
     for (const auto &[ny, nx] : grid_g) {
@@ -128,12 +126,12 @@ bool breath_direct(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2
 
         y = ny;
         x = nx;
-        i++;
+        ++path_n;
     }
 
     bool hit2 = false;
     bool hityou = false;
-    if (i == 0) {
+    if (path_n == 0) {
         if (flg & PROJECT_DISI) {
             if (in_disintegration_range(player_ptr->current_floor_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) {
                 hit2 = true;
@@ -161,14 +159,13 @@ bool breath_direct(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2
         POSITION gx[1024], gy[1024];
         POSITION gm[32];
         POSITION gm_rad = rad;
-        breath_shape(player_ptr, grid_g, grid_g.path_num(), &grids, gx, gy, gm, &gm_rad, rad, y1, x1, y, x, typ);
-        for (i = 0; i < grids; i++) {
-            y = gy[i];
-            x = gx[i];
-            if ((y == y2) && (x == x2)) {
+        breath_shape(player_ptr, grid_g, path_n, &grids, gx, gy, gm, &gm_rad, rad, y1, x1, y, x, typ);
+        for (auto i = 0; i < grids; i++) {
+            const Pos2D pos(gy[i], gx[i]);
+            if ((pos.y == y2) && (pos.x == x2)) {
                 hit2 = true;
             }
-            if (player_bold(player_ptr, y, x)) {
+            if (player_ptr->is_located_at(pos)) {
                 hityou = true;
             }
         }
@@ -196,7 +193,7 @@ bool breath_direct(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2
  */
 void get_project_point(PlayerType *player_ptr, POSITION sy, POSITION sx, POSITION *ty, POSITION *tx, BIT_FLAGS flg)
 {
-    projection_path path_g(player_ptr, get_max_range(player_ptr), sy, sx, *ty, *tx, flg);
+    projection_path path_g(player_ptr, AngbandSystem::get_instance().get_max_range(), sy, sx, *ty, *tx, flg);
     *ty = sy;
     *tx = sx;
     for (const auto &[y, x] : path_g) {
@@ -279,7 +276,7 @@ bool dispel_check(PlayerType *player_ptr, MONSTER_IDX m_idx)
 
     const auto &floor_ref = *player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ref.m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->ability_flags.has(MonsterAbilityType::BR_ACID)) {
         if (!has_immune_acid(player_ptr) && (player_ptr->oppose_acid || music_singing(player_ptr, MUSIC_RESIST))) {
             return true;
index 269c7e4..978af5b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index 0332ae2..fc19d9e 100644 (file)
@@ -1,5 +1,4 @@
-#include "mspell/mspell-learn-checker.h"
-#include "floor/cave.h"
+#include "mspell/mspell-learn-checker.h"
 #include "grid/grid.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
@@ -18,8 +17,9 @@
  */
 bool spell_learnable(PlayerType *player_ptr, MONSTER_IDX m_idx)
 {
-    const auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    const auto seen = (!player_ptr->effects()->blindness()->is_blind() && m_ptr->ml);
-    const auto maneable = player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx);
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &monster = floor.m_list[m_idx];
+    const auto seen = (!player_ptr->effects()->blindness()->is_blind() && monster.ml);
+    const auto maneable = floor.has_los({ monster.fy, monster.fx });
     return seen && maneable && (w_ptr->timewalk_m_idx == 0);
 }
index ad25303..40fead7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 6b1346a..264406c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの魔法によってフロアを明るくする処理及びその判定
  * @date 2020/07/23
  * @author Hourier
@@ -19,6 +19,7 @@
 #include "mspell/mspell-judgement.h"
 #include "player-base/player-class.h"
 #include "spell/range-calc.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -58,7 +59,7 @@ bool adjacent_grid_check(PlayerType *player_ptr, MonsterEntity *m_ptr, POSITION
     for (int i = 0; i < 8; i++) {
         int next_x = *xp + tonari_x[next][i];
         int next_y = *yp + tonari_y[next][i];
-        grid_type *g_ptr;
+        Grid *g_ptr;
         g_ptr = &player_ptr->current_floor_ptr->grid_array[next_y][next_x];
         if (!g_ptr->cave_has_flag(f_flag)) {
             continue;
@@ -83,8 +84,9 @@ void decide_lite_range(PlayerType *player_ptr, msa_type *msa_ptr)
     msa_ptr->y_br_lite = msa_ptr->y;
     msa_ptr->x_br_lite = msa_ptr->x;
     if (los(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y_br_lite, msa_ptr->x_br_lite)) {
-        auto *f_ptr = &terrains_info[player_ptr->current_floor_ptr->grid_array[msa_ptr->y_br_lite][msa_ptr->x_br_lite].feat];
-        if (f_ptr->flags.has_not(TerrainCharacteristics::LOS) && f_ptr->flags.has(TerrainCharacteristics::PROJECT) && one_in_(2)) {
+        const Pos2D pos(msa_ptr->y_br_lite, msa_ptr->x_br_lite);
+        const auto &terrain = player_ptr->current_floor_ptr->get_grid(pos).get_terrain();
+        if (terrain.flags.has_not(TerrainCharacteristics::LOS) && terrain.flags.has(TerrainCharacteristics::PROJECT) && one_in_(2)) {
             msa_ptr->ability_flags.reset(MonsterAbilityType::BR_LITE);
         }
     } else if (!adjacent_grid_check(player_ptr, msa_ptr->m_ptr, &msa_ptr->y_br_lite, &msa_ptr->x_br_lite, TerrainCharacteristics::LOS, los)) {
@@ -99,42 +101,53 @@ void decide_lite_range(PlayerType *player_ptr, msa_type *msa_ptr)
     msa_ptr->x_br_lite = 0;
 }
 
-static void feature_projection(FloorType *floor_ptr, msa_type *msa_ptr)
+static void feature_projection(const FloorType &floor, msa_type *msa_ptr)
 {
-    auto *f_ptr = &terrains_info[floor_ptr->grid_array[msa_ptr->y][msa_ptr->x].feat];
-    if (f_ptr->flags.has(TerrainCharacteristics::PROJECT)) {
+    const Pos2D pos(msa_ptr->y, msa_ptr->x);
+    const auto &terrain = floor.get_grid(pos).get_terrain();
+    if (terrain.flags.has(TerrainCharacteristics::PROJECT)) {
         return;
     }
 
-    if (msa_ptr->ability_flags.has(MonsterAbilityType::BR_DISI) && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI) && one_in_(2)) {
+    if (msa_ptr->ability_flags.has(MonsterAbilityType::BR_DISI) && terrain.flags.has(TerrainCharacteristics::HURT_DISI) && one_in_(2)) {
         msa_ptr->do_spell = DO_SPELL_BR_DISI;
         return;
     }
 
-    if (msa_ptr->ability_flags.has(MonsterAbilityType::BR_LITE) && f_ptr->flags.has(TerrainCharacteristics::LOS) && one_in_(2)) {
+    if (msa_ptr->ability_flags.has(MonsterAbilityType::BR_LITE) && terrain.flags.has(TerrainCharacteristics::LOS) && one_in_(2)) {
         msa_ptr->do_spell = DO_SPELL_BR_LITE;
     }
 }
 
 static void check_lite_area_by_mspell(PlayerType *player_ptr, msa_type *msa_ptr)
 {
-    if (msa_ptr->ability_flags.has(MonsterAbilityType::BR_DISI) && (msa_ptr->m_ptr->cdis < get_max_range(player_ptr) / 2) && in_disintegration_range(player_ptr->current_floor_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x) && (one_in_(10) || (projectable(player_ptr, msa_ptr->y, msa_ptr->x, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx) && one_in_(2)))) {
+    const auto &system = AngbandSystem::get_instance();
+    auto light_by_disintegration = msa_ptr->ability_flags.has(MonsterAbilityType::BR_DISI);
+    light_by_disintegration &= msa_ptr->m_ptr->cdis < system.get_max_range() / 2;
+    light_by_disintegration &= in_disintegration_range(player_ptr->current_floor_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x);
+    light_by_disintegration &= one_in_(10) || (projectable(player_ptr, msa_ptr->y, msa_ptr->x, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx) && one_in_(2));
+    if (light_by_disintegration) {
         msa_ptr->do_spell = DO_SPELL_BR_DISI;
         msa_ptr->success = true;
         return;
     }
 
-    if (msa_ptr->ability_flags.has(MonsterAbilityType::BR_LITE) && (msa_ptr->m_ptr->cdis < get_max_range(player_ptr) / 2) && los(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x) && one_in_(5)) {
+    auto light_by_lite = msa_ptr->ability_flags.has(MonsterAbilityType::BR_LITE);
+    light_by_lite &= msa_ptr->m_ptr->cdis < system.get_max_range() / 2;
+    light_by_lite &= los(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x);
+    light_by_lite &= one_in_(5);
+    if (light_by_lite) {
         msa_ptr->do_spell = DO_SPELL_BR_LITE;
         msa_ptr->success = true;
         return;
     }
 
-    if (msa_ptr->ability_flags.has_not(MonsterAbilityType::BA_LITE) || (msa_ptr->m_ptr->cdis > get_max_range(player_ptr))) {
+    if (msa_ptr->ability_flags.has_not(MonsterAbilityType::BA_LITE) || (msa_ptr->m_ptr->cdis > system.get_max_range())) {
         return;
     }
 
-    POSITION by = msa_ptr->y, bx = msa_ptr->x;
+    auto by = msa_ptr->y;
+    auto bx = msa_ptr->x;
     get_project_point(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, &by, &bx, 0L);
     if ((distance(by, bx, msa_ptr->y, msa_ptr->x) <= 3) && los(player_ptr, by, bx, msa_ptr->y, msa_ptr->x) && one_in_(5)) {
         msa_ptr->do_spell = DO_SPELL_BA_LITE;
@@ -142,7 +155,7 @@ static void check_lite_area_by_mspell(PlayerType *player_ptr, msa_type *msa_ptr)
     }
 }
 
-static void decide_lite_breath(PlayerType *player_ptr, msa_type *msa_ptr)
+static void decide_lite_breath(msa_type *msa_ptr)
 {
     if (msa_ptr->success) {
         return;
@@ -155,7 +168,11 @@ static void decide_lite_breath(PlayerType *player_ptr, msa_type *msa_ptr)
         msa_ptr->success = true;
     }
 
-    if ((msa_ptr->y_br_lite == 0) || (msa_ptr->x_br_lite == 0) || (msa_ptr->m_ptr->cdis > get_max_range(player_ptr) / 2) || !one_in_(5)) {
+    auto should_set = msa_ptr->y_br_lite == 0;
+    should_set |= msa_ptr->x_br_lite == 0;
+    should_set |= msa_ptr->m_ptr->cdis > AngbandSystem::get_instance().get_max_range() / 2;
+    should_set |= !one_in_(5);
+    if (should_set) {
         return;
     }
 
@@ -173,7 +190,7 @@ static void decide_lite_breath(PlayerType *player_ptr, msa_type *msa_ptr)
 bool decide_lite_projection(PlayerType *player_ptr, msa_type *msa_ptr)
 {
     if (projectable(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x)) {
-        feature_projection(player_ptr->current_floor_ptr, msa_ptr);
+        feature_projection(*player_ptr->current_floor_ptr, msa_ptr);
         return true;
     }
 
@@ -183,7 +200,7 @@ bool decide_lite_projection(PlayerType *player_ptr, msa_type *msa_ptr)
         msa_ptr->success = adjacent_grid_check(player_ptr, msa_ptr->m_ptr, &msa_ptr->y, &msa_ptr->x, TerrainCharacteristics::PROJECT, projectable);
     }
 
-    decide_lite_breath(player_ptr, msa_ptr);
+    decide_lite_breath(msa_ptr);
     return msa_ptr->success;
 }
 
@@ -194,13 +211,16 @@ void decide_lite_area(PlayerType *player_ptr, msa_type *msa_ptr)
     }
 
     PlayerClass pc(player_ptr);
-    bool can_use_lite_area = pc.equals(PlayerClassType::NINJA) && msa_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD) && msa_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::HURT_LITE) && (msa_ptr->r_ptr->brightness_flags.has_none_of(dark_mask));
+    auto can_use_lite_area = pc.equals(PlayerClassType::NINJA);
+    can_use_lite_area &= msa_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD);
+    can_use_lite_area &= msa_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::HURT_LITE);
+    can_use_lite_area &= (msa_ptr->r_ptr->brightness_flags.has_none_of(dark_mask));
 
     if (msa_ptr->r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) {
         return;
     }
 
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    if (player_ptr->current_floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         msa_ptr->ability_flags.reset(MonsterAbilityType::DARKNESS);
         return;
     }
index 6de1a5a..83b5159 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 0cf9ea3..ed46541 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include "system/angband.h"
 
 //! モンスターが魔法を使った際の結果。
index 52b4861..ffce4d2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターが詠唱する魔法を選択する処理
  * @date 2020/07/23
  * @author Hourier
@@ -8,12 +8,14 @@
 #include "mspell/mspell-selector.h"
 #include "floor/geometry.h"
 #include "monster-race/monster-race.h"
+#include "monster-race/race-ability-mask.h"
 #include "monster-race/race-flags2.h"
 #include "monster-race/race-indice-types.h"
 #include "monster/monster-status.h"
 #include "mspell/mspell-attack-util.h"
 #include "mspell/mspell-judgement.h"
 #include "player/player-status.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "world/world.h"
 
 /*!
- * @brief 指定したID値が指定した範囲内のIDかどうかを返す
- *
- * enum値に対して範囲で判定するのはあまり好ましくないが、歴史的経緯により仕方がない
- *
- * @param spell 判定対象のID
- * @param start 範囲の開始ID
- * @param end 範囲の終了ID(このIDも含む)
- * @return IDが start <= spell <= end なら true、そうでなければ false
- */
-static bool spell_in_between(MonsterAbilityType spell, MonsterAbilityType start, MonsterAbilityType end)
-{
-    auto spell_int = enum2i(spell);
-    return enum2i(start) <= spell_int && spell_int <= enum2i(end);
-}
-
-/*!
  * @brief ID値が攻撃魔法のIDかどうかを返す /
  * Return TRUE if a spell is good for hurting the player (directly).
  * @param spell 判定対象のID
@@ -45,42 +31,7 @@ static bool spell_in_between(MonsterAbilityType spell, MonsterAbilityType start,
  */
 static bool spell_attack(MonsterAbilityType spell)
 {
-    /* All RF4 spells hurt (except for shriek and dispel) */
-    if (spell_in_between(spell, MonsterAbilityType::ROCKET, MonsterAbilityType::BR_DISI)) {
-        return true;
-    }
-    if (spell_in_between(spell, MonsterAbilityType::BR_VOID, MonsterAbilityType::BR_ABYSS)) {
-        return true;
-    }
-
-    /* Various "ball" spells */
-    if (spell_in_between(spell, MonsterAbilityType::BA_ACID, MonsterAbilityType::BA_DARK)) {
-        return true;
-    }
-    if (spell_in_between(spell, MonsterAbilityType::BA_VOID, MonsterAbilityType::BA_ABYSS)) {
-        return true;
-    }
-
-    /* "Cause wounds" and "bolt" spells */
-    if (spell_in_between(spell, MonsterAbilityType::CAUSE_1, MonsterAbilityType::MISSILE)) {
-        return true;
-    }
-    if (spell_in_between(spell, MonsterAbilityType::BO_VOID, MonsterAbilityType::BO_ABYSS)) {
-        return true;
-    }
-
-    /* Hand of Doom */
-    if (spell == MonsterAbilityType::HAND_DOOM) {
-        return true;
-    }
-
-    /* Psycho-Spear */
-    if (spell == MonsterAbilityType::PSY_SPEAR) {
-        return true;
-    }
-
-    /* Doesn't hurt */
-    return false;
+    return RF_ABILITY_ATTACK_SPELLS_MASK.has(spell);
 }
 
 /*!
@@ -113,38 +64,7 @@ static bool spell_escape(MonsterAbilityType spell)
  */
 static bool spell_annoy(MonsterAbilityType spell)
 {
-    /* Shriek */
-    if (spell == MonsterAbilityType::SHRIEK) {
-        return true;
-    }
-
-    /* Brain smash, et al (added curses) */
-    if (spell_in_between(spell, MonsterAbilityType::DRAIN_MANA, MonsterAbilityType::CAUSE_4)) {
-        return true;
-    }
-
-    /* Scare, confuse, blind, slow, paralyze */
-    if (spell_in_between(spell, MonsterAbilityType::SCARE, MonsterAbilityType::HOLD)) {
-        return true;
-    }
-
-    /* Teleport to */
-    if (spell == MonsterAbilityType::TELE_TO) {
-        return true;
-    }
-
-    /* Teleport level */
-    if (spell == MonsterAbilityType::TELE_LEVEL) {
-        return true;
-    }
-
-    /* Darkness, make traps, cause amnesia */
-    if (spell_in_between(spell, MonsterAbilityType::TRAPS, MonsterAbilityType::RAISE_DEAD)) {
-        return true;
-    }
-
-    /* Doesn't annoy */
-    return false;
+    return RF_ABILITY_ANNOY_SPELLS_MASK.has(spell);
 }
 
 /*!
@@ -155,7 +75,7 @@ static bool spell_annoy(MonsterAbilityType spell)
  */
 static bool spell_summon(MonsterAbilityType spell)
 {
-    return spell_in_between(spell, MonsterAbilityType::S_KIN, MonsterAbilityType::S_UNIQUE);
+    return RF_ABILITY_SUMMON_MASK.has(spell);
 }
 
 /*!
@@ -220,9 +140,9 @@ static bool spell_world(MonsterAbilityType spell)
  * @param spell 判定対象のID
  * @return 特別効果魔法のIDならばTRUEを返す。
  */
-static bool spell_special(PlayerType *player_ptr, MonsterAbilityType spell)
+static bool spell_special(MonsterAbilityType spell)
 {
-    if (player_ptr->phase_out) {
+    if (AngbandSystem::get_instance().is_phase_out()) {
         return false;
     }
 
@@ -263,6 +183,28 @@ static bool spell_dispel(MonsterAbilityType spell)
 }
 
 /*!
+ * @brief 特殊魔法を使用する確率の判定
+ * @param r_idx モンスター種族ID
+ * @return 特殊魔法を使用するか否か
+ * @details 分離/合体ユニークは常に使用しない (その前に判定済のため).
+ */
+static bool decide_select_special(MonsterRaceId r_idx)
+{
+    if (MonraceList::get_instance().is_separated(r_idx)) {
+        return false;
+    }
+
+    switch (r_idx) {
+    case MonsterRaceId::OHMU:
+        return false;
+    case MonsterRaceId::ROLENTO:
+        return randint0(100) < 40;
+    default:
+        return randint0(100) < 50;
+    }
+}
+
+/*!
  * @brief モンスターの魔法選択ルーチン
  * Have a monster choose a spell from a list of "useful" spells.
  * @param player_ptr プレイヤーへの参照ポインタ
@@ -300,9 +242,9 @@ MonsterAbilityType choose_attack_spell(PlayerType *player_ptr, msa_type *msa_ptr
     std::vector<MonsterAbilityType> dispel;
 
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[msa_ptr->m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->flags2 & RF2_STUPID) {
-        return msa_ptr->mspells[randint0(msa_ptr->mspells.size())];
+        return rand_choice(msa_ptr->mspells);
     }
 
     for (size_t i = 0; i < msa_ptr->mspells.size(); i++) {
@@ -338,7 +280,7 @@ MonsterAbilityType choose_attack_spell(PlayerType *player_ptr, msa_type *msa_ptr
             world.push_back(msa_ptr->mspells[i]);
         }
 
-        if (spell_special(player_ptr, msa_ptr->mspells[i])) {
+        if (spell_special(msa_ptr->mspells[i])) {
             special.push_back(msa_ptr->mspells[i]);
         }
 
@@ -360,117 +302,88 @@ MonsterAbilityType choose_attack_spell(PlayerType *player_ptr, msa_type *msa_ptr
     }
 
     if (!world.empty() && (randint0(100) < 15) && !w_ptr->timewalk_m_idx) {
-        return world[randint0(world.size())];
+        return rand_choice(world);
     }
 
-    if (!special.empty()) {
-        bool success = false;
-        switch (m_ptr->r_idx) {
-        case MonsterRaceId::BANOR:
-        case MonsterRaceId::LUPART:
-            if ((m_ptr->hp < m_ptr->maxhp / 2) && monraces_info[MonsterRaceId::BANOR].max_num && monraces_info[MonsterRaceId::LUPART].max_num) {
-                success = true;
-            }
-            break;
-        default:
-            break;
-        }
-
-        if (success) {
-            return special[randint0(special.size())];
-        }
+    const auto &monrace_list = MonraceList::get_instance();
+    if (!special.empty() && monrace_list.can_select_separate(m_ptr->r_idx, m_ptr->hp, m_ptr->maxhp)) {
+        return rand_choice(special);
     }
 
     if (m_ptr->hp < m_ptr->maxhp / 3 && one_in_(2)) {
         if (!heal.empty()) {
-            return heal[randint0(heal.size())];
+            return rand_choice(heal);
         }
     }
 
     if (((m_ptr->hp < m_ptr->maxhp / 3) || m_ptr->is_fearful()) && one_in_(2)) {
         if (!escape.empty()) {
-            return escape[randint0(escape.size())];
+            return rand_choice(escape);
         }
     }
 
     if (!special.empty()) {
-        bool success = false;
-        switch (m_ptr->r_idx) {
-        case MonsterRaceId::OHMU:
-        case MonsterRaceId::BANOR:
-        case MonsterRaceId::LUPART:
-            break;
-        case MonsterRaceId::BANORLUPART:
-            if (randint0(100) < 70) {
-                success = true;
-            }
-            break;
-        case MonsterRaceId::ROLENTO:
-            if (randint0(100) < 40) {
-                success = true;
-            }
-            break;
-        default:
-            if (randint0(100) < 50) {
-                success = true;
-            }
-            break;
-        }
-        if (success) {
-            return special[randint0(special.size())];
+        const auto r_idx = m_ptr->r_idx;
+        auto should_select_special = monrace_list.is_unified(r_idx) && (randint0(100) < 70);
+        should_select_special |= decide_select_special(r_idx);
+        if (should_select_special) {
+            return rand_choice(special);
         }
     }
 
-    if ((distance(player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx) < 4) && (!attack.empty() || r_ptr->ability_flags.has(MonsterAbilityType::TRAPS)) && (randint0(100) < 75) && !w_ptr->timewalk_m_idx) {
-        if (!tactic.empty()) {
-            return tactic[randint0(tactic.size())];
-        }
+    auto should_select_tactic = distance(player_ptr->y, player_ptr->x, m_ptr->fy, m_ptr->fx) < 4;
+    should_select_tactic &= !attack.empty() || r_ptr->ability_flags.has(MonsterAbilityType::TRAPS);
+    should_select_tactic &= randint0(100) < 75;
+    should_select_tactic &= w_ptr->timewalk_m_idx == 0;
+    should_select_tactic &= !tactic.empty();
+    if (should_select_tactic) {
+        return rand_choice(tactic);
     }
 
     if (!summon.empty() && (randint0(100) < 40)) {
-        return summon[randint0(summon.size())];
+        return rand_choice(summon);
     }
 
     if (!dispel.empty() && one_in_(2)) {
         if (dispel_check(player_ptr, msa_ptr->m_idx)) {
-            return dispel[randint0(dispel.size())];
+            return rand_choice(dispel);
         }
     }
 
     if (!raise.empty() && (randint0(100) < 40)) {
-        return raise[randint0(raise.size())];
+        return rand_choice(raise);
     }
 
     if (is_invuln(player_ptr)) {
         if (!psy_spe.empty() && (randint0(100) < 50)) {
-            return psy_spe[randint0(psy_spe.size())];
+            return rand_choice(psy_spe);
         } else if (!attack.empty() && (randint0(100) < 40)) {
-            return attack[randint0(attack.size())];
+            return rand_choice(attack);
         }
     } else if (!attack.empty() && (randint0(100) < 85)) {
-        return attack[randint0(attack.size())];
+        return rand_choice(attack);
     }
 
     if (!tactic.empty() && (randint0(100) < 50) && !w_ptr->timewalk_m_idx) {
-        return tactic[randint0(tactic.size())];
+        return rand_choice(tactic);
     }
 
     if (!invul.empty() && !m_ptr->mtimed[MTIMED_INVULNER] && (randint0(100) < 50)) {
-        return invul[randint0(invul.size())];
+        return rand_choice(invul);
     }
 
     if ((m_ptr->hp < m_ptr->maxhp * 3 / 4) && (randint0(100) < 25)) {
         if (!heal.empty()) {
-            return heal[randint0(heal.size())];
+            return rand_choice(heal);
         }
     }
 
     if (!haste.empty() && (randint0(100) < 20) && !m_ptr->is_accelerated()) {
-        return haste[randint0(haste.size())];
+        return rand_choice(haste);
     }
 
     if (!annoy.empty() && (randint0(100) < 80)) {
-        return annoy[randint0(annoy.size())];
+        return rand_choice(annoy);
     }
 
     return MonsterAbilityType::MAX;
index 9bbea80..e88f617 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index abd035e..a7c40ec 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 特殊な行動を取るモンスターの具体的な行動定義 (MonsterRaceDefinitionsのSPECIALフラグ)
  * @date 2020/05/16
  * @author Hourier
@@ -6,7 +6,6 @@
 
 #include "mspell/mspell-special.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
 #include "player/player-damage.h"
 #include "spell-kind/spells-teleport.h"
 #include "spell-realm/spells-crusade.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
+#include <algorithm>
+#include <sstream>
 
 /*!
- * @brief ã\83\90ã\83¼ã\83\8eã\83¼ã\83«ã\83»ã\83«ã\83\91ã\83¼ã\83\88ã\81®RF6_SPECIALã\81®å\87¦ç\90\86ã\80\82å\88\86è£\82ã\83»å\90\88ä½\93ã\80\82 /
+ * @brief ã\83¦ã\83\8bã\83¼ã\82¯ã\81®å\88\86é\9b¢ã\83»å\90\88ä½\93å\87¦ç\90\86
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param m_idx 呪文を唱えるモンスターID
  */
-static MonsterSpellResult spell_RF6_SPECIAL_BANORLUPART(PlayerType *player_ptr, MONSTER_IDX m_idx)
+static MonsterSpellResult spell_RF6_SPECIAL_UNIFICATION(PlayerType *player_ptr, MONSTER_IDX m_idx)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    int dummy_hp, dummy_maxhp;
-    POSITION dummy_y = m_ptr->fy;
-    POSITION dummy_x = m_ptr->fx;
-    BIT_FLAGS mode = 0L;
-
+    auto dummy_y = m_ptr->fy;
+    auto dummy_x = m_ptr->fx;
     if (see_monster(player_ptr, m_idx) && monster_near_player(floor_ptr, m_idx, 0)) {
         disturb(player_ptr, true, true);
     }
 
-    switch (m_ptr->r_idx) {
-    case MonsterRaceId::BANORLUPART:
-        dummy_hp = (m_ptr->hp + 1) / 2;
-        dummy_maxhp = m_ptr->maxhp / 2;
-
-        if (floor_ptr->inside_arena || player_ptr->phase_out || !summon_possible(player_ptr, m_ptr->fy, m_ptr->fx)) {
+    const auto &monraces = MonraceList::get_instance();
+    const auto &unified_uniques = MonraceList::get_unified_uniques();
+    if (const auto it_unified = unified_uniques.find(m_ptr->r_idx); it_unified != unified_uniques.end()) {
+        const int separates_size = it_unified->second.size();
+        const auto separated_hp = (m_ptr->hp + 1) / separates_size;
+        const auto separated_maxhp = m_ptr->maxhp / separates_size;
+        if (floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out() || !summon_possible(player_ptr, m_ptr->fy, m_ptr->fx)) {
             return MonsterSpellResult::make_invalid();
         }
 
         delete_monster_idx(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].m_idx);
-        summon_named_creature(player_ptr, 0, dummy_y, dummy_x, MonsterRaceId::BANOR, mode);
-        floor_ptr->m_list[hack_m_idx_ii].hp = dummy_hp;
-        floor_ptr->m_list[hack_m_idx_ii].maxhp = dummy_maxhp;
-        summon_named_creature(player_ptr, 0, dummy_y, dummy_x, MonsterRaceId::LUPART, mode);
-        floor_ptr->m_list[hack_m_idx_ii].hp = dummy_hp;
-        floor_ptr->m_list[hack_m_idx_ii].maxhp = dummy_maxhp;
-
-        msg_print(_("『バーノール・ルパート』が分裂した!", "Banor=Rupart splits into two persons!"));
-        break;
-
-    case MonsterRaceId::BANOR:
-    case MonsterRaceId::LUPART:
-        dummy_hp = 0;
-        dummy_maxhp = 0;
-
-        if (!monraces_info[MonsterRaceId::BANOR].cur_num || !monraces_info[MonsterRaceId::LUPART].cur_num) {
+        for (const auto separate : it_unified->second) {
+            summon_named_creature(player_ptr, 0, dummy_y, dummy_x, separate, MD_NONE);
+            floor_ptr->m_list[hack_m_idx_ii].hp = separated_hp;
+            floor_ptr->m_list[hack_m_idx_ii].maxhp = separated_maxhp;
+        }
+
+        const auto &m_name = monraces[it_unified->first].name;
+        msg_format(_("%sが分離した!", "%s splits!"), m_name.data());
+        return MonsterSpellResult::make_valid();
+    }
+
+    for (const auto &[unified_unique, separates] : unified_uniques) {
+        if (!separates.contains(m_ptr->r_idx)) {
+            continue;
+        }
+
+        if (!monraces.exists_separates(unified_unique)) {
             return MonsterSpellResult::make_invalid();
         }
 
-        for (MONSTER_IDX k = 1; k < floor_ptr->m_max; k++) {
-            if (floor_ptr->m_list[k].r_idx == MonsterRaceId::BANOR || floor_ptr->m_list[k].r_idx == MonsterRaceId::LUPART) {
-                dummy_hp += floor_ptr->m_list[k].hp;
-                dummy_maxhp += floor_ptr->m_list[k].maxhp;
-                if (floor_ptr->m_list[k].r_idx != m_ptr->r_idx) {
-                    dummy_y = floor_ptr->m_list[k].fy;
-                    dummy_x = floor_ptr->m_list[k].fx;
-                }
-                delete_monster_idx(player_ptr, k);
+        auto unified_hp = 0;
+        auto unified_maxhp = 0;
+        for (short k = 1; k < floor_ptr->m_max; k++) {
+            const auto &monster = floor_ptr->m_list[k];
+            if (!separates.contains(monster.r_idx)) {
+                continue;
             }
+
+            unified_hp += monster.hp;
+            unified_maxhp += monster.maxhp;
+            if (monster.r_idx != m_ptr->r_idx) {
+                dummy_y = monster.fy;
+                dummy_x = monster.fx;
+            }
+
+            delete_monster_idx(player_ptr, k);
         }
-        summon_named_creature(player_ptr, 0, dummy_y, dummy_x, MonsterRaceId::BANORLUPART, mode);
-        floor_ptr->m_list[hack_m_idx_ii].hp = dummy_hp;
-        floor_ptr->m_list[hack_m_idx_ii].maxhp = dummy_maxhp;
 
-        msg_print(_("『バーノール』と『ルパート』が合体した!", "Banor and Rupart combine into one!"));
-        break;
+        summon_named_creature(player_ptr, 0, dummy_y, dummy_x, unified_unique, MD_NONE);
+        floor_ptr->m_list[hack_m_idx_ii].hp = unified_hp;
+        floor_ptr->m_list[hack_m_idx_ii].maxhp = unified_maxhp;
+        std::vector<std::string> m_names;
+        for (const auto &separate : separates) {
+            const auto &monrace = monraces[separate];
+            m_names.push_back(monrace.name);
+        }
 
-    default:
-        break;
+        std::stringstream ss;
+        ss << *m_names.begin();
+        for (size_t i = 1; i < m_names.size(); i++) { // @todo clang v14 はstd::views::drop() 非対応
+            const auto &m_name = m_names[i];
+            ss << _("と", " and ");
+            ss << m_name;
+        }
+
+        const auto fmt = _("%sが合体した!", "%s combine into one!");
+        msg_print(format(fmt, ss.str().data()));
+        return MonsterSpellResult::make_valid();
     }
 
     return MonsterSpellResult::make_valid();
@@ -164,10 +184,10 @@ static MonsterSpellResult spell_RF6_SPECIAL_B(PlayerType *player_ptr, POSITION y
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto *m_ptr = &floor_ptr->m_list[m_idx];
     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
     bool monster_to_player = (target_type == MONSTER_TO_PLAYER);
     bool monster_to_monster = (target_type == MONSTER_TO_MONSTER);
-    bool direct = player_bold(player_ptr, y, x);
+    bool direct = player_ptr->is_located_at({ y, x });
     const auto m_name = monster_name(player_ptr, m_idx);
 
     disturb(player_ptr, true, true);
@@ -178,7 +198,7 @@ static MonsterSpellResult spell_RF6_SPECIAL_B(PlayerType *player_ptr, POSITION y
         simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
 
         teleport_away(player_ptr, m_idx, 10, TELEPORT_NONMAGICAL);
-        player_ptr->update |= (PU_MONSTER_STATUSES);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
         return MonsterSpellResult::make_valid();
     }
 
@@ -212,7 +232,7 @@ static MonsterSpellResult spell_RF6_SPECIAL_B(PlayerType *player_ptr, POSITION y
     dam += damroll(6, 8);
 
     if (monster_to_player || (monster_to_monster && player_ptr->riding == t_idx)) {
-        int get_damage = take_hit(player_ptr, DAMAGE_NOESCAPE, dam, m_name.data());
+        int get_damage = take_hit(player_ptr, DAMAGE_NOESCAPE, dam, m_name);
         if (player_ptr->tim_eyeeye && get_damage > 0 && !player_ptr->is_dead) {
             const auto m_name_self = monster_desc(player_ptr, m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE | MD_OBJECTIVE);
             msg_print(_(format("攻撃が%s自身を傷つけた!", m_name.data()), format("The attack of %s has wounded %s!", m_name.data(), m_name_self.data())));
@@ -223,11 +243,11 @@ static MonsterSpellResult spell_RF6_SPECIAL_B(PlayerType *player_ptr, POSITION y
 
     if (monster_to_player && player_ptr->riding) {
         const auto &m_ref = floor_ptr->m_list[player_ptr->riding];
-        mon_take_hit_mon(player_ptr, player_ptr->riding, dam, &dead, &fear, extract_note_dies(m_ref.get_real_r_idx()), m_idx);
+        mon_take_hit_mon(player_ptr, player_ptr->riding, dam, &dead, &fear, m_ref.get_died_message(), m_idx);
     }
 
     if (monster_to_monster) {
-        mon_take_hit_mon(player_ptr, t_idx, dam, &dead, &fear, extract_note_dies(t_ptr->get_real_r_idx()), m_idx);
+        mon_take_hit_mon(player_ptr, t_idx, dam, &dead, &fear, t_ptr->get_died_message(), m_idx);
     }
 
     return MonsterSpellResult::make_valid();
@@ -246,29 +266,24 @@ static MonsterSpellResult spell_RF6_SPECIAL_B(PlayerType *player_ptr, POSITION y
  */
 MonsterSpellResult spell_RF6_SPECIAL(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *m_ptr = &floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &monster = floor.m_list[m_idx];
+    const auto &monrace = monster.get_monrace();
+    const auto r_idx = monster.r_idx;
+    if (MonraceList::get_instance().can_unify_separate(r_idx)) {
+        return spell_RF6_SPECIAL_UNIFICATION(player_ptr, m_idx);
+    }
 
-    switch (m_ptr->r_idx) {
+    switch (r_idx) {
     case MonsterRaceId::OHMU:
         return MonsterSpellResult::make_invalid();
-
-    case MonsterRaceId::BANORLUPART:
-    case MonsterRaceId::BANOR:
-    case MonsterRaceId::LUPART:
-        return spell_RF6_SPECIAL_BANORLUPART(player_ptr, m_idx);
-
     case MonsterRaceId::ROLENTO:
         return spell_RF6_SPECIAL_ROLENTO(player_ptr, y, x, m_idx, t_idx, target_type);
-        break;
-
     default:
-        if (r_ptr->d_char == 'B') {
+        if (monrace.d_char == 'B') {
             return spell_RF6_SPECIAL_B(player_ptr, y, x, m_idx, t_idx, target_type);
-            break;
-        } else {
-            return MonsterSpellResult::make_invalid();
         }
+
+        return MonsterSpellResult::make_invalid();
     }
 }
index 797eac5..0166884 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 6d33cf2..51da8c7 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーのステータスを下げるか、モンスター自身のステータスを上げるスペル類の処理
  * @date 2020/05/16
  * @author Hourier
@@ -8,7 +8,6 @@
 #include "mspell/mspell-status.h"
 #include "blue-magic/blue-magic-checker.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-processor.h"
 #include "mind/drs-types.h"
@@ -35,6 +34,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
@@ -254,7 +254,7 @@ MonsterSpellResult spell_RF5_SCARE(MONSTER_IDX m_idx, PlayerType *player_ptr, MO
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
     bool resist, saving_throw;
 
@@ -280,7 +280,7 @@ MonsterSpellResult spell_RF5_SCARE(MONSTER_IDX m_idx, PlayerType *player_ptr, MO
         return res;
     }
 
-    resist = ((tr_ptr->flags3 & RF3_NO_FEAR) != 0);
+    resist = (tr_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR));
     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
 
     mspell_cast_msg_bad_status_to_monster msg(_("%s^が恐ろしげな幻覚を作り出した。", "%s^ casts a fearful illusion in front of %s."),
@@ -311,7 +311,7 @@ MonsterSpellResult spell_RF5_BLIND(MONSTER_IDX m_idx, PlayerType *player_ptr, MO
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
     bool resist, saving_throw;
 
@@ -346,7 +346,7 @@ MonsterSpellResult spell_RF5_BLIND(MONSTER_IDX m_idx, PlayerType *player_ptr, MO
         msg_default = _("%sは呪文を唱えて%sの目を焼き付かせた。", "%s^ casts a spell, burning %s's eyes.");
     }
 
-    resist = ((tr_ptr->flags3 & RF3_NO_CONF) != 0);
+    resist = (tr_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF));
     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
 
     mspell_cast_msg_bad_status_to_monster msg(msg_default, _("%s^には効果がなかった。", "%s^ is unaffected."),
@@ -376,7 +376,7 @@ MonsterSpellResult spell_RF5_CONF(MONSTER_IDX m_idx, PlayerType *player_ptr, MON
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
     bool resist, saving_throw;
 
@@ -403,7 +403,7 @@ MonsterSpellResult spell_RF5_CONF(MONSTER_IDX m_idx, PlayerType *player_ptr, MON
         return res;
     }
 
-    resist = ((tr_ptr->flags3 & RF3_NO_CONF) != 0);
+    resist = (tr_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF));
     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
 
     mspell_cast_msg_bad_status_to_monster msg(_("%s^が%sの前に幻惑的な幻をつくり出した。", "%s^ casts a mesmerizing illusion in front of %s."),
@@ -434,7 +434,7 @@ MonsterSpellResult spell_RF5_HOLD(MONSTER_IDX m_idx, PlayerType *player_ptr, MON
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
     bool resist, saving_throw;
 
@@ -460,7 +460,7 @@ MonsterSpellResult spell_RF5_HOLD(MONSTER_IDX m_idx, PlayerType *player_ptr, MON
         return res;
     }
 
-    resist = (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || (tr_ptr->flags3 & RF3_NO_STUN) != 0);
+    resist = (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || tr_ptr->resistance_flags.has(MonsterResistanceType::NO_STUN));
     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
 
     mspell_cast_msg_bad_status_to_monster msg(_("%s^は%sをじっと見つめた。", "%s^ stares intently at %s."),
@@ -522,7 +522,7 @@ MonsterSpellResult spell_RF5_SLOW(MONSTER_IDX m_idx, PlayerType *player_ptr, MON
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
-    MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
+    MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
     bool resist, saving_throw;
 
@@ -617,12 +617,13 @@ MonsterSpellResult spell_RF6_HEAL(PlayerType *player_ptr, MONSTER_IDX m_idx, MON
     }
 
     monspell_message_base(player_ptr, m_idx, t_idx, msg, !seen, target_type);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->health_who == m_idx) {
-        player_ptr->redraw |= (PR_HEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
     }
+
     if (player_ptr->riding == m_idx) {
-        player_ptr->redraw |= (PR_UHEALTH);
+        rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
     }
 
     if (!m_ptr->is_fearful()) {
index 9221893..465c4b4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 4d50372..5cc3a00 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-summon.h"
+#include "mspell/mspell-summon.h"
 #include "core/disturbance.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
@@ -110,7 +110,7 @@ static void decide_summon_kin_caster(
             msg_format(_("%s^が何かをつぶやいた。", "%s^ mumbles."), m_name);
         }
     } else if (mon_to_player || (mon_to_mon && known && see_either)) {
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
 #ifdef JP
         (void)m_poss;
 #endif
@@ -579,7 +579,7 @@ MonsterSpellResult spell_RF6_S_ANGEL(PlayerType *player_ptr, POSITION y, POSITIO
     summon_disturb(player_ptr, target_type, known, see_either);
 
     auto *m_ptr = &floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     int num = 1;
     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
         num += r_ptr->level / 40;
@@ -969,3 +969,49 @@ MonsterSpellResult spell_RF6_S_UNIQUE(PlayerType *player_ptr, POSITION y, POSITI
 
     return res;
 }
+
+/*!
+ * @brief RF6_S_DEAD_UNIQUEの処理。撃破済みユニーク・モンスターをクローンとして召喚。 /
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @param y 対象の地点のy座標
+ * @param x 対象の地点のx座標
+ * @param m_idx 呪文を唱えるモンスターID
+ * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
+ * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象ならラーニング可。
+ */
+MonsterSpellResult spell_RF6_S_DEAD_UNIQUE(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
+{
+    auto *floor_ptr = player_ptr->current_floor_ptr;
+    auto rlev = monster_level_idx(floor_ptr, m_idx);
+    auto mon_to_mon = (target_type == MONSTER_TO_MONSTER);
+    auto mon_to_player = (target_type == MONSTER_TO_PLAYER);
+    auto see_either = see_monster(player_ptr, m_idx) || see_monster(player_ptr, t_idx);
+    auto known = monster_near_player(floor_ptr, m_idx, t_idx);
+
+    mspell_cast_msg_blind msg(_("%^sが何かをつぶやいた。", "%^s mumbles."),
+        _("%s^が魔法で特別な強敵を蘇らせた!", "%^s magically animates special opponents!"),
+        _("%s^が魔法で特別な強敵を蘇らせた!", "%^s magically animates special opponents!"));
+
+    monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
+    summon_disturb(player_ptr, target_type, known, see_either);
+
+    auto count = 0;
+    for (auto k = 0; k < S_NUM_4; k++) {
+        count += summon_specific(player_ptr, m_idx, y, x, rlev, SUMMON_DEAD_UNIQUE, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_CLONE));
+    }
+
+    if (player_ptr->effects()->blindness()->is_blind() && count && mon_to_player) {
+        msg_format(_("多くの力強いものが間近に蘇った音が聞こえる。", "You hear many powerful things animate nearby."));
+    }
+
+    if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(player_ptr, t_idx) && count && mon_to_mon) {
+        floor_ptr->monster_noise = true;
+    }
+
+    auto res = MonsterSpellResult::make_valid();
+    res.learnable = target_type == MONSTER_TO_PLAYER;
+
+    return res;
+}
index 0974683..eb8bad5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -21,3 +21,4 @@ MonsterSpellResult spell_RF6_S_HI_UNDEAD(PlayerType *player_ptr, POSITION y, POS
 MonsterSpellResult spell_RF6_S_HI_DRAGON(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type);
 MonsterSpellResult spell_RF6_S_AMBERITES(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type);
 MonsterSpellResult spell_RF6_S_UNIQUE(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type);
+MonsterSpellResult spell_RF6_S_DEAD_UNIQUE(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type);
index 8a6c393..478242f 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/mspell-util.h"
+#include "mspell/mspell-util.h"
 #include "core/disturbance.h"
 #include "floor/geometry.h"
 #include "grid/grid.h"
@@ -76,18 +76,18 @@ bool monspell_message_base(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_ID
 
     if (msg_flag_aux) {
         if (mon_to_player) {
-            msg_format(msgs.to_player_true, m_name.data());
+            msg_format(msgs.to_player_true.data(), m_name.data());
             notice = true;
         } else if (mon_to_mon && known && see_either) {
-            msg_format(msgs.to_mons_true, m_name.data());
+            msg_format(msgs.to_mons_true.data(), m_name.data());
             notice = true;
         }
     } else {
         if (mon_to_player) {
-            msg_format(msgs.to_player_false, m_name.data());
+            msg_format(msgs.to_player_false.data(), m_name.data());
             notice = true;
         } else if (mon_to_mon && known && see_either) {
-            msg_format(msgs.to_mons_false, m_name.data(), t_name.data());
+            msg_format(msgs.to_mons_false.data(), m_name.data(), t_name.data());
             notice = true;
         }
     }
index 8bfef6f..1c62a8a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 729ee5a..7d7f46c 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/smart-mspell-util.h"
+#include "mspell/smart-mspell-util.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-ability-flags.h"
 #include "monster-race/race-flags2.h"
@@ -8,13 +8,11 @@
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 
-msr_type *initialize_msr_type(PlayerType *player_ptr, msr_type *msr_ptr, MONSTER_IDX m_idx, const EnumClassFlagGroup<MonsterAbilityType> &ability_flags)
+msr_type::msr_type(PlayerType *player_ptr, short m_idx, const EnumClassFlagGroup<MonsterAbilityType> &ability_flags)
+    : ability_flags(ability_flags)
 {
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    msr_ptr->r_ptr = &monraces_info[m_ptr->r_idx];
-    msr_ptr->ability_flags = ability_flags;
-    msr_ptr->smart.clear();
-    return msr_ptr;
+    this->r_ptr = &m_ptr->get_monrace();
 }
 
 /*!
@@ -24,7 +22,7 @@ msr_type *initialize_msr_type(PlayerType *player_ptr, msr_type *msr_ptr, MONSTER
  * @param prob 基本確率(%)
  * @return 適した選択を取るならばTRUEを返す。
  */
-bool int_outof(MonsterRaceInfo *r_ptr, PERCENTAGE prob)
+bool int_outof(MonsterRaceInfo *r_ptr, int prob)
 {
     if (r_ptr->behavior_flags.has_not(MonsterBehaviorType::SMART)) {
         prob = prob / 2;
index f3ff4a0..a5ff308 100644 (file)
@@ -1,18 +1,17 @@
-#pragma once
+#pragma once
 
 #include "monster-race/race-ability-flags.h"
 #include "monster/smart-learn-types.h"
-#include "system/angband.h"
 #include "util/flag-group.h"
 
 // Monster Spell Remover.
 class MonsterRaceInfo;
+class PlayerType;
 struct msr_type {
+    msr_type(PlayerType *player_ptr, short m_idx, const EnumClassFlagGroup<MonsterAbilityType> &ability_flags);
     MonsterRaceInfo *r_ptr;
     EnumClassFlagGroup<MonsterAbilityType> ability_flags;
-    EnumClassFlagGroup<MonsterSmartLearnType> smart;
+    EnumClassFlagGroup<MonsterSmartLearnType> smart_flags{};
 };
 
-class PlayerType;
-msr_type *initialize_msr_type(PlayerType *player_ptr, msr_type *msr_ptr, MONSTER_IDX m_idx, const EnumClassFlagGroup<MonsterAbilityType> &ability_flags);
-bool int_outof(MonsterRaceInfo *r_ptr, PERCENTAGE prob);
+bool int_outof(MonsterRaceInfo *r_ptr, int prob);
index e090537..53caf56 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/specified-summon.h"
+#include "mspell/specified-summon.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
 #include "floor/cave.h"
index 54adf8f..f1b5752 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 307f2cb..ea36fb1 100644 (file)
@@ -1,4 +1,4 @@
-#include "mspell/summon-checker.h"
+#include "mspell/summon-checker.h"
 #include "monster-attack/monster-attack-table.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
@@ -9,10 +9,11 @@
 #include "monster-race/race-flags8.h"
 #include "monster-race/race-indice-types.h"
 #include "monster/monster-util.h"
-#include "player-info/race-info.h"
+#include "player-base/player-race.h"
 #include "spell/summon-types.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 
 /*!
  */
 bool check_summon_specific(PlayerType *player_ptr, MonsterRaceId summoner_idx, MonsterRaceId r_idx)
 {
-    auto *r_ptr = &monraces_info[r_idx];
-    bool is_match = false;
+    const auto &monrace = monraces_info[r_idx];
     switch (summon_specific_type) {
     case SUMMON_ANT:
-        is_match = r_ptr->d_char == 'a';
-        break;
+        return monrace.d_char == 'a';
     case SUMMON_SPIDER:
-        is_match = r_ptr->d_char == 'S';
-        break;
+        return monrace.d_char == 'S';
     case SUMMON_HOUND:
-        is_match = (r_ptr->d_char == 'C') || (r_ptr->d_char == 'Z');
-        break;
+        return (monrace.d_char == 'C') || (monrace.d_char == 'Z');
     case SUMMON_HYDRA:
-        is_match = r_ptr->d_char == 'M';
-        break;
+        return monrace.d_char == 'M';
     case SUMMON_ANGEL:
-        is_match = (r_ptr->d_char == 'A') && ((r_ptr->kind_flags.has(MonsterKindType::EVIL)) || (r_ptr->kind_flags.has(MonsterKindType::GOOD)));
-        break;
+        return (monrace.d_char == 'A') && ((monrace.kind_flags.has(MonsterKindType::EVIL)) || (monrace.kind_flags.has(MonsterKindType::GOOD)));
     case SUMMON_DEMON:
-        is_match = r_ptr->kind_flags.has(MonsterKindType::DEMON);
-        break;
+        return monrace.kind_flags.has(MonsterKindType::DEMON);
     case SUMMON_UNDEAD:
-        is_match = r_ptr->kind_flags.has(MonsterKindType::UNDEAD);
-        break;
+        return monrace.kind_flags.has(MonsterKindType::UNDEAD);
     case SUMMON_DRAGON:
-        is_match = r_ptr->kind_flags.has(MonsterKindType::DRAGON);
-        break;
+        return monrace.kind_flags.has(MonsterKindType::DRAGON);
     case SUMMON_HI_UNDEAD:
-        is_match = (r_ptr->d_char == 'L') || (r_ptr->d_char == 'V') || (r_ptr->d_char == 'W');
-        break;
+        return (monrace.d_char == 'L') || (monrace.d_char == 'V') || (monrace.d_char == 'W');
     case SUMMON_HI_DRAGON:
-        is_match = (r_ptr->d_char == 'D');
-        break;
+        return monrace.d_char == 'D';
     case SUMMON_HI_DEMON:
-        is_match = ((r_ptr->d_char == 'U') || (r_ptr->d_char == 'H') || (r_ptr->d_char == 'B')) && (r_ptr->kind_flags.has(MonsterKindType::DEMON));
-        break;
+        return ((monrace.d_char == 'U') || (monrace.d_char == 'H') || (monrace.d_char == 'B')) && (monrace.kind_flags.has(MonsterKindType::DEMON));
     case SUMMON_AMBERITES:
-        is_match = r_ptr->kind_flags.has(MonsterKindType::AMBERITE);
-        break;
+        return monrace.kind_flags.has(MonsterKindType::AMBERITE);
     case SUMMON_UNIQUE:
-        is_match = r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
-        break;
+        return monrace.kind_flags.has(MonsterKindType::UNIQUE);
     case SUMMON_MOLD:
-        is_match = r_ptr->d_char == 'm';
-        break;
+        return monrace.d_char == 'm';
     case SUMMON_BAT:
-        is_match = r_ptr->d_char == 'b';
-        break;
+        return monrace.d_char == 'b';
     case SUMMON_QUYLTHULG:
-        is_match = r_ptr->d_char == 'Q';
-        break;
+        return monrace.d_char == 'Q';
     case SUMMON_COIN_MIMIC:
-        is_match = r_ptr->d_char == '$';
-        break;
+        return monrace.d_char == '$';
     case SUMMON_MIMIC:
-        is_match = ((r_ptr->d_char == '!') || (r_ptr->d_char == '?') || (r_ptr->d_char == '=') || (r_ptr->d_char == '$') || (r_ptr->d_char == '|'));
-        break;
+        return (monrace.d_char == '!') || (monrace.d_char == '?') || (monrace.d_char == '=') || (monrace.d_char == '$') || (monrace.d_char == '|');
     case SUMMON_GOLEM:
-        is_match = (r_ptr->d_char == 'g');
-        break;
+        return (monrace.d_char == 'g');
     case SUMMON_CYBER:
-        is_match = (r_ptr->d_char == 'U') && r_ptr->ability_flags.has(MonsterAbilityType::ROCKET);
-        break;
+        return (monrace.d_char == 'U') && monrace.ability_flags.has(MonsterAbilityType::ROCKET);
     case SUMMON_KIN: {
-        auto summon_kin_type = MonsterRace(summoner_idx).is_valid() ? monraces_info[summoner_idx].d_char : get_summon_symbol_from_player(player_ptr);
-        is_match = (r_ptr->d_char == summon_kin_type) && (r_idx != MonsterRaceId::HAGURE);
-        break;
+        auto summon_kin_type = MonsterRace(summoner_idx).is_valid() ? monraces_info[summoner_idx].d_char : PlayerRace(player_ptr).get_summon_symbol();
+        return (monrace.d_char == summon_kin_type) && (r_idx != MonsterRaceId::HAGURE);
     }
     case SUMMON_DAWN:
-        is_match = r_idx == MonsterRaceId::DAWN;
-        break;
+        return r_idx == MonsterRaceId::DAWN;
     case SUMMON_ANIMAL:
-        is_match = r_ptr->kind_flags.has(MonsterKindType::ANIMAL);
-        break;
-    case SUMMON_ANIMAL_RANGER:
-        is_match = (r_ptr->kind_flags.has(MonsterKindType::ANIMAL) && (angband_strchr("abcflqrwBCHIJKMRS", r_ptr->d_char)) && r_ptr->kind_flags.has_not(MonsterKindType::DRAGON) && r_ptr->kind_flags.has_not(MonsterKindType::EVIL) && r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD) && r_ptr->kind_flags.has_not(MonsterKindType::DEMON) && !(r_ptr->flags2 & (RF2_MULTIPLY)) && r_ptr->ability_flags.none());
-        break;
+        return monrace.kind_flags.has(MonsterKindType::ANIMAL);
+    case SUMMON_ANIMAL_RANGER: {
+        auto is_match = monrace.kind_flags.has(MonsterKindType::ANIMAL);
+        is_match &= angband_strchr("abcflqrwBCHIJKMRS", monrace.d_char) != nullptr;
+        is_match &= monrace.kind_flags.has_not(MonsterKindType::DRAGON);
+        is_match &= monrace.kind_flags.has_not(MonsterKindType::EVIL);
+        is_match &= monrace.kind_flags.has_not(MonsterKindType::UNDEAD);
+        is_match &= monrace.kind_flags.has_not(MonsterKindType::DEMON);
+        is_match &= none_bits(monrace.flags2, RF2_MULTIPLY);
+        is_match &= monrace.ability_flags.none();
+        return is_match;
+    }
     case SUMMON_SMALL_MOAI:
-        is_match = r_idx == MonsterRaceId::SMALL_MOAI;
-        break;
+        return r_idx == MonsterRaceId::SMALL_MOAI;
     case SUMMON_PYRAMID:
-        is_match = one_in_(16) ? r_ptr->d_char == 'z' : r_idx == MonsterRaceId::SCARAB;
-        break;
+        return one_in_(16) ? monrace.d_char == 'z' : r_idx == MonsterRaceId::SCARAB;
     case SUMMON_PHANTOM:
-        is_match = (r_idx == MonsterRaceId::PHANTOM_B) || (r_idx == MonsterRaceId::PHANTOM_W);
-        break;
+        return (r_idx == MonsterRaceId::PHANTOM_B) || (r_idx == MonsterRaceId::PHANTOM_W);
     case SUMMON_BLUE_HORROR:
-        is_match = r_idx == MonsterRaceId::BLUE_HORROR;
-        break;
+        return r_idx == MonsterRaceId::BLUE_HORROR;
     case SUMMON_TOTEM_MOAI:
-        is_match = r_idx == MonsterRaceId::TOTEM_MOAI;
-        break;
+        return r_idx == MonsterRaceId::TOTEM_MOAI;
     case SUMMON_LIVING:
-        is_match = monster_living(r_idx);
-        break;
+        return monrace.has_living_flag();
     case SUMMON_HI_DRAGON_LIVING:
-        is_match = ((r_ptr->d_char == 'D') && monster_living(r_idx));
-        break;
+        return (monrace.d_char == 'D') && monrace.has_living_flag();
     case SUMMON_ELEMENTAL:
-        is_match = r_ptr->d_char == 'E';
-        break;
+        return monrace.d_char == 'E';
     case SUMMON_VORTEX:
-        is_match = r_ptr->d_char == 'v';
-        break;
+        return monrace.d_char == 'v';
     case SUMMON_HYBRID:
-        is_match = r_ptr->d_char == 'H';
-        break;
+        return monrace.d_char == 'H';
     case SUMMON_BIRD:
-        is_match = r_ptr->d_char == 'B';
-        break;
+        return monrace.d_char == 'B';
     case SUMMON_KAMIKAZE:
-        for (int i = 0; i < 4; i++) {
-            if (r_ptr->blow[i].method == RaceBlowMethodType::EXPLODE) {
-                is_match = true;
-            }
-        }
-
-        break;
-    case SUMMON_KAMIKAZE_LIVING:
-        for (int i = 0; i < 4; i++) {
-            if (r_ptr->blow[i].method == RaceBlowMethodType::EXPLODE) {
-                is_match = true;
-            }
-        }
-
-        is_match &= monster_living(r_idx);
-        break;
+        return monrace.is_explodable();
+    case SUMMON_KAMIKAZE_LIVING: {
+        return monrace.is_explodable() && monrace.has_living_flag();
     case SUMMON_MANES:
-        is_match = r_idx == MonsterRaceId::MANES;
-        break;
+        return r_idx == MonsterRaceId::MANES;
     case SUMMON_LOUSE:
-        is_match = r_idx == MonsterRaceId::LOUSE;
-        break;
+        return r_idx == MonsterRaceId::LOUSE;
     case SUMMON_GUARDIANS:
-        is_match = (r_ptr->flags7 & RF7_GUARDIAN) != 0;
-        break;
-    case SUMMON_KNIGHTS:
-        is_match = ((r_idx == MonsterRaceId::NOV_PALADIN) || (r_idx == MonsterRaceId::NOV_PALADIN_G) || (r_idx == MonsterRaceId::PALADIN) || (r_idx == MonsterRaceId::W_KNIGHT) || (r_idx == MonsterRaceId::ULTRA_PALADIN) || (r_idx == MonsterRaceId::KNI_TEMPLAR));
-        break;
-    case SUMMON_EAGLES:
-        is_match = (r_ptr->d_char == 'B') && (r_ptr->wilderness_flags.has(MonsterWildernessType::WILD_MOUNTAIN)) && (r_ptr->wilderness_flags.has(MonsterWildernessType::WILD_ONLY));
-        break;
+        return any_bits(monrace.flags7, RF7_GUARDIAN);
+    case SUMMON_KNIGHTS: {
+        auto is_match = r_idx == MonsterRaceId::NOV_PALADIN;
+        is_match |= r_idx == MonsterRaceId::NOV_PALADIN_G;
+        is_match |= r_idx == MonsterRaceId::PALADIN;
+        is_match |= r_idx == MonsterRaceId::W_KNIGHT;
+        is_match |= r_idx == MonsterRaceId::ULTRA_PALADIN;
+        is_match |= r_idx == MonsterRaceId::KNI_TEMPLAR;
+        return is_match;
+    }
+    case SUMMON_EAGLES: {
+        auto is_match = monrace.d_char == 'B';
+        is_match &= monrace.wilderness_flags.has(MonsterWildernessType::WILD_MOUNTAIN);
+        is_match &= monrace.wilderness_flags.has(MonsterWildernessType::WILD_ONLY);
+        return is_match;
+    }
     case SUMMON_PIRANHAS:
-        is_match = r_idx == MonsterRaceId::PIRANHA;
-        break;
+        return r_idx == MonsterRaceId::PIRANHA;
     case SUMMON_ARMAGE_GOOD:
-        is_match = (r_ptr->d_char == 'A') && (r_ptr->kind_flags.has(MonsterKindType::GOOD));
-        break;
+        return (monrace.d_char == 'A') && (monrace.kind_flags.has(MonsterKindType::GOOD));
     case SUMMON_ARMAGE_EVIL:
-        is_match = (r_ptr->kind_flags.has(MonsterKindType::DEMON)) || ((r_ptr->d_char == 'A') && (r_ptr->kind_flags.has(MonsterKindType::EVIL)));
-        break;
+        return (monrace.kind_flags.has(MonsterKindType::DEMON)) || ((monrace.d_char == 'A') && (monrace.kind_flags.has(MonsterKindType::EVIL)));
     case SUMMON_APOCRYPHA_FOLLOWERS:
-        is_match = (r_idx == MonsterRaceId::FOLLOWER_WARRIOR) || (r_idx == MonsterRaceId::FOLLOWER_MAGE);
-        break;
+        return (r_idx == MonsterRaceId::FOLLOWER_WARRIOR) || (r_idx == MonsterRaceId::FOLLOWER_MAGE);
     case SUMMON_APOCRYPHA_DRAGONS:
-        is_match = (r_ptr->d_char == 'D') && (r_ptr->level >= 60) && (r_idx != MonsterRaceId::WYRM_COLOURS) && (r_idx != MonsterRaceId::ALDUIN);
-        break;
+        return (monrace.d_char == 'D') && (monrace.level >= 60) && (r_idx != MonsterRaceId::WYRM_COLOURS) && (r_idx != MonsterRaceId::ALDUIN);
     case SUMMON_VESPOID:
-        is_match = r_idx == MonsterRaceId::VESPOID;
-        break;
-    case SUMMON_ANTI_TIGERS:
-        is_match = one_in_(32) ? (r_ptr->d_char == 'P') : false;
-        is_match |= one_in_(48) ? (r_ptr->d_char == 'd') : false;
-        is_match |= one_in_(16) ? (r_ptr->d_char == 'l') : false;
+        return r_idx == MonsterRaceId::VESPOID;
+    case SUMMON_ANTI_TIGERS: {
+        auto is_match = one_in_(32) ? (monrace.d_char == 'P') : false;
+        is_match |= one_in_(48) ? (monrace.d_char == 'd') : false;
+        is_match |= one_in_(16) ? (monrace.d_char == 'l') : false;
         is_match |= (r_idx == MonsterRaceId::STAR_VAMPIRE) || (r_idx == MonsterRaceId::SWALLOW) || (r_idx == MonsterRaceId::HAWK);
         is_match |= (r_idx == MonsterRaceId::LION) || (r_idx == MonsterRaceId::BUFFALO) || (r_idx == MonsterRaceId::FIGHTER) || (r_idx == MonsterRaceId::GOLDEN_EAGLE);
         is_match |= (r_idx == MonsterRaceId::SHALLOW_PUDDLE) || (r_idx == MonsterRaceId::DEEP_PUDDLE) || (r_idx == MonsterRaceId::SKY_WHALE);
-        break;
+        return is_match;
+    }
+    case SUMMON_DEAD_UNIQUE: {
+        return monrace.kind_flags.has(MonsterKindType::UNIQUE) && monrace.max_num == 0;
+    }
     default:
-        break;
+        return false;
+    }
     }
-
-    return is_match;
 }
index 897a6e7..3981fce 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f2478ea..ccf1877 100644 (file)
@@ -1,4 +1,4 @@
-#include "mutation/gain-mutation-switcher.h"
+#include "mutation/gain-mutation-switcher.h"
 #include "mutation/mutation-flag-types.h"
 #include "mutation/mutation-util.h"
 #include "player-base/player-class.h"
index f8b3f8d..9d9a840 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct glm_type;
 class PlayerType;
index c7da136..28a04f5 100644 (file)
@@ -1,4 +1,4 @@
-#include "mutation/lose-mutation-switcher.h"
+#include "mutation/lose-mutation-switcher.h"
 #include "mutation/mutation-flag-types.h"
 #include "mutation/mutation-util.h"
 #include "system/player-type-definition.h"
index 1ef31b9..cbaba4f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct glm_type;
 class PlayerType;
index f4b8185..3ca5e07 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 突然変異の各種計算 / Calculations for mutation
  * @date 2014/01/11
  * @author
index 62b9572..7f0419e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 int calc_mutant_regenerate_mod(PlayerType *player_ptr);
index 9eb35dc..bb8bc1d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class PlayerMutationType {
     SPIT_ACID = 0, /*!< 突然変異: 酸の唾 */
index 0393bb8..3d77456 100644 (file)
@@ -1,6 +1,5 @@
-#include "mutation/mutation-investor-remover.h"
+#include "mutation/mutation-investor-remover.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "mutation/gain-mutation-switcher.h"
 #include "mutation/lose-mutation-switcher.h"
@@ -9,6 +8,7 @@
 #include "mutation/mutation-util.h"
 #include "player-base/player-race.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
@@ -230,7 +230,7 @@ bool gain_mutation(PlayerType *player_ptr, MUTATION_IDX choose_mut)
     neutralize_other_status(player_ptr, gm_ptr);
 
     player_ptr->mutant_regenerate_mod = calc_mutant_regenerate_mod(player_ptr);
-    set_bits(player_ptr->update, PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -274,7 +274,7 @@ bool lose_mutation(PlayerType *player_ptr, MUTATION_IDX choose_mut)
         player_ptr->muta.reset(glm_ptr->muta_which);
     }
 
-    set_bits(player_ptr->update, PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     player_ptr->mutant_regenerate_mod = calc_mutant_regenerate_mod(player_ptr);
     return true;
@@ -286,7 +286,7 @@ void lose_all_mutations(PlayerType *player_ptr)
         chg_virtue(player_ptr, Virtue::CHANCE, -5);
         msg_print(_("全ての突然変異が治った。", "You are cured of all mutations."));
         player_ptr->muta.clear();
-        set_bits(player_ptr->update, PU_BONUS);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
         handle_stuff(player_ptr);
         player_ptr->mutant_regenerate_mod = calc_mutant_regenerate_mod(player_ptr);
     }
index f0ae022..2bb876c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 1e424b5..a64c140 100644 (file)
@@ -1,7 +1,6 @@
-#include "mutation/mutation-processor.h"
+#include "mutation/mutation-processor.h"
 #include "core/asking-player.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "effect/attribute-types.h"
 #include "floor/geometry.h"
 #include "grid/grid.h"
@@ -40,6 +39,7 @@
 #include "store/store-owners.h"
 #include "store/store-util.h"
 #include "store/store.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -47,6 +47,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "target/target-setter.h"
 #include "target/target-types.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
 
-static bool get_hack_dir(PlayerType *player_ptr, DIRECTION *dp)
+static int get_hack_dir(PlayerType *player_ptr)
 {
-    *dp = 0;
-    char command;
-    DIRECTION dir = 0;
-    while (!dir) {
-        concptr p = target_okay(player_ptr)
-                        ? _("方向 ('5'でターゲットへ, '*'でターゲット再選択, ESCで中断)? ", "Direction ('5' for target, '*' to re-target, Escape to cancel)? ")
-                        : _("方向 ('*'でターゲット選択, ESCで中断)? ", "Direction ('*' to choose a target, Escape to cancel)? ");
-        if (!get_com(p, &command, true)) {
+    auto dir = 0;
+    while (dir == 0) {
+        const auto p = target_okay(player_ptr)
+                           ? _("方向 ('5'でターゲットへ, '*'でターゲット再選択, ESCで中断)? ", "Direction ('5' for target, '*' to re-target, Escape to cancel)? ")
+                           : _("方向 ('*'でターゲット選択, ESCで中断)? ", "Direction ('*' to choose a target, Escape to cancel)? ");
+        const auto command_opt = input_command(p, true);
+        if (!command_opt) {
             break;
         }
 
+        auto command = *command_opt;
         if (use_menu && (command == '\r')) {
             command = 't';
         }
@@ -99,13 +100,13 @@ static bool get_hack_dir(PlayerType *player_ptr, DIRECTION *dp)
             dir = 0;
         }
 
-        if (!dir) {
+        if (dir == 0) {
             bell();
         }
     }
 
-    if (!dir) {
-        return false;
+    if (dir == 0) {
+        return 0;
     }
 
     command_dir = dir;
@@ -117,8 +118,7 @@ static bool get_hack_dir(PlayerType *player_ptr, DIRECTION *dp)
         msg_print(_("あなたは混乱している。", "You are confused."));
     }
 
-    *dp = dir;
-    return true;
+    return dir;
 }
 
 /*!
@@ -127,7 +127,7 @@ static bool get_hack_dir(PlayerType *player_ptr, DIRECTION *dp)
  */
 void process_world_aux_mutation(PlayerType *player_ptr)
 {
-    if (player_ptr->muta.none() || player_ptr->phase_out || player_ptr->wild_mode) {
+    if (player_ptr->muta.none() || AngbandSystem::get_instance().is_phase_out() || player_ptr->wild_mode) {
         return;
     }
 
@@ -160,7 +160,7 @@ void process_world_aux_mutation(PlayerType *player_ptr)
     if (player_ptr->muta.has(PlayerMutationType::ALCOHOL) && (randint1(6400) == 321)) {
         if (!has_resist_conf(player_ptr) && !has_resist_chaos(player_ptr)) {
             disturb(player_ptr, false, true);
-            player_ptr->redraw |= PR_EXTRA;
+            RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::EXTRA);
             msg_print(_("いひきがもーろーとひてきたきがふる...ヒック!", "You feel a SSSCHtupor cOmINg over yOu... *HIC*!"));
         }
 
@@ -192,7 +192,7 @@ void process_world_aux_mutation(PlayerType *player_ptr)
     if (player_ptr->muta.has(PlayerMutationType::HALLU) && (randint1(6400) == 42)) {
         if (!has_resist_chaos(player_ptr)) {
             disturb(player_ptr, false, true);
-            player_ptr->redraw |= PR_EXTRA;
+            RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::EXTRA);
             (void)bss.mod_hallucination(randint0(50) + 20);
         }
     }
@@ -205,15 +205,14 @@ void process_world_aux_mutation(PlayerType *player_ptr)
     }
 
     if (player_ptr->muta.has(PlayerMutationType::PROD_MANA) && !player_ptr->anti_magic && one_in_(9000)) {
-        int dire = 0;
         disturb(player_ptr, false, true);
         msg_print(_("魔法のエネルギーが突然あなたの中に流れ込んできた!エネルギーを解放しなければならない!",
             "Magical energy flows through you! You must release it!"));
 
         flush();
         msg_print(nullptr);
-        (void)get_hack_dir(player_ptr, &dire);
-        fire_ball(player_ptr, AttributeType::MANA, dire, player_ptr->lev * 2, 3);
+        const auto dir = get_hack_dir(player_ptr);
+        fire_ball(player_ptr, AttributeType::MANA, dir, player_ptr->lev * 2, 3);
     }
 
     if (player_ptr->muta.has(PlayerMutationType::ATT_DEMON) && !player_ptr->anti_magic && (randint1(6666) == 666)) {
@@ -431,7 +430,7 @@ void process_world_aux_mutation(PlayerType *player_ptr)
         int danger_amount = 0;
         for (MONSTER_IDX monster = 0; monster < player_ptr->current_floor_ptr->m_max; monster++) {
             auto *m_ptr = &player_ptr->current_floor_ptr->m_list[monster];
-            auto *r_ptr = &monraces_info[m_ptr->r_idx];
+            auto *r_ptr = &m_ptr->get_monrace();
             if (!m_ptr->is_valid()) {
                 continue;
             }
@@ -463,6 +462,10 @@ void process_world_aux_mutation(PlayerType *player_ptr)
         (void)set_invuln(player_ptr, randint1(8) + 8, false);
     }
 
+    static constexpr auto flags = {
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
     if (player_ptr->muta.has(PlayerMutationType::SP_TO_HP) && one_in_(2000)) {
         MANA_POINT wounds = (MANA_POINT)(player_ptr->mhp - player_ptr->chp);
         if (wounds > 0) {
@@ -473,7 +476,7 @@ void process_world_aux_mutation(PlayerType *player_ptr)
 
             hp_player(player_ptr, healing);
             player_ptr->csp -= healing;
-            player_ptr->redraw |= (PR_HP | PR_MP);
+            RedrawingFlagsUpdater::get_instance().set_flags(flags);
         }
     }
 
@@ -486,7 +489,7 @@ void process_world_aux_mutation(PlayerType *player_ptr)
             }
 
             player_ptr->csp += healing;
-            player_ptr->redraw |= (PR_HP | PR_MP);
+            RedrawingFlagsUpdater::get_instance().set_flags(flags);
             take_hit(player_ptr, DAMAGE_LOSELIFE, healing, _("頭に昇った血", "blood rushing to the head"));
         }
     }
index 4e2c459..c49c43b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void process_world_aux_mutation(PlayerType *player_ptr);
index b40dbbb..b3f916b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 突然変異でのみ得ることができる特殊能力処理
  * @date 2020/07/04
  * @author Hourier
 bool eat_rock(PlayerType *player_ptr)
 {
     DIRECTION dir;
-    if (!get_direction(player_ptr, &dir, false, false)) {
+    if (!get_direction(player_ptr, &dir)) {
         return false;
     }
 
-    POSITION y = player_ptr->y + ddy[dir];
-    POSITION x = player_ptr->x + ddx[dir];
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    TerrainType *f_ptr, *mimic_f_ptr;
-    f_ptr = &terrains_info[g_ptr->feat];
-    mimic_f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
+    const Pos2D pos(player_ptr->y + ddy[dir], player_ptr->x + ddx[dir]);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
+    const auto &terrain_mimic = grid.get_terrain_mimic();
 
     stop_mouth(player_ptr);
-    if (mimic_f_ptr->flags.has_not(TerrainCharacteristics::HURT_ROCK)) {
+    if (terrain_mimic.flags.has_not(TerrainCharacteristics::HURT_ROCK)) {
         msg_print(_("この地形は食べられない。", "You cannot eat this feature."));
-    } else if (f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
-        msg_format(_("いてっ!この%sはあなたの歯より硬い!", "Ouch!  This %s is harder than your teeth!"), mimic_f_ptr->name.data());
-    } else if (g_ptr->m_idx) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
+    } else if (terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
+        msg_format(_("いてっ!この%sはあなたの歯より硬い!", "Ouch!  This %s is harder than your teeth!"), terrain_mimic.name.data());
+    } else if (grid.m_idx) {
+        const auto &monster = player_ptr->current_floor_ptr->m_list[grid.m_idx];
         msg_print(_("何かが邪魔しています!", "There's something in the way!"));
-
-        if (!m_ptr->ml || !m_ptr->is_pet()) {
-            do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
+        if (!monster.ml || !monster.is_pet()) {
+            do_cmd_attack(player_ptr, pos.y, pos.x, HISSATSU_NONE);
         }
-    } else if (f_ptr->flags.has(TerrainCharacteristics::TREE)) {
+    } else if (terrain.flags.has(TerrainCharacteristics::TREE)) {
         msg_print(_("木の味は好きじゃない!", "You don't like the woody taste!"));
-    } else if (f_ptr->flags.has(TerrainCharacteristics::GLASS)) {
+    } else if (terrain.flags.has(TerrainCharacteristics::GLASS)) {
         msg_print(_("ガラスの味は好きじゃない!", "You don't like the glassy taste!"));
-    } else if (f_ptr->flags.has(TerrainCharacteristics::DOOR) || f_ptr->flags.has(TerrainCharacteristics::CAN_DIG)) {
+    } else if (terrain.flags.has(TerrainCharacteristics::DOOR) || terrain.flags.has(TerrainCharacteristics::CAN_DIG)) {
         (void)set_food(player_ptr, player_ptr->food + 3000);
-    } else if (f_ptr->flags.has(TerrainCharacteristics::MAY_HAVE_GOLD) || f_ptr->flags.has(TerrainCharacteristics::HAS_GOLD)) {
+    } else if (terrain.flags.has(TerrainCharacteristics::MAY_HAVE_GOLD) || terrain.flags.has(TerrainCharacteristics::HAS_GOLD)) {
         (void)set_food(player_ptr, player_ptr->food + 5000);
     } else {
-        msg_format(_("この%sはとてもおいしい!", "This %s is very filling!"), mimic_f_ptr->name.data());
+        msg_format(_("この%sはとてもおいしい!", "This %s is very filling!"), terrain_mimic.name.data());
         (void)set_food(player_ptr, player_ptr->food + 10000);
     }
 
-    cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_ROCK);
-    (void)move_player_effect(player_ptr, y, x, MPE_DONT_PICKUP);
+    cave_alter_feat(player_ptr, pos.y, pos.x, TerrainCharacteristics::HURT_ROCK);
+    (void)move_player_effect(player_ptr, pos.y, pos.x, MPE_DONT_PICKUP);
     return true;
 }
index ee9ac26..8ad7328 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool eat_rock(PlayerType *player_ptr);
index 1e7597d..b748ef5 100644 (file)
@@ -1,4 +1,4 @@
-#include "mutation/mutation-util.h"
+#include "mutation/mutation-util.h"
 #include "mutation/mutation-flag-types.h"
 
 glm_type *initialize_glm_type(glm_type *gm_ptr, MUTATION_IDX choose_mut)
index 8df15bb..27ad7a6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
diff --git a/src/net/curl-easy-session.cpp b/src/net/curl-easy-session.cpp
new file mode 100644 (file)
index 0000000..568ba85
--- /dev/null
@@ -0,0 +1,116 @@
+#include "net/curl-easy-session.h"
+
+#if !defined(DISABLE_NET)
+
+namespace libcurl {
+
+namespace {
+
+    size_t write_callback(char *buf, size_t size, size_t nitems, EasySession::SendHandler *userdata)
+    {
+        return (*userdata)(buf, size * nitems);
+    }
+
+    size_t read_callback(char *buf, size_t size, size_t nitems, EasySession::ReceiveHandler *userdata)
+    {
+        return (*userdata)(buf, size * nitems);
+    }
+
+    int progress_callback(EasySession::ProgressHandler *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
+    {
+        return (*userdata)(dltotal, dlnow, ultotal, ulnow) ? 0 : 1;
+    }
+}
+
+class EasySession::Impl {
+public:
+    Impl()
+        : handle_(curl_easy_init(), curl_easy_cleanup)
+    {
+    }
+    ~Impl() = default;
+    Impl(const Impl &) = delete;
+    Impl &operator=(const Impl &) = delete;
+    Impl(Impl &&) = default;
+    Impl &operator=(Impl &&) = default;
+
+    std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> handle_;
+    SendHandler send_handler_;
+    ReceiveHandler receive_handler_;
+    ProgressHandler progress_handler_;
+};
+
+EasySession::EasySession()
+    : pimpl_(std::make_unique<Impl>())
+{
+}
+
+EasySession::~EasySession() = default;
+EasySession::EasySession(EasySession &&) = default;
+EasySession &EasySession::operator=(EasySession &&) = default;
+
+bool EasySession::is_valid() const
+{
+    return pimpl_->handle_ != nullptr;
+}
+
+void EasySession::common_setup(const std::string &url, int timeout_sec)
+{
+    this->setopt(CURLOPT_URL, url.data());
+
+    this->setopt(CURLOPT_NOSIGNAL, 1);
+
+    if (timeout_sec > 0) {
+        this->setopt(CURLOPT_CONNECTTIMEOUT, timeout_sec);
+    }
+}
+
+void EasySession::sender_setup(SendHandler handler, long post_field_size)
+{
+    pimpl_->send_handler_ = std::move(handler);
+    if (!pimpl_->send_handler_) {
+        return;
+    }
+
+    this->setopt(CURLOPT_READDATA, &pimpl_->send_handler_);
+    this->setopt(CURLOPT_READFUNCTION, read_callback);
+    this->setopt(CURLOPT_POSTFIELDSIZE, post_field_size);
+}
+
+void EasySession::receiver_setup(ReceiveHandler handler)
+{
+    pimpl_->receive_handler_ = std::move(handler);
+    if (!pimpl_->receive_handler_) {
+        return;
+    }
+
+    this->setopt(CURLOPT_WRITEDATA, &pimpl_->receive_handler_);
+    this->setopt(CURLOPT_WRITEFUNCTION, write_callback);
+}
+
+void EasySession::progress_setup(ProgressHandler handler)
+{
+    pimpl_->progress_handler_ = std::move(handler);
+    if (!pimpl_->progress_handler_) {
+        this->setopt(CURLOPT_NOPROGRESS, 1);
+        return;
+    }
+
+    this->setopt(CURLOPT_NOPROGRESS, 0);
+    this->setopt(CURLOPT_XFERINFODATA, &pimpl_->progress_handler_);
+    this->setopt(CURLOPT_XFERINFOFUNCTION, progress_callback);
+}
+
+bool EasySession::perform()
+{
+    return curl_easy_perform(pimpl_->handle_.get()) == CURLE_OK;
+}
+
+CURL *EasySession::get_curl_handle()
+{
+    return pimpl_->handle_.get();
+}
+
+}
+
+#endif
diff --git a/src/net/curl-easy-session.h b/src/net/curl-easy-session.h
new file mode 100644 (file)
index 0000000..20d0a23
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "system/angband.h"
+#include <functional>
+#include <memory>
+#include <string>
+
+#if !defined(DISABLE_NET)
+
+#ifdef WINDOWS
+#define CURL_STATICLIB
+#endif
+#include <curl/curl.h>
+
+namespace libcurl {
+
+/*!
+ * @brief libcurl easy session の薄いラッパークラス
+ */
+class EasySession {
+public:
+    using SendHandler = std::function<size_t(char *, size_t)>;
+    using ReceiveHandler = std::function<size_t(char *, size_t)>;
+    using ProgressHandler = std::function<bool(curl_off_t, curl_off_t, curl_off_t, curl_off_t)>;
+
+    EasySession();
+    ~EasySession();
+    EasySession(const EasySession &) = delete;
+    EasySession &operator=(const EasySession &) = delete;
+    EasySession(EasySession &&);
+    EasySession &operator=(EasySession &&);
+
+    bool is_valid() const;
+    void common_setup(const std::string &url, int timeout_sec = 0);
+    void sender_setup(SendHandler handler, long post_field_size);
+    void receiver_setup(ReceiveHandler handler);
+    void progress_setup(ProgressHandler handler);
+    bool perform();
+
+    template <typename T>
+    void setopt(CURLoption opt, T param)
+    {
+        curl_easy_setopt(this->get_curl_handle(), opt, param);
+    }
+
+    template <typename T>
+    bool getinfo(CURLINFO info, T arg)
+    {
+        return curl_easy_getinfo(this->get_curl_handle(), info, arg) == CURLE_OK;
+    }
+
+private:
+    CURL *get_curl_handle();
+
+    class Impl;
+    std::unique_ptr<Impl> pimpl_;
+};
+
+}
+
+#endif
diff --git a/src/net/curl-slist.cpp b/src/net/curl-slist.cpp
new file mode 100644 (file)
index 0000000..902c99a
--- /dev/null
@@ -0,0 +1,65 @@
+#include "net/curl-slist.h"
+
+#if !defined(DISABLE_NET)
+
+namespace libcurl {
+
+class SList::Impl {
+public:
+    Impl()
+        : slist(nullptr, curl_slist_free_all)
+    {
+    }
+    ~Impl() = default;
+    Impl(const Impl &) = delete;
+    Impl &operator=(const Impl &) = delete;
+    Impl(Impl &&) = default;
+    Impl &operator=(Impl &&) = default;
+
+    std::unique_ptr<curl_slist, decltype(&curl_slist_free_all)> slist;
+    bool valid = true;
+};
+
+SList::SList()
+    : pimpl_(std::make_unique<Impl>())
+{
+}
+
+SList::~SList() = default;
+SList::SList(SList &&) = default;
+SList &SList::operator=(SList &&) = default;
+
+bool SList::is_valid() const
+{
+    return pimpl_->valid;
+}
+
+void SList::append(const char *str)
+{
+    if (!pimpl_->valid) {
+        return;
+    }
+
+    auto result = curl_slist_append(pimpl_->slist.get(), str);
+    if (result == nullptr) {
+        pimpl_->valid = false;
+        return;
+    }
+
+    pimpl_->slist.release();
+    pimpl_->slist.reset(result);
+}
+
+void SList::append(const std::string &str)
+{
+    this->append(str.data());
+}
+
+curl_slist *SList::get()
+{
+    return pimpl_->slist.get();
+}
+
+}
+
+#endif
diff --git a/src/net/curl-slist.h b/src/net/curl-slist.h
new file mode 100644 (file)
index 0000000..8c6a411
--- /dev/null
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "system/angband.h"
+#include <memory>
+#include <string>
+
+#if !defined(DISABLE_NET)
+
+#ifdef WINDOWS
+#define CURL_STATICLIB
+#endif
+#include <curl/curl.h>
+
+namespace libcurl {
+
+/*!
+ * @brief libcurl string list の薄いラッパークラス
+ */
+class SList {
+public:
+    SList();
+    ~SList();
+    SList(const SList &) = delete;
+    SList &operator=(const SList &) = delete;
+    SList(SList &&);
+    SList &operator=(SList &&);
+
+    bool is_valid() const;
+    void append(const char *str);
+    void append(const std::string &str);
+    curl_slist *get();
+
+private:
+    class Impl;
+    std::unique_ptr<Impl> pimpl_;
+};
+
+}
+
+#endif
diff --git a/src/net/http-client.cpp b/src/net/http-client.cpp
new file mode 100644 (file)
index 0000000..c3ed6da
--- /dev/null
@@ -0,0 +1,172 @@
+#include "net/http-client.h"
+#include "net/curl-easy-session.h"
+#include "net/curl-slist.h"
+#include <fstream>
+#include <string_view>
+
+#if !defined(DISABLE_NET)
+
+namespace http {
+
+namespace {
+
+    constexpr auto HTTP_CONNECTION_TIMEOUT = 10; //!< HTTP接続タイムアウト時間(秒)
+
+    void setup_http_option(libcurl::EasySession &session, const std::optional<std::string> &user_agent)
+    {
+        if (user_agent) {
+            session.setopt(CURLOPT_USERAGENT, user_agent->data());
+        }
+
+        session.setopt(CURLOPT_FOLLOWLOCATION, 1);
+        session.setopt(CURLOPT_MAXREDIRS, 10);
+        session.setopt(CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
+    }
+
+    class GetRequest {
+    public:
+        GetRequest(const std::string &url, const std::optional<std::string> &user_agent = {})
+            : url(url)
+            , user_agent(user_agent)
+        {
+        }
+
+        std::optional<int> perform()
+        {
+            libcurl::EasySession session;
+            if (!session.is_valid()) {
+                return std::nullopt;
+            }
+
+            session.common_setup(this->url, HTTP_CONNECTION_TIMEOUT);
+            setup_http_option(session, this->user_agent);
+
+            session.receiver_setup(this->receiver);
+            if (this->progress_handler) {
+                auto handler = [handler = this->progress_handler](size_t dltotal, size_t dlnow, size_t, size_t) {
+                    return handler({ dltotal, dlnow });
+                };
+                session.progress_setup(handler);
+            }
+
+            if (!session.perform()) {
+                return std::nullopt;
+            }
+
+            long status;
+            session.getinfo(CURLINFO_RESPONSE_CODE, &status);
+            return static_cast<int>(status);
+        }
+
+        libcurl::EasySession::ReceiveHandler receiver;
+        http::Client::GetRequestProgressHandler progress_handler;
+
+    private:
+        std::string url;
+        std::optional<std::string> user_agent;
+    };
+}
+
+/*!
+ * @brief HTTP GETリクエストを送信する
+ * @param url リクエストの送信先URL
+ * @param progress_handler 進捗状況を受け取るコールバック関数
+ * @return 送信に成功した場合Responseオブジェクト、失敗した場合std::nullopt
+ */
+std::optional<Response> Client::get(const std::string &url, GetRequestProgressHandler progress_handler)
+{
+    Response response{};
+
+    GetRequest request(url, this->user_agent);
+    request.receiver = [&response](char *buf, size_t n) {
+        response.body.append(buf, n);
+        return n;
+    };
+    request.progress_handler = progress_handler;
+
+    const auto status_opt = request.perform();
+    if (!status_opt) {
+        return std::nullopt;
+    }
+
+    response.status = *status_opt;
+    return std::make_optional(std::move(response));
+}
+
+/*!
+ * @brief HTTP GETリクエストを送信し、応答をファイルに保存する
+ *
+ * ファイルへの保存に成功した場合は、Responseオブジェクトのbodyにファイルパスが格納される。
+ *
+ * @param url リクエストの送信先URL
+ * @param path ファイルの保存先パス
+ * @param progress_handler 進捗状況を受け取るコールバック関数
+ * @return 送信に成功した場合Responseオブジェクト、失敗した場合std::nullopt
+ */
+std::optional<Response> Client::get(const std::string &url, const std::filesystem::path &path, GetRequestProgressHandler progress_handler)
+{
+    std::ofstream ofs(path, std::ios::binary);
+
+    GetRequest request(url, this->user_agent);
+    request.receiver = [&ofs](char *buf, size_t n) {
+        ofs.write(buf, n);
+        return ofs ? n : 0;
+    };
+    request.progress_handler = progress_handler;
+
+    const auto status_opt = request.perform();
+    if (!status_opt) {
+        return std::nullopt;
+    }
+
+    return Response{ *status_opt, path.string() };
+}
+
+/*!
+ * @brief HTTP POSTリクエストを送信する
+ * @param url リクエストの送信先URL
+ * @param post_data POSTデータ本体
+ * @param media_type POSTデータのメディアタイプ(Content-Typeヘッダの内容)
+ * @return 送信に成功した場合Responseオブジェクト、失敗した場合std::nullopt
+ */
+std::optional<Response> Client::post(const std::string &url, const std::string &post_data, const std::string &media_type)
+{
+    libcurl::EasySession session;
+    libcurl::SList headers;
+    headers.append(format("Content-Type: %s", media_type.data()));
+
+    if (!session.is_valid() || !headers.is_valid()) {
+        return std::nullopt;
+    }
+
+    session.common_setup(url, HTTP_CONNECTION_TIMEOUT);
+    setup_http_option(session, this->user_agent);
+
+    session.setopt(CURLOPT_HTTPHEADER, headers.get());
+    session.setopt(CURLOPT_POST, 1);
+
+    auto sender = [data = std::string_view(post_data)](char *buf, size_t n) mutable {
+        const auto len = data.copy(buf, n);
+        data.remove_prefix(len);
+        return len;
+    };
+    session.sender_setup(std::move(sender), post_data.length());
+
+    Response response{};
+    auto receiver = [&response](char *buf, size_t n) {
+        response.body.append(buf, n);
+        return n;
+    };
+    session.receiver_setup(std::move(receiver));
+
+    if (!session.perform()) {
+        return std::nullopt;
+    }
+
+    session.getinfo(CURLINFO_RESPONSE_CODE, &response.status);
+    return std::make_optional(std::move(response));
+}
+
+}
+
+#endif
diff --git a/src/net/http-client.h b/src/net/http-client.h
new file mode 100644 (file)
index 0000000..74f3763
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "system/angband.h"
+#include <filesystem>
+#include <functional>
+#include <optional>
+#include <string>
+
+#if !defined(DISABLE_NET)
+
+namespace http {
+
+struct Response {
+    int status;
+    std::string body;
+};
+
+struct Progress {
+    size_t total; ///< 通信の総バイト数。0の場合は不明
+    size_t now; ///< 通信済みのバイト数
+};
+
+class HttpContentBase;
+class Client {
+public:
+    /*!
+     * @brief HTTP GET通信のコールバック関数の型
+     * @param progress 進捗状況。libcurlの仕様によりnow/totalが0で呼ばれることがあるのでそれを考慮すること
+     * @return 通信を継続する場合はtrue、中断する場合はfalseを返す
+     */
+    using GetRequestProgressHandler = std::function<bool(Progress)>;
+
+    std::optional<Response> get(const std::string &url, GetRequestProgressHandler progress_handler = {});
+    std::optional<Response> get(const std::string &url, const std::filesystem::path &path, GetRequestProgressHandler progress_handler = {});
+    std::optional<Response> post(const std::string &url, const std::string &post_data, const std::string &media_type);
+
+    std::optional<std::string> user_agent;
+};
+
+}
+
+#endif
diff --git a/src/net/report-error.cpp b/src/net/report-error.cpp
new file mode 100644 (file)
index 0000000..bbf08eb
--- /dev/null
@@ -0,0 +1,72 @@
+#include "external-lib/include-json.h"
+#include "locale/japanese.h"
+#include "net/http-client.h"
+#include "system/angband-version.h"
+#include <sstream>
+#include <string_view>
+
+#if !defined(DISABLE_NET)
+
+namespace {
+
+/*!
+ * @brief エラーレポート送信用のWebhook URLを取得する
+ * @return 取得に成功した場合はWebhook URL、失敗した場合は空文字列
+ */
+std::string fetch_webhook_url_for_sending_error_report()
+{
+    http::Client client;
+    constexpr auto url = "https://hengband.github.io/api/report-error";
+    const auto response = client.get(url);
+    if (!response || (response->status != 200)) {
+        return "";
+    }
+
+    const auto json = nlohmann::json::parse(response->body);
+    return json["webhook_url"];
+}
+
+/*!
+ * @brief 送信するエラーレポートのJSONオブジェクトを作成する
+ *
+ * @param message エラーメッセージ
+ * @return 作成したJSONオブジェクト
+ */
+nlohmann::json create_report_json(std::string_view message)
+{
+    nlohmann::json webhook;
+    webhook["username"] = "Hengband Error Report";
+    constexpr auto conv_error_msg = "Cannot convert to UTF-8";
+    nlohmann::json embed;
+    embed["title"] = sys_to_utf8(get_version()).value_or(conv_error_msg);
+    embed["description"] = sys_to_utf8(message).value_or(conv_error_msg);
+    embed["color"] = 0xff0000; // red
+    webhook["embeds"].push_back(std::move(embed));
+
+    return webhook;
+}
+
+}
+
+/*!
+ * @brief エラーレポートを送信する
+ *
+ * @param description 送信するエラーの説明
+ * @return 送信に成功した場合はtrue、失敗した場合はfalse
+ */
+bool report_error(std::string_view description)
+{
+    const auto webhook_url = fetch_webhook_url_for_sending_error_report();
+    if (webhook_url.empty()) {
+        return false;
+    }
+
+    const auto report_json = create_report_json(description);
+
+    http::Client client;
+    const auto response = client.post(webhook_url, report_json.dump(), "application/json");
+
+    return (response && (response->status == 200));
+}
+
+#endif // !defined(DISABLE_NET)
diff --git a/src/net/report-error.h b/src/net/report-error.h
new file mode 100644 (file)
index 0000000..3fbcc17
--- /dev/null
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "system/angband.h"
+
+#if !defined(DISABLE_NET)
+
+#include <string_view>
+
+bool report_error(std::string_view description);
+
+#endif // !defined(DISABLE_NET)
index 1bae108..5a45622 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-activation/activation-bolt-ball.h"
+#include "object-activation/activation-bolt-ball.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
@@ -96,10 +96,10 @@ bool activate_bolt_cold_1(PlayerType *player_ptr)
     return true;
 }
 
-bool activate_bolt_hypodynamia_1(PlayerType *player_ptr, concptr name)
+bool activate_bolt_hypodynamia_1(PlayerType *player_ptr, std::string_view name)
 {
     DIRECTION dir;
-    msg_format(_("あなたは%sに敵を締め殺すよう命じた。", "You order the %s to strangle your opponent."), name);
+    msg_format(_("あなたは%sに敵を締め殺すよう命じた。", "You order the %s to strangle your opponent."), name.data());
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
@@ -152,10 +152,10 @@ bool activate_bolt_drain_2(PlayerType *player_ptr)
     return true;
 }
 
-bool activate_bolt_mana(PlayerType *player_ptr, concptr name)
+bool activate_bolt_mana(PlayerType *player_ptr, std::string_view name)
 {
     DIRECTION dir;
-    msg_format(_("%sに魔法のトゲが現れた...", "The %s grows magical spikes..."), name);
+    msg_format(_("%sに魔法のトゲが現れた...", "The %s grows magical spikes..."), name.data());
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
@@ -224,10 +224,10 @@ bool activate_ball_fire_1(PlayerType *player_ptr)
     return true;
 }
 
-bool activate_ball_fire_2(PlayerType *player_ptr, concptr name)
+bool activate_ball_fire_2(PlayerType *player_ptr, std::string_view name)
 {
     DIRECTION dir;
-    msg_format(_("%sから炎が吹き出した...", "The %s rages in fire..."), name);
+    msg_format(_("%sから炎が吹き出した...", "The %s rages in fire..."), name.data());
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
@@ -320,10 +320,10 @@ bool activate_rocket(PlayerType *player_ptr)
     return true;
 }
 
-bool activate_ball_water(PlayerType *player_ptr, concptr name)
+bool activate_ball_water(PlayerType *player_ptr, std::string_view name)
 {
     DIRECTION dir;
-    msg_format(_("%sが深い青色に鼓動している...", "The %s throbs deep blue..."), name);
+    msg_format(_("%sが深い青色に鼓動している...", "The %s throbs deep blue..."), name.data());
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
@@ -332,11 +332,11 @@ bool activate_ball_water(PlayerType *player_ptr, concptr name)
     return true;
 }
 
-bool activate_ball_lite(PlayerType *player_ptr, concptr name)
+bool activate_ball_lite(PlayerType *player_ptr, std::string_view name)
 {
     int num = damroll(5, 3);
     POSITION y = 0, x = 0;
-    msg_format(_("%sが稲妻で覆われた...", "The %s is surrounded by lightning..."), name);
+    msg_format(_("%sが稲妻で覆われた...", "The %s is surrounded by lightning..."), name.data());
     for (int k = 0; k < num; k++) {
         int attempts = 1000;
         while (attempts--) {
@@ -345,7 +345,7 @@ bool activate_ball_lite(PlayerType *player_ptr, concptr name)
                 continue;
             }
 
-            if (!player_bold(player_ptr, y, x)) {
+            if (!player_ptr->is_located_at({ y, x })) {
                 break;
             }
         }
@@ -356,10 +356,10 @@ bool activate_ball_lite(PlayerType *player_ptr, concptr name)
     return true;
 }
 
-bool activate_ball_dark(PlayerType *player_ptr, concptr name)
+bool activate_ball_dark(PlayerType *player_ptr, std::string_view name)
 {
     DIRECTION dir;
-    msg_format(_("%sが深い闇に覆われた...", "The %s is covered in pitch-darkness..."), name);
+    msg_format(_("%sが深い闇に覆われた...", "The %s is covered in pitch-darkness..."), name.data());
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
@@ -368,10 +368,10 @@ bool activate_ball_dark(PlayerType *player_ptr, concptr name)
     return true;
 }
 
-bool activate_ball_mana(PlayerType *player_ptr, concptr name)
+bool activate_ball_mana(PlayerType *player_ptr, std::string_view name)
 {
     DIRECTION dir;
-    msg_format(_("%sが青白く光った...", "The %s becomes pale..."), name);
+    msg_format(_("%sが青白く光った...", "The %s becomes pale..."), name.data());
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
index 7b162d9..0846c7b 100644 (file)
@@ -1,6 +1,6 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <string_view>
 
 class PlayerType;
 bool activate_missile_1(PlayerType *player_ptr);
@@ -10,17 +10,17 @@ bool activate_bolt_acid_1(PlayerType *player_ptr);
 bool activate_bolt_elec_1(PlayerType *player_ptr);
 bool activate_bolt_fire_1(PlayerType *player_ptr);
 bool activate_bolt_cold_1(PlayerType *player_ptr);
-bool activate_bolt_hypodynamia_1(PlayerType *player_ptr, concptr name);
+bool activate_bolt_hypodynamia_1(PlayerType *player_ptr, std::string_view name);
 bool activate_bolt_hypodynamia_2(PlayerType *player_ptr);
 bool activate_bolt_drain_1(PlayerType *player_ptr);
 bool activate_bolt_drain_2(PlayerType *player_ptr);
-bool activate_bolt_mana(PlayerType *player_ptr, concptr name);
+bool activate_bolt_mana(PlayerType *player_ptr, std::string_view name);
 bool activate_ball_pois_1(PlayerType *player_ptr);
 bool activate_ball_cold_1(PlayerType *player_ptr);
 bool activate_ball_cold_2(PlayerType *player_ptr);
 bool activate_ball_cold_3(PlayerType *player_ptr);
 bool activate_ball_fire_1(PlayerType *player_ptr);
-bool activate_ball_fire_2(PlayerType *player_ptr, concptr name);
+bool activate_ball_fire_2(PlayerType *player_ptr, std::string_view name);
 bool activate_ball_fire_3(PlayerType *player_ptr);
 bool activate_ball_fire_4(PlayerType *player_ptr);
 bool activate_ball_elec_2(PlayerType *player_ptr);
@@ -28,7 +28,7 @@ bool activate_ball_elec_3(PlayerType *player_ptr);
 bool activate_ball_acid_1(PlayerType *player_ptr);
 bool activate_ball_nuke_1(PlayerType *player_ptr);
 bool activate_rocket(PlayerType *player_ptr);
-bool activate_ball_water(PlayerType *player_ptr, concptr name);
-bool activate_ball_lite(PlayerType *player_ptr, concptr name);
-bool activate_ball_dark(PlayerType *player_ptr, concptr name);
-bool activate_ball_mana(PlayerType *player_ptr, concptr name);
+bool activate_ball_water(PlayerType *player_ptr, std::string_view name);
+bool activate_ball_lite(PlayerType *player_ptr, std::string_view name);
+bool activate_ball_dark(PlayerType *player_ptr, std::string_view name);
+bool activate_ball_mana(PlayerType *player_ptr, std::string_view name);
index 03bb38f..d6b06b4 100644 (file)
@@ -1,7 +1,6 @@
-#include "object-activation/activation-breath.h"
+#include "object-activation/activation-breath.h"
 #include "effect/attribute-types.h"
 #include "object-enchant/dragon-breaths-table.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "player/player-status.h"
 #include "spell-kind/spells-launcher.h"
@@ -14,6 +13,8 @@
 #include "target/target-getter.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
+#include <utility>
+#include <vector>
 
 /*!
  * @brief 発動によるブレスの属性をアイテムの耐性から選択し、実行を処理する。/ Dragon breath activation
@@ -29,20 +30,9 @@ bool activate_dragon_breath(PlayerType *player_ptr, ItemEntity *o_ptr)
         return false;
     }
 
-    auto resistance_flags = object_flags(o_ptr);
-
-    AttributeType type[20];
-    int n = 0;
-    concptr name[20];
-    for (int i = 0; dragonbreath_info[i].flag != 0; i++) {
-        if (resistance_flags.has(dragonbreath_info[i].flag)) {
-            type[n] = dragonbreath_info[i].type;
-            name[n] = dragonbreath_info[i].name;
-            n++;
-        }
-    }
-
-    if (n == 0) {
+    const auto flags = o_ptr->get_flags();
+    const auto breaths = DragonBreaths::get_breaths(flags);
+    if (breaths.empty()) {
         return false;
     }
 
@@ -54,9 +44,9 @@ bool activate_dragon_breath(PlayerType *player_ptr, ItemEntity *o_ptr)
         (void)SpellHex(player_ptr).stop_all_spells();
     }
 
-    int t = randint0(n);
-    msg_format(_("あなたは%sのブレスを吐いた。", "You breathe %s."), name[t]);
-    fire_breath(player_ptr, type[t], dir, 250, 4);
+    const auto &breath = rand_choice(breaths);
+    msg_format(_("あなたは%sのブレスを吐いた。", "You breathe %s."), breath.second.data());
+    fire_breath(player_ptr, breath.first, dir, 250, 4);
     return true;
 }
 
index 47a1baf..d05fcc4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index e56e2c3..72a7b53 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-activation/activation-charm.h"
+#include "object-activation/activation-charm.h"
 #include "spell-kind/spells-charm.h"
 #include "spell-kind/spells-sight.h"
 #include "system/player-type-definition.h"
index 9ec35a1..4455b65 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool activate_charm_animal(PlayerType *player_ptr);
index a1c9d87..5364cc4 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-activation/activation-genocide.h"
+#include "object-activation/activation-genocide.h"
 #include "spell-kind/spells-genocide.h"
 #include "system/player-type-definition.h"
 #include "view/display-messages.h"
index 2a390b3..84cd156 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool activate_genocide(PlayerType *player_ptr);
index 307b57b..98ab5d0 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 発動処理その他 (肥大化しがちなので適宜まとまりを別ファイルへ分割すること)
  * @date 2020/08/19
  * @author Hourier
@@ -9,11 +9,9 @@
 #include "avatar/avatar.h"
 #include "cmd-io/cmd-save.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
-#include "floor/cave.h"
 #include "game-option/special-options.h"
 #include "hpmp/hp-mp-processor.h"
 #include "mind/mind-archer.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
 #include "target/target-getter.h"
 #include "target/target-setter.h"
 #include "target/target-types.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "view/display-messages.h"
 
 bool activate_sunlight(PlayerType *player_ptr)
@@ -109,12 +107,12 @@ bool activate_scare(PlayerType *player_ptr)
     return true;
 }
 
-bool activate_aggravation(PlayerType *player_ptr, ItemEntity *o_ptr, concptr name)
+bool activate_aggravation(PlayerType *player_ptr, ItemEntity *o_ptr, std::string_view name)
 {
     if (o_ptr->is_specific_artifact(FixedArtifactId::HYOUSIGI)) {
         msg_print(_("拍子木を打った。", "You beat your wooden clappers."));
     } else {
-        msg_format(_("%sは不快な物音を立てた。", "The %s sounds an unpleasant noise."), name);
+        msg_format(_("%sは不快な物音を立てた。", "The %s sounds an unpleasant noise."), name.data());
     }
 
     aggravate_monsters(player_ptr, 0);
@@ -133,35 +131,35 @@ bool activate_stone_mud(PlayerType *player_ptr)
     return true;
 }
 
-bool activate_judgement(PlayerType *player_ptr, concptr name)
+bool activate_judgement(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sは赤く明るく光った!", "The %s flashes bright red!"), name);
+    msg_format(_("%sは赤く明るく光った!", "The %s flashes bright red!"), name.data());
     chg_virtue(player_ptr, Virtue::KNOWLEDGE, 1);
     chg_virtue(player_ptr, Virtue::ENLIGHTEN, 1);
     wiz_lite(player_ptr, false);
 
-    msg_format(_("%sはあなたの体力を奪った...", "The %s drains your vitality..."), name);
+    msg_format(_("%sはあなたの体力を奪った...", "The %s drains your vitality..."), name.data());
     take_hit(player_ptr, DAMAGE_LOSELIFE, damroll(3, 8), _("審判の宝石", "the Jewel of Judgement"));
 
     (void)detect_traps(player_ptr, DETECT_RAD_DEFAULT, true);
     (void)detect_doors(player_ptr, DETECT_RAD_DEFAULT);
     (void)detect_stairs(player_ptr, DETECT_RAD_DEFAULT);
 
-    if (get_check(_("帰還の力を使いますか?", "Activate recall? "))) {
+    if (input_check(_("帰還の力を使いますか?", "Activate recall? "))) {
         (void)recall_player(player_ptr, randint0(21) + 15);
     }
 
     return true;
 }
 
-bool activate_telekinesis(PlayerType *player_ptr, concptr name)
+bool activate_telekinesis(PlayerType *player_ptr, std::string_view name)
 {
     DIRECTION dir;
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
 
-    msg_format(_("%sを伸ばした。", "You stretched your %s."), name);
+    msg_format(_("%sを伸ばした。", "You stretched your %s."), name.data());
     fetch_item(player_ptr, dir, 500, true);
     return true;
 }
@@ -177,7 +175,7 @@ bool activate_unique_detection(PlayerType *player_ptr)
             continue;
         }
 
-        r_ptr = &monraces_info[m_ptr->r_idx];
+        r_ptr = &m_ptr->get_monrace();
         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
             msg_format(_("%s. ", "%s. "), r_ptr->name.data());
         }
@@ -187,16 +185,17 @@ bool activate_unique_detection(PlayerType *player_ptr)
         }
 
         if (m_ptr->r_idx == MonsterRaceId::SAURON) {
-            msg_print(_("あなたは一瞬、瞼なき御目に凝視される感覚に襲われた!", "For a moment, you had the horrible sensation of being stared at by the lidless eye!"));
+            msg_print(_("あなたは一瞬、瞼なき御目に凝視される感覚に襲われた!",
+                "For a moment, you had the horrible sensation of being stared at by the lidless eye!"));
         }
     }
 
     return true;
 }
 
-bool activate_dispel_curse(PlayerType *player_ptr, concptr name)
+bool activate_dispel_curse(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが真実を照らし出す...", "The %s exhibits the truth..."), name);
+    msg_format(_("%sが真実を照らし出す...", "The %s exhibits the truth..."), name.data());
     (void)remove_all_curse(player_ptr);
     (void)probing(player_ptr);
     return true;
@@ -212,7 +211,8 @@ bool activate_cure_lw(PlayerType *player_ptr)
 bool activate_grand_cross(PlayerType *player_ptr)
 {
     msg_print(_("「闇に還れ!」", "You say, 'Return to darkness!'"));
-    (void)project(player_ptr, 0, 8, player_ptr->y, player_ptr->x, (randint1(100) + 200) * 2, AttributeType::HOLY_FIRE, PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID);
+    constexpr auto flags = PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID;
+    (void)project(player_ptr, 0, 8, player_ptr->y, player_ptr->x, (randint1(100) + 200) * 2, AttributeType::HOLY_FIRE, flags);
     return true;
 }
 
@@ -296,9 +296,9 @@ bool activate_whirlwind(PlayerType *player_ptr)
     return true;
 }
 
-bool activate_blinding_light(PlayerType *player_ptr, concptr name)
+bool activate_blinding_light(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが眩しい光で輝いた...", "The %s gleams with blinding light..."), name);
+    msg_format(_("%sが眩しい光で輝いた...", "The %s gleams with blinding light..."), name.data());
     (void)fire_ball(player_ptr, AttributeType::LITE, 0, 300, 6);
     confuse_monsters(player_ptr, 3 * player_ptr->lev / 2);
     return true;
@@ -330,9 +330,9 @@ bool activate_recharge(PlayerType *player_ptr)
     return true;
 }
 
-bool activate_recharge_extra(PlayerType *player_ptr, concptr name)
+bool activate_recharge_extra(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが白く輝いた...", "The %s gleams with blinding light..."), name);
+    msg_format(_("%sが白く輝いた...", "The %s gleams with blinding light..."), name.data());
     return recharge(player_ptr, 1000);
 }
 
@@ -382,13 +382,13 @@ bool activate_protection_elbereth(PlayerType *player_ptr)
     (void)bss.set_blindness(0);
     (void)bss.hallucination(0);
     set_blessed(player_ptr, randint0(25) + 25, true);
-    set_bits(player_ptr->redraw, PR_ABILITY_SCORE);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
     return true;
 }
 
-bool activate_light(PlayerType *player_ptr, concptr name)
+bool activate_light(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sから澄んだ光があふれ出た...", "The %s wells with clear light..."), name);
+    msg_format(_("%sから澄んだ光があふれ出た...", "The %s wells with clear light..."), name.data());
     (void)lite_area(player_ptr, damroll(2, 15), 3);
     return true;
 }
@@ -399,10 +399,10 @@ bool activate_recall(PlayerType *player_ptr)
     return recall_player(player_ptr, randint0(21) + 15);
 }
 
-bool activate_tree_creation(PlayerType *player_ptr, ItemEntity *o_ptr, concptr name)
+bool activate_tree_creation(PlayerType *player_ptr, ItemEntity *o_ptr, std::string_view name)
 {
     const auto randart_name = o_ptr->is_random_artifact() ? o_ptr->randart_name->data() : "";
-    msg_format(_("%s%sから明るい緑の光があふれ出た...", "The %s%s wells with clear light..."), name, randart_name);
+    msg_format(_("%s%sから明るい緑の光があふれ出た...", "The %s%s wells with clear light..."), name.data(), randart_name);
     return tree_creation(player_ptr, player_ptr->y, player_ptr->x);
 }
 
@@ -435,8 +435,14 @@ bool activate_dispel_magic(PlayerType *player_ptr)
         return false;
     }
 
-    auto m_idx = player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx;
-    if ((m_idx == 0) || !player_has_los_bold(player_ptr, target_row, target_col) || !projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(target_row, target_col);
+    const auto m_idx = floor.get_grid(pos).m_idx;
+    if (m_idx == 0) {
+        return true;
+    }
+
+    if (!floor.has_los(pos) || !projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
         return true;
     }
 
index 3ea629e..9457733 100644 (file)
@@ -1,6 +1,6 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <string_view>
 
 class ItemEntity;
 class PlayerType;
@@ -8,12 +8,12 @@ bool activate_sunlight(PlayerType *player_ptr);
 bool activate_confusion(PlayerType *player_ptr);
 bool activate_banish_evil(PlayerType *player_ptr);
 bool activate_scare(PlayerType *player_ptr);
-bool activate_aggravation(PlayerType *player_ptr, ItemEntity *o_ptr, concptr name);
+bool activate_aggravation(PlayerType *player_ptr, ItemEntity *o_ptr, std::string_view name);
 bool activate_stone_mud(PlayerType *player_ptr);
-bool activate_judgement(PlayerType *player_ptr, concptr name);
-bool activate_telekinesis(PlayerType *player_ptr, concptr name);
+bool activate_judgement(PlayerType *player_ptr, std::string_view name);
+bool activate_telekinesis(PlayerType *player_ptr, std::string_view name);
 bool activate_unique_detection(PlayerType *player_ptr);
-bool activate_dispel_curse(PlayerType *player_ptr, concptr name);
+bool activate_dispel_curse(PlayerType *player_ptr, std::string_view name);
 bool activate_cure_lw(PlayerType *player_ptr);
 bool activate_grand_cross(PlayerType *player_ptr);
 bool activate_call_chaos(PlayerType *player_ptr);
@@ -26,21 +26,21 @@ bool activate_fully_identification(PlayerType *player_ptr);
 bool activate_identification(PlayerType *player_ptr);
 bool activate_pesticide(PlayerType *player_ptr);
 bool activate_whirlwind(PlayerType *player_ptr);
-bool activate_blinding_light(PlayerType *player_ptr, concptr name);
+bool activate_blinding_light(PlayerType *player_ptr, std::string_view name);
 bool activate_sleep(PlayerType *player_ptr);
 bool activate_door_destroy(PlayerType *player_ptr);
 bool activate_earthquake(PlayerType *player_ptr);
 bool activate_recharge(PlayerType *player_ptr);
-bool activate_recharge_extra(PlayerType *player_ptr, concptr name);
+bool activate_recharge_extra(PlayerType *player_ptr, std::string_view name);
 bool activate_shikofumi(PlayerType *player_ptr);
 bool activate_terror(PlayerType *player_ptr);
 bool activate_map_light(PlayerType *player_ptr);
 bool activate_exploding_rune(PlayerType *player_ptr);
 bool activate_protection_rune(PlayerType *player_ptr);
 bool activate_protection_elbereth(PlayerType *player_ptr);
-bool activate_light(PlayerType *player_ptr, concptr name);
+bool activate_light(PlayerType *player_ptr, std::string_view name);
 bool activate_recall(PlayerType *player_ptr);
-bool activate_tree_creation(PlayerType *player_ptr, ItemEntity *o_ptr, concptr name);
+bool activate_tree_creation(PlayerType *player_ptr, ItemEntity *o_ptr, std::string_view name);
 bool activate_animate_dead(PlayerType *player_ptr, ItemEntity *o_ptr);
 bool activate_detect_treasure(PlayerType *player_ptr);
 bool activate_create_ammo(PlayerType *player_ptr);
index 5a2ea89..366be61 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-activation/activation-resistance.h"
+#include "object-activation/activation-resistance.h"
 #include "effect/attribute-types.h"
 #include "hpmp/hp-mp-processor.h"
 #include "spell-kind/spells-launcher.h"
@@ -29,9 +29,9 @@ bool activate_resistance_elements(PlayerType *player_ptr)
  * @param name アイテム名
  * @return 発動をキャンセルした場合FALSE、それ以外はTRUEを返す
  */
-bool activate_acid_ball_and_resistance(PlayerType *player_ptr, concptr name)
+bool activate_acid_ball_and_resistance(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが黒く輝いた...", "The %s grows black."), name);
+    msg_format(_("%sが黒く輝いた...", "The %s grows black."), name.data());
 
     DIRECTION dir;
     if (!get_aim_dir(player_ptr, &dir)) {
@@ -50,9 +50,9 @@ bool activate_acid_ball_and_resistance(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 発動をキャンセルした場合FALSE、それ以外はTRUEを返す
  */
-bool activate_elec_ball_and_resistance(PlayerType *player_ptr, concptr name)
+bool activate_elec_ball_and_resistance(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが青く輝いた...", "The %s grows blue."), name);
+    msg_format(_("%sが青く輝いた...", "The %s grows blue."), name.data());
 
     DIRECTION dir;
     if (!get_aim_dir(player_ptr, &dir)) {
@@ -71,9 +71,9 @@ bool activate_elec_ball_and_resistance(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 発動をキャンセルした場合FALSE、それ以外はTRUEを返す
  */
-bool activate_fire_ball_and_resistance(PlayerType *player_ptr, concptr name)
+bool activate_fire_ball_and_resistance(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが赤く輝いた...", "The %s grows red."), name);
+    msg_format(_("%sが赤く輝いた...", "The %s grows red."), name.data());
 
     DIRECTION dir;
     if (!get_aim_dir(player_ptr, &dir)) {
@@ -92,9 +92,9 @@ bool activate_fire_ball_and_resistance(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 発動をキャンセルした場合FALSE、それ以外はTRUEを返す
  */
-bool activate_cold_ball_and_resistance(PlayerType *player_ptr, concptr name)
+bool activate_cold_ball_and_resistance(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが白く輝いた...", "The %s grows white."), name);
+    msg_format(_("%sが白く輝いた...", "The %s grows white."), name.data());
 
     DIRECTION dir;
     if (!get_aim_dir(player_ptr, &dir)) {
@@ -113,9 +113,9 @@ bool activate_cold_ball_and_resistance(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 発動をキャンセルした場合FALSE、それ以外はTRUEを返す
  */
-bool activate_pois_ball_and_resistance(PlayerType *player_ptr, concptr name)
+bool activate_pois_ball_and_resistance(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが緑に輝いた...", "The %s grows green."), name);
+    msg_format(_("%sが緑に輝いた...", "The %s grows green."), name.data());
 
     DIRECTION dir;
     if (!get_aim_dir(player_ptr, &dir)) {
@@ -134,9 +134,9 @@ bool activate_pois_ball_and_resistance(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 常にTRUE
  */
-bool activate_resistance_acid(PlayerType *player_ptr, concptr name)
+bool activate_resistance_acid(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが黒く輝いた...", "The %s grows black."), name);
+    msg_format(_("%sが黒く輝いた...", "The %s grows black."), name.data());
     (void)set_oppose_acid(player_ptr, randint1(20) + 20, false);
     return true;
 }
@@ -147,9 +147,9 @@ bool activate_resistance_acid(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 常にTRUE
  */
-bool activate_resistance_elec(PlayerType *player_ptr, concptr name)
+bool activate_resistance_elec(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが青く輝いた...", "The %s grows blue."), name);
+    msg_format(_("%sが青く輝いた...", "The %s grows blue."), name.data());
     (void)set_oppose_elec(player_ptr, randint1(20) + 20, false);
     return true;
 }
@@ -160,9 +160,9 @@ bool activate_resistance_elec(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 常にTRUE
  */
-bool activate_resistance_fire(PlayerType *player_ptr, concptr name)
+bool activate_resistance_fire(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが赤く輝いた...", "The %s grows red."), name);
+    msg_format(_("%sが赤く輝いた...", "The %s grows red."), name.data());
     (void)set_oppose_fire(player_ptr, randint1(20) + 20, false);
     return true;
 }
@@ -173,9 +173,9 @@ bool activate_resistance_fire(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 常にTRUE
  */
-bool activate_resistance_cold(PlayerType *player_ptr, concptr name)
+bool activate_resistance_cold(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが白く輝いた...", "The %s grows white."), name);
+    msg_format(_("%sが白く輝いた...", "The %s grows white."), name.data());
     (void)set_oppose_cold(player_ptr, randint1(20) + 20, false);
     return true;
 }
@@ -186,9 +186,9 @@ bool activate_resistance_cold(PlayerType *player_ptr, concptr name)
  * @param name アイテム名
  * @return 常にTRUE
  */
-bool activate_resistance_pois(PlayerType *player_ptr, concptr name)
+bool activate_resistance_pois(PlayerType *player_ptr, std::string_view name)
 {
-    msg_format(_("%sが緑に輝いた...", "The %s grows green."), name);
+    msg_format(_("%sが緑に輝いた...", "The %s grows green."), name.data());
     (void)set_oppose_pois(player_ptr, randint1(20) + 20, false);
     return true;
 }
index c9ec17a..77871b7 100644 (file)
@@ -1,17 +1,17 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <string_view>
 
 class PlayerType;
 bool activate_resistance_elements(PlayerType *player_ptr);
-bool activate_resistance_acid(PlayerType *player_ptr, concptr name);
-bool activate_resistance_elec(PlayerType *player_ptr, concptr name);
-bool activate_resistance_fire(PlayerType *player_ptr, concptr name);
-bool activate_resistance_cold(PlayerType *player_ptr, concptr name);
-bool activate_resistance_pois(PlayerType *player_ptr, concptr name);
-bool activate_acid_ball_and_resistance(PlayerType *player_ptr, concptr name);
-bool activate_elec_ball_and_resistance(PlayerType *player_ptr, concptr name);
-bool activate_fire_ball_and_resistance(PlayerType *player_ptr, concptr name);
-bool activate_cold_ball_and_resistance(PlayerType *player_ptr, concptr name);
-bool activate_pois_ball_and_resistance(PlayerType *player_ptr, concptr name);
+bool activate_resistance_acid(PlayerType *player_ptr, std::string_view name);
+bool activate_resistance_elec(PlayerType *player_ptr, std::string_view name);
+bool activate_resistance_fire(PlayerType *player_ptr, std::string_view name);
+bool activate_resistance_cold(PlayerType *player_ptr, std::string_view name);
+bool activate_resistance_pois(PlayerType *player_ptr, std::string_view name);
+bool activate_acid_ball_and_resistance(PlayerType *player_ptr, std::string_view name);
+bool activate_elec_ball_and_resistance(PlayerType *player_ptr, std::string_view name);
+bool activate_fire_ball_and_resistance(PlayerType *player_ptr, std::string_view name);
+bool activate_cold_ball_and_resistance(PlayerType *player_ptr, std::string_view name);
+bool activate_pois_ball_and_resistance(PlayerType *player_ptr, std::string_view name);
 bool activate_ultimate_resistance(PlayerType *player_ptr);
index a4b3def..29f4b73 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーの発動コマンド実装
  * @date 2018/09/07
  * @author deskull
 #include "timed-effect/player-acceleration.h"
 #include "view/display-messages.h"
 
-bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const activation_type *const act_ptr, concptr name)
+bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const RandomArtActType index, std::string_view name)
 {
-    auto *o_ptr = (*o_ptr_ptr);
-
-    switch (act_ptr->index) {
+    auto *o_ptr = *o_ptr_ptr;
+    switch (index) {
     case RandomArtActType::SUNLIGHT:
         return activate_sunlight(player_ptr);
     case RandomArtActType::BO_MISS_1:
@@ -222,11 +221,11 @@ bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const act
         (void)cure_critical_wounds(player_ptr, 1000);
         return true;
     case RandomArtActType::CURING:
-        msg_format(_("%sの優しさに癒される...", "the %s cures you affectionately ..."), name);
+        msg_format(_("%sの優しさに癒される...", "the %s cures you affectionately ..."), name.data());
         true_healing(player_ptr, 0);
         return true;
     case RandomArtActType::CURE_MANA_FULL:
-        msg_format(_("%sが青白く光った...", "The %s glows palely..."), name);
+        msg_format(_("%sが青白く光った...", "The %s glows palely..."), name.data());
         restore_mana(player_ptr, true);
         return true;
     case RandomArtActType::ESP:
@@ -236,7 +235,7 @@ bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const act
         (void)berserk(player_ptr, randint1(25) + 25);
         return true;
     case RandomArtActType::PROT_EVIL:
-        msg_format(_("%sから鋭い音が流れ出た...", "The %s lets out a shrill wail..."), name);
+        msg_format(_("%sから鋭い音が流れ出た...", "The %s lets out a shrill wail..."), name.data());
         (void)set_protevil(player_ptr, randint1(25) + player_ptr->lev * 3, false);
         return true;
     case RandomArtActType::RESIST_ALL:
@@ -332,7 +331,7 @@ bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const act
     case RandomArtActType::DISP_CURSE_XTRA:
         return activate_dispel_curse(player_ptr, name);
     case RandomArtActType::BRAND_FIRE_BOLTS:
-        msg_format(_("%sが深紅に輝いた...", "Your %s glows deep red..."), name);
+        msg_format(_("%sが深紅に輝いた...", "Your %s glows deep red..."), name.data());
         brand_bolts(player_ptr);
         return true;
     case RandomArtActType::RECHARGE_XTRA:
@@ -361,7 +360,7 @@ bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const act
     case RandomArtActType::TELEPORT_LEVEL:
         return activate_teleport_level(player_ptr);
     case RandomArtActType::STRAIN_HASTE:
-        msg_format(_("%sはあなたの体力を奪った...", "The %s drains your vitality..."), name);
+        msg_format(_("%sはあなたの体力を奪った...", "The %s drains your vitality..."), name.data());
         take_hit(player_ptr, DAMAGE_LOSELIFE, damroll(3, 8), _("加速した疲労", "the strain of haste"));
         (void)mod_acceleration(player_ptr, 25 + randint1(25), false);
         return true;
@@ -385,7 +384,7 @@ bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const act
     case RandomArtActType::DISPEL_MAGIC:
         return activate_dispel_magic(player_ptr);
     default:
-        msg_format(_("Unknown activation effect: %d.", "Unknown activation effect: %d."), enum2i(act_ptr->index));
+        msg_format(_("Unknown activation effect: %d.", "Unknown activation effect: %d."), enum2i(index));
         return false;
     }
 }
index c303c88..67aa35c 100644 (file)
@@ -1,8 +1,8 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <string_view>
 
-struct activation_type;
+enum class RandomArtActType : short;
 class ItemEntity;
 class PlayerType;
-bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const activation_type *const act_ptr, concptr name);
+bool switch_activation(PlayerType *player_ptr, ItemEntity **o_ptr_ptr, const RandomArtActType index, std::string_view name);
index 401e49c..444e5a1 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-activation/activation-teleport.h"
+#include "object-activation/activation-teleport.h"
 #include "cmd-io/cmd-save.h"
 #include "core/asking-player.h"
 #include "effect/attribute-types.h"
@@ -44,7 +44,7 @@ bool activate_escape(PlayerType *player_ptr)
         (void)stair_creation(player_ptr);
         return true;
     default:
-        if (!get_check(_("この階を去りますか?", "Leave this level? "))) {
+        if (!input_check(_("この階を去りますか?", "Leave this level? "))) {
             return true;
         }
 
@@ -59,7 +59,7 @@ bool activate_escape(PlayerType *player_ptr)
 
 bool activate_teleport_level(PlayerType *player_ptr)
 {
-    if (!get_check(_("本当に他の階にテレポートしますか?", "Are you sure? (Teleport Level)"))) {
+    if (!input_check(_("本当に他の階にテレポートしますか?", "Are you sure? (Teleport Level)"))) {
         return false;
     }
 
index 54b8900..d0c0aa3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool activate_teleport_away(PlayerType *player_ptr);
index ca1726f..febe74f 100644 (file)
@@ -1,12 +1,12 @@
-#include "object-activation/activation-util.h"
+#include "object-activation/activation-util.h"
 #include "object/object-info.h"
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
 
-ae_type *initialize_ae_type(PlayerType *player_ptr, ae_type *ae_ptr, const INVENTORY_IDX item)
+ae_type *initialize_ae_type(PlayerType *player_ptr, ae_type *ae_ptr, const INVENTORY_IDX i_idx)
 {
-    ae_ptr->o_ptr = ref_item(player_ptr, item);
+    ae_ptr->o_ptr = ref_item(player_ptr, i_idx);
     ae_ptr->lev = ae_ptr->o_ptr->get_baseitem().level;
     return ae_ptr;
 }
index 2bc44d5..914a548 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -14,4 +14,4 @@ struct ae_type {
 };
 
 class PlayerType;
-ae_type *initialize_ae_type(PlayerType *player_ptr, ae_type *ae_ptr, const INVENTORY_IDX item);
+ae_type *initialize_ae_type(PlayerType *player_ptr, ae_type *ae_ptr, const INVENTORY_IDX i_idx);
index dc1bb92..e906e29 100644 (file)
-#include "object-enchant/activation-info-table.h"
+#include "object-enchant/activation-info-table.h"
 #include "artifact/random-art-effects.h"
+#include "locale/language-switcher.h"
+#include <sstream>
 
 /*!
- * @brief アイテムの発動効果テーブル /
- * Define flags, levels, values of activations
+ * @brief アイテムの発動効果テーブル
  */
-const std::vector<activation_type> activation_info = {
-    { "SUNLIGHT", RandomArtActType::SUNLIGHT, 10, 250, { 10, 0 }, _("太陽光線", "beam of sunlight") },
-    { "BO_MISS_1", RandomArtActType::BO_MISS_1, 10, 250, { 2, 0 }, _("マジック・ミサイル(2d6)", "magic missile (2d6)") },
-    { "BA_POIS_1", RandomArtActType::BA_POIS_1, 10, 300, { 4, 0 }, _("悪臭雲(12)", "stinking cloud (12)") },
-    { "BO_ELEC_1", RandomArtActType::BO_ELEC_1, 20, 250, { 5, 0 }, _("サンダー・ボルト(4d8)", "lightning bolt (4d8)") },
-    { "BO_ACID_1", RandomArtActType::BO_ACID_1, 20, 250, { 6, 0 }, _("アシッド・ボルト(5d8)", "acid bolt (5d8)") },
-    { "BO_COLD_1", RandomArtActType::BO_COLD_1, 20, 250, { 7, 0 }, _("アイス・ボルト(6d8)", "frost bolt (6d8)") },
-    { "BO_FIRE_1", RandomArtActType::BO_FIRE_1, 20, 250, { 8, 0 }, _("ファイア・ボルト(9d8)", "fire bolt (9d8)") },
-    { "BA_COLD_1", RandomArtActType::BA_COLD_1, 30, 750, { 6, 0 }, _("アイス・ボール(48)", "ball of cold (48)") },
-    { "BA_COLD_2", RandomArtActType::BA_COLD_2, 40, 1000, { 12, 0 }, _("アイス・ボール(100)", "ball of cold (100)") },
-    { "BA_COLD_3", RandomArtActType::BA_COLD_3, 70, 2500, { 50, 0 }, _("巨大アイス・ボール(400)", "ball of cold (400)") },
-    { "BA_FIRE_1", RandomArtActType::BA_FIRE_1, 30, 1000, { 9, 0 }, _("ファイア・ボール(72)", "ball of fire (72)") },
-    { "BA_FIRE_2", RandomArtActType::BA_FIRE_2, 40, 1500, { 15, 0 }, _("巨大ファイア・ボール(120)", "large fire ball (120)") },
-    { "BA_FIRE_3", RandomArtActType::BA_FIRE_3, 60, 1750, { 40, 0 }, _("巨大ファイア・ボール(300)", "fire ball (300)") },
-    { "BA_FIRE_4", RandomArtActType::BA_FIRE_4, 40, 1000, { 12, 0 }, _("ファイア・ボール(100)", "fire ball (100)") },
-    { "BA_ELEC_2", RandomArtActType::BA_ELEC_2, 40, 1000, { 12, 0 }, _("サンダー・ボール(100)", "ball of lightning (100)") },
-    { "BA_ELEC_3", RandomArtActType::BA_ELEC_3, 70, 2500, { 70, 0 }, _("巨大サンダー・ボール(500)", "ball of lightning (500)") },
-    { "BA_ACID_1", RandomArtActType::BA_ACID_1, 30, 1000, { 12, 0 }, _("アシッド・ボール(100)", "ball of acid (100)") },
-    { "BA_NUKE_1", RandomArtActType::BA_NUKE_1, 50, 1000, { 12, 0 }, _("放射能球(100)", "ball of nuke (100)") },
-    { "HYPODYNAMIA_1", RandomArtActType::HYPODYNAMIA_1, 30, 500, { 12, 0 }, _("窒息攻撃(100)", "a strangling attack (100)") },
-    { "HYPODYNAMIA_2", RandomArtActType::HYPODYNAMIA_2, 40, 750, { 15, 0 }, _("衰弱の矢(120)", "hypodynamic bolt (120)") },
-    { "DRAIN_1", RandomArtActType::DRAIN_1, 40, 1000, { 20, 0 }, _("吸収の矢(3*50)", "drain bolt (3*50)") },
-    { "BO_MISS_2", RandomArtActType::BO_MISS_2, 40, 1000, { 20, 0 }, _("矢(150)", "arrows (150)") },
-    { "WHIRLWIND", RandomArtActType::WHIRLWIND, 50, 7500, { 25, 0 }, _("カマイタチ", "whirlwind attack") },
-    { "DRAIN_2", RandomArtActType::DRAIN_2, 50, 2500, { 40, 0 }, _("吸収の矢(3*100)", "drain bolt (3*100)") },
-    { "CALL_CHAOS", RandomArtActType::CALL_CHAOS, 70, 5000, { 35, 0 }, _("混沌召来", "call chaos") },
-    { "ROCKET", RandomArtActType::ROCKET, 70, 5000, { 20, 0 }, _("ロケット(120+レベル)", "launch rocket (120+level)") },
-    { "DISP_EVIL", RandomArtActType::DISP_EVIL, 50, 4000, { 50, 0 }, _("邪悪退散(x5)", "dispel evil (x5)") },
-    { "BA_MISS_3", RandomArtActType::BA_MISS_3, 50, 1500, { 50, 0 }, _("エレメントのブレス(300)", "elemental breath (300)") },
-    { "DISP_GOOD", RandomArtActType::DISP_GOOD, 50, 3500, { 50, 0 }, _("善良退散(x5)", "dispel good (x5)") },
-    { "BO_MANA", RandomArtActType::BO_MANA, 40, 1500, { 20, 0 }, _("魔法の矢(150)", "a magical arrow (150)") },
-    { "BA_WATER", RandomArtActType::BA_WATER, 50, 2000, { 25, 0 }, _("ウォーター・ボール(200)", "water ball (200)") },
-    { "BA_STAR", RandomArtActType::BA_STAR, 50, 2200, { 25, 0 }, _("巨大スター・ボール(200)", "large star ball (200)") },
+const std::vector<ActivationType> activation_info = {
+    { "SUNLIGHT", RandomArtActType::SUNLIGHT, 10, 250, 10, 0, _("太陽光線", "beam of sunlight") },
+    { "BO_MISS_1", RandomArtActType::BO_MISS_1, 10, 250, 2, 0, _("マジック・ミサイル(2d6)", "magic missile (2d6)") },
+    { "BA_POIS_1", RandomArtActType::BA_POIS_1, 10, 300, 4, 0, _("悪臭雲(12)", "stinking cloud (12)") },
+    { "BO_ELEC_1", RandomArtActType::BO_ELEC_1, 20, 250, 5, 0, _("サンダー・ボルト(4d8)", "lightning bolt (4d8)") },
+    { "BO_ACID_1", RandomArtActType::BO_ACID_1, 20, 250, 6, 0, _("アシッド・ボルト(5d8)", "acid bolt (5d8)") },
+    { "BO_COLD_1", RandomArtActType::BO_COLD_1, 20, 250, 7, 0, _("アイス・ボルト(6d8)", "frost bolt (6d8)") },
+    { "BO_FIRE_1", RandomArtActType::BO_FIRE_1, 20, 250, 8, 0, _("ファイア・ボルト(9d8)", "fire bolt (9d8)") },
+    { "BA_COLD_1", RandomArtActType::BA_COLD_1, 30, 750, 6, 0, _("アイス・ボール(48)", "ball of cold (48)") },
+    { "BA_COLD_2", RandomArtActType::BA_COLD_2, 40, 1000, 12, 0, _("アイス・ボール(100)", "ball of cold (100)") },
+    { "BA_COLD_3", RandomArtActType::BA_COLD_3, 70, 2500, 50, 0, _("巨大アイス・ボール(400)", "ball of cold (400)") },
+    { "BA_FIRE_1", RandomArtActType::BA_FIRE_1, 30, 1000, 9, 0, _("ファイア・ボール(72)", "ball of fire (72)") },
+    { "BA_FIRE_2", RandomArtActType::BA_FIRE_2, 40, 1500, 15, 0, _("巨大ファイア・ボール(120)", "large fire ball (120)") },
+    { "BA_FIRE_3", RandomArtActType::BA_FIRE_3, 60, 1750, 40, 0, _("巨大ファイア・ボール(300)", "fire ball (300)") },
+    { "BA_FIRE_4", RandomArtActType::BA_FIRE_4, 40, 1000, 12, 0, _("ファイア・ボール(100)", "fire ball (100)") },
+    { "BA_ELEC_2", RandomArtActType::BA_ELEC_2, 40, 1000, 12, 0, _("サンダー・ボール(100)", "ball of lightning (100)") },
+    { "BA_ELEC_3", RandomArtActType::BA_ELEC_3, 70, 2500, 70, 0, _("巨大サンダー・ボール(500)", "ball of lightning (500)") },
+    { "BA_ACID_1", RandomArtActType::BA_ACID_1, 30, 1000, 12, 0, _("アシッド・ボール(100)", "ball of acid (100)") },
+    { "BA_NUKE_1", RandomArtActType::BA_NUKE_1, 50, 1000, 12, 0, _("放射能球(100)", "ball of nuke (100)") },
+    { "HYPODYNAMIA_1", RandomArtActType::HYPODYNAMIA_1, 30, 500, 12, 0, _("窒息攻撃(100)", "a strangling attack (100)") },
+    { "HYPODYNAMIA_2", RandomArtActType::HYPODYNAMIA_2, 40, 750, 15, 0, _("衰弱の矢(120)", "hypodynamic bolt (120)") },
+    { "DRAIN_1", RandomArtActType::DRAIN_1, 40, 1000, 20, 0, _("吸収の矢(3*50)", "drain bolt (3*50)") },
+    { "BO_MISS_2", RandomArtActType::BO_MISS_2, 40, 1000, 20, 0, _("矢(150)", "arrows (150)") },
+    { "WHIRLWIND", RandomArtActType::WHIRLWIND, 50, 7500, 25, 0, _("カマイタチ", "whirlwind attack") },
+    { "DRAIN_2", RandomArtActType::DRAIN_2, 50, 2500, 40, 0, _("吸収の矢(3*100)", "drain bolt (3*100)") },
+    { "CALL_CHAOS", RandomArtActType::CALL_CHAOS, 70, 5000, 35, 0, _("混沌召来", "call chaos") },
+    { "ROCKET", RandomArtActType::ROCKET, 70, 5000, 20, 0, _("ロケット(120+レベル)", "launch rocket (120+level)") },
+    { "DISP_EVIL", RandomArtActType::DISP_EVIL, 50, 4000, 50, 0, _("邪悪退散(x5)", "dispel evil (x5)") },
+    { "BA_MISS_3", RandomArtActType::BA_MISS_3, 50, 1500, 50, 0, _("エレメントのブレス(300)", "elemental breath (300)") },
+    { "DISP_GOOD", RandomArtActType::DISP_GOOD, 50, 3500, 50, 0, _("善良退散(x5)", "dispel good (x5)") },
+    { "BO_MANA", RandomArtActType::BO_MANA, 40, 1500, 20, 0, _("魔法の矢(150)", "a magical arrow (150)") },
+    { "BA_WATER", RandomArtActType::BA_WATER, 50, 2000, 25, 0, _("ウォーター・ボール(200)", "water ball (200)") },
+    { "BA_STAR", RandomArtActType::BA_STAR, 50, 2200, 25, 0, _("巨大スター・ボール(200)", "large star ball (200)") },
 
-    { "BA_DARK", RandomArtActType::BA_DARK, 50, 2200, { 30, 0 }, _("暗黒の嵐(250)", "darkness storm (250)") },
-    { "BA_MANA", RandomArtActType::BA_MANA, 70, 2500, { 30, 0 }, _("魔力の嵐(250)", "a mana storm (250)") },
-    { "PESTICIDE", RandomArtActType::PESTICIDE, 10, 500, { 10, 0 }, _("害虫の駆除", "dispel pests") },
-    { "BLINDING_LIGHT", RandomArtActType::BLINDING_LIGHT, 30, 5000, { 40, 0 }, _("眩しい光", "blinding light") },
-    { "BIZARRE", RandomArtActType::BIZARRE, 90, 10000, { 50, 0 }, _("信じ難いこと", "bizarre things") },
-    { "CAST_BA_STAR", RandomArtActType::CAST_BA_STAR, 70, 7500, { 100, 0 }, _("スター・ボール・ダスト(150)", "cast star balls (150)") },
-    { "BLADETURNER", RandomArtActType::BLADETURNER, 80, 20000, { 80, 0 },
+    { "BA_DARK", RandomArtActType::BA_DARK, 50, 2200, 30, 0, _("暗黒の嵐(250)", "darkness storm (250)") },
+    { "BA_MANA", RandomArtActType::BA_MANA, 70, 2500, 30, 0, _("魔力の嵐(250)", "a mana storm (250)") },
+    { "PESTICIDE", RandomArtActType::PESTICIDE, 10, 500, 10, 0, _("害虫の駆除", "dispel pests") },
+    { "BLINDING_LIGHT", RandomArtActType::BLINDING_LIGHT, 30, 5000, 40, 0, _("眩しい光", "blinding light") },
+    { "BIZARRE", RandomArtActType::BIZARRE, 90, 10000, 50, 0, _("信じ難いこと", "bizarre things") },
+    { "CAST_BA_STAR", RandomArtActType::CAST_BA_STAR, 70, 7500, 100, 0, _("スター・ボール・ダスト(150)", "cast star balls (150)") },
+    { "BLADETURNER", RandomArtActType::BLADETURNER, 80, 20000, 80, 0,
         _("エレメントのブレス(300), 士気高揚、祝福、耐性", "breathe elements (300), hero, bless, and resistance") },
-    { "BR_FIRE", RandomArtActType::BR_FIRE, 50, 5000, { -1, 0 }, _("火炎のブレス (200)", "fire breath (200)") },
-    { "BR_COLD", RandomArtActType::BR_COLD, 50, 5000, { -1, 0 }, _("冷気のブレス (200)", "cold breath (200)") },
-    { "BR_DRAGON", RandomArtActType::BR_DRAGON, 70, 10000, { 30, 0 }, "" /* built by item_activation_dragon_breath() */ },
-    { "CONFUSE", RandomArtActType::CONFUSE, 10, 500, { 10, 0 }, _("パニック・モンスター", "confuse monster") },
-    { "SLEEP", RandomArtActType::SLEEP, 10, 750, { 15, 0 }, _("周囲のモンスターを眠らせる", "sleep nearby monsters") },
-    { "QUAKE", RandomArtActType::QUAKE, 30, 600, { 20, 0 }, _("地震", "earthquake") },
-    { "TERROR", RandomArtActType::TERROR, 20, 2500, { -1, 0 }, _("恐慌", "terror") },
-    { "TELE_AWAY", RandomArtActType::TELE_AWAY, 20, 2000, { 15, 0 }, _("テレポート・アウェイ", "teleport away") },
-    { "BANISH_EVIL", RandomArtActType::BANISH_EVIL, 40, 2000, { 250, 0 }, _("邪悪消滅", "banish evil") },
-    { "GENOCIDE", RandomArtActType::GENOCIDE, 50, 10000, { 500, 0 }, _("抹殺", "genocide") },
-    { "MASS_GENO", RandomArtActType::MASS_GENO, 50, 10000, { 1000, 0 }, _("周辺抹殺", "mass genocide") },
-    { "SCARE_AREA", RandomArtActType::SCARE_AREA, 20, 2500, { 20, 0 }, _("モンスター恐慌", "frighten monsters") },
-    { "AGGRAVATE", RandomArtActType::AGGRAVATE, 0, 100, { 0, 0 }, _("モンスターを怒らせる", "aggravate monsters") },
-    { "CHARM_ANIMAL", RandomArtActType::CHARM_ANIMAL, 40, 7500, { 200, 0 }, _("動物魅了", "charm animal") },
-    { "CHARM_UNDEAD", RandomArtActType::CHARM_UNDEAD, 40, 10000, { 333, 0 }, _("アンデッド従属", "enslave undead") },
-    { "CHARM_OTHER", RandomArtActType::CHARM_OTHER, 40, 10000, { 400, 0 }, _("モンスター魅了", "charm monster") },
-    { "CHARM_ANIMALS", RandomArtActType::CHARM_ANIMALS, 40, 12500, { 500, 0 }, _("動物友和", "animal friendship") },
-    { "CHARM_OTHERS", RandomArtActType::CHARM_OTHERS, 40, 17500, { 750, 0 }, _("周辺魅了", "mass charm") },
-    { "SUMMON_ANIMAL", RandomArtActType::SUMMON_ANIMAL, 50, 10000, { 200, 300 }, _("動物召喚", "summon animal") },
-    { "SUMMON_PHANTOM", RandomArtActType::SUMMON_PHANTOM, 50, 12000, { 200, 200 }, _("幻霊召喚", "summon phantasmal servant") },
-    { "SUMMON_ELEMENTAL", RandomArtActType::SUMMON_ELEMENTAL, 50, 15000, { 750, 0 }, _("エレメンタル召喚", "summon elemental") },
-    { "SUMMON_DEMON", RandomArtActType::SUMMON_DEMON, 50, 20000, { 666, 0 }, _("悪魔召喚", "summon demon") },
-    { "SUMMON_UNDEAD", RandomArtActType::SUMMON_UNDEAD, 50, 20000, { 666, 0 }, _("アンデッド召喚", "summon undead") },
-    { "SUMMON_HOUND", RandomArtActType::SUMMON_HOUND, 50, 15000, { 300, 0 }, _("ハウンド召喚", "summon hound") },
-    { "SUMMON_DAWN", RandomArtActType::SUMMON_DAWN, 50, 15000, { 500, 0 }, _("暁の師団召喚", "summon the Legion of the Dawn") },
+    { "BR_FIRE", RandomArtActType::BR_FIRE, 50, 5000, std::nullopt, 0, _("火炎のブレス (200)", "fire breath (200)") },
+    { "BR_COLD", RandomArtActType::BR_COLD, 50, 5000, std::nullopt, 0, _("冷気のブレス (200)", "cold breath (200)") },
+    { "BR_DRAGON", RandomArtActType::BR_DRAGON, 70, 10000, 30, 0, "" /* built by item_activation_dragon_breath() */ },
+    { "CONFUSE", RandomArtActType::CONFUSE, 10, 500, 10, 0, _("パニック・モンスター", "confuse monster") },
+    { "SLEEP", RandomArtActType::SLEEP, 10, 750, 15, 0, _("周囲のモンスターを眠らせる", "sleep nearby monsters") },
+    { "QUAKE", RandomArtActType::QUAKE, 30, 600, 20, 0, _("地震", "earthquake") },
+    { "TERROR", RandomArtActType::TERROR, 20, 2500, std::nullopt, 0, _("恐慌", "terror") },
+    { "TELE_AWAY", RandomArtActType::TELE_AWAY, 20, 2000, 15, 0, _("テレポート・アウェイ", "teleport away") },
+    { "BANISH_EVIL", RandomArtActType::BANISH_EVIL, 40, 2000, 250, 0, _("邪悪消滅", "banish evil") },
+    { "GENOCIDE", RandomArtActType::GENOCIDE, 50, 10000, 500, 0, _("抹殺", "genocide") },
+    { "MASS_GENO", RandomArtActType::MASS_GENO, 50, 10000, 1000, 0, _("周辺抹殺", "mass genocide") },
+    { "SCARE_AREA", RandomArtActType::SCARE_AREA, 20, 2500, 20, 0, _("モンスター恐慌", "frighten monsters") },
+    { "AGGRAVATE", RandomArtActType::AGGRAVATE, 0, 100, 0, 0, _("モンスターを怒らせる", "aggravate monsters") },
+    { "CHARM_ANIMAL", RandomArtActType::CHARM_ANIMAL, 40, 7500, 200, 0, _("動物魅了", "charm animal") },
+    { "CHARM_UNDEAD", RandomArtActType::CHARM_UNDEAD, 40, 10000, 333, 0, _("アンデッド従属", "enslave undead") },
+    { "CHARM_OTHER", RandomArtActType::CHARM_OTHER, 40, 10000, 400, 0, _("モンスター魅了", "charm monster") },
+    { "CHARM_ANIMALS", RandomArtActType::CHARM_ANIMALS, 40, 12500, 500, 0, _("動物友和", "animal friendship") },
+    { "CHARM_OTHERS", RandomArtActType::CHARM_OTHERS, 40, 17500, 750, 0, _("周辺魅了", "mass charm") },
+    { "SUMMON_ANIMAL", RandomArtActType::SUMMON_ANIMAL, 50, 10000, 200, 300, _("動物召喚", "summon animal") },
+    { "SUMMON_PHANTOM", RandomArtActType::SUMMON_PHANTOM, 50, 12000, 200, 200, _("幻霊召喚", "summon phantasmal servant") },
+    { "SUMMON_ELEMENTAL", RandomArtActType::SUMMON_ELEMENTAL, 50, 15000, 750, 0, _("エレメンタル召喚", "summon elemental") },
+    { "SUMMON_DEMON", RandomArtActType::SUMMON_DEMON, 50, 20000, 666, 0, _("悪魔召喚", "summon demon") },
+    { "SUMMON_UNDEAD", RandomArtActType::SUMMON_UNDEAD, 50, 20000, 666, 0, _("アンデッド召喚", "summon undead") },
+    { "SUMMON_HOUND", RandomArtActType::SUMMON_HOUND, 50, 15000, 300, 0, _("ハウンド召喚", "summon hound") },
+    { "SUMMON_DAWN", RandomArtActType::SUMMON_DAWN, 50, 15000, 500, 0, _("暁の師団召喚", "summon the Legion of the Dawn") },
 
-    { "SUMMON_OCTOPUS", RandomArtActType::SUMMON_OCTOPUS, 50, 15000, { 300, 0 }, _("蛸の大群召喚", "summon octopus") },
-    { "CHOIR_SINGS", RandomArtActType::CHOIR_SINGS, 60, 20000, { 300, 0 }, _("回復(777)、癒し、士気高揚", "heal 777 hit points, curing and HEROism") },
-    { "CURE_LW", RandomArtActType::CURE_LW, 10, 500, { 10, 0 }, _("恐怖除去/体力回復(30)", "remove fear and heal 30 hp") },
-    { "CURE_MW", RandomArtActType::CURE_MW, 20, 750, { 3, 3 }, _("傷回復(4d8)", "heal 4d8 and wounds") },
-    { "CURE_POISON", RandomArtActType::CURE_POISON, 10, 1000, { 5, 0 }, _("恐怖除去/毒消し", "remove fear and cure poison") },
-    { "REST_LIFE", RandomArtActType::REST_EXP, 40, 7500, { 450, 0 }, _("経験値復活", "restore experience") },
-    { "REST_ALL", RandomArtActType::REST_ALL, 30, 15000, { 750, 0 }, _("全ステータスと経験値復活", "restore stats and experience") },
-    { "CURE_700", RandomArtActType::CURE_700, 40, 10000, { 250, 0 }, _("体力回復(700)", "heal 700 hit points") },
-    { "CURE_1000", RandomArtActType::CURE_1000, 50, 15000, { 888, 0 }, _("体力回復(1000)", "heal 1000 hit points") },
-    { "CURING", RandomArtActType::CURING, 30, 5000, { 100, 0 }, _("癒し", "curing") },
-    { "CURE_MANA_FULL", RandomArtActType::CURE_MANA_FULL, 60, 20000, { 777, 0 }, _("魔力復活", "restore mana") },
-    { "ESP", RandomArtActType::ESP, 30, 1500, { 100, 0 }, _("テレパシー(期間 25+d30)", "telepathy (dur 25+d30)") },
-    { "BERSERK", RandomArtActType::BERSERK, 10, 800, { 75, 0 }, _("狂戦士化(25+d25ターン)", "berserk (25+d25 turns)") },
-    { "PROT_EVIL", RandomArtActType::PROT_EVIL, 30, 5000, { 100, 0 }, _("対邪悪結界(期間 3*レベル+d25)", "protect evil (dur level*3 + d25)") },
-    { "RESIST_ALL", RandomArtActType::RESIST_ALL, 30, 5000, { 111, 0 }, _("全耐性(期間 20+d20)", "resist elements (dur 20+d20)") },
-    { "SPEED", RandomArtActType::SPEED, 40, 15000, { 250, 0 }, _("加速(期間 20+d20)", "speed (dur 20+d20)") },
-    { "MID_SPEED", RandomArtActType::MID_SPEED, 40, 20000, { 250, 0 }, _("加速(期間 50+d50)", "speed (dur 50+d50)") },
-    { "XTRA_SPEED", RandomArtActType::XTRA_SPEED, 40, 25000, { 200, 200 }, _("加速(期間 75+d75)", "speed (dur 75+d75)") },
-    { "WRAITH", RandomArtActType::WRAITH, 90, 25000, { 1000, 0 }, _("幽体化(期間 (レベル/2)+d(レベル/2))", "wraith form (dur level/2 + d(level/2))") },
-    { "INVULN", RandomArtActType::INVULN, 90, 25000, { 1000, 0 }, _("無敵化(期間 8+d8)", "invulnerability (dur 8+d8)") },
-    { "HERO", RandomArtActType::HERO, 10, 500, { 30, 30 }, _("士気高揚", "heroism") },
-    { "HERO_SPEED", RandomArtActType::HERO_SPEED, 30, 20000, { 100, 200 }, _("士気高揚, スピード(期間 50+d50ターン)", "hero and +10 to speed (dur 50+d50)") },
-    { "ACID_BALL_AND_RESISTANCE", RandomArtActType::ACID_BALL_AND_RESISTANCE, 20, 2000, { 40, 40 }, _("酸の球と酸への耐性", "acid ball and resist") },
-    { "FIRE_BALL_AND_RESISTANCE", RandomArtActType::FIRE_BALL_AND_RESISTANCE, 20, 2000, { 40, 40 }, _("火炎の球と火炎への耐性", "fire ball and resist") },
-    { "COLD_BALL_AND_RESISTANCE", RandomArtActType::COLD_BALL_AND_RESISTANCE, 20, 2000, { 40, 40 }, _("冷気の球と冷気への耐性", "cold ball and resist") },
-    { "ELEC_BALL_AND_RESISTANCE", RandomArtActType::ELEC_BALL_AND_RESISTANCE, 20, 2000, { 40, 40 }, _("電撃の球と電撃への耐性", "elec ball and resist") },
-    { "POIS_BALL_AND_RESISTANCE", RandomArtActType::POIS_BALL_AND_RESISTANCE, 20, 2000, { 40, 40 }, _("毒の球と毒への耐性", "pois ball and resist") },
-    { "RESIST_ACID", RandomArtActType::RESIST_ACID, 20, 2000, { 40, 40 }, _("酸への耐性(期間 20+d20)", "resist acid (dur 20+d20)") },
-    { "RESIST_FIRE", RandomArtActType::RESIST_FIRE, 20, 2000, { 40, 40 }, _("火炎への耐性(期間 20+d20)", "resist fire (dur 20+d20)") },
-    { "RESIST_COLD", RandomArtActType::RESIST_COLD, 20, 2000, { 40, 40 }, _("冷気への耐性(期間 20+d20)", "resist cold (dur 20+d20)") },
-    { "RESIST_ELEC", RandomArtActType::RESIST_ELEC, 20, 2000, { 40, 40 }, _("電撃への耐性(期間 20+d20)", "resist elec (dur 20+d20)") },
-    { "RESIST_POIS", RandomArtActType::RESIST_POIS, 20, 2000, { 40, 40 }, _("毒への耐性(期間 20+d20)", "resist poison (dur 20+d20)") },
-    { "LIGHT", RandomArtActType::LIGHT, 10, 150, { 10, 10 }, _("イルミネーション", "light area (dam 2d15)") },
+    { "SUMMON_OCTOPUS", RandomArtActType::SUMMON_OCTOPUS, 50, 15000, 300, 0, _("蛸の大群召喚", "summon octopus") },
+    { "CHOIR_SINGS", RandomArtActType::CHOIR_SINGS, 60, 20000, 300, 0, _("回復(777)、癒し、士気高揚", "heal 777 hit points, curing and HEROism") },
+    { "CURE_LW", RandomArtActType::CURE_LW, 10, 500, 10, 0, _("恐怖除去/体力回復(30)", "remove fear and heal 30 hp") },
+    { "CURE_MW", RandomArtActType::CURE_MW, 20, 750, 3, 3, _("傷回復(4d8)", "heal 4d8 and wounds") },
+    { "CURE_POISON", RandomArtActType::CURE_POISON, 10, 1000, 5, 0, _("恐怖除去/毒消し", "remove fear and cure poison") },
+    { "REST_LIFE", RandomArtActType::REST_EXP, 40, 7500, 450, 0, _("経験値復活", "restore experience") },
+    { "REST_ALL", RandomArtActType::REST_ALL, 30, 15000, 750, 0, _("全ステータスと経験値復活", "restore stats and experience") },
+    { "CURE_700", RandomArtActType::CURE_700, 40, 10000, 250, 0, _("体力回復(700)", "heal 700 hit points") },
+    { "CURE_1000", RandomArtActType::CURE_1000, 50, 15000, 888, 0, _("体力回復(1000)", "heal 1000 hit points") },
+    { "CURING", RandomArtActType::CURING, 30, 5000, 100, 0, _("癒し", "curing") },
+    { "CURE_MANA_FULL", RandomArtActType::CURE_MANA_FULL, 60, 20000, 777, 0, _("魔力復活", "restore mana") },
+    { "ESP", RandomArtActType::ESP, 30, 1500, 100, 0, _("テレパシー(期間 25+d30)", "telepathy (dur 25+d30)") },
+    { "BERSERK", RandomArtActType::BERSERK, 10, 800, 75, 0, _("狂戦士化(25+d25ターン)", "berserk (25+d25 turns)") },
+    { "PROT_EVIL", RandomArtActType::PROT_EVIL, 30, 5000, 100, 0, _("対邪悪結界(期間 3*レベル+d25)", "protect evil (dur level*3 + d25)") },
+    { "RESIST_ALL", RandomArtActType::RESIST_ALL, 30, 5000, 111, 0, _("全耐性(期間 20+d20)", "resist elements (dur 20+d20)") },
+    { "SPEED", RandomArtActType::SPEED, 40, 15000, 250, 0, _("加速(期間 20+d20)", "speed (dur 20+d20)") },
+    { "MID_SPEED", RandomArtActType::MID_SPEED, 40, 20000, 250, 0, _("加速(期間 50+d50)", "speed (dur 50+d50)") },
+    { "XTRA_SPEED", RandomArtActType::XTRA_SPEED, 40, 25000, 200, 200, _("加速(期間 75+d75)", "speed (dur 75+d75)") },
+    { "WRAITH", RandomArtActType::WRAITH, 90, 25000, 1000, 0, _("幽体化(期間 (レベル/2)+d(レベル/2))", "wraith form (dur level/2 + d(level/2))") },
+    { "INVULN", RandomArtActType::INVULN, 90, 25000, 1000, 0, _("無敵化(期間 8+d8)", "invulnerability (dur 8+d8)") },
+    { "HERO", RandomArtActType::HERO, 10, 500, 30, 30, _("士気高揚", "heroism") },
+    { "HERO_SPEED", RandomArtActType::HERO_SPEED, 30, 20000, 100, 200, _("士気高揚, スピード(期間 50+d50ターン)", "hero and +10 to speed (dur 50+d50)") },
+    { "ACID_BALL_AND_RESISTANCE", RandomArtActType::ACID_BALL_AND_RESISTANCE, 20, 2000, 40, 40, _("酸の球と酸への耐性", "acid ball and resist") },
+    { "FIRE_BALL_AND_RESISTANCE", RandomArtActType::FIRE_BALL_AND_RESISTANCE, 20, 2000, 40, 40, _("火炎の球と火炎への耐性", "fire ball and resist") },
+    { "COLD_BALL_AND_RESISTANCE", RandomArtActType::COLD_BALL_AND_RESISTANCE, 20, 2000, 40, 40, _("冷気の球と冷気への耐性", "cold ball and resist") },
+    { "ELEC_BALL_AND_RESISTANCE", RandomArtActType::ELEC_BALL_AND_RESISTANCE, 20, 2000, 40, 40, _("電撃の球と電撃への耐性", "elec ball and resist") },
+    { "POIS_BALL_AND_RESISTANCE", RandomArtActType::POIS_BALL_AND_RESISTANCE, 20, 2000, 40, 40, _("毒の球と毒への耐性", "pois ball and resist") },
+    { "RESIST_ACID", RandomArtActType::RESIST_ACID, 20, 2000, 40, 40, _("酸への耐性(期間 20+d20)", "resist acid (dur 20+d20)") },
+    { "RESIST_FIRE", RandomArtActType::RESIST_FIRE, 20, 2000, 40, 40, _("火炎への耐性(期間 20+d20)", "resist fire (dur 20+d20)") },
+    { "RESIST_COLD", RandomArtActType::RESIST_COLD, 20, 2000, 40, 40, _("冷気への耐性(期間 20+d20)", "resist cold (dur 20+d20)") },
+    { "RESIST_ELEC", RandomArtActType::RESIST_ELEC, 20, 2000, 40, 40, _("電撃への耐性(期間 20+d20)", "resist elec (dur 20+d20)") },
+    { "RESIST_POIS", RandomArtActType::RESIST_POIS, 20, 2000, 40, 40, _("毒への耐性(期間 20+d20)", "resist poison (dur 20+d20)") },
+    { "LIGHT", RandomArtActType::LIGHT, 10, 150, 10, 10, _("イルミネーション", "light area (dam 2d15)") },
 
-    { "MAP_LIGHT", RandomArtActType::MAP_LIGHT, 30, 500, { 50, 50 }, _("魔法の地図と光", "light (dam 2d15) & map area") },
-    { "DETECT_ALL", RandomArtActType::DETECT_ALL, 30, 1000, { 55, 55 }, _("全感知", "detection") },
-    { "DETECT_XTRA", RandomArtActType::DETECT_XTRA, 50, 12500, { 100, 0 }, _("全感知、探索、*鑑定*", "detection, probing and identify true") },
-    { "ID_FULL", RandomArtActType::ID_FULL, 50, 10000, { 75, 0 }, _("*鑑定*", "identify true") },
-    { "ID_PLAIN", RandomArtActType::ID_PLAIN, 20, 1250, { 10, 0 }, _("鑑定", "identify spell") },
-    { "RUNE_EXPLO", RandomArtActType::RUNE_EXPLO, 40, 4000, { 200, 0 }, _("爆発のルーン", "explosive rune") },
-    { "RUNE_PROT", RandomArtActType::RUNE_PROT, 60, 10000, { 400, 0 }, _("守りのルーン", "rune of protection") },
-    { "SATIATE", RandomArtActType::SATIATE, 10, 2000, { 200, 0 }, _("空腹充足", "satisfy hunger") },
-    { "DEST_DOOR", RandomArtActType::DEST_DOOR, 10, 100, { 10, 0 }, _("ドア破壊", "destroy doors") },
-    { "STONE_MUD", RandomArtActType::STONE_MUD, 20, 1000, { 3, 0 }, _("岩石溶解", "stone to mud") },
-    { "RECHARGE", RandomArtActType::RECHARGE, 30, 1000, { 70, 0 }, _("魔力充填", "recharging") },
-    { "ALCHEMY", RandomArtActType::ALCHEMY, 50, 10000, { 500, 0 }, _("錬金術", "alchemy") },
-    { "DIM_DOOR", RandomArtActType::DIM_DOOR, 50, 10000, { 100, 0 }, _("次元の扉", "dimension door") },
-    { "TELEPORT", RandomArtActType::TELEPORT, 10, 2000, { 25, 0 }, _("テレポート", "teleport") },
-    { "RECALL", RandomArtActType::RECALL, 30, 7500, { 200, 0 }, _("帰還の詔", "word of recall") },
-    { "JUDGE", RandomArtActType::JUDGE, 90, 50000, { 20, 20 }, _("体力と引き替えに千里眼と帰還", "clairvoyance and recall, draining you") },
-    { "TELEKINESIS", RandomArtActType::TELEKINESIS, 20, 5500, { 25, 25 }, _("物体を引き寄せる(重量25kgまで)", "a telekinesis (50 lb)") },
-    { "DETECT_UNIQUE", RandomArtActType::DETECT_UNIQUE, 40, 10000, { 200, 0 }, _("この階にいるユニークモンスターを表示", "list of the uniques on the level") },
-    { "ESCAPE", RandomArtActType::ESCAPE, 10, 3000, { 35, 0 }, _("逃走", "a getaway") },
-    { "DISP_CURSE_XTRA", RandomArtActType::DISP_CURSE_XTRA, 40, 30000, { 0, 0 }, _("*解呪*と調査", "dispel curse and probing") },
-    { "BRAND_FIRE_BOLTS", RandomArtActType::BRAND_FIRE_BOLTS, 40, 20000, { 999, 0 }, _("刃先のファイア・ボルト", "fire branding of bolts") },
-    { "RECHARGE_XTRA", RandomArtActType::RECHARGE_XTRA, 70, 30000, { 200, 0 }, _("魔力充填", "recharge item") },
-    { "LORE", RandomArtActType::LORE, 10, 30000, { 0, 0 }, _("危険を伴う鑑定", "perilous identify") },
-    { "SHIKOFUMI", RandomArtActType::SHIKOFUMI, 10, 10000, { 100, 100 }, _("四股踏み", "shiko") },
-    { "PHASE_DOOR", RandomArtActType::PHASE_DOOR, 10, 1500, { 10, 0 }, _("ショート・テレポート", "blink") },
-    { "DETECT_ALL_MONS", RandomArtActType::DETECT_ALL_MONS, 30, 3000, { 150, 0 }, _("全モンスター感知", "detect all monsters") },
-    { "ULTIMATE_RESIST", RandomArtActType::ULTIMATE_RESIST, 90, 20000, { 777, 0 }, _("士気高揚、祝福、究極の耐性", "hero, bless, and ultimate resistance") },
-    { "CAST_OFF", RandomArtActType::CAST_OFF, 30, 15000, { 100, 0 }, _("脱衣と小宇宙燃焼", "cast it off and cosmic heroism") },
-    { "FISHING", RandomArtActType::FISHING, 0, 100, { 0, 0 }, _("釣りをする", "fishing") },
-    { "INROU", RandomArtActType::INROU, 40, 15000, { 150, 150 }, _("例のアレ", "reveal your identity") },
-    { "MURAMASA", RandomArtActType::MURAMASA, 0, 0, { -1, 0 }, _("腕力の上昇", "increase STR") },
-    { "BLOODY_MOON", RandomArtActType::BLOODY_MOON, 0, 0, { 3333, 0 }, _("属性変更", "change zokusei") },
+    { "MAP_LIGHT", RandomArtActType::MAP_LIGHT, 30, 500, 50, 50, _("魔法の地図と光", "light (dam 2d15) & map area") },
+    { "DETECT_ALL", RandomArtActType::DETECT_ALL, 30, 1000, 55, 55, _("全感知", "detection") },
+    { "DETECT_XTRA", RandomArtActType::DETECT_XTRA, 50, 12500, 100, 0, _("全感知、探索、*鑑定*", "detection, probing and identify true") },
+    { "ID_FULL", RandomArtActType::ID_FULL, 50, 10000, 75, 0, _("*鑑定*", "identify true") },
+    { "ID_PLAIN", RandomArtActType::ID_PLAIN, 20, 1250, 10, 0, _("鑑定", "identify spell") },
+    { "RUNE_EXPLO", RandomArtActType::RUNE_EXPLO, 40, 4000, 200, 0, _("爆発のルーン", "explosive rune") },
+    { "RUNE_PROT", RandomArtActType::RUNE_PROT, 60, 10000, 400, 0, _("守りのルーン", "rune of protection") },
+    { "SATIATE", RandomArtActType::SATIATE, 10, 2000, 200, 0, _("空腹充足", "satisfy hunger") },
+    { "DEST_DOOR", RandomArtActType::DEST_DOOR, 10, 100, 10, 0, _("ドア破壊", "destroy doors") },
+    { "STONE_MUD", RandomArtActType::STONE_MUD, 20, 1000, 3, 0, _("岩石溶解", "stone to mud") },
+    { "RECHARGE", RandomArtActType::RECHARGE, 30, 1000, 70, 0, _("魔力充填", "recharging") },
+    { "ALCHEMY", RandomArtActType::ALCHEMY, 50, 10000, 500, 0, _("錬金術", "alchemy") },
+    { "DIM_DOOR", RandomArtActType::DIM_DOOR, 50, 10000, 100, 0, _("次元の扉", "dimension door") },
+    { "TELEPORT", RandomArtActType::TELEPORT, 10, 2000, 25, 0, _("テレポート", "teleport") },
+    { "RECALL", RandomArtActType::RECALL, 30, 7500, 200, 0, _("帰還の詔", "word of recall") },
+    { "JUDGE", RandomArtActType::JUDGE, 90, 50000, 20, 20, _("体力と引き替えに千里眼と帰還", "clairvoyance and recall, draining you") },
+    { "TELEKINESIS", RandomArtActType::TELEKINESIS, 20, 5500, 25, 25, _("物体を引き寄せる(重量25kgまで)", "a telekinesis (50 lb)") },
+    { "DETECT_UNIQUE", RandomArtActType::DETECT_UNIQUE, 40, 10000, 200, 0, _("この階にいるユニークモンスターを表示", "list of the uniques on the level") },
+    { "ESCAPE", RandomArtActType::ESCAPE, 10, 3000, 35, 0, _("逃走", "a getaway") },
+    { "DISP_CURSE_XTRA", RandomArtActType::DISP_CURSE_XTRA, 40, 30000, 0, 0, _("*解呪*と調査", "dispel curse and probing") },
+    { "BRAND_FIRE_BOLTS", RandomArtActType::BRAND_FIRE_BOLTS, 40, 20000, 999, 0, _("刃先のファイア・ボルト", "fire branding of bolts") },
+    { "RECHARGE_XTRA", RandomArtActType::RECHARGE_XTRA, 70, 30000, 200, 0, _("魔力充填", "recharge item") },
+    { "LORE", RandomArtActType::LORE, 10, 30000, 0, 0, _("危険を伴う鑑定", "perilous identify") },
+    { "SHIKOFUMI", RandomArtActType::SHIKOFUMI, 10, 10000, 100, 100, _("四股踏み", "shiko") },
+    { "PHASE_DOOR", RandomArtActType::PHASE_DOOR, 10, 1500, 10, 0, _("ショート・テレポート", "blink") },
+    { "DETECT_ALL_MONS", RandomArtActType::DETECT_ALL_MONS, 30, 3000, 150, 0, _("全モンスター感知", "detect all monsters") },
+    { "ULTIMATE_RESIST", RandomArtActType::ULTIMATE_RESIST, 90, 20000, 777, 0, _("士気高揚、祝福、究極の耐性", "hero, bless, and ultimate resistance") },
+    { "CAST_OFF", RandomArtActType::CAST_OFF, 30, 15000, 100, 0, _("脱衣と小宇宙燃焼", "cast it off and cosmic heroism") },
+    { "FISHING", RandomArtActType::FISHING, 0, 100, 0, 0, _("釣りをする", "fishing") },
+    { "INROU", RandomArtActType::INROU, 40, 15000, 150, 150, _("例のアレ", "reveal your identity") },
+    { "MURAMASA", RandomArtActType::MURAMASA, 0, 0, std::nullopt, 0, _("腕力の上昇", "increase STR") },
+    { "BLOODY_MOON", RandomArtActType::BLOODY_MOON, 0, 0, 3333, 0, _("属性変更", "change zokusei") },
 
-    { "CRIMSON", RandomArtActType::CRIMSON, 0, 50000, { 15, 0 }, _("ファイア!", "fire!") },
-    { "STRAIN_HASTE", RandomArtActType::STRAIN_HASTE, 10, 1000, { 120, 100 }, _("体力と引き換えに加速", "haste with strain") },
-    { "GRAND_CROSS", RandomArtActType::GRAND_CROSS, 30, 15000, { 250, 200 }, _("グランド・クロス", "grand cross") },
-    { "TELEPORT_LEVEL", RandomArtActType::TELEPORT_LEVEL, 10, 1500, { 100, 200 }, _("テレポート・レベル", "teleport level") },
-    { "ARTS_FALLING_STAR", RandomArtActType::FALLING_STAR, 20, 5500, { 30, 50 }, _("魔剣・流れ星", "blade arts 'falling star'") },
-    { "ANIM_DEAD", RandomArtActType::ANIM_DEAD, 30, 2000, { 10, 10 }, _("死者復活", "animate dead") },
-    { "TREE_CREATION", RandomArtActType::TREE_CREATION, 50, 25000, { 1000, 0 }, _("森林生成", "tree creation") },
-    { "ELBERETH", RandomArtActType::ELBERETH, 10, 30000, { 75, 0 }, _("エルベレスの結界", "Rune of Elbereth") },
-    { "DETECT_TREASURE", RandomArtActType::DETECT_TREASURE, 10, 3000, { 35, 0 }, _("財宝感知", "detect treasure") },
-    { "HERO_BLESS", RandomArtActType::HERO_BLESS, 10, 500, { 30, 30 }, _("士気高揚、祝福", "hero, bless") },
-    { "CREATE_AMMO", RandomArtActType::CREATE_AMMO, 10, 30000, { 200, 0 }, _("弾/矢の製造", "Create Ammo") },
-    { "DISPEL_MAGIC", RandomArtActType::DISPEL_MAGIC, 10, 10000, { 50, 50 }, _("魔力消去", "Dispel Magic") },
-    { nullptr, RandomArtActType::NONE, 0, 0, { 0, 0 }, "" },
+    { "CRIMSON", RandomArtActType::CRIMSON, 0, 50000, 15, 0, _("ファイア!", "fire!") },
+    { "STRAIN_HASTE", RandomArtActType::STRAIN_HASTE, 10, 1000, 120, 100, _("体力と引き換えに加速", "haste with strain") },
+    { "GRAND_CROSS", RandomArtActType::GRAND_CROSS, 30, 15000, 250, 200, _("グランド・クロス", "grand cross") },
+    { "TELEPORT_LEVEL", RandomArtActType::TELEPORT_LEVEL, 10, 1500, 100, 200, _("テレポート・レベル", "teleport level") },
+    { "ARTS_FALLING_STAR", RandomArtActType::FALLING_STAR, 20, 5500, 30, 50, _("魔剣・流れ星", "blade arts 'falling star'") },
+    { "ANIM_DEAD", RandomArtActType::ANIM_DEAD, 30, 2000, 10, 10, _("死者復活", "animate dead") },
+    { "TREE_CREATION", RandomArtActType::TREE_CREATION, 50, 25000, 1000, 0, _("森林生成", "tree creation") },
+    { "ELBERETH", RandomArtActType::ELBERETH, 10, 30000, 75, 0, _("エルベレスの結界", "Rune of Elbereth") },
+    { "DETECT_TREASURE", RandomArtActType::DETECT_TREASURE, 10, 3000, 35, 0, _("財宝感知", "detect treasure") },
+    { "HERO_BLESS", RandomArtActType::HERO_BLESS, 10, 500, 30, 30, _("士気高揚、祝福", "hero, bless") },
+    { "CREATE_AMMO", RandomArtActType::CREATE_AMMO, 10, 30000, 200, 0, _("弾/矢の製造", "Create Ammo") },
+    { "DISPEL_MAGIC", RandomArtActType::DISPEL_MAGIC, 10, 10000, 50, 50, _("魔力消去", "Dispel Magic") },
 };
+
+std::optional<std::string> ActivationType::build_timeout_description() const
+{
+    if ((this->constant == 0) && (this->dice == 0)) {
+        return _("いつでも", "every turn");
+    }
+
+    if (!this->constant) {
+        return std::nullopt;
+    }
+
+    std::stringstream ss;
+    ss << _("", "every ");
+    if (this->constant > 0) {
+        ss << *this->constant;
+        if (this->dice > 0) {
+            ss << '+';
+        }
+    }
+
+    if (this->dice > 0) {
+        ss << 'd' << this->dice;
+    }
+
+    ss << _(" ターン毎", " turns");
+    return ss.str();
+}
index 992d87e..dd5fc59 100644 (file)
@@ -1,19 +1,21 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <optional>
+#include <string>
 #include <vector>
 
 enum class RandomArtActType : short;
-struct activation_type {
-    concptr flag;
+class ActivationType {
+public:
+    std::string flag;
     RandomArtActType index;
-    byte level;
-    int32_t value;
-    struct {
-        int constant;
-        DICE_NUMBER dice;
-    } timeout;
-    concptr desc;
+    int level;
+    int value;
+    std::optional<int> constant; // 発動間隔の最低ターン数
+    int dice; // 発動間隔の追加ターン数
+    std::string desc;
+
+    std::optional<std::string> build_timeout_description() const;
 };
 
-extern const std::vector<activation_type> activation_info;
+extern const std::vector<ActivationType> activation_info;
index 6ebb89c..9b4f809 100644 (file)
@@ -1,11 +1,15 @@
-#include "object-enchant/dragon-breaths-table.h"
+#include "object-enchant/dragon-breaths-table.h"
 #include "effect/attribute-types.h"
+#include "locale/language-switcher.h"
+#include "object-enchant/tr-types.h"
+#include <sstream>
 
 /*!
  * @brief 装備耐性に準じたブレス効果の選択テーブル /
  * Define flags, effect type, name for dragon breath activation
  */
-const dragonbreath_type dragonbreath_info[] = {
+namespace {
+const std::vector<DragonBreathType> dragon_breaths_info = {
     { TR_RES_ACID, AttributeType::ACID, _("酸", "acid") },
     { TR_RES_ELEC, AttributeType::ELEC, _("電撃", "lightning") },
     { TR_RES_FIRE, AttributeType::FIRE, _("火炎", "fire") },
@@ -20,5 +24,39 @@ const dragonbreath_type dragonbreath_info[] = {
     { TR_RES_NETHER, AttributeType::NETHER, _("地獄", "nether") },
     { TR_RES_CHAOS, AttributeType::CHAOS, _("カオス", "chaos") },
     { TR_RES_DISEN, AttributeType::DISENCHANT, _("劣化", "disenchantment") },
-    { TR_STR, AttributeType::NONE, nullptr }
 };
+}
+
+std::vector<std::pair<AttributeType, std::string>> DragonBreaths::get_breaths(const TrFlags &flags)
+{
+    std::vector<std::pair<AttributeType, std::string>> breaths;
+    for (const auto &dragon_breath : dragon_breaths_info) {
+        if (flags.has(dragon_breath.flag)) {
+            breaths.push_back({ dragon_breath.type, dragon_breath.name });
+        }
+    }
+
+    return breaths;
+}
+
+std::string DragonBreaths::build_description(const TrFlags &flags)
+{
+    std::stringstream ss;
+    ss << _("", "breathe ");
+    auto has_multi_breaths = false;
+    for (const auto &dragon_breath : dragon_breaths_info) {
+        if (flags.has_not(dragon_breath.flag)) {
+            continue;
+        }
+
+        if (has_multi_breaths) {
+            ss << _("、", ", ");
+        }
+
+        ss << dragon_breath.name;
+        has_multi_breaths = true;
+    }
+
+    ss << _("のブレス(250)", " (250)");
+    return ss.str();
+}
index a4e2346..5b07bdb 100644 (file)
@@ -1,13 +1,21 @@
-#pragma once
+#pragma once
 
-#include "effect/attribute-types.h"
-#include "object-enchant/tr-types.h"
-#include "system/angband.h"
+#include "object-enchant/tr-flags.h"
+#include <string>
+#include <utility>
+#include <vector>
 
-struct dragonbreath_type {
+enum tr_type : int;
+enum class AttributeType;
+class DragonBreathType {
+public:
     tr_type flag;
     AttributeType type;
-    concptr name;
+    std::string name;
 };
 
-extern const dragonbreath_type dragonbreath_info[];
+class DragonBreaths {
+public:
+    static std::vector<std::pair<AttributeType, std::string>> get_breaths(const TrFlags &flags);
+    static std::string build_description(const TrFlags &flags);
+};
index d3a3416..a745b10 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * @file enchanter-base.h
index 062d1b7..57bb440 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief アイテムの強化/弱化処理クラスを選択するファクトリクラス
  * @date 2022/03/22
  * @author Hourier
index ab031f1..5c0b681 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <memory>
 
index 0d03b77..bbd160f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Bit flags for apply_magic()
@@ -12,3 +12,15 @@ enum item_am_type : uint32_t {
     AM_CURSED = 0x00000010, /*!< Generate cursed/worthless items */
     AM_FORBID_CHEST = 0x00000020, /*!< 箱からさらに箱が出現することを抑止する */
 };
+
+// @todo v3.0 正式リリース以降、上記enum をこちらに差し替える.
+enum class ItemMagicAppliance {
+    CURSED,
+    NO_FIXED_ART,
+    GOOD,
+    GREAT,
+    EGO,
+    SPECIAL,
+    FORBID_CHEST,
+    MAX,
+};
index 1e1685e..163a72b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * アイテムの簡易鑑定定義 / Game generated inscription indices. These are stored in the object,
index 57dfe2c..7215492 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ベースアイテムを強化する処理
  * @date 2022/03/22
  * @author Hourier
@@ -74,13 +74,15 @@ void ItemMagicApplier::execute()
 std::tuple<int, int> ItemMagicApplier::calculate_chances()
 {
     auto chance_good = this->lev + 10;
-    if (chance_good > dungeons_info[this->player_ptr->dungeon_idx].obj_good) {
-        chance_good = dungeons_info[this->player_ptr->dungeon_idx].obj_good;
+    const auto &floor = *this->player_ptr->current_floor_ptr;
+    const auto &dungeon = floor.get_dungeon_definition();
+    if (chance_good > dungeon.obj_good) {
+        chance_good = dungeon.obj_good;
     }
 
     auto chance_great = chance_good * 2 / 3;
-    if ((this->player_ptr->ppersonality != PERSONALITY_MUNCHKIN) && (chance_great > dungeons_info[this->player_ptr->dungeon_idx].obj_great)) {
-        chance_great = dungeons_info[this->player_ptr->dungeon_idx].obj_great;
+    if ((this->player_ptr->ppersonality != PERSONALITY_MUNCHKIN) && (chance_great > dungeon.obj_great)) {
+        chance_great = dungeon.obj_great;
     }
 
     if (has_good_luck(this->player_ptr)) {
index d721f4b..9ad5a4d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <tuple>
index d0cf647..0d20a2f 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-enchant/object-boost.h"
+#include "object-enchant/object-boost.h"
 #include "artifact/random-art-effects.h"
 #include "object-enchant/tr-types.h"
 #include "player-ability/player-ability-types.h"
@@ -104,26 +104,16 @@ int m_bonus(int max, DEPTH level)
  */
 void one_sustain(ItemEntity *o_ptr)
 {
-    switch (randint0(A_MAX)) {
-    case 0:
-        o_ptr->art_flags.set(TR_SUST_STR);
-        break;
-    case 1:
-        o_ptr->art_flags.set(TR_SUST_INT);
-        break;
-    case 2:
-        o_ptr->art_flags.set(TR_SUST_WIS);
-        break;
-    case 3:
-        o_ptr->art_flags.set(TR_SUST_DEX);
-        break;
-    case 4:
-        o_ptr->art_flags.set(TR_SUST_CON);
-        break;
-    case 5:
-        o_ptr->art_flags.set(TR_SUST_CHR);
-        break;
-    }
+    constexpr static auto sustains = {
+        TR_SUST_STR,
+        TR_SUST_INT,
+        TR_SUST_WIS,
+        TR_SUST_DEX,
+        TR_SUST_CON,
+        TR_SUST_CHR,
+    };
+
+    o_ptr->art_flags.set(rand_choice(sustains));
 }
 
 /*!
@@ -133,22 +123,16 @@ void one_sustain(ItemEntity *o_ptr)
  */
 bool add_esp_strong(ItemEntity *o_ptr)
 {
-    bool nonliv = false;
-
-    switch (randint1(3)) {
-    case 1:
-        o_ptr->art_flags.set(TR_ESP_EVIL);
-        break;
-    case 2:
-        o_ptr->art_flags.set(TR_TELEPATHY);
-        break;
-    case 3:
-        o_ptr->art_flags.set(TR_ESP_NONLIVING);
-        nonliv = true;
-        break;
-    }
+    constexpr static auto candidates = {
+        TR_ESP_EVIL,
+        TR_TELEPATHY,
+        TR_ESP_NONLIVING,
+    };
+
+    const auto flag = rand_choice(candidates);
+    o_ptr->art_flags.set(flag);
 
-    return nonliv;
+    return flag == TR_ESP_NONLIVING;
 }
 
 /*!
@@ -223,20 +207,14 @@ void add_low_telepathy(ItemEntity *o_ptr)
  */
 void one_ele_resistance(ItemEntity *o_ptr)
 {
-    switch (randint0(4)) {
-    case 0:
-        o_ptr->art_flags.set(TR_RES_ACID);
-        break;
-    case 1:
-        o_ptr->art_flags.set(TR_RES_ELEC);
-        break;
-    case 2:
-        o_ptr->art_flags.set(TR_RES_COLD);
-        break;
-    case 3:
-        o_ptr->art_flags.set(TR_RES_FIRE);
-        break;
-    }
+    constexpr static auto resistances = {
+        TR_RES_ACID,
+        TR_RES_ELEC,
+        TR_RES_COLD,
+        TR_RES_FIRE,
+    };
+
+    o_ptr->art_flags.set(rand_choice(resistances));
 }
 
 /*!
@@ -260,53 +238,25 @@ void one_dragon_ele_resistance(ItemEntity *o_ptr)
  */
 void one_high_resistance(ItemEntity *o_ptr)
 {
-    switch (randint0(15)) {
-    case 0:
-        o_ptr->art_flags.set(TR_RES_POIS);
-        break;
-    case 1:
-        o_ptr->art_flags.set(TR_RES_LITE);
-        break;
-    case 2:
-        o_ptr->art_flags.set(TR_RES_DARK);
-        break;
-    case 3:
-        o_ptr->art_flags.set(TR_RES_SHARDS);
-        break;
-    case 4:
-        o_ptr->art_flags.set(TR_RES_BLIND);
-        break;
-    case 5:
-        o_ptr->art_flags.set(TR_RES_CONF);
-        break;
-    case 6:
-        o_ptr->art_flags.set(TR_RES_SOUND);
-        break;
-    case 7:
-        o_ptr->art_flags.set(TR_RES_NETHER);
-        break;
-    case 8:
-        o_ptr->art_flags.set(TR_RES_NEXUS);
-        break;
-    case 9:
-        o_ptr->art_flags.set(TR_RES_CHAOS);
-        break;
-    case 10:
-        o_ptr->art_flags.set(TR_RES_DISEN);
-        break;
-    case 11:
-        o_ptr->art_flags.set(TR_RES_FEAR);
-        break;
-    case 12:
-        o_ptr->art_flags.set(TR_RES_TIME);
-        break;
-    case 13:
-        o_ptr->art_flags.set(TR_RES_WATER);
-        break;
-    case 14:
-        o_ptr->art_flags.set(TR_RES_CURSE);
-        break;
-    }
+    constexpr static auto high_resistances = {
+        TR_RES_POIS,
+        TR_RES_LITE,
+        TR_RES_DARK,
+        TR_RES_SHARDS,
+        TR_RES_BLIND,
+        TR_RES_CONF,
+        TR_RES_SOUND,
+        TR_RES_NETHER,
+        TR_RES_NEXUS,
+        TR_RES_CHAOS,
+        TR_RES_DISEN,
+        TR_RES_FEAR,
+        TR_RES_TIME,
+        TR_RES_WATER,
+        TR_RES_CURSE,
+    };
+
+    o_ptr->art_flags.set(rand_choice(high_resistances));
 }
 
 /*!
@@ -347,36 +297,23 @@ void one_resistance(ItemEntity *o_ptr)
  */
 void one_ability(ItemEntity *o_ptr)
 {
-    switch (randint0(10)) {
-    case 0:
-        o_ptr->art_flags.set(TR_LEVITATION);
-        break;
-    case 1:
-        o_ptr->art_flags.set(TR_LITE_1);
-        break;
-    case 2:
-        o_ptr->art_flags.set(TR_SEE_INVIS);
-        break;
-    case 3:
-        o_ptr->art_flags.set(TR_WARNING);
-        break;
-    case 4:
-        o_ptr->art_flags.set(TR_SLOW_DIGEST);
-        break;
-    case 5:
-        o_ptr->art_flags.set(TR_REGEN);
-        break;
-    case 6:
-        o_ptr->art_flags.set(TR_FREE_ACT);
-        break;
-    case 7:
-        o_ptr->art_flags.set(TR_HOLD_EXP);
-        break;
-    case 8:
-    case 9:
+    if (one_in_(5)) {
         one_low_esp(o_ptr);
-        break;
+        return;
     }
+
+    constexpr static auto abilities = {
+        TR_LEVITATION,
+        TR_LITE_1,
+        TR_SEE_INVIS,
+        TR_WARNING,
+        TR_SLOW_DIGEST,
+        TR_REGEN,
+        TR_FREE_ACT,
+        TR_HOLD_EXP,
+    };
+
+    o_ptr->art_flags.set(rand_choice(abilities));
 }
 
 /*!
@@ -387,38 +324,20 @@ void one_ability(ItemEntity *o_ptr)
  */
 void one_low_esp(ItemEntity *o_ptr)
 {
-    switch (randint1(10)) {
-    case 1:
-        o_ptr->art_flags.set(TR_ESP_ANIMAL);
-        break;
-    case 2:
-        o_ptr->art_flags.set(TR_ESP_UNDEAD);
-        break;
-    case 3:
-        o_ptr->art_flags.set(TR_ESP_DEMON);
-        break;
-    case 4:
-        o_ptr->art_flags.set(TR_ESP_ORC);
-        break;
-    case 5:
-        o_ptr->art_flags.set(TR_ESP_TROLL);
-        break;
-    case 6:
-        o_ptr->art_flags.set(TR_ESP_GIANT);
-        break;
-    case 7:
-        o_ptr->art_flags.set(TR_ESP_DRAGON);
-        break;
-    case 8:
-        o_ptr->art_flags.set(TR_ESP_HUMAN);
-        break;
-    case 9:
-        o_ptr->art_flags.set(TR_ESP_GOOD);
-        break;
-    case 10:
-        o_ptr->art_flags.set(TR_ESP_UNIQUE);
-        break;
-    }
+    constexpr static auto low_esps = {
+        TR_ESP_ANIMAL,
+        TR_ESP_UNDEAD,
+        TR_ESP_DEMON,
+        TR_ESP_ORC,
+        TR_ESP_TROLL,
+        TR_ESP_GIANT,
+        TR_ESP_DRAGON,
+        TR_ESP_HUMAN,
+        TR_ESP_GOOD,
+        TR_ESP_UNIQUE,
+    };
+
+    o_ptr->art_flags.set(rand_choice(low_esps));
 }
 
 /*!
@@ -549,47 +468,23 @@ void one_activation(ItemEntity *o_ptr)
  */
 void one_lordly_high_resistance(ItemEntity *o_ptr)
 {
-    switch (randint0(13)) {
-    case 0:
-        o_ptr->art_flags.set(TR_RES_LITE);
-        break;
-    case 1:
-        o_ptr->art_flags.set(TR_RES_DARK);
-        break;
-    case 2:
-        o_ptr->art_flags.set(TR_RES_SHARDS);
-        break;
-    case 3:
-        o_ptr->art_flags.set(TR_RES_BLIND);
-        break;
-    case 4:
-        o_ptr->art_flags.set(TR_RES_CONF);
-        break;
-    case 5:
-        o_ptr->art_flags.set(TR_RES_SOUND);
-        break;
-    case 6:
-        o_ptr->art_flags.set(TR_RES_NETHER);
-        break;
-    case 7:
-        o_ptr->art_flags.set(TR_RES_NEXUS);
-        break;
-    case 8:
-        o_ptr->art_flags.set(TR_RES_CHAOS);
-        break;
-    case 9:
-        o_ptr->art_flags.set(TR_RES_FEAR);
-        break;
-    case 10:
-        o_ptr->art_flags.set(TR_RES_TIME);
-        break;
-    case 11:
-        o_ptr->art_flags.set(TR_RES_WATER);
-        break;
-    case 12:
-        o_ptr->art_flags.set(TR_RES_CURSE);
-        break;
-    }
+    constexpr static auto lordly_high_resistances = {
+        TR_RES_LITE,
+        TR_RES_DARK,
+        TR_RES_SHARDS,
+        TR_RES_BLIND,
+        TR_RES_CONF,
+        TR_RES_SOUND,
+        TR_RES_NETHER,
+        TR_RES_NEXUS,
+        TR_RES_CHAOS,
+        TR_RES_FEAR,
+        TR_RES_TIME,
+        TR_RES_WATER,
+        TR_RES_CURSE,
+    };
+
+    o_ptr->art_flags.set(rand_choice(lordly_high_resistances));
 }
 
 /*!
index 0de3219..b6d5fed 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 8c65991..8300e91 100644 (file)
@@ -1,5 +1,4 @@
-#include "object-enchant/object-curse.h"
-#include "core/player-update-types.h"
+#include "object-enchant/object-curse.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "inventory/inventory-slot-types.h"
@@ -8,9 +7,9 @@
 #include "object-enchant/trc-types.h"
 #include "object-hook/hook-armor.h"
 #include "object-hook/hook-weapon.h"
-#include "object/object-flags.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
 #include "view/display-messages.h"
@@ -75,7 +74,7 @@ void curse_equipment(PlayerType *player_ptr, PERCENTAGE chance, PERCENTAGE heavy
         return;
     }
 
-    auto oflags = object_flags(o_ptr);
+    const auto oflags = o_ptr->get_flags();
     const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
 
     /* Extra, biased saving throw for blessed items */
@@ -120,5 +119,5 @@ void curse_equipment(PlayerType *player_ptr, PERCENTAGE chance, PERCENTAGE heavy
         o_ptr->feeling = FEEL_NONE;
     }
 
-    player_ptr->update |= PU_BONUS;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
index 71813c8..aa4123e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f69fe72..a491482 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief エゴアイテムに関する処理
  * @date 2019/05/02
  * @author deskull
@@ -169,9 +169,8 @@ static void ego_interpret_extra_abilities(ItemEntity *o_ptr, const EgoItemDefini
             continue;
         }
 
-        auto n = xtra.tr_flags.size();
-        if (n > 0) {
-            const auto f = xtra.tr_flags[randint0(n)];
+        if (!xtra.tr_flags.empty()) {
+            const auto f = rand_choice(xtra.tr_flags);
             const auto except = (f == TR_VORPAL) && (o_ptr->bi_key.tval() != ItemKindType::SWORD);
             if (!except) {
                 o_ptr->art_flags.set(f);
index dcbe17b..5185ef1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <map>
 #include <string>
index 32c17f6..d17b606 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 変愚ver1.5.0以前に使われていたアイテムの追加特性フラグ / Hack -- special "xtra" object powers
  * @date 2020/05/28
  * @author Hourier
index 290c277..b349306 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief アミュレットを強化生成する処理
  * @date 2021/04/30
  * @author Hourier
@@ -69,11 +69,11 @@ void AmuletEnchanter::apply_magic()
 void AmuletEnchanter::sval_enchant()
 {
     const auto sval = this->o_ptr->bi_key.sval();
-    if (!sval.has_value()) {
+    if (!sval) {
         return;
     }
 
-    switch (sval.value()) {
+    switch (*sval) {
     case SV_AMULET_INTELLIGENCE:
     case SV_AMULET_WISDOM:
     case SV_AMULET_CHARISMA:
@@ -265,11 +265,11 @@ void AmuletEnchanter::give_ego_index()
 void AmuletEnchanter::give_high_ego_index()
 {
     const auto sval = this->o_ptr->bi_key.sval();
-    if (!sval.has_value()) {
+    if (!sval) {
         return;
     }
 
-    switch (sval.value()) {
+    switch (*sval) {
     case SV_AMULET_TELEPORT:
         if (m_bonus(10, this->level) > 9) {
             this->o_ptr->ego_idx = EgoType::AMU_D_DOOR;
index e908561..6116e30 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/enchanter-base.h"
 #include "system/angband.h"
index 1fcfb75..e4978c8 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-enchant/others/apply-magic-lite.h"
+#include "object-enchant/others/apply-magic-lite.h"
 #include "artifact/random-art-generator.h"
 #include "inventory/inventory-slot-types.h"
 #include "object-enchant/object-ego.h"
@@ -12,11 +12,11 @@ LiteEnchanter::LiteEnchanter(PlayerType *player_ptr, ItemEntity *o_ptr, int powe
     , power(power)
 {
     const auto sval = this->o_ptr->bi_key.sval();
-    if (!sval.has_value()) {
+    if (!sval) {
         return;
     }
 
-    switch (sval.value()) {
+    switch (*sval) {
     case SV_LITE_TORCH:
         o_ptr->fuel = randint1(FUEL_TORCH / 2);
         return;
@@ -86,11 +86,11 @@ void LiteEnchanter::give_cursed()
 void LiteEnchanter::add_dark_flag()
 {
     const auto sval = this->o_ptr->bi_key.sval();
-    if (!sval.has_value()) {
+    if (!sval) {
         return;
     }
 
-    switch (sval.value()) {
+    switch (*sval) {
     case SV_LITE_TORCH:
         this->o_ptr->art_flags.set(TR_LITE_M1);
         return;
index 1836f09..b916c1d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/enchanter-base.h"
 #include "system/angband.h"
index 004de6c..505b727 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 武器でも防具でもアクセサリでもない、その他のアイテム群を生成・強化する処理
  * @date 2022/02/23
  * @author Hourier
@@ -9,6 +9,7 @@
 #include "artifact/random-art-generator.h"
 #include "game-option/cheat-options.h"
 #include "inventory/inventory-slot-types.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-indice-types.h"
@@ -65,7 +66,7 @@ void OtherItemsEnchanter::apply_magic()
     case ItemKindType::CAPTURE:
         this->o_ptr->pval = 0;
         object_aware(this->player_ptr, this->o_ptr);
-        object_known(this->o_ptr);
+        this->o_ptr->mark_as_known();
         break;
     case ItemKindType::FIGURINE:
         this->generate_figurine();
@@ -138,7 +139,7 @@ void OtherItemsEnchanter::generate_figurine()
  */
 void OtherItemsEnchanter::generate_corpse()
 {
-    const std::unordered_map<OBJECT_SUBTYPE_VALUE, MonsterDropType> match = {
+    const std::unordered_map<int, MonsterDropType> match = {
         { SV_SKELETON, MonsterDropType::DROP_SKELETON },
         { SV_CORPSE, MonsterDropType::DROP_CORPSE },
     };
@@ -147,15 +148,15 @@ void OtherItemsEnchanter::generate_corpse()
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
     MonsterRaceId r_idx;
     while (true) {
-        r_idx = get_mon_num(this->player_ptr, 0, floor_ptr->dun_level, 0);
+        r_idx = get_mon_num(this->player_ptr, 0, floor_ptr->dun_level, PM_NONE);
         auto &r_ref = monraces_info[r_idx];
         auto check = (floor_ptr->dun_level < r_ref.level) ? (r_ref.level - floor_ptr->dun_level) : 0;
         const auto sval = this->o_ptr->bi_key.sval();
-        if (!sval.has_value()) {
+        if (!sval) {
             continue;
         }
 
-        if ((r_ref.rarity == 0) || (match.find(sval.value()) != match.end() && r_ref.drop_flags.has_not(match.at(sval.value()))) || (randint0(check) > 0)) {
+        if ((r_ref.rarity == 0) || (match.find(*sval) != match.end() && r_ref.drop_flags.has_not(match.at(*sval))) || (randint0(check) > 0)) {
             continue;
         }
 
@@ -164,7 +165,7 @@ void OtherItemsEnchanter::generate_corpse()
 
     this->o_ptr->pval = enum2i(r_idx);
     object_aware(this->player_ptr, this->o_ptr);
-    object_known(this->o_ptr);
+    this->o_ptr->mark_as_known();
 }
 
 /*
@@ -190,7 +191,7 @@ void OtherItemsEnchanter::generate_statue()
     }
 
     object_aware(this->player_ptr, this->o_ptr);
-    object_known(this->o_ptr);
+    this->o_ptr->mark_as_known();
 }
 
 /*
index 1826d9b..a1de44e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/enchanter-base.h"
 
index e42327a..114e922 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 指輪を強化生成する処理
  * @date 2021/04/30
  * @author Hourier
@@ -68,11 +68,11 @@ void RingEnchanter::apply_magic()
 void RingEnchanter::sval_enchant()
 {
     const auto sval = this->o_ptr->bi_key.sval();
-    if (!sval.has_value()) {
+    if (!sval) {
         return;
     }
 
-    switch (sval.value()) {
+    switch (*sval) {
     case SV_RING_ATTACKS:
         this->o_ptr->pval = (PARAMETER_VALUE)m_bonus(2, this->level);
         if (one_in_(15)) {
@@ -406,11 +406,11 @@ void RingEnchanter::give_ego_index()
 void RingEnchanter::give_high_ego_index()
 {
     const auto sval = this->o_ptr->bi_key.sval();
-    if (!sval.has_value()) {
+    if (!sval) {
         return;
     }
 
-    switch (sval.value()) {
+    switch (*sval) {
     case SV_RING_SPEED:
         if (!one_in_(3)) {
             break;
index 024087a..b5e1f84 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/enchanter-base.h"
 #include "system/angband.h"
index 93eef77..8f89672 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 防具類に耐性等を付与する処理の共通部分
  * @date 2021/08/01
  * @author Hourier
index 7404a46..93aed9d 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 鎧類に耐性等の追加効果を付与する基底処理
  * @date 2022/03/12
  * @author Hourier
index e3ea538..44f4e7c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/abstract-protector-enchanter.h"
 #include "system/angband.h"
index 4b32552..14055a1 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 靴に耐性等の追加効果を付与する処理
  * @date 2021/08/01
  * @author Hourier
index 8cd63e7..d6a4b57 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/abstract-protector-enchanter.h"
 #include "system/angband.h"
index ff90936..f04ade9 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief クロークに耐性等の追加効果を付与する処理
  * @date 2021/08/01
  * @author Hourier
index b0a8eff..2a11e8f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/abstract-protector-enchanter.h"
 #include "system/angband.h"
index ffa1c0c..15e00b8 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 冠に耐性等の追加効果を付与する処理
  * @date 2021/08/01
  * @author Hourier
index 8ab327f..d6fee9f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/abstract-protector-enchanter.h"
 #include "system/angband.h"
index d40719a..8a7bd7f 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief ドラゴン・スケイルメイルに耐性等の追加効果を付与する処理
  * @date 2022/03/12
  * @author Hourier
index 45ba86d..f613bba 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/abstract-protector-enchanter.h"
 #include "system/angband.h"
index 21db829..6ad75c0 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 籠手に耐性等の追加効果を付与する処理
  * @date 2021/08/01
  * @author Hourier
index 012b5a6..715643b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/abstract-protector-enchanter.h"
 #include "system/angband.h"
index 0da2d59..6699a53 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 重鎧に耐性等の追加効果を付与する処理
  * @date 2022/03/12
  * @author Hourier
index dff2e0c..54f9427 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/apply-magic-armor.h"
 #include "system/angband.h"
index ffab38e..65d49b6 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 兜に耐性等の追加効果を付与する処理
  * @date 2021/08/01
  * @author Hourier
index 50c1bb2..7141e4d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/abstract-protector-enchanter.h"
 #include "system/angband.h"
index 5aafd42..d6acbce 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 盾に耐性等の追加効果を付与する処理
  * @date 2021/08/01
  * @author Hourier
index 01c233c..2028add 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/abstract-protector-enchanter.h"
 #include "system/angband.h"
index 50d93d9..73e1cd2 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 軽鎧に耐性等の追加効果を付与する処理
  * @date 2022/03/12
  * @author Hourier
@@ -48,11 +48,11 @@ void SoftArmorEnchanter::apply_magic()
 void SoftArmorEnchanter::sval_enchant()
 {
     const auto sval = this->o_ptr->bi_key.sval();
-    if (!sval.has_value()) {
+    if (!sval) {
         return;
     }
 
-    switch (sval.value()) {
+    switch (*sval) {
     case SV_KUROSHOUZOKU:
         this->o_ptr->pval = randint1(4);
         return;
index 998c44e..dca638d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/protector/apply-magic-armor.h"
 #include "system/angband.h"
index 06b3c02..7b0ecbb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Special Object Flags
index ca157ea..014e548 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/tr-types.h"
 #include "util/flag-group.h"
index bff1cb1..fe65f12 100644 (file)
@@ -1,13 +1,11 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 #include <array>
 
 /*!
  * @todo TRが何の略か分かる人、補足求む
  */
-enum tr_type : int32_t {
+enum tr_type : int {
     TR_STR = 0, /* STR += "pval" */
     TR_INT = 1, /* INT += "pval" */
     TR_WIS = 2, /* WIS += "pval" */
@@ -154,7 +152,7 @@ enum tr_type : int32_t {
     TR_EASY2_WEAPON = 139,
     TR_DOWN_SAVING = 140,
     TR_NO_AC = 141,
-    TR_HEAVY_SPELL = 142,
+    TR_XXX_142 = 142, //!< 未使用 / Unused
     TR_RES_TIME = 143,
     TR_RES_WATER = 144,
     TR_INVULN_ARROW = 145,
index 45aebca..877ba3a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* 旧TRC. 実態に即した名称に変更 */
 enum class CurseTraitType {
index 1a973e7..38e69b3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 // clang-format off
 /*!
index f6252d1..356a51a 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-enchant/vorpal-weapon.h"
+#include "object-enchant/vorpal-weapon.h"
 #include "artifact/fixed-art-types.h"
 #include "inventory/inventory-slot-types.h"
 #include "io/files-util.h"
@@ -6,7 +6,7 @@
 #include "main/sound-of-music.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags-resistance.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
@@ -63,8 +63,8 @@ static void print_chainsword_noise(ItemEntity *o_ptr)
     }
 
     const auto chainsword_noise = get_random_line(_("chainswd_j.txt", "chainswd.txt"), 0);
-    if (chainsword_noise.has_value()) {
-        msg_print(chainsword_noise.value());
+    if (chainsword_noise) {
+        msg_print(*chainsword_noise);
     }
 }
 
@@ -95,7 +95,7 @@ void process_vorpal_attack(PlayerType *player_ptr, player_attack_type *pa_ptr, c
     }
 
     pa_ptr->attack_damage *= (int)vorpal_magnification;
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     if ((r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL) ? pa_ptr->attack_damage / 100 : pa_ptr->attack_damage) > pa_ptr->m_ptr->hp) {
         msg_format(_("%sを真っ二つにした!", "You cut %s in half!"), pa_ptr->m_name);
     } else {
index 4a1da30..a65f76c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct player_attack_type;
 class PlayerType;
index 5a0aae8..1c50ab8 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-enchant/weapon/abstract-weapon-enchanter.h"
+#include "object-enchant/weapon/abstract-weapon-enchanter.h"
 #include "object-enchant/object-boost.h"
 #include "object/tval-types.h"
 #include "sv-definition/sv-weapon-types.h"
index 397ddf9..585f945 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/enchanter-base.h"
 #include "system/angband.h"
index 49a3c4a..f00bbbe 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 矢類のアイテムを強化する処理
  * @date 2022/03/11
  * @author Hourier
index 80091f6..465849e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/weapon/abstract-weapon-enchanter.h"
 #include "system/angband.h"
index ad4b146..80c4d1d 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 弓系のアイテムを強化する処理
  * @date 2022/03/11
  * @author Hourier
index 3042e6f..e1fa0c9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/weapon/abstract-weapon-enchanter.h"
 #include "system/angband.h"
index 9d23aa7..8136731 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 掘削武器に耐性等の追加効果を付与する処理
  * @date 2022/03/11
  * @author Hourier
index a3a50cf..d7eb73d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/weapon/abstract-weapon-enchanter.h"
 #include "system/angband.h"
index 6f333d2..244a366 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 鈍器に耐性等の追加効果を付与する処理
  * @date 2022/03/22
  * @author Hourier
index 0e80dac..032b864 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/weapon/melee-weapon-enchanter.h"
 #include "system/angband.h"
index 7627641..a8a02fc 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 長柄/斧に耐性等の追加効果を付与する処理
  * @date 2022/03/22
  * @author Hourier
index 5c229bc..e9056b8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/weapon/melee-weapon-enchanter.h"
 #include "system/angband.h"
index fa6341b..4523f33 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 剣に耐性等の追加効果を付与する処理
  * @date 2022/03/22
  * @author Hourier
index a24db23..4d3f801 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/weapon/melee-weapon-enchanter.h"
 #include "system/angband.h"
index b4bca16..078aac4 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 剣・鈍器・長柄/斧武器に耐性等の追加効果を付与する処理
  * @date 2022/03/22
  * @author Hourier
index 52e09ef..157abac 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/weapon/abstract-weapon-enchanter.h"
 #include "system/angband.h"
index aad32dc..9395539 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-hook/hook-armor.h"
+#include "object-hook/hook-armor.h"
 #include "inventory/inventory-slot-types.h"
 #include "object/object-info.h"
 #include "player/player-sex.h"
index a2cd8ed..eb08aa8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index d3acc6b..576e79d 100644 (file)
@@ -1,6 +1,5 @@
-#include "object-hook/hook-expendable.h"
+#include "object-hook/hook-expendable.h"
 #include "artifact/fixed-art-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "monster-race/monster-race.h"
 #include "object-enchant/item-feeling.h"
@@ -15,6 +14,7 @@
 #include "system/item-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/string-processor.h"
 
 /*!
@@ -37,7 +37,7 @@ bool item_tester_hook_eatable(PlayerType *player_ptr, const ItemEntity *o_ptr)
         }
     } else if (food_type == PlayerRaceFoodType::CORPSE) {
         auto corpse_r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
-        if ((o_ptr->bi_key == BaseitemKey(ItemKindType::CORPSE, SV_CORPSE)) && angband_strchr("pht", monraces_info[corpse_r_idx].d_char)) {
+        if (o_ptr->is_corpse() && angband_strchr("pht", monraces_info[corpse_r_idx].d_char)) {
             return true;
         }
     }
@@ -62,12 +62,11 @@ bool item_tester_hook_quaff(PlayerType *player_ptr, const ItemEntity *o_ptr)
 }
 
 /*!
- * @brief 破壊可能なアイテムかを返す /
- * Determines whether an object can be destroyed, and makes fake inscription.
+ * @brief 破壊可能なアイテムかを返す
  * @param o_ptr 破壊可能かを確認したいオブジェクトの構造体参照ポインタ
  * @return オブジェクトが破壊可能ならばTRUEを返す
  */
-bool can_player_destroy_object(PlayerType *player_ptr, ItemEntity *o_ptr)
+bool can_player_destroy_object(ItemEntity *o_ptr)
 {
     /* Artifacts cannot be destroyed */
     if (!o_ptr->is_fixed_or_random_artifact()) {
@@ -82,8 +81,13 @@ bool can_player_destroy_object(PlayerType *player_ptr, ItemEntity *o_ptr)
 
         o_ptr->feeling = feel;
         o_ptr->ident |= IDENT_SENSE;
-        player_ptr->update |= (PU_COMBINATION);
-        player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(StatusRecalculatingFlag::COMBINATION);
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::INVENTORY,
+            SubWindowRedrawingFlag::EQUIPMENT,
+        };
+        rfu.set_flags(flags);
         return false;
     }
 
index ff25fb9..fd7d412 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
 bool item_tester_hook_eatable(PlayerType *player_ptr, const ItemEntity *o_ptr);
 bool item_tester_hook_quaff(PlayerType *player_ptr, const ItemEntity *o_ptr);
-bool can_player_destroy_object(PlayerType *player_ptr, ItemEntity *o_ptr);
+bool can_player_destroy_object(ItemEntity *o_ptr);
index 8cc7e55..8c14020 100644 (file)
@@ -1,7 +1,6 @@
-#include "object-hook/hook-magic.h"
+#include "object-hook/hook-magic.h"
 #include "inventory/inventory-slot-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "perception/object-perception.h"
 #include "player-base/player-class.h"
 #include "player-info/class-info.h"
@@ -41,11 +40,8 @@ bool item_tester_hook_use(PlayerType *player_ptr, const ItemEntity *o_ptr)
         }
 
         for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
-            if (&player_ptr->inventory_list[i] == o_ptr) {
-                auto flags = object_flags(o_ptr);
-                if (flags.has(TR_ACTIVATE)) {
-                    return true;
-                }
+            if ((&player_ptr->inventory_list[i] == o_ptr) && o_ptr->get_flags().has(TR_ACTIVATE)) {
+                return true;
             }
         }
 
index c29e4de..6b63de0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index 6962507..1890a4a 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-hook/hook-perception.h"
+#include "object-hook/hook-perception.h"
 #include "object-hook/hook-weapon.h"
 #include "perception/object-perception.h"
 #include "system/item-entity.h"
index 2578cff..53c317e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 bool object_is_nameless_weapon_armour(const ItemEntity *o_ptr);
index 09aabaf..1491dbb 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-hook/hook-quest.h"
+#include "object-hook/hook-quest.h"
 #include "artifact/fixed-art-types.h"
 #include "cmd-building/cmd-building.h"
 #include "dungeon/quest.h"
index 1264ca0..1fc0367 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "dungeon/quest.h"
 #include "system/angband.h"
index 2d75a69..e0e04da 100644 (file)
@@ -1,7 +1,6 @@
-#include "object-hook/hook-weapon.h"
+#include "object-hook/hook-weapon.h"
 #include "object-enchant/tr-types.h"
 #include "object-hook/hook-armor.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "player/player-skill.h"
 #include "sv-definition/sv-weapon-types.h"
@@ -22,10 +21,10 @@ bool object_is_favorite(PlayerType *player_ptr, const ItemEntity *o_ptr)
 
     /* Favorite weapons are varied depend on the class */
     const auto tval = o_ptr->bi_key.tval();
-    const auto sval = o_ptr->bi_key.sval().value();
+    const auto sval = *o_ptr->bi_key.sval();
     switch (player_ptr->pclass) {
     case PlayerClassType::PRIEST: {
-        const auto flags = object_flags_known(o_ptr);
+        const auto flags = o_ptr->get_flags_known();
         return flags.has(TR_BLESSED) || (tval == ItemKindType::HAFTED);
     }
     case PlayerClassType::MONK:
@@ -35,7 +34,7 @@ bool object_is_favorite(PlayerType *player_ptr, const ItemEntity *o_ptr)
     case PlayerClassType::BEASTMASTER:
     case PlayerClassType::CAVALRY: {
         /* Is it known to be suitable to using while riding? */
-        auto flags = object_flags_known(o_ptr);
+        auto flags = o_ptr->get_flags_known();
         return flags.has(TR_RIDING);
     }
     case PlayerClassType::SORCERER:
index a17f156..ce926b7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index 3366d5c..9b2ea8c 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-use/item-use-checker.h"
+#include "object-use/item-use-checker.h"
 #include "system/player-type-definition.h"
 #include "timed-effect/player-stun.h"
 #include "timed-effect/timed-effects.h"
index 3aac03e..8c8bb30 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 
index ffc06c4..221a810 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 薬を飲んだ時の効果処理
  * @date 2022/03/10
  * @author Hourier
@@ -7,7 +7,6 @@
 #include "object-use/quaff/quaff-effects.h"
 #include "avatar/avatar.h"
 #include "birth/birth-stat.h"
-#include "core/player-update-types.h"
 #include "game-option/birth-options.h"
 #include "mutation/mutation-investor-remover.h"
 #include "object/object-info.h"
@@ -37,6 +36,7 @@
 #include "system/angband.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-acceleration.h"
 #include "timed-effect/player-poison.h"
 #include "timed-effect/timed-effects.h"
@@ -48,13 +48,13 @@ QuaffEffects::QuaffEffects(PlayerType *player_ptr)
 {
 }
 
-bool QuaffEffects::influence(const ItemEntity &o_ref)
+bool QuaffEffects::influence(const ItemEntity &item)
 {
-    if (o_ref.bi_key.tval() != ItemKindType::POTION) {
+    if (item.bi_key.tval() != ItemKindType::POTION) {
         return false;
     }
 
-    switch (o_ref.bi_key.sval().value()) {
+    switch (*item.bi_key.sval()) {
     case SV_POTION_WATER:
         msg_print(_("口の中がさっぱりした。", "That was refreshing."));
         msg_print(_("のどの渇きが少しおさまった。", "You feel less thirsty."));
@@ -274,7 +274,7 @@ bool QuaffEffects::booze()
         ident = true;
     }
 
-    if (!is_monk || !one_in_(13)) {
+    if (is_monk || !one_in_(13)) {
         return ident;
     }
 
@@ -504,7 +504,7 @@ bool QuaffEffects::new_life()
 {
     roll_hitdice(this->player_ptr, SPOP_NONE);
     get_max_stats(this->player_ptr);
-    this->player_ptr->update |= PU_BONUS;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     lose_all_mutations(this->player_ptr);
     return true;
 }
index 068c350..3c1cda7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
@@ -6,7 +6,7 @@ class QuaffEffects {
 public:
     QuaffEffects(PlayerType *player_ptr);
 
-    bool influence(const ItemEntity &o_ref);
+    bool influence(const ItemEntity &item);
 
 private:
     PlayerType *player_ptr;
index 920076d..3c4e286 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 薬を飲んだ時の各種効果処理
  * @date 2022/03/10
  * @author Hourier
@@ -6,7 +6,6 @@
 
 #include "object-use/quaff/quaff-execution.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "game-option/disturbance-options.h"
 #include "inventory/inventory-object.h"
@@ -27,6 +26,7 @@
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "view/display-messages.h"
 
@@ -41,40 +41,50 @@ ObjectQuaffEntity::ObjectQuaffEntity(PlayerType *player_ptr)
 
 /*!
  * @brief 薬を飲む.
- * @param item 飲む薬オブジェクトの所持品ID
+ * @param i_idx 薬のインベントリID
  * @details
  * 効果発動のあと、食料タイプによって空腹度を少し充足する。
  * 但し骸骨は除く
  */
-void ObjectQuaffEntity::execute(INVENTORY_IDX item)
+void ObjectQuaffEntity::execute(INVENTORY_IDX i_idx)
 {
     if (!this->can_influence()) {
         return;
     }
 
-    const auto &o_ref = this->copy_object(item);
-    vary_item(this->player_ptr, item, -1);
+    auto item = this->copy_object(i_idx);
+    vary_item(this->player_ptr, i_idx, -1);
     sound(SOUND_QUAFF);
-    auto ident = QuaffEffects(this->player_ptr).influence(o_ref);
+    auto ident = QuaffEffects(this->player_ptr).influence(item);
     if (PlayerRace(this->player_ptr).equals(PlayerRaceType::SKELETON)) {
         msg_print(_("液体の一部はあなたのアゴを素通りして落ちた!", "Some of the fluid falls through your jaws!"));
-        (void)potion_smash_effect(this->player_ptr, 0, this->player_ptr->y, this->player_ptr->x, o_ref.bi_id);
+        (void)potion_smash_effect(this->player_ptr, 0, this->player_ptr->y, this->player_ptr->x, item.bi_id);
     }
 
-    this->player_ptr->update |= PU_COMBINATION | PU_REORDER;
-    this->change_virtue_as_quaff(o_ref);
-    object_tried(&o_ref);
-    if (ident && !o_ref.is_aware()) {
-        object_aware(this->player_ptr, &o_ref);
-        gain_exp(this->player_ptr, (o_ref.get_baseitem().level + (this->player_ptr->lev >> 1)) / this->player_ptr->lev);
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flags(flags_srf);
+    this->change_virtue_as_quaff(item);
+    item.mark_as_tried();
+    if (ident && !item.is_aware()) {
+        object_aware(this->player_ptr, &item);
+        gain_exp(this->player_ptr, (item.get_baseitem().level + (this->player_ptr->lev >> 1)) / this->player_ptr->lev);
     }
 
-    this->player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags);
     if (PlayerRace(this->player_ptr).equals(PlayerRaceType::SKELETON)) {
         return;
     }
 
-    this->moisten(o_ref);
+    this->moisten(item);
 }
 
 bool ObjectQuaffEntity::can_influence()
@@ -111,9 +121,9 @@ bool ObjectQuaffEntity::can_quaff()
     return ItemUseChecker(this->player_ptr).check_stun(_("朦朧としていて瓶の蓋を開けられなかった!", "You are too stunned to quaff it!"));
 }
 
-ItemEntity ObjectQuaffEntity::copy_object(const INVENTORY_IDX item)
+ItemEntity ObjectQuaffEntity::copy_object(const INVENTORY_IDX i_idx)
 {
-    auto *tmp_o_ptr = ref_item(this->player_ptr, item);
+    auto *tmp_o_ptr = ref_item(this->player_ptr, i_idx);
     auto o_val = *tmp_o_ptr;
     o_val.number = 1;
     return o_val;
index 9daa7d6..8a24022 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -9,14 +9,14 @@ public:
     ObjectQuaffEntity(PlayerType *player_ptr);
     virtual ~ObjectQuaffEntity() = default;
 
-    void execute(INVENTORY_IDX item);
+    void execute(INVENTORY_IDX i_idx);
 
 private:
     PlayerType *player_ptr;
 
     bool can_influence();
     bool can_quaff();
-    ItemEntity copy_object(const INVENTORY_IDX item);
+    ItemEntity copy_object(const INVENTORY_IDX i_idx);
     void moisten(const ItemEntity &o_ref);
     void change_virtue_as_quaff(const ItemEntity &o_ref);
 };
index 0a5b49e..651dfb7 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 読むことができるアイテム群の内、Tシャツ『★GHB』を読んだ時の効果や処理を記述する.
  * @date 2022/02/26
  * @author Hourier
index d70033a..4c719f8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-use/read/read-executor-base.h"
 
index 3b938db..2ef8b87 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 読むことができるアイテム群の内、中つ国ガイドを読んだ時の効果や処理を記述する.
  * @date 2022/02/26
  * @author Hourier
@@ -14,6 +14,8 @@
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h"
 #include "util/angband-files.h"
+#include <iomanip>
+#include <sstream>
 
 ParchmentReadExecutor::ParchmentReadExecutor(PlayerType *player_ptr, ItemEntity *o_ptr)
     : player_ptr(player_ptr)
@@ -28,12 +30,15 @@ bool ParchmentReadExecutor::is_identified() const
 
 bool ParchmentReadExecutor::read()
 {
-    char buf[1024]{};
     screen_save();
-    auto q = format("book-%d_jp.txt", this->o_ptr->bi_key.sval().value());
+    std::stringstream ss;
+    ss << "book-" << std::setfill('0') << std::right << std::setw(3) << *this->o_ptr->bi_key.sval();
+    ss << "_" << _("jp", "en") << ".txt";
     const auto item_name = describe_flavor(this->player_ptr, this->o_ptr, OD_NAME_ONLY);
-    path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, q);
-    (void)show_file(this->player_ptr, true, buf, item_name.data(), 0, 0);
+    auto path = path_build(ANGBAND_DIR_FILE, "books");
+    path.append(ss.str());
+    const auto &filename = path.string();
+    (void)show_file(this->player_ptr, true, filename, 0, 0, item_name);
     screen_load();
     return false;
 }
index b9b3bb4..c859151 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-use/read/read-executor-base.h"
 
index 06c6273..8ff4fdd 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 巻物を読んだ際の効果処理
  * @date 2022/02/26
  * @author Hourier
@@ -7,7 +7,6 @@
 #include "object-use/read/read-execution.h"
 #include "action/action-limited.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "inventory/inventory-object.h"
 #include "main/sound-definitions-table.h"
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
 /*!
  * @brief コンストラクタ
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 読むオブジェクトの所持品ID
+ * @param i_idx 読むアイテムのインベントリID
  */
-ObjectReadEntity::ObjectReadEntity(PlayerType *player_ptr, INVENTORY_IDX item)
+ObjectReadEntity::ObjectReadEntity(PlayerType *player_ptr, INVENTORY_IDX i_idx)
     : player_ptr(player_ptr)
-    , item(item)
+    , i_idx(i_idx)
 {
 }
 
@@ -44,7 +44,7 @@ ObjectReadEntity::ObjectReadEntity(PlayerType *player_ptr, INVENTORY_IDX item)
  */
 void ObjectReadEntity::execute(bool known)
 {
-    auto *o_ptr = ref_item(this->player_ptr, this->item);
+    auto *o_ptr = ref_item(this->player_ptr, this->i_idx);
     PlayerEnergy(this->player_ptr).set_player_turn_energy(100);
     if (!this->can_read()) {
         return;
@@ -61,19 +61,30 @@ void ObjectReadEntity::execute(bool known)
 
     auto executor = ReadExecutorFactory::create(player_ptr, o_ptr, known);
     auto used_up = executor->read();
-    BIT_FLAGS inventory_flags = PU_COMBINATION | PU_REORDER | (this->player_ptr->update & PU_AUTO_DESTRUCTION);
-    reset_bits(this->player_ptr->update, PU_COMBINATION | PU_REORDER | PU_AUTO_DESTRUCTION);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    using Srf = StatusRecalculatingFlag;
+    EnumClassFlagGroup<Srf> flags_srf = { Srf::COMBINATION, Srf::REORDER };
+    if (rfu.has(Srf::AUTO_DESTRUCTION)) {
+        flags_srf.set(Srf::AUTO_DESTRUCTION);
+    }
+
+    rfu.reset_flags(flags_srf);
     this->change_virtue_as_read(*o_ptr);
-    object_tried(o_ptr);
+    o_ptr->mark_as_tried();
     this->gain_exp_from_item_use(o_ptr, executor->is_identified());
-    this->player_ptr->window_flags |= PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER;
-    this->player_ptr->update |= inventory_flags;
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags_swrf);
+    rfu.set_flags(flags_srf);
     if (!used_up) {
         return;
     }
 
     sound(SOUND_SCROLL);
-    vary_item(this->player_ptr, this->item, -1);
+    vary_item(this->player_ptr, this->i_idx, -1);
 }
 
 bool ObjectReadEntity::can_read() const
index c8e4f53..91bc003 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -6,14 +6,14 @@ class ItemEntity;
 class PlayerType;
 class ObjectReadEntity {
 public:
-    ObjectReadEntity(PlayerType *player_ptr, INVENTORY_IDX item);
+    ObjectReadEntity(PlayerType *player_ptr, INVENTORY_IDX i_idx);
     virtual ~ObjectReadEntity() = default;
 
     void execute(bool known);
 
 private:
     PlayerType *player_ptr;
-    INVENTORY_IDX item;
+    INVENTORY_IDX i_idx;
 
     bool can_read() const;
     void change_virtue_as_read(ItemEntity &o_ref);
index e23cc91..efa0c53 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ReadExecutorBase {
 public:
index 49d212d..51db6c7 100644 (file)
@@ -1,4 +1,4 @@
-#include "object-use/read/read-executor-factory.h"
+#include "object-use/read/read-executor-factory.h"
 #include "artifact/fixed-art-types.h"
 #include "object-use/read/gbh-shirt-read-executor.h"
 #include "object-use/read/parchment-read-executor.h"
index 8dff9f7..dc0d14a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-use/read/read-executor-base.h"
 #include <memory>
index 2a6abab..2160ba4 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 読むことができるアイテム群の内、一つの指輪に刻印された文字を読んだ時の効果や処理を記述する.
  * @date 2022/02/26
  * @author Hourier
index 4059c7b..73fbe79 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-use/read/read-executor-base.h"
 
index a4fe1d1..1fdad22 100644 (file)
@@ -1,12 +1,10 @@
-/*
+/*
  * @brief 読むことができるアイテム群の内、巻物を読んだ時の効果や処理を記述する.
  * @date 2022/02/26
  * @author Hourier
  */
 
 #include "object-use/read/scroll-read-executor.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "monster-floor/monster-summon.h"
 #include "monster-floor/place-monster-types.h"
 #include "player-base/player-class.h"
@@ -41,6 +39,7 @@
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
@@ -59,7 +58,8 @@ bool ScrollReadExecutor::is_identified() const
 bool ScrollReadExecutor::read()
 {
     auto used_up = true;
-    switch (this->o_ptr->bi_key.sval().value()) {
+    auto *floor_ptr = this->player_ptr->current_floor_ptr;
+    switch (*this->o_ptr->bi_key.sval()) {
     case SV_SCROLL_DARKNESS:
         if (!has_resist_blind(this->player_ptr) && !has_resist_dark(this->player_ptr)) {
             (void)BadStatusSetter(this->player_ptr).mod_blindness(3 + randint1(5));
@@ -100,7 +100,7 @@ bool ScrollReadExecutor::read()
     }
     case SV_SCROLL_SUMMON_MONSTER:
         for (auto k = 0; k < randint1(3); k++) {
-            if (summon_specific(this->player_ptr, 0, this->player_ptr->y, this->player_ptr->x, this->player_ptr->current_floor_ptr->dun_level, SUMMON_NONE,
+            if (summon_specific(this->player_ptr, 0, this->player_ptr->y, this->player_ptr->x, floor_ptr->dun_level, SUMMON_NONE,
                     PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET)) {
                 this->ident = true;
             }
@@ -109,7 +109,7 @@ bool ScrollReadExecutor::read()
         break;
     case SV_SCROLL_SUMMON_UNDEAD:
         for (auto k = 0; k < randint1(3); k++) {
-            if (summon_specific(this->player_ptr, 0, this->player_ptr->y, this->player_ptr->x, this->player_ptr->current_floor_ptr->dun_level, SUMMON_UNDEAD,
+            if (summon_specific(this->player_ptr, 0, this->player_ptr->y, this->player_ptr->x, floor_ptr->dun_level, SUMMON_UNDEAD,
                     PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET)) {
                 this->ident = true;
             }
@@ -118,7 +118,7 @@ bool ScrollReadExecutor::read()
         break;
     case SV_SCROLL_SUMMON_PET:
         if (summon_specific(
-                this->player_ptr, -1, this->player_ptr->y, this->player_ptr->x, this->player_ptr->current_floor_ptr->dun_level, SUMMON_NONE, PM_ALLOW_GROUP | PM_FORCE_PET)) {
+                this->player_ptr, -1, this->player_ptr->y, this->player_ptr->x, floor_ptr->dun_level, SUMMON_NONE, PM_ALLOW_GROUP | PM_FORCE_PET)) {
             this->ident = true;
         }
 
@@ -302,7 +302,7 @@ bool ScrollReadExecutor::read()
 
         msg_print(_("手が輝き始めた。", "Your hands begin to glow."));
         this->player_ptr->special_attack |= ATTACK_CONFUSE;
-        this->player_ptr->redraw |= PR_TIMED_EFFECT;
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
         this->ident = true;
         break;
     case SV_SCROLL_PROTECTION_FROM_EVIL: {
@@ -343,7 +343,7 @@ bool ScrollReadExecutor::read()
         }
 
         this->player_ptr->add_spells++;
-        this->player_ptr->update |= PU_SPELLS;
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::SPELLS);
         this->ident = true;
         break;
     case SV_SCROLL_GENOCIDE:
@@ -355,11 +355,11 @@ bool ScrollReadExecutor::read()
         this->ident = true;
         break;
     case SV_SCROLL_ACQUIREMENT:
-        acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 1, true, false, false);
+        acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 1, true);
         this->ident = true;
         break;
     case SV_SCROLL_STAR_ACQUIREMENT:
-        acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, randint1(2) + 1, true, false, false);
+        acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, randint1(2) + 1, true);
         this->ident = true;
         break;
     case SV_SCROLL_FIRE:
index e3e9421..311d21f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-use/read/read-executor-base.h"
 
index 38608d1..f813ef2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file throw-util.cpp
  * @brief 投擲処理関連クラス
  * @date 2021/08/20
@@ -11,7 +11,6 @@
 #include "combat/attack-power-table.h"
 #include "combat/shoot.h"
 #include "combat/slaying.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
@@ -45,7 +44,6 @@
 #include "object/item-tester-hooker.h"
 #include "object/item-use-flags.h"
 #include "object/object-broken.h"
-#include "object/object-flags.h"
 #include "object/object-info.h"
 #include "object/object-stack.h"
 #include "player-base/player-class.h"
@@ -60,6 +58,7 @@
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "target/target-getter.h"
 #include "term/screen-processor.h"
@@ -88,7 +87,7 @@ bool ObjectThrowEntity::check_can_throw()
         return false;
     }
 
-    if (this->o_ptr->is_cursed() && (this->item >= INVEN_MAIN_HAND)) {
+    if (this->o_ptr->is_cursed() && (this->i_idx >= INVEN_MAIN_HAND)) {
         msg_print(_("ふーむ、どうやら呪われているようだ。", "Hmmm, it seems to be cursed."));
         return false;
     }
@@ -106,7 +105,7 @@ bool ObjectThrowEntity::check_can_throw()
 void ObjectThrowEntity::calc_throw_range()
 {
     this->q_ptr->copy_from(this->o_ptr);
-    this->obj_flags = object_flags(this->q_ptr);
+    this->obj_flags = this->q_ptr->get_flags();
     torch_flags(this->q_ptr, this->obj_flags);
     distribute_charges(this->o_ptr, this->q_ptr, 1);
     this->q_ptr->number = 1;
@@ -158,18 +157,18 @@ void ObjectThrowEntity::reflect_inventory_by_throw()
         this->return_when_thrown = true;
     }
 
-    if (this->item < 0) {
-        floor_item_increase(this->player_ptr, 0 - this->item, -1);
-        floor_item_optimize(this->player_ptr, 0 - this->item);
+    if (this->i_idx < 0) {
+        floor_item_increase(this->player_ptr, 0 - this->i_idx, -1);
+        floor_item_optimize(this->player_ptr, 0 - this->i_idx);
         return;
     }
 
-    inven_item_increase(this->player_ptr, this->item, -1);
+    inven_item_increase(this->player_ptr, this->i_idx, -1);
     if (!this->return_when_thrown) {
-        inven_item_describe(this->player_ptr, this->item);
+        inven_item_describe(this->player_ptr, this->i_idx);
     }
 
-    inven_item_optimize(this->player_ptr, this->item);
+    inven_item_optimize(this->player_ptr, this->i_idx);
 }
 
 void ObjectThrowEntity::set_class_specific_throw_params()
@@ -271,7 +270,8 @@ void ObjectThrowEntity::display_potion_throw()
 
     const auto angry_m_name = monster_desc(this->player_ptr, angry_m_ptr, 0);
     msg_format(_("%sは怒った!", "%s^ gets angry!"), angry_m_name.data());
-    set_hostile(this->player_ptr, &floor_ptr->m_list[floor_ptr->grid_array[this->y][this->x].m_idx]);
+    const auto &grid = floor_ptr->get_grid({ this->y, this->x });
+    floor_ptr->m_list[grid.m_idx].set_hostile();
     this->do_drop = false;
 }
 
@@ -299,24 +299,30 @@ void ObjectThrowEntity::check_boomerang_throw()
 void ObjectThrowEntity::process_boomerang_back()
 {
     if (this->come_back) {
-        if ((this->item != INVEN_MAIN_HAND) && (this->item != INVEN_SUB_HAND)) {
-            store_item_to_inventory(player_ptr, this->q_ptr);
+        if ((this->i_idx != INVEN_MAIN_HAND) && (this->i_idx != INVEN_SUB_HAND)) {
+            store_item_to_inventory(this->player_ptr, this->q_ptr);
             this->do_drop = false;
             return;
         }
 
-        this->o_ptr = &player_ptr->inventory_list[this->item];
+        this->o_ptr = &player_ptr->inventory_list[this->i_idx];
         this->o_ptr->copy_from(this->q_ptr);
-        player_ptr->equip_cnt++;
-        player_ptr->update |= PU_BONUS | PU_TORCH | PU_MP;
-        player_ptr->window_flags |= PW_EQUIPMENT;
+        this->player_ptr->equip_cnt++;
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        static constexpr auto flags = {
+            StatusRecalculatingFlag::BONUS,
+            StatusRecalculatingFlag::TORCH,
+            StatusRecalculatingFlag::MP,
+        };
+        rfu.set_flags(flags);
+        rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
         this->do_drop = false;
         return;
     }
 
     if (this->equiped_item) {
-        verify_equip_slot(player_ptr, this->item);
-        calc_android_exp(player_ptr);
+        verify_equip_slot(this->player_ptr, this->i_idx);
+        calc_android_exp(this->player_ptr);
     }
 }
 
@@ -335,8 +341,8 @@ void ObjectThrowEntity::drop_thrown_item()
 bool ObjectThrowEntity::check_what_throw()
 {
     if (this->shuriken >= 0) {
-        this->item = this->shuriken;
-        this->o_ptr = &this->player_ptr->inventory_list[this->item];
+        this->i_idx = this->shuriken;
+        this->o_ptr = &this->player_ptr->inventory_list[this->i_idx];
         return true;
     }
 
@@ -344,10 +350,9 @@ bool ObjectThrowEntity::check_what_throw()
         return this->check_throw_boomerang();
     }
 
-    concptr q, s;
-    q = _("どのアイテムを投げますか? ", "Throw which item? ");
-    s = _("投げるアイテムがない。", "You have nothing to throw.");
-    this->o_ptr = choose_object(this->player_ptr, &this->item, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP);
+    constexpr auto q = _("どのアイテムを投げますか? ", "Throw which item? ");
+    constexpr auto s = _("投げるアイテムがない。", "You have nothing to throw.");
+    this->o_ptr = choose_object(this->player_ptr, &this->i_idx, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP);
     if (!this->o_ptr) {
         flush();
         return false;
@@ -362,7 +367,7 @@ bool ObjectThrowEntity::check_throw_boomerang()
         concptr q, s;
         q = _("どの武器を投げますか? ", "Throw which item? ");
         s = _("投げる武器がない。", "You have nothing to throw.");
-        this->o_ptr = choose_object(this->player_ptr, &this->item, q, s, USE_EQUIP, FuncItemTester(&ItemEntity::is_throwable));
+        this->o_ptr = choose_object(this->player_ptr, &this->i_idx, q, s, USE_EQUIP, FuncItemTester(&ItemEntity::is_throwable));
         if (!this->o_ptr) {
             flush();
             return false;
@@ -372,21 +377,21 @@ bool ObjectThrowEntity::check_throw_boomerang()
     }
 
     if (has_melee_weapon(this->player_ptr, INVEN_SUB_HAND)) {
-        this->item = INVEN_SUB_HAND;
-        this->o_ptr = &this->player_ptr->inventory_list[this->item];
+        this->i_idx = INVEN_SUB_HAND;
+        this->o_ptr = &this->player_ptr->inventory_list[this->i_idx];
         return true;
     }
 
-    this->item = INVEN_MAIN_HAND;
-    this->o_ptr = &this->player_ptr->inventory_list[this->item];
+    this->i_idx = INVEN_MAIN_HAND;
+    this->o_ptr = &this->player_ptr->inventory_list[this->i_idx];
     return true;
 }
 
 bool ObjectThrowEntity::check_racial_target_bold()
 {
-    this->ny[this->cur_dis] = this->y;
-    this->nx[this->cur_dis] = this->x;
-    mmove2(&this->ny[this->cur_dis], &this->nx[this->cur_dis], this->player_ptr->y, this->player_ptr->x, this->ty, this->tx);
+    const auto pos = mmove2({ this->y, this->x }, this->player_ptr->get_position(), { this->ty, this->tx });
+    this->ny[this->cur_dis] = pos.y;
+    this->nx[this->cur_dis] = pos.x;
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
     if (cave_has_flag_bold(floor_ptr, this->ny[this->cur_dis], this->nx[this->cur_dis], TerrainCharacteristics::PROJECT)) {
         return false;
@@ -447,7 +452,7 @@ void ObjectThrowEntity::attack_racial_power()
     }
 
     MonsterDamageProcessor mdp(this->player_ptr, this->g_ptr->m_idx, this->tdam, &fear, attribute_flags);
-    if (mdp.mon_take_hit(extract_note_dies(this->m_ptr->get_real_r_idx()))) {
+    if (mdp.mon_take_hit(this->m_ptr->get_died_message())) {
         return;
     }
 
@@ -495,7 +500,7 @@ void ObjectThrowEntity::calc_racial_power_damage()
     this->tdam = critical_shot(this->player_ptr, this->q_ptr->weight, this->q_ptr->to_h, 0, this->tdam);
     this->tdam += (this->q_ptr->to_d > 0 ? 1 : -1) * this->q_ptr->to_d;
     if (this->boomerang) {
-        this->tdam *= (this->mult + this->player_ptr->num_blow[this->item - INVEN_MAIN_HAND]);
+        this->tdam *= (this->mult + this->player_ptr->num_blow[this->i_idx - INVEN_MAIN_HAND]);
         this->tdam += this->player_ptr->to_d_m;
     } else if (this->obj_flags.has(TR_THROW)) {
         this->tdam *= (3 + this->mult);
@@ -548,13 +553,13 @@ void ObjectThrowEntity::process_boomerang_throw()
 void ObjectThrowEntity::display_boomerang_throw()
 {
     const auto is_blind = this->player_ptr->effects()->blindness()->is_blind();
-    if ((this->back_chance > 37) && !is_blind && (this->item >= 0)) {
+    if ((this->back_chance > 37) && !is_blind && (this->i_idx >= 0)) {
         msg_format(_("%sが手元に返ってきた。", "%s comes back to you."), this->o2_name.data());
         this->come_back = true;
         return;
     }
 
-    auto back_message = this->item >= 0 ? _("%sを受け損ねた!", "%s comes back, but you can't catch!") : _("%sが返ってきた。", "%s comes back.");
+    auto back_message = this->i_idx >= 0 ? _("%sを受け損ねた!", "%s comes back, but you can't catch!") : _("%sが返ってきた。", "%s comes back.");
     msg_format(back_message, this->o2_name.data());
     this->y = this->player_ptr->y;
     this->x = this->player_ptr->x;
index e6d527f..6cdc092 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 /*!
  * @file throw-util.h
  * @brief 投擲処理関連ヘッダ
@@ -10,7 +10,7 @@
 #include "util/flag-group.h"
 #include <string>
 
-struct grid_type;
+class Grid;
 class MonsterEntity;
 class ItemEntity;
 class PlayerType;
@@ -22,7 +22,7 @@ public:
     virtual ~ObjectThrowEntity() = default;
 
     ItemEntity *q_ptr;
-    OBJECT_IDX item{};
+    OBJECT_IDX i_idx{};
     POSITION y{};
     POSITION x{};
     POSITION prev_y{};
@@ -66,7 +66,7 @@ private:
     TrFlags obj_flags{};
     bool come_back = false;
     bool do_drop = true;
-    grid_type *g_ptr{};
+    Grid *g_ptr{};
     MonsterEntity *m_ptr{};
     std::string m_name{};
     int back_chance{};
index 8f8f552..362db34 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 杖を振る処理
  * @date 2021/09/25
  * @author Hourier
@@ -7,7 +7,6 @@
 #include "action/action-limited.h"
 #include "avatar/avatar.h"
 #include "cmd-item/cmd-usestaff.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "floor/floor-object.h"
 #include "game-option/disturbance-options.h"
@@ -24,6 +23,7 @@
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-confusion.h"
 #include "timed-effect/timed-effects.h"
 /*!
  * @brief コンストラクタ
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param item 使うオブジェクトの所持品ID
+ * @param i_idx 使うオブジェクトの所持品ID
  */
-ObjectUseEntity::ObjectUseEntity(PlayerType *player_ptr, INVENTORY_IDX item)
+ObjectUseEntity::ObjectUseEntity(PlayerType *player_ptr, INVENTORY_IDX i_idx)
     : player_ptr(player_ptr)
-    , item(item)
+    , i_idx(i_idx)
 {
 }
 
@@ -48,8 +48,8 @@ ObjectUseEntity::ObjectUseEntity(PlayerType *player_ptr, INVENTORY_IDX item)
 void ObjectUseEntity::execute()
 {
     auto use_charge = true;
-    auto *o_ptr = ref_item(this->player_ptr, this->item);
-    if ((this->item < 0) && (o_ptr->number > 1)) {
+    auto *o_ptr = ref_item(this->player_ptr, this->i_idx);
+    if ((this->i_idx < 0) && (o_ptr->number > 1)) {
         msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));
         return;
     }
@@ -91,54 +91,67 @@ void ObjectUseEntity::execute()
 
         msg_print(_("この杖にはもう魔力が残っていない。", "The staff has no charges left."));
         o_ptr->ident |= IDENT_EMPTY;
-        this->player_ptr->update |= PU_COMBINATION | PU_REORDER;
-        this->player_ptr->window_flags |= PW_INVENTORY;
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        static constexpr auto flags = {
+            StatusRecalculatingFlag::COMBINATION,
+            StatusRecalculatingFlag::REORDER,
+        };
+        rfu.set_flags(flags);
+        rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
         return;
     }
 
     sound(SOUND_ZAP);
-    auto ident = staff_effect(this->player_ptr, o_ptr->bi_key.sval().value(), &use_charge, false, false, o_ptr->is_aware());
+    auto ident = staff_effect(this->player_ptr, *o_ptr->bi_key.sval(), &use_charge, false, false, o_ptr->is_aware());
     if (!(o_ptr->is_aware())) {
         chg_virtue(this->player_ptr, Virtue::PATIENCE, -1);
         chg_virtue(this->player_ptr, Virtue::CHANCE, 1);
         chg_virtue(this->player_ptr, Virtue::KNOWLEDGE, -1);
     }
 
-    /*
-     * Temporarily remove the flags for updating the inventory so
-     * gain_exp() does not reorder the inventory before the charge
-     * is deducted from the staff.
-     */
-    BIT_FLAGS inventory_flags = PU_COMBINATION | PU_REORDER | (this->player_ptr->update & PU_AUTO_DESTRUCTION);
-    reset_bits(this->player_ptr->update, PU_COMBINATION | PU_REORDER | PU_AUTO_DESTRUCTION);
-    object_tried(o_ptr);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    using Srf = StatusRecalculatingFlag;
+    EnumClassFlagGroup<Srf> flags_srf = { Srf::COMBINATION, Srf::REORDER };
+    if (rfu.has(Srf::AUTO_DESTRUCTION)) {
+        flags_srf.set(Srf::AUTO_DESTRUCTION);
+    }
+
+    rfu.reset_flags(flags_srf);
+    o_ptr->mark_as_tried();
     if (ident && !o_ptr->is_aware()) {
         object_aware(this->player_ptr, o_ptr);
         gain_exp(this->player_ptr, (lev + (this->player_ptr->lev >> 1)) / this->player_ptr->lev);
     }
 
-    set_bits(this->player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
-    set_bits(this->player_ptr->update, inventory_flags);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
+    rfu.set_flags(flags_srf);
     if (!use_charge) {
         return;
     }
 
     o_ptr->pval--;
-    if ((this->item >= 0) && (o_ptr->number > 1)) {
+    if ((this->i_idx >= 0) && (o_ptr->number > 1)) {
         ItemEntity forge;
         auto *q_ptr = &forge;
         q_ptr->copy_from(o_ptr);
         q_ptr->number = 1;
         o_ptr->pval++;
         o_ptr->number--;
-        this->item = store_item_to_inventory(this->player_ptr, q_ptr);
+        this->i_idx = store_item_to_inventory(this->player_ptr, q_ptr);
         msg_print(_("杖をまとめなおした。", "You unstack your staff."));
     }
 
-    if (this->item >= 0) {
-        inven_item_charges(this->player_ptr->inventory_list[this->item]);
+    if (this->i_idx >= 0) {
+        inven_item_charges(this->player_ptr->inventory_list[this->i_idx]);
     } else {
-        floor_item_charges(this->player_ptr->current_floor_ptr, 0 - this->item);
+        floor_item_charges(this->player_ptr->current_floor_ptr, 0 - this->i_idx);
     }
 }
 
index 4258361..d1dcda0 100644 (file)
@@ -1,18 +1,18 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 class PlayerType;
 class ObjectUseEntity {
 public:
-    ObjectUseEntity(PlayerType *player_ptr, INVENTORY_IDX item);
+    ObjectUseEntity(PlayerType *player_ptr, INVENTORY_IDX i_idx);
     virtual ~ObjectUseEntity() = default;
 
     void execute();
 
 private:
     PlayerType *player_ptr;
-    INVENTORY_IDX item;
+    INVENTORY_IDX i_idx;
 
     bool check_can_use();
 };
index 862ca27..88d1d81 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ロッドを振る処理
  * @date 2021/09/25
  * @author Hourier
@@ -7,7 +7,6 @@
 #include "action/action-limited.h"
 #include "avatar/avatar.h"
 #include "cmd-item/cmd-zaprod.h" // 相互依存。暫定的措置、後で何とかする.
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "game-option/disturbance-options.h"
 #include "main/sound-definitions-table.h"
@@ -23,6 +22,7 @@
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-getter.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-confusion.h"
@@ -43,12 +43,12 @@ ObjectZapRodEntity::ObjectZapRodEntity(PlayerType *player_ptr)
 /*!
  * @brief ロッドを使う
  */
-void ObjectZapRodEntity::execute(INVENTORY_IDX item)
+void ObjectZapRodEntity::execute(INVENTORY_IDX i_idx)
 {
     DIRECTION dir = 0;
     auto use_charge = true;
-    auto *o_ptr = ref_item(this->player_ptr, item);
-    if ((item < 0) && (o_ptr->number > 1)) {
+    auto *o_ptr = ref_item(this->player_ptr, i_idx);
+    if ((i_idx < 0) && (o_ptr->number > 1)) {
         msg_print(_("まずはロッドを拾わなければ。", "You must first pick up the rods."));
         return;
     }
@@ -122,25 +122,37 @@ void ObjectZapRodEntity::execute(INVENTORY_IDX item)
     }
 
     sound(SOUND_ZAP);
-    auto ident = rod_effect(this->player_ptr, o_ptr->bi_key.sval().value(), dir, &use_charge, false);
+    auto ident = rod_effect(this->player_ptr, *o_ptr->bi_key.sval(), dir, &use_charge, false);
     if (use_charge) {
         o_ptr->timeout += baseitem.pval;
     }
 
-    this->player_ptr->update |= PU_COMBINATION | PU_REORDER;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
     if (!(o_ptr->is_aware())) {
         chg_virtue(this->player_ptr, Virtue::PATIENCE, -1);
         chg_virtue(this->player_ptr, Virtue::CHANCE, 1);
         chg_virtue(this->player_ptr, Virtue::KNOWLEDGE, -1);
     }
 
-    object_tried(o_ptr);
+    o_ptr->mark_as_tried();
     if ((ident != 0) && !o_ptr->is_aware()) {
         object_aware(this->player_ptr, o_ptr);
         gain_exp(this->player_ptr, (lev + (this->player_ptr->lev >> 1)) / this->player_ptr->lev);
     }
 
-    set_bits(this->player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 bool ObjectZapRodEntity::check_can_zap()
index d674da5..5623b99 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -8,7 +8,7 @@ public:
     ObjectZapRodEntity(PlayerType *player_ptr);
     virtual ~ObjectZapRodEntity() = default;
 
-    void execute(INVENTORY_IDX item);
+    void execute(INVENTORY_IDX i_idx);
 
 private:
     PlayerType *player_ptr;
index f2ae33f..3bf89a7 100644 (file)
@@ -1,8 +1,7 @@
-#include "object-use/zapwand-execution.h"
+#include "object-use/zapwand-execution.h"
 #include "action/action-limited.h"
 #include "avatar/avatar.h"
 #include "cmd-item/cmd-zapwand.h" // 相互依存。暫定的措置、後で何とかする.
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "floor/floor-object.h"
 #include "game-option/disturbance-options.h"
@@ -20,6 +19,7 @@
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-getter.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-confusion.h"
@@ -35,13 +35,13 @@ ObjectZapWandEntity::ObjectZapWandEntity(PlayerType *player_ptr)
 
 /*!
  * @brief 魔法棒を使うコマンドのサブルーチン /
- * @param item 使うオブジェクトの所持品ID
+ * @param i_idx 使うオブジェクトの所持品ID
  */
-void ObjectZapWandEntity::execute(INVENTORY_IDX item)
+void ObjectZapWandEntity::execute(INVENTORY_IDX i_idx)
 {
     auto old_target_pet = target_pet;
-    auto *o_ptr = ref_item(this->player_ptr, item);
-    if ((item < 0) && (o_ptr->number > 1)) {
+    auto *o_ptr = ref_item(this->player_ptr, i_idx);
+    if ((i_idx < 0) && (o_ptr->number > 1)) {
         msg_print(_("まずは魔法棒を拾わなければ。", "You must first pick up the wands."));
         return;
     }
@@ -88,6 +88,7 @@ void ObjectZapWandEntity::execute(INVENTORY_IDX item)
         return;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (o_ptr->pval <= 0) {
         if (flush_failure) {
             flush();
@@ -95,42 +96,52 @@ void ObjectZapWandEntity::execute(INVENTORY_IDX item)
 
         msg_print(_("この魔法棒にはもう魔力が残っていない。", "The wand has no charges left."));
         o_ptr->ident |= IDENT_EMPTY;
-        this->player_ptr->update |= PU_COMBINATION | PU_REORDER;
-        this->player_ptr->window_flags |= PW_INVENTORY;
+        static constexpr auto flags = {
+            StatusRecalculatingFlag::COMBINATION,
+            StatusRecalculatingFlag::REORDER,
+        };
+        rfu.set_flags(flags);
+        rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
         return;
     }
 
     sound(SOUND_ZAP);
-    auto ident = wand_effect(this->player_ptr, sval.value(), dir, false, false);
-
-    /*
-     * Temporarily remove the flags for updating the inventory so
-     * gain_exp() does not reorder the inventory before the charge
-     * is deducted from the wand.
-     */
-    BIT_FLAGS inventory_flags = (PU_COMBINATION | PU_REORDER | (this->player_ptr->update & PU_AUTO_DESTRUCTION));
-    reset_bits(this->player_ptr->update, PU_COMBINATION | PU_REORDER | PU_AUTO_DESTRUCTION);
-    if (!(o_ptr->is_aware())) {
+    auto ident = wand_effect(this->player_ptr, *sval, dir, false, false);
+    using Srf = StatusRecalculatingFlag;
+    EnumClassFlagGroup<Srf> flags_srf = { Srf::COMBINATION, Srf::REORDER };
+    if (rfu.has(Srf::AUTO_DESTRUCTION)) {
+        flags_srf.set(Srf::AUTO_DESTRUCTION);
+    }
+
+    rfu.reset_flags(flags_srf);
+    if (!o_ptr->is_aware()) {
         chg_virtue(this->player_ptr, Virtue::PATIENCE, -1);
         chg_virtue(this->player_ptr, Virtue::CHANCE, 1);
         chg_virtue(this->player_ptr, Virtue::KNOWLEDGE, -1);
     }
 
-    object_tried(o_ptr);
+    o_ptr->mark_as_tried();
     if (ident && !o_ptr->is_aware()) {
         object_aware(this->player_ptr, o_ptr);
         gain_exp(this->player_ptr, (lev + (this->player_ptr->lev >> 1)) / this->player_ptr->lev);
     }
 
-    set_bits(this->player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
-    set_bits(this->player_ptr->update, inventory_flags);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
+    rfu.set_flags(flags_srf);
     o_ptr->pval--;
-    if (item >= 0) {
-        inven_item_charges(this->player_ptr->inventory_list[item]);
+    if (i_idx >= 0) {
+        inven_item_charges(this->player_ptr->inventory_list[i_idx]);
         return;
     }
 
-    floor_item_charges(this->player_ptr->current_floor_ptr, 0 - item);
+    floor_item_charges(this->player_ptr->current_floor_ptr, 0 - i_idx);
 }
 
 bool ObjectZapWandEntity::check_can_zap() const
index 74299e7..6ee62eb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -8,7 +8,7 @@ public:
     ObjectZapWandEntity(PlayerType *player_ptr);
     virtual ~ObjectZapWandEntity() = default;
 
-    void execute(INVENTORY_IDX item);
+    void execute(INVENTORY_IDX i_idx);
 
 private:
     PlayerType *player_ptr;
index b4f97df..4ed10d9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief オブジェクトに関する汎用判定処理
  * @date 2018/09/24
  * @author deskull
index c9a8e83..fcd6f17 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 
@@ -14,7 +14,12 @@ class PlayerType;
  */
 class ItemTester {
 public:
+    ItemTester(const ItemTester &) = default;
+    ItemTester(ItemTester &&) = default;
+    ItemTester &operator=(const ItemTester &) = default;
+    ItemTester &operator=(ItemTester &&) = default;
     virtual ~ItemTester() = default;
+
     bool okay(const ItemEntity *o_ptr) const;
     virtual std::unique_ptr<ItemTester> clone() const = 0;
 
@@ -81,5 +86,5 @@ private:
     virtual bool okay_impl(const ItemEntity *o_ptr) const;
 
     std::function<bool(PlayerType *, const ItemEntity *)> test_func;
-    PlayerType *player_ptr;
+    PlayerType *player_ptr = nullptr;
 };
index 75b7e63..1425033 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * get_item()関数でアイテムの選択を行うフラグ / Bit flags for the "get_item" function
index 9a03bb9..2e94dbc 100644 (file)
@@ -1,6 +1,5 @@
-#include "object/lite-processor.h"
+#include "object/lite-processor.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "game-option/disturbance-options.h"
 #include "inventory/inventory-slot-types.h"
@@ -9,6 +8,7 @@
 #include "sv-definition/sv-lite-types.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
@@ -47,8 +47,9 @@ void reduce_lite_life(PlayerType *player_ptr)
  */
 void notice_lite_change(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if ((o_ptr->fuel < 100) || (!(o_ptr->fuel % 100))) {
-        player_ptr->window_flags |= (PW_EQUIPMENT);
+        rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
     }
 
     if (player_ptr->effects()->blindness()->is_blind()) {
@@ -58,8 +59,11 @@ void notice_lite_change(PlayerType *player_ptr, ItemEntity *o_ptr)
     } else if (o_ptr->fuel == 0) {
         disturb(player_ptr, false, true);
         msg_print(_("明かりが消えてしまった!", "Your light has gone out!"));
-        player_ptr->update |= (PU_TORCH);
-        player_ptr->update |= (PU_BONUS);
+        static constexpr auto flags = {
+            StatusRecalculatingFlag::TORCH,
+            StatusRecalculatingFlag::BONUS,
+        };
+        rfu.set_flags(flags);
     } else if (o_ptr->ego_idx == EgoType::LITE_LONG) {
         if ((o_ptr->fuel < 50) && (!(o_ptr->fuel % 5)) && (w_ptr->game_turn % (TURNS_PER_TICK * 2))) {
             if (disturb_minor) {
index da790e2..00be05c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index 18dafb4..7a27087 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief アイテム破壊処理
  * @date 2019/03/06
  * @author deskull
@@ -9,7 +9,6 @@
 #include "effect/effect-processor.h"
 #include "mind/snipe-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "sv-definition/sv-potion-types.h"
 #include "system/baseitem-info.h"
@@ -172,8 +171,7 @@ bool ObjectBreaker::can_destroy(ItemEntity *o_ptr) const
         return false;
     }
 
-    auto flags = object_flags(o_ptr);
-    return flags.has_not(this->ignore_flg);
+    return o_ptr->get_flags().has_not(this->ignore_flg);
 }
 
 /*!
@@ -210,7 +208,7 @@ bool potion_smash_effect(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, PO
     int dam = 0;
     bool angry = false;
     const auto &baseitem = baseitems_info[bi_id];
-    switch (baseitem.bi_key.sval().value()) {
+    switch (*baseitem.bi_key.sval()) {
     case SV_POTION_SALT_WATER:
     case SV_POTION_SLIME_MOLD:
     case SV_POTION_LOSE_MEMORIES:
index 543e38f..3e5a7d0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/tr-types.h"
 #include "system/angband.h"
diff --git a/src/object/object-flags.cpp b/src/object/object-flags.cpp
deleted file mode 100644 (file)
index 142cc0c..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-#include "object/object-flags.h"
-#include "mind/mind-weaponsmith.h"
-#include "object-enchant/object-ego.h"
-#include "object-enchant/tr-types.h"
-#include "object/tval-types.h"
-#include "perception/object-perception.h"
-#include "smith/object-smith.h"
-#include "system/artifact-type-definition.h"
-#include "system/baseitem-info.h"
-#include "system/item-entity.h"
-#include "system/player-type-definition.h"
-#include "util/bit-flags-calculator.h"
-
-/*!
- * @brief エゴ光源のフラグを修正する
- *
- * 寿命のある光源で寿命が0ターンの時、光源エゴアイテムに起因するフラグは
- * 灼熱エゴの火炎耐性を除き付与されないようにする。
- *
- * @param o_ptr フラグ取得元のオブジェクト構造体ポインタ
- * @param flags フラグ情報を受け取る配列
- */
-static void modify_ego_lite_flags(const ItemEntity *o_ptr, TrFlags &flags)
-{
-    if (o_ptr->bi_key.tval() != ItemKindType::LITE) {
-        return;
-    }
-
-    if (!o_ptr->is_lite_requiring_fuel() || o_ptr->fuel != 0) {
-        return;
-    }
-
-    switch (o_ptr->ego_idx) {
-    case EgoType::LITE_AURA_FIRE:
-        flags.reset(TR_SH_FIRE);
-        return;
-    case EgoType::LITE_INFRA:
-        flags.reset(TR_INFRA);
-        return;
-    case EgoType::LITE_EYE:
-        flags.reset({ TR_RES_BLIND, TR_SEE_INVIS });
-        return;
-    default:
-        return;
-    }
-}
-
-/*!
- * @brief オブジェクトのフラグ類を配列に与える
- * @param o_ptr フラグ取得元のオブジェクト構造体ポインタ
- * @param flags フラグ情報を受け取る配列
- */
-TrFlags object_flags(const ItemEntity *o_ptr)
-{
-    const auto &baseitem = o_ptr->get_baseitem();
-    auto flags = baseitem.flags;
-
-    if (o_ptr->is_fixed_artifact()) {
-        flags = o_ptr->get_fixed_artifact().flags;
-    }
-
-    if (o_ptr->is_ego()) {
-        const auto &ego = o_ptr->get_ego();
-        flags.set(ego.flags);
-        modify_ego_lite_flags(o_ptr, flags);
-    }
-
-    flags.set(o_ptr->art_flags);
-    if (auto effect = Smith::object_effect(o_ptr); effect.has_value()) {
-        auto tr_flags = Smith::get_effect_tr_flags(effect.value());
-        flags.set(tr_flags);
-    }
-
-    if (Smith::object_activation(o_ptr).has_value()) {
-        flags.set(TR_ACTIVATE);
-    }
-
-    return flags;
-}
-
-/*!
- * @brief オブジェクトの明示されているフラグ類を取得する
- * Obtain the "flags" for an item which are known to the player
- * @param o_ptr フラグ取得元のオブジェクト構造体ポインタ
- * @param flags フラグ情報を受け取る配列
- */
-TrFlags object_flags_known(const ItemEntity *o_ptr)
-{
-    TrFlags flags{};
-    if (!o_ptr->is_aware()) {
-        return flags;
-    }
-
-    const auto &baseitem = o_ptr->get_baseitem();
-    flags = baseitem.flags;
-    if (!o_ptr->is_known()) {
-        return flags;
-    }
-
-    if (o_ptr->is_ego()) {
-        const auto &ego = o_ptr->get_ego();
-        flags.set(ego.flags);
-        modify_ego_lite_flags(o_ptr, flags);
-    }
-
-    if (o_ptr->is_fully_known()) {
-        if (o_ptr->is_fixed_artifact()) {
-            flags = o_ptr->get_fixed_artifact().flags;
-        }
-
-        flags.set(o_ptr->art_flags);
-    }
-
-    if (auto effect = Smith::object_effect(o_ptr); effect.has_value()) {
-        auto tr_flags = Smith::get_effect_tr_flags(effect.value());
-        flags.set(tr_flags);
-    }
-
-    if (Smith::object_activation(o_ptr).has_value()) {
-        flags.set(TR_ACTIVATE);
-    }
-
-    return flags;
-}
diff --git a/src/object/object-flags.h b/src/object/object-flags.h
deleted file mode 100644 (file)
index 228959a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-#include "system/angband.h"
-#include "system/system-variables.h"
-
-#include "object-enchant/tr-flags.h"
-
-class ItemEntity;
-TrFlags object_flags(const ItemEntity *o_ptr);
-TrFlags object_flags_known(const ItemEntity *o_ptr);
index a4c5b50..5170eae 100644 (file)
@@ -1,4 +1,4 @@
-#include "object/object-index-list.h"
+#include "object/object-index-list.h"
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 
index c665929..43c9b4b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 1f72128..541d0f7 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief オブジェクトの実装 / Object code, part 1
  * @date 2014/01/10
  * @author
  */
 
 #include "object/object-info.h"
-#include "artifact/artifact-info.h"
-#include "artifact/fixed-art-types.h"
-#include "artifact/random-art-effects.h"
 #include "inventory/inventory-slot-types.h"
-#include "monster-race/monster-race.h"
-#include "object-enchant/activation-info-table.h"
-#include "object-enchant/dragon-breaths-table.h"
-#include "object-enchant/object-ego.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player/player-realm.h"
 #include "realm/realm-names-table.h"
-#include "sv-definition/sv-other-types.h"
-#include "sv-definition/sv-ring-types.h"
-#include "system/baseitem-info.h"
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
-#include "system/monster-race-info.h"
-#include "system/player-type-definition.h"
-#include "term/term-color-types.h"
-#include "util/bit-flags-calculator.h"
 #include "util/int-char-converter.h"
-#include <sstream>
-
-/*!
- * @brief オブジェクトの発動効果名称を返す(サブルーチン/ブレス)
- * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
- * @return std::string 発動名称を返す文字列ポインタ
- */
-static std::string item_activation_dragon_breath(ItemEntity *o_ptr)
-{
-    std::string desc = _("", "breathe ");
-    int n = 0;
-
-    auto flags = object_flags(o_ptr);
-
-    for (int i = 0; dragonbreath_info[i].flag != 0; i++) {
-        if (flags.has(dragonbreath_info[i].flag)) {
-            if (n > 0) {
-                desc.append(_("、", ", "));
-            }
-
-            desc.append(dragonbreath_info[i].name);
-            n++;
-        }
-    }
-
-    desc.append(_("のブレス(250)", " (250)"));
-    return desc;
-}
-
-/*!
- * @brief オブジェクトの発動効果名称を返す(サブルーチン/汎用)
- * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
- * @return concptr 発動名称を返す文字列ポインタ
- */
-static concptr item_activation_aux(ItemEntity *o_ptr)
-{
-    static std::string activation_detail;
-    auto tmp_act_ptr = find_activation_info(o_ptr);
-    if (!tmp_act_ptr.has_value()) {
-        return _("未定義", "something undefined");
-    }
-
-    auto *act_ptr = tmp_act_ptr.value();
-    concptr desc = act_ptr->desc;
-    std::string dragon_breath;
-    switch (act_ptr->index) {
-    case RandomArtActType::NONE:
-        break;
-    case RandomArtActType::BR_FIRE:
-        if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES)) {
-            desc = _("火炎のブレス (200) と火への耐性", "breathe fire (200) and resist fire");
-        }
-        break;
-    case RandomArtActType::BR_COLD:
-        if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE)) {
-            desc = _("冷気のブレス (200) と冷気への耐性", "breathe cold (200) and resist cold");
-        }
-        break;
-    case RandomArtActType::BR_DRAGON:
-        dragon_breath = item_activation_dragon_breath(o_ptr);
-        desc = dragon_breath.data();
-        break;
-    case RandomArtActType::AGGRAVATE:
-        if (o_ptr->is_specific_artifact(FixedArtifactId::HYOUSIGI)) {
-            desc = _("拍子木を打ちならす", "beat wooden clappers");
-        }
-        break;
-    case RandomArtActType::ACID_BALL_AND_RESISTANCE:
-        desc = _("アシッド・ボール (100) と酸への耐性", "ball of acid (100) and resist acid");
-        break;
-    case RandomArtActType::FIRE_BALL_AND_RESISTANCE:
-        desc = _("ファイア・ボール (100) と火への耐性", "ball of fire (100) and resist fire");
-        break;
-    case RandomArtActType::COLD_BALL_AND_RESISTANCE:
-        desc = _("アイス・ボール (100) と冷気への耐性", "ball of cold (100) and resist cold");
-        break;
-    case RandomArtActType::ELEC_BALL_AND_RESISTANCE:
-        desc = _("サンダー・ボール (100) と電撃への耐性", "ball of elec (100) and resist elec");
-        break;
-    case RandomArtActType::POIS_BALL_AND_RESISTANCE:
-        desc = _("ポイズン・ボール (100) と毒への耐性", "ball of poison (100) and resist elec");
-        break;
-    case RandomArtActType::RESIST_ACID:
-        desc = _("一時的な酸への耐性", "temporary resist acid");
-        break;
-    case RandomArtActType::RESIST_FIRE:
-        desc = _("一時的な火への耐性", "temporary resist fire");
-        break;
-    case RandomArtActType::RESIST_COLD:
-        desc = _("一時的な冷気への耐性", "temporary resist cold");
-        break;
-    case RandomArtActType::RESIST_ELEC:
-        desc = _("一時的な電撃への耐性", "temporary resist elec");
-        break;
-    case RandomArtActType::RESIST_POIS:
-        desc = _("一時的な毒への耐性", "temporary resist elec");
-        break;
-    default:
-        break;
-    }
-
-    /* Timeout description */
-    std::stringstream timeout;
-    int constant = act_ptr->timeout.constant;
-    int dice = act_ptr->timeout.dice;
-    if (constant == 0 && dice == 0) {
-        /* We can activate it every turn */
-        timeout << _("いつでも", "every turn");
-    } else if (constant < 0) {
-        /* Activations that have special timeout */
-        switch (act_ptr->index) {
-        case RandomArtActType::BR_FIRE:
-            timeout << _("", "every ") << (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES) ? 200 : 250) << _(" ターン毎", " turns");
-            break;
-        case RandomArtActType::BR_COLD:
-            timeout << _("", "every ") << (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE) ? 200 : 250) << _(" ターン毎", " turns");
-            break;
-        case RandomArtActType::TERROR:
-            timeout << _("3*(レベル+10) ターン毎", "every 3 * (level+10) turns");
-            break;
-        case RandomArtActType::MURAMASA:
-            timeout << _("確率50%で壊れる", "(destroyed 50%)");
-            break;
-        default:
-            timeout << "undefined";
-            break;
-        }
-    } else {
-        timeout << _("", "every ");
-        if (constant > 0) {
-            timeout << constant;
-            if (dice > 0) {
-                timeout << '+';
-            }
-        }
-        if (dice > 0) {
-            timeout << 'd' << dice;
-        }
-        timeout << _(" ターン毎", " turns");
-    }
-
-    activation_detail = desc;
-    activation_detail.append(_(" : ", " ")).append(timeout.str());
-    return activation_detail.data();
-}
-
-/*!
- * @brief オブジェクトの発動効果名称を返す(メインルーチン) /
- * Determine the "Activation" (if any) for an artifact Return a string, or nullptr for "no activation"
- * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
- * @return concptr 発動名称を返す文字列ポインタ
- */
-concptr activation_explanation(ItemEntity *o_ptr)
-{
-    auto flags = object_flags(o_ptr);
-    if (flags.has_not(TR_ACTIVATE)) {
-        return _("なし", "nothing");
-    }
-
-    if (activation_index(o_ptr) > RandomArtActType::NONE) {
-        return item_activation_aux(o_ptr);
-    }
-
-    const auto tval = o_ptr->bi_key.tval();
-    if (tval == ItemKindType::WHISTLE) {
-        return _("ペット呼び寄せ : 100+d100ターン毎", "call pet every 100+d100 turns");
-    }
-
-    if (tval == ItemKindType::CAPTURE) {
-        return _("モンスターを捕える、又は解放する。", "captures or releases a monster.");
-    }
-
-    return _("何も起きない", "Nothing");
-}
 
 /*!
  * @brief オブジェクト選択時の選択アルファベットラベルを返す /
@@ -310,8 +121,8 @@ bool check_book_realm(PlayerType *player_ptr, const BaseitemKey &bi_key)
     return (get_realm1_book(player_ptr) == tval) || (get_realm2_book(player_ptr) == tval);
 }
 
-ItemEntity *ref_item(PlayerType *player_ptr, INVENTORY_IDX item)
+ItemEntity *ref_item(PlayerType *player_ptr, INVENTORY_IDX i_idx)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    return item >= 0 ? &player_ptr->inventory_list[item] : &(floor_ptr->o_list[0 - item]);
+    return i_idx >= 0 ? &player_ptr->inventory_list[i_idx] : &(floor_ptr->o_list[0 - i_idx]);
 }
index ea67889..58c257d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 #include "system/angband.h"
@@ -8,8 +8,7 @@
 class BaseitemKey;
 class ItemEntity;
 class PlayerType;
-concptr activation_explanation(ItemEntity *o_ptr);
 char index_to_label(int i);
 int16_t wield_slot(PlayerType *player_ptr, const ItemEntity *o_ptr);
 bool check_book_realm(PlayerType *player_ptr, const BaseitemKey &bi_key);
-ItemEntity *ref_item(PlayerType *player_ptr, INVENTORY_IDX item);
+ItemEntity *ref_item(PlayerType *player_ptr, INVENTORY_IDX i_idx);
index 302ae71..e089946 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief アイテムが特定種別のものであるかどうかの判定関数群
  * @date 2018/12/15
  * @author deskull
@@ -197,7 +197,7 @@ static const std::map<ItemKindType, std::vector<int>> &create_baseitems_cache()
             continue;
         }
 
-        cache[tval].push_back(bi_key.sval().value());
+        cache[tval].push_back(*bi_key.sval());
     }
 
     return cache;
@@ -250,7 +250,7 @@ static short exe_lookup(const BaseitemKey &key)
 short lookup_baseitem_id(const BaseitemKey &key)
 {
     const auto sval = key.sval();
-    if (sval.has_value()) {
+    if (sval) {
         return exe_lookup(key);
     }
 
@@ -261,6 +261,5 @@ short lookup_baseitem_id(const BaseitemKey &key)
     }
 
     const auto &svals = itr->second;
-    const auto sval_indice = randint0(svals.size());
-    return exe_lookup({ key.tval(), svals.at(sval_indice) });
+    return exe_lookup({ key.tval(), rand_choice(svals) });
 }
index 0c15a99..13c4bff 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 bool kind_is_cloak(short bi_id);
 bool kind_is_polearm(short bi_id);
index 4b7fefc..6497214 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief How an entity of an item is marked (flags in ItemEntity::marked)
  * @date 2020/05/28
  * @author Hourier
index 6966251..72cc8de 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 同種のアイテムをインベントリや床に重ね合わせたり、その判断を行う処理
  * @date 2020/06/03
  * @author Hourier
@@ -11,7 +11,6 @@
 #include "object-enchant/trc-types.h"
 #include "object/object-value.h"
 #include "object/tval-types.h"
-#include "perception/object-perception.h"
 #include "smith/object-smith.h"
 #include "sv-definition/sv-other-types.h"
 #include "system/baseitem-info.h"
@@ -262,7 +261,7 @@ void object_absorb(ItemEntity *o_ptr, ItemEntity *j_ptr)
 
     o_ptr->number = (total > max_num) ? max_num : total;
     if (j_ptr->is_known()) {
-        object_known(o_ptr);
+        o_ptr->mark_as_known();
     }
 
     if (((o_ptr->ident & IDENT_STORE) || (j_ptr->ident & IDENT_STORE)) && (!((o_ptr->ident & IDENT_STORE) && (j_ptr->ident & IDENT_STORE)))) {
index 34a0e50..5293314 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 void distribute_charges(ItemEntity *o_ptr, ItemEntity *q_ptr, int amt);
index 72fb96c..2ebf454 100644 (file)
@@ -1,10 +1,8 @@
-#include "object/object-value-calc.h"
-#include "artifact/artifact-info.h"
+#include "object/object-value-calc.h"
 #include "object-enchant/activation-info-table.h"
 #include "object-enchant/object-ego.h"
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
-#include "object/object-flags.h"
 #include "system/artifact-type-definition.h"
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
@@ -21,7 +19,7 @@
 PRICE flag_cost(const ItemEntity *o_ptr, int plusses)
 {
     PRICE total = 0;
-    auto flags = object_flags(o_ptr);
+    auto flags = o_ptr->get_flags();
     const auto &baseitem = o_ptr->get_baseitem();
     flags.reset(baseitem.flags);
 
@@ -529,9 +527,9 @@ PRICE flag_cost(const ItemEntity *o_ptr, int plusses)
 
     /* Also, give some extra for activatable powers... */
     if (o_ptr->is_random_artifact() && o_ptr->art_flags.has(TR_ACTIVATE)) {
-        auto act_ptr = find_activation_info(o_ptr);
-        if (act_ptr.has_value()) {
-            total += act_ptr.value()->value;
+        const auto act_ptr = o_ptr->find_activation_info();
+        if (act_ptr != activation_info.end()) {
+            total += act_ptr->value;
         }
     }
 
index 2847fbe..df23dd7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b4334f8..7faa7ec 100644 (file)
@@ -1,6 +1,5 @@
-#include "object/object-value.h"
+#include "object/object-value.h"
 #include "monster-race/monster-race.h"
-#include "object/object-flags.h"
 #include "object/object-value-calc.h"
 #include "object/tval-types.h"
 #include "system/artifact-type-definition.h"
@@ -44,7 +43,7 @@ PRICE object_value_real(const ItemEntity *o_ptr)
     }
 
     PRICE value = baseitem.cost;
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
     if (o_ptr->is_fixed_artifact()) {
         const auto &artifact = o_ptr->get_fixed_artifact();
         if (!artifact.cost) {
index 05ece9d..df632a4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 148e9e2..98be388 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * The values for the "tval" field of various objects.
  *
  * This value is the primary means by which items are sorted in the
index 968ef75..78dba08 100644 (file)
@@ -1,4 +1,4 @@
-#include "object/warning.h"
+#include "object/warning.h"
 #include "artifact/fixed-art-types.h"
 #include "core/asking-player.h"
 #include "core/disturbance.h"
@@ -21,7 +21,6 @@
 #include "mspell/mspell-damage-calculator.h"
 #include "mutation/mutation-flag-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-race.h"
 #include "player/player-status-flags.h"
 #include "player/player-status-resist.h"
@@ -39,6 +38,7 @@
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
+#include <vector>
 
 /*!
  * @brief 警告を放つアイテムを選択する /
  */
 ItemEntity *choose_warning_item(PlayerType *player_ptr)
 {
-    int choices[INVEN_TOTAL - INVEN_MAIN_HAND];
-
     /* Paranoia -- Player has no warning ability */
     if (!player_ptr->warning) {
         return nullptr;
     }
 
     /* Search Inventory */
-    int number = 0;
+    std::vector<int> candidates;
     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
-        auto *o_ptr = &player_ptr->inventory_list[i];
-
-        auto flags = object_flags(o_ptr);
-        if (flags.has(TR_WARNING)) {
-            choices[number] = i;
-            number++;
+        const auto *o_ptr = &player_ptr->inventory_list[i];
+        if (o_ptr->get_flags().has(TR_WARNING)) {
+            candidates.push_back(i);
         }
     }
 
     /* Choice one of them */
-    return number ? &player_ptr->inventory_list[choices[randint0(number)]] : nullptr;
+    return candidates.empty() ? nullptr : &player_ptr->inventory_list[rand_choice(candidates)];
 }
 
 /*!
@@ -81,7 +76,7 @@ ItemEntity *choose_warning_item(PlayerType *player_ptr)
  */
 static void spell_damcalc(PlayerType *player_ptr, MonsterEntity *m_ptr, AttributeType typ, int dam, int *max)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     int rlev = r_ptr->level;
     bool ignore_wraith_form = false;
 
@@ -275,24 +270,24 @@ static void spell_damcalc_by_spellnum(PlayerType *player_ptr, MonsterAbilityType
  * @brief 警告基準を定めるためにモンスターの打撃最大ダメージを算出する /
  * Calculate blow damages
  * @param m_ptr 打撃を行使するモンスターの構造体参照ポインタ
- * @param blow_ptr モンスターの打撃能力の構造体参照ポインタ
+ * @param blow モンスターの打撃能力の構造体参照
  * @return 算出された最大ダメージを返す。
  */
-static int blow_damcalc(MonsterEntity *m_ptr, PlayerType *player_ptr, MonsterBlow *blow_ptr)
+static int blow_damcalc(MonsterEntity *m_ptr, PlayerType *player_ptr, const MonsterBlow &blow)
 {
-    int dam = blow_ptr->d_dice * blow_ptr->d_side;
+    int dam = blow.d_dice * blow.d_side;
     int dummy_max = 0;
 
-    if (blow_ptr->method == RaceBlowMethodType::EXPLODE) {
+    if (blow.method == RaceBlowMethodType::EXPLODE) {
         dam = (dam + 1) / 2;
-        spell_damcalc(player_ptr, m_ptr, mbe_info[enum2i(blow_ptr->effect)].explode_type, dam, &dummy_max);
+        spell_damcalc(player_ptr, m_ptr, mbe_info[enum2i(blow.effect)].explode_type, dam, &dummy_max);
         dam = dummy_max;
         return dam;
     }
 
     ARMOUR_CLASS ac = player_ptr->ac + player_ptr->to_a;
     bool check_wraith_form = true;
-    switch (blow_ptr->effect) {
+    switch (blow.effect) {
     case RaceBlowEffectType::SUPERHURT: {
         int tmp_dam = dam - (dam * ((ac < 150) ? ac : 150) / 250);
         dam = std::max(dam, tmp_dam * 2);
@@ -357,29 +352,26 @@ static int blow_damcalc(MonsterEntity *m_ptr, PlayerType *player_ptr, MonsterBlo
 bool process_warning(PlayerType *player_ptr, POSITION xx, POSITION yy)
 {
     POSITION mx, my;
-    grid_type *g_ptr;
-
 #define WARNING_AWARE_RANGE 12
     int dam_max = 0;
     static int old_damage = 0;
 
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &dungeon = floor.get_dungeon_definition();
     for (mx = xx - WARNING_AWARE_RANGE; mx < xx + WARNING_AWARE_RANGE + 1; mx++) {
         for (my = yy - WARNING_AWARE_RANGE; my < yy + WARNING_AWARE_RANGE + 1; my++) {
             int dam_max0 = 0;
-            MonsterEntity *m_ptr;
-            MonsterRaceInfo *r_ptr;
-
-            if (!in_bounds(player_ptr->current_floor_ptr, my, mx) || (distance(my, mx, yy, xx) > WARNING_AWARE_RANGE)) {
+            if (!in_bounds(&floor, my, mx) || (distance(my, mx, yy, xx) > WARNING_AWARE_RANGE)) {
                 continue;
             }
 
-            g_ptr = &player_ptr->current_floor_ptr->grid_array[my][mx];
+            const auto *g_ptr = &floor.grid_array[my][mx];
 
             if (!g_ptr->m_idx) {
                 continue;
             }
 
-            m_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
+            auto *m_ptr = &floor.m_list[g_ptr->m_idx];
 
             if (m_ptr->is_asleep()) {
                 continue;
@@ -388,13 +380,13 @@ bool process_warning(PlayerType *player_ptr, POSITION xx, POSITION yy)
                 continue;
             }
 
-            r_ptr = &monraces_info[m_ptr->r_idx];
+            auto *r_ptr = &m_ptr->get_monrace();
 
             /* Monster spells (only powerful ones)*/
             if (projectable(player_ptr, my, mx, yy, xx)) {
                 const auto flags = r_ptr->ability_flags;
 
-                if (dungeons_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::NO_MAGIC)) {
+                if (dungeon.flags.has_not(DungeonFeatureType::NO_MAGIC)) {
                     if (flags.has(MonsterAbilityType::BA_CHAO)) {
                         spell_damcalc_by_spellnum(player_ptr, MonsterAbilityType::BA_CHAO, AttributeType::CHAOS, g_ptr->m_idx, &dam_max0);
                     }
@@ -498,7 +490,7 @@ bool process_warning(PlayerType *player_ptr, POSITION xx, POSITION yy)
                 }
             }
             /* Monster melee attacks */
-            if (r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_BLOW) || dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
+            if (r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_BLOW) || dungeon.flags.has(DungeonFeatureType::NO_MELEE)) {
                 dam_max += dam_max0;
                 continue;
             }
@@ -509,15 +501,15 @@ bool process_warning(PlayerType *player_ptr, POSITION xx, POSITION yy)
             }
 
             int dam_melee = 0;
-            for (int m = 0; m < 4; m++) {
+            for (const auto &blow : r_ptr->blows) {
                 /* Skip non-attacks */
-                if (r_ptr->blow[m].method == RaceBlowMethodType::NONE || (r_ptr->blow[m].method == RaceBlowMethodType::SHOOT)) {
+                if (blow.method == RaceBlowMethodType::NONE || (blow.method == RaceBlowMethodType::SHOOT)) {
                     continue;
                 }
 
                 /* Extract the attack info */
-                dam_melee += blow_damcalc(m_ptr, player_ptr, &r_ptr->blow[m]);
-                if (r_ptr->blow[m].method == RaceBlowMethodType::EXPLODE) {
+                dam_melee += blow_damcalc(m_ptr, player_ptr, blow);
+                if (blow.method == RaceBlowMethodType::EXPLODE) {
                     break;
                 }
             }
@@ -545,13 +537,13 @@ bool process_warning(PlayerType *player_ptr, POSITION xx, POSITION yy)
             msg_format(_("%sが鋭く震えた!", "Your %s pulsates sharply!"), item_name.data());
 
             disturb(player_ptr, false, true);
-            return get_check(_("本当にこのまま進むか?", "Really want to go ahead? "));
+            return input_check(_("本当にこのまま進むか?", "Really want to go ahead? "));
         }
     } else {
         old_damage = old_damage / 2;
     }
 
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[yy][xx];
+    auto *g_ptr = &floor.grid_array[yy][xx];
     bool is_warning = (!easy_disarm && is_trap(player_ptr, g_ptr->feat)) || (g_ptr->mimic && is_trap(player_ptr, g_ptr->feat));
     is_warning &= !one_in_(13);
     if (!is_warning) {
@@ -568,5 +560,5 @@ bool process_warning(PlayerType *player_ptr, POSITION xx, POSITION yy)
 
     msg_format(_("%sが鋭く震えた!", "Your %s pulsates sharply!"), item_name.data());
     disturb(player_ptr, false, true);
-    return get_check(_("本当にこのまま進むか?", "Really want to go ahead? "));
+    return input_check(_("本当にこのまま進むか?", "Really want to go ahead? "));
 }
index 0ef31bf..c4f8ca5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 63dfb08..ddf68c4 100644 (file)
@@ -1,4 +1,4 @@
-#include "perception/identification.h"
+#include "perception/identification.h"
 #include "artifact/fixed-art-types.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -11,7 +11,6 @@
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
 #include "object-hook/hook-weapon.h"
-#include "object/object-flags.h"
 #include "object/object-info.h"
 #include "sv-definition/sv-amulet-types.h"
 #include "sv-definition/sv-other-types.h"
@@ -26,6 +25,8 @@
 #include "util/buffer-shaper.h"
 #include "util/enum-converter.h"
 #include <algorithm>
+#include <array>
+#include <string>
 
 /*!
  * @brief オブジェクトの*鑑定*内容を詳述して表示する /
@@ -37,9 +38,9 @@
  */
 bool screen_object(PlayerType *player_ptr, ItemEntity *o_ptr, BIT_FLAGS mode)
 {
-    concptr info[128];
+    std::array<std::string, 128> info{};
     int trivial_info = 0;
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
 
     const auto item_text = o_ptr->is_fixed_artifact() ? o_ptr->get_fixed_artifact().text.data() : o_ptr->get_baseitem().text.data();
     const auto item_text_lines = shape_buffer(item_text, 77 - 15);
@@ -54,7 +55,7 @@ bool screen_object(PlayerType *player_ptr, ItemEntity *o_ptr, BIT_FLAGS mode)
 
     if (flags.has(TR_ACTIVATE)) {
         info[i++] = _("始動したときの効果...", "It can be activated for...");
-        info[i++] = activation_explanation(o_ptr);
+        info[i++] = o_ptr->explain_activation();
         info[i++] = _("...ただし装備していなければならない。", "...if it is being worn.");
     }
 
@@ -92,10 +93,6 @@ bool screen_object(PlayerType *player_ptr, ItemEntity *o_ptr, BIT_FLAGS mode)
         info[i++] = _("それは魔法の難易度を下げる。", "It affects your ability to cast spells.");
     }
 
-    if (flags.has(TR_HEAVY_SPELL)) {
-        info[i++] = _("それは魔法の難易度を上げる。", "It interferes with casting spells.");
-    }
-
     if (flags.has(TR_MIGHTY_THROW)) {
         info[i++] = _("それは物を強く投げることを可能にする。", "It provides great strength when you throw an item.");
     }
@@ -727,7 +724,7 @@ bool screen_object(PlayerType *player_ptr, ItemEntity *o_ptr, BIT_FLAGS mode)
     }
 
     if (mode & SCROBJ_FAKE_OBJECT) {
-        const auto sval = o_ptr->bi_key.sval().value();
+        const auto sval = *o_ptr->bi_key.sval();
         switch (o_ptr->bi_key.tval()) {
         case ItemKindType::RING:
             switch (sval) {
@@ -788,9 +785,7 @@ bool screen_object(PlayerType *player_ptr, ItemEntity *o_ptr, BIT_FLAGS mode)
     }
 
     screen_save();
-    int wid, hgt;
-    term_get_size(&wid, &hgt);
-
+    const auto &[wid, hgt] = term_get_size();
     std::string item_name;
     if (!(mode & SCROBJ_FAKE_OBJECT)) {
         item_name = describe_flavor(player_ptr, o_ptr, 0);
index 7f3a255..4e8a8c9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e08eabe..9a6fe0a 100644 (file)
@@ -1,42 +1,12 @@
-#include "perception/object-perception.h"
+#include "perception/object-perception.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "game-option/play-record-options.h"
 #include "io/write-diary.h"
-#include "object-enchant/item-feeling.h"
-#include "object-enchant/special-object-flags.h"
-#include "object-enchant/trg-types.h"
-#include "object/item-tester-hooker.h" // 暫定、このファイルへ引っ越す.
-#include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
 
 /*!
- * @brief オブジェクトを鑑定済にする /
- * Known is true when the "attributes" of an object are "known".
- * @param o_ptr 鑑定済にするオブジェクトの構造体参照ポインタ
- * These include tohit, todam, toac, cost, and pval (charges).\n
- *\n
- * Note that "knowing" an object gives you everything that an "awareness"\n
- * gives you, and much more.  In fact, the player is always "aware" of any\n
- * item of which he has full "knowledge".\n
- *\n
- * But having full knowledge of, say, one "wand of wonder", does not, by\n
- * itself, give you knowledge, or even awareness, of other "wands of wonder".\n
- * It happens that most "identify" routines (including "buying from a shop")\n
- * will make the player "aware" of the object as well as fully "know" it.\n
- *\n
- * This routine also removes any inscriptions generated by "feelings".\n
- */
-void object_known(ItemEntity *o_ptr)
-{
-    o_ptr->feeling = FEEL_NONE;
-    o_ptr->ident &= ~(IDENT_SENSE);
-    o_ptr->ident &= ~(IDENT_EMPTY);
-    o_ptr->ident |= (IDENT_KNOWN);
-}
-
-/*!
  * @brief オブジェクトを*鑑定*済にする /
  * The player is now aware of the effects of the given object.
  * @param player_ptr プレイヤーへの参照ポインタ
@@ -73,15 +43,5 @@ void object_aware(PlayerType *player_ptr, const ItemEntity *o_ptr)
     q_ptr->copy_from(o_ptr);
     q_ptr->number = 1;
     const auto item_name = describe_flavor(player_ptr, q_ptr, OD_NAME_ONLY);
-    exe_write_diary(player_ptr, DIARY_FOUND, 0, item_name.data());
-}
-
-/*!
- * @brief オブジェクトを試行済にする /
- * Something has been "sampled"
- * @param o_ptr 試行済にするオブジェクトの構造体参照ポインタ
- */
-void object_tried(const ItemEntity *o_ptr)
-{
-    o_ptr->get_baseitem().tried = true;
+    exe_write_diary(player_ptr, DiaryKind::FOUND, 0, item_name);
 }
index 8aec9d5..04f3321 100644 (file)
@@ -1,7 +1,5 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
-void object_known(ItemEntity *o_ptr);
 void object_aware(PlayerType *player_ptr, const ItemEntity *o_ptr);
-void object_tried(const ItemEntity *o_ptr);
index 8067b86..dd3e280 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 疑似鑑定処理
  * @date 2020/05/15
  * @author Hourier
@@ -8,7 +8,6 @@
 #include "autopick/autopick.h"
 #include "avatar/avatar.h"
 #include "core/disturbance.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flag-inscriptions-table.h"
 #include "flavor/flavor-describer.h"
@@ -24,6 +23,7 @@
 #include "player/player-status-flags.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-confusion.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
@@ -100,17 +100,21 @@ static void sense_inventory_aux(PlayerType *player_ptr, INVENTORY_IDX slot, bool
     const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
     if (slot >= INVEN_MAIN_HAND) {
 #ifdef JP
-        msg_format("%s%s(%c)は%sという感じがする...", describe_use(player_ptr, slot), item_name.data(), index_to_label(slot), game_inscriptions[feel]);
+        constexpr auto mes = "%s%s(%c)は%sという感じがする...";
+        msg_format(mes, describe_use(player_ptr, slot), item_name.data(), index_to_label(slot), game_inscriptions[feel]);
 #else
-        msg_format("You feel the %s (%c) you are %s %s %s...", item_name.data(), index_to_label(slot), describe_use(player_ptr, slot),
+        constexpr auto mes = "You feel the %s (%c) you are %s %s %s...";
+        msg_format(mes, item_name.data(), index_to_label(slot), describe_use(player_ptr, slot),
             ((o_ptr->number == 1) ? "is" : "are"), game_inscriptions[feel]);
 #endif
 
     } else {
 #ifdef JP
-        msg_format("ザックの中の%s(%c)は%sという感じがする...", item_name.data(), index_to_label(slot), game_inscriptions[feel]);
+        constexpr auto mes = "ザックの中の%s(%c)は%sという感じがする...";
+        msg_format(mes, item_name.data(), index_to_label(slot), game_inscriptions[feel]);
 #else
-        msg_format("You feel the %s (%c) in your pack %s %s...", item_name.data(), index_to_label(slot), ((o_ptr->number == 1) ? "is" : "are"), game_inscriptions[feel]);
+        constexpr auto mes = "You feel the %s (%c) in your pack %s %s...";
+        msg_format(mes, item_name.data(), index_to_label(slot), ((o_ptr->number == 1) ? "is" : "are"), game_inscriptions[feel]);
 #endif
     }
 
@@ -118,8 +122,17 @@ static void sense_inventory_aux(PlayerType *player_ptr, INVENTORY_IDX slot, bool
     o_ptr->feeling = feel;
 
     autopick_alter_item(player_ptr, slot, destroy_feeling);
-    player_ptr->update |= (PU_COMBINATION | PU_REORDER);
-    player_ptr->window_flags |= (PW_INVENTORY | PW_EQUIPMENT);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
index fe2b418..6212886 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/item-feeling.h"
 
index 1b5f132..ce0be87 100644 (file)
@@ -1,12 +1,10 @@
-/*!
+/*!
  * @brief 落馬処理
  * @date 2020/05/31
  * @author Hourier
  */
 
 #include "pet/pet-fall-off.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "floor/cave.h"
@@ -25,6 +23,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/target-checker.h"
 #include "view/display-messages.h"
@@ -93,7 +92,7 @@ bool process_fall_off_horse(PlayerType *player_ptr, int dam, bool force)
     POSITION sx = 0;
     int sn = 0;
     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     if (!player_ptr->riding || player_ptr->wild_mode) {
         return false;
@@ -109,7 +108,7 @@ bool process_fall_off_horse(PlayerType *player_ptr, int dam, bool force)
             POSITION y = player_ptr->y + ddy_ddd[i];
             POSITION x = player_ptr->x + ddx_ddd[i];
 
-            grid_type *g_ptr;
+            Grid *g_ptr;
             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
 
             if (g_ptr->m_idx) {
@@ -160,16 +159,28 @@ bool process_fall_off_horse(PlayerType *player_ptr, int dam, bool force)
     player_ptr->pet_extra_flags &= ~(PF_TWO_HANDS);
     player_ptr->riding_ryoute = player_ptr->old_riding_ryoute = false;
 
-    player_ptr->update |= (PU_BONUS | PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTER_LITE | PU_MONSTER_STATUSES);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::FLOW,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
     handle_stuff(player_ptr);
-
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
-    player_ptr->redraw |= (PR_EXTRA);
-
-    /* Update health track of mount */
-    player_ptr->redraw |= (PR_UHEALTH);
-
-    bool fall_dam = false;
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::UHEALTH,
+    };
+    rfu.set_flags(flags_mwrf);
+    auto fall_dam = false;
     if (player_ptr->levitation && !force) {
         const auto m_name = monster_desc(player_ptr, m_ptr, 0);
         msg_format(_("%sから落ちたが、空中でうまく体勢を立て直して着地した。", "You are thrown from %s but make a good landing."), m_name.data());
index 63e4eb3..35e213f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 896723b..7cfab81 100644 (file)
@@ -1,5 +1,4 @@
-#include "pet/pet-util.h"
-#include "core/player-update-types.h"
+#include "pet/pet-util.h"
 #include "core/stuff-handler.h"
 #include "grid/grid.h"
 #include "monster-race/monster-race.h"
@@ -13,6 +12,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "world/world.h"
 
@@ -24,7 +24,7 @@ int total_friends = 0;
  * @param now_riding trueなら下馬処理、falseならば騎乗処理
  * @return 可能ならばtrueを返す
  */
-bool can_player_ride_pet(PlayerType *player_ptr, grid_type *g_ptr, bool now_riding)
+bool can_player_ride_pet(PlayerType *player_ptr, const Grid *g_ptr, bool now_riding)
 {
     bool old_character_xtra = w_ptr->character_xtra;
     MONSTER_IDX old_riding = player_ptr->riding;
@@ -41,7 +41,8 @@ bool can_player_ride_pet(PlayerType *player_ptr, grid_type *g_ptr, bool now_ridi
         player_ptr->riding_ryoute = player_ptr->old_riding_ryoute = false;
     }
 
-    player_ptr->update |= PU_BONUS;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
 
     bool p_can_enter = player_can_enter(player_ptr, g_ptr->feat, CEM_P_CAN_ENTER_PATTERN);
@@ -54,7 +55,7 @@ bool can_player_ride_pet(PlayerType *player_ptr, grid_type *g_ptr, bool now_ridi
 
     player_ptr->riding_ryoute = old_riding_two_hands;
     player_ptr->old_riding_ryoute = old_old_riding_two_hands;
-    player_ptr->update |= PU_BONUS;
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
 
     w_ptr->character_xtra = old_character_xtra;
@@ -75,7 +76,7 @@ PERCENTAGE calculate_upkeep(PlayerType *player_ptr)
         if (!m_ptr->is_valid()) {
             continue;
         }
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
 
         if (!m_ptr->is_pet()) {
             continue;
@@ -94,7 +95,7 @@ PERCENTAGE calculate_upkeep(PlayerType *player_ptr)
 
         if (player_ptr->riding == m_idx) {
             total_friend_levels += (r_ptr->level + 5) * 2;
-        } else if (!has_a_unique && any_bits(monraces_info[m_ptr->r_idx].flags7, RF7_RIDING)) {
+        } else if (!has_a_unique && any_bits(m_ptr->get_monrace().flags7, RF7_RIDING)) {
             total_friend_levels += (r_ptr->level + 5) * 7 / 2;
         } else {
             total_friend_levels += (r_ptr->level + 5) * 10;
index 5c4bc7e..3027330 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -42,8 +42,7 @@ enum pet_permission {
 
 extern int total_friends;
 
-struct grid_type;
-;
+class Grid;
 class PlayerType;
-bool can_player_ride_pet(PlayerType *player_ptr, grid_type *g_ptr, bool now_riding);
+bool can_player_ride_pet(PlayerType *player_ptr, const Grid *g_ptr, bool now_riding);
 PERCENTAGE calculate_upkeep(PlayerType *player_ptr);
index e196714..c7d24c6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * @file player-ability-types.h
index 61b0f8d..50336d9 100644 (file)
@@ -1,6 +1,5 @@
-#include "player-ability/player-charisma.h"
+#include "player-ability/player-charisma.h"
 #include "mutation/mutation-flag-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-info/class-info.h"
 #include "player-info/mimic-info-table.h"
index fa18bcb..6401730 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-status/player-basic-statistics.h"
 
index 4bac551..de3d0f7 100644 (file)
@@ -1,6 +1,5 @@
-#include "player-ability/player-constitution.h"
+#include "player-ability/player-constitution.h"
 #include "mutation/mutation-flag-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/class-info.h"
index 868160f..c0ea4eb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-status/player-basic-statistics.h"
 
index a64ca2e..70a49ad 100644 (file)
@@ -1,6 +1,5 @@
-#include "player-ability/player-dexterity.h"
+#include "player-ability/player-dexterity.h"
 #include "mutation/mutation-flag-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/class-info.h"
index 48b4cac..8d068a9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-status/player-basic-statistics.h"
 
index 274c60f..18a9106 100644 (file)
@@ -1,6 +1,5 @@
-#include "player-ability/player-intelligence.h"
+#include "player-ability/player-intelligence.h"
 #include "mutation/mutation-flag-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-info/class-info.h"
 #include "player-info/mimic-info-table.h"
index 12c6021..5fea2da 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-status/player-basic-statistics.h"
 
index 3b99f83..b9b16a7 100644 (file)
@@ -1,6 +1,5 @@
-#include "player-ability/player-strength.h"
+#include "player-ability/player-strength.h"
 #include "mutation/mutation-flag-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/monk-data-type.h"
index 06a4e59..1bd913e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-status/player-basic-statistics.h"
 
index 413506e..f638236 100644 (file)
@@ -1,6 +1,5 @@
-#include "player-ability/player-wisdom.h"
+#include "player-ability/player-wisdom.h"
 #include "mutation/mutation-flag-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-info/class-info.h"
 #include "player-info/mimic-info-table.h"
index 8b4894f..9d25e64 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-status/player-basic-statistics.h"
 
index d94ae47..36154b2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 特殊属性武器で攻撃した際の追加効果処理
  * @date 2020/05/23
  * @author Hourier
@@ -8,7 +8,6 @@
 
 #include "player-attack/attack-chaos-effect.h"
 #include "artifact/fixed-art-types.h"
-#include "core/player-redraw-types.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "inventory/inventory-object.h"
@@ -25,7 +24,7 @@
 #include "monster/monster-status-setter.h"
 #include "monster/monster-status.h"
 #include "object/object-mark-types.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "player/attack-defense-types.h"
 #include "realm/realm-hex-numbers.h"
 #include "spell-kind/spells-polymorph.h"
@@ -37,6 +36,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
@@ -54,13 +54,13 @@ static void attack_confuse(PlayerType *player_ptr, player_attack_type *pa_ptr, b
     if (player_ptr->special_attack & ATTACK_CONFUSE) {
         player_ptr->special_attack &= ~(ATTACK_CONFUSE);
         msg_print(_("手の輝きがなくなった。", "Your hands stop glowing."));
-        player_ptr->redraw |= (PR_TIMED_EFFECT);
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     }
 
     auto *r_ptr = pa_ptr->r_ptr;
-    if (r_ptr->flags3 & RF3_NO_CONF) {
+    if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
         if (is_original_ap_and_seen(player_ptr, pa_ptr->m_ptr)) {
-            r_ptr->r_flags3 |= RF3_NO_CONF;
+            r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_CONF);
         }
         msg_format(_("%s^には効果がなかった。", "%s^ is unaffected."), pa_ptr->m_name);
 
@@ -83,9 +83,9 @@ static void attack_confuse(PlayerType *player_ptr, player_attack_type *pa_ptr, b
 static void attack_stun(PlayerType *player_ptr, player_attack_type *pa_ptr, bool can_resist = true)
 {
     auto *r_ptr = pa_ptr->r_ptr;
-    if (any_bits(r_ptr->flags3, RF3_NO_STUN)) {
+    if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_STUN)) {
         if (is_original_ap_and_seen(player_ptr, pa_ptr->m_ptr)) {
-            set_bits(r_ptr->flags3, RF3_NO_STUN);
+            r_ptr->resistance_flags.set(MonsterResistanceType::NO_STUN);
         }
         msg_format(_("%s^には効果がなかった。", "%s^ is unaffected."), pa_ptr->m_name);
     } else if (can_resist && randint0(100) < r_ptr->level) {
@@ -107,9 +107,9 @@ static void attack_stun(PlayerType *player_ptr, player_attack_type *pa_ptr, bool
 static void attack_scare(PlayerType *player_ptr, player_attack_type *pa_ptr, bool can_resist = true)
 {
     auto *r_ptr = pa_ptr->r_ptr;
-    if (any_bits(r_ptr->flags3, RF3_NO_FEAR)) {
+    if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
         if (is_original_ap_and_seen(player_ptr, pa_ptr->m_ptr)) {
-            set_bits(r_ptr->flags3, RF3_NO_FEAR);
+            r_ptr->resistance_flags.set(MonsterResistanceType::NO_FEAR);
         }
         msg_format(_("%s^には効果がなかった。", "%s^ is unaffected."), pa_ptr->m_name);
     } else if (can_resist && randint0(100) < r_ptr->level) {
@@ -149,7 +149,7 @@ static void attack_dispel(PlayerType *player_ptr, player_attack_type *pa_ptr)
 
     auto sp = damroll(dd, 8);
     player_ptr->csp = std::min(player_ptr->msp, player_ptr->csp + sp);
-    set_bits(player_ptr->redraw, PR_MP);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
 }
 
 /*!
@@ -243,7 +243,7 @@ static void attack_polymorph(PlayerType *player_ptr, player_attack_type *pa_ptr,
     }
 
     pa_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[pa_ptr->m_idx];
-    angband_strcpy(pa_ptr->m_name, monster_desc(player_ptr, pa_ptr->m_ptr, 0).data(), sizeof(pa_ptr->m_name));
+    angband_strcpy(pa_ptr->m_name, monster_desc(player_ptr, pa_ptr->m_ptr, 0), sizeof(pa_ptr->m_name));
 }
 
 /*!
@@ -306,7 +306,7 @@ void change_monster_stat(PlayerType *player_ptr, player_attack_type *pa_ptr, con
         attack_teleport_away(player_ptr, pa_ptr, num);
     }
 
-    if (pa_ptr->chaos_effect == CE_POLYMORPH && (randint1(90) > monraces_info[pa_ptr->m_ptr->r_idx].level)) {
+    if (pa_ptr->chaos_effect == CE_POLYMORPH && (randint1(90) > pa_ptr->m_ptr->get_monrace().level)) {
         attack_polymorph(player_ptr, pa_ptr, y, x);
     }
 
index f17e57e..7cea0e7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 62fb32b..7e2df2b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 吸血処理
  * @date 2020/05/23
  * @author Hourier
@@ -11,7 +11,7 @@
 #include "inventory/inventory-slot-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "object-enchant/tr-types.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "realm/realm-hex-numbers.h"
 #include "spell-realm/spells-hex.h"
 #include "system/item-entity.h"
@@ -35,7 +35,7 @@ void decide_blood_sucking(PlayerType *player_ptr, player_attack_type *pa_ptr)
         return;
     }
 
-    pa_ptr->can_drain = monster_living(pa_ptr->m_ptr->r_idx);
+    pa_ptr->can_drain = pa_ptr->m_ptr->has_living_flag();
 }
 
 /*!
index ee1a252..4a98b49 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct player_attack_type;
 class PlayerType;
diff --git a/src/player-attack/player-attack-util.h b/src/player-attack/player-attack-util.h
deleted file mode 100644 (file)
index 8ed6a65..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#pragma once
-
-#include "combat/combat-options-type.h"
-#include "combat/martial-arts-table.h"
-#include "effect/attribute-types.h"
-#include "object-enchant/tr-flags.h"
-#include "system/angband.h"
-#include "system/system-variables.h"
-
-/*!
- * @brief カオス効果種別
- */
-enum chaotic_effect {
-    CE_NONE = 0,
-    CE_VAMPIRIC = 1,
-    CE_QUAKE = 2,
-    CE_CONFUSION = 3,
-    CE_TELE_AWAY = 4,
-    CE_POLYMORPH = 5,
-};
-
-/*!
- * @brief 魔術効果種別
- */
-enum class MagicalBrandEffectType { NONE = 0,
-    EXTRA = 1,
-    STUN = 2,
-    SCARE = 3,
-    DISPELL = 4,
-    PROBE = 5,
-    MAX };
-
-/*!
- * @brief プレイヤーの打撃に関する情報
- */
-struct grid_type;
-;
-class MonsterRaceInfo;
-class MonsterEntity;
-struct player_attack_type {
-    int16_t hand{}; //!< 武器の持ち手
-    grid_type *g_ptr; //!< ターゲットのいる地形情報
-    MONSTER_IDX m_idx{}; //!< モンスターID
-    MonsterEntity *m_ptr{}; //!< モンスター情報(参照ポインタ)
-    GAME_TEXT m_name[MAX_NLEN]{}; //!< モンスター名
-    MonsterRaceId r_idx{}; //!< モンスター種族ID
-    MonsterRaceInfo *r_ptr{}; //!< モンスター種族情報(参照ポインタ)
-    bool backstab{}; //!< 眠っている敵を不意打ちしたか
-    bool surprise_attack{}; //!< 気づいていない敵に闇討ちしたか(忍者)
-    bool stab_fleeing{}; //!< 逃げている敵の背後を襲ったか
-    combat_options mode{}; //!< 剣術種別
-    bool monk_attack{}; //!< 素手/マーシャルアーツかどうか
-    const martial_arts *ma_ptr{}; //!< マーシャルアーツ種別
-    int attack_damage{}; //!< 累積ダメージ
-    int num_blow{}; //!< 打撃回数
-    TrFlags flags{}; //!< 武器フラグ
-    chaotic_effect chaos_effect{}; //!< カオス効果
-    MagicalBrandEffectType magical_effect{}; //!< 魔術効果
-    bool *fear{}; //!< 恐怖したかどうか
-    bool *mdeath{}; //!< 死んだかどうか
-    bool can_drain{}; //!< 吸血できるかどうか
-    int drain_result{}; //!< 吸血した累積量
-    int drain_left{}; //!< 吸血できる残量(最大MAX_VAMPIRIC_DRAIN)
-    bool weak{}; //!< 打撃効果でモンスターが弱くなったかどうか
-    AttributeFlags attribute_flags{}; //!< 与えたダメージの種類
-};
index 664880f..7b6338b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーからモンスターへの打撃処理
  * @date 2020/05/22
  * @author Hourier
@@ -12,7 +12,6 @@
 #include "combat/attack-criticality.h"
 #include "combat/martial-arts-table.h"
 #include "combat/slaying.h"
-#include "core/player-update-types.h"
 #include "floor/cave.h"
 #include "floor/geometry.h"
 #include "game-option/cheat-types.h"
 #include "object-enchant/tr-types.h"
 #include "object-enchant/vorpal-weapon.h"
 #include "object-hook/hook-weapon.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "player-attack/attack-chaos-effect.h"
 #include "player-attack/blood-sucking-processor.h"
-#include "player-attack/player-attack-util.h"
 #include "player-base/player-class.h"
 #include "player-info/equipment-info.h"
 #include "player-status/player-energy.h"
@@ -69,25 +66,21 @@ constexpr auto MAX_VAMPIRIC_DRAIN = 50;
 /*!
  * @brief プレイヤーの攻撃情報を初期化する(コンストラクタ以外の分)
  */
-static player_attack_type *initialize_player_attack_type(
-    player_attack_type *pa_ptr, PlayerType *player_ptr, POSITION y, POSITION x, int16_t hand, combat_options mode, bool *fear, bool *mdeath)
+player_attack_type::player_attack_type(FloorType &floor, POSITION y, POSITION x, int16_t hand, combat_options mode, bool *fear, bool *mdeath)
+    : hand(hand)
+    , mode(mode)
+    , fear(fear)
+    , mdeath(mdeath)
+    , drain_left(MAX_VAMPIRIC_DRAIN)
+    , g_ptr(&floor.grid_array[y][x])
+    , chaos_effect(CE_NONE)
+    , magical_effect(MagicalBrandEffectType::NONE)
 {
-    auto floor_ptr = player_ptr->current_floor_ptr;
-    auto g_ptr = &floor_ptr->grid_array[y][x];
-    auto m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
-
-    pa_ptr->hand = hand;
-    pa_ptr->mode = mode;
-    pa_ptr->m_idx = g_ptr->m_idx;
-    pa_ptr->m_ptr = m_ptr;
-    pa_ptr->r_idx = m_ptr->r_idx;
-    pa_ptr->r_ptr = &monraces_info[m_ptr->r_idx];
-    pa_ptr->ma_ptr = &ma_blows[0];
-    pa_ptr->g_ptr = g_ptr;
-    pa_ptr->fear = fear;
-    pa_ptr->mdeath = mdeath;
-    pa_ptr->drain_left = MAX_VAMPIRIC_DRAIN;
-    return pa_ptr;
+    this->m_idx = this->g_ptr->m_idx;
+    this->m_ptr = &floor.m_list[this->g_ptr->m_idx];
+    this->r_idx = this->m_ptr->r_idx;
+    this->r_ptr = &this->m_ptr->get_monrace();
+    this->ma_ptr = &ma_blows[0];
 }
 
 /*!
@@ -121,7 +114,7 @@ static void attack_classify(PlayerType *player_ptr, player_attack_type *pa_ptr)
  */
 static void get_bare_knuckle_exp(PlayerType *player_ptr, player_attack_type *pa_ptr)
 {
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     if ((r_ptr->level + 10) <= player_ptr->lev) {
         return;
     }
@@ -148,7 +141,7 @@ static void get_weapon_exp(PlayerType *player_ptr, player_attack_type *pa_ptr)
  */
 static void get_attack_exp(PlayerType *player_ptr, player_attack_type *pa_ptr)
 {
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
     if (!o_ptr->is_valid()) {
         get_bare_knuckle_exp(player_ptr, pa_ptr);
@@ -393,7 +386,7 @@ static void apply_damage_bonus(PlayerType *player_ptr, player_attack_type *pa_pt
         pa_ptr->attack_damage *= 2;
     }
 
-    if ((pa_ptr->mode == HISSATSU_SEKIRYUKA) && !monster_living(pa_ptr->m_ptr->r_idx)) {
+    if ((pa_ptr->mode == HISSATSU_SEKIRYUKA) && !pa_ptr->m_ptr->has_living_flag()) {
         pa_ptr->attack_damage = 0;
     }
 
@@ -420,8 +413,8 @@ static void apply_damage_negative_effect(player_attack_type *pa_ptr, bool is_zan
         pa_ptr->attack_damage = 0;
     }
 
-    auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
-    if ((pa_ptr->mode == HISSATSU_ZANMA) && !(!monster_living(pa_ptr->m_ptr->r_idx) && r_ptr->kind_flags.has(MonsterKindType::EVIL))) {
+    auto *r_ptr = &pa_ptr->m_ptr->get_monrace();
+    if ((pa_ptr->mode == HISSATSU_ZANMA) && !(!pa_ptr->m_ptr->has_living_flag() && r_ptr->kind_flags.has(MonsterKindType::EVIL))) {
         pa_ptr->attack_damage = 0;
     }
 
@@ -446,7 +439,7 @@ static void apply_damage_negative_effect(player_attack_type *pa_ptr, bool is_zan
 static bool check_fear_death(PlayerType *player_ptr, player_attack_type *pa_ptr, const int num, const bool is_lowlevel)
 {
     MonsterDamageProcessor mdp(player_ptr, pa_ptr->m_idx, pa_ptr->attack_damage, pa_ptr->fear, pa_ptr->attribute_flags);
-    if (!mdp.mon_take_hit(nullptr)) {
+    if (!mdp.mon_take_hit("")) {
         return false;
     }
 
@@ -493,7 +486,7 @@ static void apply_actual_attack(
     sound(SOUND_HIT);
     print_surprise_attack(pa_ptr);
 
-    pa_ptr->flags = object_flags(o_ptr);
+    pa_ptr->flags = o_ptr->get_flags();
     pa_ptr->chaos_effect = select_chaotic_effect(player_ptr, pa_ptr);
     pa_ptr->magical_effect = select_magical_brand_effect(player_ptr, pa_ptr);
     decide_blood_sucking(player_ptr, pa_ptr);
@@ -549,8 +542,8 @@ void exe_player_attack_to_monster(PlayerType *player_ptr, POSITION y, POSITION x
     bool do_quake = false;
     bool drain_msg = true;
 
-    player_attack_type tmp_attack;
-    auto pa_ptr = initialize_player_attack_type(&tmp_attack, player_ptr, y, x, hand, mode, fear, mdeath);
+    player_attack_type tmp_attack(*player_ptr->current_floor_ptr, y, x, hand, mode, fear, mdeath);
+    auto pa_ptr = &tmp_attack;
 
     bool is_human = (pa_ptr->r_ptr->d_char == 'p');
     bool is_lowlevel = (pa_ptr->r_ptr->level < (player_ptr->lev - 15));
@@ -560,7 +553,7 @@ void exe_player_attack_to_monster(PlayerType *player_ptr, POSITION y, POSITION x
 
     /* Disturb the monster */
     (void)set_monster_csleep(player_ptr, pa_ptr->m_idx, 0);
-    angband_strcpy(pa_ptr->m_name, monster_desc(player_ptr, pa_ptr->m_ptr, 0).data(), sizeof(pa_ptr->m_name));
+    angband_strcpy(pa_ptr->m_name, monster_desc(player_ptr, pa_ptr->m_ptr, 0), sizeof(pa_ptr->m_name));
 
     int chance = calc_attack_quality(player_ptr, pa_ptr);
     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
@@ -613,7 +606,7 @@ void exe_player_attack_to_monster(PlayerType *player_ptr, POSITION y, POSITION x
  */
 void massacre(PlayerType *player_ptr)
 {
-    grid_type *g_ptr;
+    Grid *g_ptr;
     MonsterEntity *m_ptr;
     for (DIRECTION dir = 0; dir < 8; dir++) {
         POSITION y = player_ptr->y + ddy_ddd[dir];
index 4a1f157..6ea2581 100644 (file)
@@ -1,7 +1,75 @@
-#pragma once
+#pragma once
 
 #include "combat/combat-options-type.h"
+#include "combat/martial-arts-table.h"
+#include "effect/attribute-types.h"
+#include "object-enchant/tr-flags.h"
 #include "system/angband.h"
+#include "system/system-variables.h"
+
+/*!
+ * @brief カオス効果種別
+ */
+enum chaotic_effect {
+    CE_NONE = 0,
+    CE_VAMPIRIC = 1,
+    CE_QUAKE = 2,
+    CE_CONFUSION = 3,
+    CE_TELE_AWAY = 4,
+    CE_POLYMORPH = 5,
+};
+
+/*!
+ * @brief 魔術効果種別
+ */
+enum class MagicalBrandEffectType { NONE = 0,
+    EXTRA = 1,
+    STUN = 2,
+    SCARE = 3,
+    DISPELL = 4,
+    PROBE = 5,
+    MAX };
+
+/*!
+ * @brief プレイヤーの打撃に関する情報
+ * @todo fear とmdeath はポインタである必要はないはず
+ */
+enum class MonsterRaceId : short;
+class Grid;
+class FloorType;
+class MonsterRaceInfo;
+class MonsterEntity;
+struct player_attack_type {
+    player_attack_type(FloorType &floor, POSITION y, POSITION x, int16_t hand, combat_options mode, bool *fear, bool *mdeath);
+
+    bool backstab = false; //!< 眠っている敵を不意打ちしたか
+    bool surprise_attack = false; //!< 気づいていない敵に闇討ちしたか(忍者)
+    bool stab_fleeing = false; //!< 逃げている敵の背後を襲ったか
+    bool monk_attack = false; //!< 素手/マーシャルアーツかどうか
+    int attack_damage = 0; //!< 累積ダメージ
+    int num_blow = 0; //!< 打撃回数
+    bool can_drain = false; //!< 吸血できるかどうか
+    int drain_result = 0; //!< 吸血した累積量
+    bool weak = false; //!< 打撃効果でモンスターが弱くなったかどうか
+    GAME_TEXT m_name[MAX_NLEN]{}; //!< モンスター名
+    TrFlags flags{}; //!< 武器フラグ
+    AttributeFlags attribute_flags{}; //!< 与えたダメージの種類
+
+    int16_t hand; //!< 武器の持ち手
+    combat_options mode; //!< 剣術種別
+    bool *fear; //!< 恐怖したかどうか
+    bool *mdeath; //!< 死んだかどうか
+    int drain_left; //!< 吸血できる残量(最大MAX_VAMPIRIC_DRAIN)
+    Grid *g_ptr; //!< ターゲットのいる地形情報
+    chaotic_effect chaos_effect; //!< カオス効果
+    MagicalBrandEffectType magical_effect; //!< 魔術効果
+
+    MONSTER_IDX m_idx; //!< モンスターID
+    MonsterEntity *m_ptr; //!< モンスター情報(参照ポインタ)
+    MonsterRaceId r_idx; //!< モンスター種族ID
+    MonsterRaceInfo *r_ptr; //!< モンスター種族情報(参照ポインタ)
+    const martial_arts *ma_ptr; //!< マーシャルアーツ種別
+};
 
 class PlayerType;
 void exe_player_attack_to_monster(PlayerType *player_ptr, POSITION y, POSITION x, bool *fear, bool *mdeath, int16_t hand, combat_options mode);
index 602d2ab..72f11dc 100644 (file)
@@ -1,12 +1,11 @@
-/*!
+/*!
  * @brief プレイヤーの職業クラスに基づく耐性・能力の判定処理等を行うクラス
  * @date 2021/09/08
  * @author Hourier
  * @details PlayerRaceからPlayerClassへの依存はあるが、逆は依存させないこと.
  */
 #include "player-base/player-class.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "cmd-io/diary-subtitle-table.h"
 #include "inventory/inventory-slot-types.h"
 #include "mind/mind-elementalist.h"
 #include "player-info/bard-data-type.h"
@@ -28,6 +27,7 @@
 #include "status/action-setter.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
@@ -395,10 +395,17 @@ bool PlayerClass::lose_balance()
     }
 
     this->set_samurai_stance(SamuraiStanceType::NONE);
-    this->player_ptr->update |= PU_BONUS;
-    this->player_ptr->update |= PU_MONSTER_STATUSES;
-    this->player_ptr->redraw |= PR_ACTION;
-    this->player_ptr->redraw |= PR_TIMED_EFFECT;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::ACTION,
+        MainWindowRedrawingFlag::TIMED_EFFECT,
+    };
+    rfu.set_flags(flags_mwrf);
     this->player_ptr->action = ACTION_NONE;
     return true;
 }
@@ -500,7 +507,7 @@ void PlayerClass::init_specific_data()
         this->player_ptr->class_specific_data = std::make_shared<mane_data_type>();
         break;
     case PlayerClassType::SNIPER:
-        this->player_ptr->class_specific_data = std::make_shared<sniper_data_type>();
+        this->player_ptr->class_specific_data = std::make_shared<SniperData>();
         break;
     case PlayerClassType::SAMURAI:
         this->player_ptr->class_specific_data = std::make_shared<samurai_data_type>();
@@ -532,3 +539,26 @@ bool PlayerClass::has_ninja_speed() const
     has_ninja_speed_sub |= can_attack_with_sub_hand(this->player_ptr);
     return has_ninja_speed_main && has_ninja_speed_sub;
 }
+
+/*!
+ * @brief 日記のサブタイトルの候補一覧を取得する
+ *
+ * 候補一覧の先頭は「最高の肉体を求めて」、末尾は「最高の頭脳を求めて」で
+ * あるため、プレイヤーの職業に従い範囲を決定する。
+ *
+ * @return 候補一覧を参照するstd::spanオブジェクト
+ */
+std::span<const std::string> PlayerClass::get_subtitle_candidates() const
+{
+    static const std::span<const std::string> candidates(diary_subtitles);
+    const auto max = diary_subtitles.size();
+    if (this->is_tough()) {
+        return candidates.subspan(0, max - 1);
+    }
+
+    if (this->is_wizard()) {
+        return candidates.subspan(1);
+    }
+
+    return candidates.subspan(1, max - 2);
+}
index b2498c1..736f1be 100644 (file)
@@ -1,12 +1,10 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 #include "object-enchant/tr-flags.h"
 #include "system/player-type-definition.h"
-
 #include <initializer_list>
 #include <memory>
+#include <span>
 #include <variant>
 
 enum class SamuraiStanceType : uint8_t;
@@ -49,6 +47,7 @@ public:
     std::shared_ptr<T> get_specific_data() const;
 
     bool has_ninja_speed() const;
+    std::span<const std::string> get_subtitle_candidates() const;
 
 private:
     PlayerType *player_ptr;
index 1b2852a..fc5db76 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーの種族に基づく耐性・能力の判定処理等を行うクラス
  * @date 2021/09/08
  * @author Hourier
@@ -9,6 +9,7 @@
 #include "player-base/player-class.h"
 #include "player-info/mimic-info-table.h"
 #include "player/race-info-table.h"
+#include "system/angband-exceptions.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
@@ -44,8 +45,8 @@ TrFlags PlayerRace::tr_flags() const
         if (this->player_ptr->lev < cond.level) {
             continue;
         }
-        if (cond.pclass.has_value()) {
-            auto is_class_equal = PlayerClass(this->player_ptr).equals(cond.pclass.value());
+        if (cond.pclass) {
+            auto is_class_equal = PlayerClass(this->player_ptr).equals(*cond.pclass);
             if (cond.not_class && is_class_equal) {
                 continue;
             }
@@ -79,7 +80,7 @@ const player_race_info *PlayerRace::get_info() const
     case MimicKindType::VAMPIRE:
         return &mimic_info.at(this->player_ptr->mimic_form);
     default:
-        throw("Invalid MimicKindType was specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid MimicKindType was specified!");
     }
 }
 
@@ -148,9 +149,9 @@ int16_t PlayerRace::speed() const
     }
 
     if (this->equals(PlayerRaceType::MERFOLK)) {
-        auto *floor_ptr = this->player_ptr->current_floor_ptr;
-        auto *f_ptr = &terrains_info[floor_ptr->grid_array[this->player_ptr->y][this->player_ptr->x].feat];
-        if (f_ptr->flags.has(TerrainCharacteristics::WATER)) {
+        const auto &floor = *this->player_ptr->current_floor_ptr;
+        const auto &terrain = floor.get_grid(this->player_ptr->get_position()).get_terrain();
+        if (terrain.flags.has(TerrainCharacteristics::WATER)) {
             result += (2 + this->player_ptr->lev / 10);
         } else if (!this->player_ptr->levitation) {
             result -= 2;
@@ -167,7 +168,7 @@ int16_t PlayerRace::speed() const
     case MimicKindType::VAMPIRE:
         return result + 3;
     default:
-        throw("Invalid MimicKindType was specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid MimicKindType was specified!");
     }
 }
 
@@ -248,3 +249,24 @@ int16_t PlayerRace::additional_constitution() const
 
     return result;
 }
+
+/*!
+ * @brief 救援召喚時のモンスターシンボルを返す
+ * @param player_ptr プレイヤー情報への参照ポインタ
+ * @return シンボル文字
+ */
+char PlayerRace::get_summon_symbol() const
+{
+    auto symbol = 'N';
+    auto mmc_ptr = this->get_info();
+
+    auto l = strlen(mmc_ptr->symbol);
+    auto mul = 1;
+    for (size_t i = 0; i < l; i++) {
+        if (one_in_(mul)) {
+            symbol = mmc_ptr->symbol[i];
+        }
+        mul *= 13;
+    }
+    return symbol;
+}
index 85e243c..5c2e602 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/tr-flags.h"
 
@@ -26,6 +26,7 @@ public:
     int16_t additional_strength() const;
     int16_t additional_dexterity() const;
     int16_t additional_constitution() const;
+    char get_summon_symbol() const;
 
 private:
     PlayerType *player_ptr;
index bae4157..4511d45 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/alignment.h"
+#include "player-info/alignment.h"
 #include "artifact/fixed-art-types.h"
 #include "avatar/avatar.h"
 #include "game-option/text-display-options.h"
@@ -9,6 +9,7 @@
 #include "monster/monster-status.h"
 #include "player-info/equipment-info.h"
 #include "player-info/race-info.h"
+#include "system/angband-exceptions.h"
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
@@ -49,7 +50,7 @@ void PlayerAlignment::update_alignment()
         if (!m_ptr->is_valid()) {
             continue;
         }
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
 
         if (!m_ptr->is_pet()) {
             continue;
@@ -87,7 +88,7 @@ void PlayerAlignment::update_alignment()
     case MimicKindType::VAMPIRE:
         break;
     default:
-        throw("Invalid MimicKindType was specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid MimicKindType was specified!");
     }
 
     for (int i = 0; i < 2; i++) {
index 5da5aa4..b81d39d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
index 9e16d67..628d39e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 12c3575..99f5370 100644 (file)
@@ -1,7 +1,6 @@
-#include "player-info/base-status-info.h"
+#include "player-info/base-status-info.h"
 #include "inventory/inventory-slot-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "player-info/self-info-util.h"
 #include "player/player-status-flags.h"
 #include "system/player-type-definition.h"
@@ -15,7 +14,7 @@ void set_equipment_influence(PlayerType *player_ptr, self_info_type *self_ptr)
             continue;
         }
 
-        auto tflags = object_flags(o_ptr);
+        const auto tflags = o_ptr->get_flags();
         self_ptr->flags.set(tflags);
     }
 
index bb59d99..13040f2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct self_info_type;
index 3335e89..cc45cb6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index adefafc..acea61f 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/body-improvement-info.h"
+#include "player-info/body-improvement-info.h"
 #include "player-info/self-info-util.h"
 #include "player/player-status-flags.h"
 #include "player/player-status.h"
@@ -147,10 +147,6 @@ void set_body_improvement_info_3(PlayerType *player_ptr, self_info_type *self_pt
         self_ptr->info[self_ptr->line++] = _("あなたは低い失敗率で魔法を唱えることができる。", "Your magic fails less often.");
     }
 
-    if (player_ptr->heavy_spell) {
-        self_ptr->info[self_ptr->line++] = _("あなたは高い失敗率で魔法を唱えなければいけない。", "Your magic fails more often.");
-    }
-
     if (player_ptr->mighty_throw) {
         self_ptr->info[self_ptr->line++] = _("あなたは強く物を投げる。", "You can throw objects powerfully.");
     }
index 29d20f6..e535da4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct self_info_type;
index fe90260..eec640d 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/class-ability-info.h"
+#include "player-info/class-ability-info.h"
 #include "player-info/self-info-util.h"
 #include "realm/realm-names-table.h"
 #include "realm/realm-types.h"
index dc695bc..4768c45 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct self_info_type;
index 7dafbce..18aaffd 100644 (file)
@@ -1,11 +1,10 @@
-/*!
+/*!
  * @brief プレイヤーの職業に関する諸テーブル定義
  * @date 2019/04/30
  * @author deskull
  */
 
 #include "player-info/class-info.h"
-#include "core/player-redraw-types.h"
 #include "inventory/inventory-slot-types.h"
 #include "player-info/race-info.h"
 #include "system/item-entity.h"
index ad2237e..ad6015d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* 人畜無害なenumヘッダを先に読み込む */
 #include "system/angband.h"
index 83aa151..859ab30 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <memory>
 #include <variant>
@@ -11,7 +11,7 @@ struct bluemage_data_type;
 struct magic_eater_data_type;
 struct bard_data_type;
 struct mane_data_type;
-struct sniper_data_type;
+class SniperData;
 struct samurai_data_type;
 struct monk_data_type;
 struct ninja_data_type;
@@ -26,7 +26,7 @@ using ClassSpecificData = std::variant<
     std::shared_ptr<magic_eater_data_type>,
     std::shared_ptr<bard_data_type>,
     std::shared_ptr<mane_data_type>,
-    std::shared_ptr<sniper_data_type>,
+    std::shared_ptr<SniperData>,
     std::shared_ptr<samurai_data_type>,
     std::shared_ptr<monk_data_type>,
     std::shared_ptr<ninja_data_type>,
index 4cb664f..35f0ad5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class PlayerClassType : short {
     WARRIOR = 0,
index a857795..afb6fc8 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/equipment-info.h"
+#include "player-info/equipment-info.h"
 #include "inventory/inventory-slot-types.h"
 #include "object-hook/hook-weapon.h"
 #include "object/tval-types.h"
index ea5a987..bb85753 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 34bc808..43995c5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 46df2b2..4766a91 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/magic-eater-data-type.h"
+#include "player-info/magic-eater-data-type.h"
 #include "sv-definition/sv-rod-types.h"
 #include "sv-definition/sv-staff-types.h"
 #include "sv-definition/sv-wand-types.h"
index 52570ad..912fe79 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 38062df..7437652 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e434c77..37dc18d 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/mimic-info-table.h"
+#include "player-info/mimic-info-table.h"
 #include "player-info/race-info.h"
 
 #ifdef JP
index 44f269c..84c3773 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-info/race-info.h"
 #include <map>
index 2a7be8f..e83f98a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 55175cd..d8f170f 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/mutation-info.h"
+#include "player-info/mutation-info.h"
 #include "mutation/mutation-flag-types.h"
 #include "player-info/self-info-util.h"
 #include "player/player-status-flags.h"
index 5c31bb2..66b5ccb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct self_info_type;
index 9e30c7c..60845c2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index edfc06c..ccc390d 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/race-ability-info.h"
+#include "player-info/race-ability-info.h"
 #include "player-info/self-info-util.h"
 #include "system/player-type-definition.h"
 #include "term/z-form.h"
index 639458e..127eb30 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct self_info_type;
index a27920e..7bc39ce 100644 (file)
@@ -1,34 +1,3 @@
-#include "player-info/race-info.h"
-#include "core/player-redraw-types.h"
-#include "inventory/inventory-slot-types.h"
-#include "player-base/player-race.h"
-#include "player-info/mimic-info-table.h"
-#include "player-info/race-types.h"
-#include "player/race-info-table.h"
-#include "system/item-entity.h"
-#include "system/player-type-definition.h"
-#include "util/bit-flags-calculator.h"
-#include "util/enum-converter.h"
+#include "player-info/race-info.h"
 
 const player_race_info *rp_ptr;
-
-/*!
- * @brief 救援召喚時のモンスターシンボルを返す
- * @param player_ptr プレイヤー情報への参照ポインタ
- * @return シンボル文字
- */
-char get_summon_symbol_from_player(PlayerType *player_ptr)
-{
-    auto symbol = 'N';
-    auto mmc_ptr = PlayerRace(player_ptr).get_info();
-
-    auto l = strlen(mmc_ptr->symbol);
-    auto mul = 1;
-    for (size_t i = 0; i < l; i++) {
-        if (one_in_(mul)) {
-            symbol = mmc_ptr->symbol[i];
-        }
-        mul *= 13;
-    }
-    return symbol;
-}
index 5242754..834968e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <optional>
 #include <unordered_map>
@@ -109,6 +109,3 @@ struct player_race_info {
 };
 
 extern const player_race_info *rp_ptr;
-
-class PlayerType;
-char get_summon_symbol_from_player(PlayerType *player_ptr);
index bd96994..d6f3894 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "util/enum-converter.h"
 
index db87d72..f4df125 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/resistance-info.h"
+#include "player-info/resistance-info.h"
 #include "player-base/player-race.h"
 #include "player-info/race-info.h"
 #include "player-info/self-info-util.h"
index 8833af2..ff4a018 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct self_info_type;
index 4afab18..90046e3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index dca3506..d3e0e97 100644 (file)
@@ -1,9 +1,7 @@
-#include "player-info/self-info-util.h"
+/*!
+ * @brief 自己分析における各種情報格納処理 (予定地)
+ * @author Hourier
+ * @date 2023/06/10
+ */
 
-self_info_type *initialize_self_info_type(self_info_type *self_ptr)
-{
-    self_ptr->line = 0;
-    self_ptr->flags.clear();
-
-    return self_ptr;
-}
+#include "player-info/self-info-util.h"
index 6f1c71b..03e0bca 100644 (file)
@@ -1,16 +1,14 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
 #include "system/item-entity.h"
 
 struct self_info_type {
-    int line;
-    char v_string[8][128];
-    char s_string[6][128];
-    TrFlags flags;
-    char plev_buf[80];
-    char buf[2][80];
-    concptr info[220];
+    self_info_type() = default;
+    int line = 0;
+    char v_string[8][128]{};
+    char s_string[6][128]{};
+    TrFlags flags{};
+    char plev_buf[80]{};
+    char buf[2][80]{};
+    const char *info[220]{};
 };
-
-self_info_type *initialize_self_info_type(self_info_type *self_ptr);
index 7d7320a..5957dd1 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 自己分析処理/ Self knowledge
  * @date 2018/09/07
  * @author deskull
@@ -249,7 +249,7 @@ static void set_esp_info(PlayerType *player_ptr, self_info_type *self_ptr)
 void self_knowledge(PlayerType *player_ptr)
 {
     self_info_type tmp_si;
-    self_info_type *self_ptr = initialize_self_info_type(&tmp_si);
+    self_info_type *self_ptr = &tmp_si;
     display_life_rating(player_ptr, self_ptr);
     chg_virtue(player_ptr, Virtue::KNOWLEDGE, 1);
     chg_virtue(player_ptr, Virtue::ENLIGHTEN, 1);
index 6241bd9..3e9e615 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void self_knowledge(PlayerType *player_ptr);
index fb0506f..fa0db42 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index a2281f0..db03cec 100644 (file)
@@ -1,11 +1,15 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 constexpr int16_t CONCENT_RADAR_THRESHOLD = 2;
 constexpr int16_t CONCENT_TELE_THRESHOLD = 5;
 
-struct sniper_data_type {
+class SniperData {
+public:
+    SniperData() = default;
     int16_t concent{}; //!< Concentration level
     bool reset_concent{}; //!< Concentration reset flag
+
+    void reset_concentration_flag();
 };
index 0d4e8e5..c2eb89b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 28f5f36..edabf9e 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-info/weapon-effect-info.h"
+#include "player-info/weapon-effect-info.h"
 #include "inventory/inventory-slot-types.h"
 #include "object-enchant/tr-types.h"
 #include "player-info/self-info-util.h"
index f5a8a11..a7d20d5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct self_info_type;
index a0fa8bd..081008a 100644 (file)
@@ -1,9 +1,6 @@
-#include "player-status/player-basic-statistics.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "player-status/player-basic-statistics.h"
 #include "core/window-redrawer.h"
 #include "mutation/mutation-flag-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-race.h"
 #include "player-info/class-info.h"
 #include "player-info/mimic-info-table.h"
@@ -14,6 +11,7 @@
 #include "realm/realm-hex-numbers.h"
 #include "spell-realm/spells-hex.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
 
@@ -107,8 +105,9 @@ void PlayerBasicStatistics::update_top_status()
 
     if (this->player_ptr->stat_top[status] != top) {
         this->player_ptr->stat_top[status] = (int16_t)top;
-        set_bits(this->player_ptr->redraw, PR_ABILITY_SCORE);
-        set_bits(this->player_ptr->window_flags, PW_PLAYER);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
+        rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
     }
 }
 
@@ -140,8 +139,9 @@ void PlayerBasicStatistics::update_use_status()
 
     if (this->player_ptr->stat_use[status] != use) {
         this->player_ptr->stat_use[status] = (int16_t)use;
-        set_bits(this->player_ptr->redraw, PR_ABILITY_SCORE);
-        set_bits(this->player_ptr->window_flags, PW_PLAYER);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
+        rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
     }
 }
 
@@ -169,21 +169,26 @@ void PlayerBasicStatistics::update_index_status()
     }
 
     this->player_ptr->stat_index[status] = (int16_t)index;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+    };
     if (status == A_CON) {
-        set_bits(this->player_ptr->update, PU_HP);
+        rfu.set_flag(StatusRecalculatingFlag::HP);
     } else if (status == A_INT) {
         if (mp_ptr->spell_stat == A_INT) {
-            set_bits(this->player_ptr->update, (PU_MP | PU_SPELLS));
+            rfu.set_flags(flags);
         }
     } else if (status == A_WIS) {
         if (mp_ptr->spell_stat == A_WIS) {
-            set_bits(this->player_ptr->update, (PU_MP | PU_SPELLS));
+            rfu.set_flags(flags);
         }
     } else if (status == A_CHR) {
         if (mp_ptr->spell_stat == A_CHR) {
-            set_bits(this->player_ptr->update, (PU_MP | PU_SPELLS));
+            rfu.set_flags(flags);
         }
     }
 
-    set_bits(this->player_ptr->window_flags, PW_PLAYER);
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
 }
index abd859f..e5b382b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-ability/player-ability-types.h"
 #include "player-status/player-status-base.h"
index 2599fa2..98a61dd 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @file player-energy.cpp
  * @brief ゲームターン当たりの行動エネルギー増減処理
  * @author Hourier
index 18c88c1..d4a0460 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index bdd25a4..a14189b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!< Empty hand status */
 enum empty_hand_status {
index 58f8e29..54fd9e8 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-status/player-infravision.h"
+#include "player-status/player-infravision.h"
 #include "mutation/mutation-flag-types.h"
 #include "player-base/player-race.h"
 #include "player-info/mimic-info-table.h"
index 1da20b8..dea9344 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include "player-status/player-status-base.h"
 
 class PlayerInfravision : public PlayerStatusBase {
index 786c22b..08861c2 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-status/player-speed.h"
+#include "player-status/player-speed.h"
 #include "artifact/fixed-art-types.h"
 #include "grid/feature-flag-types.h"
 #include "grid/feature.h"
@@ -7,7 +7,6 @@
 #include "monster/monster-status.h"
 #include "mutation/mutation-flag-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/equipment-info.h"
@@ -306,9 +305,9 @@ int16_t PlayerSpeed::inventory_weight_bonus()
     int16_t bonus = 0;
     auto weight = calc_inventory_weight(this->player_ptr);
     if (this->player_ptr->riding) {
-        auto *riding_m_ptr = &(this->player_ptr)->current_floor_ptr->m_list[this->player_ptr->riding];
-        auto *riding_r_ptr = &monraces_info[riding_m_ptr->r_idx];
-        auto count = 1500 + riding_r_ptr->level * 25;
+        const auto &monster = this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding];
+        const auto &monrace = monster.get_monrace();
+        auto count = 1500 + monrace.level * 25;
         if (weight > count) {
             bonus -= ((weight - count) / (count / 5));
         }
index 0c9a528..a9eb955 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include "player-status/player-status-base.h"
 
 class PlayerSpeed : public PlayerStatusBase {
index 16fdfcb..a110159 100644 (file)
@@ -1,6 +1,5 @@
-#include "player-status/player-status-base.h"
+#include "player-status/player-status-base.h"
 #include "inventory/inventory-slot-types.h"
-#include "object/object-flags.h"
 #include "player/player-status.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
@@ -217,7 +216,7 @@ BIT_FLAGS PlayerStatusBase::equipments_flags(tr_type check_flag)
             continue;
         }
 
-        auto o_flags = object_flags(o_ptr);
+        const auto o_flags = o_ptr->get_flags();
         if (o_flags.has(check_flag)) {
             set_bits(flags, convert_inventory_slot_type_to_flag_cause(i2enum<inventory_slot_type>(i)));
         }
@@ -240,7 +239,7 @@ BIT_FLAGS PlayerStatusBase::equipments_bad_flags(tr_type check_flag)
             continue;
         }
 
-        auto o_flags = object_flags(o_ptr);
+        const auto o_flags = o_ptr->get_flags();
         if (o_flags.has(check_flag)) {
             if (o_ptr->pval < 0) {
                 set_bits(flags, convert_inventory_slot_type_to_flag_cause(i2enum<inventory_slot_type>(i)));
@@ -260,8 +259,8 @@ int16_t PlayerStatusBase::equipments_bonus()
     this->set_locals(); /* 計算前に値のセット。派生クラスの値がセットされる。*/
     int16_t bonus = 0;
     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
-        auto *o_ptr = &player_ptr->inventory_list[i];
-        auto o_flags = object_flags(o_ptr);
+        const auto *o_ptr = &player_ptr->inventory_list[i];
+        const auto o_flags = o_ptr->get_flags();
         if (!o_ptr->is_valid()) {
             continue;
         }
index f35dc94..fba2c68 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include "player/player-status-flags.h"
 #include "system/angband.h"
 
index 8a436c0..89dd9f3 100644 (file)
@@ -1,4 +1,4 @@
-#include "player-status/player-stealth.h"
+#include "player-status/player-stealth.h"
 #include "mind/mind-ninja.h"
 #include "mutation/mutation-flag-types.h"
 #include "player-base/player-class.h"
index 0d19abd..a6b14b6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include "player-status/player-status-base.h"
 
 class PlayerStealth : public PlayerStatusBase {
index f82fa96..bad6552 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum special_attack_type {
     ATTACK_CONFUSE = 0x00000001, /*!< プレイヤーのステータス:混乱打撃 */
index d160fdd..326be3e 100644 (file)
@@ -1,8 +1,6 @@
-#include "player/digestion-processor.h"
+#include "player/digestion-processor.h"
 #include "avatar/avatar.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "core/stuff-handler.h"
 #include "floor/wild.h"
@@ -17,7 +15,9 @@
 #include "player/player-status.h"
 #include "player/special-defense-types.h"
 #include "status/bad-status-setter.h"
+#include "system/angband-system.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-paralysis.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
@@ -29,7 +29,7 @@
  */
 void starve_player(PlayerType *player_ptr)
 {
-    if (player_ptr->phase_out) {
+    if (AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -214,8 +214,10 @@ bool set_food(PlayerType *player_ptr, TIME_EFFECT v)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->redraw |= (PR_HUNGER);
+
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(MainWindowRedrawingFlag::HUNGER);
     handle_stuff(player_ptr);
 
     return true;
index c59a578..d865df1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 95ebd3c..a5c7481 100644 (file)
@@ -1,13 +1,13 @@
-/*!
+/*!
  * @brief エルドリッチホラー処理
  * @date 2020/06/07
  * @author Hourier
  */
 
 #include "player/eldritch-horror.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "locale/english.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
 #include "player/player-status.h"
 #include "status/bad-status-setter.h"
 #include "status/base-status.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-hallucination.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
@@ -68,9 +70,9 @@ static bool process_mod_hallucination(PlayerType *player_ptr, std::string_view m
         return false;
     }
 
-    msg_format(_("%s%sの顔を見てしまった!", "You behold the %s visage of %s!"), funny_desc[randint0(funny_desc.size())].data(), m_name.data());
+    msg_format(_("%s%sの顔を見てしまった!", "You behold the %s visage of %s!"), rand_choice(funny_desc).data(), m_name.data());
     if (one_in_(3)) {
-        msg_print(funny_comments[randint0(funny_comments.size())]);
+        msg_print(rand_choice(funny_comments));
         BadStatusSetter(player_ptr).mod_hallucination(randint1(monrace.level));
     }
 
@@ -84,13 +86,13 @@ static bool process_mod_hallucination(PlayerType *player_ptr, std::string_view m
  */
 void sanity_blast(PlayerType *player_ptr, MonsterEntity *m_ptr, bool necro)
 {
-    if (player_ptr->phase_out || !w_ptr->character_dungeon) {
+    if (AngbandSystem::get_instance().is_phase_out() || !w_ptr->character_dungeon) {
         return;
     }
 
     int power = 100;
     if (!necro && m_ptr) {
-        auto *r_ptr = &monraces_info[m_ptr->ap_r_idx];
+        auto *r_ptr = &m_ptr->get_appearance_monrace();
         const auto m_name = monster_desc(player_ptr, m_ptr, 0);
         power = r_ptr->level / 2;
         if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
@@ -143,7 +145,7 @@ void sanity_blast(PlayerType *player_ptr, MonsterEntity *m_ptr, bool necro)
         }
     } else if (!necro) {
         get_mon_num_prep(player_ptr, get_nightmare, nullptr);
-        auto *r_ptr = &monraces_info[get_mon_num(player_ptr, 0, MAX_DEPTH, 0)];
+        auto *r_ptr = &monraces_info[get_mon_num(player_ptr, 0, MAX_DEPTH, PM_NONE)];
         power = r_ptr->level + 10;
         const auto &desc = r_ptr->name;
         get_mon_num_prep(player_ptr, nullptr, nullptr);
@@ -316,6 +318,6 @@ void sanity_blast(PlayerType *player_ptr, MonsterEntity *m_ptr, bool necro)
         break;
     }
 
-    player_ptr->update |= PU_BONUS;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
 }
index fd49350..8d82f74 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class MonsterEntity;
 class PlayerType;
index 266795f..07d6200 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/patron.h"
+#include "player/patron.h"
 #include "cmd-action/cmd-pet.h"
 #include "cmd-io/cmd-dump.h"
 #include "flavor/flavor-describer.h"
@@ -229,13 +229,13 @@ void Patron::gain_level_reward(PlayerType *player_ptr_, int chosen_reward)
         case REW_GOOD_OBJ:
             msg_format(_("%sの声がささやいた:", "The voice of %s whispers:"), this->name.data());
             msg_print(_("「我が与えし物を賢明に使うべし。」", "'Use my gift wisely.'"));
-            acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 1, false, false, false);
+            acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 1, false);
             reward = _("上質なアイテムを手に入れた。", "a good item");
             break;
         case REW_GREA_OBJ:
             msg_format(_("%sの声が響き渡った:", "The voice of %s booms out:"), this->name.data());
             msg_print(_("「我が与えし物を賢明に使うべし。」", "'Use my gift wisely.'"));
-            acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 1, true, false, false);
+            acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, 1, true);
             reward = _("高級品のアイテムを手に入れた。", "an excellent item");
             break;
         case REW_CHAOS_WP:
@@ -247,13 +247,13 @@ void Patron::gain_level_reward(PlayerType *player_ptr_, int chosen_reward)
         case REW_GOOD_OBS:
             msg_format(_("%sの声が響き渡った:", "The voice of %s booms out:"), this->name.data());
             msg_print(_("「汝の行いは貴き報いに値せり。」", "'Thy deed hath earned thee a worthy reward.'"));
-            acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, randint1(2) + 1, false, false, false);
+            acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, randint1(2) + 1, false);
             reward = _("上質なアイテムを手に入れた。", "good items");
             break;
         case REW_GREA_OBS:
             msg_format(_("%sの声が響き渡った:", "The voice of %s booms out:"), this->name.data());
             msg_print(_("「下僕よ、汝の献身への我が惜しみ無き報いを見るがよい。」", "'Behold, mortal, how generously I reward thy loyalty.'"));
-            acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, randint1(2) + 1, true, false, false);
+            acquirement(this->player_ptr, this->player_ptr->y, this->player_ptr->x, randint1(2) + 1, true);
             reward = _("高級品のアイテムを手に入れた。", "excellent items");
             break;
         case REW_TY_CURSE:
@@ -334,7 +334,7 @@ void Patron::gain_level_reward(PlayerType *player_ptr_, int chosen_reward)
             msg_format(_("%sの声が響き渡った:", "The voice of %s booms out:"), this->name.data());
             msg_print(_("「苦しむがよい、無能な愚か者よ!」", "'Suffer, pathetic fool!'"));
             fire_ball(this->player_ptr, AttributeType::DISINTEGRATE, 0, this->player_ptr->lev * 4, 4);
-            take_hit(this->player_ptr, DAMAGE_NOESCAPE, this->player_ptr->lev * 4, wrath_reason.data());
+            take_hit(this->player_ptr, DAMAGE_NOESCAPE, this->player_ptr->lev * 4, wrath_reason);
             reward = _("分解の球が発生した。", "generating disintegration ball");
             break;
         case REW_HEAL_FUL:
@@ -429,7 +429,7 @@ void Patron::gain_level_reward(PlayerType *player_ptr_, int chosen_reward)
         case REW_WRATH:
             msg_format(_("%sの声が轟き渡った:", "The voice of %s thunders:"), this->name.data());
             msg_print(_("「死ぬがよい、下僕よ!」", "'Die, mortal!'"));
-            take_hit(this->player_ptr, DAMAGE_LOSELIFE, this->player_ptr->lev * 4, wrath_reason.data());
+            take_hit(this->player_ptr, DAMAGE_LOSELIFE, this->player_ptr->lev * 4, wrath_reason);
             for (int stat = 0; stat < A_MAX; stat++) {
                 (void)dec_stat(this->player_ptr, stat, 10 + randint1(15), false);
             }
@@ -517,7 +517,7 @@ void Patron::gain_level_reward(PlayerType *player_ptr_, int chosen_reward)
 
     if (!reward.empty()) {
         const auto note = format(_("パトロンの報酬で%s", "The patron rewarded you with %s."), reward.data());
-        exe_write_diary(this->player_ptr, DIARY_DESCRIPTION, 0, note.data());
+        exe_write_diary(this->player_ptr, DiaryKind::DESCRIPTION, 0, note);
     }
 }
 
index 0f75287..34cf72f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
@@ -61,7 +61,6 @@ public:
 #else
     Patron(const char *name, std::vector<patron_reward> reward_table, const player_ability_type boost_stat);
 #endif
-    virtual ~Patron() = default;
 
     // @note C4458 クラスメンバーの隠蔽 への対応として末尾に「_」を付ける.
     void gain_level_reward(PlayerType *player_ptr_, int chosen_reward);
index e2cca43..70a9acd 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/permanent-resistances.h"
+#include "player/permanent-resistances.h"
 #include "inventory/inventory-slot-types.h"
 #include "mind/mind-elementalist.h"
 #include "mutation/mutation-flag-types.h"
index d223e98..d65c4c4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 25af3de..13cab81 100644 (file)
@@ -1,12 +1,10 @@
-#include "player/player-damage.h"
+#include "player/player-damage.h"
 #include "autopick/autopick-pref-processor.h"
 #include "avatar/avatar.h"
 #include "blue-magic/blue-magic-checker.h"
 #include "cmd-io/cmd-process-screen.h"
 #include "core/asking-player.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "dungeon/quest.h"
@@ -41,7 +39,6 @@
 #include "object-hook/hook-armor.h"
 #include "object/item-tester-hooker.h"
 #include "object/object-broken.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/class-info.h"
@@ -64,6 +61,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "timed-effect/player-hallucination.h"
@@ -76,7 +74,7 @@
 #include <sstream>
 #include <string>
 
-using dam_func = int (*)(PlayerType *player_ptr, int dam, concptr kb_str, bool aura);
+using dam_func = int (*)(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura);
 
 /*!
  * @brief 酸攻撃による装備のAC劣化処理 /
@@ -90,51 +88,44 @@ using dam_func = int (*)(PlayerType *player_ptr, int dam, concptr kb_str, bool a
  */
 static bool acid_minus_ac(PlayerType *player_ptr)
 {
-    ItemEntity *o_ptr = nullptr;
-    switch (randint1(7)) {
-    case 1:
-        o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND];
-        break;
-    case 2:
-        o_ptr = &player_ptr->inventory_list[INVEN_SUB_HAND];
-        break;
-    case 3:
-        o_ptr = &player_ptr->inventory_list[INVEN_BODY];
-        break;
-    case 4:
-        o_ptr = &player_ptr->inventory_list[INVEN_OUTER];
-        break;
-    case 5:
-        o_ptr = &player_ptr->inventory_list[INVEN_ARMS];
-        break;
-    case 6:
-        o_ptr = &player_ptr->inventory_list[INVEN_HEAD];
-        break;
-    case 7:
-        o_ptr = &player_ptr->inventory_list[INVEN_FEET];
-        break;
-    }
+    constexpr static auto candidates = {
+        INVEN_MAIN_HAND,
+        INVEN_SUB_HAND,
+        INVEN_BODY,
+        INVEN_OUTER,
+        INVEN_ARMS,
+        INVEN_HEAD,
+        INVEN_FEET,
+    };
+
+    const auto slot = rand_choice(candidates);
+    auto *o_ptr = &player_ptr->inventory_list[slot];
 
     if ((o_ptr == nullptr) || !o_ptr->is_valid() || !o_ptr->is_protector()) {
         return false;
     }
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, OD_OMIT_PREFIX | OD_NAME_ONLY);
-    auto flags = object_flags(o_ptr);
+    const auto item_flags = o_ptr->get_flags();
     if (o_ptr->ac + o_ptr->to_a <= 0) {
         msg_format(_("%sは既にボロボロだ!", "Your %s is already fully corroded!"), item_name.data());
         return false;
     }
 
-    if (flags.has(TR_IGNORE_ACID)) {
+    if (item_flags.has(TR_IGNORE_ACID)) {
         msg_format(_("しかし%sには効果がなかった!", "Your %s is unaffected!"), item_name.data());
         return true;
     }
 
     msg_format(_("%sが酸で腐食した!", "Your %s is corroded!"), item_name.data());
     o_ptr->to_a--;
-    player_ptr->update |= PU_BONUS;
-    player_ptr->window_flags |= PW_EQUIPMENT | PW_PLAYER;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags_swrf);
     calc_android_exp(player_ptr);
     return true;
 }
@@ -150,7 +141,7 @@ static bool acid_minus_ac(PlayerType *player_ptr)
  * @return 修正HPダメージ量
  * @details 酸オーラは存在しないが関数ポインタのために引数だけは用意している
  */
-int acid_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura)
+int acid_dam(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura)
 {
     int inv = (dam < 30) ? 1 : (dam < 60) ? 2
                                           : 3;
@@ -188,7 +179,7 @@ int acid_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura)
  * @param aura オーラよるダメージが原因ならばTRUE
  * @return 修正HPダメージ量
  */
-int elec_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura)
+int elec_dam(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura)
 {
     int inv = (dam < 30) ? 1 : (dam < 60) ? 2
                                           : 3;
@@ -224,7 +215,7 @@ int elec_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura)
  * @param aura オーラよるダメージが原因ならばTRUE
  * @return 修正HPダメージ量
  */
-int fire_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura)
+int fire_dam(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura)
 {
     int inv = (dam < 30) ? 1 : (dam < 60) ? 2
                                           : 3;
@@ -260,7 +251,7 @@ int fire_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura)
  * @param aura オーラよるダメージが原因ならばTRUE
  * @return 修正HPダメージ量
  */
-int cold_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura)
+int cold_dam(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura)
 {
     int inv = (dam < 30) ? 1 : (dam < 60) ? 2
                                           : 3;
@@ -293,7 +284,7 @@ int cold_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura)
  * the game when he dies, since the "You die." message is shown before
  * setting the player to "dead".
  */
-int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr hit_from)
+int take_hit(PlayerType *player_ptr, int damage_type, int damage, std::string_view hit_from)
 {
     int old_chp = player_ptr->chp;
     int warning = (player_ptr->mhp * hitpoint_warn / 10);
@@ -363,8 +354,9 @@ int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr hit_fr
         player_ptr->chp = 0;
     }
 
-    player_ptr->redraw |= PR_HP;
-    player_ptr->window_flags |= PW_PLAYER;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::HP);
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
 
     if (damage_type != DAMAGE_GENO && player_ptr->chp == 0) {
         chg_virtue(player_ptr, Virtue::SACRIFICE, 1);
@@ -387,18 +379,18 @@ int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr hit_fr
             player_ptr->is_dead = true;
         }
 
-        const auto &floor_ref = *player_ptr->current_floor_ptr;
-        if (floor_ref.inside_arena) {
-            concptr m_name = monraces_info[arena_info[player_ptr->arena_number].r_idx].name.data();
-            msg_format(_("あなたは%sの前に敗れ去った。", "You are beaten by %s."), m_name);
+        const auto &floor = *player_ptr->current_floor_ptr;
+        if (floor.inside_arena) {
+            const auto &m_name = monraces_info[arena_info[player_ptr->arena_number].r_idx].name;
+            msg_format(_("あなたは%sの前に敗れ去った。", "You are beaten by %s."), m_name.data());
             msg_print(nullptr);
             if (record_arena) {
-                exe_write_diary(player_ptr, DIARY_ARENA, -1 - player_ptr->arena_number, m_name);
+                exe_write_diary(player_ptr, DiaryKind::ARENA, -1 - player_ptr->arena_number, m_name);
             }
         } else {
-            auto q_idx = quest_number(player_ptr, floor_ref.dun_level);
-            bool seppuku = streq(hit_from, "Seppuku");
-            bool winning_seppuku = w_ptr->total_winner && seppuku;
+            const auto q_idx = floor.get_quest_id();
+            const auto seppuku = hit_from == "Seppuku";
+            const auto winning_seppuku = w_ptr->total_winner && seppuku;
 
             play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_GAMEOVER);
 
@@ -420,50 +412,46 @@ int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr hit_fr
 
                 auto hallucintion_state = is_hallucinated ? _("幻覚に歪んだ", "hallucinatingly distorted ") : "";
 #ifdef JP
-                player_ptr->died_from = format("%s%s%s", paralysis_state, hallucintion_state, hit_from);
+                player_ptr->died_from = format("%s%s%s", paralysis_state, hallucintion_state, hit_from.data());
 #else
-                player_ptr->died_from = format("%s%s%s", hallucintion_state, hit_from, paralysis_state);
+                player_ptr->died_from = format("%s%s%s", hallucintion_state, hit_from.data(), paralysis_state);
 #endif
             }
 
             w_ptr->total_winner = false;
             if (winning_seppuku) {
-                add_retired_class(player_ptr->pclass);
-                exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, _("勝利の後切腹した。", "committed seppuku after the winning."));
+                w_ptr->add_retired_class(player_ptr->pclass);
+                exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, _("勝利の後切腹した。", "committed seppuku after the winning."));
             } else {
                 std::string place;
 
-                if (floor_ref.inside_arena) {
+                if (floor.inside_arena) {
                     place = _("アリーナ", "in the Arena");
-                } else if (!floor_ref.is_in_dungeon()) {
+                } else if (!floor.is_in_dungeon()) {
                     place = _("地上", "on the surface");
                 } else if (inside_quest(q_idx) && (QuestType::is_fixed(q_idx) && !((q_idx == QuestId::OBERON) || (q_idx == QuestId::SERPENT)))) {
                     place = _("クエスト", "in a quest");
                 } else {
-                    place = format(_("%d階", "on level %d"), static_cast<int>(floor_ref.dun_level));
+                    place = format(_("%d階", "on level %d"), static_cast<int>(floor.dun_level));
                 }
 
 #ifdef JP
-                std::string note = format("%sで%sに殺された。", place.data(), player_ptr->died_from.data());
+                const auto note = format("%sで%sに殺された。", place.data(), player_ptr->died_from.data());
 #else
-                std::string note = format("killed by %s %s.", player_ptr->died_from.data(), place.data());
+                const auto note = format("killed by %s %s.", player_ptr->died_from.data(), place.data());
 #endif
-                exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, note.data());
+                exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, note);
             }
 
-            exe_write_diary(player_ptr, DIARY_GAMESTART, 1, _("-------- ゲームオーバー --------", "--------   Game  Over   --------"));
-            exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, "\n\n\n\n");
+            exe_write_diary(player_ptr, DiaryKind::GAMESTART, 1, _("-------- ゲームオーバー --------", "--------   Game  Over   --------"));
+            exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, "\n\n\n\n");
             flush();
-            if (get_check_strict(player_ptr, _("画面を保存しますか?", "Dump the screen? "), CHECK_NO_HISTORY)) {
+            if (input_check_strict(player_ptr, _("画面を保存しますか?", "Dump the screen? "), UserCheck::NO_HISTORY)) {
                 do_cmd_save_screen(player_ptr);
             }
 
             flush();
-            if (player_ptr->last_message) {
-                string_free(player_ptr->last_message);
-            }
-
-            player_ptr->last_message = nullptr;
+            player_ptr->last_message = "";
             if (!last_words) {
 #ifdef JP
                 msg_format("あなたは%sました。", android ? "壊れ" : "死に");
@@ -473,30 +461,28 @@ int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr hit_fr
 
                 msg_print(nullptr);
             } else {
-                std::optional<std::string> opt_death_message;
+                std::optional<std::string> death_message_opt;
                 if (winning_seppuku) {
-                    opt_death_message = get_random_line(_("seppuku_j.txt", "seppuku.txt"), 0);
+                    death_message_opt = get_random_line(_("seppuku_j.txt", "seppuku.txt"), 0);
                 } else {
-                    opt_death_message = get_random_line(_("death_j.txt", "death.txt"), 0);
+                    death_message_opt = get_random_line(_("death_j.txt", "death.txt"), 0);
                 }
 
-                auto &death_message = opt_death_message.value();
+                auto &death_message = *death_message_opt;
                 constexpr auto max_last_words = 1024;
-                char player_last_words[max_last_words]{};
-                angband_strcpy(player_last_words, death_message.data(), max_last_words);
-                do {
-#ifdef JP
-                    while (!get_string(winning_seppuku ? "辞世の句: " : "断末魔の叫び: ", player_last_words, max_last_words)) {
-                        ;
+                const auto prompt = winning_seppuku ? _("辞世の句: ", "Haiku: ") : _("断末魔の叫び: ", "Last words: ");
+                while (true) {
+                    const auto input_last_words = input_string(prompt, max_last_words, death_message);
+                    if (!input_last_words) {
+                        continue;
                     }
-#else
-                    while (!get_string("Last words: ", player_last_words, max_last_words)) {
-                        ;
+
+                    if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::NO_HISTORY)) {
+                        death_message = *input_last_words;
+                        break;
                     }
-#endif
-                } while (winning_seppuku && !get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_NO_HISTORY));
+                }
 
-                death_message = player_last_words;
                 if (death_message.empty()) {
 #ifdef JP
                     death_message = format("あなたは%sました。", android ? "壊れ" : "死に");
@@ -504,7 +490,7 @@ int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr hit_fr
                     death_message = android ? "You are broken." : "You die.";
 #endif
                 } else {
-                    player_ptr->last_message = string_make(death_message.data());
+                    player_ptr->last_message = death_message;
                 }
 
 #ifdef JP
@@ -584,7 +570,7 @@ int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr hit_fr
             ss << _(hit_from, "was in a critical situation because of ");
             ss << _("によってピンチに陥った。", hit_from);
             ss << _("", ".");
-            exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0, ss.str().data());
+            exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 0, ss.str());
         }
 
         if (auto_more) {
@@ -615,7 +601,7 @@ int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr hit_fr
  */
 static void process_aura_damage(MonsterEntity *m_ptr, PlayerType *player_ptr, bool immune, MonsterAuraType aura_flag, dam_func dam_func, concptr message)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
     if (r_ptr->aura_flags.has_not(aura_flag) || immune) {
         return;
     }
index 03afec3..7b5fe87 100644 (file)
@@ -1,6 +1,6 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <string_view>
 
 #define DAMAGE_FORCE 1
 #define DAMAGE_GENO 2
@@ -11,9 +11,9 @@
 
 class MonsterEntity;
 class PlayerType;
-int take_hit(PlayerType *player_ptr, int damage_type, int damage, concptr kb_str);
-int acid_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura);
-int elec_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura);
-int fire_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura);
-int cold_dam(PlayerType *player_ptr, int dam, concptr kb_str, bool aura);
+int take_hit(PlayerType *player_ptr, int damage_type, int damage, std::string_view kb_str);
+int acid_dam(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura);
+int elec_dam(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura);
+int fire_dam(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura);
+int cold_dam(PlayerType *player_ptr, int dam, std::string_view kb_str, bool aura);
 void touch_zap_player(MonsterEntity *m_ptr, PlayerType *player_ptr);
index b737465..d5bc3a0 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  *  @brief プレイヤーの移動処理 / Movement commands
  *  @date 2014/01/02
  *  @author
@@ -7,8 +7,6 @@
 
 #include "player/player-move.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/special-internal-keys.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
@@ -45,6 +43,7 @@
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/target-checker.h"
 #include "timed-effect/player-blindness.h"
@@ -67,37 +66,35 @@ POSITION temp2_y[MAX_SHORT];
  * @param y 対象となるマスのY座標
  * @param x 対象となるマスのX座標
  */
-static void discover_hidden_things(PlayerType *player_ptr, POSITION y, POSITION x)
+static void discover_hidden_things(PlayerType *player_ptr, const Pos2D &pos)
 {
-    grid_type *g_ptr;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    g_ptr = &floor_ptr->grid_array[y][x];
-    if (g_ptr->mimic && is_trap(player_ptr, g_ptr->feat)) {
-        disclose_grid(player_ptr, y, x);
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.get_grid(pos);
+    if (grid.mimic && is_trap(player_ptr, grid.feat)) {
+        disclose_grid(player_ptr, pos.y, pos.x);
         msg_print(_("トラップを発見した。", "You have found a trap."));
         disturb(player_ptr, false, true);
     }
 
-    if (is_hidden_door(player_ptr, g_ptr)) {
+    if (is_hidden_door(player_ptr, grid)) {
         msg_print(_("隠しドアを発見した。", "You have found a secret door."));
-        disclose_grid(player_ptr, y, x);
+        disclose_grid(player_ptr, pos.y, pos.x);
         disturb(player_ptr, false, false);
     }
 
-    for (const auto this_o_idx : g_ptr->o_idx_list) {
-        ItemEntity *o_ptr;
-        o_ptr = &floor_ptr->o_list[this_o_idx];
-        if (o_ptr->bi_key.tval() != ItemKindType::CHEST) {
+    for (const auto this_o_idx : grid.o_idx_list) {
+        auto &item = floor.o_list[this_o_idx];
+        if (item.bi_key.tval() != ItemKindType::CHEST) {
             continue;
         }
 
-        if (o_ptr->pval <= 0 || chest_traps[o_ptr->pval].none()) {
+        if (item.pval <= 0 || chest_traps[item.pval].none()) {
             continue;
         }
 
-        if (!o_ptr->is_known()) {
+        if (!item.is_known()) {
             msg_print(_("箱に仕掛けられたトラップを発見した!", "You have discovered a trap on the chest!"));
-            object_known(o_ptr);
+            item.mark_as_known();
             disturb(player_ptr, false, false);
         }
     }
@@ -121,7 +118,7 @@ void search(PlayerType *player_ptr)
 
     for (DIRECTION i = 0; i < 9; ++i) {
         if (randint0(100) < chance) {
-            discover_hidden_things(player_ptr, player_ptr->y + ddy_ddd[i], player_ptr->x + ddx_ddd[i]);
+            discover_hidden_things(player_ptr, { player_ptr->y + ddy_ddd[i], player_ptr->x + ddx_ddd[i] });
         }
     }
 }
@@ -136,53 +133,64 @@ void search(PlayerType *player_ptr)
  */
 bool move_player_effect(PlayerType *player_ptr, POSITION ny, POSITION nx, BIT_FLAGS mpe_mode)
 {
-    POSITION oy = player_ptr->y;
-    POSITION ox = player_ptr->x;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ptr->grid_array[ny][nx];
-    grid_type *oc_ptr = &floor_ptr->grid_array[oy][ox];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
-    TerrainType *of_ptr = &terrains_info[oc_ptr->feat];
-
+    const Pos2D pos_new(ny, nx);
+    const Pos2D pos_old(player_ptr->y, player_ptr->x);
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &grid_new = floor.get_grid(pos_new);
+    auto &grid_old = floor.get_grid(pos_old);
+    const auto &terrain_new = grid_new.get_terrain();
+    const auto &terrain_old = grid_old.get_terrain();
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (!(mpe_mode & MPE_STAYING)) {
-        MONSTER_IDX om_idx = oc_ptr->m_idx;
-        MONSTER_IDX nm_idx = g_ptr->m_idx;
-        player_ptr->y = ny;
-        player_ptr->x = nx;
+        const auto om_idx = grid_old.m_idx;
+        const auto nm_idx = grid_new.m_idx;
+        player_ptr->y = pos_new.y;
+        player_ptr->x = pos_new.x;
         if (!(mpe_mode & MPE_DONT_SWAP_MON)) {
-            g_ptr->m_idx = om_idx;
-            oc_ptr->m_idx = nm_idx;
+            grid_new.m_idx = om_idx;
+            grid_old.m_idx = nm_idx;
             if (om_idx > 0) {
-                MonsterEntity *om_ptr = &floor_ptr->m_list[om_idx];
-                om_ptr->fy = ny;
-                om_ptr->fx = nx;
+                MonsterEntity *om_ptr = &floor.m_list[om_idx];
+                om_ptr->fy = pos_new.y;
+                om_ptr->fx = pos_new.x;
                 update_monster(player_ptr, om_idx, true);
             }
 
             if (nm_idx > 0) {
-                MonsterEntity *nm_ptr = &floor_ptr->m_list[nm_idx];
-                nm_ptr->fy = oy;
-                nm_ptr->fx = ox;
+                MonsterEntity *nm_ptr = &floor.m_list[nm_idx];
+                nm_ptr->fy = pos_old.y;
+                nm_ptr->fx = pos_old.x;
                 update_monster(player_ptr, nm_idx, true);
             }
         }
 
-        lite_spot(player_ptr, oy, ox);
-        lite_spot(player_ptr, ny, nx);
+        lite_spot(player_ptr, pos_old.y, pos_old.x);
+        lite_spot(player_ptr, pos_new.y, pos_new.x);
         verify_panel(player_ptr);
         if (mpe_mode & MPE_FORGET_FLOW) {
-            forget_flow(floor_ptr);
-            player_ptr->update |= PU_UN_VIEW;
-            player_ptr->redraw |= PR_MAP;
+            forget_flow(&floor);
+            rfu.set_flag(StatusRecalculatingFlag::UN_VIEW);
+            rfu.set_flag(MainWindowRedrawingFlag::MAP);
         }
 
-        player_ptr->update |= PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTER_LITE | PU_DISTANCE;
-        player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
-        if ((!player_ptr->effects()->blindness()->is_blind() && !no_lite(player_ptr)) || !is_trap(player_ptr, g_ptr->feat)) {
-            g_ptr->info &= ~(CAVE_UNSAFE);
+        static constexpr auto flags_srf = {
+            StatusRecalculatingFlag::VIEW,
+            StatusRecalculatingFlag::LITE,
+            StatusRecalculatingFlag::FLOW,
+            StatusRecalculatingFlag::MONSTER_LITE,
+            StatusRecalculatingFlag::DISTANCE,
+        };
+        rfu.set_flags(flags_srf);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::OVERHEAD,
+            SubWindowRedrawingFlag::DUNGEON,
+        };
+        rfu.set_flags(flags_swrf);
+        if ((!player_ptr->effects()->blindness()->is_blind() && !no_lite(player_ptr)) || !is_trap(player_ptr, grid_new.feat)) {
+            grid_new.info &= ~(CAVE_UNSAFE);
         }
 
-        if (floor_ptr->dun_level && dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::FORGET)) {
+        if (floor.dun_level && floor.get_dungeon_definition().flags.has(DungeonFeatureType::FORGET)) {
             wiz_dark(player_ptr);
         }
 
@@ -191,30 +199,32 @@ bool move_player_effect(PlayerType *player_ptr, POSITION ny, POSITION nx, BIT_FL
         }
 
         if (PlayerClass(player_ptr).equals(PlayerClassType::NINJA)) {
-            if (g_ptr->info & (CAVE_GLOW)) {
+            if (grid_new.info & (CAVE_GLOW)) {
                 set_superstealth(player_ptr, false);
             } else if (player_ptr->cur_lite <= 0) {
                 set_superstealth(player_ptr, true);
             }
         }
 
-        if ((player_ptr->action == ACTION_HAYAGAKE) && (f_ptr->flags.has_not(TerrainCharacteristics::PROJECT) || (!player_ptr->levitation && f_ptr->flags.has(TerrainCharacteristics::DEEP)))) {
+        using Tc = TerrainCharacteristics;
+        if ((player_ptr->action == ACTION_HAYAGAKE) && (terrain_new.flags.has_not(Tc::PROJECT) || (!player_ptr->levitation && terrain_new.flags.has(Tc::DEEP)))) {
             msg_print(_("ここでは素早く動けない。", "You cannot run in here."));
             set_action(player_ptr, ACTION_NONE);
         }
 
         if (PlayerRace(player_ptr).equals(PlayerRaceType::MERFOLK)) {
-            if (f_ptr->flags.has(TerrainCharacteristics::WATER) ^ of_ptr->flags.has(TerrainCharacteristics::WATER)) {
-                player_ptr->update |= PU_BONUS;
+            if (terrain_new.flags.has(Tc::WATER) ^ terrain_old.flags.has(Tc::WATER)) {
+                rfu.set_flag(StatusRecalculatingFlag::BONUS);
                 update_creature(player_ptr);
             }
         }
     }
 
+    const Pos2D pos(ny, nx);
     if (mpe_mode & MPE_ENERGY_USE) {
         if (music_singing(player_ptr, MUSIC_WALL)) {
             (void)project(player_ptr, 0, 0, player_ptr->y, player_ptr->x, (60 + player_ptr->lev), AttributeType::DISINTEGRATE, PROJECT_KILL | PROJECT_ITEM);
-            if (!player_bold(player_ptr, ny, nx) || player_ptr->is_dead || player_ptr->leaving) {
+            if (!player_ptr->is_located_at(pos) || player_ptr->is_dead || player_ptr->leaving) {
                 return false;
             }
         }
@@ -232,55 +242,59 @@ bool move_player_effect(PlayerType *player_ptr, POSITION ny, POSITION nx, BIT_FL
         carry(player_ptr, any_bits(mpe_mode, MPE_DO_PICKUP));
     }
 
+    // 自動拾い/自動破壊により床上のアイテムリストが変化した可能性があるので表示を更新
     if (!player_ptr->running) {
-        // 自動拾い/自動破壊により床上のアイテムリストが変化した可能性があるので表示を更新
-        set_bits(player_ptr->window_flags, PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::FLOOR_ITEMS,
+            SubWindowRedrawingFlag::FOUND_ITEMS,
+        };
+        rfu.set_flags(flags_swrf);
         window_stuff(player_ptr);
     }
 
     PlayerEnergy energy(player_ptr);
-    if (f_ptr->flags.has(TerrainCharacteristics::STORE)) {
+    if (terrain_new.flags.has(TerrainCharacteristics::STORE)) {
         disturb(player_ptr, false, true);
         energy.reset_player_turn();
         command_new = SPECIAL_KEY_STORE;
-    } else if (f_ptr->flags.has(TerrainCharacteristics::BLDG)) {
+    } else if (terrain_new.flags.has(TerrainCharacteristics::BLDG)) {
         disturb(player_ptr, false, true);
         energy.reset_player_turn();
         command_new = SPECIAL_KEY_BUILDING;
-    } else if (f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER)) {
+    } else if (terrain_new.flags.has(TerrainCharacteristics::QUEST_ENTER)) {
         disturb(player_ptr, false, true);
         energy.reset_player_turn();
         command_new = SPECIAL_KEY_QUEST;
-    } else if (f_ptr->flags.has(TerrainCharacteristics::QUEST_EXIT)) {
+    } else if (terrain_new.flags.has(TerrainCharacteristics::QUEST_EXIT)) {
         const auto &quest_list = QuestList::get_instance();
-        if (quest_list[floor_ptr->quest_number].type == QuestKindType::FIND_EXIT) {
-            complete_quest(player_ptr, floor_ptr->quest_number);
+        if (quest_list[floor.quest_number].type == QuestKindType::FIND_EXIT) {
+            complete_quest(player_ptr, floor.quest_number);
         }
         leave_quest_check(player_ptr);
-        floor_ptr->quest_number = i2enum<QuestId>(g_ptr->special);
-        floor_ptr->dun_level = 0;
-        if (!inside_quest(floor_ptr->quest_number)) {
+        floor.quest_number = i2enum<QuestId>(grid_new.special);
+        floor.dun_level = 0;
+        if (!floor.is_in_quest()) {
             player_ptr->word_recall = 0;
         }
         player_ptr->oldpx = 0;
         player_ptr->oldpy = 0;
         player_ptr->leaving = true;
-    } else if (f_ptr->flags.has(TerrainCharacteristics::HIT_TRAP) && !(mpe_mode & MPE_STAYING)) {
+    } else if (terrain_new.flags.has(TerrainCharacteristics::HIT_TRAP) && !(mpe_mode & MPE_STAYING)) {
         disturb(player_ptr, false, true);
-        if (g_ptr->mimic || f_ptr->flags.has(TerrainCharacteristics::SECRET)) {
+        if (grid_new.mimic || terrain_new.flags.has(TerrainCharacteristics::SECRET)) {
             msg_print(_("トラップだ!", "You found a trap!"));
             disclose_grid(player_ptr, player_ptr->y, player_ptr->x);
         }
 
         hit_trap(player_ptr, any_bits(mpe_mode, MPE_BREAK_TRAP));
-        if (!player_bold(player_ptr, ny, nx) || player_ptr->is_dead || player_ptr->leaving) {
+        if (!player_ptr->is_located_at(pos) || player_ptr->is_dead || player_ptr->leaving) {
             return false;
         }
     }
 
-    if (!(mpe_mode & MPE_STAYING) && (disturb_trap_detect || alert_trap_detect) && player_ptr->dtrap && !(g_ptr->info & CAVE_IN_DETECT)) {
+    if (!(mpe_mode & MPE_STAYING) && (disturb_trap_detect || alert_trap_detect) && player_ptr->dtrap && !(grid_new.info & CAVE_IN_DETECT)) {
         player_ptr->dtrap = false;
-        if (!(g_ptr->info & CAVE_UNSAFE)) {
+        if (!(grid_new.info & CAVE_UNSAFE)) {
             if (alert_trap_detect) {
                 msg_print(_("* 注意:この先はトラップの感知範囲外です! *", "*Leaving trap detect region!*"));
             }
@@ -291,7 +305,7 @@ bool move_player_effect(PlayerType *player_ptr, POSITION ny, POSITION nx, BIT_FL
         }
     }
 
-    return player_bold(player_ptr, ny, nx) && !player_ptr->is_dead && !player_ptr->leaving;
+    return player_ptr->is_located_at(pos) && !player_ptr->is_dead && !player_ptr->leaving;
 }
 
 /*!
@@ -302,12 +316,12 @@ bool move_player_effect(PlayerType *player_ptr, POSITION ny, POSITION nx, BIT_FL
  */
 bool trap_can_be_ignored(PlayerType *player_ptr, FEAT_IDX feat)
 {
-    auto *f_ptr = &terrains_info[feat];
-    if (f_ptr->flags.has_not(TerrainCharacteristics::TRAP)) {
+    const auto &terrain = TerrainList::get_instance()[feat];
+    if (terrain.flags.has_not(TerrainCharacteristics::TRAP)) {
         return true;
     }
 
-    switch (i2enum<TrapType>(f_ptr->subtype)) {
+    switch (i2enum<TrapType>(terrain.subtype)) {
     case TrapType::TRAPDOOR:
     case TrapType::PIT:
     case TrapType::SPIKED_PIT:
index 6656e11..cc9b59d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 8ba70d8..9f50910 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum player_personality_type {
     PERSONALITY_ORDINARY = 0,
index 5c2bcca..10a0bc2 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/player-personality.h"
+#include "player/player-personality.h"
 #include "mutation/mutation-flag-types.h"
 #include "object-enchant/trc-types.h"
 
index aa48593..5f25c87 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player/player-personality-types.h"
 #include "system/angband.h"
index cd116e3..5905f94 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/player-realm.h"
+#include "player/player-realm.h"
 #include "object/tval-types.h"
 #include "system/player-type-definition.h"
 
index c193795..7db6efe 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <vector>
index b1fe5e6..7552c5b 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/player-sex.h"
+#include "player/player-sex.h"
 
 /*
  * Pointer to the player tables
index 7f76f0d..2206700 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index df6a175..a3b80d8 100644 (file)
@@ -1,16 +1,17 @@
-#include "player/player-skill.h"
-#include "core/player-update-types.h"
+#include "player/player-skill.h"
 #include "monster-race/monster-race.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/class-info.h"
 #include "player/player-realm.h"
+#include "realm/realm-names-table.h"
 #include "sv-definition/sv-weapon-types.h"
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 
 /* Proficiency of weapons and misc. skills (except riding) */
@@ -61,7 +62,7 @@ void gain_attack_skill_exp(PlayerType *player_ptr, short &exp, const GainAmountL
     }
 
     exp += static_cast<short>(gain_amount);
-    set_bits(player_ptr->update, PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 void gain_spell_skill_exp_aux(PlayerType *player_ptr, short &exp, const GainAmountList &gain_amount_list, int spell_level)
@@ -91,7 +92,7 @@ void gain_spell_skill_exp_aux(PlayerType *player_ptr, short &exp, const GainAmou
     }
 
     exp += static_cast<short>(gain_amount);
-    set_bits(player_ptr->update, PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 }
@@ -305,7 +306,7 @@ void PlayerSkill::gain_riding_skill_exp_on_melee_attack(const MonsterRaceInfo *r
     }
 
     this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] = std::min<SUB_EXP>(max_exp, now_exp + inc);
-    set_bits(this->player_ptr->update, PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 void PlayerSkill::gain_riding_skill_exp_on_range_attack()
@@ -316,9 +317,12 @@ void PlayerSkill::gain_riding_skill_exp_on_range_attack()
         return;
     }
 
-    if (((this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] - (RIDING_EXP_BEGINNER * 2)) / 200 < monraces_info[this->player_ptr->current_floor_ptr->m_list[this->player_ptr->riding].r_idx].level) && one_in_(2)) {
+    const auto *floor_ptr = this->player_ptr->current_floor_ptr;
+    const auto &monster = floor_ptr->m_list[this->player_ptr->riding];
+    const auto &monrace = monster.get_monrace();
+    if (((this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] - (RIDING_EXP_BEGINNER * 2)) / 200 < monrace.level) && one_in_(2)) {
         this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] += 1;
-        set_bits(this->player_ptr->update, PU_BONUS);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     }
 }
 
@@ -344,17 +348,17 @@ void PlayerSkill::gain_riding_skill_exp_on_fall_off_check(int dam)
     }
 
     this->player_ptr->skill_exp[PlayerSkillKindType::RIDING] = std::min<SUB_EXP>(max_exp, now_exp + inc);
-    set_bits(this->player_ptr->update, PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
 
 void PlayerSkill::gain_spell_skill_exp(int realm, int spell_idx)
 {
-    if ((realm < 1) || ((static_cast<int>(std::size(mp_ptr->info)) < realm) && (realm != REALM_MUSIC) && (realm != REALM_HEX))) {
-        return;
-    }
+    auto is_valid_realm = is_magic(realm) ||
+                          (realm == REALM_MUSIC) || (realm == REALM_HEX);
+    is_valid_realm &= (realm == this->player_ptr->realm1) || (realm == this->player_ptr->realm2);
+    const auto is_valid_spell_idx = (0 <= spell_idx) && (spell_idx < 32);
 
-    if (((spell_idx < 0) || (32 <= spell_idx)) ||
-        ((realm != this->player_ptr->realm1) && (realm != this->player_ptr->realm2))) {
+    if (!is_valid_realm || !is_valid_spell_idx) {
         return;
     }
 
@@ -362,7 +366,7 @@ void PlayerSkill::gain_spell_skill_exp(int realm, int spell_idx)
     constexpr GainAmountList gain_amount_list_second{ { 60, 8, 2, 0 } };
 
     const auto is_first_realm = (realm == this->player_ptr->realm1);
-    const auto *s_ptr = &mp_ptr->info[realm - 1][spell_idx];
+    const auto *s_ptr = is_magic(realm) ? &mp_ptr->info[realm - 1][spell_idx] : &technic_info[realm - MIN_TECHNIC][spell_idx];
 
     gain_spell_skill_exp_aux(this->player_ptr, this->player_ptr->spell_exp[spell_idx + (is_first_realm ? 0 : 32)],
         (is_first_realm ? gain_amount_list_first : gain_amount_list_second), s_ptr->slevel);
@@ -404,8 +408,7 @@ PlayerSkillRank PlayerSkill::gain_spell_skill_exp_over_learning(int spell_idx)
         exp = SPELL_EXP_BEGINNER + exp / 3;
     }
 
-    set_bits(this->player_ptr->update, PU_BONUS);
-
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     return PlayerSkill::spell_skill_rank(exp);
 }
 
index 762e3cd..4447d25 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 2709147..1ae2b98 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/player-status-flags.h"
+#include "player/player-status-flags.h"
 #include "artifact/fixed-art-types.h"
 #include "inventory/inventory-slot-types.h"
 #include "mind/mind-elementalist.h"
@@ -10,7 +10,6 @@
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
 #include "object-hook/hook-weapon.h"
-#include "object/object-flags.h"
 #include "player-ability/player-charisma.h"
 #include "player-ability/player-constitution.h"
 #include "player-ability/player-dexterity.h"
@@ -48,7 +47,6 @@
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 
 namespace {
@@ -129,7 +127,7 @@ BIT_FLAGS check_equipment_flags(PlayerType *player_ptr, tr_type tr_flag)
             continue;
         }
 
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
 
         if (flags.has(tr_flag)) {
             set_bits(result, convert_inventory_slot_type_to_flag_cause(i2enum<inventory_slot_type>(i)));
@@ -430,7 +428,9 @@ BIT_FLAGS get_player_flags(PlayerType *player_ptr, tr_type tr_flag)
     case TR_COWARDICE:
     case TR_LOW_MELEE:
     case TR_LOW_AC:
+        return check_equipment_flags(player_ptr, tr_flag);
     case TR_HARD_SPELL:
+        return has_hard_spell(player_ptr);
     case TR_FAST_DIGEST:
     case TR_SLOW_REGEN:
         return check_equipment_flags(player_ptr, tr_flag);
@@ -442,8 +442,8 @@ BIT_FLAGS get_player_flags(PlayerType *player_ptr, tr_type tr_flag)
         return has_down_saving(player_ptr);
     case TR_NO_AC:
         return has_no_ac(player_ptr);
-    case TR_HEAVY_SPELL:
-        return has_heavy_spell(player_ptr);
+    case TR_XXX_142:
+        return check_equipment_flags(player_ptr, tr_flag);
     case TR_INVULN_ARROW:
         return has_invuln_arrow(player_ptr);
     case TR_DARK_SOURCE:
@@ -488,15 +488,13 @@ bool has_kill_wall(PlayerType *player_ptr)
         return true;
     }
 
-    if (player_ptr->riding) {
-        MonsterEntity *riding_m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-        MonsterRaceInfo *riding_r_ptr = &monraces_info[riding_m_ptr->r_idx];
-        if (riding_r_ptr->feature_flags.has(MonsterFeatureType::KILL_WALL)) {
-            return true;
-        }
+    if (player_ptr->riding == 0) {
+        return false;
     }
 
-    return false;
+    const auto &riding_monster = player_ptr->current_floor_ptr->m_list[player_ptr->riding];
+    const auto &riding_monrace = riding_monster.get_monrace();
+    return riding_monrace.feature_flags.has(MonsterFeatureType::KILL_WALL);
 }
 
 /*!
@@ -509,21 +507,17 @@ bool has_kill_wall(PlayerType *player_ptr)
  */
 bool has_pass_wall(PlayerType *player_ptr)
 {
-    bool pow = false;
-
     if (player_ptr->wraith_form || player_ptr->tim_pass_wall || PlayerRace(player_ptr).equals(PlayerRaceType::SPECTRE)) {
-        pow = true;
+        return true;
     }
 
-    if (player_ptr->riding) {
-        MonsterEntity *riding_m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-        MonsterRaceInfo *riding_r_ptr = &monraces_info[riding_m_ptr->r_idx];
-        if (riding_r_ptr->feature_flags.has_not(MonsterFeatureType::PASS_WALL)) {
-            pow = false;
-        }
+    if (player_ptr->riding == 0) {
+        return false;
     }
 
-    return pow;
+    const auto &monster = player_ptr->current_floor_ptr->m_list[player_ptr->riding];
+    const auto &monrace = monraces_info[monster.r_idx];
+    return monrace.feature_flags.has(MonsterFeatureType::PASS_WALL);
 }
 
 /*!
@@ -803,7 +797,7 @@ BIT_FLAGS has_warning(PlayerType *player_ptr)
             continue;
         }
 
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
 
         if (flags.has(TR_WARNING)) {
             if (!o_ptr->is_inscribed() || !angband_strchr(o_ptr->inscription->data(), '$')) {
@@ -870,9 +864,9 @@ BIT_FLAGS has_easy_spell(PlayerType *player_ptr)
     return common_cause_flags(player_ptr, TR_EASY_SPELL);
 }
 
-BIT_FLAGS has_heavy_spell(PlayerType *player_ptr)
+BIT_FLAGS has_hard_spell(PlayerType *player_ptr)
 {
-    return common_cause_flags(player_ptr, TR_HEAVY_SPELL);
+    return common_cause_flags(player_ptr, TR_HARD_SPELL);
 }
 
 BIT_FLAGS has_hold_exp(PlayerType *player_ptr)
@@ -1004,27 +998,24 @@ BIT_FLAGS has_levitation(PlayerType *player_ptr)
     }
 
     // 乗馬中は実際に浮遊するかどうかは乗馬中のモンスターに依存する
-    if (player_ptr->riding) {
-        MonsterEntity *riding_m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-        MonsterRaceInfo *riding_r_ptr = &monraces_info[riding_m_ptr->r_idx];
-        result = riding_r_ptr->feature_flags.has(MonsterFeatureType::CAN_FLY) ? FLAG_CAUSE_RIDING : FLAG_CAUSE_NONE;
+    if (player_ptr->riding == 0) {
+        return result;
     }
 
-    return result;
+    const auto &monster = player_ptr->current_floor_ptr->m_list[player_ptr->riding];
+    const auto &monrace = monraces_info[monster.r_idx];
+    return monrace.feature_flags.has(MonsterFeatureType::CAN_FLY) ? FLAG_CAUSE_RIDING : FLAG_CAUSE_NONE;
 }
 
 bool has_can_swim(PlayerType *player_ptr)
 {
-    bool can_swim = false;
-    if (player_ptr->riding) {
-        MonsterEntity *riding_m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-        MonsterRaceInfo *riding_r_ptr = &monraces_info[riding_m_ptr->r_idx];
-        if (riding_r_ptr->feature_flags.has_any_of({ MonsterFeatureType::CAN_SWIM, MonsterFeatureType::AQUATIC })) {
-            can_swim = true;
-        }
+    if (player_ptr->riding == 0) {
+        return false;
     }
 
-    return can_swim;
+    const auto &monster = player_ptr->current_floor_ptr->m_list[player_ptr->riding];
+    const auto &monrace = monraces_info[monster.r_idx];
+    return monrace.feature_flags.has_any_of({ MonsterFeatureType::CAN_SWIM, MonsterFeatureType::AQUATIC });
 }
 
 BIT_FLAGS has_slow_digest(PlayerType *player_ptr)
@@ -1072,7 +1063,7 @@ void update_curses(PlayerType *player_ptr)
         if (!o_ptr->is_valid()) {
             continue;
         }
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
         if (flags.has(TR_AGGRAVATE)) {
             player_ptr->cursed.set(CurseTraitType::AGGRAVATE);
         }
@@ -1183,7 +1174,7 @@ void update_extra_blows(PlayerType *player_ptr)
             continue;
         }
 
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
         if (flags.has(TR_BLOWS)) {
             if ((i == INVEN_MAIN_HAND || i == INVEN_MAIN_RING) && !two_handed) {
                 player_ptr->extra_blows[0] += o_ptr->pval;
@@ -1486,7 +1477,7 @@ BIT_FLAGS has_vuln_curse(PlayerType *player_ptr)
             continue;
         }
 
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
 
         if (flags.has(TR_VUL_CURSE) || o_ptr->curse_flags.has(CurseTraitType::VUL_CURSE)) {
             set_bits(result, convert_inventory_slot_type_to_flag_cause(i2enum<inventory_slot_type>(i)));
@@ -1511,7 +1502,7 @@ BIT_FLAGS has_heavy_vuln_curse(PlayerType *player_ptr)
             continue;
         }
 
-        auto flags = object_flags(o_ptr);
+        const auto flags = o_ptr->get_flags();
 
         if ((flags.has(TR_VUL_CURSE) || o_ptr->curse_flags.has(CurseTraitType::VUL_CURSE)) && o_ptr->curse_flags.has(CurseTraitType::HEAVY_CURSE)) {
             set_bits(result, convert_inventory_slot_type_to_flag_cause(i2enum<inventory_slot_type>(i)));
@@ -1727,8 +1718,8 @@ bool has_disable_two_handed_bonus(PlayerType *player_ptr, int i)
  */
 bool is_wielding_icky_weapon(PlayerType *player_ptr, int i)
 {
-    auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
-    auto flags = object_flags(o_ptr);
+    const auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
+    const auto flags = o_ptr->get_flags();
 
     const auto tval = o_ptr->bi_key.tval();
     const auto has_no_weapon = (tval == ItemKindType::NONE) || (tval == ItemKindType::SHIELD);
@@ -1755,8 +1746,8 @@ bool is_wielding_icky_weapon(PlayerType *player_ptr, int i)
  */
 bool is_wielding_icky_riding_weapon(PlayerType *player_ptr, int i)
 {
-    auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
-    auto flags = object_flags(o_ptr);
+    const auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
+    const auto flags = o_ptr->get_flags();
     const auto tval = o_ptr->bi_key.tval();
     const auto has_no_weapon = (tval == ItemKindType::NONE) || (tval == ItemKindType::SHIELD);
     const auto is_suitable = o_ptr->is_lance() || flags.has(TR_RIDING);
@@ -1771,7 +1762,7 @@ bool has_not_ninja_weapon(PlayerType *player_ptr, int i)
 
     const auto &item = player_ptr->inventory_list[INVEN_MAIN_HAND + i];
     const auto tval = item.bi_key.tval();
-    const auto sval = item.bi_key.sval().value();
+    const auto sval = *item.bi_key.sval();
     return PlayerClass(player_ptr).equals(PlayerClassType::NINJA) &&
            !((player_ptr->weapon_exp_max[tval][sval] > PlayerSkill::weapon_exp_at(PlayerSkillRank::BEGINNER)) &&
                (player_ptr->inventory_list[INVEN_SUB_HAND - i].bi_key.tval() != ItemKindType::SHIELD));
@@ -1785,7 +1776,7 @@ bool has_not_monk_weapon(PlayerType *player_ptr, int i)
 
     const auto &item = player_ptr->inventory_list[INVEN_MAIN_HAND + i];
     const auto tval = item.bi_key.tval();
-    const auto sval = item.bi_key.sval().value();
+    const auto sval = *item.bi_key.sval();
     PlayerClass pc(player_ptr);
     return pc.is_martial_arts_pro() && (player_ptr->weapon_exp_max[tval][sval] == PlayerSkill::weapon_exp_at(PlayerSkillRank::UNSKILLED));
 }
index 2c9386d..0a59477 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "inventory/inventory-slot-types.h"
 #include "object-enchant/tr-types.h"
@@ -84,7 +84,7 @@ BIT_FLAGS has_sh_fire(PlayerType *player_ptr);
 BIT_FLAGS has_sh_elec(PlayerType *player_ptr);
 BIT_FLAGS has_sh_cold(PlayerType *player_ptr);
 BIT_FLAGS has_easy_spell(PlayerType *player_ptr);
-BIT_FLAGS has_heavy_spell(PlayerType *player_ptr);
+BIT_FLAGS has_hard_spell(PlayerType *player_ptr);
 BIT_FLAGS has_hold_exp(PlayerType *player_ptr);
 BIT_FLAGS has_see_inv(PlayerType *player_ptr);
 BIT_FLAGS has_magic_mastery(PlayerType *player_ptr);
index 8cea6c0..30d5099 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/player-status-resist.h"
+#include "player/player-status-resist.h"
 #include "artifact/fixed-art-types.h"
 #include "grid/grid.h"
 #include "inventory/inventory-slot-types.h"
@@ -10,7 +10,6 @@
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
 #include "object-hook/hook-weapon.h"
-#include "object/object-flags.h"
 #include "player-base/player-race.h"
 #include "player-info/class-info.h"
 #include "player-info/race-info.h"
@@ -29,7 +28,6 @@
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
 #include "util/bit-flags-calculator.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 
 /*!
index e683fe8..b426435 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index a178c08..24fdd93 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/player-status-table.h"
+#include "player/player-status-table.h"
 
 /*!
  * @brief 能力値テーブル / Abbreviations of healthy stats
index a43b57d..23460a5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-ability/player-ability-types.h"
 #include "system/angband.h"
index 3e09b27..0d45a15 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/player-status.h"
+#include "player/player-status.h"
 #include "artifact/fixed-art-types.h"
 #include "autopick/autopick-reader-writer.h"
 #include "autopick/autopick.h"
@@ -9,8 +9,6 @@
 #include "cmd-item/cmd-magiceat.h"
 #include "combat/attack-power-table.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "dungeon/dungeon-flag-types.h"
@@ -48,7 +46,6 @@
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
 #include "object-hook/hook-armor.h"
-#include "object/object-flags.h"
 #include "object/object-info.h"
 #include "object/object-mark-types.h"
 #include "perception/object-perception.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-acceleration.h"
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
 #include "world/world.h"
@@ -168,7 +165,7 @@ static void delayed_visual_update(PlayerType *player_ptr)
     for (int i = 0; i < floor_ptr->redraw_n; i++) {
         POSITION y = floor_ptr->redraw_y[i];
         POSITION x = floor_ptr->redraw_x[i];
-        grid_type *g_ptr;
+        Grid *g_ptr;
         g_ptr = &floor_ptr->grid_array[y][x];
         if (none_bits(g_ptr->info, CAVE_REDRAW)) {
             continue;
@@ -309,7 +306,7 @@ static void update_bonuses(PlayerType *player_ptr)
     player_ptr->anti_magic = has_anti_magic(player_ptr);
     player_ptr->anti_tele = has_anti_tele(player_ptr);
     player_ptr->easy_spell = has_easy_spell(player_ptr);
-    player_ptr->heavy_spell = has_heavy_spell(player_ptr);
+    player_ptr->hard_spell = has_hard_spell(player_ptr);
     player_ptr->hold_exp = has_hold_exp(player_ptr);
     player_ptr->see_inv = has_see_inv(player_ptr);
     player_ptr->free_act = has_free_act(player_ptr);
@@ -377,12 +374,13 @@ static void update_bonuses(PlayerType *player_ptr)
     player_ptr->dis_ac = calc_base_ac(player_ptr);
     player_ptr->dis_to_a = calc_to_ac(player_ptr, false);
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (old_mighty_throw != player_ptr->mighty_throw) {
-        player_ptr->window_flags |= PW_INVENTORY;
+        rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
     }
 
     if (player_ptr->telepathy != old_telepathy) {
-        set_bits(player_ptr->update, PU_MONSTER_STATUSES);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
     }
 
     auto is_esp_updated = player_ptr->esp_animal != old_esp_animal;
@@ -398,20 +396,20 @@ static void update_bonuses(PlayerType *player_ptr)
     is_esp_updated |= player_ptr->esp_nonliving != old_esp_nonliving;
     is_esp_updated |= player_ptr->esp_unique != old_esp_unique;
     if (is_esp_updated) {
-        set_bits(player_ptr->update, PU_MONSTER_STATUSES);
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
     }
 
     if (player_ptr->see_inv != old_see_inv) {
-        set_bits(player_ptr->update, PU_MONSTER_STATUSES);
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
     }
 
     if (player_ptr->pspeed != old_speed) {
-        set_bits(player_ptr->redraw, PR_SPEED);
+        rfu.set_flag(MainWindowRedrawingFlag::SPEED);
     }
 
     if ((player_ptr->dis_ac != old_dis_ac) || (player_ptr->dis_to_a != old_dis_to_a)) {
-        set_bits(player_ptr->redraw, PR_AC);
-        set_bits(player_ptr->window_flags, PW_PLAYER);
+        rfu.set_flag(MainWindowRedrawingFlag::AC);
+        rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
     }
 
     if (w_ptr->character_xtra) {
@@ -496,8 +494,9 @@ static void update_max_hitpoints(PlayerType *player_ptr)
 #endif
     player_ptr->mhp = mhp;
 
-    player_ptr->redraw |= PR_HP;
-    player_ptr->window_flags |= PW_PLAYER;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::HP);
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
 }
 
 /*!
@@ -520,7 +519,7 @@ static void update_num_of_spells(PlayerType *player_ptr)
         return;
     }
 
-    concptr p = spell_category_name(mp_ptr->spell_book);
+    const auto spell_category = spell_category_name(mp_ptr->spell_book);
     int levels = player_ptr->lev - mp_ptr->spell_first + 1;
     if (levels < 0) {
         levels = 0;
@@ -608,9 +607,9 @@ static void update_num_of_spells(PlayerType *player_ptr)
 
         const auto spell_name = exe_spell(player_ptr, which, j % 32, SpellProcessType::NAME);
 #ifdef JP
-        msg_format("%sの%sを忘れてしまった。", spell_name->data(), p);
+        msg_format("%sの%sを忘れてしまった。", spell_name->data(), spell_category.data());
 #else
-        msg_format("You have forgotten the %s of %s.", p, spell_name->data());
+        msg_format("You have forgotten the %s of %s.", spell_category.data(), spell_name->data());
 #endif
         player_ptr->new_spells++;
     }
@@ -653,9 +652,9 @@ static void update_num_of_spells(PlayerType *player_ptr)
 
         const auto spell_name = exe_spell(player_ptr, which, j % 32, SpellProcessType::NAME);
 #ifdef JP
-        msg_format("%sの%sを忘れてしまった。", spell_name->data(), p);
+        msg_format("%sの%sを忘れてしまった。", spell_name->data(), spell_category.data());
 #else
-        msg_format("You have forgotten the %s of %s.", p, spell_name->data());
+        msg_format("You have forgotten the %s of %s.", spell_category.data(), spell_name->data());
 #endif
         player_ptr->new_spells++;
     }
@@ -714,9 +713,9 @@ static void update_num_of_spells(PlayerType *player_ptr)
 
         const auto spell_name = exe_spell(player_ptr, which, j % 32, SpellProcessType::NAME);
 #ifdef JP
-        msg_format("%sの%sを思い出した。", spell_name->data(), p);
+        msg_format("%sの%sを思い出した。", spell_name->data(), spell_category.data());
 #else
-        msg_format("You have remembered the %s of %s.", p, spell_name->data());
+        msg_format("You have remembered the %s of %s.", spell_category.data(), spell_name->data());
 #endif
         player_ptr->new_spells--;
     }
@@ -761,18 +760,19 @@ static void update_num_of_spells(PlayerType *player_ptr)
     if (player_ptr->new_spells) {
 #ifdef JP
         if (player_ptr->new_spells < 10) {
-            msg_format("あと %d つの%sを学べる。", player_ptr->new_spells, p);
+            msg_format("あと %d つの%sを学べる。", player_ptr->new_spells, spell_category.data());
         } else {
-            msg_format("あと %d 個の%sを学べる。", player_ptr->new_spells, p);
+            msg_format("あと %d 個の%sを学べる。", player_ptr->new_spells, spell_category.data());
         }
 #else
-        msg_format("You can learn %d more %s%s.", player_ptr->new_spells, p, (player_ptr->new_spells != 1) ? "s" : "");
+        msg_format("You can learn %d more %s%s.", player_ptr->new_spells, spell_category.data(), (player_ptr->new_spells != 1) ? "s" : "");
 #endif
     }
 
     player_ptr->old_spells = player_ptr->new_spells;
-    set_bits(player_ptr->redraw, PR_STUDY);
-    set_bits(player_ptr->window_flags, PW_ITEM_KNOWLEDGTE);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::STUDY);
+    rfu.set_flag(SubWindowRedrawingFlag::ITEM_KNOWLEDGE);
 }
 
 /*!
@@ -799,7 +799,7 @@ static void update_max_mana(PlayerType *player_ptr)
     } else {
         if (mp_ptr->spell_first > player_ptr->lev) {
             player_ptr->msp = 0;
-            set_bits(player_ptr->redraw, PR_MP);
+            RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
             return;
         }
 
@@ -833,8 +833,8 @@ static void update_max_mana(PlayerType *player_ptr)
 
     if (any_bits(mp_ptr->spell_xtra, extra_magic_glove_reduce_mana)) {
         player_ptr->cumber_glove = false;
-        auto *o_ptr = &player_ptr->inventory_list[INVEN_ARMS];
-        auto flags = object_flags(o_ptr);
+        const auto *o_ptr = &player_ptr->inventory_list[INVEN_ARMS];
+        const auto flags = o_ptr->get_flags();
         auto should_mp_decrease = o_ptr->is_valid();
         should_mp_decrease &= flags.has_not(TR_FREE_ACT);
         should_mp_decrease &= flags.has_not(TR_DEC_MANA);
@@ -1002,8 +1002,13 @@ static void update_max_mana(PlayerType *player_ptr)
         }
 #endif
         player_ptr->msp = msp;
-        set_bits(player_ptr->redraw, PR_MP);
-        set_bits(player_ptr->window_flags, (PW_PLAYER | PW_SPELL));
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::MP);
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::PLAYER,
+            SubWindowRedrawingFlag::SPELL,
+        };
+        rfu.set_flags(flags);
     }
 
     if (w_ptr->character_xtra) {
@@ -1054,14 +1059,12 @@ short calc_num_fire(PlayerType *player_ptr, const ItemEntity *o_ptr)
             continue;
         }
 
-        auto flags = object_flags(q_ptr);
-        if (flags.has(TR_XTRA_SHOTS)) {
+        if (q_ptr->get_flags().has(TR_XTRA_SHOTS)) {
             extra_shots++;
         }
     }
 
-    auto flags = object_flags(o_ptr);
-    if (flags.has(TR_XTRA_SHOTS)) {
+    if (o_ptr->get_flags().has(TR_XTRA_SHOTS)) {
         extra_shots++;
     }
 
@@ -1171,8 +1174,8 @@ static ACTION_SKILL_POWER calc_device_ability(PlayerType *player_ptr)
         if (!o_ptr->is_valid()) {
             continue;
         }
-        auto flags = object_flags(o_ptr);
-        if (flags.has(TR_MAGIC_MASTERY)) {
+
+        if (o_ptr->get_flags().has(TR_MAGIC_MASTERY)) {
             pow += 8 * o_ptr->pval;
         }
     }
@@ -1300,8 +1303,8 @@ static ACTION_SKILL_POWER calc_search(PlayerType *player_ptr)
         if (!o_ptr->is_valid()) {
             continue;
         }
-        auto flags = object_flags(o_ptr);
-        if (flags.has(TR_SEARCH)) {
+
+        if (o_ptr->get_flags().has(TR_SEARCH)) {
             pow += (o_ptr->pval * 5);
         }
     }
@@ -1351,8 +1354,8 @@ static ACTION_SKILL_POWER calc_search_freq(PlayerType *player_ptr)
         if (!o_ptr->is_valid()) {
             continue;
         }
-        auto flags = object_flags(o_ptr);
-        if (flags.has(TR_SEARCH)) {
+
+        if (o_ptr->get_flags().has(TR_SEARCH)) {
             pow += (o_ptr->pval * 5);
         }
     }
@@ -1489,8 +1492,8 @@ static ACTION_SKILL_POWER calc_skill_dig(PlayerType *player_ptr)
         if (!o_ptr->is_valid()) {
             continue;
         }
-        auto flags = object_flags(o_ptr);
-        if (flags.has(TR_TUNNEL)) {
+
+        if (o_ptr->get_flags().has(TR_TUNNEL)) {
             pow += (o_ptr->pval * 20);
         }
     }
@@ -1531,11 +1534,9 @@ static bool is_heavy_wield(PlayerType *player_ptr, int i)
 
 static int16_t calc_num_blow(PlayerType *player_ptr, int i)
 {
-    ItemEntity *o_ptr;
     int16_t num_blow = 1;
 
-    o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
-    auto flags = object_flags(o_ptr);
+    const auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
     PlayerClass pc(player_ptr);
     if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND + i)) {
         if (o_ptr->is_valid() && !player_ptr->heavy_wield[i]) {
@@ -1547,7 +1548,7 @@ static int16_t calc_num_blow(PlayerType *player_ptr, int i)
             wgt = info.wgt;
             mul = info.mul;
 
-            if (pc.equals(PlayerClassType::CAVALRY) && player_ptr->riding && flags.has(TR_RIDING)) {
+            if (pc.equals(PlayerClassType::CAVALRY) && player_ptr->riding && o_ptr->get_flags().has(TR_RIDING)) {
                 num = 5;
                 wgt = 70;
                 mul = 4;
@@ -1780,9 +1781,8 @@ static ARMOUR_CLASS calc_to_ac(PlayerType *player_ptr, bool is_real_value)
     }
 
     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
-        ItemEntity *o_ptr;
-        o_ptr = &player_ptr->inventory_list[i];
-        auto flags = object_flags(o_ptr);
+        const auto *o_ptr = &player_ptr->inventory_list[i];
+        const auto flags = o_ptr->get_flags();
         if (!o_ptr->is_valid()) {
             continue;
         }
@@ -1790,7 +1790,7 @@ static ARMOUR_CLASS calc_to_ac(PlayerType *player_ptr, bool is_real_value)
             ac += o_ptr->to_a;
         }
 
-        if (o_ptr->curse_flags.has(CurseTraitType::LOW_AC) || object_flags(o_ptr).has(TR_LOW_AC)) {
+        if (o_ptr->curse_flags.has(CurseTraitType::LOW_AC) || flags.has(TR_LOW_AC)) {
             if (o_ptr->curse_flags.has(CurseTraitType::HEAVY_CURSE)) {
                 if (is_real_value || o_ptr->is_fully_known()) {
                     ac -= 30;
@@ -1938,7 +1938,7 @@ int16_t calc_double_weapon_penalty(PlayerType *player_ptr, INVENTORY_IDX slot)
     int penalty = 0;
 
     if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND) && has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
-        auto flags = object_flags(&player_ptr->inventory_list[INVEN_SUB_HAND]);
+        const auto flags = player_ptr->inventory_list[INVEN_SUB_HAND].get_flags();
 
         penalty = ((100 - player_ptr->skill_exp[PlayerSkillKindType::TWO_WEAPON] / 160) - (130 - player_ptr->inventory_list[slot].weight) / 8);
         if (set_quick_and_tiny(player_ptr) || set_icing_and_twinkle(player_ptr) || set_anubis_and_chariot(player_ptr)) {
@@ -1974,15 +1974,14 @@ static bool is_riding_two_hands(PlayerType *player_ptr)
 
     if (has_two_handed_weapons(player_ptr) || (empty_hands(player_ptr, false) == EMPTY_HAND_NONE)) {
         return true;
-    } else if (any_bits(player_ptr->pet_extra_flags, PF_TWO_HANDS)) {
+    }
+
+    if (any_bits(player_ptr->pet_extra_flags, PF_TWO_HANDS)) {
         switch (player_ptr->pclass) {
         case PlayerClassType::MONK:
         case PlayerClassType::FORCETRAINER:
         case PlayerClassType::BERSERKER:
-            if ((empty_hands(player_ptr, false) != EMPTY_HAND_NONE) && !has_melee_weapon(player_ptr, INVEN_MAIN_HAND) && !has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
-                return true;
-            }
-
+            return (empty_hands(player_ptr, false) != EMPTY_HAND_NONE) && !has_melee_weapon(player_ptr, INVEN_MAIN_HAND) && !has_melee_weapon(player_ptr, INVEN_SUB_HAND);
         default:
             break;
         }
@@ -2111,11 +2110,16 @@ void put_equipment_warning(PlayerType *player_ptr)
     }
 }
 
-static short calc_to_damage(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_real_value)
+static bool is_bare_knuckle(PlayerType *player_ptr)
 {
-    auto *o_ptr = &player_ptr->inventory_list[slot];
-    auto flags = object_flags(o_ptr);
+    auto bare_knuckle = is_martial_arts_mode(player_ptr);
+    bare_knuckle &= empty_hands(player_ptr, false) == (EMPTY_HAND_MAIN | EMPTY_HAND_SUB);
+    return bare_knuckle;
+}
 
+static short calc_to_damage(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_real_value)
+{
+    const auto *o_ptr = &player_ptr->inventory_list[slot];
     player_hand calc_hand = PLAYER_HAND_OTHER;
     if (slot == INVEN_MAIN_HAND) {
         calc_hand = PLAYER_HAND_MAIN;
@@ -2135,7 +2139,7 @@ static short calc_to_damage(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_
     damage -= player_stun->get_damage_penalty();
     PlayerClass pc(player_ptr);
     const auto tval = o_ptr->bi_key.tval();
-    if (pc.equals(PlayerClassType::PRIEST) && (flags.has_not(TR_BLESSED)) && ((tval == ItemKindType::SWORD) || (tval == ItemKindType::POLEARM))) {
+    if (pc.equals(PlayerClassType::PRIEST) && (o_ptr->get_flags().has_not(TR_BLESSED)) && ((tval == ItemKindType::SWORD) || (tval == ItemKindType::POLEARM))) {
         damage -= 2;
     } else if (pc.equals(PlayerClassType::BERSERKER)) {
         damage += player_ptr->lev / 6;
@@ -2175,7 +2179,11 @@ static short calc_to_damage(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_
         int bonus_to_d = 0;
         o_ptr = &player_ptr->inventory_list[i];
         const auto has_melee = has_melee_weapon(player_ptr, i);
-        if (!o_ptr->is_valid() || (o_ptr->bi_key.tval() == ItemKindType::CAPTURE) || ((i == INVEN_MAIN_HAND) && has_melee) || ((i == INVEN_SUB_HAND) && has_melee) || (i == INVEN_BOW)) {
+        if (!o_ptr->is_valid() || (o_ptr->bi_key.tval() == ItemKindType::CAPTURE)) {
+            continue;
+        }
+
+        if (((i == INVEN_MAIN_HAND) && has_melee) || ((i == INVEN_SUB_HAND) && has_melee) || (i == INVEN_BOW)) {
             continue;
         }
 
@@ -2238,7 +2246,7 @@ static short calc_to_damage(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_
     }
 
     if (main_attack_hand(player_ptr) == calc_hand) {
-        if ((is_martial_arts_mode(player_ptr) && empty_hands(player_ptr, false) == (EMPTY_HAND_MAIN | EMPTY_HAND_SUB)) || !has_disable_two_handed_bonus(player_ptr, calc_hand)) {
+        if (is_bare_knuckle(player_ptr) || !has_disable_two_handed_bonus(player_ptr, calc_hand)) {
             int bonus_to_d = 0;
             bonus_to_d = ((int)(adj_str_td[player_ptr->stat_index[A_STR]]) - 128) / 2;
             damage += std::max<int>(bonus_to_d, 1);
@@ -2316,7 +2324,7 @@ static short calc_to_hit(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_rea
             break;
         }
 
-        if ((is_martial_arts_mode(player_ptr) && empty_hands(player_ptr, false) == (EMPTY_HAND_MAIN | EMPTY_HAND_SUB)) || !has_disable_two_handed_bonus(player_ptr, calc_hand)) {
+        if (is_bare_knuckle(player_ptr) || !has_disable_two_handed_bonus(player_ptr, calc_hand)) {
             int bonus_to_h = 0;
             bonus_to_h = ((int)(adj_str_th[player_ptr->stat_index[A_STR]]) - 128) + ((int)(adj_dex_th[player_ptr->stat_index[A_DEX]]) - 128);
             hit += std::max<int>(bonus_to_h, 1);
@@ -2326,12 +2334,11 @@ static short calc_to_hit(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_rea
     /* Bonuses and penalties by weapon */
     PlayerClass pc(player_ptr);
     if (has_melee_weapon(player_ptr, slot)) {
-        auto *o_ptr = &player_ptr->inventory_list[slot];
-        auto flags = object_flags(o_ptr);
+        const auto *o_ptr = &player_ptr->inventory_list[slot];
 
         /* Traind bonuses */
         const auto tval = o_ptr->bi_key.tval();
-        const auto sval = o_ptr->bi_key.sval().value();
+        const auto sval = *o_ptr->bi_key.sval();
         hit += (player_ptr->weapon_exp[tval][sval] - PlayerSkill::weapon_exp_at(PlayerSkillRank::BEGINNER)) / 200;
 
         /* Weight penalty */
@@ -2349,6 +2356,7 @@ static short calc_to_hit(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_rea
         }
 
         /* Riding bonus and penalty */
+        const auto flags = o_ptr->get_flags();
         if (player_ptr->riding > 0) {
             if (o_ptr->is_lance()) {
                 hit += 15;
@@ -2413,7 +2421,11 @@ static short calc_to_hit(PlayerType *player_ptr, INVENTORY_IDX slot, bool is_rea
 
         /* Ignore empty hands, handed weapons, bows and capture balls */
         const auto has_melee = has_melee_weapon(player_ptr, i);
-        if (!o_ptr->is_valid() || o_ptr->bi_key.tval() == ItemKindType::CAPTURE || (i == INVEN_MAIN_HAND && has_melee) || (i == INVEN_SUB_HAND && has_melee) || i == INVEN_BOW) {
+        if (!o_ptr->is_valid() || o_ptr->bi_key.tval() == ItemKindType::CAPTURE) {
+            continue;
+        }
+
+        if (((i == INVEN_MAIN_HAND) && has_melee) || ((i == INVEN_SUB_HAND) && has_melee) || (i == INVEN_BOW)) {
             continue;
         }
 
@@ -2550,7 +2562,11 @@ static int16_t calc_to_hit_bow(PlayerType *player_ptr, bool is_real_value)
         int bonus_to_h;
         o_ptr = &player_ptr->inventory_list[i];
         const auto has_melee = has_melee_weapon(player_ptr, i);
-        if (!o_ptr->is_valid() || (o_ptr->bi_key.tval() == ItemKindType::CAPTURE) || ((i == INVEN_MAIN_HAND) && has_melee) || ((i == INVEN_SUB_HAND) && has_melee) || i == INVEN_BOW) {
+        if (!o_ptr->is_valid() || (o_ptr->bi_key.tval() == ItemKindType::CAPTURE)) {
+            continue;
+        }
+
+        if (((i == INVEN_MAIN_HAND) && has_melee) || ((i == INVEN_SUB_HAND) && has_melee) || (i == INVEN_BOW)) {
             continue;
         }
 
@@ -2670,28 +2686,29 @@ WEIGHT calc_weight_limit(PlayerType *player_ptr)
  */
 void update_creature(PlayerType *player_ptr)
 {
-    if (!player_ptr->update) {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    if (!rfu.any_stats()) {
         return;
     }
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (any_bits(player_ptr->update, (PU_AUTO_DESTRUCTION))) {
-        reset_bits(player_ptr->update, PU_AUTO_DESTRUCTION);
+    if (rfu.has(StatusRecalculatingFlag::AUTO_DESTRUCTION)) {
+        rfu.reset_flag(StatusRecalculatingFlag::AUTO_DESTRUCTION);
         autopick_delayed_alter(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_COMBINATION))) {
-        reset_bits(player_ptr->update, PU_COMBINATION);
+    if (rfu.has(StatusRecalculatingFlag::COMBINATION)) {
+        rfu.reset_flag(StatusRecalculatingFlag::COMBINATION);
         combine_pack(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_REORDER))) {
-        reset_bits(player_ptr->update, PU_REORDER);
+    if (rfu.has(StatusRecalculatingFlag::REORDER)) {
+        rfu.reset_flag(StatusRecalculatingFlag::REORDER);
         reorder_pack(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_BONUS))) {
-        reset_bits(player_ptr->update, PU_BONUS);
+    if (rfu.has(StatusRecalculatingFlag::BONUS)) {
+        rfu.reset_flag(StatusRecalculatingFlag::BONUS);
         PlayerAlignment(player_ptr).update_alignment();
         PlayerSkill ps(player_ptr);
         ps.apply_special_weapon_skill_max_values();
@@ -2699,75 +2716,72 @@ void update_creature(PlayerType *player_ptr)
         update_bonuses(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_TORCH))) {
-        reset_bits(player_ptr->update, PU_TORCH);
+    if (rfu.has(StatusRecalculatingFlag::TORCH)) {
+        rfu.reset_flag(StatusRecalculatingFlag::TORCH);
         update_lite_radius(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_HP))) {
-        reset_bits(player_ptr->update, PU_HP);
+    if (rfu.has(StatusRecalculatingFlag::HP)) {
+        rfu.reset_flag(StatusRecalculatingFlag::HP);
         update_max_hitpoints(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_MP))) {
-        reset_bits(player_ptr->update, PU_MP);
+    if (rfu.has(StatusRecalculatingFlag::MP)) {
+        rfu.reset_flag(StatusRecalculatingFlag::MP);
         update_max_mana(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_SPELLS))) {
-        reset_bits(player_ptr->update, PU_SPELLS);
+    if (rfu.has(StatusRecalculatingFlag::SPELLS)) {
+        rfu.reset_flag(StatusRecalculatingFlag::SPELLS);
         update_num_of_spells(player_ptr);
     }
 
-    if (!w_ptr->character_generated) {
-        return;
-    }
-    if (w_ptr->character_icky_depth > 0) {
+    if (!w_ptr->character_generated || (w_ptr->character_icky_depth > 0)) {
         return;
     }
-    if (any_bits(player_ptr->update, (PU_UN_LITE))) {
-        reset_bits(player_ptr->update, PU_UN_LITE);
+
+    if (rfu.has(StatusRecalculatingFlag::UN_LITE)) {
+        rfu.reset_flag(StatusRecalculatingFlag::UN_LITE);
         forget_lite(floor_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_UN_VIEW))) {
-        reset_bits(player_ptr->update, PU_UN_VIEW);
+    if (rfu.has(StatusRecalculatingFlag::UN_VIEW)) {
+        rfu.reset_flag(StatusRecalculatingFlag::UN_VIEW);
         forget_view(floor_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_VIEW))) {
-        reset_bits(player_ptr->update, PU_VIEW);
+    if (rfu.has(StatusRecalculatingFlag::VIEW)) {
+        rfu.reset_flag(StatusRecalculatingFlag::VIEW);
         update_view(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_LITE))) {
-        reset_bits(player_ptr->update, PU_LITE);
+    if (rfu.has(StatusRecalculatingFlag::LITE)) {
+        rfu.reset_flag(StatusRecalculatingFlag::LITE);
         update_lite(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_FLOW))) {
-        reset_bits(player_ptr->update, PU_FLOW);
+    if (rfu.has(StatusRecalculatingFlag::FLOW)) {
+        rfu.reset_flag(StatusRecalculatingFlag::FLOW);
         update_flow(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_DISTANCE))) {
-        reset_bits(player_ptr->update, PU_DISTANCE);
-
+    if (rfu.has(StatusRecalculatingFlag::DISTANCE)) {
+        rfu.reset_flag(StatusRecalculatingFlag::DISTANCE);
         update_monsters(player_ptr, true);
     }
 
-    if (any_bits(player_ptr->update, (PU_MONSTER_LITE))) {
-        reset_bits(player_ptr->update, PU_MONSTER_LITE);
+    if (rfu.has(StatusRecalculatingFlag::MONSTER_LITE)) {
+        rfu.reset_flag(StatusRecalculatingFlag::MONSTER_LITE);
         update_mon_lite(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_DELAY_VISIBILITY))) {
-        reset_bits(player_ptr->update, PU_DELAY_VISIBILITY);
+    if (rfu.has(StatusRecalculatingFlag::DELAY_VISIBILITY)) {
+        rfu.reset_flag(StatusRecalculatingFlag::DELAY_VISIBILITY);
         delayed_visual_update(player_ptr);
     }
 
-    if (any_bits(player_ptr->update, (PU_MONSTER_STATUSES))) {
-        reset_bits(player_ptr->update, PU_MONSTER_STATUSES);
+    if (rfu.has(StatusRecalculatingFlag::MONSTER_STATUSES)) {
+        rfu.reset_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
         update_monsters(player_ptr, false);
     }
 }
@@ -2821,8 +2835,9 @@ bool player_place(PlayerType *player_ptr, POSITION y, POSITION x)
 void wreck_the_pattern(PlayerType *player_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    int pattern_type = terrains_info[floor_ptr->grid_array[player_ptr->y][player_ptr->x].feat].subtype;
-    if (pattern_type == PATTERN_TILE_WRECKED) {
+    const auto p_pos = player_ptr->get_position();
+    const auto &terrain = floor_ptr->get_grid(p_pos).get_terrain();
+    if (terrain.subtype == PATTERN_TILE_WRECKED) {
         return;
     }
 
@@ -2833,13 +2848,14 @@ void wreck_the_pattern(PlayerType *player_ptr)
         take_hit(player_ptr, DAMAGE_NOESCAPE, damroll(10, 8), _("パターン損壊", "corrupting the Pattern"));
     }
 
-    int to_ruin = randint1(45) + 35;
+    auto to_ruin = randint1(45) + 35;
     while (to_ruin--) {
-        POSITION r_y, r_x;
-        scatter(player_ptr, &r_y, &r_x, player_ptr->y, player_ptr->x, 4, PROJECT_NONE);
-
-        if (pattern_tile(floor_ptr, r_y, r_x) && (terrains_info[floor_ptr->grid_array[r_y][r_x].feat].subtype != PATTERN_TILE_WRECKED)) {
-            cave_set_feat(player_ptr, r_y, r_x, feat_pattern_corrupted);
+        int y;
+        int x;
+        scatter(player_ptr, &y, &x, player_ptr->y, player_ptr->x, 4, PROJECT_NONE);
+        const Pos2D pos(y, x);
+        if (pattern_tile(floor_ptr, pos.y, pos.x) && (floor_ptr->get_grid(pos).get_terrain().subtype != PATTERN_TILE_WRECKED)) {
+            cave_set_feat(player_ptr, pos.y, pos.x, feat_pattern_corrupted);
         }
     }
 
@@ -2879,17 +2895,28 @@ void check_experience(PlayerType *player_ptr)
         player_ptr->max_max_exp = player_ptr->max_exp;
     }
 
-    set_bits(player_ptr->redraw, PR_EXP);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::EXP);
     handle_stuff(player_ptr);
 
     PlayerRace pr(player_ptr);
     bool android = pr.equals(PlayerRaceType::ANDROID);
     PLAYER_LEVEL old_lev = player_ptr->lev;
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+    };
     while ((player_ptr->lev > 1) && (player_ptr->exp < ((android ? player_exp_a : player_exp)[player_ptr->lev - 2] * player_ptr->expfact / 100L))) {
         player_ptr->lev--;
-        set_bits(player_ptr->update, PU_BONUS | PU_HP | PU_MP | PU_SPELLS);
-        set_bits(player_ptr->redraw, PR_LEVEL | PR_TITLE);
-        set_bits(player_ptr->window_flags, PW_PLAYER);
+        rfu.set_flags(flags_srf);
+        static constexpr auto flags_mwrf = {
+            MainWindowRedrawingFlag::LEVEL,
+            MainWindowRedrawingFlag::TITLE,
+        };
+        rfu.set_flags(flags_mwrf);
+        rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
         handle_stuff(player_ptr);
     }
 
@@ -2911,14 +2938,24 @@ void check_experience(PlayerType *player_ptr)
             }
             level_inc_stat = true;
 
-            exe_write_diary(player_ptr, DIARY_LEVELUP, player_ptr->lev, nullptr);
+            exe_write_diary(player_ptr, DiaryKind::LEVELUP, player_ptr->lev);
         }
 
         sound(SOUND_LEVEL);
         msg_format(_("レベル %d にようこそ。", "Welcome to level %d."), player_ptr->lev);
-        set_bits(player_ptr->update, (PU_BONUS | PU_HP | PU_MP | PU_SPELLS));
-        set_bits(player_ptr->redraw, (PR_LEVEL | PR_TITLE | PR_EXP));
-        set_bits(player_ptr->window_flags, (PW_PLAYER | PW_SPELL | PW_INVENTORY));
+        rfu.set_flags(flags_srf);
+        const auto flags_mwrf_levelup = {
+            MainWindowRedrawingFlag::LEVEL,
+            MainWindowRedrawingFlag::TITLE,
+            MainWindowRedrawingFlag::EXP,
+        };
+        rfu.set_flags(flags_mwrf_levelup);
+        const auto &flags_swrf_levelup = {
+            SubWindowRedrawingFlag::PLAYER,
+            SubWindowRedrawingFlag::SPELL,
+            SubWindowRedrawingFlag::INVENTORY,
+        };
+        rfu.set_flags(flags_swrf_levelup);
         player_ptr->level_up_message = true;
         handle_stuff(player_ptr);
 
@@ -2951,7 +2988,7 @@ void check_experience(PlayerType *player_ptr)
                             prt("", n + 2, 14);
                         }
                     }
-                    if (get_check(_("よろしいですか?", "Are you sure? "))) {
+                    if (input_check(_("よろしいですか?", "Are you sure? "))) {
                         break;
                     }
                 }
@@ -2977,9 +3014,17 @@ void check_experience(PlayerType *player_ptr)
             level_reward = false;
         }
 
-        set_bits(player_ptr->update, PU_BONUS | PU_HP | PU_MP | PU_SPELLS);
-        set_bits(player_ptr->redraw, (PR_LEVEL | PR_TITLE));
-        set_bits(player_ptr->window_flags, (PW_PLAYER | PW_SPELL));
+        rfu.set_flags(flags_srf);
+        static constexpr auto flags_mwrf = {
+            MainWindowRedrawingFlag::LEVEL,
+            MainWindowRedrawingFlag::TITLE,
+        };
+        rfu.set_flags(flags_mwrf);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::PLAYER,
+            SubWindowRedrawingFlag::SPELL,
+        };
+        rfu.set_flags(flags_swrf);
         handle_stuff(player_ptr);
     }
 
@@ -3147,7 +3192,7 @@ bool is_blessed(PlayerType *player_ptr)
 
 bool is_tim_esp(PlayerType *player_ptr)
 {
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     auto sniper_concent = sniper_data ? sniper_data->concent : 0;
     return player_ptr->tim_esp || music_singing(player_ptr, MUSIC_MIND) || (sniper_concent >= CONCENT_TELE_THRESHOLD);
 }
@@ -3159,7 +3204,7 @@ bool is_tim_stealth(PlayerType *player_ptr)
 
 bool is_time_limit_esp(PlayerType *player_ptr)
 {
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     auto sniper_concent = sniper_data ? sniper_data->concent : 0;
     return player_ptr->tim_esp || music_singing(player_ptr, MUSIC_MIND) || (sniper_concent >= CONCENT_TELE_THRESHOLD);
 }
index 7e227c5..f9136d1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * @file player-status.h
index ef8f734..3f5659b 100644 (file)
@@ -1,5 +1,4 @@
-#include "player/player-view.h"
-#include "core/player-update-types.h"
+#include "player/player-view.h"
 #include "floor/cave.h"
 #include "floor/line-of-sight.h"
 #include "game-option/map-screen-options.h"
@@ -7,6 +6,7 @@
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/point-2d.h"
 #include <vector>
 
@@ -30,8 +30,8 @@
 static bool update_view_aux(PlayerType *player_ptr, POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    grid_type *g1_c_ptr;
-    grid_type *g2_c_ptr;
+    Grid *g1_c_ptr;
+    Grid *g2_c_ptr;
     g1_c_ptr = &floor_ptr->grid_array[y1][x1];
     g2_c_ptr = &floor_ptr->grid_array[y2][x2];
     bool f1 = (feat_supports_los(g1_c_ptr->feat));
@@ -46,7 +46,7 @@ static bool update_view_aux(PlayerType *player_ptr, POSITION y, POSITION x, POSI
         return true;
     }
 
-    grid_type *g_ptr;
+    Grid *g_ptr;
     g_ptr = &floor_ptr->grid_array[y][x];
     bool wall = (!feat_supports_los(g_ptr->feat));
     bool z1 = (v1 && (g1_c_ptr->info & CAVE_XTRA));
@@ -114,7 +114,7 @@ void update_view(PlayerType *player_ptr)
     POSITION y_max = floor_ptr->height - 1;
     POSITION x_max = floor_ptr->width - 1;
 
-    grid_type *g_ptr;
+    Grid *g_ptr;
     if (view_reduce_view && !floor_ptr->dun_level) {
         full = MAX_PLAYER_SIGHT / 2;
         over = MAX_PLAYER_SIGHT * 3 / 4;
@@ -379,5 +379,5 @@ void update_view(PlayerType *player_ptr)
         cave_redraw_later(floor_ptr, py, px);
     }
 
-    player_ptr->update |= PU_DELAY_VISIBILITY;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::DELAY_VISIBILITY);
 }
index 3491ed7..19351c8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void update_view(PlayerType *player_ptr);
index 391ece4..91ca9c4 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 死亡・引退・切腹時の画面表示
  * @date 2020/02/24
  * @author Hourier
@@ -8,7 +8,6 @@
 
 #include "player/process-death.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "flavor/flavor-describer.h"
 #include "floor/floor-town.h"
@@ -25,6 +24,7 @@
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
 #include "util/buffer-shaper.h"
@@ -101,19 +101,17 @@ static int show_killing_monster(PlayerType *player_ptr)
 
     if (lines.size() >= 3) {
         char buf[GRAVE_LINE_WIDTH + 1];
-        angband_strcpy(buf, lines[1].data(), sizeof(buf) - 2);
+        angband_strcpy(buf, lines[1], sizeof(buf) - 2);
         angband_strcat(buf, "…", sizeof(buf));
         show_tomb_line(lines[0], GRAVE_KILLER_NAME_ROW);
         show_tomb_line(buf, GRAVE_KILLER_NAME_ROW + 1);
         return 1;
     }
 
-    if (const auto start_ptr = angband_strstr(lines[0].data(), "『");
-        (start_ptr != nullptr) && suffix(lines[1], "』")) {
-        const auto start_pos = start_ptr - lines[0].data();
-
+    if (const auto start_pos = lines[0].find("『");
+        (start_pos != std::string::npos) && suffix(lines[1], "』")) {
         if (lines[0].length() + lines[1].length() - start_pos <= GRAVE_LINE_WIDTH) {
-            const auto name = lines[0].substr(start_pos).append(lines[1]);
+            const auto &name = lines[0].substr(start_pos).append(lines[1]);
             std::string_view title(lines[0].data(), start_pos);
             show_tomb_line(title, GRAVE_KILLER_NAME_ROW);
             show_tomb_line(name, GRAVE_KILLER_NAME_ROW + 1);
@@ -245,7 +243,7 @@ static void inventory_aware(PlayerType *player_ptr)
         }
 
         object_aware(player_ptr, o_ptr);
-        object_known(o_ptr);
+        o_ptr->mark_as_known();
     }
 }
 
@@ -256,7 +254,7 @@ static void inventory_aware(PlayerType *player_ptr)
 static void home_aware(PlayerType *player_ptr)
 {
     for (size_t i = 1; i < towns_info.size(); i++) {
-        auto *store_ptr = &towns_info[i].store[enum2i(StoreSaleType::HOME)];
+        auto *store_ptr = &towns_info[i].stores[StoreSaleType::HOME];
         for (auto j = 0; j < store_ptr->stock_num; j++) {
             auto *o_ptr = &store_ptr->stock[j];
             if (!o_ptr->is_valid()) {
@@ -264,7 +262,7 @@ static void home_aware(PlayerType *player_ptr)
             }
 
             object_aware(player_ptr, o_ptr);
-            object_known(o_ptr);
+            o_ptr->mark_as_known();
         }
     }
 }
@@ -305,7 +303,7 @@ static bool show_dead_player_items(PlayerType *player_ptr)
 static void show_dead_home_items(PlayerType *player_ptr)
 {
     for (size_t l = 1; l < towns_info.size(); l++) {
-        const auto *store_ptr = &towns_info[l].store[enum2i(StoreSaleType::HOME)];
+        const auto *store_ptr = &towns_info[l].stores[StoreSaleType::HOME];
         if (store_ptr->stock_num == 0) {
             continue;
         }
@@ -337,17 +335,14 @@ static void export_player_info(PlayerType *player_ptr)
     prt(_("キャラクターの記録をファイルに書き出すことができます。", "You may now dump a character record to one or more files."), 21, 0);
     prt(_("リターンキーでキャラクターを見ます。ESCで中断します。", "Then, hit RETURN to see the character, or ESC to abort."), 22, 0);
     while (true) {
-        char out_val[160] = "";
         put_str(_("ファイルネーム: ", "Filename: "), 23, 0);
-        if (!askfor(out_val, 60)) {
+        const auto ask_result = askfor(60);
+        if (!ask_result || ask_result->empty()) {
             return;
         }
-        if (!out_val[0]) {
-            break;
-        }
 
         screen_save();
-        (void)file_character(player_ptr, out_val);
+        file_character(player_ptr, *ask_result);
         screen_load();
     }
 }
@@ -361,13 +356,10 @@ static void file_character_auto(PlayerType *player_ptr)
     struct tm *now_tm = localtime(&now_t);
 
     char datetime[32];
-    char filename[128];
-
     strftime(datetime, sizeof(datetime), "%Y-%m-%d_%H%M%S", now_tm);
-    strnfmt(filename, sizeof(filename), "%s_Autodump_%s.txt", p_ptr->name, datetime);
-
     screen_save();
-    (void)file_character(player_ptr, filename);
+    const auto filename = format("%s_Autodump_%s.txt", player_ptr->name, datetime);
+    file_character(player_ptr, filename);
     screen_load();
 }
 
@@ -381,7 +373,7 @@ void show_death_info(PlayerType *player_ptr)
     inventory_aware(player_ptr);
     home_aware(player_ptr);
 
-    player_ptr->update |= (PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     flush();
     msg_erase();
index 00bdddc..161145b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void print_tomb(PlayerType *player_ptr);
index ebf8d35..d25c596 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/process-name.h"
+#include "player/process-name.h"
 #include "autopick/autopick-reader-writer.h"
 #include "core/asking-player.h"
 #include "game-option/birth-options.h"
@@ -8,8 +8,14 @@
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "util/angband-files.h"
+#include "util/finalizer.h"
 #include "util/string-processor.h"
+#include "view/display-player-misc-info.h"
 #include "world/world.h"
+#include <sstream>
+#ifdef SAVEFILE_USE_UID
+#include "main-unix/unix-user-ids.h"
+#endif
 
 /*!
  * @brief プレイヤーの名前をチェックして修正する
@@ -86,35 +92,26 @@ void process_player_name(PlayerType *player_ptr, bool is_new_savefile)
     }
 
     auto is_modified = false;
-    if (is_new_savefile && (!savefile[0] || !keep_savefile)) {
-        std::string temp;
+    if (is_new_savefile && (savefile.empty() || !keep_savefile)) {
+        std::stringstream ss;
 
 #ifdef SAVEFILE_USE_UID
-        /* Rename the savefile, using the player_ptr->player_uid and player_ptr->base_name */
-        temp = std::to_string(player_ptr->player_uid);
-        temp.append(".").append(player_ptr->base_name);
+        ss << UnixUserIds::get_instance().get_user_id();
+        ss << '.' << player_ptr->base_name;
 #else
-        /* Rename the savefile, using the player_ptr->base_name */
-        temp = player_ptr->base_name;
+        ss << player_ptr->base_name;
 #endif
-        path_build(savefile, sizeof(savefile), ANGBAND_DIR_SAVE, temp);
+        savefile = path_build(ANGBAND_DIR_SAVE, ss.str());
         is_modified = true;
     }
 
-    if (is_modified || !savefile_base[0]) {
-        auto s = savefile;
-        while (true) {
-            auto t = angband_strstr(s, PATH_SEP);
-            if (!t) {
-                break;
-            }
-            s = t + 1;
-        }
-
+    if (is_modified || savefile_base.empty()) {
 #ifdef SAVEFILE_USE_UID
-        strcpy(savefile_base, angband_strstr(s, ".") + 1);
+        const auto &savefile_str = savefile.filename().string();
+        const auto split = str_split(savefile_str, '.');
+        savefile_base = split[1];
 #else
-        strcpy(savefile_base, s);
+        savefile_base = savefile.filename().string();
 #endif
     }
 
@@ -124,41 +121,32 @@ void process_player_name(PlayerType *player_ptr, bool is_new_savefile)
 }
 
 /*!
- * @brief プレイヤーの名前を変更するコマンドのメインルーチン
- * Gets a name for the character, reacting to name changes.
+ * @brief プレイヤーの名前を変更する
  * @param player_ptr プレイヤーへの参照ポインタ
- * @details
- * <pre>
- * Assumes that "display_player()" has just been called
- * Perhaps we should NOT ask for a name (at "birth()") on
- * Unix machines?  XXX XXX
- * What a horrible name for a global function.
- * </pre>
+ * @details PlayerType::name は32バイトで定義されているが、
+ * スコアファイル(lib/apex/scores.raw)に保存されているプレイヤー名が最大16バイト (ヌル文字含)となっている
+ * このため最大値を16バイトに制限する
  */
 void get_name(PlayerType *player_ptr)
 {
-    char tmp[64];
-    strcpy(tmp, player_ptr->name);
-
-    if (get_string(_("キャラクターの名前を入力して下さい: ", "Enter a name for your character: "), tmp, 15)) {
-        strcpy(player_ptr->name, tmp);
-    }
+    const auto finalizer = util::make_finalizer([player_ptr]() {
+        display_player_misc_info(player_ptr);
+    });
+
+    std::string initial_name(player_ptr->name);
+    const auto max_name_size = 15;
+    const auto copy_size = sizeof(player_ptr->name);
+    constexpr auto prompt = _("キャラクターの名前を入力して下さい: ", "Enter a name for your character: ");
+    const auto name = input_string(prompt, max_name_size, initial_name);
+    if (name) {
+        if (!name->empty()) {
+            angband_strcpy(player_ptr->name, *name, copy_size);
+        }
 
-    if (strlen(player_ptr->name) == 0) {
-        strcpy(player_ptr->name, "PLAYER");
+        return;
     }
 
-    strcpy(tmp, ap_ptr->title);
-#ifdef JP
-    if (ap_ptr->no == 1) {
-        strcat(tmp, "の");
+    if (initial_name.empty()) {
+        angband_strcpy(player_ptr->name, "PLAYER", copy_size);
     }
-#else
-    strcat(tmp, " ");
-#endif
-    strcat(tmp, player_ptr->name);
-
-    term_erase(34, 1, 255);
-    c_put_str(TERM_L_BLUE, tmp, 1, 34);
-    clear_from(22);
 }
index 6cbbf0f..b1dc64a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void process_player_name(PlayerType *player_ptr, bool is_new_savefile = false);
index 2d6a8c7..a666b43 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/race-info-table.h"
+#include "player/race-info-table.h"
 
 #ifdef JP
 #define N(JAPANESE, ENGLISH) JAPANESE, ENGLISH
index fbf4ea5..cddf16d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-info/race-info.h"
 #include "player-info/race-types.h"
index 9d7353b..d825412 100644 (file)
@@ -1,9 +1,8 @@
-#include "player/race-resistances.h"
+#include "player/race-resistances.h"
 #include "inventory/inventory-slot-types.h"
 #include "mind/mind-elementalist.h"
 #include "mutation/mutation-flag-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player-base/player-race.h"
 #include "player-info/race-info.h"
@@ -87,7 +86,7 @@ void known_obj_immunity(PlayerType *player_ptr, TrFlags &flags)
             continue;
         }
 
-        auto o_flags = object_flags_known(o_ptr);
+        auto o_flags = o_ptr->get_flags_known();
         if (o_flags.has(TR_IM_ACID)) {
             flags.set(TR_RES_ACID);
         }
index a922310..63a4600 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b2ee35e..e01a1ed 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum special_defence {
     DEFENSE_ACID = 0x00000001, /*!< プレイヤーのステータス:酸免疫 */
index 20b5822..bb87ced 100644 (file)
@@ -1,4 +1,4 @@
-#include "player/temporary-resistances.h"
+#include "player/temporary-resistances.h"
 #include "object-enchant/tr-types.h"
 #include "player-info/race-info.h"
 #include "player-info/race-types.h"
index 93e8b29..f6fca6a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 4343b4e..94bbe1f 100644 (file)
@@ -1,4 +1,4 @@
-#include "racial/class-racial-switcher.h"
+#include "racial/class-racial-switcher.h"
 #include "cmd-action/cmd-spell.h"
 #include "mind/mind-elementalist.h"
 #include "racial/racial-util.h"
index c53842c..06d80cd 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct rc_type;
index 566b95c..bfa02ad 100644 (file)
@@ -1,4 +1,4 @@
-#include "racial/mutation-racial-selector.h"
+#include "racial/mutation-racial-selector.h"
 #include "cmd-action/cmd-spell.h"
 #include "locale/japanese.h"
 #include "mutation/mutation-flag-types.h"
@@ -22,7 +22,7 @@ void select_mutation_racial(PlayerType *player_ptr, rc_type *rc_ptr)
 
     if (player_ptr->muta.has(PlayerMutationType::BR_FIRE)) {
         rpi = rpi_type(_("炎のブレス", "Fire Breath"));
-        rpi.info = format("%s%d", KWD_DAM, rc_ptr->lvl);
+        rpi.info = format("%s%d", KWD_DAM, rc_ptr->lvl * 2);
         rpi.text = _("火炎のブレスを放つ", "Fires a breath of fire.");
         rpi.min_level = 20;
         rpi.cost = rc_ptr->lvl;
index 85dbebf..42b6267 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct rc_type;
index 56cb678..309a1ba 100644 (file)
@@ -1,4 +1,4 @@
-#include "racial/race-racial-command-setter.h"
+#include "racial/race-racial-command-setter.h"
 #include "cmd-action/cmd-spell.h"
 #include "player-info/race-info.h"
 #include "racial/racial-util.h"
index 5262ea0..4857487 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct rc_type;
index f17282d..a792def 100644 (file)
@@ -1,4 +1,4 @@
-#include "racial/racial-android.h"
+#include "racial/racial-android.h"
 #include "effect/attribute-types.h"
 #include "inventory/inventory-slot-types.h"
 #include "object-enchant/object-ego.h"
index 5db1e23..3422cae 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool android_inside_weapon(PlayerType *player_ptr);
index 748b1d0..7db4f57 100644 (file)
@@ -1,4 +1,4 @@
-#include "racial/racial-balrog.h"
+#include "racial/racial-balrog.h"
 #include "effect/attribute-types.h"
 #include "player/player-status.h"
 #include "spell-kind/spells-launcher.h"
index 7dd926b..a67eea9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool demonic_breath(PlayerType *player_ptr);
index 668929d..30664bc 100644 (file)
@@ -1,4 +1,4 @@
-#include "racial/racial-draconian.h"
+#include "racial/racial-draconian.h"
 #include "effect/attribute-types.h"
 #include "mind/mind-elementalist.h"
 #include "player/player-status.h"
index 8fa35ea..40e524f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool draconian_breath(PlayerType *player_ptr);
index 726515a..08569b7 100644 (file)
@@ -1,10 +1,9 @@
-#include "racial/racial-kutar.h"
+#include "racial/racial-kutar.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "game-option/disturbance-options.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -40,8 +39,8 @@ bool set_leveling(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tsubureru = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -49,7 +48,8 @@ bool set_leveling(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
index 1865126..e0ed33b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 9416c95..b0fbb09 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief レイシャルと突然変異の技能処理 / Racial powers (and mutations)
  * @date 2014/01/08
  * @author
@@ -16,8 +16,6 @@
 #include "cmd-action/cmd-spell.h"
 #include "cmd-item/cmd-magiceat.h"
 #include "cmd-item/cmd-zapwand.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "effect/spells-effect-util.h"
@@ -79,6 +77,7 @@
 #include "status/buff-setter.h"
 #include "status/experience.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-getter.h"
 #include "timed-effect/player-paralysis.h"
 #include "timed-effect/timed-effects.h"
@@ -94,7 +93,7 @@ bool switch_class_racial_execution(PlayerType *player_ptr, const int32_t command
         return sword_dancing(player_ptr);
     case PlayerClassType::HIGH_MAGE:
         if (player_ptr->realm1 == REALM_HEX) {
-            auto retval = SpellHex(player_ptr).stop_spells_with_selection();
+            const auto retval = SpellHex(player_ptr).stop_spells_with_selection();
             if (retval) {
                 PlayerEnergy(player_ptr).set_player_turn_energy(10);
             }
@@ -155,7 +154,7 @@ bool switch_class_racial_execution(PlayerType *player_ptr, const int32_t command
                 return false;
             }
 
-            set_bits(player_ptr->update, PU_BONUS);
+            RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
             return true;
         }
 
@@ -248,7 +247,7 @@ bool switch_class_racial_execution(PlayerType *player_ptr, const int32_t command
             return false;
         }
 
-        set_bits(player_ptr->update, PU_BONUS);
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
         return true;
     case PlayerClassType::BLUE_MAGE:
         set_action(player_ptr, player_ptr->action == ACTION_LEARN ? ACTION_NONE : ACTION_LEARN);
index 2a1a65f..2a870f7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 7c8b677..bc10d09 100644 (file)
@@ -1,4 +1,4 @@
-#include "racial/racial-util.h"
+#include "racial/racial-util.h"
 #include "io/input-key-requester.h"
 #include "player-base/player-class.h"
 #include "system/player-type-definition.h"
index 230ef60..0739238 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <string>
 #include <vector>
@@ -54,7 +54,6 @@ struct rc_type {
     PLAYER_LEVEL lvl{}; //!< プレイヤーレベル
     bool is_warrior{}; //!< 戦士/狂戦士かどうか
     bool is_chosen{}; //!< 選択したかどうか
-    bool cast{}; //!< パワーが使用されたかどうか
     char choice{}; //!< コマンドキー
     char out_val[160]{}; //!< 出力文字列用バッファ
     int menu_line{}; //!< 現在選択中の行
index 14b46d7..9c1974a 100644 (file)
@@ -1,4 +1,4 @@
-#include "racial/racial-vampire.h"
+#include "racial/racial-vampire.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/geometry.h"
 #include "hpmp/hp-mp-processor.h"
 
 bool vampirism(PlayerType *player_ptr)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::NO_MELEE)) {
         msg_print(_("なぜか攻撃することができない。", "Something prevents you from attacking."));
         return false;
     }
 
     DIRECTION dir;
-    if (!get_direction(player_ptr, &dir, false, false)) {
+    if (!get_direction(player_ptr, &dir)) {
         return false;
     }
 
     POSITION y = player_ptr->y + ddy[dir];
     POSITION x = player_ptr->x + ddx[dir];
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+    const auto *g_ptr = &floor.grid_array[y][x];
     stop_mouth(player_ptr);
     if (!(g_ptr->m_idx)) {
         msg_print(_("何もない場所に噛みついた!", "You bite into thin air!"));
index 5083635..34b94e1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool vampirism(PlayerType *player_ptr);
index 18b180b..8b119f7 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-arcane.h"
+#include "realm/realm-arcane.h"
 #include "avatar/avatar.h"
 #include "cmd-action/cmd-spell.h"
 #include "core/asking-player.h"
@@ -594,7 +594,7 @@ std::optional<std::string> do_arcane_spell(PlayerType *player_ptr, SPELL_IDX spe
 
         {
             if (cast) {
-                if (!get_check(_("本当に他の階にテレポートしますか?", "Are you sure? (Teleport Level)"))) {
+                if (!input_check(_("本当に他の階にテレポートしますか?", "Are you sure? (Teleport Level)"))) {
                     return std::nullopt;
                 }
                 teleport_level(player_ptr, 0);
@@ -644,27 +644,18 @@ std::optional<std::string> do_arcane_spell(PlayerType *player_ptr, SPELL_IDX spe
             }
 
             if (cast) {
-                AttributeType type;
-
                 if (!get_aim_dir(player_ptr, &dir)) {
                     return std::nullopt;
                 }
 
-                switch (randint1(4)) {
-                case 1:
-                    type = AttributeType::FIRE;
-                    break;
-                case 2:
-                    type = AttributeType::ELEC;
-                    break;
-                case 3:
-                    type = AttributeType::COLD;
-                    break;
-                default:
-                    type = AttributeType::ACID;
-                    break;
-                }
+                constexpr static auto element_types = {
+                    AttributeType::FIRE,
+                    AttributeType::ELEC,
+                    AttributeType::COLD,
+                    AttributeType::ACID,
+                };
 
+                const auto type = rand_choice(element_types);
                 fire_ball(player_ptr, type, dir, dam, rad);
             }
         }
index ecc6a09..1766be0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 4513ba1..90c503c 100644 (file)
@@ -1,7 +1,6 @@
-#include "realm/realm-chaos.h"
+#include "realm/realm-chaos.h"
 #include "cmd-action/cmd-spell.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
@@ -22,6 +21,7 @@
 #include "spell/spells-summon.h"
 #include "status/shape-changer.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-getter.h"
 #include "view/display-messages.h"
 
@@ -126,7 +126,7 @@ std::optional<std::string> do_chaos_spell(PlayerType *player_ptr, SPELL_IDX spel
                 if (!(player_ptr->special_attack & ATTACK_CONFUSE)) {
                     msg_print(_("あなたの手は光り始めた。", "Your hands start glowing."));
                     player_ptr->special_attack |= ATTACK_CONFUSE;
-                    player_ptr->redraw |= (PR_TIMED_EFFECT);
+                    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
                 }
             }
         }
@@ -713,7 +713,7 @@ std::optional<std::string> do_chaos_spell(PlayerType *player_ptr, SPELL_IDX spel
 
         {
             if (cast) {
-                if (!get_check(_("変身します。よろしいですか?", "You will polymorph yourself. Are you sure? "))) {
+                if (!input_check(_("変身します。よろしいですか?", "You will polymorph yourself. Are you sure? "))) {
                     return std::nullopt;
                 }
                 do_poly_self(player_ptr);
index 1e21fd0..bc7db58 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index e20b0d1..fb0c929 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-craft.h"
+#include "realm/realm-craft.h"
 #include "cmd-action/cmd-spell.h"
 #include "monster-floor/monster-summon.h"
 #include "monster-floor/place-monster-types.h"
index 10acff3..03c10dd 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 18b970a..af59aa5 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-crusade.h"
+#include "realm/realm-crusade.h"
 #include "cmd-action/cmd-spell.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
index a29ebc1..98a796a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index f7cbac3..bbd42c1 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-death.h"
+#include "realm/realm-death.h"
 #include "avatar/avatar.h"
 #include "cmd-action/cmd-spell.h"
 #include "effect/effect-characteristics.h"
index aa70d3c..bbe171a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 3af703f..c4d1acc 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-demon.h"
+#include "realm/realm-demon.h"
 #include "cmd-action/cmd-spell.h"
 #include "effect/attribute-types.h"
 #include "monster-floor/monster-summon.h"
index d680dbb..2cc0176 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 7c158e3..b793248 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum spell_hex_type {
     /* 1st book */
index 881d0a8..18a3351 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 呪術の処理実装 / Hex code
  * @date 2014/01/14
  * @author
@@ -9,8 +9,6 @@
 #include "cmd-action/cmd-spell.h"
 #include "cmd-item/cmd-quaff.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
@@ -28,7 +26,6 @@
 #include "object-hook/hook-armor.h"
 #include "object/item-tester-hooker.h"
 #include "object/item-use-flags.h"
-#include "object/object-flags.h"
 #include "player/attack-defense-types.h"
 #include "player/player-skill.h"
 #include "player/player-status.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/grid-selector.h"
 #include "target/target-getter.h"
 #include "term/screen-processor.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 #include "world/world.h"
-
 #ifdef JP
 #else
 #include "player-info/equipment-info.h"
@@ -166,22 +163,20 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
         }
 
         if (cast) {
-            const auto q = _("どれを呪いますか?", "Which weapon do you curse?");
-            const auto s = _("武器を装備していない。", "You're not wielding a weapon.");
-            short item;
-            auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_melee_weapon));
+            constexpr auto q = _("どれを呪いますか?", "Which weapon do you curse?");
+            constexpr auto s = _("武器を装備していない。", "You're not wielding a weapon.");
+            short i_idx;
+            auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_melee_weapon));
             if (o_ptr == nullptr) {
                 return "";
             }
 
             const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
-            auto f = object_flags(o_ptr);
-
-            if (!get_check(format(_("本当に %s を呪いますか?", "Do you curse %s, really?"), item_name.data()))) {
+            if (!input_check(format(_("本当に %s を呪いますか?", "Do you curse %s, really?"), item_name.data()))) {
                 return "";
             }
 
-            if (!one_in_(3) && (o_ptr->is_fixed_or_random_artifact() || f.has(TR_BLESSED))) {
+            if (!one_in_(3) && (o_ptr->is_fixed_or_random_artifact() || o_ptr->get_flags().has(TR_BLESSED))) {
                 msg_format(_("%s は呪いを跳ね返した。", "%s resists the effect."), item_name.data());
                 if (one_in_(3)) {
                     if (o_ptr->to_d > 0) {
@@ -231,7 +226,7 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
                 o_ptr->curse_flags.set(get_curse(curse_rank, o_ptr));
             }
 
-            player_ptr->update |= (PU_BONUS);
+            RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
             should_continue = false;
         }
         break;
@@ -520,23 +515,21 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
             return _("装備している防具に呪いをかける。", "Curse a piece of armour that you are wielding.");
         }
         if (cast) {
-            const auto q = _("どれを呪いますか?", "Which piece of armour do you curse?");
-            const auto s = _("防具を装備していない。", "You're not wearing any armor.");
-            OBJECT_IDX item;
-            auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_protector));
+            constexpr auto q = _("どれを呪いますか?", "Which piece of armour do you curse?");
+            constexpr auto s = _("防具を装備していない。", "You're not wearing any armor.");
+            short i_idx;
+            auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_protector));
             if (!o_ptr) {
                 return "";
             }
 
-            o_ptr = &player_ptr->inventory_list[item];
+            o_ptr = &player_ptr->inventory_list[i_idx];
             const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
-            auto f = object_flags(o_ptr);
-
-            if (!get_check(format(_("本当に %s を呪いますか?", "Do you curse %s, really?"), item_name.data()))) {
+            if (!input_check(format(_("本当に %s を呪いますか?", "Do you curse %s, really?"), item_name.data()))) {
                 return "";
             }
 
-            if (!one_in_(3) && (o_ptr->is_fixed_or_random_artifact() || f.has(TR_BLESSED))) {
+            if (!one_in_(3) && (o_ptr->is_fixed_or_random_artifact() || o_ptr->get_flags().has(TR_BLESSED))) {
                 msg_format(_("%s は呪いを跳ね返した。", "%s resists the effect."), item_name.data());
                 if (one_in_(3)) {
                     if (o_ptr->to_d > 0) {
@@ -587,7 +580,7 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
                 o_ptr->curse_flags.set(get_curse(curse_rank, o_ptr));
             }
 
-            player_ptr->update |= (PU_BONUS);
+            RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
             should_continue = false;
         }
         break;
@@ -698,6 +691,8 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
 
                 flag = true;
             }
+
+            auto &rfu = RedrawingFlagsUpdater::get_instance();
             for (i = A_STR; i < A_MAX; i++) {
                 if (player_ptr->stat_cur[i] < player_ptr->stat_max[i]) {
                     if (player_ptr->stat_cur[i] < 18) {
@@ -709,8 +704,8 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
                     if (player_ptr->stat_cur[i] > player_ptr->stat_max[i]) {
                         player_ptr->stat_cur[i] = player_ptr->stat_max[i];
                     }
-                    player_ptr->update |= (PU_BONUS);
 
+                    rfu.set_flag(StatusRecalculatingFlag::BONUS);
                     flag = true;
                 }
             }
@@ -724,9 +719,14 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
                     set_action(player_ptr, ACTION_NONE);
                 }
 
-                player_ptr->update |= (PU_BONUS | PU_HP | PU_MP | PU_SPELLS);
-                player_ptr->redraw |= (PR_EXTRA);
-
+                static constexpr auto flags = {
+                    StatusRecalculatingFlag::BONUS,
+                    StatusRecalculatingFlag::HP,
+                    StatusRecalculatingFlag::MP,
+                    StatusRecalculatingFlag::SPELLS,
+                };
+                rfu.set_flags(flags);
+                rfu.set_flag(MainWindowRedrawingFlag::EXTRA);
                 return "";
             }
         }
@@ -740,22 +740,16 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
             return _("呪われた装備品の呪いを吸収して魔力を回復する。", "Drains curse on your equipment and heals SP a little.");
         }
         if (cast) {
-            OBJECT_IDX item;
-            concptr s, q;
-            ItemEntity *o_ptr;
-
-            q = _("どの装備品から吸収しますか?", "Which cursed equipment do you drain mana from?");
-            s = _("呪われたアイテムを装備していない。", "You have no cursed equipment.");
-
-            o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_cursed));
+            constexpr auto q = _("どの装備品から吸収しますか?", "Which cursed equipment do you drain mana from?");
+            constexpr auto s = _("呪われたアイテムを装備していない。", "You have no cursed equipment.");
+            short i_idx;
+            auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP), FuncItemTester(&ItemEntity::is_cursed));
             if (!o_ptr) {
                 return "";
             }
 
-            auto f = object_flags(o_ptr);
-
             player_ptr->csp += (player_ptr->lev / 5) + randint1(player_ptr->lev / 5);
-            if (f.has(TR_TY_CURSE) || o_ptr->curse_flags.has(CurseTraitType::TY_CURSE)) {
+            if (o_ptr->get_flags().has(TR_TY_CURSE) || o_ptr->curse_flags.has(CurseTraitType::TY_CURSE)) {
                 player_ptr->csp += randint1(5);
             }
             if (player_ptr->csp > player_ptr->msp) {
@@ -840,18 +834,20 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
 
                 flag = false;
 
+                const auto *floor_ptr = player_ptr->current_floor_ptr;
                 for (dir = 0; dir < 8; dir++) {
                     int dy = y + ddy_ddd[dir];
                     int dx = x + ddx_ddd[dir];
                     if (dir == 5) {
                         continue;
                     }
-                    if (player_ptr->current_floor_ptr->grid_array[dy][dx].m_idx) {
+                    if (floor_ptr->grid_array[dy][dx].m_idx) {
                         flag = true;
                     }
                 }
 
-                if (!is_cave_empty_bold(player_ptr, y, x) || player_ptr->current_floor_ptr->grid_array[y][x].is_icky() || (distance(y, x, player_ptr->y, player_ptr->x) > player_ptr->lev + 2)) {
+                const auto dist = distance(y, x, player_ptr->y, player_ptr->x);
+                if (!is_cave_empty_bold(player_ptr, y, x) || floor_ptr->grid_array[y][x].is_icky() || (dist > player_ptr->lev + 2)) {
                     msg_print(_("そこには移動できない。", "Can not teleport to there."));
                     continue;
                 }
@@ -956,8 +952,20 @@ std::optional<std::string> do_hex_spell(PlayerType *player_ptr, spell_hex_type s
     }
 
     if (!info) {
-        player_ptr->update |= (PU_BONUS | PU_HP | PU_MP | PU_SPELLS);
-        player_ptr->redraw |= (PR_EXTRA | PR_HP | PR_MP);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        static constexpr auto flags_srf = {
+            StatusRecalculatingFlag::BONUS,
+            StatusRecalculatingFlag::HP,
+            StatusRecalculatingFlag::MP,
+            StatusRecalculatingFlag::SPELLS,
+        };
+        rfu.set_flags(flags_srf);
+        static constexpr auto flags_mwrf = {
+            MainWindowRedrawingFlag::EXTRA,
+            MainWindowRedrawingFlag::HP,
+            MainWindowRedrawingFlag::MP,
+        };
+        rfu.set_flags(flags_mwrf);
     }
 
     return "";
index 1d3efbf..81e3719 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "realm/realm-hex-numbers.h"
 #include "spell/spells-util.h"
index cd739e6..f8860b4 100644 (file)
@@ -1,12 +1,10 @@
-#include "realm/realm-hissatsu.h"
+#include "realm/realm-hissatsu.h"
 #include "artifact/fixed-art-types.h"
 #include "cmd-action/cmd-attack.h"
 #include "cmd-action/cmd-spell.h"
 #include "cmd-item/cmd-throw.h"
 #include "combat/combat-options-type.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "effect/attribute-types.h"
@@ -30,7 +28,6 @@
 #include "monster/monster-info.h"
 #include "monster/monster-update.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "player-info/equipment-info.h"
 #include "player/player-damage.h"
 #include "player/player-move.h"
@@ -49,6 +46,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/grid-selector.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-getter.h"
@@ -106,7 +104,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
             DIRECTION cdir;
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -176,7 +174,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -219,7 +217,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -274,7 +272,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                 return std::nullopt;
             }
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
 
@@ -284,21 +282,22 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
             y = player_ptr->y + ddy[dir];
             x = player_ptr->x + ddx[dir];
 
-            if (!player_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
+            const auto *floor_ptr = player_ptr->current_floor_ptr;
+            const auto &grid = floor_ptr->grid_array[y][x];
+            if (!grid.m_idx) {
                 msg_print(_("その方向にはモンスターはいません。", "There is no monster."));
                 return std::nullopt;
             }
 
             do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
-
-            if (!player_can_enter(player_ptr, player_ptr->current_floor_ptr->grid_array[y][x].feat, 0) || is_trap(player_ptr, player_ptr->current_floor_ptr->grid_array[y][x].feat)) {
+            if (!player_can_enter(player_ptr, grid.feat, 0) || is_trap(player_ptr, grid.feat)) {
                 break;
             }
 
             y += ddy[dir];
             x += ddx[dir];
 
-            if (player_can_enter(player_ptr, player_ptr->current_floor_ptr->grid_array[y][x].feat, 0) && !is_trap(player_ptr, player_ptr->current_floor_ptr->grid_array[y][x].feat) && !player_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
+            if (player_can_enter(player_ptr, grid.feat, 0) && !is_trap(player_ptr, grid.feat) && !grid.m_idx) {
                 msg_print(nullptr);
                 (void)move_player_effect(player_ptr, y, x, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
             }
@@ -316,7 +315,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -347,7 +346,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -377,7 +376,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -387,13 +386,14 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
             y = player_ptr->y + ddy[dir];
             x = player_ptr->x + ddx[dir];
 
+            const auto &floor = *player_ptr->current_floor_ptr;
             if (player_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
                 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
             } else {
                 msg_print(_("その方向にはモンスターはいません。", "There is no monster."));
                 return std::nullopt;
             }
-            if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
+            if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::NO_MELEE)) {
                 return "";
             }
             if (player_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
@@ -425,8 +425,8 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                     lite_spot(player_ptr, oy, ox);
                     lite_spot(player_ptr, ty, tx);
 
-                    if (monraces_info[m_ptr->r_idx].brightness_flags.has_any_of(ld_mask)) {
-                        player_ptr->update |= (PU_MONSTER_LITE);
+                    if (m_ptr->get_monrace().brightness_flags.has_any_of(ld_mask)) {
+                        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
                     }
                 }
             }
@@ -466,7 +466,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -486,7 +486,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
 
             /* Destroy the feature */
             cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_ROCK);
-            player_ptr->update |= (PU_FLOW);
+            RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
         }
         break;
 
@@ -502,7 +502,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -533,7 +533,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -563,7 +563,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -594,7 +594,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -625,7 +625,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -683,7 +683,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                     continue;
                 }
 
-                if (monster_living(m_ptr->r_idx)) {
+                if (m_ptr->has_living_flag()) {
                     do_cmd_attack(player_ptr, y, x, HISSATSU_SEKIRYUKA);
                     continue;
                 }
@@ -705,7 +705,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -747,14 +747,13 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                 o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
                 basedam = (o_ptr->dd * (o_ptr->ds + 1)) * 50;
                 damage = o_ptr->to_d * 100;
-                auto flags = object_flags(o_ptr);
 
                 // @todo ヴォーパルの多重定義.
                 if (o_ptr->is_specific_artifact(FixedArtifactId::VORPAL_BLADE) || o_ptr->is_specific_artifact(FixedArtifactId::CHAINSWORD)) {
                     /* vorpal blade */
                     basedam *= 5;
                     basedam /= 3;
-                } else if (flags.has(TR_VORPAL)) {
+                } else if (o_ptr->get_flags().has(TR_VORPAL)) {
                     /* vorpal flag only */
                     basedam *= 11;
                     basedam /= 9;
@@ -797,18 +796,19 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             int i;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
                 return std::nullopt;
             }
 
+            const auto &floor = *player_ptr->current_floor_ptr;
             for (i = 0; i < 3; i++) {
                 POSITION y, x;
                 POSITION ny, nx;
                 MONSTER_IDX m_idx;
-                grid_type *g_ptr;
+                Grid *g_ptr;
                 MonsterEntity *m_ptr;
 
                 y = player_ptr->y + ddy[dir];
@@ -822,7 +822,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                     return std::nullopt;
                 }
 
-                if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
+                if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::NO_MELEE)) {
                     return "";
                 }
 
@@ -837,7 +837,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                 m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
 
                 /* Monster cannot move back? */
-                if (!monster_can_enter(player_ptr, ny, nx, &monraces_info[m_ptr->r_idx], 0)) {
+                if (!monster_can_enter(player_ptr, ny, nx, &m_ptr->get_monrace(), 0)) {
                     /* -more- */
                     if (i < 2) {
                         msg_print(nullptr);
@@ -887,7 +887,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -951,7 +951,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                 }
                 command_dir = 0;
 
-                player_ptr->redraw |= PR_MP;
+                RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
                 handle_stuff(player_ptr);
             } while (player_ptr->csp > mana_cost_per_monster);
 
@@ -980,7 +980,9 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                 return std::nullopt;
             }
 
-            if (!cave_player_teleportable_bold(player_ptr, y, x, TELEPORT_SPONTANEOUS) || (distance(y, x, player_ptr->y, player_ptr->x) > MAX_PLAYER_SIGHT / 2) || !projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+            const auto is_teleportable = cave_player_teleportable_bold(player_ptr, y, x, TELEPORT_SPONTANEOUS);
+            const auto dist = distance(y, x, player_ptr->y, player_ptr->x);
+            if (!is_teleportable || (dist > MAX_PLAYER_SIGHT / 2) || !projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
                 msg_print(_("失敗!", "You cannot move to that place!"));
                 break;
             }
@@ -1004,7 +1006,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION x, y;
 
-            if (!get_rep_dir(player_ptr, &dir, false)) {
+            if (!get_rep_dir(player_ptr, &dir)) {
                 return std::nullopt;
             }
 
@@ -1037,7 +1039,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
             POSITION y, x;
             ItemEntity *o_ptr;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -1047,7 +1049,8 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
             y = player_ptr->y + ddy[dir];
             x = player_ptr->x + ddx[dir];
 
-            if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MELEE)) {
+            auto &floor = *player_ptr->current_floor_ptr;
+            if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::NO_MELEE)) {
                 msg_print(_("なぜか攻撃することができない。", "Something prevents you from attacking."));
                 return "";
             }
@@ -1060,14 +1063,13 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                 o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
                 basedam = (o_ptr->dd * (o_ptr->ds + 1)) * 50;
                 damage = o_ptr->to_d * 100;
-                auto flags = object_flags(o_ptr);
 
                 // @todo ヴォーパルの多重定義.
                 if (o_ptr->is_specific_artifact(FixedArtifactId::VORPAL_BLADE) || o_ptr->is_specific_artifact(FixedArtifactId::CHAINSWORD)) {
                     /* vorpal blade */
                     basedam *= 5;
                     basedam /= 3;
-                } else if (flags.has(TR_VORPAL)) {
+                } else if (o_ptr->get_flags().has(TR_VORPAL)) {
                     /* vorpal flag only */
                     basedam *= 11;
                     basedam /= 9;
@@ -1077,8 +1079,10 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
                 damage *= player_ptr->num_blow[i];
                 total_damage += (damage / 100);
             }
-            project(player_ptr, 0, (cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::PROJECT) ? 5 : 0), y, x, total_damage * 3 / 2, AttributeType::METEOR,
-                PROJECT_KILL | PROJECT_JUMP | PROJECT_ITEM);
+
+            const auto is_bold = cave_has_flag_bold(&floor, y, x, TerrainCharacteristics::PROJECT);
+            constexpr auto flags = PROJECT_KILL | PROJECT_JUMP | PROJECT_ITEM;
+            project(player_ptr, 0, (is_bold ? 5 : 0), y, x, total_damage * 3 / 2, AttributeType::METEOR, flags);
         }
         break;
 
@@ -1094,7 +1098,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
         if (cast) {
             POSITION y, x;
 
-            if (!get_direction(player_ptr, &dir, false, false)) {
+            if (!get_direction(player_ptr, &dir)) {
                 return std::nullopt;
             }
             if (dir == 5) {
@@ -1124,7 +1128,7 @@ std::optional<std::string> do_hissatsu_spell(PlayerType *player_ptr, SPELL_IDX s
 
         if (cast) {
             int i;
-            if (!get_check(_("本当に自殺しますか?", "Do you really want to commit suicide? "))) {
+            if (!input_check(_("本当に自殺しますか?", "Do you really want to commit suicide? "))) {
                 return std::nullopt;
             }
             /* Special Verification for suicide */
index 9e9da9b..1cbb4ce 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 386bbae..4118b6b 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-life.h"
+#include "realm/realm-life.h"
 #include "cmd-action/cmd-spell.h"
 #include "effect/attribute-types.h"
 #include "player/digestion-processor.h"
index 4c18841..c6020fc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 31a71d7..c0b4e4d 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-names-table.h"
+#include "realm/realm-names-table.h"
 
 #ifdef JP
 /*!
index 44d8046..171039e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 魔法領域に関する関数マクロ群
  * @date 2021/10/11
  * @author Hourier
@@ -12,7 +12,7 @@
 #include "util/enum-converter.h"
 
 #define VALID_REALM (MAX_REALM + MAX_MAGIC - MIN_TECHNIC + 1)
-#define is_magic(A) (((A) > REALM_NONE) && ((A) < MAX_MAGIC + 1))
+#define is_magic(A) (((A) > REALM_NONE) && ((A) <= MAX_MAGIC))
 
 enum class ItemKindType : short;
 #define tval2realm(A) ((A)-ItemKindType::LIFE_BOOK + 1)
index 11d5b67..9cc51e3 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-nature.h"
+#include "realm/realm-nature.h"
 #include "avatar/avatar.h"
 #include "cmd-action/cmd-spell.h"
 #include "effect/attribute-types.h"
index b348425..1ade6a2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 90e5592..0a3431a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum realm_song_type : int {
     MUSIC_NONE = 0,
index f9255ba..9d12769 100644 (file)
@@ -1,6 +1,4 @@
-#include "cmd-action/cmd-spell.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "cmd-action/cmd-spell.h"
 #include "core/window-redrawer.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
@@ -24,6 +22,7 @@
 #include "status/bad-status-setter.h"
 #include "status/experience.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-getter.h"
 #include "timed-effect/player-acceleration.h"
 #include "timed-effect/timed-effects.h"
@@ -45,16 +44,19 @@ static void start_singing(PlayerType *player_ptr, SPELL_IDX spell, int32_t song)
     /* Now the player is singing */
     set_action(player_ptr, ACTION_SING);
 
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
 }
 
 /*!
  * @brief 歌の各処理を行う
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param spell 歌ID
- * @param mode 処理内容 (SpellProcessType::NAME / SPELL_DESC / SpellProcessType::INFO / SpellProcessType::CAST / SpellProcessType::FAIL / SPELL_CONT / SpellProcessType::STOP)
- * @return SpellProcessType::NAME / SPELL_DESC / SpellProcessType::INFO 時には文字列を返す。SpellProcessType::CAST / SpellProcessType::FAIL / SPELL_CONT / SpellProcessType::STOP 時は std::nullopt を返す。
+ * @param mode 処理内容 (NAME / SPELL_DESC / INFO / CAST / FAIL / SPELL_CONT / STOP)
+ * @return
+ * NAME / SPELL_DESC / INFO 時には文字列を返す.
+ * CAST / FAIL / SPELL_CONT / STOP 時は std::nullopt を返す.
  */
 std::optional<std::string> do_music_spell(PlayerType *player_ptr, SPELL_IDX spell, SpellProcessType mode)
 {
@@ -303,15 +305,14 @@ std::optional<std::string> do_music_spell(PlayerType *player_ptr, SPELL_IDX spel
 
             (void)hp_player(player_ptr, 10);
             (void)BadStatusSetter(player_ptr).set_fear(0);
-            player_ptr->update |= PU_HP;
+            RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::HP);
             start_singing(player_ptr, spell, MUSIC_HERO);
         }
 
         if (stop) {
             if (!player_ptr->hero) {
                 msg_print(_("ヒーローの気分が消え失せた。", "The heroism wears off."));
-                /* Recalculate hitpoints */
-                player_ptr->update |= (PU_HP);
+                RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::HP);
             }
         }
 
@@ -960,14 +961,14 @@ std::optional<std::string> do_music_spell(PlayerType *player_ptr, SPELL_IDX spel
             msg_print(_("英雄の歌を口ずさんだ...", "You chant a powerful, heroic call to arms..."));
             (void)hp_player(player_ptr, 10);
             (void)BadStatusSetter(player_ptr).set_fear(0);
-            player_ptr->update |= PU_HP;
+            RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::HP);
             start_singing(player_ptr, spell, MUSIC_SHERO);
         }
 
         if (stop) {
             if (!player_ptr->hero) {
                 msg_print(_("ヒーローの気分が消え失せた。", "The heroism wears off."));
-                player_ptr->update |= PU_HP;
+                RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::HP);
             }
 
             if (!player_ptr->effects()->acceleration()->is_fast()) {
@@ -1090,21 +1091,28 @@ std::optional<std::string> do_music_spell(PlayerType *player_ptr, SPELL_IDX spel
 
         if (cast) {
             msg_print(_("フィンゴルフィンの冥王への挑戦を歌った...", "You recall the valor of Fingolfin's challenge to the Dark Lord..."));
-
-            player_ptr->redraw |= (PR_MAP);
-            player_ptr->update |= (PU_MONSTER_STATUSES);
-            player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
-
+            auto &rfu = RedrawingFlagsUpdater::get_instance();
+            rfu.set_flag(MainWindowRedrawingFlag::MAP);
+            rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+            static constexpr auto flags = {
+                SubWindowRedrawingFlag::OVERHEAD,
+                SubWindowRedrawingFlag::DUNGEON,
+            };
+            rfu.set_flags(flags);
             start_singing(player_ptr, spell, MUSIC_INVULN);
         }
 
         if (stop) {
             if (!player_ptr->invuln) {
                 msg_print(_("無敵ではなくなった。", "The invulnerability wears off."));
-
-                player_ptr->redraw |= (PR_MAP);
-                player_ptr->update |= (PU_MONSTER_STATUSES);
-                player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+                auto &rfu = RedrawingFlagsUpdater::get_instance();
+                rfu.set_flag(MainWindowRedrawingFlag::MAP);
+                rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+                static constexpr auto flags = {
+                    SubWindowRedrawingFlag::OVERHEAD,
+                    SubWindowRedrawingFlag::DUNGEON,
+                };
+                rfu.set_flags(flags);
             }
         }
 
index 1a47a20..78de623 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 11f9ca4..5a4a731 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-sorcery.h"
+#include "realm/realm-sorcery.h"
 #include "avatar/avatar.h"
 #include "cmd-action/cmd-spell.h"
 #include "core/asking-player.h"
@@ -508,7 +508,7 @@ std::optional<std::string> do_sorcery_spell(PlayerType *player_ptr, SPELL_IDX sp
 
         {
             if (cast) {
-                if (!get_check(_("本当に他の階にテレポートしますか?", "Are you sure? (Teleport Level)"))) {
+                if (!input_check(_("本当に他の階にテレポートしますか?", "Are you sure? (Teleport Level)"))) {
                     return std::nullopt;
                 }
                 teleport_level(player_ptr, 0);
index d70c3b9..6a5d9b3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 6818dde..10800ab 100644 (file)
@@ -1,4 +1,4 @@
-#include "realm/realm-trump.h"
+#include "realm/realm-trump.h"
 #include "cmd-action/cmd-spell.h"
 #include "core/asking-player.h"
 #include "effect/attribute-types.h"
@@ -340,7 +340,7 @@ std::optional<std::string> do_trump_spell(PlayerType *player_ptr, SPELL_IDX spel
 
         {
             if (cast) {
-                if (!get_check(_("本当に他の階にテレポートしますか?", "Are you sure? (Teleport Level)"))) {
+                if (!input_check(_("本当に他の階にテレポートしますか?", "Are you sure? (Teleport Level)"))) {
                     return std::nullopt;
                 }
                 teleport_level(player_ptr, 0);
index 45d6275..5e36902 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index ea6c729..2547df5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum magic_realm_type {
     REALM_NONE = 0,
index 69760de..9accd23 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief fill_data_type構造体を使ってダンジョンを生成/構成する処理
  * @date 2020/07/24
  * @author Hourier
@@ -240,6 +240,7 @@ static void cave_fill(PlayerType *player_ptr, const POSITION y, const POSITION x
     que.emplace(y, x);
 
     while (!que.empty()) {
+        // 参照で受けるとダングリング状態になるのでコピーする.
         const auto [y_cur, x_cur] = que.front();
         que.pop();
 
@@ -275,9 +276,9 @@ bool generate_fracave(PlayerType *player_ptr, POSITION y0, POSITION x0, POSITION
     fill_data.c1 = cutoff;
     fill_data.c2 = 0;
     fill_data.c3 = 0;
-    fill_data.feat1 = feat_ground_type[randint0(100)];
-    fill_data.feat2 = feat_ground_type[randint0(100)];
-    fill_data.feat3 = feat_ground_type[randint0(100)];
+    fill_data.feat1 = rand_choice(feat_ground_type);
+    fill_data.feat2 = rand_choice(feat_ground_type);
+    fill_data.feat3 = rand_choice(feat_ground_type);
     fill_data.info1 = CAVE_FLOOR;
     fill_data.info2 = CAVE_FLOOR;
     fill_data.info3 = CAVE_FLOOR;
@@ -407,21 +408,21 @@ bool generate_lake(PlayerType *player_ptr, POSITION y0, POSITION x0, POSITION xs
     case LAKE_T_LAVA: /* Lava */
         feat1 = feat_deep_lava;
         feat2 = feat_shallow_lava;
-        feat3 = feat_ground_type[randint0(100)];
+        feat3 = rand_choice(feat_ground_type);
         break;
     case LAKE_T_WATER: /* Water */
         feat1 = feat_deep_water;
         feat2 = feat_shallow_water;
-        feat3 = feat_ground_type[randint0(100)];
+        feat3 = rand_choice(feat_ground_type);
         break;
     case LAKE_T_CAVE: /* Collapsed floor_ptr->grid_array */
-        feat1 = feat_ground_type[randint0(100)];
-        feat2 = feat_ground_type[randint0(100)];
+        feat1 = rand_choice(feat_ground_type);
+        feat2 = rand_choice(feat_ground_type);
         feat3 = feat_rubble;
         break;
     case LAKE_T_EARTH_VAULT: /* Earth vault */
         feat1 = feat_rubble;
-        feat2 = feat_ground_type[randint0(100)];
+        feat2 = rand_choice(feat_ground_type);
         feat3 = feat_rubble;
         break;
     case LAKE_T_AIR_VAULT: /* Air vault */
@@ -490,7 +491,7 @@ bool generate_lake(PlayerType *player_ptr, POSITION y0, POSITION x0, POSITION xs
 
             floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM);
             if (cave_has_flag_bold(floor_ptr, y0 + y - yhsize, x0 + x - xhsize, TerrainCharacteristics::LAVA)) {
-                if (dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS)) {
+                if (floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS)) {
                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= CAVE_GLOW;
                 }
             }
index f180e76..e8c68a3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b638b54..133644b 100644 (file)
@@ -1,3 +1,3 @@
-#include "room/door-definition.h"
+#include "room/door-definition.h"
 
 door_type feat_door[MAX_DOOR_TYPES];
index c507c00..7b5cf43 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d54fe51..828cd6e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* 池型地形の生成ID / Room types for generate_lake() */
 enum lake_type {
index fe4e635..afa8457 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/room-generator.h"
+#include "room/room-generator.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "game-option/birth-options.h"
 #include "game-option/cheat-types.h"
@@ -110,7 +110,8 @@ bool generate_rooms(PlayerType *player_ptr, dun_data_type *dd_ptr)
      * かつ「常に通常でない部屋を生成する」フラグがONならば、
      * GRATER_VAULTのみを生成対象とする。 / Ironman sees only Greater Vaults
      */
-    if (ironman_rooms && dungeons_info[floor_ptr->dungeon_idx].flags.has_none_of({ DungeonFeatureType::BEGINNER, DungeonFeatureType::CHAMELEON, DungeonFeatureType::SMALLEST })) {
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    if (ironman_rooms && dungeon.flags.has_none_of({ DungeonFeatureType::BEGINNER, DungeonFeatureType::CHAMELEON, DungeonFeatureType::SMALLEST })) {
         for (auto r : ROOM_TYPE_LIST) {
             if (r == RoomType::GREATER_VAULT) {
                 prob_list[r] = 1;
@@ -118,7 +119,7 @@ bool generate_rooms(PlayerType *player_ptr, dun_data_type *dd_ptr)
                 prob_list[r] = 0;
             }
         }
-    } else if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_VAULT)) {
+    } else if (dungeon.flags.has(DungeonFeatureType::NO_VAULT)) {
         /*! @details ダンジョンにNO_VAULTフラグがあるならば、LESSER_VAULT / GREATER_VAULT/ RANDOM_VAULTを除外 / Forbidden vaults */
         prob_list[RoomType::LESSER_VAULT] = 0;
         prob_list[RoomType::GREATER_VAULT] = 0;
@@ -126,16 +127,16 @@ bool generate_rooms(PlayerType *player_ptr, dun_data_type *dd_ptr)
     }
 
     /*! @details ダンジョンにBEGINNERフラグがあるならば、FIXED_ROOMを除外 / Forbidden vaults */
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::BEGINNER)) {
+    if (dungeon.flags.has(DungeonFeatureType::BEGINNER)) {
         prob_list[RoomType::FIXED] = 0;
     }
 
     /*! @details ダンジョンにNO_CAVEフラグがある場合、FRACAVEの生成枠がNORMALに与えられる。CRIPT、OVALの生成枠がINNER_Fに与えられる。/ NO_CAVE dungeon */
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE)) {
+    if (dungeon.flags.has(DungeonFeatureType::NO_CAVE)) {
         move_prob_list(RoomType::NORMAL, RoomType::FRACAVE, prob_list);
         move_prob_list(RoomType::INNER_FEAT, RoomType::CRYPT, prob_list);
         move_prob_list(RoomType::INNER_FEAT, RoomType::OVAL, prob_list);
-    } else if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::CAVE)) {
+    } else if (dungeon.flags.has(DungeonFeatureType::CAVE)) {
         /*! @details ダンジョンにCAVEフラグがある場合、NORMALの生成枠がFRACAVEに与えられる。/ CAVE dungeon (Orc floor_ptr->grid_array etc.) */
         move_prob_list(RoomType::FRACAVE, RoomType::NORMAL, prob_list);
     } else if (dd_ptr->cavern || dd_ptr->empty_level) {
@@ -144,12 +145,12 @@ bool generate_rooms(PlayerType *player_ptr, dun_data_type *dd_ptr)
     }
 
     /*! @details ダンジョンに最初からGLASS_ROOMフラグがある場合、GLASS を生成から除外。/ Forbidden glass rooms */
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::GLASS_ROOM)) {
+    if (dungeon.flags.has_not(DungeonFeatureType::GLASS_ROOM)) {
         prob_list[RoomType::GLASS] = 0;
     }
 
     /*! @details ARCADEは同フラグがダンジョンにないと生成されない。 / Forbidden glass rooms */
-    if (dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::ARCADE)) {
+    if (dungeon.flags.has_not(DungeonFeatureType::ARCADE)) {
         prob_list[RoomType::ARCADE] = 0;
     }
 
index f2eb21a..5ca4719 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct dun_data_type;
 class PlayerType;
index df8ef63..bf2fe0f 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/room-info-table.h"
+#include "room/room-info-table.h"
 
 /*!
  * 各部屋タイプの生成比定義
index e33b1ae..d25cff2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "room/room-types.h"
 #include "system/angband.h"
index e6b2481..246586c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "util/enum-converter.h"
 #include "util/enum-range.h"
index 810f668..6a7c745 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ダンジョンフロアの部屋生成処理 / make rooms. Used by generate.c when creating dungeons.
  * @date 2014/01/06
  * @author
@@ -38,6 +38,7 @@
 #include "room/rooms-builder.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/cave.h"
+#include "floor/geometry.h"
 #include "grid/door.h"
 #include "grid/feature.h"
 #include "grid/grid.h"
@@ -75,20 +76,8 @@ void build_small_room(PlayerType *player_ptr, POSITION x0, POSITION y0)
         place_bold(player_ptr, y0 + 1, x, GB_INNER);
     }
 
-    switch (randint0(4)) {
-    case 0:
-        place_secret_door(player_ptr, y0, x0 - 1, DOOR_DEFAULT);
-        break;
-    case 1:
-        place_secret_door(player_ptr, y0, x0 + 1, DOOR_DEFAULT);
-        break;
-    case 2:
-        place_secret_door(player_ptr, y0 - 1, x0, DOOR_DEFAULT);
-        break;
-    case 3:
-        place_secret_door(player_ptr, y0 + 1, x0, DOOR_DEFAULT);
-        break;
-    }
+    const auto n = randint0(4);
+    place_secret_door(player_ptr, y0 + ddy_ddd[n], x0 + ddx_ddd[n], DOOR_DEFAULT);
 
     player_ptr->current_floor_ptr->grid_array[y0][x0].mimic = 0;
     place_bold(player_ptr, y0, x0, GB_FLOOR);
@@ -102,7 +91,7 @@ void build_cavern(PlayerType *player_ptr)
     bool light = false;
     bool done = false;
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((floor_ptr->dun_level <= randint1(50)) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS)) {
+    if ((floor_ptr->dun_level <= randint1(50)) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS)) {
         light = true;
     }
 
@@ -356,27 +345,27 @@ void build_recursive_room(PlayerType *player_ptr, POSITION x1, POSITION y1, POSI
  */
 void add_outer_wall(PlayerType *player_ptr, POSITION x, POSITION y, int light, POSITION x1, POSITION y1, POSITION x2, POSITION y2)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!in_bounds(floor_ptr, y, x)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(y, x);
+    if (!in_bounds(&floor, pos.y, pos.x)) {
         return;
     }
 
-    grid_type *g_ptr;
-    g_ptr = &floor_ptr->grid_array[y][x];
-    if (g_ptr->is_room()) {
+    auto &grid = floor.get_grid(pos);
+    if (grid.is_room()) {
         return;
     }
 
-    g_ptr->info |= CAVE_ROOM;
-    TerrainType *f_ptr;
-    f_ptr = &terrains_info[g_ptr->feat];
-    if (g_ptr->is_floor()) {
-        for (int i = -1; i <= 1; i++) {
-            for (int j = -1; j <= 1; j++) {
-                if ((x + i >= x1) && (x + i <= x2) && (y + j >= y1) && (y + j <= y2)) {
-                    add_outer_wall(player_ptr, x + i, y + j, light, x1, y1, x2, y2);
+    grid.info |= CAVE_ROOM;
+    const auto &terrain = grid.get_terrain();
+    if (grid.is_floor()) {
+        for (auto i = -1; i <= 1; i++) {
+            for (auto j = -1; j <= 1; j++) {
+                const Pos2D pos_sweep(pos.y + j, pos.x + i);
+                if ((pos_sweep.x >= x1) && (pos_sweep.x <= x2) && (pos_sweep.y >= y1) && (pos_sweep.y <= y2)) {
+                    add_outer_wall(player_ptr, pos_sweep.x, pos_sweep.y, light, x1, y1, x2, y2);
                     if (light) {
-                        g_ptr->info |= CAVE_GLOW;
+                        grid.info |= CAVE_GLOW;
                     }
                 }
             }
@@ -385,18 +374,18 @@ void add_outer_wall(PlayerType *player_ptr, POSITION x, POSITION y, int light, P
         return;
     }
 
-    if (g_ptr->is_extra()) {
-        place_bold(player_ptr, y, x, GB_OUTER);
+    if (grid.is_extra()) {
+        place_bold(player_ptr, pos.y, pos.x, GB_OUTER);
         if (light) {
-            g_ptr->info |= CAVE_GLOW;
+            grid.info |= CAVE_GLOW;
         }
 
         return;
     }
 
-    if (permanent_wall(f_ptr)) {
+    if (terrain.is_permanent_wall()) {
         if (light) {
-            g_ptr->info |= CAVE_GLOW;
+            grid.info |= CAVE_GLOW;
         }
     }
 }
index ed6c017..6b7a2de 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index eceb1a7..fc17a46 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/rooms-city.h"
+#include "room/rooms-city.h"
 #include "floor/floor-generator.h"
 #include "floor/floor-town.h"
 #include "game-option/cheat-types.h"
@@ -22,8 +22,8 @@ static bool precalc_ugarcade(int town_hgt, int town_wid, int n, std::vector<ugbl
 {
     POSITION i, y, x, center_y, center_x;
     int tmp, attempt = 10000;
-    POSITION max_bldg_hgt = 3 * town_hgt / MAX_TOWN_HGT;
-    POSITION max_bldg_wid = 5 * town_wid / MAX_TOWN_WID;
+    auto max_buildings_height = 3 * town_hgt / MAX_TOWN_HGT;
+    auto max_buildings_width = 5 * town_wid / MAX_TOWN_WID;
     ugbldg_type *cur_ugbldg;
     std::vector<std::vector<bool>> ugarcade_used(town_hgt, std::vector<bool>(town_wid));
     bool abort;
@@ -34,13 +34,13 @@ static bool precalc_ugarcade(int town_hgt, int town_wid, int n, std::vector<ugbl
         do {
             center_y = rand_range(2, town_hgt - 3);
             center_x = rand_range(2, town_wid - 3);
-            tmp = center_y - randint1(max_bldg_hgt);
+            tmp = center_y - randint1(max_buildings_height);
             cur_ugbldg->y0 = std::max(tmp, 1);
-            tmp = center_x - randint1(max_bldg_wid);
+            tmp = center_x - randint1(max_buildings_width);
             cur_ugbldg->x0 = std::max(tmp, 1);
-            tmp = center_y + randint1(max_bldg_hgt);
+            tmp = center_y + randint1(max_buildings_height);
             cur_ugbldg->y1 = std::min(tmp, town_hgt - 2);
-            tmp = center_x + randint1(max_bldg_wid);
+            tmp = center_x + randint1(max_buildings_width);
             cur_ugbldg->x1 = std::min(tmp, town_wid - 2);
             for (abort = false, y = cur_ugbldg->y0; (y <= cur_ugbldg->y1) && !abort; y++) {
                 for (x = cur_ugbldg->x0; x <= cur_ugbldg->x1; x++) {
@@ -71,7 +71,7 @@ static bool precalc_ugarcade(int town_hgt, int town_wid, int n, std::vector<ugbl
 /* Create a new floor room with optional light */
 static void generate_room_floor(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, int light)
 {
-    grid_type *g_ptr;
+    Grid *g_ptr;
     for (POSITION y = y1; y <= y2; y++) {
         for (POSITION x = x1; x <= x2; x++) {
             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
@@ -145,11 +145,13 @@ static void build_stores(PlayerType *player_ptr, POSITION ltcy, POSITION ltcx, S
             break;
         }
 
-        if (auto it = std::find_if(terrains_info.begin(), terrains_info.end(),
-                [subtype = stores[i]](const TerrainType &f_ref) {
-                    return f_ref.flags.has(TerrainCharacteristics::STORE) && (i2enum<StoreSaleType>(static_cast<int>(f_ref.subtype)) == subtype);
+        const auto &terrains = TerrainList::get_instance();
+        const auto end = terrains.end();
+        if (auto it = std::find_if(terrains.begin(), end,
+                [subtype = stores[i]](const TerrainType &terrain) {
+                    return terrain.flags.has(TerrainCharacteristics::STORE) && (i2enum<StoreSaleType>(static_cast<int>(terrain.subtype)) == subtype);
                 });
-            it != terrains_info.end()) {
+            it != end) {
             cave_set_feat(player_ptr, ltcy + y, ltcx + x, (*it).idx);
             store_init(VALID_TOWNS, stores[i]);
         }
index 56b8472..7f69b8d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 765a29f..3a26a58 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/rooms-fractal.h"
+#include "room/rooms-fractal.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/floor-generator.h"
 #include "room/cave-filler.h"
@@ -44,7 +44,7 @@ bool build_type9(PlayerType *player_ptr, dun_data_type *dd_ptr)
     light = done = false;
     room = true;
 
-    if ((floor_ptr->dun_level <= randint1(25)) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS)) {
+    if ((floor_ptr->dun_level <= randint1(25)) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS)) {
         light = true;
     }
 
index 5edb557..78d5dbe 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct dun_data_type;
 class PlayerType;
index 86eb6e3..bc08b74 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/rooms-maze-vault.h"
+#include "room/rooms-maze-vault.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "game-option/cheat-types.h"
 #include "grid/grid.h"
@@ -101,7 +101,7 @@ void build_maze_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION
 {
     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("迷路ランダムVaultを生成しました。", "Maze Vault."));
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    bool light = ((floor_ptr->dun_level <= randint1(25)) && is_vault && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS));
+    bool light = ((floor_ptr->dun_level <= randint1(25)) && is_vault && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS));
     POSITION dy = ysize / 2 - 1;
     POSITION dx = xsize / 2 - 1;
     POSITION y1 = y0 - dy;
@@ -110,7 +110,7 @@ void build_maze_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION
     POSITION x2 = x0 + dx;
     for (POSITION y = y1 - 1; y <= y2 + 1; y++) {
         for (POSITION x = x1 - 1; x <= x2 + 1; x++) {
-            grid_type *g_ptr;
+            Grid *g_ptr;
             g_ptr = &floor_ptr->grid_array[y][x];
             g_ptr->info |= CAVE_ROOM;
             if (is_vault) {
index b70ab7f..53ee104 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 50194c1..89bfbc0 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/rooms-normal.h"
+#include "room/rooms-normal.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/geometry.h"
 #include "grid/door.h"
  */
 bool build_type1(PlayerType *player_ptr, dun_data_type *dd_ptr)
 {
-    POSITION y, x, y2, x2, yval, xval;
-    POSITION y1, x1, xsize, ysize;
-
-    bool light;
-
-    grid_type *g_ptr;
-
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    bool curtain = (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::CURTAIN)) && one_in_(dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) ? 48 : 512);
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    const auto is_curtain = dungeon.flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeon.flags.has(DungeonFeatureType::NO_CAVE) ? 48 : 512);
 
     /* Pick a room size */
-    y1 = randint1(4);
-    x1 = randint1(11);
-    y2 = randint1(3);
-    x2 = randint1(11);
-
-    xsize = x1 + x2 + 1;
-    ysize = y1 + y2 + 1;
+    auto y1 = randint1(4);
+    auto x1 = randint1(11);
+    auto y2 = randint1(3);
+    auto x2 = randint1(11);
+    auto xsize = x1 + x2 + 1;
+    auto ysize = y1 + y2 + 1;
 
     /* Find and reserve some space in the dungeon.  Get center of room. */
-    if (!find_space(player_ptr, dd_ptr, &yval, &xval, ysize + 2, xsize + 2)) {
+    int yval;
+    int xval;
+    auto is_pos_found = find_space(player_ptr, dd_ptr, &yval, &xval, ysize + 2, xsize + 2);
+    if (!is_pos_found) {
         /* Limit to the minimum room size, and retry */
         y1 = 1;
         x1 = 1;
@@ -52,13 +48,14 @@ bool build_type1(PlayerType *player_ptr, dun_data_type *dd_ptr)
         ysize = y1 + y2 + 1;
 
         /* Find and reserve some space in the dungeon.  Get center of room. */
-        if (!find_space(player_ptr, dd_ptr, &yval, &xval, ysize + 2, xsize + 2)) {
+        is_pos_found = find_space(player_ptr, dd_ptr, &yval, &xval, ysize + 2, xsize + 2);
+        if (!is_pos_found) {
             return false;
         }
     }
 
     /* Choose lite or dark */
-    light = ((floor_ptr->dun_level <= randint1(25)) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS));
+    const auto should_brighten = ((floor_ptr->dun_level <= randint1(25)) && dungeon.flags.has_not(DungeonFeatureType::DARKNESS));
 
     /* Get corner values */
     y1 = yval - ysize / 2;
@@ -67,57 +64,57 @@ bool build_type1(PlayerType *player_ptr, dun_data_type *dd_ptr)
     x2 = xval + (xsize - 1) / 2;
 
     /* Place a full floor under the room */
-    for (y = y1 - 1; y <= y2 + 1; y++) {
-        for (x = x1 - 1; x <= x2 + 1; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
-            g_ptr->info |= (CAVE_ROOM);
-            if (light) {
-                g_ptr->info |= (CAVE_GLOW);
+    for (auto y = y1 - 1; y <= y2 + 1; y++) {
+        for (auto x = x1 - 1; x <= x2 + 1; x++) {
+            auto &grid = floor_ptr->get_grid({ y, x });
+            place_grid(player_ptr, &grid, GB_FLOOR);
+            grid.info |= (CAVE_ROOM);
+            if (should_brighten) {
+                grid.info |= (CAVE_GLOW);
             }
         }
     }
 
     /* Walls around the room */
-    for (y = y1 - 1; y <= y2 + 1; y++) {
-        g_ptr = &floor_ptr->grid_array[y][x1 - 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y][x2 + 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto y = y1 - 1; y <= y2 + 1; y++) {
+        auto &grid1 = floor_ptr->get_grid({ y, x1 - 1 });
+        place_grid(player_ptr, &grid1, GB_OUTER);
+        auto &grid2 = floor_ptr->get_grid({ y, x2 + 1 });
+        place_grid(player_ptr, &grid2, GB_OUTER);
     }
-    for (x = x1 - 1; x <= x2 + 1; x++) {
-        g_ptr = &floor_ptr->grid_array[y1 - 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y2 + 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto x = x1 - 1; x <= x2 + 1; x++) {
+        auto &grid1 = floor_ptr->get_grid({ y1 - 1, x });
+        place_grid(player_ptr, &grid1, GB_OUTER);
+        auto &grid2 = floor_ptr->get_grid({ y2 + 1, x });
+        place_grid(player_ptr, &grid2, GB_OUTER);
     }
 
     /* Hack -- Occasional curtained room */
-    if (curtain && (y2 - y1 > 2) && (x2 - x1 > 2)) {
-        for (y = y1; y <= y2; y++) {
-            g_ptr = &floor_ptr->grid_array[y][x1];
-            g_ptr->feat = feat_door[DOOR_CURTAIN].closed;
-            g_ptr->info &= ~(CAVE_MASK);
-            g_ptr = &floor_ptr->grid_array[y][x2];
-            g_ptr->feat = feat_door[DOOR_CURTAIN].closed;
-            g_ptr->info &= ~(CAVE_MASK);
+    if (is_curtain && (y2 - y1 > 2) && (x2 - x1 > 2)) {
+        for (auto y = y1; y <= y2; y++) {
+            auto &grid1 = floor_ptr->get_grid({ y, x1 });
+            grid1.feat = feat_door[DOOR_CURTAIN].closed;
+            grid1.info &= ~(CAVE_MASK);
+            auto &grid2 = floor_ptr->get_grid({ y, x2 });
+            grid2.feat = feat_door[DOOR_CURTAIN].closed;
+            grid2.info &= ~(CAVE_MASK);
         }
-        for (x = x1; x <= x2; x++) {
-            g_ptr = &floor_ptr->grid_array[y1][x];
-            g_ptr->feat = feat_door[DOOR_CURTAIN].closed;
-            g_ptr->info &= ~(CAVE_MASK);
-            g_ptr = &floor_ptr->grid_array[y2][x];
-            g_ptr->feat = feat_door[DOOR_CURTAIN].closed;
-            g_ptr->info &= ~(CAVE_MASK);
+        for (auto x = x1; x <= x2; x++) {
+            auto &grid1 = floor_ptr->get_grid({ y1, x });
+            grid1.feat = feat_door[DOOR_CURTAIN].closed;
+            grid1.info &= ~(CAVE_MASK);
+            auto &grid2 = floor_ptr->get_grid({ y2, x });
+            grid2.feat = feat_door[DOOR_CURTAIN].closed;
+            grid2.info &= ~(CAVE_MASK);
         }
     }
 
     /* Hack -- Occasional pillar room */
     if (one_in_(20)) {
-        for (y = y1; y <= y2; y += 2) {
-            for (x = x1; x <= x2; x += 2) {
-                g_ptr = &floor_ptr->grid_array[y][x];
-                place_grid(player_ptr, g_ptr, GB_INNER);
+        for (auto y = y1; y <= y2; y += 2) {
+            for (auto x = x1; x <= x2; x += 2) {
+                auto &grid = floor_ptr->get_grid({ y, x });
+                place_grid(player_ptr, &grid, GB_INNER);
             }
         }
     }
@@ -125,45 +122,33 @@ bool build_type1(PlayerType *player_ptr, dun_data_type *dd_ptr)
     /* Hack -- Occasional room with four pillars */
     else if (one_in_(20)) {
         if ((y1 + 4 < y2) && (x1 + 4 < x2)) {
-            g_ptr = &floor_ptr->grid_array[y1 + 1][x1 + 1];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-
-            g_ptr = &floor_ptr->grid_array[y1 + 1][x2 - 1];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-
-            g_ptr = &floor_ptr->grid_array[y2 - 1][x1 + 1];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-
-            g_ptr = &floor_ptr->grid_array[y2 - 1][x2 - 1];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y1 + 1, x1 + 1 }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y1 + 1, x2 - 1 }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y2 - 1, x1 + 1 }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y2 - 1, x2 - 1 }), GB_INNER);
         }
     }
 
     /* Hack -- Occasional ragged-edge room */
     else if (one_in_(50)) {
-        for (y = y1 + 2; y <= y2 - 2; y += 2) {
-            g_ptr = &floor_ptr->grid_array[y][x1];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[y][x2];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+        for (auto y = y1 + 2; y <= y2 - 2; y += 2) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, x1 }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, x2 }), GB_INNER);
         }
-        for (x = x1 + 2; x <= x2 - 2; x += 2) {
-            g_ptr = &floor_ptr->grid_array[y1][x];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[y2][x];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+        for (auto x = x1 + 2; x <= x2 - 2; x += 2) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y1, x }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y2, x }), GB_INNER);
         }
     }
     /* Hack -- Occasional divided room */
     else if (one_in_(50)) {
-        bool curtain2 = (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::CURTAIN)) && one_in_(dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) ? 2 : 128);
-
+        const auto should_close_curtain = (dungeon.flags.has(DungeonFeatureType::CURTAIN)) && one_in_(dungeon.flags.has(DungeonFeatureType::NO_CAVE) ? 2 : 128);
         if (randint1(100) < 50) {
             /* Horizontal wall */
-            for (x = x1; x <= x2; x++) {
+            for (auto x = x1; x <= x2; x++) {
                 place_bold(player_ptr, yval, x, GB_INNER);
-                if (curtain2) {
-                    floor_ptr->grid_array[yval][x].feat = feat_door[DOOR_CURTAIN].closed;
+                if (should_close_curtain) {
+                    floor_ptr->get_grid({ yval, x }).feat = feat_door[DOOR_CURTAIN].closed;
                 }
             }
 
@@ -172,10 +157,10 @@ bool build_type1(PlayerType *player_ptr, dun_data_type *dd_ptr)
             place_bold(player_ptr, yval, x2 + 1, GB_SOLID);
         } else {
             /* Vertical wall */
-            for (y = y1; y <= y2; y++) {
+            for (auto y = y1; y <= y2; y++) {
                 place_bold(player_ptr, y, xval, GB_INNER);
-                if (curtain2) {
-                    floor_ptr->grid_array[y][xval].feat = feat_door[DOOR_CURTAIN].closed;
+                if (should_close_curtain) {
+                    floor_ptr->get_grid({ y, xval }).feat = feat_door[DOOR_CURTAIN].closed;
                 }
             }
 
@@ -185,8 +170,8 @@ bool build_type1(PlayerType *player_ptr, dun_data_type *dd_ptr)
         }
 
         place_random_door(player_ptr, yval, xval, true);
-        if (curtain2) {
-            floor_ptr->grid_array[yval][xval].feat = feat_door[DOOR_CURTAIN].closed;
+        if (should_close_curtain) {
+            floor_ptr->get_grid({ yval, xval }).feat = feat_door[DOOR_CURTAIN].closed;
         }
     }
 
@@ -199,98 +184,85 @@ bool build_type1(PlayerType *player_ptr, dun_data_type *dd_ptr)
  */
 bool build_type2(PlayerType *player_ptr, dun_data_type *dd_ptr)
 {
-    POSITION y, x, xval, yval;
-    POSITION y1a, x1a, y2a, x2a;
-    POSITION y1b, x1b, y2b, x2b;
-    bool light;
-    grid_type *g_ptr;
-
     /* Find and reserve some space in the dungeon.  Get center of room. */
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!find_space(player_ptr, dd_ptr, &yval, &xval, 11, 25)) {
+    int yval;
+    int xval;
+    const auto is_pos_found = find_space(player_ptr, dd_ptr, &yval, &xval, 11, 25);
+    if (!is_pos_found) {
         return false;
     }
 
     /* Choose lite or dark */
-    light = ((floor_ptr->dun_level <= randint1(25)) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS));
+    const auto should_brighten = (floor_ptr->dun_level <= randint1(25)) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS);
 
     /* Determine extents of the first room */
-    y1a = yval - randint1(4);
-    y2a = yval + randint1(3);
-    x1a = xval - randint1(11);
-    x2a = xval + randint1(10);
+    auto y1a = yval - randint1(4);
+    auto y2a = yval + randint1(3);
+    auto x1a = xval - randint1(11);
+    auto x2a = xval + randint1(10);
 
     /* Determine extents of the second room */
-    y1b = yval - randint1(3);
-    y2b = yval + randint1(4);
-    x1b = xval - randint1(10);
-    x2b = xval + randint1(11);
+    auto y1b = yval - randint1(3);
+    auto y2b = yval + randint1(4);
+    auto x1b = xval - randint1(10);
+    auto x2b = xval + randint1(11);
 
     /* Place a full floor for room "a" */
-    for (y = y1a - 1; y <= y2a + 1; y++) {
-        for (x = x1a - 1; x <= x2a + 1; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
-            g_ptr->info |= (CAVE_ROOM);
-            if (light) {
-                g_ptr->info |= (CAVE_GLOW);
+    for (auto y = y1a - 1; y <= y2a + 1; y++) {
+        for (auto x = x1a - 1; x <= x2a + 1; x++) {
+            auto &grid = floor_ptr->get_grid({ y, x });
+            place_grid(player_ptr, &grid, GB_FLOOR);
+            grid.info |= (CAVE_ROOM);
+            if (should_brighten) {
+                grid.info |= (CAVE_GLOW);
             }
         }
     }
 
     /* Place a full floor for room "b" */
-    for (y = y1b - 1; y <= y2b + 1; y++) {
-        for (x = x1b - 1; x <= x2b + 1; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
-            g_ptr->info |= (CAVE_ROOM);
-            if (light) {
-                g_ptr->info |= (CAVE_GLOW);
+    for (auto y = y1b - 1; y <= y2b + 1; y++) {
+        for (auto x = x1b - 1; x <= x2b + 1; x++) {
+            auto &grid = floor_ptr->get_grid({ y, x });
+            place_grid(player_ptr, &grid, GB_FLOOR);
+            grid.info |= (CAVE_ROOM);
+            if (should_brighten) {
+                grid.info |= (CAVE_GLOW);
             }
         }
     }
 
     /* Place the walls around room "a" */
-    for (y = y1a - 1; y <= y2a + 1; y++) {
-        g_ptr = &floor_ptr->grid_array[y][x1a - 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y][x2a + 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto y = y1a - 1; y <= y2a + 1; y++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x1a - 1 }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x2a + 1 }), GB_OUTER);
     }
-    for (x = x1a - 1; x <= x2a + 1; x++) {
-        g_ptr = &floor_ptr->grid_array[y1a - 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y2a + 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto x = x1a - 1; x <= x2a + 1; x++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y1a - 1, x }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y2a + 1, x }), GB_OUTER);
     }
 
     /* Place the walls around room "b" */
-    for (y = y1b - 1; y <= y2b + 1; y++) {
-        g_ptr = &floor_ptr->grid_array[y][x1b - 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y][x2b + 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto y = y1b - 1; y <= y2b + 1; y++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x1b - 1 }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x2b + 1 }), GB_OUTER);
     }
-    for (x = x1b - 1; x <= x2b + 1; x++) {
-        g_ptr = &floor_ptr->grid_array[y1b - 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y2b + 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto x = x1b - 1; x <= x2b + 1; x++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y1b - 1, x }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y2b + 1, x }), GB_OUTER);
     }
 
     /* Replace the floor for room "a" */
-    for (y = y1a; y <= y2a; y++) {
-        for (x = x1a; x <= x2a; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
+    for (auto y = y1a; y <= y2a; y++) {
+        for (auto x = x1a; x <= x2a; x++) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_FLOOR);
         }
     }
 
     /* Replace the floor for room "b" */
-    for (y = y1b; y <= y2b; y++) {
-        for (x = x1b; x <= x2b; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
+    for (auto y = y1b; y <= y2b; y++) {
+        for (auto x = x1b; x <= x2b; x++) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_FLOOR);
         }
     }
 
@@ -312,108 +284,96 @@ bool build_type2(PlayerType *player_ptr, dun_data_type *dd_ptr)
  */
 bool build_type3(PlayerType *player_ptr, dun_data_type *dd_ptr)
 {
-    POSITION y, x, dy, dx, wy, wx;
-    POSITION y1a, x1a, y2a, x2a;
-    POSITION y1b, x1b, y2b, x2b;
-    POSITION yval, xval;
-    bool light;
-    grid_type *g_ptr;
-
     /* Find and reserve some space in the dungeon.  Get center of room. */
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!find_space(player_ptr, dd_ptr, &yval, &xval, 11, 25)) {
+    int yval;
+    int xval;
+    const auto is_pos_found = find_space(player_ptr, dd_ptr, &yval, &xval, 11, 25);
+    if (!is_pos_found) {
         return false;
     }
 
     /* Choose lite or dark */
-    light = ((floor_ptr->dun_level <= randint1(25)) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS));
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    const auto should_brighten = ((floor_ptr->dun_level <= randint1(25)) && dungeon.flags.has_not(DungeonFeatureType::DARKNESS));
 
     /* For now, always 3x3 */
-    wx = wy = 1;
+    auto wx = 1;
+    auto wy = 1;
 
     /* Pick max vertical size (at most 4) */
-    dy = rand_range(3, 4);
+    auto dy = rand_range(3, 4);
 
     /* Pick max horizontal size (at most 15) */
-    dx = rand_range(3, 11);
+    auto dx = rand_range(3, 11);
 
     /* Determine extents of the north/south room */
-    y1a = yval - dy;
-    y2a = yval + dy;
-    x1a = xval - wx;
-    x2a = xval + wx;
+    auto y1a = yval - dy;
+    auto y2a = yval + dy;
+    auto x1a = xval - wx;
+    auto x2a = xval + wx;
 
     /* Determine extents of the east/west room */
-    y1b = yval - wy;
-    y2b = yval + wy;
-    x1b = xval - dx;
-    x2b = xval + dx;
+    auto y1b = yval - wy;
+    auto y2b = yval + wy;
+    auto x1b = xval - dx;
+    auto x2b = xval + dx;
 
     /* Place a full floor for room "a" */
-    for (y = y1a - 1; y <= y2a + 1; y++) {
-        for (x = x1a - 1; x <= x2a + 1; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
-            g_ptr->info |= (CAVE_ROOM);
-            if (light) {
-                g_ptr->info |= (CAVE_GLOW);
+    for (auto y = y1a - 1; y <= y2a + 1; y++) {
+        for (auto x = x1a - 1; x <= x2a + 1; x++) {
+            auto &grid = floor_ptr->get_grid({ y, x });
+            place_grid(player_ptr, &grid, GB_FLOOR);
+            grid.info |= (CAVE_ROOM);
+            if (should_brighten) {
+                grid.info |= (CAVE_GLOW);
             }
         }
     }
 
     /* Place a full floor for room "b" */
-    for (y = y1b - 1; y <= y2b + 1; y++) {
-        for (x = x1b - 1; x <= x2b + 1; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
-            g_ptr->info |= (CAVE_ROOM);
-            if (light) {
-                g_ptr->info |= (CAVE_GLOW);
+    for (auto y = y1b - 1; y <= y2b + 1; y++) {
+        for (auto x = x1b - 1; x <= x2b + 1; x++) {
+            auto &grid = floor_ptr->get_grid({ y, x });
+            place_grid(player_ptr, &grid, GB_FLOOR);
+            grid.info |= (CAVE_ROOM);
+            if (should_brighten) {
+                grid.info |= (CAVE_GLOW);
             }
         }
     }
 
     /* Place the walls around room "a" */
-    for (y = y1a - 1; y <= y2a + 1; y++) {
-        g_ptr = &floor_ptr->grid_array[y][x1a - 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y][x2a + 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto y = y1a - 1; y <= y2a + 1; y++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x1a - 1 }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x2a + 1 }), GB_OUTER);
     }
-    for (x = x1a - 1; x <= x2a + 1; x++) {
-        g_ptr = &floor_ptr->grid_array[y1a - 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y2a + 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto x = x1a - 1; x <= x2a + 1; x++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y1a - 1, x }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y2a + 1, x }), GB_OUTER);
     }
 
     /* Place the walls around room "b" */
-    for (y = y1b - 1; y <= y2b + 1; y++) {
-        g_ptr = &floor_ptr->grid_array[y][x1b - 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y][x2b + 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto y = y1b - 1; y <= y2b + 1; y++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x1b - 1 }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x2b + 1 }), GB_OUTER);
     }
-    for (x = x1b - 1; x <= x2b + 1; x++) {
-        g_ptr = &floor_ptr->grid_array[y1b - 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y2b + 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto x = x1b - 1; x <= x2b + 1; x++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y1b - 1, x }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y2b + 1, x }), GB_OUTER);
     }
 
     /* Replace the floor for room "a" */
-    for (y = y1a; y <= y2a; y++) {
-        for (x = x1a; x <= x2a; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
+    for (auto y = y1a; y <= y2a; y++) {
+        for (auto x = x1a; x <= x2a; x++) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_FLOOR);
         }
     }
 
     /* Replace the floor for room "b" */
-    for (y = y1b; y <= y2b; y++) {
-        for (x = x1b; x <= x2b; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
+    for (auto y = y1b; y <= y2b; y++) {
+        for (auto x = x1b; x <= x2b; x++) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_FLOOR);
         }
     }
 
@@ -421,10 +381,9 @@ bool build_type3(PlayerType *player_ptr, dun_data_type *dd_ptr)
     switch (randint0(4)) {
         /* Large solid middle pillar */
     case 1: {
-        for (y = y1b; y <= y2b; y++) {
-            for (x = x1a; x <= x2a; x++) {
-                g_ptr = &floor_ptr->grid_array[y][x];
-                place_grid(player_ptr, g_ptr, GB_INNER);
+        for (auto y = y1b; y <= y2b; y++) {
+            for (auto x = x1a; x <= x2a; x++) {
+                place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_INNER);
             }
         }
         break;
@@ -433,17 +392,13 @@ bool build_type3(PlayerType *player_ptr, dun_data_type *dd_ptr)
     /* Inner treasure vault */
     case 2: {
         /* Build the vault */
-        for (y = y1b; y <= y2b; y++) {
-            g_ptr = &floor_ptr->grid_array[y][x1a];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[y][x2a];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+        for (auto y = y1b; y <= y2b; y++) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, x1a }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, x2a }), GB_INNER);
         }
-        for (x = x1a; x <= x2a; x++) {
-            g_ptr = &floor_ptr->grid_array[y1b][x];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[y2b][x];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+        for (auto x = x1a; x <= x2a; x++) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y1b, x }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y1b, x }), GB_INNER);
         }
 
         /* Place a secret door on the inner room */
@@ -463,13 +418,13 @@ bool build_type3(PlayerType *player_ptr, dun_data_type *dd_ptr)
         }
 
         /* Place a treasure in the vault */
-        place_object(player_ptr, yval, xval, 0L);
+        place_object(player_ptr, yval, xval, 0);
 
         /* Let's guard the treasure well */
         vault_monsters(player_ptr, yval, xval, randint0(2) + 3);
 
         /* Traps naturally */
-        vault_traps(player_ptr, yval, xval, 4, 4, randint0(3) + 2);
+        vault_traps(floor_ptr, yval, xval, 4, 4, randint0(3) + 2);
 
         break;
     }
@@ -479,32 +434,30 @@ bool build_type3(PlayerType *player_ptr, dun_data_type *dd_ptr)
         /* Occasionally pinch the center shut */
         if (one_in_(3)) {
             /* Pinch the east/west sides */
-            for (y = y1b; y <= y2b; y++) {
+            for (auto y = y1b; y <= y2b; y++) {
                 if (y == yval) {
                     continue;
                 }
-                g_ptr = &floor_ptr->grid_array[y][x1a - 1];
-                place_grid(player_ptr, g_ptr, GB_INNER);
-                g_ptr = &floor_ptr->grid_array[y][x2a + 1];
-                place_grid(player_ptr, g_ptr, GB_INNER);
+
+                place_grid(player_ptr, &floor_ptr->get_grid({ y, x1a - 1 }), GB_INNER);
+                place_grid(player_ptr, &floor_ptr->get_grid({ y, x2a + 1 }), GB_INNER);
             }
 
             /* Pinch the north/south sides */
-            for (x = x1a; x <= x2a; x++) {
+            for (auto x = x1a; x <= x2a; x++) {
                 if (x == xval) {
                     continue;
                 }
-                g_ptr = &floor_ptr->grid_array[y1b - 1][x];
-                place_grid(player_ptr, g_ptr, GB_INNER);
-                g_ptr = &floor_ptr->grid_array[y2b + 1][x];
-                place_grid(player_ptr, g_ptr, GB_INNER);
+
+                place_grid(player_ptr, &floor_ptr->grid_array[y1b - 1][x], GB_INNER);
+                place_grid(player_ptr, &floor_ptr->grid_array[y2b + 1][x], GB_INNER);
             }
 
             /* Sometimes shut using secret doors */
             if (one_in_(3)) {
-                int door_type = (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
+                int door_type = (dungeon.flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeon.flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
                                     ? DOOR_CURTAIN
-                                    : (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
+                                    : (dungeon.flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
 
                 place_secret_door(player_ptr, yval, x1a - 1, door_type);
                 place_secret_door(player_ptr, yval, x2a + 1, door_type);
@@ -515,22 +468,16 @@ bool build_type3(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
         /* Occasionally put a "plus" in the center */
         else if (one_in_(3)) {
-            g_ptr = &floor_ptr->grid_array[yval][xval];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[y1b][xval];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[y2b][xval];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[yval][x1a];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[yval][x2a];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ yval, xval }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y1b, xval }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ y2b, xval }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ yval, x1a }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ yval, x2a }), GB_INNER);
         }
 
         /* Occasionally put a pillar in the center */
         else if (one_in_(3)) {
-            g_ptr = &floor_ptr->grid_array[yval][xval];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ yval, xval }), GB_INNER);
         }
 
         break;
@@ -553,70 +500,60 @@ bool build_type3(PlayerType *player_ptr, dun_data_type *dd_ptr)
  */
 bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
 {
-    POSITION y, x, y1, x1;
-    POSITION y2, x2, tmp, yval, xval;
-    bool light;
-    grid_type *g_ptr;
-
     /* Find and reserve some space in the dungeon.  Get center of room. */
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!find_space(player_ptr, dd_ptr, &yval, &xval, 11, 25)) {
+    const auto &dungeon = floor_ptr->get_dungeon_definition();
+    int yval;
+    int xval;
+    const auto is_pos_found = find_space(player_ptr, dd_ptr, &yval, &xval, 11, 25);
+    if (!is_pos_found) {
         return false;
     }
 
     /* Choose lite or dark */
-    light = ((floor_ptr->dun_level <= randint1(25)) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS));
+    const auto should_brighten = ((floor_ptr->dun_level <= randint1(25)) && dungeon.flags.has_not(DungeonFeatureType::DARKNESS));
 
     /* Large room */
-    y1 = yval - 4;
-    y2 = yval + 4;
-    x1 = xval - 11;
-    x2 = xval + 11;
+    const auto y1_outer = yval - 4;
+    const auto y2_outer = yval + 4;
+    const auto x1_outer = xval - 11;
+    const auto x2_outer = xval + 11;
 
     /* Place a full floor under the room */
-    for (y = y1 - 1; y <= y2 + 1; y++) {
-        for (x = x1 - 1; x <= x2 + 1; x++) {
-            g_ptr = &floor_ptr->grid_array[y][x];
-            place_grid(player_ptr, g_ptr, GB_FLOOR);
-            g_ptr->info |= (CAVE_ROOM);
-            if (light) {
-                g_ptr->info |= (CAVE_GLOW);
+    for (auto y = y1_outer - 1; y <= y2_outer + 1; y++) {
+        for (auto x = x1_outer - 1; x <= x2_outer + 1; x++) {
+            auto &grid = floor_ptr->get_grid({ y, x });
+            place_grid(player_ptr, &grid, GB_FLOOR);
+            grid.info |= (CAVE_ROOM);
+            if (should_brighten) {
+                grid.info |= (CAVE_GLOW);
             }
         }
     }
 
     /* Outer Walls */
-    for (y = y1 - 1; y <= y2 + 1; y++) {
-        g_ptr = &floor_ptr->grid_array[y][x1 - 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y][x2 + 1];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto y = y1_outer - 1; y <= y2_outer + 1; y++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x1_outer - 1 }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x2_outer + 1 }), GB_OUTER);
     }
-    for (x = x1 - 1; x <= x2 + 1; x++) {
-        g_ptr = &floor_ptr->grid_array[y1 - 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
-        g_ptr = &floor_ptr->grid_array[y2 + 1][x];
-        place_grid(player_ptr, g_ptr, GB_OUTER);
+    for (auto x = x1_outer - 1; x <= x2_outer + 1; x++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y1_outer - 1, x }), GB_OUTER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y2_outer + 1, x }), GB_OUTER);
     }
 
-    /* The inner room */
-    y1 = y1 + 2;
-    y2 = y2 - 2;
-    x1 = x1 + 2;
-    x2 = x2 - 2;
+    const auto y1_inner = y1_outer + 2;
+    const auto y2_inner = y2_outer - 2;
+    const auto x1_inner = x1_outer + 2;
+    const auto x2_inner = x2_outer - 2;
 
     /* The inner walls */
-    for (y = y1 - 1; y <= y2 + 1; y++) {
-        g_ptr = &floor_ptr->grid_array[y][x1 - 1];
-        place_grid(player_ptr, g_ptr, GB_INNER);
-        g_ptr = &floor_ptr->grid_array[y][x2 + 1];
-        place_grid(player_ptr, g_ptr, GB_INNER);
+    for (auto y = y1_inner - 1; y <= y2_inner + 1; y++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x1_inner - 1 }), GB_INNER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y, x2_inner + 1 }), GB_INNER);
     }
-    for (x = x1 - 1; x <= x2 + 1; x++) {
-        g_ptr = &floor_ptr->grid_array[y1 - 1][x];
-        place_grid(player_ptr, g_ptr, GB_INNER);
-        g_ptr = &floor_ptr->grid_array[y2 + 1][x];
-        place_grid(player_ptr, g_ptr, GB_INNER);
+    for (auto x = x1_inner - 1; x <= x2_inner + 1; x++) {
+        place_grid(player_ptr, &floor_ptr->get_grid({ y1_inner - 1, x }), GB_INNER);
+        place_grid(player_ptr, &floor_ptr->get_grid({ y2_inner + 1, x }), GB_INNER);
     }
 
     /* Inner room variations */
@@ -626,16 +563,16 @@ bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
         /* Place a secret door */
         switch (randint1(4)) {
         case 1:
-            place_secret_door(player_ptr, y1 - 1, xval, DOOR_DEFAULT);
+            place_secret_door(player_ptr, y1_inner - 1, xval, DOOR_DEFAULT);
             break;
         case 2:
-            place_secret_door(player_ptr, y2 + 1, xval, DOOR_DEFAULT);
+            place_secret_door(player_ptr, y2_inner + 1, xval, DOOR_DEFAULT);
             break;
         case 3:
-            place_secret_door(player_ptr, yval, x1 - 1, DOOR_DEFAULT);
+            place_secret_door(player_ptr, yval, x1_inner - 1, DOOR_DEFAULT);
             break;
         case 4:
-            place_secret_door(player_ptr, yval, x2 + 1, DOOR_DEFAULT);
+            place_secret_door(player_ptr, yval, x2_inner + 1, DOOR_DEFAULT);
             break;
         }
 
@@ -650,27 +587,27 @@ bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
         /* Place a secret door */
         switch (randint1(4)) {
         case 1:
-            place_secret_door(player_ptr, y1 - 1, xval, DOOR_DEFAULT);
+            place_secret_door(player_ptr, y1_inner - 1, xval, DOOR_DEFAULT);
             break;
         case 2:
-            place_secret_door(player_ptr, y2 + 1, xval, DOOR_DEFAULT);
+            place_secret_door(player_ptr, y2_inner + 1, xval, DOOR_DEFAULT);
             break;
         case 3:
-            place_secret_door(player_ptr, yval, x1 - 1, DOOR_DEFAULT);
+            place_secret_door(player_ptr, yval, x1_inner - 1, DOOR_DEFAULT);
             break;
         case 4:
-            place_secret_door(player_ptr, yval, x2 + 1, DOOR_DEFAULT);
+            place_secret_door(player_ptr, yval, x2_inner + 1, DOOR_DEFAULT);
             break;
         }
 
         /* Place another inner room */
-        for (y = yval - 1; y <= yval + 1; y++) {
-            for (x = xval - 1; x <= xval + 1; x++) {
+        for (auto y = yval - 1; y <= yval + 1; y++) {
+            for (auto x = xval - 1; x <= xval + 1; x++) {
                 if ((x == xval) && (y == yval)) {
                     continue;
                 }
-                g_ptr = &floor_ptr->grid_array[y][x];
-                place_grid(player_ptr, g_ptr, GB_INNER);
+
+                place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_INNER);
             }
         }
 
@@ -704,7 +641,7 @@ bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
         }
 
         /* Traps to protect the treasure */
-        vault_traps(player_ptr, yval, xval, 4, 10, 2 + randint1(3));
+        vault_traps(floor_ptr, yval, xval, 4, 10, 2 + randint1(3));
 
         break;
     }
@@ -714,61 +651,55 @@ bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
         /* Place a secret door */
         switch (randint1(4)) {
         case 1:
-            place_secret_door(player_ptr, y1 - 1, xval, DOOR_DEFAULT);
+            place_secret_door(player_ptr, y1_inner - 1, xval, DOOR_DEFAULT);
             break;
         case 2:
-            place_secret_door(player_ptr, y2 + 1, xval, DOOR_DEFAULT);
+            place_secret_door(player_ptr, y2_inner + 1, xval, DOOR_DEFAULT);
             break;
         case 3:
-            place_secret_door(player_ptr, yval, x1 - 1, DOOR_DEFAULT);
+            place_secret_door(player_ptr, yval, x1_inner - 1, DOOR_DEFAULT);
             break;
         case 4:
-            place_secret_door(player_ptr, yval, x2 + 1, DOOR_DEFAULT);
+            place_secret_door(player_ptr, yval, x2_inner + 1, DOOR_DEFAULT);
             break;
         }
 
         /* Large Inner Pillar */
-        for (y = yval - 1; y <= yval + 1; y++) {
-            for (x = xval - 1; x <= xval + 1; x++) {
-                g_ptr = &floor_ptr->grid_array[y][x];
-                place_grid(player_ptr, g_ptr, GB_INNER);
+        for (auto y = yval - 1; y <= yval + 1; y++) {
+            for (auto x = xval - 1; x <= xval + 1; x++) {
+                place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_INNER);
             }
         }
 
         /* Occasionally, two more Large Inner Pillars */
         if (one_in_(2)) {
-            tmp = randint1(2);
-            for (y = yval - 1; y <= yval + 1; y++) {
-                for (x = xval - 5 - tmp; x <= xval - 3 - tmp; x++) {
-                    g_ptr = &floor_ptr->grid_array[y][x];
-                    place_grid(player_ptr, g_ptr, GB_INNER);
+            const auto tmp = randint1(2);
+            for (auto y = yval - 1; y <= yval + 1; y++) {
+                for (auto x = xval - 5 - tmp; x <= xval - 3 - tmp; x++) {
+                    place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_INNER);
                 }
-                for (x = xval + 3 + tmp; x <= xval + 5 + tmp; x++) {
-                    g_ptr = &floor_ptr->grid_array[y][x];
-                    place_grid(player_ptr, g_ptr, GB_INNER);
+
+                for (auto x = xval + 3 + tmp; x <= xval + 5 + tmp; x++) {
+                    place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_INNER);
                 }
             }
         }
 
         /* Occasionally, some Inner rooms */
         if (one_in_(3)) {
-            int door_type = (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
+            int door_type = (dungeon.flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeon.flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
                                 ? DOOR_CURTAIN
-                                : (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
+                                : (dungeon.flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
 
             /* Long horizontal walls */
-            for (x = xval - 5; x <= xval + 5; x++) {
-                g_ptr = &floor_ptr->grid_array[yval - 1][x];
-                place_grid(player_ptr, g_ptr, GB_INNER);
-                g_ptr = &floor_ptr->grid_array[yval + 1][x];
-                place_grid(player_ptr, g_ptr, GB_INNER);
+            for (auto x = xval - 5; x <= xval + 5; x++) {
+                place_grid(player_ptr, &floor_ptr->get_grid({ yval - 1, x }), GB_INNER);
+                place_grid(player_ptr, &floor_ptr->get_grid({ yval + 1, x }), GB_INNER);
             }
 
             /* Close off the left/right edges */
-            g_ptr = &floor_ptr->grid_array[yval][xval - 5];
-            place_grid(player_ptr, g_ptr, GB_INNER);
-            g_ptr = &floor_ptr->grid_array[yval][xval + 5];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ yval, xval - 5 }), GB_INNER);
+            place_grid(player_ptr, &floor_ptr->get_grid({ yval, xval + 5 }), GB_INNER);
 
             /* Secret doors (random top/bottom) */
             place_secret_door(player_ptr, yval - 3 + (randint1(2) * 2), xval - 3, door_type);
@@ -795,25 +726,24 @@ bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
         /* Place a secret door */
         switch (randint1(4)) {
         case 1:
-            place_secret_door(player_ptr, y1 - 1, xval, DOOR_DEFAULT);
+            place_secret_door(player_ptr, y1_inner - 1, xval, DOOR_DEFAULT);
             break;
         case 2:
-            place_secret_door(player_ptr, y2 + 1, xval, DOOR_DEFAULT);
+            place_secret_door(player_ptr, y2_inner + 1, xval, DOOR_DEFAULT);
             break;
         case 3:
-            place_secret_door(player_ptr, yval, x1 - 1, DOOR_DEFAULT);
+            place_secret_door(player_ptr, yval, x1_inner - 1, DOOR_DEFAULT);
             break;
         case 4:
-            place_secret_door(player_ptr, yval, x2 + 1, DOOR_DEFAULT);
+            place_secret_door(player_ptr, yval, x2_inner + 1, DOOR_DEFAULT);
             break;
         }
 
         /* Maze (really a checkerboard) */
-        for (y = y1; y <= y2; y++) {
-            for (x = x1; x <= x2; x++) {
+        for (auto y = y1_inner; y <= y2_inner; y++) {
+            for (auto x = x1_inner; x <= x2_inner; x++) {
                 if (0x1 & (x + y)) {
-                    g_ptr = &floor_ptr->grid_array[y][x];
-                    place_grid(player_ptr, g_ptr, GB_INNER);
+                    place_grid(player_ptr, &floor_ptr->get_grid({ y, x }), GB_INNER);
                 }
             }
         }
@@ -823,8 +753,8 @@ bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
         vault_monsters(player_ptr, yval, xval + 5, randint1(3));
 
         /* Traps make them entertaining. */
-        vault_traps(player_ptr, yval, xval - 3, 2, 8, randint1(3));
-        vault_traps(player_ptr, yval, xval + 3, 2, 8, randint1(3));
+        vault_traps(floor_ptr, yval, xval - 3, 2, 8, randint1(3));
+        vault_traps(floor_ptr, yval, xval + 3, 2, 8, randint1(3));
 
         /* Mazes should have some treasure too. */
         vault_objects(player_ptr, yval, xval, 3);
@@ -834,33 +764,32 @@ bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
     /* Four small rooms. */
     case 5: {
-        int door_type = (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
+        int door_type = (dungeon.flags.has(DungeonFeatureType::CURTAIN) && one_in_(dungeon.flags.has(DungeonFeatureType::NO_CAVE) ? 16 : 256))
                             ? DOOR_CURTAIN
-                            : (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
+                            : (dungeon.flags.has(DungeonFeatureType::GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
 
         /* Inner "cross" */
-        for (y = y1; y <= y2; y++) {
-            g_ptr = &floor_ptr->grid_array[y][xval];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+        for (auto y = y1_inner; y <= y2_inner; y++) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ y, xval }), GB_INNER);
         }
-        for (x = x1; x <= x2; x++) {
-            g_ptr = &floor_ptr->grid_array[yval][x];
-            place_grid(player_ptr, g_ptr, GB_INNER);
+
+        for (auto x = x1_inner; x <= x2_inner; x++) {
+            place_grid(player_ptr, &floor_ptr->get_grid({ yval, x }), GB_INNER);
         }
 
         /* Doors into the rooms */
         if (randint0(100) < 50) {
             int i = randint1(10);
-            place_secret_door(player_ptr, y1 - 1, xval - i, door_type);
-            place_secret_door(player_ptr, y1 - 1, xval + i, door_type);
-            place_secret_door(player_ptr, y2 + 1, xval - i, door_type);
-            place_secret_door(player_ptr, y2 + 1, xval + i, door_type);
+            place_secret_door(player_ptr, y1_inner - 1, xval - i, door_type);
+            place_secret_door(player_ptr, y1_inner - 1, xval + i, door_type);
+            place_secret_door(player_ptr, y2_inner + 1, xval - i, door_type);
+            place_secret_door(player_ptr, y2_inner + 1, xval + i, door_type);
         } else {
             int i = randint1(3);
-            place_secret_door(player_ptr, yval + i, x1 - 1, door_type);
-            place_secret_door(player_ptr, yval - i, x1 - 1, door_type);
-            place_secret_door(player_ptr, yval + i, x2 + 1, door_type);
-            place_secret_door(player_ptr, yval - i, x2 + 1, door_type);
+            place_secret_door(player_ptr, yval + i, x1_inner - 1, door_type);
+            place_secret_door(player_ptr, yval - i, x1_inner - 1, door_type);
+            place_secret_door(player_ptr, yval + i, x2_inner + 1, door_type);
+            place_secret_door(player_ptr, yval - i, x2_inner + 1, door_type);
         }
 
         /* Treasure, centered at the center of the cross */
@@ -890,29 +819,26 @@ bool build_type4(PlayerType *player_ptr, dun_data_type *dd_ptr)
  */
 bool build_type11(PlayerType *player_ptr, dun_data_type *dd_ptr)
 {
-    POSITION rad, x, y, x0, y0;
-    int light = false;
-
     /* Occasional light */
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((randint1(floor_ptr->dun_level) <= 15) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS)) {
-        light = true;
-    }
-
-    rad = randint0(9);
+    const auto should_brighten = (randint1(floor_ptr->dun_level) <= 15) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS);
+    const auto rad = randint0(9);
 
     /* Find and reserve some space in the dungeon.  Get center of room. */
-    if (!find_space(player_ptr, dd_ptr, &y0, &x0, rad * 2 + 1, rad * 2 + 1)) {
+    int yval;
+    int xval;
+    const auto is_pos_found = find_space(player_ptr, dd_ptr, &yval, &xval, rad * 2 + 1, rad * 2 + 1);
+    if (!is_pos_found) {
         return false;
     }
 
     /* Make circular floor */
-    for (x = x0 - rad; x <= x0 + rad; x++) {
-        for (y = y0 - rad; y <= y0 + rad; y++) {
-            if (distance(y0, x0, y, x) <= rad - 1) {
+    for (auto x = xval - rad; x <= xval + rad; x++) {
+        for (auto y = yval - rad; y <= yval + rad; y++) {
+            if (distance(yval, xval, y, x) <= rad - 1) {
                 /* inside- so is floor */
                 place_bold(player_ptr, y, x, GB_FLOOR);
-            } else if (distance(y0, x0, y, x) <= rad + 1) {
+            } else if (distance(yval, xval, y, x) <= rad + 1) {
                 /* make granite outside so on_defeat_arena_monster works */
                 place_bold(player_ptr, y, x, GB_EXTRA);
             }
@@ -920,8 +846,7 @@ bool build_type11(PlayerType *player_ptr, dun_data_type *dd_ptr)
     }
 
     /* Find visible outer walls and set to be FEAT_OUTER */
-    add_outer_wall(player_ptr, x0, y0, light, x0 - rad, y0 - rad, x0 + rad, y0 + rad);
-
+    add_outer_wall(player_ptr, xval, yval, should_brighten, xval - rad, yval - rad, xval + rad, yval + rad);
     return true;
 }
 
@@ -936,40 +861,35 @@ bool build_type11(PlayerType *player_ptr, dun_data_type *dd_ptr)
  */
 bool build_type12(PlayerType *player_ptr, dun_data_type *dd_ptr)
 {
-    POSITION rad, x, y, x0, y0;
-    int light = false;
-    bool emptyflag = true;
-
     /* Make a random metric */
-    POSITION h1, h2, h3, h4;
-    h1 = randint1(32) - 16;
-    h2 = randint1(16);
-    h3 = randint1(32);
-    h4 = randint1(32) - 16;
+    const auto h1 = randint1(32) - 16;
+    const auto h2 = randint1(16);
+    const auto h3 = randint1(32);
+    const auto h4 = randint1(32) - 16;
 
     /* Occasional light */
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((randint1(floor_ptr->dun_level) <= 5) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS)) {
-        light = true;
-    }
-
-    rad = randint1(9);
+    const auto should_brighten = (randint1(floor_ptr->dun_level) <= 5) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS);
+    const auto rad = randint1(9);
 
     /* Find and reserve some space in the dungeon.  Get center of room. */
-    if (!find_space(player_ptr, dd_ptr, &y0, &x0, rad * 2 + 3, rad * 2 + 3)) {
+    int yval;
+    int xval;
+    const auto is_pos_found = find_space(player_ptr, dd_ptr, &yval, &xval, rad * 2 + 3, rad * 2 + 3);
+    if (!is_pos_found) {
         return false;
     }
 
     /* Make floor */
-    for (x = x0 - rad; x <= x0 + rad; x++) {
-        for (y = y0 - rad; y <= y0 + rad; y++) {
+    for (auto x = xval - rad; x <= xval + rad; x++) {
+        for (auto y = yval - rad; y <= yval + rad; y++) {
             /* clear room flag */
             floor_ptr->grid_array[y][x].info &= ~(CAVE_ROOM);
 
-            if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1) {
+            if (dist2(yval, xval, y, x, h1, h2, h3, h4) <= rad - 1) {
                 /* inside - so is floor */
                 place_bold(player_ptr, y, x, GB_FLOOR);
-            } else if (distance(y0, x0, y, x) < 3) {
+            } else if (distance(yval, xval, y, x) < 3) {
                 place_bold(player_ptr, y, x, GB_FLOOR);
             } else {
                 /* make granite outside so on_defeat_arena_monster works */
@@ -977,37 +897,42 @@ bool build_type12(PlayerType *player_ptr, dun_data_type *dd_ptr)
             }
 
             /* proper boundary for on_defeat_arena_monster */
-            if (((y + rad) == y0) || ((y - rad) == y0) || ((x + rad) == x0) || ((x - rad) == x0)) {
+            if (((y + rad) == yval) || ((y - rad) == yval) || ((x + rad) == xval) || ((x - rad) == xval)) {
                 place_bold(player_ptr, y, x, GB_EXTRA);
             }
         }
     }
 
     /* Find visible outer walls and set to be FEAT_OUTER */
-    add_outer_wall(player_ptr, x0, y0, light, x0 - rad - 1, y0 - rad - 1, x0 + rad + 1, y0 + rad + 1);
+    add_outer_wall(player_ptr, xval, yval, should_brighten, xval - rad - 1, yval - rad - 1, xval + rad + 1, yval + rad + 1);
 
     /* Check to see if there is room for an inner vault */
-    for (x = x0 - 2; x <= x0 + 2; x++) {
-        for (y = y0 - 2; y <= y0 + 2; y++) {
-            if (!floor_ptr->grid_array[y][x].is_floor()) {
-                /* Wall in the way */
-                emptyflag = false;
+    auto is_empty = true;
+    for (auto x = xval - 2; x <= xval + 2; x++) {
+        if (!is_empty) {
+            break;
+        }
+
+        for (auto y = yval - 2; y <= yval + 2; y++) {
+            if (!floor_ptr->get_grid({ y, x }).is_floor()) {
+                is_empty = false;
+                break;
             }
         }
     }
 
-    if (emptyflag && one_in_(2)) {
+    if (is_empty && one_in_(2)) {
         /* Build the vault */
-        build_small_room(player_ptr, x0, y0);
+        build_small_room(player_ptr, xval, yval);
 
         /* Place a treasure in the vault */
-        place_object(player_ptr, y0, x0, 0L);
+        place_object(player_ptr, yval, xval, 0);
 
         /* Let's guard the treasure well */
-        vault_monsters(player_ptr, y0, x0, randint0(2) + 3);
+        vault_monsters(player_ptr, yval, xval, randint0(2) + 3);
 
         /* Traps naturally */
-        vault_traps(player_ptr, y0, x0, 4, 4, randint0(3) + 2);
+        vault_traps(floor_ptr, yval, xval, 4, 4, randint0(3) + 2);
     }
 
     return true;
index 7d9d8fa..857e030 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct dun_data_type;
 class PlayerType;
index ed462e8..9c0c4ff 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/rooms-pit-nest.h"
+#include "room/rooms-pit-nest.h"
 #include "floor/floor-generator.h"
 #include "game-option/cheat-options.h"
 #include "game-option/cheat-types.h"
@@ -196,7 +196,7 @@ std::vector<nest_pit_type> nest_types = {
 /*!
  * @todo intをenumに変更する
  */
-static void add_cave_info(grid_type *g_ptr, int cave_mask)
+static void add_cave_info(Grid *g_ptr, int cave_mask)
 {
     g_ptr->info |= cave_mask;
 }
@@ -229,10 +229,10 @@ bool build_type5(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
     MonsterEntity align;
 
-    grid_type *g_ptr;
+    Grid *g_ptr;
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    int cur_nest_type = pick_vault_type(floor_ptr, nest_types, dungeons_info[floor_ptr->dungeon_idx].nest);
+    int cur_nest_type = pick_vault_type(floor_ptr, nest_types, floor_ptr->get_dungeon_definition().nest);
     nest_pit_type *n_ptr;
 
     /* No type available */
@@ -255,7 +255,7 @@ bool build_type5(PlayerType *player_ptr, dun_data_type *dd_ptr)
         auto select_r_idx = [player_ptr, floor_ptr, &align]() -> std::optional<MonsterRaceId> {
             for (auto attempts = 100; attempts > 0; attempts--) {
                 /* Get a (hard) monster type */
-                auto r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, 0);
+                auto r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, PM_NONE);
                 auto *r_ptr = &monraces_info[r_idx];
 
                 /* Decline incorrect alignment */
@@ -275,11 +275,11 @@ bool build_type5(PlayerType *player_ptr, dun_data_type *dd_ptr)
         };
 
         const auto r_idx = select_r_idx();
-        if (!r_idx.has_value()) {
+        if (!r_idx) {
             return false;
         }
 
-        const auto *r_ptr = &monraces_info[r_idx.value()];
+        const auto *r_ptr = &monraces_info[*r_idx];
 
         /* Note the alignment */
         if (r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
@@ -289,7 +289,7 @@ bool build_type5(PlayerType *player_ptr, dun_data_type *dd_ptr)
             align.sub_align |= SUB_ALIGN_GOOD;
         }
 
-        nest_mon_info[i].r_idx = r_idx.value();
+        nest_mon_info[i].r_idx = *r_idx;
         nest_mon_info[i].used = false;
     }
 
@@ -381,7 +381,7 @@ bool build_type5(PlayerType *player_ptr, dun_data_type *dd_ptr)
             r_idx = nest_mon_info[i].r_idx;
 
             /* Place that "random" monster (no groups) */
-            (void)place_monster_aux(player_ptr, 0, y, x, r_idx, 0L);
+            (void)place_specific_monster(player_ptr, 0, y, x, r_idx, 0L);
 
             nest_mon_info[i].used = true;
         }
@@ -404,7 +404,8 @@ bool build_type5(PlayerType *player_ptr, dun_data_type *dd_ptr)
                 }
             }
 
-            msg_format_wizard(player_ptr, CHEAT_DUNGEON, "Nest構成モンスターNo.%d:%s", i, monraces_info[nest_mon_info[i].r_idx].name.data());
+            constexpr auto fmt = _("Nest構成モンスターNo.%d: %s", "Nest monster No.%d: %s");
+            msg_format_wizard(player_ptr, CHEAT_DUNGEON, fmt, i, monraces_info[nest_mon_info[i].r_idx].name.data());
         }
     }
 
@@ -472,10 +473,10 @@ bool build_type6(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
     MonsterEntity align;
 
-    grid_type *g_ptr;
+    Grid *g_ptr;
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    int cur_pit_type = pick_vault_type(floor_ptr, pit_types, dungeons_info[floor_ptr->dungeon_idx].pit);
+    int cur_pit_type = pick_vault_type(floor_ptr, pit_types, floor_ptr->get_dungeon_definition().pit);
     nest_pit_type *n_ptr;
 
     /* No type available */
@@ -501,7 +502,7 @@ bool build_type6(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
         while (attempts--) {
             /* Get a (hard) monster type */
-            r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, 0);
+            r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, PM_NONE);
             r_ptr = &monraces_info[r_idx];
 
             /* Decline incorrect alignment */
@@ -635,49 +636,49 @@ bool build_type6(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
     /* Top and bottom rows */
     for (x = xval - 9; x <= xval + 9; x++) {
-        place_monster_aux(player_ptr, 0, yval - 2, x, what[0], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, yval + 2, x, what[0], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, yval - 2, x, what[0], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, yval + 2, x, what[0], PM_NO_KAGE);
     }
 
     /* Middle columns */
     for (y = yval - 1; y <= yval + 1; y++) {
-        place_monster_aux(player_ptr, 0, y, xval - 9, what[0], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, y, xval + 9, what[0], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval - 9, what[0], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval + 9, what[0], PM_NO_KAGE);
 
-        place_monster_aux(player_ptr, 0, y, xval - 8, what[1], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, y, xval + 8, what[1], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval - 8, what[1], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval + 8, what[1], PM_NO_KAGE);
 
-        place_monster_aux(player_ptr, 0, y, xval - 7, what[1], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, y, xval + 7, what[1], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval - 7, what[1], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval + 7, what[1], PM_NO_KAGE);
 
-        place_monster_aux(player_ptr, 0, y, xval - 6, what[2], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, y, xval + 6, what[2], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval - 6, what[2], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval + 6, what[2], PM_NO_KAGE);
 
-        place_monster_aux(player_ptr, 0, y, xval - 5, what[2], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, y, xval + 5, what[2], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval - 5, what[2], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval + 5, what[2], PM_NO_KAGE);
 
-        place_monster_aux(player_ptr, 0, y, xval - 4, what[3], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, y, xval + 4, what[3], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval - 4, what[3], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval + 4, what[3], PM_NO_KAGE);
 
-        place_monster_aux(player_ptr, 0, y, xval - 3, what[3], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, y, xval + 3, what[3], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval - 3, what[3], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval + 3, what[3], PM_NO_KAGE);
 
-        place_monster_aux(player_ptr, 0, y, xval - 2, what[4], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, y, xval + 2, what[4], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval - 2, what[4], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, xval + 2, what[4], PM_NO_KAGE);
     }
 
     /* Above/Below the center monster */
     for (x = xval - 1; x <= xval + 1; x++) {
-        place_monster_aux(player_ptr, 0, yval + 1, x, what[5], PM_NO_KAGE);
-        place_monster_aux(player_ptr, 0, yval - 1, x, what[5], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, yval + 1, x, what[5], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, yval - 1, x, what[5], PM_NO_KAGE);
     }
 
     /* Next to the center monster */
-    place_monster_aux(player_ptr, 0, yval, xval + 1, what[6], PM_NO_KAGE);
-    place_monster_aux(player_ptr, 0, yval, xval - 1, what[6], PM_NO_KAGE);
+    place_specific_monster(player_ptr, 0, yval, xval + 1, what[6], PM_NO_KAGE);
+    place_specific_monster(player_ptr, 0, yval, xval - 1, what[6], PM_NO_KAGE);
 
     /* Center monster */
-    place_monster_aux(player_ptr, 0, yval, xval, what[7], PM_NO_KAGE);
+    place_specific_monster(player_ptr, 0, yval, xval, what[7], PM_NO_KAGE);
 
     return true;
 }
@@ -782,10 +783,10 @@ bool build_type13(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
     MonsterEntity align;
 
-    grid_type *g_ptr;
+    Grid *g_ptr;
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    int cur_pit_type = pick_vault_type(floor_ptr, pit_types, dungeons_info[floor_ptr->dungeon_idx].pit);
+    int cur_pit_type = pick_vault_type(floor_ptr, pit_types, floor_ptr->get_dungeon_definition().pit);
     nest_pit_type *n_ptr;
 
     /* Only in Angband */
@@ -816,7 +817,7 @@ bool build_type13(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
         while (attempts--) {
             /* Get a (hard) monster type */
-            r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 0, 0);
+            r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 0, PM_NONE);
             r_ptr = &monraces_info[r_idx];
 
             /* Decline incorrect alignment */
@@ -970,7 +971,7 @@ bool build_type13(PlayerType *player_ptr, dun_data_type *dd_ptr)
     for (i = 0; place_table_trapped_pit[i][2] >= 0; i++) {
         y = yval + place_table_trapped_pit[i][0];
         x = xval + place_table_trapped_pit[i][1];
-        place_monster_aux(player_ptr, 0, y, x, what[place_table_trapped_pit[i][2]], PM_NO_KAGE);
+        place_specific_monster(player_ptr, 0, y, x, what[place_table_trapped_pit[i][2]], PM_NO_KAGE);
     }
 
     return true;
index 8a95372..9b370d0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b3c5be1..0431b0e 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/rooms-special.h"
+#include "room/rooms-special.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor//geometry.h"
 #include "floor/floor-generator.h"
@@ -34,7 +34,7 @@ bool build_type15(PlayerType *player_ptr, dun_data_type *dd_ptr)
     POSITION y1, x1, xsize, ysize;
     bool light;
 
-    grid_type *g_ptr;
+    Grid *g_ptr;
 
     /* Pick a room size */
     xsize = rand_range(9, 13);
@@ -47,7 +47,7 @@ bool build_type15(PlayerType *player_ptr, dun_data_type *dd_ptr)
     }
 
     /* Choose lite or dark */
-    light = ((floor_ptr->dun_level <= randint1(25)) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS));
+    light = ((floor_ptr->dun_level <= randint1(25)) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS));
 
     /* Get corner values */
     y1 = yval - ysize / 2;
@@ -100,7 +100,7 @@ bool build_type15(PlayerType *player_ptr, dun_data_type *dd_ptr)
             y = yval + 2 * ddy_ddd[dir1];
             x = xval + 2 * ddx_ddd[dir1];
             if (MonsterRace(r_idx).is_valid()) {
-                place_monster_aux(player_ptr, 0, y, x, r_idx, PM_ALLOW_SLEEP);
+                place_specific_monster(player_ptr, 0, y, x, r_idx, PM_ALLOW_SLEEP);
             }
 
             /* Walls around the breather */
@@ -162,7 +162,7 @@ bool build_type15(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
         r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level, 0);
         if (MonsterRace(r_idx).is_valid()) {
-            place_monster_aux(player_ptr, 0, yval, xval, r_idx, 0L);
+            place_specific_monster(player_ptr, 0, yval, xval, r_idx, 0L);
         }
 
         /* Walls around the breather */
@@ -226,7 +226,7 @@ bool build_type15(PlayerType *player_ptr, dun_data_type *dd_ptr)
             y = yval + ddy_ddd[dir1];
             x = xval + ddx_ddd[dir1];
             if (MonsterRace(r_idx).is_valid()) {
-                place_monster_aux(player_ptr, 0, y, x, r_idx, 0L);
+                place_specific_monster(player_ptr, 0, y, x, r_idx, 0L);
             }
         }
 
index 6954f7f..25a9118 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct dun_data_type;
 class PlayerType;
index 150c0ca..41d9251 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/rooms-trap.h"
+#include "room/rooms-trap.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/floor-generator.h"
 #include "game-option/cheat-types.h"
@@ -26,7 +26,7 @@ bool build_type14(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
     bool light;
 
-    grid_type *g_ptr;
+    Grid *g_ptr;
     int16_t trap;
 
     /* Pick a room size */
@@ -45,7 +45,7 @@ bool build_type14(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
     /* Choose lite or dark */
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    light = ((floor_ptr->dun_level <= randint1(25)) && dungeons_info[floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS));
+    light = ((floor_ptr->dun_level <= randint1(25)) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS));
 
     /* Get corner values */
     y1 = yval - ysize / 2;
@@ -89,7 +89,7 @@ bool build_type14(PlayerType *player_ptr, dun_data_type *dd_ptr)
     g_ptr = &floor_ptr->grid_array[rand_spread(yval, ysize / 4)][rand_spread(xval, xsize / 4)];
     g_ptr->mimic = g_ptr->feat;
     g_ptr->feat = trap;
-
-    msg_format_wizard(player_ptr, CHEAT_DUNGEON, _("%sの部屋が生成されました。", "Room of %s was generated."), terrains_info[trap].name.data());
+    constexpr auto fmt = _("%sの部屋が生成されました。", "Room of %s was generated.");
+    msg_format_wizard(player_ptr, CHEAT_DUNGEON, fmt, TerrainList::get_instance()[trap].name.data());
     return true;
 }
index e6100aa..ce0fee1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct dun_data_type;
 class PlayerType;
index 24e6c82..3137295 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief Vaultの生成処理
  * @date 2018/09/11
  * @author deskull
@@ -319,7 +319,7 @@ static void build_vault(
 {
     POSITION dx, dy, x, y, i, j;
     concptr t;
-    grid_type *g_ptr;
+    Grid *g_ptr;
 
     /* Place dungeon features and objects */
     auto *floor_ptr = player_ptr->current_floor_ptr;
@@ -391,7 +391,7 @@ static void build_vault(
                 if (randint0(100) < 75) {
                     place_object(player_ptr, y, x, 0L);
                 } else {
-                    place_trap(player_ptr, y, x);
+                    place_trap(floor_ptr, y, x);
                 }
                 break;
 
@@ -425,7 +425,7 @@ static void build_vault(
 
                 /* Trap */
             case '^':
-                place_trap(player_ptr, y, x);
+                place_trap(floor_ptr, y, x);
                 break;
 
                 /* Black market in a dungeon */
@@ -550,7 +550,7 @@ static void build_vault(
             switch (*t) {
             case '&': {
                 floor_ptr->monster_level = floor_ptr->base_level + 5;
-                place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
+                place_random_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
                 floor_ptr->monster_level = floor_ptr->base_level;
                 break;
             }
@@ -558,7 +558,7 @@ static void build_vault(
             /* Meaner monster */
             case '@': {
                 floor_ptr->monster_level = floor_ptr->base_level + 11;
-                place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
+                place_random_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
                 floor_ptr->monster_level = floor_ptr->base_level;
                 break;
             }
@@ -566,7 +566,7 @@ static void build_vault(
             /* Meaner monster, plus treasure */
             case '9': {
                 floor_ptr->monster_level = floor_ptr->base_level + 9;
-                place_monster(player_ptr, y, x, PM_ALLOW_SLEEP);
+                place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP);
                 floor_ptr->monster_level = floor_ptr->base_level;
                 floor_ptr->object_level = floor_ptr->base_level + 7;
                 place_object(player_ptr, y, x, AM_GOOD);
@@ -577,7 +577,7 @@ static void build_vault(
             /* Nasty monster and treasure */
             case '8': {
                 floor_ptr->monster_level = floor_ptr->base_level + 40;
-                place_monster(player_ptr, y, x, PM_ALLOW_SLEEP);
+                place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP);
                 floor_ptr->monster_level = floor_ptr->base_level;
                 floor_ptr->object_level = floor_ptr->base_level + 20;
                 place_object(player_ptr, y, x, AM_GOOD | AM_GREAT);
@@ -589,7 +589,7 @@ static void build_vault(
             case ',': {
                 if (randint0(100) < 50) {
                     floor_ptr->monster_level = floor_ptr->base_level + 3;
-                    place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
+                    place_random_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
                     floor_ptr->monster_level = floor_ptr->base_level;
                 }
                 if (randint0(100) < 50) {
@@ -962,7 +962,7 @@ bool build_type10(PlayerType *player_ptr, dun_data_type *dd_ptr)
     /* Select type of vault */
     do {
         vtype = randint1(15);
-    } while (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) && ((vtype == 1) || (vtype == 3) || (vtype == 8) || (vtype == 9) || (vtype == 11)));
+    } while (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::NO_CAVE) && ((vtype == 1) || (vtype == 3) || (vtype == 8) || (vtype == 9) || (vtype == 11)));
 
     switch (vtype) {
         /* Build an appropriate room */
index 7571712..0f43975 100644 (file)
@@ -1,19 +1,20 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <stdint.h>
 #include <string>
 #include <vector>
 
 struct vault_type {
-    int16_t idx;
+    vault_type() = default;
+    short idx = 0;
 
-    std::string name; /* Name (offset) */
-    std::string text; /* Text (offset) */
+    std::string name = ""; /* Name (offset) */
+    std::string text = ""; /* Text (offset) */
 
-    byte typ{}; /* Vault type */
-    PROB rat{}; /* Vault rating (unused) */
-    POSITION hgt{}; /* Vault height */
-    POSITION wid{}; /* Vault width */
+    uint8_t typ = 0; /* Vault type */
+    int rat = 0; /* Vault rating (unused) */
+    int hgt = 0; /* Vault height */
+    int wid = 0; /* Vault width */
 };
 
 extern std::vector<vault_type> vaults_info;
index 86c6b3f..fb6e891 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/space-finder.h"
+#include "room/space-finder.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/cave.h"
 #include "grid/grid.h"
@@ -9,18 +9,17 @@
 #include "system/player-type-definition.h"
 
 /*!
- * @brief 指定のマスが床系地形であるかを返す / Function that sees if a square is a floor.  (Includes range checking.)
- * @param x チェックするマスのX座標
- * @param y チェックするマスのY座標
- * @return 床系地形ならばTRUE
+ * @brief 指定のマスが床系地形であるかを返す
+ * @param pos チェックするマスの座標
+ * @return 床系地形か否か
  */
-static bool get_is_floor(FloorType *floor_ptr, POSITION x, POSITION y)
+static bool get_is_floor(FloorType *floor_ptr, const Pos2D &pos)
 {
-    if (!in_bounds(floor_ptr, y, x)) {
+    if (!in_bounds(floor_ptr, pos.y, pos.x)) {
         return false;
     }
 
-    if (floor_ptr->grid_array[y][x].is_floor()) {
+    if (floor_ptr->get_grid(pos).is_floor()) {
         return true;
     }
 
@@ -28,49 +27,41 @@ static bool get_is_floor(FloorType *floor_ptr, POSITION x, POSITION y)
 }
 
 /*!
- * @brief 指定のマスを床地形に変える / Set a square to be floor.  (Includes range checking.)
+ * @brief 指定のマスを床地形に変える
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param x 地形を変えたいマスのX座標
- * @param y 地形を変えたいマスのY座標
+ * @param pos 地形を変えたいマスの座標
  */
-static void set_floor(PlayerType *player_ptr, POSITION x, POSITION y)
+static void set_floor(PlayerType *player_ptr, const Pos2D &pos)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!in_bounds(floor_ptr, y, x)) {
+    if (!in_bounds(floor_ptr, pos.y, pos.x)) {
         return;
     }
 
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
-    if (g_ptr->is_room()) {
+    auto &grid = floor_ptr->get_grid(pos);
+    if (grid.is_room()) {
         return;
     }
 
-    if (g_ptr->is_extra()) {
-        place_bold(player_ptr, y, x, GB_FLOOR);
+    if (grid.is_extra()) {
+        place_bold(player_ptr, pos.y, pos.x, GB_FLOOR);
     }
 }
 
 /*!
- * @brief
- * 指定範囲に通路が通っていることを確認した上で床で埋める
- * This function tunnels around a room if it will cut off part of a grid system.
+ * @brief 指定範囲に通路が通っていることを確認した上で床で埋める
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param x1 範囲の左端
- * @param y1 範囲の上端
- * @param x2 範囲の右端
- * @param y2 範囲の下端
+ * @param pos1 範囲の左上端
+ * @param pos2 範囲の右下端
  */
-static void check_room_boundary(PlayerType *player_ptr, POSITION x1, POSITION y1, POSITION x2, POSITION y2)
+static void check_room_boundary(PlayerType *player_ptr, const Pos2D &pos1, const Pos2D &pos2)
 {
-    bool old_is_floor;
-    bool new_is_floor;
-    int count = 0;
-
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    old_is_floor = get_is_floor(floor_ptr, x1 - 1, y1);
-
-    for (POSITION x = x1; x <= x2; x++) {
-        new_is_floor = get_is_floor(floor_ptr, x, y1 - 1);
+    auto count = 0;
+    auto old_is_floor = get_is_floor(floor_ptr, { pos1.y, pos1.x - 1 });
+    bool new_is_floor;
+    for (auto x = pos1.x; x <= pos2.x; x++) {
+        new_is_floor = get_is_floor(floor_ptr, { pos1.y - 1, x });
         if (new_is_floor != old_is_floor) {
             count++;
         }
@@ -78,8 +69,8 @@ static void check_room_boundary(PlayerType *player_ptr, POSITION x1, POSITION y1
         old_is_floor = new_is_floor;
     }
 
-    for (POSITION y = y1; y <= y2; y++) {
-        new_is_floor = get_is_floor(floor_ptr, x2 + 1, y);
+    for (auto y = pos1.y; y <= pos2.y; y++) {
+        new_is_floor = get_is_floor(floor_ptr, { y, pos2.x + 1 });
         if (new_is_floor != old_is_floor) {
             count++;
         }
@@ -87,8 +78,8 @@ static void check_room_boundary(PlayerType *player_ptr, POSITION x1, POSITION y1
         old_is_floor = new_is_floor;
     }
 
-    for (POSITION x = x2; x >= x1; x--) {
-        new_is_floor = get_is_floor(floor_ptr, x, y2 + 1);
+    for (auto x = pos2.x; x >= pos1.x; x--) {
+        new_is_floor = get_is_floor(floor_ptr, { pos2.y + 1, x });
         if (new_is_floor != old_is_floor) {
             count++;
         }
@@ -96,8 +87,8 @@ static void check_room_boundary(PlayerType *player_ptr, POSITION x1, POSITION y1
         old_is_floor = new_is_floor;
     }
 
-    for (POSITION y = y2; y >= y1; y--) {
-        new_is_floor = get_is_floor(floor_ptr, x1 - 1, y);
+    for (auto y = pos2.y; y >= pos1.y; y--) {
+        new_is_floor = get_is_floor(floor_ptr, { y, pos1.x - 1 });
         if (new_is_floor != old_is_floor) {
             count++;
         }
@@ -109,61 +100,58 @@ static void check_room_boundary(PlayerType *player_ptr, POSITION x1, POSITION y1
         return;
     }
 
-    for (POSITION y = y1; y <= y2; y++) {
-        for (POSITION x = x1; x <= x2; x++) {
-            set_floor(player_ptr, x, y);
+    for (auto y = pos1.y; y <= pos2.y; y++) {
+        for (auto x = pos1.x; x <= pos2.x; x++) {
+            set_floor(player_ptr, { y, x });
         }
     }
 }
 
 /*!
- * @brief
- * find_space()の予備処理として部屋の生成が可能かを判定する /
- * Helper function for find_space(). Is this a good location?
+ * @brief find_space()の予備処理として部屋の生成が可能かを判定する
  * @param blocks_high 範囲の高さ
  * @param blocks_wide 範囲の幅
  * @param block_y 範囲の上端
  * @param block_x 範囲の左端
  */
-static bool find_space_aux(dun_data_type *dd_ptr, POSITION blocks_high, POSITION blocks_wide, POSITION block_y, POSITION block_x)
+static bool find_space_aux(dun_data_type *dd_ptr, const Pos2D &max_block_size, const Pos2D &block)
 {
-    if (blocks_wide < 3) {
-        if ((blocks_wide == 2) && (block_x % 3) == 2) {
+    if (max_block_size.x < 3) {
+        if ((max_block_size.x == 2) && (block.x % 3) == 2) {
             return false;
         }
-    } else if ((blocks_wide % 3) == 0) {
-        if ((block_x % 3) != 0) {
+    } else if ((max_block_size.x % 3) == 0) {
+        if ((block.x % 3) != 0) {
             return false;
         }
     } else {
-        if (block_x + (blocks_wide / 2) <= dd_ptr->col_rooms / 2) {
-            if (((block_x % 3) == 2) && ((blocks_wide % 3) == 2)) {
+        if (block.x + (max_block_size.x / 2) <= dd_ptr->col_rooms / 2) {
+            if (((block.x % 3) == 2) && ((max_block_size.x % 3) == 2)) {
                 return false;
             }
-            if ((block_x % 3) == 1) {
+            if ((block.x % 3) == 1) {
                 return false;
             }
         } else {
-            if (((block_x % 3) == 2) && ((blocks_wide % 3) == 2)) {
+            if (((block.x % 3) == 2) && ((max_block_size.x % 3) == 2)) {
                 return false;
             }
-            if ((block_x % 3) == 1) {
+            if ((block.x % 3) == 1) {
                 return false;
             }
         }
     }
 
-    POSITION by1 = block_y;
-    POSITION bx1 = block_x;
-    POSITION by2 = block_y + blocks_high;
-    POSITION bx2 = block_x + blocks_wide;
-
+    const auto by1 = block.y;
+    const auto bx1 = block.x;
+    const auto by2 = block.y + max_block_size.y;
+    const auto bx2 = block.x + max_block_size.x;
     if ((by1 < 0) || (by2 > dd_ptr->row_rooms) || (bx1 < 0) || (bx2 > dd_ptr->col_rooms)) {
         return false;
     }
 
-    for (POSITION by = by1; by < by2; by++) {
-        for (POSITION bx = bx1; bx < bx2; bx++) {
+    for (auto by = by1; by < by2; by++) {
+        for (auto bx = bx1; bx < bx2; bx++) {
             if (dd_ptr->room_map[by][bx]) {
                 return false;
             }
@@ -208,7 +196,7 @@ bool find_space(PlayerType *player_ptr, dun_data_type *dd_ptr, POSITION *y, POSI
     int candidates = 0;
     for (block_y = dd_ptr->row_rooms - blocks_high; block_y >= 0; block_y--) {
         for (block_x = dd_ptr->col_rooms - blocks_wide; block_x >= 0; block_x--) {
-            if (find_space_aux(dd_ptr, blocks_high, blocks_wide, block_y, block_x)) {
+            if (find_space_aux(dd_ptr, { blocks_high, blocks_wide }, { block_y, block_x })) {
                 /* Find a valid place */
                 candidates++;
             }
@@ -219,7 +207,7 @@ bool find_space(PlayerType *player_ptr, dun_data_type *dd_ptr, POSITION *y, POSI
         return false;
     }
 
-    if (dungeons_info[player_ptr->current_floor_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::NO_CAVE)) {
+    if (player_ptr->current_floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::NO_CAVE)) {
         pick = randint1(candidates);
     } else {
         pick = candidates / 2 + 1;
@@ -227,7 +215,7 @@ bool find_space(PlayerType *player_ptr, dun_data_type *dd_ptr, POSITION *y, POSI
 
     for (block_y = dd_ptr->row_rooms - blocks_high; block_y >= 0; block_y--) {
         for (block_x = dd_ptr->col_rooms - blocks_wide; block_x >= 0; block_x--) {
-            if (find_space_aux(dd_ptr, blocks_high, blocks_wide, block_y, block_x)) {
+            if (find_space_aux(dd_ptr, { blocks_high, blocks_wide }, { block_y, block_x })) {
                 pick--;
                 if (!pick) {
                     break;
@@ -254,10 +242,14 @@ bool find_space(PlayerType *player_ptr, dun_data_type *dd_ptr, POSITION *y, POSI
 
     for (POSITION by = by1; by < by2; by++) {
         for (POSITION bx = bx1; bx < bx2; bx++) {
+            if ((by < 0) || (bx < 0)) {
+                continue;
+            }
+
             dd_ptr->room_map[by][bx] = true;
         }
     }
 
-    check_room_boundary(player_ptr, *x - width / 2 - 1, *y - height / 2 - 1, *x + (width - 1) / 2 + 1, *y + (height - 1) / 2 + 1);
+    check_room_boundary(player_ptr, { *y - height / 2 - 1, *x - width / 2 - 1 }, { *y + (height - 1) / 2 + 1, *x + (width - 1) / 2 + 1 });
     return true;
 }
index 1234590..459bcda 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 84515dc..8bbeb54 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 部屋にアイテム・モンスター・罠を配置する処理
  * @date 2020/07/24
  * @author Hourier
@@ -39,38 +39,38 @@ void fill_treasure(PlayerType *player_ptr, POSITION x1, POSITION x2, POSITION y1
 
             if (value < 0) {
                 floor_ptr->monster_level = floor_ptr->base_level + 40;
-                place_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
+                place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
                 floor_ptr->monster_level = floor_ptr->base_level;
                 floor_ptr->object_level = floor_ptr->base_level + 20;
                 place_object(player_ptr, y, x, AM_GOOD);
                 floor_ptr->object_level = floor_ptr->base_level;
             } else if (value < 5) {
                 floor_ptr->monster_level = floor_ptr->base_level + 20;
-                place_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
+                place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
                 floor_ptr->monster_level = floor_ptr->base_level;
                 floor_ptr->object_level = floor_ptr->base_level + 10;
                 place_object(player_ptr, y, x, AM_GOOD);
                 floor_ptr->object_level = floor_ptr->base_level;
             } else if (value < 10) {
                 floor_ptr->monster_level = floor_ptr->base_level + 9;
-                place_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
+                place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
                 floor_ptr->monster_level = floor_ptr->base_level;
             } else if (value < 17) {
             } else if (value < 23) {
                 if (randint0(100) < 25) {
                     place_object(player_ptr, y, x, 0L);
                 } else {
-                    place_trap(player_ptr, y, x);
+                    place_trap(floor_ptr, y, x);
                 }
             } else if (value < 30) {
                 floor_ptr->monster_level = floor_ptr->base_level + 5;
-                place_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
+                place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
                 floor_ptr->monster_level = floor_ptr->base_level;
-                place_trap(player_ptr, y, x);
+                place_trap(floor_ptr, y, x);
             } else if (value < 40) {
                 if (randint0(100) < 50) {
                     floor_ptr->monster_level = floor_ptr->base_level + 3;
-                    place_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
+                    place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
                     floor_ptr->monster_level = floor_ptr->base_level;
                 }
 
@@ -80,12 +80,12 @@ void fill_treasure(PlayerType *player_ptr, POSITION x1, POSITION x2, POSITION y1
                     floor_ptr->object_level = floor_ptr->base_level;
                 }
             } else if (value < 50) {
-                place_trap(player_ptr, y, x);
+                place_trap(floor_ptr, y, x);
             } else {
                 if (randint0(100) < 20) {
-                    place_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
+                    place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
                 } else if (randint0(100) < 50) {
-                    place_trap(player_ptr, y, x);
+                    place_trap(floor_ptr, y, x);
                 } else if (randint0(100) < 50) {
                     place_object(player_ptr, y, x, 0L);
                 }
index 7e7968d..8c6b2ca 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index fa626d3..546b081 100644 (file)
@@ -1,4 +1,4 @@
-#include "room/vault-builder.h"
+#include "room/vault-builder.h"
 #include "floor/cave.h"
 #include "floor/floor-generator-util.h"
 #include "floor/floor-util.h"
@@ -16,7 +16,7 @@
 /*
  * Grid based version of "creature_bold()"
  */
-static bool player_grid(PlayerType *player_ptr, grid_type *g_ptr)
+static bool player_grid(PlayerType *player_ptr, Grid *g_ptr)
 {
     return g_ptr == &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
 }
@@ -24,7 +24,7 @@ static bool player_grid(PlayerType *player_ptr, grid_type *g_ptr)
 /*
  * Grid based version of "cave_empty_bold()"
  */
-static bool is_cave_empty_grid(PlayerType *player_ptr, grid_type *g_ptr)
+static bool is_cave_empty_grid(PlayerType *player_ptr, Grid *g_ptr)
 {
     bool is_empty_grid = g_ptr->cave_has_flag(TerrainCharacteristics::PLACE);
     is_empty_grid &= g_ptr->m_idx == 0;
@@ -49,14 +49,14 @@ void vault_monsters(PlayerType *player_ptr, POSITION y1, POSITION x1, int num)
             int d = 1;
             POSITION y, x;
             scatter(player_ptr, &y, &x, y1, x1, d, 0);
-            grid_type *g_ptr;
+            Grid *g_ptr;
             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
             if (!is_cave_empty_grid(player_ptr, g_ptr)) {
                 continue;
             }
 
             floor_ptr->monster_level = floor_ptr->base_level + 2;
-            (void)place_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
+            (void)place_random_monster(player_ptr, y, x, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
             floor_ptr->monster_level = floor_ptr->base_level;
         }
     }
@@ -92,7 +92,7 @@ void vault_objects(PlayerType *player_ptr, POSITION y, POSITION x, int num)
                 msg_print(_("警告!地下室のアイテムを配置できません!", "Warning! Could not place vault object!"));
             }
 
-            grid_type *g_ptr;
+            Grid *g_ptr;
             g_ptr = &floor_ptr->grid_array[j][k];
             if (!g_ptr->is_floor() || !g_ptr->o_idx_list.empty()) {
                 continue;
@@ -118,10 +118,9 @@ void vault_objects(PlayerType *player_ptr, POSITION y, POSITION x, int num)
  * @details
  * Only really called by some of the "vault" routines.
  */
-static void vault_trap_aux(PlayerType *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd)
+static void vault_trap_aux(FloorType *floor_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd)
 {
-    grid_type *g_ptr;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
+    Grid *g_ptr;
     int y1 = y, x1 = x;
     int dummy = 0;
     for (int count = 0; count <= 5; count++) {
@@ -144,7 +143,7 @@ static void vault_trap_aux(PlayerType *player_ptr, POSITION y, POSITION x, POSIT
             continue;
         }
 
-        place_trap(player_ptr, y1, x1);
+        place_trap(floor_ptr, y1, x1);
         break;
     }
 }
@@ -161,9 +160,9 @@ static void vault_trap_aux(PlayerType *player_ptr, POSITION y, POSITION x, POSIT
  * Only really called by some of the "vault" routines.
  * @todo rooms-normal からしか呼ばれていない、要調整
  */
-void vault_traps(PlayerType *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd, int num)
+void vault_traps(FloorType *floor_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd, int num)
 {
     for (int i = 0; i < num; i++) {
-        vault_trap_aux(player_ptr, y, x, yd, xd);
+        vault_trap_aux(floor_ptr, y, x, yd, xd);
     }
 }
index 3d8ff83..c08de47 100644 (file)
@@ -1,8 +1,9 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
+class FloorType;
 class PlayerType;
 void vault_monsters(PlayerType *player_ptr, POSITION y1, POSITION x1, int num);
 void vault_objects(PlayerType *player_ptr, POSITION y, POSITION x, int num);
-void vault_traps(PlayerType *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd, int num);
+void vault_traps(FloorType *floor_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd, int num);
index 4780c64..ff82442 100644 (file)
@@ -1,6 +1,5 @@
-#include "save/floor-writer.h"
+#include "save/floor-writer.h"
 #include "core/object-compressor.h"
-#include "core/player-update-types.h"
 #include "floor/floor-events.h"
 #include "floor/floor-save-util.h"
 #include "floor/floor-save.h"
@@ -16,6 +15,7 @@
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/z-form.h"
 #include "util/angband-files.h"
 #include "util/sort.h"
@@ -156,10 +156,17 @@ bool wr_dungeon(PlayerType *player_ptr)
     forget_lite(player_ptr->current_floor_ptr);
     forget_view(player_ptr->current_floor_ptr);
     clear_mon_lite(player_ptr->current_floor_ptr);
-    player_ptr->update |= PU_VIEW | PU_LITE | PU_MONSTER_LITE;
-    player_ptr->update |= PU_MONSTER_STATUSES | PU_DISTANCE | PU_FLOW;
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+        StatusRecalculatingFlag::DISTANCE,
+        StatusRecalculatingFlag::FLOW,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     wr_s16b(max_floor_id);
-    wr_byte((byte)player_ptr->dungeon_idx);
+    wr_byte((byte)player_ptr->current_floor_ptr->dungeon_idx);
     if (!player_ptr->floor_id) {
         /* No array elements */
         wr_byte(0);
@@ -247,23 +254,24 @@ bool save_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr, BIT_FLAGS mode
         old_x_stamp = x_stamp;
     }
 
-    std::string floor_savefile = savefile;
+    auto floor_savefile = savefile.string();
     char ext[32];
     strnfmt(ext, sizeof(ext), ".F%02d", (int)sf_ptr->savefile_id);
     floor_savefile.append(ext);
-    safe_setuid_grab(player_ptr);
-    fd_kill(floor_savefile.data());
+    safe_setuid_grab();
+    fd_kill(floor_savefile);
     safe_setuid_drop();
     saving_savefile = nullptr;
-    safe_setuid_grab(player_ptr);
+    safe_setuid_grab();
 
-    auto fd = fd_make(floor_savefile.data());
+    auto fd = fd_make(floor_savefile);
     safe_setuid_drop();
     bool is_save_successful = false;
     if (fd >= 0) {
         (void)fd_close(fd);
-        safe_setuid_grab(player_ptr);
-        saving_savefile = angband_fopen(floor_savefile.data(), FileOpenMode::WRITE, true);
+        safe_setuid_grab();
+        saving_savefile = angband_fopen(floor_savefile, FileOpenMode::WRITE,
+            true, FileOpenType::RAW);
         safe_setuid_drop();
         if (saving_savefile) {
             if (save_floor_aux(player_ptr, sf_ptr)) {
@@ -276,8 +284,8 @@ bool save_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr, BIT_FLAGS mode
         }
 
         if (!is_save_successful) {
-            safe_setuid_grab(player_ptr);
-            (void)fd_kill(floor_savefile.data());
+            safe_setuid_grab();
+            (void)fd_kill(floor_savefile);
             safe_setuid_drop();
         }
     }
index b94f986..0228416 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3fb09f1..1ab0a9a 100644 (file)
@@ -1,4 +1,4 @@
-#include "save/info-writer.h"
+#include "save/info-writer.h"
 #include "birth/quick-start.h"
 #include "game-option/cheat-options.h"
 #include "game-option/option-flags.h"
@@ -11,6 +11,7 @@
 #include "store/store-util.h"
 #include "system/angband.h"
 #include "system/item-entity.h"
+#include "util/enum-converter.h"
 #include "world/world.h"
 
 /*!
@@ -130,26 +131,26 @@ void wr_options(SaveType type)
         }
 
         if (*option_info[i].o_var) {
-            option_flag[os] |= (1UL << ob);
+            g_option_flags[os] |= (1UL << ob);
         } else {
-            option_flag[os] &= ~(1UL << ob);
+            g_option_flags[os] &= ~(1UL << ob);
         }
     }
 
-    for (int i = 0; i < 8; i++) {
-        wr_u32b(option_flag[i]);
+    for (const auto &option_flag : g_option_flags) {
+        wr_u32b(option_flag);
     }
 
-    for (int i = 0; i < 8; i++) {
-        wr_u32b(option_mask[i]);
+    for (const auto &option_mask : g_option_masks) {
+        wr_u32b(option_mask);
     }
 
-    for (int i = 0; i < 8; i++) {
-        wr_u32b(window_flag[i]);
+    for (const auto &window_flag : g_window_flags) {
+        wr_FlagGroup_bytes(window_flag, wr_byte, 4);
     }
 
-    for (int i = 0; i < 8; i++) {
-        wr_u32b(window_mask[i]);
+    for (const auto &window_mask : g_window_masks) {
+        wr_FlagGroup_bytes(window_mask, wr_byte, 4);
     }
 }
 
index 7f70b54..5550c94 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class SaveType;
 struct store_type;
index 49d25b4..6c0c825 100644 (file)
@@ -1,4 +1,4 @@
-#include "save/item-writer.h"
+#include "save/item-writer.h"
 #include "artifact/random-art-effects.h"
 #include "load/old/item-flag-types-savefile50.h"
 #include "save/save-util.h"
@@ -6,7 +6,6 @@
 #include "system/item-entity.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
-#include "util/quarks.h"
 
 static void write_item_flags(ItemEntity *o_ptr, BIT_FLAGS *flags)
 {
@@ -217,14 +216,14 @@ static void write_item_info(ItemEntity *o_ptr, const BIT_FLAGS flags)
     }
 
     if (any_bits(flags, SaveDataItemFlagType::SMITH)) {
-        if (o_ptr->smith_effect.has_value()) {
-            wr_s16b(enum2i(o_ptr->smith_effect.value()));
+        if (o_ptr->smith_effect) {
+            wr_s16b(enum2i(*o_ptr->smith_effect));
         } else {
             wr_s16b(0);
         }
 
-        if (o_ptr->smith_act_idx.has_value()) {
-            wr_s16b(enum2i(o_ptr->smith_act_idx.value()));
+        if (o_ptr->smith_act_idx) {
+            wr_s16b(enum2i(*o_ptr->smith_act_idx));
         } else {
             wr_s16b(0);
         }
@@ -260,11 +259,11 @@ void wr_item(ItemEntity *o_ptr)
 
     write_item_info(o_ptr, flags);
     if (any_bits(flags, SaveDataItemFlagType::INSCRIPTION)) {
-        wr_string(o_ptr->inscription.value());
+        wr_string(*o_ptr->inscription);
     }
 
     if (any_bits(flags, SaveDataItemFlagType::ART_NAME)) {
-        wr_string(o_ptr->randart_name.value());
+        wr_string(*o_ptr->randart_name);
     }
 }
 
index 9ea38d5..2e36ceb 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 void wr_item(ItemEntity *o_ptr);
index 93aa231..70f0be4 100644 (file)
@@ -1,4 +1,4 @@
-#include "save/monster-writer.h"
+#include "save/monster-writer.h"
 #include "load/old/monster-flag-types-savefile50.h"
 #include "monster-race/monster-race.h"
 #include "monster/monster-info.h"
@@ -8,7 +8,6 @@
 #include "system/monster-race-info.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
-#include "util/quarks.h"
 
 static void write_monster_flags(MonsterEntity *m_ptr, BIT_FLAGS *flags)
 {
index a4b5e5a..7b2163d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index c601612..0b6fbb1 100644 (file)
@@ -1,4 +1,4 @@
-#include "save/player-class-specific-data-writer.h"
+#include "save/player-class-specific-data-writer.h"
 #include "player-info/bard-data-type.h"
 #include "player-info/bluemage-data-type.h"
 #include "player-info/force-trainer-data-type.h"
@@ -67,7 +67,7 @@ void PlayerClassSpecificDataWriter::operator()(const std::shared_ptr<mane_data_t
     }
 }
 
-void PlayerClassSpecificDataWriter::operator()(const std::shared_ptr<sniper_data_type> &sniper_data) const
+void PlayerClassSpecificDataWriter::operator()(const std::shared_ptr<SniperData> &sniper_data) const
 {
     wr_s16b(sniper_data->concent);
 }
index 3767c00..5f06f2e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <memory>
 
@@ -10,7 +10,7 @@ struct bluemage_data_type;
 struct magic_eater_data_type;
 struct bard_data_type;
 struct mane_data_type;
-struct sniper_data_type;
+class SniperData;
 struct samurai_data_type;
 struct monk_data_type;
 struct ninja_data_type;
@@ -25,7 +25,7 @@ public:
     void operator()(const std::shared_ptr<magic_eater_data_type> &magic_eater_data) const;
     void operator()(const std::shared_ptr<bard_data_type> &bird_data) const;
     void operator()(const std::shared_ptr<mane_data_type> &mane_data) const;
-    void operator()(const std::shared_ptr<sniper_data_type> &sniper_data) const;
+    void operator()(const std::shared_ptr<SniperData> &sniper_data) const;
     void operator()(const std::shared_ptr<samurai_data_type> &samurai_data) const;
     void operator()(const std::shared_ptr<monk_data_type> &monk_data) const;
     void operator()(const std::shared_ptr<ninja_data_type> &ninja_data) const;
index 4789afd..3096fbf 100644 (file)
@@ -1,4 +1,4 @@
-#include "save/player-writer.h"
+#include "save/player-writer.h"
 #include "cmd-building/cmd-building.h"
 #include "game-option/birth-options.h"
 #include "player-base/player-class.h"
@@ -6,6 +6,7 @@
 #include "save/info-writer.h"
 #include "save/player-class-specific-data-writer.h"
 #include "save/save-util.h"
+#include "system/angband-system.h"
 #include "system/building-type-definition.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
@@ -46,7 +47,7 @@ void wr_player(PlayerType *player_ptr)
 {
     wr_string(player_ptr->name);
     wr_string(player_ptr->died_from);
-    wr_string(player_ptr->last_message ? player_ptr->last_message : "");
+    wr_string(player_ptr->last_message);
 
     save_quick_start();
     for (int i = 0; i < 4; i++) {
@@ -130,8 +131,8 @@ void wr_player(PlayerType *player_ptr)
     wr_s16b(player_ptr->arena_number);
     wr_s16b(player_ptr->current_floor_ptr->inside_arena);
     wr_s16b(enum2i(player_ptr->current_floor_ptr->quest_number));
-    wr_s16b(player_ptr->phase_out);
-    wr_byte(player_ptr->exit_bldg);
+    wr_s16b(AngbandSystem::get_instance().is_phase_out());
+    wr_byte(w_ptr->get_arena());
     wr_byte(0); /* Unused */
 
     wr_s16b((int16_t)player_ptr->oldpx);
index 5722002..f8664e0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void wr_player(PlayerType *player_ptr);
index 29d56be..6c174eb 100644 (file)
@@ -1,4 +1,4 @@
-#include "save/save-util.h"
+#include "save/save-util.h"
 
 FILE *saving_savefile; /* Current save "file" */
 byte save_xor_byte; /* Simple encryption */
index 13dd5e3..49e1d49 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 2509b5b..5a80a96 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file save.c
  * @brief セーブファイル書き込み処理 / Purpose: interact with savefiles
  * @date 2014/07/12
@@ -43,6 +43,8 @@
 #include "view/display-messages.h"
 #include "world/world.h"
 #include <algorithm>
+#include <sstream>
+#include <string>
 
 /*!
  * @brief セーブデータの書き込み /
@@ -108,7 +110,7 @@ static bool wr_savefile_new(PlayerType *player_ptr, SaveType type)
 
     wr_u32b(tmp32u);
     for (int i = tmp32u - 1; i >= 0; i--) {
-        wr_string(message_str(i));
+        wr_string(*message_str(i));
     }
 
     uint16_t tmp16u = static_cast<uint16_t>(monraces_info.size());
@@ -218,8 +220,8 @@ static bool wr_savefile_new(PlayerType *player_ptr, SaveType type)
     tmp16u = MAX_STORES;
     wr_u16b(tmp16u);
     for (size_t i = 1; i < towns_info.size(); i++) {
-        for (auto j = 0; j < MAX_STORES; j++) {
-            wr_store(&towns_info[i].store[j]);
+        for (auto sst : STORE_SALE_TYPE_LIST) {
+            wr_store(&towns_info[i].stores[sst]);
         }
     }
 
@@ -246,25 +248,25 @@ static bool wr_savefile_new(PlayerType *player_ptr, SaveType type)
 }
 
 /*!
- * @brief セーブデータ書き込みのサブルーチン /
- * Medium level player saver
+ * @brief セーブデータ書き込みのサブルーチン
  * @param player_ptr プレイヤーへの参照ポインタ
- * @return 成功すればtrue
- * @details
- * Angband 2.8.0 will use "fd" instead of "fff" if possible
+ * @param path セーブデータのフルパス
+ * @param type セーブ後の処理種別
+ * @return セーブの成功可否
  */
-static bool save_player_aux(PlayerType *player_ptr, char *name, SaveType type)
+static bool save_player_aux(PlayerType *player_ptr, const std::filesystem::path &path, SaveType type)
 {
-    safe_setuid_grab(player_ptr);
-    auto fd = fd_make(name);
+    safe_setuid_grab();
+    auto fd = fd_make(path);
     safe_setuid_drop();
 
     bool is_save_successful = false;
     saving_savefile = nullptr;
     if (fd >= 0) {
         (void)fd_close(fd);
-        safe_setuid_grab(player_ptr);
-        saving_savefile = angband_fopen(name, FileOpenMode::WRITE, true);
+        safe_setuid_grab();
+        saving_savefile = angband_fopen(path, FileOpenMode::WRITE, true,
+            FileOpenType::SAVE);
         safe_setuid_drop();
         if (saving_savefile) {
             if (wr_savefile_new(player_ptr, type)) {
@@ -276,9 +278,9 @@ static bool save_player_aux(PlayerType *player_ptr, char *name, SaveType type)
             }
         }
 
-        safe_setuid_grab(player_ptr);
+        safe_setuid_grab();
         if (!is_save_successful) {
-            (void)fd_kill(name);
+            (void)fd_kill(path);
         }
 
         safe_setuid_drop();
@@ -294,39 +296,40 @@ static bool save_player_aux(PlayerType *player_ptr, char *name, SaveType type)
 }
 
 /*!
- * @brief セーブデータ書き込みのメインルーチン /
- * Attempt to save the player in a savefile
+ * @brief セーブデータ書き込みのメインルーチン
  * @param player_ptr プレイヤーへの参照ポインタ
  * @return 成功すればtrue
+ * @details 以下の順番で書き込みを実行する.
+ * 1. hoge.new にセーブデータを書き込む
+ * 2. hoge をhoge.old にリネームする
+ * 3. hoge.new をhoge にリネームする
+ * 4. hoge.old を削除する
  */
 bool save_player(PlayerType *player_ptr, SaveType type)
 {
-    char safe[1024];
-    strcpy(safe, savefile);
-    strcat(safe, ".new");
-    safe_setuid_grab(player_ptr);
-    fd_kill(safe);
+    std::stringstream ss_new;
+    ss_new << savefile.string() << ".new";
+    auto savefile_new = ss_new.str();
+    safe_setuid_grab();
+    fd_kill(savefile_new);
+    if (type == SaveType::DEBUG) {
+        const auto debug_save_dir = std::filesystem::path(debug_savefile).remove_filename();
+        std::error_code ec;
+        std::filesystem::create_directory(debug_save_dir, ec);
+    }
     safe_setuid_drop();
-    update_playtime();
-    bool result = false;
-    if (save_player_aux(player_ptr, safe, type)) {
-        char temp[1024];
-        char filename[1024];
-        strcpy(temp, savefile);
-        strcat(temp, ".old");
-        safe_setuid_grab(player_ptr);
-        fd_kill(temp);
-
-        if (type == SaveType::DEBUG) {
-            strcpy(filename, debug_savefile);
-        }
-        if (type != SaveType::DEBUG) {
-            strcpy(filename, savefile);
-        }
-
-        fd_move(filename, temp);
-        fd_move(safe, filename);
-        fd_kill(temp);
+    w_ptr->update_playtime();
+    auto result = false;
+    if (save_player_aux(player_ptr, savefile_new.data(), type)) {
+        std::stringstream ss_old;
+        ss_old << savefile.string() << ".old";
+        auto savefile_old = ss_old.str();
+        safe_setuid_grab();
+        fd_kill(savefile_old);
+        const auto &path = type == SaveType::DEBUG ? debug_savefile : savefile;
+        fd_move(path, savefile_old);
+        fd_move(savefile_new, path);
+        fd_kill(savefile_old);
         safe_setuid_drop();
         w_ptr->character_loaded = true;
         result = true;
index f77ac40..8e8113a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class SaveType {
     CLOSE_GAME,
index 81787f1..8aa7d47 100644 (file)
@@ -1,9 +1,8 @@
-#include "smith/object-smith.h"
+#include "smith/object-smith.h"
 #include "object-enchant/special-object-flags.h"
 #include "object-enchant/tr-flags.h"
 #include "object-enchant/tr-types.h"
 #include "object/item-tester-hooker.h"
-#include "object/object-flags.h"
 #include "perception/object-perception.h"
 #include "player-base/player-class.h"
 #include "player-info/smith-data-type.h"
@@ -98,11 +97,7 @@ concptr Smith::get_essence_name(SmithEssenceType essence)
 concptr Smith::get_effect_name(SmithEffectType effect)
 {
     auto info = find_smith_info(effect);
-    if (!info.has_value()) {
-        return _("不明", "Unknown");
-    }
-
-    return info.value()->name;
+    return info ? (*info)->name : _("不明", "Unknown");
 }
 
 /*!
@@ -114,11 +109,11 @@ concptr Smith::get_effect_name(SmithEffectType effect)
 std::string Smith::get_need_essences_desc(SmithEffectType effect)
 {
     auto info = find_smith_info(effect);
-    if (!info.has_value() || info.value()->need_essences.empty()) {
+    if (!info || (*info)->need_essences.empty()) {
         return _("不明", "Unknown");
     }
 
-    const auto &need_essences = info.value()->need_essences;
+    const auto &need_essences = (*info)->need_essences;
     std::stringstream ss;
     for (auto i = 0U; i < need_essences.size(); i++) {
         ss << Smith::get_essence_name(need_essences[i]);
@@ -139,11 +134,11 @@ std::string Smith::get_need_essences_desc(SmithEffectType effect)
 std::vector<SmithEssenceType> Smith::get_need_essences(SmithEffectType effect)
 {
     auto info = find_smith_info(effect);
-    if (!info.has_value()) {
+    if (!info) {
         return {};
     }
 
-    return info.value()->need_essences;
+    return (*info)->need_essences;
 }
 
 /*!
@@ -158,11 +153,11 @@ std::vector<SmithEssenceType> Smith::get_need_essences(SmithEffectType effect)
 int Smith::get_essence_consumption(SmithEffectType effect, const ItemEntity *o_ptr)
 {
     auto info = find_smith_info(effect);
-    if (!info.has_value()) {
+    if (!info) {
         return 0;
     }
 
-    auto consumption = info.value()->consumption;
+    auto consumption = (*info)->consumption;
     if (o_ptr == nullptr) {
         return consumption;
     }
@@ -185,11 +180,11 @@ int Smith::get_essence_consumption(SmithEffectType effect, const ItemEntity *o_p
 std::unique_ptr<ItemTester> Smith::get_item_tester(SmithEffectType effect)
 {
     auto info = find_smith_info(effect);
-    if (!info.has_value()) {
+    if (!info) {
         return std::make_unique<TvalItemTester>(ItemKindType::NONE);
     }
 
-    auto tester_func = [i = info.value()](const ItemEntity *o_ptr) {
+    auto tester_func = [i = *info](const ItemEntity *o_ptr) {
         return i->can_give_smith_effect(o_ptr);
     };
     return std::make_unique<FuncItemTester>(tester_func);
@@ -204,11 +199,11 @@ std::unique_ptr<ItemTester> Smith::get_item_tester(SmithEffectType effect)
 TrFlags Smith::get_effect_tr_flags(SmithEffectType effect)
 {
     auto info = find_smith_info(effect);
-    if (!info.has_value()) {
+    if (!info) {
         return {};
     }
 
-    return info.value()->tr_flags();
+    return (*info)->tr_flags();
 }
 
 /*!
@@ -264,13 +259,13 @@ std::vector<SmithEffectType> Smith::get_effect_list(SmithCategoryType category)
 int Smith::get_addable_count(SmithEffectType effect, const ItemEntity *o_ptr) const
 {
     auto info = find_smith_info(effect);
-    if (!info.has_value()) {
+    if (!info) {
         return 0;
     }
 
     auto consumption = Smith::get_essence_consumption(effect, o_ptr);
 
-    return addable_count(this->smith_data.get(), info.value()->need_essences, consumption);
+    return addable_count(this->smith_data.get(), (*info)->need_essences, consumption);
 }
 
 /*!
@@ -303,7 +298,7 @@ int Smith::get_essence_num_of_posessions(SmithEssenceType essence) const
 Smith::DrainEssenceResult Smith::drain_essence(ItemEntity *o_ptr)
 {
     // 抽出量を揃えるためKILLフラグのみ付いている場合はSLAYフラグも付ける
-    auto old_flags = object_flags(o_ptr);
+    auto old_flags = o_ptr->get_flags();
     if (old_flags.has(TR_KILL_DRAGON)) {
         old_flags.set(TR_SLAY_DRAGON);
     }
@@ -363,9 +358,9 @@ Smith::DrainEssenceResult Smith::drain_essence(ItemEntity *o_ptr)
 
     o_ptr->ident |= (IDENT_FULL_KNOWN);
     object_aware(player_ptr, o_ptr);
-    object_known(o_ptr);
+    o_ptr->mark_as_known();
 
-    auto new_flags = object_flags(o_ptr);
+    const auto new_flags = o_ptr->get_flags();
 
     std::unordered_map<SmithEssenceType, int> drain_values;
 
@@ -438,16 +433,16 @@ Smith::DrainEssenceResult Smith::drain_essence(ItemEntity *o_ptr)
 bool Smith::add_essence(SmithEffectType effect, ItemEntity *o_ptr, int number)
 {
     auto info = find_smith_info(effect);
-    if (!info.has_value()) {
+    if (!info) {
         return false;
     }
 
     const auto total_consumption = this->get_essence_consumption(effect, o_ptr) * number;
-    for (auto &&essence : info.value()->need_essences) {
+    for (auto &&essence : (*info)->need_essences) {
         this->smith_data->essences[essence] -= static_cast<int16_t>(total_consumption);
     }
 
-    return info.value()->add_essence(this->player_ptr, o_ptr, number);
+    return (*info)->add_essence(this->player_ptr, o_ptr, number);
 }
 
 /*!
@@ -460,13 +455,13 @@ void Smith::erase_essence(ItemEntity *o_ptr) const
     o_ptr->smith_act_idx = std::nullopt;
 
     auto effect = Smith::object_effect(o_ptr);
-    if (!effect.has_value()) {
+    if (!effect) {
         return;
     }
-    auto info = find_smith_info(effect.value());
-    if (!info.has_value()) {
+    auto info = find_smith_info(*effect);
+    if (!info) {
         return;
     }
 
-    info.value()->erase_essence(o_ptr);
+    (*info)->erase_essence(o_ptr);
 }
index bfda79a..766928b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/system-variables.h"
 
index acaa076..62ec2e0 100644 (file)
@@ -1,6 +1,5 @@
-#include "smith/smith-info.h"
+#include "smith/smith-info.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "smith/smith-types.h"
 #include "sv-definition/sv-weapon-types.h"
@@ -39,8 +38,7 @@ bool BasicSmithInfo::add_essence(PlayerType *, ItemEntity *o_ptr, int) const
 void BasicSmithInfo::erase_essence(ItemEntity *o_ptr) const
 {
     o_ptr->smith_effect = std::nullopt;
-    auto flags = object_flags(o_ptr);
-    if (flags.has_none_of(TR_PVAL_FLAG_MASK)) {
+    if (o_ptr->get_flags().has_none_of(TR_PVAL_FLAG_MASK)) {
         o_ptr->pval = 0;
     }
 }
@@ -57,7 +55,7 @@ bool BasicSmithInfo::can_give_smith_effect(const ItemEntity *o_ptr) const
      * 残る具体的な絞り込みは BasicSmithInfo::can_give_smith_effect_impl およびその派生クラスで
      * オーバーライドした関数にて行う
      */
-    if (o_ptr->is_fixed_or_random_artifact() || o_ptr->smith_effect.has_value()) {
+    if (o_ptr->is_fixed_or_random_artifact() || o_ptr->smith_effect) {
         return false;
     }
 
@@ -111,7 +109,7 @@ void ActivationSmithInfo::erase_essence(ItemEntity *o_ptr) const
 
 bool ActivationSmithInfo::can_give_smith_effect(const ItemEntity *o_ptr) const
 {
-    if (o_ptr->is_fixed_or_random_artifact() || o_ptr->smith_act_idx.has_value()) {
+    if (o_ptr->is_fixed_or_random_artifact() || o_ptr->smith_act_idx) {
         return false;
     }
 
index 19c6c63..d8af795 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 8318591..3bfbc0b 100644 (file)
@@ -1,4 +1,4 @@
-#include "smith/smith-tables.h"
+#include "smith/smith-tables.h"
 #include "artifact/random-art-effects.h"
 #include "object-enchant/tr-flags.h"
 #include "object-enchant/tr-types.h"
@@ -332,7 +332,7 @@ const std::vector<essence_drain_type> Smith::essence_drain_info_table = {
     { TR_EASY2_WEAPON, { SmithEssenceType::EASY2_WEAPON }, 10 },
     { TR_DOWN_SAVING, {}, -1 },
     { TR_NO_AC, {}, -1 },
-    { TR_HEAVY_SPELL, {}, -1 },
+    { TR_XXX_142, {}, -1 },
     { TR_RES_TIME, { SmithEssenceType::RES_TIME }, 10 },
     { TR_RES_WATER, { SmithEssenceType::RES_WATER }, 10 },
     { TR_INVULN_ARROW, {}, 0 },
index 1bc22a1..6efa2b5 100644 (file)
@@ -1,11 +1,11 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 #include <vector>
 
 enum class SmithEssenceType : int16_t;
-enum tr_type : int32_t;
+enum tr_type : int;
 
 /*!
  * @brief エッセンス抽出情報構造体
index fa186be..2336583 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/system-variables.h"
 
index 5bfa3be..c3510f7 100644 (file)
@@ -1,4 +1,4 @@
-#include "specific-object/blade-turner.h"
+#include "specific-object/blade-turner.h"
 #include "effect/attribute-types.h"
 #include "hpmp/hp-mp-processor.h"
 #include "spell-kind/spells-launcher.h"
index eb254b6..d2232f1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool activate_bladeturner(PlayerType *player_ptr);
index 520e2e8..65d65f7 100644 (file)
@@ -1,6 +1,5 @@
-#include "specific-object/bloody-moon.h"
+#include "specific-object/bloody-moon.h"
 #include "artifact/fixed-art-types.h"
-#include "core/player-update-types.h"
 #include "object-enchant/object-boost.h"
 #include "object-enchant/tr-types.h"
 #include "player-base/player-race.h"
@@ -8,9 +7,53 @@
 #include "system/artifact-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
+constexpr auto BLOODY_MOON_SLAYING_FLAG_CANDIDATES = {
+    TR_SLAY_ANIMAL,
+    TR_SLAY_EVIL,
+    TR_SLAY_UNDEAD,
+    TR_SLAY_DEMON,
+    TR_SLAY_ORC,
+    TR_SLAY_TROLL,
+    TR_SLAY_GIANT,
+    TR_SLAY_DRAGON,
+    TR_SLAY_HUMAN,
+    TR_KILL_ANIMAL,
+    TR_KILL_UNDEAD,
+    TR_KILL_DEMON,
+    TR_KILL_ORC,
+    TR_KILL_TROLL,
+    TR_KILL_GIANT,
+    TR_KILL_DRAGON,
+    TR_KILL_HUMAN,
+    TR_BRAND_POIS,
+    TR_BRAND_ACID,
+    TR_BRAND_ELEC,
+    TR_BRAND_FIRE,
+    TR_BRAND_COLD,
+    TR_CHAOTIC,
+    TR_VAMPIRIC,
+    TR_VORPAL,
+    TR_EARTHQUAKE,
+};
+
+constexpr auto BLOODY_MOON_PVAL_FLAG_CANDIDATES = {
+    TR_STR,
+    TR_INT,
+    TR_WIS,
+    TR_DEX,
+    TR_CON,
+    TR_CHR,
+    TR_STEALTH,
+    TR_SEARCH,
+    TR_INFRA,
+    TR_TUNNEL,
+    TR_SPEED,
+};
+
 /*!
  * @brief 固定アーティファクト『ブラッディムーン』の特性を変更する。
  * @details スレイ2d2種、及びone_resistance()による耐性1d2種、pval2種を得る。
@@ -20,32 +63,18 @@ void get_bloody_moon_flags(ItemEntity *o_ptr)
 {
     o_ptr->art_flags = ArtifactsInfo::get_instance().get_artifact(FixedArtifactId::BLOOD).flags;
 
-    int dummy = randint1(2) + randint1(2);
-    for (int i = 0; i < dummy; i++) {
-        int flag = randint0(26);
-        if (flag >= 20) {
-            o_ptr->art_flags.set(TR_KILL_UNDEAD + flag - 20);
-        } else if (flag == 19) {
-            o_ptr->art_flags.set(TR_KILL_ANIMAL);
-        } else if (flag == 18) {
-            o_ptr->art_flags.set(TR_SLAY_HUMAN);
-        } else {
-            o_ptr->art_flags.set(TR_CHAOTIC + flag);
-        }
+    for (int i = 0, count = damroll(2, 2); i < count; i++) {
+        const auto flag = rand_choice(BLOODY_MOON_SLAYING_FLAG_CANDIDATES);
+        o_ptr->art_flags.set(flag);
     }
 
-    dummy = randint1(2);
-    for (int i = 0; i < dummy; i++) {
+    for (int i = 0, count = randint1(2); i < count; i++) {
         one_resistance(o_ptr);
     }
 
     for (int i = 0; i < 2; i++) {
-        int tmp = randint0(11);
-        if (tmp < A_MAX) {
-            o_ptr->art_flags.set(TR_STR + tmp);
-        } else {
-            o_ptr->art_flags.set(TR_STEALTH + tmp - 6);
-        }
+        const auto flag = rand_choice(BLOODY_MOON_PVAL_FLAG_CANDIDATES);
+        o_ptr->art_flags.set(flag);
     }
 }
 
@@ -67,6 +96,10 @@ bool activate_bloody_moon(PlayerType *player_ptr, ItemEntity *o_ptr)
         calc_android_exp(player_ptr);
     }
 
-    player_ptr->update |= PU_BONUS | PU_HP;
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     return true;
 }
index 59ac646..924b63d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index 5be3d39..f026fb0 100644 (file)
@@ -1,4 +1,4 @@
-#include "specific-object/chest.h"
+#include "specific-object/chest.h"
 #include "effect/attribute-types.h"
 #include "floor/cave.h"
 #include "floor/floor-object.h"
@@ -9,7 +9,6 @@
 #include "monster-floor/monster-summon.h"
 #include "monster-floor/place-monster-types.h"
 #include "object-enchant/item-apply-magic.h"
-#include "perception/object-perception.h"
 #include "player-info/class-info.h"
 #include "player/player-damage.h"
 #include "player/player-status-flags.h"
@@ -36,32 +35,23 @@ Chest::Chest(PlayerType *player_ptr)
 }
 
 /*!
- * @brief 箱からアイテムを引き出す /
- * Allocates objects upon opening a chest    -BEN-
+ * @brief 箱からアイテムを引き出す
  * @param scatter TRUEならばトラップによるアイテムの拡散処理
- * @param y 箱の存在するマスのY座標
- * @param x 箱の存在するマスのX座標
- * @param o_idx 箱のオブジェクトID
- * @return なし
- * @details
- * <pre>
- * Disperse treasures from the given chest, centered at (x,y).
- *
- * Small chests often contain "gold", while Large chests always contain
- * items.  Wooden chests contain 2 items, Iron chests contain 4 items,
- * and Steel chests contain 6 items.  The "value" of the items in a
- * chest is based on the "power" of the chest, which is in turn based
- * on the level on which the chest is generated.
- * </pre>
+ * @param pos 箱の座標
+ * @param item_idx フロア内アイテムID
  */
-void Chest::chest_death(bool scatter, POSITION y, POSITION x, OBJECT_IDX o_idx)
+void Chest::open(bool scatter, const Pos2D &pos, short item_idx)
 {
     BIT_FLAGS mode = AM_GOOD | AM_FORBID_CHEST;
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto *o_ptr = &floor_ptr->o_list[o_idx];
+    auto &floor = *this->player_ptr->current_floor_ptr;
+    auto &item = floor.o_list[item_idx];
+    if (!item.is_valid()) {
+        msg_print(_("箱は既に壊れてしまっている…", "The chest was broken and you couldn't open it..."));
+        return;
+    }
 
     /* Small chests often hold "gold" */
-    const auto sval = o_ptr->bi_key.sval().value();
+    const auto sval = *item.bi_key.sval();
     auto small = sval < SV_CHEST_MIN_LARGE;
 
     /* Determine how much to drop (see above) */
@@ -71,14 +61,12 @@ void Chest::chest_death(bool scatter, POSITION y, POSITION x, OBJECT_IDX o_idx)
         number = 5;
         small = false;
         mode |= AM_GREAT;
-        floor_ptr->object_level = o_ptr->chest_level;
+        floor.object_level = item.chest_level;
     } else {
-        /* Determine the "value" of the items */
-        floor_ptr->object_level = std::abs(o_ptr->pval) + 10;
+        floor.object_level = std::abs(item.pval) + 10;
     }
 
-    /* Zero pval means empty chest */
-    if (!o_ptr->pval) {
+    if (item.pval == 0) {
         number = 0;
     }
 
@@ -107,11 +95,10 @@ void Chest::chest_death(bool scatter, POSITION y, POSITION x, OBJECT_IDX o_idx)
 
         /* If chest scatters its contents, pick any floor square. */
         if (scatter) {
-            int i;
-            for (i = 0; i < 200; i++) {
+            for (auto i = 0; i < 200; i++) {
                 /* Pick a totally random spot. */
-                y = randint0(MAX_HGT);
-                x = randint0(MAX_WID);
+                const auto y = randint0(MAX_HGT);
+                const auto x = randint0(MAX_WID);
 
                 /* Must be an empty floor. */
                 if (!is_cave_empty_bold(this->player_ptr, y, x)) {
@@ -127,38 +114,24 @@ void Chest::chest_death(bool scatter, POSITION y, POSITION x, OBJECT_IDX o_idx)
         }
         /* Normally, drop object near the chest. */
         else {
-            (void)drop_near(this->player_ptr, q_ptr, -1, y, x);
+            (void)drop_near(this->player_ptr, q_ptr, -1, pos.y, pos.x);
         }
     }
 
-    /* Reset the object level */
-    floor_ptr->object_level = floor_ptr->base_level;
-
-    /* Empty */
-    o_ptr->pval = 0;
-
-    /* Known */
-    object_known(o_ptr);
+    floor.object_level = floor.base_level;
+    item.pval = 0;
+    item.mark_as_known();
 }
 
 /*!
- * @brief 箱のトラップ処理 /
- * Chests have traps too.
- * @param y 箱の存在するマスのY座標
+ * @brief 箱のトラップ処理
+ * @param pos 箱の座標
  * @param x 箱の存在するマスのX座標
- * @param o_idx 箱のオブジェクトID
- * @return なし
- * @details
- * <pre>
- * Exploding chest destroys contents (and traps).
- * Note that the chest itself is never destroyed.
- * </pre>
+ * @param item_idx 箱のオブジェクトID
  */
-void Chest::chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
+void Chest::fire_trap(const Pos2D &pos, short item_idx)
 {
-    int i;
-
-    auto *o_ptr = &this->player_ptr->current_floor_ptr->o_list[o_idx];
+    auto *o_ptr = &this->player_ptr->current_floor_ptr->o_list[item_idx];
 
     int mon_level = o_ptr->chest_level;
 
@@ -167,8 +140,7 @@ void Chest::chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
         return;
     }
 
-    /* Obtain the traps */
-    auto trap = chest_traps[o_ptr->pval];
+    const auto &trap = chest_traps[o_ptr->pval];
 
     /* Lose strength */
     if (trap.has(ChestTrapType::LOSE_STR)) {
@@ -204,11 +176,11 @@ void Chest::chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
     if (trap.has(ChestTrapType::SUMMON)) {
         int num = 2 + randint1(3);
         msg_print(_("突如吹き出した煙に包み込まれた!", "You are enveloped in a cloud of smoke!"));
-        for (i = 0; i < num; i++) {
+        for (auto i = 0; i < num; i++) {
             if (randint1(100) < this->player_ptr->current_floor_ptr->dun_level) {
                 activate_hi_summon(this->player_ptr, this->player_ptr->y, this->player_ptr->x, false);
             } else {
-                (void)summon_specific(this->player_ptr, 0, y, x, mon_level, SUMMON_NONE, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
+                (void)summon_specific(this->player_ptr, 0, pos.y, pos.x, mon_level, SUMMON_NONE, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
             }
         }
     }
@@ -216,8 +188,8 @@ void Chest::chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
     /* Elemental summon. */
     if (trap.has(ChestTrapType::E_SUMMON)) {
         msg_print(_("宝を守るためにエレメンタルが現れた!", "Elemental beings appear to protect their treasures!"));
-        for (i = 0; i < randint1(3) + 5; i++) {
-            (void)summon_specific(this->player_ptr, 0, y, x, mon_level, SUMMON_ELEMENTAL, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
+        for (auto i = 0; i < randint1(3) + 5; i++) {
+            (void)summon_specific(this->player_ptr, 0, pos.y, pos.x, mon_level, SUMMON_ELEMENTAL, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
         }
     }
 
@@ -225,12 +197,12 @@ void Chest::chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
     if (trap.has(ChestTrapType::BIRD_STORM)) {
         msg_print(_("鳥の群れがあなたを取り巻いた!", "A storm of birds swirls around you!"));
 
-        for (i = 0; i < randint1(3) + 3; i++) {
-            (void)fire_meteor(this->player_ptr, -1, AttributeType::FORCE, y, x, o_ptr->pval / 5, 7);
+        for (auto i = 0; i < randint1(3) + 3; i++) {
+            (void)fire_meteor(this->player_ptr, -1, AttributeType::FORCE, pos.y, pos.x, o_ptr->pval / 5, 7);
         }
 
-        for (i = 0; i < randint1(5) + o_ptr->pval / 5; i++) {
-            (void)summon_specific(this->player_ptr, 0, y, x, mon_level, SUMMON_BIRD, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
+        for (auto i = 0; i < randint1(5) + o_ptr->pval / 5; i++) {
+            (void)summon_specific(this->player_ptr, 0, pos.y, pos.x, mon_level, SUMMON_BIRD, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
         }
     }
 
@@ -239,33 +211,33 @@ void Chest::chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
         /* Summon demons. */
         if (one_in_(4)) {
             msg_print(_("炎と硫黄の雲の中に悪魔が姿を現した!", "Demons materialize in clouds of fire and brimstone!"));
-            for (i = 0; i < randint1(3) + 2; i++) {
-                (void)fire_meteor(this->player_ptr, -1, AttributeType::FIRE, y, x, 10, 5);
-                (void)summon_specific(this->player_ptr, 0, y, x, mon_level, SUMMON_DEMON, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
+            for (auto i = 0; i < randint1(3) + 2; i++) {
+                (void)fire_meteor(this->player_ptr, -1, AttributeType::FIRE, pos.y, pos.x, 10, 5);
+                (void)summon_specific(this->player_ptr, 0, pos.y, pos.x, mon_level, SUMMON_DEMON, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
             }
         }
 
         /* Summon dragons. */
         else if (one_in_(3)) {
             msg_print(_("暗闇にドラゴンの影がぼんやりと現れた!", "Draconic forms loom out of the darkness!"));
-            for (i = 0; i < randint1(3) + 2; i++) {
-                (void)summon_specific(this->player_ptr, 0, y, x, mon_level, SUMMON_DRAGON, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
+            for (auto i = 0; i < randint1(3) + 2; i++) {
+                (void)summon_specific(this->player_ptr, 0, pos.y, pos.x, mon_level, SUMMON_DRAGON, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
             }
         }
 
         /* Summon hybrids. */
         else if (one_in_(2)) {
             msg_print(_("奇妙な姿の怪物が襲って来た!", "Creatures strange and twisted assault you!"));
-            for (i = 0; i < randint1(5) + 3; i++) {
-                (void)summon_specific(this->player_ptr, 0, y, x, mon_level, SUMMON_HYBRID, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
+            for (auto i = 0; i < randint1(5) + 3; i++) {
+                (void)summon_specific(this->player_ptr, 0, pos.y, pos.x, mon_level, SUMMON_HYBRID, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
             }
         }
 
         /* Summon vortices (scattered) */
         else {
             msg_print(_("渦巻が合体し、破裂した!", "Vortices coalesce and wreak destruction!"));
-            for (i = 0; i < randint1(3) + 2; i++) {
-                (void)summon_specific(this->player_ptr, 0, y, x, mon_level, SUMMON_VORTEX, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
+            for (auto i = 0; i < randint1(3) + 2; i++) {
+                (void)summon_specific(this->player_ptr, 0, pos.y, pos.x, mon_level, SUMMON_VORTEX, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
             }
         }
     }
@@ -314,7 +286,7 @@ void Chest::chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
                 continue;
             }
 
-            (void)fire_meteor(this->player_ptr, -1, AttributeType::NETHER, y, x, 150, 1);
+            (void)fire_meteor(this->player_ptr, -1, AttributeType::NETHER, pos.y, pos.x, 150, 1);
         }
     }
 
@@ -335,7 +307,7 @@ void Chest::chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
     /* Scatter contents. */
     if ((trap.has(ChestTrapType::SCATTER)) && o_ptr->is_valid()) {
         msg_print(_("宝箱の中身はダンジョンじゅうに散乱した!", "The contents of the chest scatter all over the dungeon!"));
-        this->chest_death(true, y, x, o_idx);
+        this->open(true, pos, item_idx);
         o_ptr->pval = 0;
     }
 }
index 87b40d6..d28e6e4 100644 (file)
@@ -1,14 +1,14 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include "util/point-2d.h"
 
 class PlayerType;
 class Chest {
 public:
     Chest(PlayerType *player_ptr);
     virtual ~Chest() = default;
-    void chest_death(bool scatter, POSITION y, POSITION x, OBJECT_IDX o_idx);
-    void chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx);
+    void open(bool scatter, const Pos2D &pos, short item_idx);
+    void fire_trap(const Pos2D &pos, short item_idx);
 
 private:
     PlayerType *player_ptr;
index 77c91d5..55c57d2 100644 (file)
@@ -1,4 +1,4 @@
-#include "specific-object/death-crimson.h"
+#include "specific-object/death-crimson.h"
 #include "artifact/fixed-art-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
index 6274ca0..39b7c5e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index b37932d..0b2b00e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 死の大鎌に特有の処理
  * @date 2020/05/23
  * @author Hourier
@@ -7,14 +7,12 @@
 
 #include "specific-object/death-scythe.h"
 #include "combat/attack-criticality.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "inventory/inventory-slot-types.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
-#include "player-attack/player-attack-util.h"
+#include "player-attack/player-attack.h"
 #include "player-base/player-class.h"
 #include "player-info/race-info.h"
 #include "player/player-damage.h"
@@ -22,6 +20,7 @@
 #include "status/element-resistance.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
@@ -113,7 +112,7 @@ static void compensate_death_scythe_reflection_magnification(PlayerType *player_
 
     if (!PlayerClass(player_ptr).equals(PlayerClassType::SAMURAI) && (death_scythe_flags.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (player_ptr->msp / 30))) {
         player_ptr->csp -= (1 + (player_ptr->msp / 30));
-        player_ptr->redraw |= (PR_MP);
+        RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
         *magnification = *magnification * 3 / 2 + 20;
     }
 }
@@ -149,7 +148,7 @@ void process_death_scythe_reflection(PlayerType *player_ptr, player_attack_type
     msg_print(_("振り回した大鎌が自分自身に返ってきた!", "Your scythe returns to you!"));
 
     auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + pa_ptr->hand];
-    auto death_scythe_flags = object_flags(o_ptr);
+    const auto death_scythe_flags = o_ptr->get_flags();
     pa_ptr->attack_damage = damroll(o_ptr->dd + player_ptr->to_dd[pa_ptr->hand], o_ptr->ds + player_ptr->to_ds[pa_ptr->hand]);
     int magnification = calc_death_scythe_reflection_magnification(player_ptr);
     compensate_death_scythe_reflection_magnification(player_ptr, &magnification, death_scythe_flags);
index f8fda9a..55fda08 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct player_attack_type;
 class PlayerType;
index 960c749..214d0f0 100644 (file)
@@ -1,4 +1,4 @@
-#include "specific-object/monster-ball.h"
+#include "specific-object/monster-ball.h"
 #include "effect/spells-effect-util.h"
 #include "floor/geometry.h"
 #include "game-option/input-options.h"
@@ -29,7 +29,7 @@ static void inscribe_nickname(ItemEntity &item, const CapturedMonsterType &cap_m
     }
 
     auto &insc = item.inscription;
-    if (!insc.has_value()) {
+    if (!insc) {
         insc = "";
     }
 
@@ -100,7 +100,7 @@ static bool release_monster(PlayerType *player_ptr, ItemEntity &item, DIRECTION
         return false;
     }
 
-    if (!place_monster_aux(player_ptr, 0, player_ptr->y + ddy[dir], player_ptr->x + ddx[dir], r_idx, PM_FORCE_PET | PM_NO_KAGE)) {
+    if (!place_specific_monster(player_ptr, 0, player_ptr->y + ddy[dir], player_ptr->x + ddx[dir], r_idx, PM_FORCE_PET | PM_NO_KAGE)) {
         return false;
     }
 
@@ -142,7 +142,7 @@ bool exe_monster_capture(PlayerType *player_ptr, ItemEntity &item)
     }
 
     DIRECTION dir;
-    if (!get_direction(player_ptr, &dir, false, false)) {
+    if (!get_direction(player_ptr, &dir)) {
         return true;
     }
 
index 191d50e..ddea3ec 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 class ItemEntity;
index b1bad06..f8180ba 100644 (file)
@@ -1,4 +1,4 @@
-#include "specific-object/muramasa.h"
+#include "specific-object/muramasa.h"
 #include "artifact/fixed-art-types.h"
 #include "core/asking-player.h"
 #include "spell/spells-object.h"
@@ -13,7 +13,7 @@ bool activate_muramasa(PlayerType *player_ptr, ItemEntity *o_ptr)
         return false;
     }
 
-    if (!get_check(_("本当に使いますか?", "Are you sure?! "))) {
+    if (!input_check(_("本当に使いますか?", "Are you sure?! "))) {
         return true;
     }
 
index 2601915..f869b7b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index 1e9932e..009e7de 100644 (file)
@@ -1,4 +1,4 @@
-#include "specific-object/ring-of-power.h"
+#include "specific-object/ring-of-power.h"
 #include "effect/attribute-types.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
@@ -53,10 +53,10 @@ static void exe_ring_of_power(PlayerType *player_ptr, DIRECTION dir)
     }
 }
 
-bool activate_ring_of_power(PlayerType *player_ptr, concptr name)
+bool activate_ring_of_power(PlayerType *player_ptr, std::string_view name)
 {
     DIRECTION dir;
-    msg_format(_("%sは漆黒に輝いた...", "The %s glows intensely black..."), name);
+    msg_format(_("%sは漆黒に輝いた...", "The %s glows intensely black..."), name.data());
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
index fec840e..cf6ea33 100644 (file)
@@ -1,6 +1,6 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
+#include <string_view>
 
 class PlayerType;
-bool activate_ring_of_power(PlayerType *player_ptr, concptr name);
+bool activate_ring_of_power(PlayerType *player_ptr, std::string_view name);
index 8fa9b28..4477319 100644 (file)
@@ -1,15 +1,15 @@
-/*!
+/*!
  * @brief 知識の石を発動させる処理
  * @date 2021/09/24
  * @author Hourier
  */
 
 #include "specific-object/stone-of-lore.h"
-#include "core/player-redraw-types.h"
 #include "player/player-damage.h"
 #include "spell-kind/spells-perception.h"
 #include "status/bad-status-setter.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
@@ -53,9 +53,10 @@ void StoneOfLore::consume_mp()
         return;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (this->player_ptr->csp >= 20) {
         this->player_ptr->csp -= 20;
-        set_bits(this->player_ptr->redraw, PR_MP);
+        rfu.set_flag(MainWindowRedrawingFlag::MP);
         return;
     }
 
@@ -66,5 +67,5 @@ void StoneOfLore::consume_mp()
     BadStatusSetter bss(this->player_ptr);
     (void)bss.mod_paralysis(randint1(5 * oops + 1));
     (void)bss.mod_confusion(randint1(5 * oops + 1));
-    set_bits(this->player_ptr->redraw, PR_MP);
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
 }
index bda09c8..555053a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 class StoneOfLore {
index 0007939..4400758 100644 (file)
@@ -1,4 +1,4 @@
-#include "specific-object/toragoroshi.h"
+#include "specific-object/toragoroshi.h"
 #include "player-attack/player-attack.h"
 #include "system/player-type-definition.h"
 #include "view/display-messages.h"
index 28021ff..2600972 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool activate_toragoroshi(PlayerType *player_ptr);
index 348a3ae..b524ce3 100644 (file)
@@ -1,5 +1,4 @@
-#include "specific-object/torch.h"
-#include "core/player-update-types.h"
+#include "specific-object/torch.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/cave.h"
 #include "grid/grid.h"
@@ -7,7 +6,6 @@
 #include "mind/mind-ninja.h"
 #include "object-enchant/object-ego.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "player/special-defense-types.h"
 #include "sv-definition/sv-lite-types.h"
@@ -16,6 +14,7 @@
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/point-2d.h"
 #include <vector>
@@ -90,10 +89,7 @@ void update_lite_radius(PlayerType *player_ptr)
 {
     player_ptr->cur_lite = 0;
     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
-        ItemEntity *o_ptr;
-        o_ptr = &player_ptr->inventory_list[i];
-        auto flags = object_flags(o_ptr);
-
+        const auto *o_ptr = &player_ptr->inventory_list[i];
         if (!o_ptr->is_valid()) {
             continue;
         }
@@ -102,6 +98,7 @@ void update_lite_radius(PlayerType *player_ptr)
             player_ptr->cur_lite++;
         }
 
+        const auto flags = o_ptr->get_flags();
         if (flags.has_not(TR_DARK_SOURCE)) {
             if (o_ptr->bi_key.tval() == ItemKindType::LITE) {
                 const auto sval = o_ptr->bi_key.sval();
@@ -143,7 +140,7 @@ void update_lite_radius(PlayerType *player_ptr)
         player_ptr->cur_lite += rad;
     }
 
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS) && player_ptr->cur_lite > 1) {
+    if (player_ptr->current_floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS) && player_ptr->cur_lite > 1) {
         player_ptr->cur_lite = 1;
     }
 
@@ -163,9 +160,13 @@ void update_lite_radius(PlayerType *player_ptr)
         return;
     }
 
-    player_ptr->update |= PU_LITE | PU_MONSTER_LITE | PU_MONSTER_STATUSES;
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     player_ptr->old_lite = player_ptr->cur_lite;
-
     if (player_ptr->cur_lite > 0) {
         set_superstealth(player_ptr, false);
     }
@@ -337,5 +338,5 @@ void update_lite(PlayerType *player_ptr)
         cave_redraw_later(floor_ptr, y, x);
     }
 
-    player_ptr->update |= PU_DELAY_VISIBILITY;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::DELAY_VISIBILITY);
 }
index a86912d..e8d077e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 8480e21..cfd3920 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 鏡使いの鏡魔法効果処理
  * @date 2022/03/07
  * @author Hourier
@@ -6,7 +6,6 @@
  */
 
 #include "spell-class/spells-mirror-master.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "effect/attribute-types.h"
 #include "monster/monster-update.h"
 #include "pet/pet-util.h"
 #include "spell-kind/spells-teleport.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/grid-selector.h"
 #include "target/projection-path-calculator.h"
@@ -51,10 +52,11 @@ SpellsMirrorMaster::SpellsMirrorMaster(PlayerType *player_ptr)
 
 void SpellsMirrorMaster::remove_mirror(int y, int x)
 {
-    auto *g_ptr = &this->player_ptr->current_floor_ptr->grid_array[y][x];
+    auto &floor = *this->player_ptr->current_floor_ptr;
+    auto *g_ptr = &floor.grid_array[y][x];
     reset_bits(g_ptr->info, CAVE_OBJECT);
     g_ptr->mimic = 0;
-    if (dungeons_info[this->player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         reset_bits(g_ptr->info, CAVE_GLOW);
         if (!view_torch_grids) {
             reset_bits(g_ptr->info, CAVE_MARK);
@@ -170,7 +172,7 @@ bool SpellsMirrorMaster::mirror_concentration()
         this->player_ptr->csp_frac = 0;
     }
 
-    set_bits(this->player_ptr->redraw, PR_MP);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
     return true;
 }
 
@@ -265,25 +267,21 @@ void SpellsMirrorMaster::next_mirror(int *next_y, int *next_x, int cury, int cur
 
 void SpellsMirrorMaster::project_seeker_ray(int target_x, int target_y, int dam)
 {
-    POSITION y1;
-    POSITION x1;
-    POSITION y2;
-    POSITION x2;
     constexpr auto typ = AttributeType::SEEKER;
     BIT_FLAGS flag = PROJECT_BEAM | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM | PROJECT_THRU | PROJECT_MIRROR;
     rakubadam_p = 0;
     rakubadam_m = 0;
     monster_target_y = this->player_ptr->y;
     monster_target_x = this->player_ptr->x;
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
+    auto &floor = *this->player_ptr->current_floor_ptr;
 
     ProjectResult res;
 
-    x1 = this->player_ptr->x;
-    y1 = this->player_ptr->y;
+    auto x1 = this->player_ptr->x;
+    auto y1 = this->player_ptr->y;
 
-    y2 = target_y;
-    x2 = target_x;
+    auto y2 = target_y;
+    auto x2 = target_x;
 
     if ((x1 == x2) && (y1 == y2)) {
         reset_bits(flag, PROJECT_THRU);
@@ -296,20 +294,20 @@ void SpellsMirrorMaster::project_seeker_ray(int target_x, int target_y, int dam)
     project_m_x = 0;
     project_m_y = 0;
     auto visual = false;
-
+    const auto max_range = AngbandSystem::get_instance().get_max_range();
     while (true) {
-        projection_path path_g(this->player_ptr, (project_length ? project_length : get_max_range(this->player_ptr)), y1, x1, y2, x2, flag);
+        projection_path path_g(this->player_ptr, (project_length ? project_length : max_range), y1, x1, y2, x2, flag);
 
         if (path_g.path_num() == 0) {
             break;
         }
 
         for (auto path_g_ite = path_g.begin(); path_g_ite != path_g.end(); path_g_ite++) {
-            const auto [oy, ox] = *(path_g_ite == path_g.begin() ? path_g.begin() : path_g_ite - 1);
-            const auto [ny, nx] = *path_g_ite;
+            const auto &[oy, ox] = *(path_g_ite == path_g.begin() ? path_g.begin() : path_g_ite - 1);
+            const auto &[ny, nx] = *path_g_ite;
 
             if (delay_factor > 0 && !this->player_ptr->effects()->blindness()->is_blind()) {
-                if (panel_contains(ny, nx) && player_has_los_bold(this->player_ptr, ny, nx)) {
+                if (panel_contains(ny, nx) && floor.has_los({ ny, nx })) {
                     print_bolt_pict(this->player_ptr, oy, ox, ny, nx, typ);
                     move_cursor_relative(ny, nx);
                     term_fresh();
@@ -334,21 +332,21 @@ void SpellsMirrorMaster::project_seeker_ray(int target_x, int target_y, int dam)
             if (affect_monster(this->player_ptr, 0, 0, py, px, dam, typ, flag, true)) {
                 res.notice = true;
             }
-            auto *g_ptr = &floor_ptr->grid_array[project_m_y][project_m_x];
-            auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
-            if (project_m_n == 1 && g_ptr->m_idx > 0 && m_ptr->ml) {
+            const auto &grid = floor.grid_array[project_m_y][project_m_x];
+            const auto &monster = floor.m_list[grid.m_idx];
+            if (project_m_n == 1 && grid.m_idx > 0 && monster.ml) {
                 if (!this->player_ptr->effects()->hallucination()->is_hallucinated()) {
-                    monster_race_track(this->player_ptr, m_ptr->ap_r_idx);
+                    monster_race_track(this->player_ptr, monster.ap_r_idx);
                 }
-                health_track(this->player_ptr, g_ptr->m_idx);
+                health_track(this->player_ptr, grid.m_idx);
             }
 
             (void)affect_feature(this->player_ptr, 0, 0, py, px, dam, typ);
         }
 
-        const auto [y, x] = path_g.back();
+        const auto &[y, x] = path_g.back();
 
-        if (!floor_ptr->grid_array[y][x].is_mirror()) {
+        if (!floor.get_grid({ y, x }).is_mirror()) {
             break;
         }
 
@@ -361,7 +359,8 @@ void SpellsMirrorMaster::project_seeker_ray(int target_x, int target_y, int dam)
     }
 }
 
-static void draw_super_ray_pict(PlayerType *player_ptr, const std::map<int, std::vector<projection_path::const_iterator>> &pos_list_map, const std::vector<projection_path> &second_path_g_list, const std::pair<int, int> &center)
+static void draw_super_ray_pict(PlayerType *player_ptr, const std::map<int, std::vector<projection_path::const_iterator>> &pos_list_map,
+    const std::vector<projection_path> &second_path_g_list, const std::pair<int, int> &center)
 {
     if (delay_factor <= 0) {
         return;
@@ -377,19 +376,20 @@ static void draw_super_ray_pict(PlayerType *player_ptr, const std::map<int, std:
     // スーパーレイの描画を行った座標のリスト。スーパーレイの全ての描画完了後に描画を消去するのに使用する。
     std::vector<std::pair<int, int>> drawn_pos_list;
 
+    const auto &floor = *player_ptr->current_floor_ptr;
     for (const auto &[n, pos_list] : pos_list_map) {
         // スーパーレイの最終到達点の座標の描画を行った座標のリスト。最終到達点の描画を '*' で上書きするのに使用する。
         std::vector<std::pair<int, int>> drawn_last_pos_list;
 
         for (const auto &it : pos_list) {
-            const auto [y, x] = (n == 1) ? center : *std::next(it, -1);
-            const auto [ny, nx] = *it;
+            const auto &[y, x] = (n == 1) ? center : *std::next(it, -1);
+            const auto &[ny, nx] = *it;
 
-            if (panel_contains(y, x) && player_has_los_bold(player_ptr, y, x)) {
+            if (panel_contains(y, x) && floor.has_los({ y, x })) {
                 print_bolt_pict(player_ptr, y, x, y, x, typ);
                 drawn_pos_list.emplace_back(y, x);
             }
-            if (panel_contains(ny, nx) && player_has_los_bold(player_ptr, ny, nx)) {
+            if (panel_contains(ny, nx) && floor.has_los({ ny, nx })) {
                 print_bolt_pict(player_ptr, y, x, ny, nx, typ);
                 if (std::find(last_pos_list.begin(), last_pos_list.end(), *it) != last_pos_list.end()) {
                     drawn_last_pos_list.emplace_back(ny, nx);
@@ -400,7 +400,7 @@ static void draw_super_ray_pict(PlayerType *player_ptr, const std::map<int, std:
         term_xtra(TERM_XTRA_DELAY, delay_factor);
 
         for (const auto &[y, x] : drawn_last_pos_list) {
-            if (panel_contains(y, x) && player_has_los_bold(player_ptr, y, x)) {
+            if (panel_contains(y, x) && floor.has_los({ y, x })) {
                 print_bolt_pict(player_ptr, y, x, y, x, typ);
                 drawn_pos_list.emplace_back(y, x);
             }
@@ -453,7 +453,7 @@ void SpellsMirrorMaster::project_super_ray(int target_x, int target_y, int dam)
     rakubadam_m = 0;
     monster_target_y = this->player_ptr->y;
     monster_target_x = this->player_ptr->x;
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
+    const auto &floor = *this->player_ptr->current_floor_ptr;
 
     ProjectResult res;
 
@@ -468,7 +468,8 @@ void SpellsMirrorMaster::project_super_ray(int target_x, int target_y, int dam)
     }
 
     /* Calculate the projection path */
-    projection_path path_g(this->player_ptr, (project_length ? project_length : get_max_range(this->player_ptr)), y1, x1, y2, x2, flag);
+    const auto &system = AngbandSystem::get_instance();
+    projection_path path_g(this->player_ptr, (project_length ? project_length : system.get_max_range()), y1, x1, y2, x2, flag);
     std::vector<projection_path> second_path_g_list;
     handle_stuff(this->player_ptr);
 
@@ -485,7 +486,7 @@ void SpellsMirrorMaster::project_super_ray(int target_x, int target_y, int dam)
     std::vector<std::pair<int, int>> drawn_pos_list;
     for (const auto &[ny, nx] : path_g) {
         if (delay_factor > 0) {
-            if (panel_contains(ny, nx) && player_has_los_bold(this->player_ptr, ny, nx)) {
+            if (panel_contains(ny, nx) && floor.has_los({ ny, nx })) {
                 print_bolt_pict(this->player_ptr, oy, ox, ny, nx, typ);
                 move_cursor_relative(ny, nx);
                 term_fresh();
@@ -502,7 +503,7 @@ void SpellsMirrorMaster::project_super_ray(int target_x, int target_y, int dam)
             }
         }
 
-        if (!cave_has_flag_bold(floor_ptr, ny, nx, TerrainCharacteristics::PROJECT)) {
+        if (!cave_has_flag_bold(&floor, ny, nx, TerrainCharacteristics::PROJECT)) {
             break;
         }
         oy = ny;
@@ -514,13 +515,13 @@ void SpellsMirrorMaster::project_super_ray(int target_x, int target_y, int dam)
     }
 
     {
-        const auto [y, x] = path_g.back();
-        if (floor_ptr->grid_array[y][x].is_mirror()) {
+        const auto &[y, x] = path_g.back();
+        if (floor.get_grid({ y, x }).is_mirror()) {
             this->remove_mirror(y, x);
             auto project_flag = flag;
             reset_bits(project_flag, PROJECT_MIRROR);
 
-            const auto length = project_length ? project_length : get_max_range(this->player_ptr);
+            const auto length = project_length ? project_length : system.get_max_range();
             for (auto i : cdd) {
                 const auto dy = ddy[i];
                 const auto dx = ddx[i];
@@ -537,8 +538,8 @@ void SpellsMirrorMaster::project_super_ray(int target_x, int target_y, int dam)
     std::map<int, std::vector<projection_path::const_iterator>> pos_list_map;
     for (const auto &second_path_g : second_path_g_list) {
         for (auto it = second_path_g.begin(); it != second_path_g.end(); ++it) {
-            const auto [o_y, o_x] = path_g.back();
-            const auto [y, x] = *it;
+            const auto &[o_y, o_x] = path_g.back();
+            const auto &[y, x] = *it;
             auto d = distance(o_y, o_x, y, x);
             pos_list_map[d].push_back(it);
         }
@@ -550,7 +551,7 @@ void SpellsMirrorMaster::project_super_ray(int target_x, int target_y, int dam)
         rand_shuffle(pos_list.begin(), pos_list.end());
 
         for (const auto &it : pos_list) {
-            const auto [y, x] = *it;
+            const auto &[y, x] = *it;
             res.notice |= activate_super_ray_effect(player_ptr, y, x, dam, flag);
         }
     }
index d8c7df7..0af474f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct ProjectResult;
index e4f94a9..e88d1ba 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/blood-curse.h"
+#include "spell-kind/blood-curse.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
index 711ecc6..27dcb8e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 05e6625..20adc47 100644 (file)
@@ -1,6 +1,4 @@
-#include "spell-kind/earthquake.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "spell-kind/earthquake.h"
 #include "core/window-redrawer.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h"
@@ -36,6 +34,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
@@ -53,7 +52,7 @@
 bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MONSTER_IDX m_idx)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((inside_quest(floor_ptr->quest_number) && QuestType::is_fixed(floor_ptr->quest_number)) || !floor_ptr->dun_level) {
+    if ((floor_ptr->is_in_quest() && QuestType::is_fixed(floor_ptr->quest_number)) || !floor_ptr->dun_level) {
         return false;
     }
 
@@ -61,32 +60,29 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
         r = 12;
     }
 
-    bool map[32][32];
-    for (POSITION y = 0; y < 32; y++) {
-        for (POSITION x = 0; x < 32; x++) {
+    bool map[32][32]{};
+    for (auto y = 0; y < 32; y++) {
+        for (auto x = 0; x < 32; x++) {
             map[y][x] = false;
         }
     }
 
-    int damage = 0;
-    bool hurt = false;
-    for (POSITION dy = -r; dy <= r; dy++) {
-        for (POSITION dx = -r; dx <= r; dx++) {
-            POSITION yy = cy + dy;
-            POSITION xx = cx + dx;
-
-            if (!in_bounds(floor_ptr, yy, xx)) {
+    auto damage = 0;
+    auto hurt = false;
+    for (auto dy = -r; dy <= r; dy++) {
+        for (auto dx = -r; dx <= r; dx++) {
+            const Pos2D pos(cy + dy, cx + dx);
+            if (!in_bounds(floor_ptr, pos.y, pos.x)) {
                 continue;
             }
 
-            if (distance(cy, cx, yy, xx) > r) {
+            if (distance(cy, cx, pos.y, pos.x) > r) {
                 continue;
             }
 
-            grid_type *g_ptr;
-            g_ptr = &floor_ptr->grid_array[yy][xx];
-            g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY | CAVE_UNSAFE);
-            g_ptr->info &= ~(CAVE_GLOW | CAVE_MARK | CAVE_KNOWN);
+            auto &grid = floor_ptr->get_grid(pos);
+            grid.info &= ~(CAVE_ROOM | CAVE_ICKY | CAVE_UNSAFE);
+            grid.info &= ~(CAVE_GLOW | CAVE_MARK | CAVE_KNOWN);
             if (!dx && !dy) {
                 continue;
             }
@@ -95,19 +91,19 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
                 continue;
             }
 
-            map[16 + yy - cy][16 + xx - cx] = true;
-            if (player_bold(player_ptr, yy, xx)) {
+            map[16 + pos.y - cy][16 + pos.x - cx] = true;
+            if (player_ptr->is_located_at(pos)) {
                 hurt = true;
             }
         }
     }
 
-    int sn = 0;
-    POSITION sy = 0, sx = 0;
+    auto sn = 0;
+    Pos2D p_pos_new(0, 0); // 落石を避けた後のプレイヤー座標
     if (hurt && !has_pass_wall(player_ptr) && !has_kill_wall(player_ptr)) {
-        for (DIRECTION i = 0; i < 8; i++) {
-            POSITION y = player_ptr->y + ddy_ddd[i];
-            POSITION x = player_ptr->x + ddx_ddd[i];
+        for (auto i = 0; i < 8; i++) {
+            auto y = player_ptr->y + ddy_ddd[i];
+            auto x = player_ptr->x + ddx_ddd[i];
             if (!is_cave_empty_bold(player_ptr, y, x)) {
                 continue;
             }
@@ -125,51 +121,35 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
                 continue;
             }
 
-            sy = y;
-            sx = x;
+            p_pos_new = { y, x };
         }
 
-        switch (randint1(3)) {
-        case 1: {
-            msg_print(_("ダンジョンの壁が崩れた!", "The dungeon's ceiling collapses!"));
-            break;
-        }
-        case 2: {
-            msg_print(_("ダンジョンの床が不自然にねじ曲がった!", "The dungeon's floor twists in an unnatural way!"));
-            break;
-        }
-        default: {
-            msg_print(_("ダンジョンが揺れた!崩れた岩が頭に降ってきた!", "The dungeon quakes!  You are pummeled with debris!"));
-            break;
-        }
-        }
+        constexpr static auto msgs = {
+            _("ダンジョンの壁が崩れた!", "The dungeon's ceiling collapses!"),
+            _("ダンジョンの床が不自然にねじ曲がった!", "The dungeon's floor twists in an unnatural way!"),
+            _("ダンジョンが揺れた!崩れた岩が頭に降ってきた!", "The dungeon quakes!  You are pummeled with debris!"),
+        };
+        msg_print(rand_choice(msgs));
 
         if (!sn) {
             msg_print(_("あなたはひどい怪我を負った!", "You are severely crushed!"));
             damage = 200;
         } else {
-            BadStatusSetter bss(player_ptr);
-            switch (randint1(3)) {
-            case 1: {
-                msg_print(_("降り注ぐ岩をうまく避けた!", "You nimbly dodge the blast!"));
-                damage = 0;
-                break;
-            }
-            case 2: {
-                msg_print(_("岩石があなたに直撃した!", "You are bashed by rubble!"));
-                damage = damroll(10, 4);
-                (void)bss.mod_stun(randint1(50));
-                break;
-            }
-            case 3: {
-                msg_print(_("あなたは床と壁との間に挟まれてしまった!", "You are crushed between the floor and ceiling!"));
+            constexpr std::array<std::pair<bool, std::string_view>, 3> candidates = { {
+                { false, _("降り注ぐ岩をうまく避けた!", "You nimbly dodge the blast!") },
+                { true, _("岩石があなたに直撃した!", "You are bashed by rubble!") },
+                { true, _("あなたは床と壁との間に挟まれてしまった!", "You are crushed between the floor and ceiling!") },
+            } };
+
+            const auto &[is_damaged, msg] = rand_choice(candidates);
+
+            msg_print(msg);
+            if (is_damaged) {
                 damage = damroll(10, 4);
-                (void)bss.mod_stun(randint1(50));
-                break;
-            }
+                BadStatusSetter(player_ptr).mod_stun(randint1(50));
             }
 
-            (void)move_player_effect(player_ptr, sy, sx, MPE_DONT_PICKUP);
+            (void)move_player_effect(player_ptr, p_pos_new.y, p_pos_new.x, MPE_DONT_PICKUP);
         }
 
         map[16 + player_ptr->y - cy][16 + player_ptr->x - cx] = false;
@@ -184,32 +164,30 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
                 killer = _("地震", "an earthquake");
             }
 
-            take_hit(player_ptr, DAMAGE_ATTACK, damage, killer.data());
+            take_hit(player_ptr, DAMAGE_ATTACK, damage, killer);
         }
     }
 
-    for (POSITION dy = -r; dy <= r; dy++) {
-        for (POSITION dx = -r; dx <= r; dx++) {
-            POSITION yy = cy + dy;
-            POSITION xx = cx + dx;
-            if (!map[16 + yy - cy][16 + xx - cx]) {
+    for (auto dy = -r; dy <= r; dy++) {
+        for (auto dx = -r; dx <= r; dx++) {
+            const Pos2D pos(cy + dy, cx + dx);
+            if (!map[16 + pos.y - cy][16 + pos.x - cx]) {
                 continue;
             }
 
-            grid_type *gg_ptr;
-            gg_ptr = &floor_ptr->grid_array[yy][xx];
-            if (gg_ptr->m_idx == player_ptr->riding) {
+            auto &grid = floor_ptr->get_grid(pos);
+            if (grid.m_idx == player_ptr->riding) {
                 continue;
             }
 
-            if (!gg_ptr->m_idx) {
+            if (!grid.m_idx) {
                 continue;
             }
 
-            auto *m_ptr = &floor_ptr->m_list[gg_ptr->m_idx];
-            auto *r_ptr = &monraces_info[m_ptr->r_idx];
+            auto *m_ptr = &floor_ptr->m_list[grid.m_idx];
+            auto *r_ptr = &m_ptr->get_monrace();
             if (r_ptr->flags1 & RF1_QUESTOR) {
-                map[16 + yy - cy][16 + xx - cx] = false;
+                map[16 + pos.y - cy][16 + pos.x - cx] = false;
                 continue;
             }
 
@@ -220,34 +198,33 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
             sn = 0;
             if (r_ptr->behavior_flags.has_not(MonsterBehaviorType::NEVER_MOVE)) {
                 for (DIRECTION i = 0; i < 8; i++) {
-                    POSITION y = yy + ddy_ddd[i];
-                    POSITION x = xx + ddx_ddd[i];
-                    if (!is_cave_empty_bold(player_ptr, y, x)) {
+                    const Pos2D pos_neighbor(pos.y + ddy_ddd[i], pos.x + ddx_ddd[i]);
+                    if (!is_cave_empty_bold(player_ptr, pos_neighbor.y, pos_neighbor.x)) {
                         continue;
                     }
 
-                    auto *g_ptr = &floor_ptr->grid_array[y][x];
-                    if (g_ptr->is_rune_protection()) {
+                    const auto &grid_neighbor = floor_ptr->get_grid(pos_neighbor);
+                    if (grid_neighbor.is_rune_protection()) {
                         continue;
                     }
 
-                    if (g_ptr->is_rune_explosion()) {
+                    if (grid_neighbor.is_rune_explosion()) {
                         continue;
                     }
 
-                    if (pattern_tile(floor_ptr, y, x)) {
+                    if (pattern_tile(floor_ptr, pos_neighbor.y, pos_neighbor.x)) {
                         continue;
                     }
 
-                    if (map[16 + y - cy][16 + x - cx]) {
+                    if (map[16 + pos_neighbor.y - cy][16 + pos_neighbor.x - cx]) {
                         continue;
                     }
 
-                    if (floor_ptr->grid_array[y][x].m_idx) {
+                    if (grid_neighbor.m_idx) {
                         continue;
                     }
 
-                    if (player_bold(player_ptr, y, x)) {
+                    if (player_ptr->is_located_at(pos)) {
                         continue;
                     }
 
@@ -257,8 +234,7 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
                         continue;
                     }
 
-                    sy = y;
-                    sx = x;
+                    p_pos_new = pos_neighbor;
                 }
             }
 
@@ -268,22 +244,22 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
             }
 
             damage = (sn ? damroll(4, 8) : (m_ptr->hp + 1));
-            (void)set_monster_csleep(player_ptr, gg_ptr->m_idx, 0);
+            (void)set_monster_csleep(player_ptr, grid.m_idx, 0);
             m_ptr->hp -= damage;
             if (m_ptr->hp < 0) {
                 if (!ignore_unview || is_seen(player_ptr, m_ptr)) {
                     msg_format(_("%s^は岩石に埋もれてしまった!", "%s^ is embedded in the rock!"), m_name.data());
                 }
 
-                if (gg_ptr->m_idx) {
-                    const auto &m_ref = floor_ptr->m_list[gg_ptr->m_idx];
+                if (grid.m_idx) {
+                    const auto &m_ref = floor_ptr->m_list[grid.m_idx];
                     if (record_named_pet && m_ref.is_named_pet()) {
                         const auto m2_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-                        exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_EARTHQUAKE, m2_name.data());
+                        exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_EARTHQUAKE, m2_name);
                     }
                 }
 
-                delete_monster(player_ptr, yy, xx);
+                delete_monster(player_ptr, pos.y, pos.x);
                 sn = 0;
             }
 
@@ -291,22 +267,22 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
                 continue;
             }
 
-            IDX m_idx_aux = floor_ptr->grid_array[yy][xx].m_idx;
-            floor_ptr->grid_array[yy][xx].m_idx = 0;
-            floor_ptr->grid_array[sy][sx].m_idx = m_idx_aux;
-            m_ptr->fy = sy;
-            m_ptr->fx = sx;
+            const auto m_idx_aux = grid.m_idx;
+            grid.m_idx = 0;
+            floor_ptr->get_grid(p_pos_new).m_idx = m_idx_aux;
+            m_ptr->fy = p_pos_new.y;
+            m_ptr->fx = p_pos_new.x;
             update_monster(player_ptr, m_idx_aux, true);
-            lite_spot(player_ptr, yy, xx);
-            lite_spot(player_ptr, sy, sx);
+            lite_spot(player_ptr, pos.y, pos.x);
+            lite_spot(player_ptr, p_pos_new.y, p_pos_new.x);
         }
     }
 
     clear_mon_lite(floor_ptr);
-    for (POSITION dy = -r; dy <= r; dy++) {
-        for (POSITION dx = -r; dx <= r; dx++) {
-            POSITION yy = cy + dy;
-            POSITION xx = cx + dx;
+    for (auto dy = -r; dy <= r; dy++) {
+        for (auto dx = -r; dx <= r; dx++) {
+            auto yy = cy + dy;
+            auto xx = cx + dx;
             if (!map[16 + yy - cy][16 + xx - cx]) {
                 continue;
             }
@@ -332,51 +308,68 @@ bool earthquake(PlayerType *player_ptr, POSITION cy, POSITION cx, POSITION r, MO
                 continue;
             }
 
-            cave_set_feat(player_ptr, yy, xx, feat_ground_type[randint0(100)]);
+            cave_set_feat(player_ptr, yy, xx, rand_choice(feat_ground_type));
         }
     }
 
-    for (POSITION dy = -r; dy <= r; dy++) {
-        for (POSITION dx = -r; dx <= r; dx++) {
-            POSITION yy = cy + dy;
-            POSITION xx = cx + dx;
-            if (!in_bounds(floor_ptr, yy, xx)) {
+    for (auto dy = -r; dy <= r; dy++) {
+        for (auto dx = -r; dx <= r; dx++) {
+            const Pos2D pos(cy + dy, cx + dx);
+            if (!in_bounds(floor_ptr, pos.y, pos.x)) {
                 continue;
             }
 
-            if (distance(cy, cx, yy, xx) > r) {
+            if (distance(cy, cx, pos.y, pos.x) > r) {
                 continue;
             }
 
-            auto *g_ptr = &floor_ptr->grid_array[yy][xx];
-            if (g_ptr->is_mirror()) {
-                g_ptr->info |= CAVE_GLOW;
+            auto &grid = floor_ptr->get_grid(pos);
+            if (grid.is_mirror()) {
+                grid.info |= CAVE_GLOW;
                 continue;
             }
 
-            if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+            if (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
                 continue;
             }
 
-            grid_type *cc_ptr;
-            for (DIRECTION ii = 0; ii < 9; ii++) {
-                POSITION yyy = yy + ddy_ddd[ii];
-                POSITION xxx = xx + ddx_ddd[ii];
-                if (!in_bounds2(floor_ptr, yyy, xxx)) {
+            for (auto j = 0; j < 9; j++) {
+                const Pos2D pos_neighbor(pos.y + ddy_ddd[j], pos.x + ddx_ddd[j]);
+                if (!in_bounds2(floor_ptr, pos_neighbor.y, pos_neighbor.x)) {
                     continue;
                 }
-                cc_ptr = &floor_ptr->grid_array[yyy][xxx];
-                if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(TerrainCharacteristics::GLOW)) {
-                    g_ptr->info |= CAVE_GLOW;
+
+                const auto &grid_neighbor = floor_ptr->get_grid(pos_neighbor);
+                if (grid_neighbor.get_terrain_mimic().flags.has(TerrainCharacteristics::GLOW)) {
+                    grid.info |= CAVE_GLOW;
                     break;
                 }
             }
         }
     }
 
-    player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTER_LITE | PU_MONSTER_STATUSES);
-    player_ptr->redraw |= (PR_HEALTH | PR_UHEALTH | PR_MAP);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::UN_VIEW,
+        StatusRecalculatingFlag::UN_LITE,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::FLOW,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::HEALTH,
+        MainWindowRedrawingFlag::UHEALTH,
+        MainWindowRedrawingFlag::MAP,
+    };
+    rfu.set_flags(flags_mwrf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
     if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
         set_superstealth(player_ptr, false);
     }
index 6503e02..aa73301 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d3ae1e9..0868504 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 魔法効果の実装/ Spell code (part 3)
  * @date 2014/07/26
  * @author
@@ -21,6 +21,7 @@
 #include "object/item-tester-hooker.h"
 #include "object/item-use-flags.h"
 #include "player-base/player-class.h"
+#include "system/angband-exceptions.h"
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
  */
 bool recharge(PlayerType *player_ptr, int power)
 {
-    concptr q = _("どのアイテムに魔力を充填しますか? ", "Recharge which item? ");
-    concptr s = _("魔力を充填すべきアイテムがない。", "You have nothing to recharge.");
+    constexpr auto q = _("どのアイテムに魔力を充填しますか? ", "Recharge which item? ");
+    constexpr auto s = _("魔力を充填すべきアイテムがない。", "You have nothing to recharge.");
 
-    OBJECT_IDX item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::can_recharge));
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::can_recharge));
     if (o_ptr == nullptr) {
         return false;
     }
@@ -116,7 +117,7 @@ bool recharge(PlayerType *player_ptr, int power)
     }
 
     if (is_recharge_successful) {
-        return update_player(player_ptr);
+        return update_player();
     }
 
     if (o_ptr->is_fixed_artifact()) {
@@ -127,7 +128,7 @@ bool recharge(PlayerType *player_ptr, int power)
         } else if (o_ptr->is_wand_staff()) {
             o_ptr->pval = 0;
         }
-        return update_player(player_ptr);
+        return update_player();
     }
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
@@ -211,7 +212,7 @@ bool recharge(PlayerType *player_ptr, int power)
             o_ptr->pval = 0;
         }
 
-        vary_item(player_ptr, item, -1);
+        vary_item(player_ptr, i_idx, -1);
         break;
     case 3:
         if (o_ptr->number > 1) {
@@ -220,11 +221,11 @@ bool recharge(PlayerType *player_ptr, int power)
             msg_format(_("乱暴な魔法のために%sが壊れた!", "Wild magic consumes your %s!"), item_name.data());
         }
 
-        vary_item(player_ptr, item, -999);
+        vary_item(player_ptr, i_idx, -999);
         break;
     default:
-        throw std::logic_error("Invalid fail type!");
+        THROW_EXCEPTION(std::logic_error, "Invalid fail type!");
     }
 
-    return update_player(player_ptr);
+    return update_player();
 }
index 14001e4..200640a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool recharge(PlayerType *player_ptr, int power);
index 87ce859..18e9edf 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-beam.h"
+#include "spell-kind/spells-beam.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "spell-kind/spells-launcher.h"
index cd3f525..f74f140 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 4dcec40..98986ea 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-charm.h"
+#include "spell-kind/spells-charm.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "spell-kind/spells-launcher.h"
index 44cf12d..c04057d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3da099d..a5b5e3a 100644 (file)
@@ -1,5 +1,4 @@
-#include "spell-kind/spells-curse-removal.h"
-#include "core/player-update-types.h"
+#include "spell-kind/spells-curse-removal.h"
 #include "core/window-redrawer.h"
 #include "inventory/inventory-slot-types.h"
 #include "object-enchant/item-feeling.h"
@@ -7,6 +6,7 @@
 #include "object-enchant/trc-types.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -19,6 +19,7 @@
 static int exe_curse_removal(PlayerType *player_ptr, int all)
 {
     auto count = 0;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
         auto *o_ptr = &player_ptr->inventory_list[i];
         if (!o_ptr->is_valid() || !o_ptr->is_cursed()) {
@@ -37,9 +38,8 @@ static int exe_curse_removal(PlayerType *player_ptr, int all)
         o_ptr->curse_flags.clear();
         o_ptr->ident |= IDENT_SENSE;
         o_ptr->feeling = FEEL_NONE;
-
-        player_ptr->update |= (PU_BONUS);
-        player_ptr->window_flags |= (PW_EQUIPMENT);
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
+        rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
         count++;
     }
 
index 152bb05..f66c9e5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 int remove_curse(PlayerType *player_ptr);
index 7cb37e8..bfff252 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-detection.h"
+#include "spell-kind/spells-detection.h"
 #include "core/window-redrawer.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "floor/cave.h"
@@ -25,6 +25,7 @@
 #include "system/item-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
  */
 static bool detect_feat_flag(PlayerType *player_ptr, POSITION range, TerrainCharacteristics flag, bool known)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
-    grid_type *g_ptr;
     bool detect = false;
-    for (POSITION y = 1; y < player_ptr->current_floor_ptr->height - 1; y++) {
-        for (POSITION x = 1; x <= player_ptr->current_floor_ptr->width - 1; x++) {
+    for (POSITION y = 1; y < floor.height - 1; y++) {
+        for (POSITION x = 1; x <= floor.width - 1; x++) {
             int dist = distance(player_ptr->y, player_ptr->x, y, x);
             if (dist > range) {
                 continue;
             }
-            g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+
+            auto *g_ptr = &floor.grid_array[y][x];
             if (flag == TerrainCharacteristics::TRAP) {
                 /* Mark as detected */
                 if (dist <= range && known) {
@@ -175,16 +177,17 @@ bool detect_treasure(PlayerType *player_ptr, POSITION range)
  */
 bool detect_objects_gold(PlayerType *player_ptr, POSITION range)
 {
+    auto &floor = *player_ptr->current_floor_ptr;
     POSITION range2 = range;
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range2 /= 3;
     }
 
     /* Scan objects */
     bool detect = false;
     POSITION y, x;
-    for (OBJECT_IDX i = 1; i < player_ptr->current_floor_ptr->o_max; i++) {
-        auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i];
+    for (OBJECT_IDX i = 1; i < floor.o_max; i++) {
+        auto *o_ptr = &floor.o_list[i];
 
         if (!o_ptr->is_valid()) {
             continue;
@@ -228,14 +231,15 @@ bool detect_objects_gold(PlayerType *player_ptr, POSITION range)
  */
 bool detect_objects_normal(PlayerType *player_ptr, POSITION range)
 {
+    auto &floor = *player_ptr->current_floor_ptr;
     POSITION range2 = range;
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range2 /= 3;
     }
 
     bool detect = false;
-    for (OBJECT_IDX i = 1; i < player_ptr->current_floor_ptr->o_max; i++) {
-        auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i];
+    for (OBJECT_IDX i = 1; i < floor.o_max; i++) {
+        auto *o_ptr = &floor.o_list[i];
 
         if (!o_ptr->is_valid()) {
             continue;
@@ -262,7 +266,7 @@ bool detect_objects_normal(PlayerType *player_ptr, POSITION range)
         detect = false;
     }
     if (detect) {
-        player_ptr->window_flags |= PW_FOUND_ITEMS;
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::FOUND_ITEMS);
         msg_print(_("アイテムの存在を感じとった!", "You sense the presence of objects!"));
     }
 
@@ -298,13 +302,14 @@ static bool is_object_magically(const ItemKindType tval)
  */
 bool detect_objects_magic(PlayerType *player_ptr, POSITION range)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
     auto detect = false;
-    for (OBJECT_IDX i = 1; i < player_ptr->current_floor_ptr->o_max; i++) {
-        auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i];
+    for (OBJECT_IDX i = 1; i < floor.o_max; i++) {
+        auto *o_ptr = &floor.o_list[i];
         if (!o_ptr->is_valid() || o_ptr->is_held_by_monster()) {
             continue;
         }
@@ -325,7 +330,7 @@ bool detect_objects_magic(PlayerType *player_ptr, POSITION range)
     }
 
     if (detect) {
-        player_ptr->window_flags |= PW_FOUND_ITEMS;
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::FOUND_ITEMS);
         msg_print(_("魔法のアイテムの存在を感じとった!", "You sense the presence of magic objects!"));
     }
 
@@ -340,14 +345,15 @@ bool detect_objects_magic(PlayerType *player_ptr, POSITION range)
  */
 bool detect_monsters_normal(PlayerType *player_ptr, POSITION range)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
     bool flag = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    for (MONSTER_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
+        auto *r_ptr = &m_ptr->get_monrace();
         if (!m_ptr->is_valid()) {
             continue;
         }
@@ -383,14 +389,16 @@ bool detect_monsters_normal(PlayerType *player_ptr, POSITION range)
  */
 bool detect_monsters_invis(PlayerType *player_ptr, POSITION range)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
-    bool flag = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    auto flag = false;
+    for (MONSTER_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
+        auto *r_ptr = &m_ptr->get_monrace();
 
         if (!m_ptr->is_valid()) {
             continue;
@@ -405,7 +413,7 @@ bool detect_monsters_invis(PlayerType *player_ptr, POSITION range)
 
         if (r_ptr->flags2 & RF2_INVISIBLE) {
             if (player_ptr->monster_race_idx == m_ptr->r_idx) {
-                player_ptr->window_flags |= (PW_MONSTER_LORE);
+                rfu.set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
             }
 
             m_ptr->mflag2.set({ MonsterConstantFlagType::MARK, MonsterConstantFlagType::SHOW });
@@ -432,14 +440,16 @@ bool detect_monsters_invis(PlayerType *player_ptr, POSITION range)
  */
 bool detect_monsters_evil(PlayerType *player_ptr, POSITION range)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
-    bool flag = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    auto flag = false;
+    for (MONSTER_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
+        auto *r_ptr = &m_ptr->get_monrace();
         if (!m_ptr->is_valid()) {
             continue;
         }
@@ -455,7 +465,7 @@ bool detect_monsters_evil(PlayerType *player_ptr, POSITION range)
             if (m_ptr->is_original_ap()) {
                 r_ptr->r_kind_flags.set(MonsterKindType::EVIL);
                 if (player_ptr->monster_race_idx == m_ptr->r_idx) {
-                    player_ptr->window_flags |= (PW_MONSTER_LORE);
+                    rfu.set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
                 }
             }
 
@@ -480,13 +490,15 @@ bool detect_monsters_evil(PlayerType *player_ptr, POSITION range)
  */
 bool detect_monsters_nonliving(PlayerType *player_ptr, POSITION range)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
-    bool flag = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    auto flag = false;
+    for (MONSTER_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
         if (!m_ptr->is_valid()) {
             continue;
         }
@@ -497,9 +509,9 @@ bool detect_monsters_nonliving(PlayerType *player_ptr, POSITION range)
             continue;
         }
 
-        if (!monster_living(m_ptr->r_idx)) {
+        if (!m_ptr->has_living_flag()) {
             if (player_ptr->monster_race_idx == m_ptr->r_idx) {
-                player_ptr->window_flags |= (PW_MONSTER_LORE);
+                rfu.set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
             }
 
             m_ptr->mflag2.set({ MonsterConstantFlagType::MARK, MonsterConstantFlagType::SHOW });
@@ -523,14 +535,16 @@ bool detect_monsters_nonliving(PlayerType *player_ptr, POSITION range)
  */
 bool detect_monsters_mind(PlayerType *player_ptr, POSITION range)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
-    bool flag = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    auto flag = false;
+    for (MONSTER_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
+        auto *r_ptr = &m_ptr->get_monrace();
         if (!m_ptr->is_valid()) {
             continue;
         }
@@ -544,7 +558,7 @@ bool detect_monsters_mind(PlayerType *player_ptr, POSITION range)
 
         if (!(r_ptr->flags2 & RF2_EMPTY_MIND)) {
             if (player_ptr->monster_race_idx == m_ptr->r_idx) {
-                player_ptr->window_flags |= (PW_MONSTER_LORE);
+                rfu.set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
             }
 
             m_ptr->mflag2.set({ MonsterConstantFlagType::MARK, MonsterConstantFlagType::SHOW });
@@ -569,14 +583,16 @@ bool detect_monsters_mind(PlayerType *player_ptr, POSITION range)
  */
 bool detect_monsters_string(PlayerType *player_ptr, POSITION range, concptr Match)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
-    bool flag = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    auto flag = false;
+    for (MONSTER_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
+        auto *r_ptr = &m_ptr->get_monrace();
         if (!m_ptr->is_valid()) {
             continue;
         }
@@ -590,7 +606,7 @@ bool detect_monsters_string(PlayerType *player_ptr, POSITION range, concptr Matc
 
         if (angband_strchr(Match, r_ptr->d_char)) {
             if (player_ptr->monster_race_idx == m_ptr->r_idx) {
-                player_ptr->window_flags |= (PW_MONSTER_LORE);
+                rfu.set_flag(SubWindowRedrawingFlag::MONSTER_LORE);
             }
 
             m_ptr->mflag2.set({ MonsterConstantFlagType::MARK, MonsterConstantFlagType::SHOW });
index 87d5919..1e61d8d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 730f453..9d76a12 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-enchant.h"
+#include "spell-kind/spells-enchant.h"
 #include "artifact/random-art-generator.h"
 #include "avatar/avatar.h"
 #include "flavor/flavor-describer.h"
  */
 bool artifact_scroll(PlayerType *player_ptr)
 {
-    concptr q = _("どのアイテムを強化しますか? ", "Enchant which item? ");
-    concptr s = _("強化できるアイテムがない。", "You have nothing to enchant.");
-    ItemEntity *o_ptr;
-    OBJECT_IDX item;
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), FuncItemTester(object_is_nameless_weapon_armour));
+    constexpr auto q = _("どのアイテムを強化しますか? ", "Enchant which item? ");
+    constexpr auto s = _("強化できるアイテムがない。", "You have nothing to enchant.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), FuncItemTester(object_is_nameless_weapon_armour));
     if (!o_ptr) {
         return false;
     }
@@ -39,7 +38,7 @@ bool artifact_scroll(PlayerType *player_ptr)
 #ifdef JP
     msg_format("%s は眩い光を発した!", item_name.data());
 #else
-    msg_format("%s %s radiate%s a blinding light!", ((item >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
+    msg_format("%s %s radiate%s a blinding light!", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
 #endif
 
     bool okay = false;
@@ -72,10 +71,10 @@ bool artifact_scroll(PlayerType *player_ptr)
             msg_format("%d of your %s %s destroyed!", (o_ptr->number) - 1, item_name.data(), (o_ptr->number > 2 ? "were" : "was"));
 #endif
 
-            if (item >= 0) {
-                inven_item_increase(player_ptr, item, 1 - (o_ptr->number));
+            if (i_idx >= 0) {
+                inven_item_increase(player_ptr, i_idx, 1 - (o_ptr->number));
             } else {
-                floor_item_increase(player_ptr, 0 - item, 1 - (o_ptr->number));
+                floor_item_increase(player_ptr, 0 - i_idx, 1 - (o_ptr->number));
             }
         }
 
@@ -98,7 +97,7 @@ bool artifact_scroll(PlayerType *player_ptr)
 
     if (record_rand_art) {
         const auto diary_item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
-        exe_write_diary(player_ptr, DIARY_ART_SCROLL, 0, diary_item_name.data());
+        exe_write_diary(player_ptr, DiaryKind::ART_SCROLL, 0, diary_item_name);
     }
 
     chg_virtue(player_ptr, Virtue::ENCHANT, 1);
@@ -126,12 +125,10 @@ bool mundane_spell(PlayerType *player_ptr, bool only_equip)
         item_tester = std::make_unique<FuncItemTester>(&ItemEntity::is_weapon_armour_ammo);
     }
 
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
-    concptr q = _("どのアイテムを凡庸化しますか?", "Mundanify which item? ");
-    concptr s = _("凡庸化できるアイテムがない。", "You have nothing to mundanify.");
-
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
+    constexpr auto q = _("どのアイテムを凡庸化しますか?", "Mundanify which item? ");
+    constexpr auto s = _("凡庸化できるアイテムがない。", "You have nothing to mundanify.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
     if (!o_ptr) {
         return false;
     }
index 209eca1..e819e78 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool artifact_scroll(PlayerType *player_ptr);
index fe9c047..ddd3b38 100644 (file)
@@ -1,6 +1,5 @@
-#include "spell-kind/spells-equipment.h"
+#include "spell-kind/spells-equipment.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -10,6 +9,7 @@
 #include "racial/racial-android.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
  */
 bool apply_disenchant(PlayerType *player_ptr, BIT_FLAGS mode)
 {
-    int t = 0;
-    switch (randint1(8)) {
-    case 1:
-        t = INVEN_MAIN_HAND;
-        break;
-    case 2:
-        t = INVEN_SUB_HAND;
-        break;
-    case 3:
-        t = INVEN_BOW;
-        break;
-    case 4:
-        t = INVEN_BODY;
-        break;
-    case 5:
-        t = INVEN_OUTER;
-        break;
-    case 6:
-        t = INVEN_HEAD;
-        break;
-    case 7:
-        t = INVEN_ARMS;
-        break;
-    case 8:
-        t = INVEN_FEET;
-        break;
-    }
+    constexpr static auto candidates = {
+        INVEN_MAIN_HAND,
+        INVEN_SUB_HAND,
+        INVEN_BOW,
+        INVEN_BODY,
+        INVEN_OUTER,
+        INVEN_HEAD,
+        INVEN_ARMS,
+        INVEN_FEET,
+    };
 
-    ItemEntity *o_ptr;
-    o_ptr = &player_ptr->inventory_list[t];
+    const auto t = rand_choice(candidates);
+    auto *o_ptr = &player_ptr->inventory_list[t];
     if (!o_ptr->is_valid()) {
         return false;
     }
@@ -119,9 +102,13 @@ bool apply_disenchant(PlayerType *player_ptr, BIT_FLAGS mode)
 #endif
     chg_virtue(player_ptr, Virtue::HARMONY, 1);
     chg_virtue(player_ptr, Virtue::ENCHANT, -2);
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->window_flags |= (PW_EQUIPMENT | PW_PLAYER);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags);
     calc_android_exp(player_ptr);
     return true;
 }
index 5595c30..ce8e20b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index ccd0b70..0164686 100644 (file)
@@ -1,6 +1,4 @@
-#include "spell-kind/spells-fetcher.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "spell-kind/spells-fetcher.h"
 #include "core/stuff-handler.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "monster/monster-describer.h"
 #include "monster/monster-status-setter.h"
 #include "monster/monster-update.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
 #include "target/target-setter.h"
  */
 void fetch_item(PlayerType *player_ptr, DIRECTION dir, WEIGHT wgt, bool require_los)
 {
-    grid_type *g_ptr;
-    ItemEntity *o_ptr;
-    if (!player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].o_idx_list.empty()) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto p_pos = player_ptr->get_position();
+    if (!floor.get_grid(p_pos).o_idx_list.empty()) {
         msg_print(_("自分の足の下にある物は取れません。", "You can't fetch when you're already standing on something."));
         return;
     }
 
     POSITION ty, tx;
+    Grid *g_ptr;
+    const auto &system = AngbandSystem::get_instance();
     if (dir == 5 && target_okay(player_ptr)) {
         tx = target_col;
         ty = target_row;
-
-        if (distance(player_ptr->y, player_ptr->x, ty, tx) > get_max_range(player_ptr)) {
+        const Pos2D pos(ty, tx);
+        if (distance(p_pos.y, p_pos.x, ty, tx) > system.get_max_range()) {
             msg_print(_("そんなに遠くにある物は取れません!", "You can't fetch something that far away!"));
             return;
         }
 
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[ty][tx];
+        g_ptr = &floor.get_grid(pos);
         if (g_ptr->o_idx_list.empty()) {
             msg_print(_("そこには何もありません。", "There is no object there."));
             return;
@@ -68,32 +70,35 @@ void fetch_item(PlayerType *player_ptr, DIRECTION dir, WEIGHT wgt, bool require_
         }
 
         if (require_los) {
-            if (!player_has_los_bold(player_ptr, ty, tx)) {
+            if (!floor.has_los(pos)) {
                 msg_print(_("そこはあなたの視界に入っていません。", "You have no direct line of sight to that location."));
                 return;
-            } else if (!projectable(player_ptr, player_ptr->y, player_ptr->x, ty, tx)) {
+            } else if (!projectable(player_ptr, p_pos.y, p_pos.x, ty, tx)) {
                 msg_print(_("そこは壁の向こうです。", "You have no direct line of sight to that location."));
                 return;
             }
         }
     } else {
-        ty = player_ptr->y;
-        tx = player_ptr->x;
+        ty = p_pos.y;
+        tx = p_pos.x;
         bool is_first_loop = true;
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[ty][tx];
+        g_ptr = &floor.grid_array[ty][tx];
         while (is_first_loop || g_ptr->o_idx_list.empty()) {
             is_first_loop = false;
             ty += ddy[dir];
             tx += ddx[dir];
-            g_ptr = &player_ptr->current_floor_ptr->grid_array[ty][tx];
+            g_ptr = &floor.grid_array[ty][tx];
+            if ((distance(p_pos.y, p_pos.x, ty, tx) > system.get_max_range())) {
+                return;
+            }
 
-            if ((distance(player_ptr->y, player_ptr->x, ty, tx) > get_max_range(player_ptr)) || !cave_has_flag_bold(player_ptr->current_floor_ptr, ty, tx, TerrainCharacteristics::PROJECT)) {
+            if (!cave_has_flag_bold(&floor, ty, tx, TerrainCharacteristics::PROJECT)) {
                 return;
             }
         }
     }
 
-    o_ptr = &player_ptr->current_floor_ptr->o_list[g_ptr->o_idx_list.front()];
+    auto *o_ptr = &floor.o_list[g_ptr->o_idx_list.front()];
     if (o_ptr->weight > wgt) {
         msg_print(_("そのアイテムは重過ぎます。", "The object is too heavy."));
         return;
@@ -101,14 +106,14 @@ void fetch_item(PlayerType *player_ptr, DIRECTION dir, WEIGHT wgt, bool require_
 
     OBJECT_IDX i = g_ptr->o_idx_list.front();
     g_ptr->o_idx_list.pop_front();
-    player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].o_idx_list.add(player_ptr->current_floor_ptr, i); /* 'move' it */
-    o_ptr->iy = player_ptr->y;
-    o_ptr->ix = player_ptr->x;
+    floor.grid_array[p_pos.y][p_pos.x].o_idx_list.add(&floor, i); /* 'move' it */
+    o_ptr->iy = p_pos.y;
+    o_ptr->ix = p_pos.x;
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
     msg_format(_("%s^があなたの足元に飛んできた。", "%s^ flies through the air to your feet."), item_name.data());
-    note_spot(player_ptr, player_ptr->y, player_ptr->x);
-    player_ptr->redraw |= PR_MAP;
+    note_spot(player_ptr, p_pos.y, p_pos.x);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MAP);
 }
 
 bool fetch_monster(PlayerType *player_ptr)
@@ -117,49 +122,52 @@ bool fetch_monster(PlayerType *player_ptr)
         return false;
     }
 
-    auto m_idx = player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx;
+    auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(target_row, target_col);
+    auto m_idx = floor.get_grid(pos).m_idx;
     if (!m_idx) {
         return false;
     }
     if (m_idx == player_ptr->riding) {
         return false;
     }
-    if (!player_has_los_bold(player_ptr, target_row, target_col)) {
+    if (!floor.has_los(pos)) {
         return false;
     }
     if (!projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
         return false;
     }
 
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    const auto m_name = monster_desc(player_ptr, m_ptr, 0);
+    auto &monster = floor.m_list[m_idx];
+    const auto m_name = monster_desc(player_ptr, &monster, 0);
     msg_format(_("%sを引き戻した。", "You pull back %s."), m_name.data());
-    projection_path path_g(player_ptr, get_max_range(player_ptr), target_row, target_col, player_ptr->y, player_ptr->x, 0);
+    projection_path path_g(player_ptr, AngbandSystem::get_instance().get_max_range(), target_row, target_col, player_ptr->y, player_ptr->x, 0);
     auto ty = target_row, tx = target_col;
     for (const auto &[ny, nx] : path_g) {
-        auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[ny][nx];
+        const Pos2D pos_path(ny, nx);
+        auto *g_ptr = &floor.get_grid(pos_path);
 
-        if (in_bounds(player_ptr->current_floor_ptr, ny, nx) && is_cave_empty_bold(player_ptr, ny, nx) && !g_ptr->is_object() && !pattern_tile(player_ptr->current_floor_ptr, ny, nx)) {
+        if (in_bounds(&floor, ny, nx) && is_cave_empty_bold(player_ptr, ny, nx) && !g_ptr->is_object() && !pattern_tile(&floor, ny, nx)) {
             ty = ny;
             tx = nx;
         }
     }
 
-    player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx = 0;
-    player_ptr->current_floor_ptr->grid_array[ty][tx].m_idx = m_idx;
-    m_ptr->fy = ty;
-    m_ptr->fx = tx;
+    floor.get_grid(pos).m_idx = 0;
+    floor.get_grid({ ty, tx }).m_idx = m_idx;
+    monster.fy = ty;
+    monster.fx = tx;
     (void)set_monster_csleep(player_ptr, m_idx, 0);
     update_monster(player_ptr, m_idx, true);
     lite_spot(player_ptr, target_row, target_col);
     lite_spot(player_ptr, ty, tx);
-    if (monraces_info[m_ptr->r_idx].brightness_flags.has_any_of(ld_mask)) {
-        player_ptr->update |= (PU_MONSTER_LITE);
+    if (monster.get_monrace().brightness_flags.has_any_of(ld_mask)) {
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 
-    if (m_ptr->ml) {
+    if (monster.ml) {
         if (!player_ptr->effects()->hallucination()->is_hallucinated()) {
-            monster_race_track(player_ptr, m_ptr->ap_r_idx);
+            monster_race_track(player_ptr, monster.ap_r_idx);
         }
 
         health_track(player_ptr, m_idx);
index 58de752..6f2f8f8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d93c9b4..ff37684 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief フロアに影響のある魔法の処理
  * @date 2019/02/21
  * @author deskull
@@ -7,8 +7,6 @@
 #include "spell-kind/spells-floor.h"
 #include "action/travel-execution.h"
 #include "cmd-io/cmd-dump.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "dungeon/quest.h"
@@ -52,6 +50,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
@@ -64,8 +63,9 @@
 void wiz_lite(PlayerType *player_ptr, bool ninja)
 {
     /* Memorize objects */
-    for (OBJECT_IDX i = 1; i < player_ptr->current_floor_ptr->o_max; i++) {
-        auto *o_ptr = &player_ptr->current_floor_ptr->o_list[i];
+    auto &floor = *player_ptr->current_floor_ptr;
+    for (OBJECT_IDX i = 1; i < floor.o_max; i++) {
+        auto *o_ptr = &floor.o_list[i];
         if (!o_ptr->is_valid()) {
             continue;
         }
@@ -76,35 +76,35 @@ void wiz_lite(PlayerType *player_ptr, bool ninja)
     }
 
     /* Scan all normal grids */
-    for (POSITION y = 1; y < player_ptr->current_floor_ptr->height - 1; y++) {
+    const auto &terrains = TerrainList::get_instance();
+    for (POSITION y = 1; y < floor.height - 1; y++) {
         /* Scan all normal grids */
-        for (POSITION x = 1; x < player_ptr->current_floor_ptr->width - 1; x++) {
-            auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+        for (POSITION x = 1; x < floor.width - 1; x++) {
+            auto *g_ptr = &floor.grid_array[y][x];
 
             /* Memorize terrain of the grid */
             g_ptr->info |= (CAVE_KNOWN);
 
             /* Feature code (applying "mimic" field) */
             FEAT_IDX feat = g_ptr->get_feat_mimic();
-            TerrainType *f_ptr;
-            f_ptr = &terrains_info[feat];
+            auto *t_ptr = &terrains[feat];
 
             /* Scan all neighbors */
             for (OBJECT_IDX i = 0; i < 9; i++) {
                 POSITION yy = y + ddy_ddd[i];
                 POSITION xx = x + ddx_ddd[i];
-                g_ptr = &player_ptr->current_floor_ptr->grid_array[yy][xx];
+                g_ptr = &floor.grid_array[yy][xx];
 
                 /* Feature code (applying "mimic" field) */
-                f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
+                t_ptr = &terrains[g_ptr->get_feat_mimic()];
 
                 /* Perma-lite the grid */
-                if (dungeons_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::DARKNESS) && !ninja) {
+                if (floor.get_dungeon_definition().flags.has_not(DungeonFeatureType::DARKNESS) && !ninja) {
                     g_ptr->info |= (CAVE_GLOW);
                 }
 
                 /* Memorize normal features */
-                if (f_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
+                if (t_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
                     /* Memorize the grid */
                     g_ptr->info |= (CAVE_MARK);
                 }
@@ -121,11 +121,16 @@ void wiz_lite(PlayerType *player_ptr, bool ninja)
         }
     }
 
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-    player_ptr->redraw |= (PR_MAP);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON | PW_FOUND_ITEMS);
-
-    if (player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
+    if (floor.grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
         set_superstealth(player_ptr, false);
     }
 }
@@ -177,11 +182,23 @@ void wiz_dark(PlayerType *player_ptr)
     /* Forget travel route when we have forgotten map */
     forget_travel_flow(player_ptr->current_floor_ptr);
 
-    player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
-    player_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTER_LITE);
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-    player_ptr->redraw |= (PR_MAP);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON | PW_FOUND_ITEMS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::UN_VIEW,
+        StatusRecalculatingFlag::UN_LITE,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*
@@ -189,44 +206,45 @@ void wiz_dark(PlayerType *player_ptr)
  */
 void map_area(PlayerType *player_ptr, POSITION range)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         range /= 3;
     }
 
     /* Scan that area */
-    for (POSITION y = 1; y < player_ptr->current_floor_ptr->height - 1; y++) {
-        for (POSITION x = 1; x < player_ptr->current_floor_ptr->width - 1; x++) {
+    const auto &terrains = TerrainList::get_instance();
+    for (POSITION y = 1; y < floor.height - 1; y++) {
+        for (POSITION x = 1; x < floor.width - 1; x++) {
             if (distance(player_ptr->y, player_ptr->x, y, x) > range) {
                 continue;
             }
 
-            grid_type *g_ptr;
-            g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+            Grid *g_ptr;
+            g_ptr = &floor.grid_array[y][x];
 
             /* Memorize terrain of the grid */
             g_ptr->info |= (CAVE_KNOWN);
 
             /* Feature code (applying "mimic" field) */
             FEAT_IDX feat = g_ptr->get_feat_mimic();
-            TerrainType *f_ptr;
-            f_ptr = &terrains_info[feat];
+            auto *t_ptr = &terrains[feat];
 
             /* Memorize normal features */
-            if (f_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
+            if (t_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
                 /* Memorize the object */
                 g_ptr->info |= (CAVE_MARK);
             }
 
             /* Memorize known walls */
             for (int i = 0; i < 8; i++) {
-                g_ptr = &player_ptr->current_floor_ptr->grid_array[y + ddy_ddd[i]][x + ddx_ddd[i]];
+                g_ptr = &floor.grid_array[y + ddy_ddd[i]][x + ddx_ddd[i]];
 
                 /* Feature code (applying "mimic" field) */
                 feat = g_ptr->get_feat_mimic();
-                f_ptr = &terrains_info[feat];
+                t_ptr = &terrains[feat];
 
                 /* Memorize walls (etc) */
-                if (f_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
+                if (t_ptr->flags.has(TerrainCharacteristics::REMEMBER)) {
                     /* Memorize the walls */
                     g_ptr->info |= (CAVE_MARK);
                 }
@@ -234,8 +252,13 @@ void map_area(PlayerType *player_ptr, POSITION range)
         }
     }
 
-    player_ptr->redraw |= (PR_MAP);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
@@ -253,50 +276,53 @@ void map_area(PlayerType *player_ptr, POSITION range)
  * "earthquake" by using the "full" to select "destruction".
  * </pre>
  */
-bool destroy_area(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate)
+bool destroy_area(PlayerType *player_ptr, const POSITION y1, const POSITION x1, POSITION r, bool in_generate)
 {
+    const Pos2D pos1(y1, x1);
+
     /* Prevent destruction of quest levels and town */
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((inside_quest(floor_ptr->quest_number) && QuestType::is_fixed(floor_ptr->quest_number)) || !floor_ptr->dun_level) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if ((floor.is_in_quest() && QuestType::is_fixed(floor.quest_number)) || !floor.dun_level) {
         return false;
     }
 
     /* Lose monster light */
     if (!in_generate) {
-        clear_mon_lite(floor_ptr);
+        clear_mon_lite(&floor);
     }
 
     /* Big area of affect */
-    bool flag = false;
-    for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
-        for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
-            if (!in_bounds(floor_ptr, y, x)) {
+    auto flag = false;
+    for (auto y = (y1 - r); y <= (y1 + r); y++) {
+        for (auto x = (x1 - r); x <= (x1 + r); x++) {
+            const Pos2D pos(y, x);
+            if (!in_bounds(&floor, pos.y, pos.x)) {
                 continue;
             }
 
             /* Extract the distance */
-            int k = distance(y1, x1, y, x);
+            auto k = distance(pos1.y, pos1.x, pos.y, pos.x);
 
             /* Stay in the circle of death */
             if (k > r) {
                 continue;
             }
-            grid_type *g_ptr;
-            g_ptr = &floor_ptr->grid_array[y][x];
+
+            auto &grid = floor.get_grid(pos);
 
             /* Lose room and vault */
-            g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
+            grid.info &= ~(CAVE_ROOM | CAVE_ICKY);
 
             /* Lose light and knowledge */
-            g_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
+            grid.info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
 
             if (!in_generate) /* Normal */
             {
                 /* Lose unsafety */
-                g_ptr->info &= ~(CAVE_UNSAFE);
+                grid.info &= ~(CAVE_UNSAFE);
 
                 /* Hack -- Notice player affect */
-                if (player_bold(player_ptr, y, x)) {
+                if (player_ptr->is_located_at(pos)) {
                     /* Hurt the player later */
                     flag = true;
 
@@ -306,63 +332,60 @@ bool destroy_area(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r,
             }
 
             /* Hack -- Skip the epicenter */
-            if ((y == y1) && (x == x1)) {
+            if (pos == pos1) {
                 continue;
             }
 
-            if (g_ptr->m_idx) {
-                auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
-                auto *r_ptr = &monraces_info[m_ptr->r_idx];
+            if (grid.m_idx) {
+                auto &monster = floor.m_list[grid.m_idx];
+                auto &monrace = monster.get_monrace();
 
                 if (in_generate) /* In generation */
                 {
                     /* Delete the monster (if any) */
-                    delete_monster(player_ptr, y, x);
-                } else if (r_ptr->flags1 & RF1_QUESTOR) {
+                    delete_monster(player_ptr, pos.y, pos.x);
+                } else if (monrace.flags1 & RF1_QUESTOR) {
                     /* Heal the monster */
-                    m_ptr->hp = m_ptr->maxhp;
+                    monster.hp = monster.maxhp;
 
                     /* Try to teleport away quest monsters */
-                    if (!teleport_away(player_ptr, g_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR)) {
+                    if (!teleport_away(player_ptr, grid.m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR)) {
                         continue;
                     }
                 } else {
-                    if (record_named_pet && m_ptr->is_named_pet()) {
-                        const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-                        exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name.data());
+                    if (record_named_pet && monster.is_named_pet()) {
+                        const auto m_name = monster_desc(player_ptr, &monster, MD_INDEF_VISIBLE);
+                        exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name);
                     }
 
                     /* Delete the monster (if any) */
-                    delete_monster(player_ptr, y, x);
+                    delete_monster(player_ptr, pos.y, pos.x);
                 }
             }
 
             /* During generation, destroyed artifacts are "preserved" */
             if (preserve_mode || in_generate) {
                 /* Scan all objects in the grid */
-                for (const auto this_o_idx : g_ptr->o_idx_list) {
-                    ItemEntity *o_ptr;
-                    o_ptr = &floor_ptr->o_list[this_o_idx];
-
-                    /* Hack -- Preserve unknown artifacts */
-                    if (o_ptr->is_fixed_artifact() && (!o_ptr->is_known() || in_generate)) {
-                        o_ptr->get_fixed_artifact().is_generated = false;
+                for (const auto this_o_idx : grid.o_idx_list) {
+                    const auto &item = floor.o_list[this_o_idx];
+                    if (item.is_fixed_artifact() && (!item.is_known() || in_generate)) {
+                        item.get_fixed_artifact().is_generated = false;
 
                         if (in_generate && cheat_peek) {
-                            const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_NAME_ONLY | OD_STORE));
+                            const auto item_name = describe_flavor(player_ptr, &item, (OD_NAME_ONLY | OD_STORE));
                             msg_format(_("伝説のアイテム (%s) は生成中に*破壊*された。", "Artifact (%s) was *destroyed* during generation."), item_name.data());
                         }
-                    } else if (in_generate && cheat_peek && o_ptr->is_random_artifact()) {
+                    } else if (in_generate && cheat_peek && item.is_random_artifact()) {
                         msg_print(
                             _("ランダム・アーティファクトの1つは生成中に*破壊*された。", "One of the random artifacts was *destroyed* during generation."));
                     }
                 }
             }
 
-            delete_all_items_from_floor(player_ptr, y, x);
+            delete_all_items_from_floor(player_ptr, pos.y, pos.x);
 
             /* Destroy "non-permanent" grids */
-            if (g_ptr->cave_has_flag(TerrainCharacteristics::PERMANENT)) {
+            if (grid.cave_has_flag(TerrainCharacteristics::PERMANENT)) {
                 continue;
             }
 
@@ -373,16 +396,16 @@ bool destroy_area(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r,
             {
                 if (t < 20) {
                     /* Create granite wall */
-                    cave_set_feat(player_ptr, y, x, feat_granite);
+                    cave_set_feat(player_ptr, pos.y, pos.x, feat_granite);
                 } else if (t < 70) {
                     /* Create quartz vein */
-                    cave_set_feat(player_ptr, y, x, feat_quartz_vein);
+                    cave_set_feat(player_ptr, pos.y, pos.x, feat_quartz_vein);
                 } else if (t < 100) {
                     /* Create magma vein */
-                    cave_set_feat(player_ptr, y, x, feat_magma_vein);
+                    cave_set_feat(player_ptr, pos.y, pos.x, feat_magma_vein);
                 } else {
                     /* Create floor */
-                    cave_set_feat(player_ptr, y, x, feat_ground_type[randint0(100)]);
+                    cave_set_feat(player_ptr, pos.y, pos.x, rand_choice(feat_ground_type));
                 }
 
                 continue;
@@ -390,20 +413,20 @@ bool destroy_area(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r,
 
             if (t < 20) {
                 /* Create granite wall */
-                place_grid(player_ptr, g_ptr, GB_EXTRA);
+                place_grid(player_ptr, &grid, GB_EXTRA);
             } else if (t < 70) {
                 /* Create quartz vein */
-                g_ptr->feat = feat_quartz_vein;
+                grid.feat = feat_quartz_vein;
             } else if (t < 100) {
                 /* Create magma vein */
-                g_ptr->feat = feat_magma_vein;
+                grid.feat = feat_magma_vein;
             } else {
                 /* Create floor */
-                place_grid(player_ptr, g_ptr, GB_FLOOR);
+                place_grid(player_ptr, &grid, GB_FLOOR);
             }
 
             /* Clear garbage of hidden trap or door */
-            g_ptr->mimic = 0;
+            grid.mimic = 0;
         }
     }
 
@@ -412,44 +435,38 @@ bool destroy_area(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r,
     }
 
     /* Process "re-glowing" */
-    for (POSITION y = (y1 - r); y <= (y1 + r); y++) {
-        for (POSITION x = (x1 - r); x <= (x1 + r); x++) {
-            if (!in_bounds(floor_ptr, y, x)) {
+    for (auto y = (y1 - r); y <= (y1 + r); y++) {
+        for (auto x = (x1 - r); x <= (x1 + r); x++) {
+            const Pos2D pos(y, x);
+            if (!in_bounds(&floor, pos.y, pos.x)) {
                 continue;
             }
 
-            /* Extract the distance */
-            int k = distance(y1, x1, y, x);
-
             /* Stay in the circle of death */
+            auto k = distance(y1, x1, pos.y, pos.x);
             if (k > r) {
                 continue;
             }
-            grid_type *g_ptr;
-            g_ptr = &floor_ptr->grid_array[y][x];
 
-            if (g_ptr->is_mirror()) {
-                g_ptr->info |= CAVE_GLOW;
+            auto &grid = floor.get_grid(pos);
+            if (grid.is_mirror()) {
+                grid.info |= CAVE_GLOW;
                 continue;
             }
 
-            if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+            if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
                 continue;
             }
 
-            DIRECTION i;
-            POSITION yy, xx;
-            grid_type *cc_ptr;
-
-            for (i = 0; i < 9; i++) {
-                yy = y + ddy_ddd[i];
-                xx = x + ddx_ddd[i];
-                if (!in_bounds2(floor_ptr, yy, xx)) {
+            for (auto i = 0; i < 9; i++) {
+                const Pos2D pos_neighbor(pos.y + ddy_ddd[i], pos.x + ddx_ddd[i]);
+                if (!in_bounds2(&floor, pos_neighbor.y, pos_neighbor.x)) {
                     continue;
                 }
-                cc_ptr = &floor_ptr->grid_array[yy][xx];
-                if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(TerrainCharacteristics::GLOW)) {
-                    g_ptr->info |= CAVE_GLOW;
+
+                const auto &grid_neighbor = floor.get_grid(pos_neighbor);
+                if (grid_neighbor.get_terrain_mimic().flags.has(TerrainCharacteristics::GLOW)) {
+                    grid.info |= CAVE_GLOW;
                     break;
                 }
             }
@@ -463,14 +480,25 @@ bool destroy_area(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r,
         }
     }
 
-    forget_flow(floor_ptr);
-
-    /* Mega-Hack -- Forget the view and lite */
-    player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTER_LITE | PU_MONSTER_STATUSES);
-    player_ptr->redraw |= (PR_MAP);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
-
-    if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
+    forget_flow(&floor);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::UN_VIEW,
+        StatusRecalculatingFlag::UN_LITE,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::FLOW,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
+    if (floor.grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) {
         set_superstealth(player_ptr, false);
     }
 
index 1a65d9a..c5f0b3e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -6,4 +6,4 @@ class PlayerType;
 void wiz_lite(PlayerType *player_ptr, bool ninja);
 void wiz_dark(PlayerType *player_ptr);
 void map_area(PlayerType *player_ptr, POSITION range);
-bool destroy_area(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate);
+bool destroy_area(PlayerType *player_ptr, const POSITION y1, const POSITION x1, POSITION r, bool in_generate);
index 3c0d745..53eb776 100644 (file)
@@ -1,7 +1,6 @@
-#include "spell-kind/spells-genocide.h"
+#include "spell-kind/spells-genocide.h"
 #include "avatar/avatar.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "dungeon/quest.h"
 #include "io/write-diary.h"
 #include "monster-floor/monster-remover.h"
 #include "monster-race/monster-race.h"
+#include "monster-race/race-flags-resistance.h"
 #include "monster-race/race-flags1.h"
 #include "monster-race/race-flags3.h"
 #include "monster-race/race-flags7.h"
 #include "monster/monster-describer.h"
 #include "monster/monster-description-types.h"
 #include "monster/monster-flag-types.h"
-#include "monster/monster-info.h"
 #include "monster/monster-status-setter.h"
 #include "monster/monster-status.h"
 #include "player/player-damage.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
  */
 bool genocide_aux(PlayerType *player_ptr, MONSTER_IDX m_idx, int power, bool player_cast, int dam_side, concptr spell_name)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
-    if (m_ptr->is_pet() && !player_cast) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &monster = floor.m_list[m_idx];
+    auto &monrace = monster.get_monrace();
+    if (monster.is_pet() && !player_cast) {
         return false;
     }
 
-    bool resist = false;
-    if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(r_ptr->flags1, RF1_QUESTOR)) {
+    auto resist = false;
+    if (monrace.kind_flags.has(MonsterKindType::UNIQUE) || any_bits(monrace.flags1, RF1_QUESTOR)) {
         resist = true;
-    } else if (r_ptr->flags7 & RF7_UNIQUE2) {
+    } else if (monrace.resistance_flags.has(MonsterResistanceType::NO_INSTANTLY_DEATH)) {
+        monrace.r_resistance_flags.set(MonsterResistanceType::NO_INSTANTLY_DEATH);
         resist = true;
     } else if (m_idx == player_ptr->riding) {
         resist = true;
-    } else if ((inside_quest(player_ptr->current_floor_ptr->quest_number) && !inside_quest(random_quest_number(player_ptr, player_ptr->current_floor_ptr->dun_level))) || player_ptr->current_floor_ptr->inside_arena || player_ptr->phase_out) {
+    } else if (floor.is_special()) {
         resist = true;
-    } else if (player_cast && (r_ptr->level > randint0(power))) {
+    } else if (player_cast && (monrace.level > randint0(power))) {
         resist = true;
-    } else if (player_cast && m_ptr->mflag2.has(MonsterConstantFlagType::NOGENO)) {
+    } else if (player_cast && monster.mflag2.has(MonsterConstantFlagType::NOGENO)) {
         resist = true;
     } else {
-        if (record_named_pet && m_ptr->is_named_pet()) {
-            const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-            exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_GENOCIDE, m_name.data());
+        if (record_named_pet && monster.is_named_pet()) {
+            const auto m_name = monster_desc(player_ptr, &monster, MD_INDEF_VISIBLE);
+            exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_GENOCIDE, m_name);
         }
 
         delete_monster_idx(player_ptr, m_idx);
     }
 
     if (resist && player_cast) {
-        bool see_m = is_seen(player_ptr, m_ptr);
-        const auto m_name = monster_desc(player_ptr, m_ptr, 0);
+        const auto see_m = is_seen(player_ptr, &monster);
+        const auto m_name = monster_desc(player_ptr, &monster, 0);
         if (see_m) {
             msg_format(_("%s^には効果がなかった。", "%s^ is unaffected."), m_name.data());
         }
 
-        if (m_ptr->is_asleep()) {
+        if (monster.is_asleep()) {
             (void)set_monster_csleep(player_ptr, m_idx, 0);
-            if (m_ptr->ml) {
+            if (monster.ml) {
                 msg_format(_("%s^が目を覚ました。", "%s^ wakes up."), m_name.data());
             }
         }
 
-        if (m_ptr->is_friendly() && !m_ptr->is_pet()) {
+        if (monster.is_friendly() && !monster.is_pet()) {
             if (see_m) {
                 msg_format(_("%sは怒った!", "%s^ gets angry!"), m_name.data());
             }
 
-            set_hostile(player_ptr, m_ptr);
+            monster.set_hostile();
         }
 
         if (one_in_(13)) {
-            m_ptr->mflag2.set(MonsterConstantFlagType::NOGENO);
+            monster.mflag2.set(MonsterConstantFlagType::NOGENO);
         }
     }
 
     if (player_cast) {
-        take_hit(player_ptr, DAMAGE_GENO, randint1(dam_side), format(_("%s^の呪文を唱えた疲労", "the strain of casting %s^"), spell_name).data());
+        take_hit(player_ptr, DAMAGE_GENO, randint1(dam_side), format(_("%s^の呪文を唱えた疲労", "the strain of casting %s^"), spell_name));
     }
 
     move_cursor_relative(player_ptr->y, player_ptr->x);
-    player_ptr->redraw |= (PR_HP);
-    player_ptr->window_flags |= (PW_PLAYER);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::HP);
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
     handle_stuff(player_ptr);
     term_fresh();
-
     term_xtra(TERM_XTRA_DELAY, delay_factor);
-
     return !resist;
 }
 
@@ -120,39 +122,43 @@ bool genocide_aux(PlayerType *player_ptr, MONSTER_IDX m_idx, int power, bool pla
  */
 bool symbol_genocide(PlayerType *player_ptr, int power, bool player_cast)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    bool is_special_floor = inside_quest(floor_ptr->quest_number) && !inside_quest(random_quest_number(player_ptr, floor_ptr->dun_level));
-    is_special_floor |= player_ptr->current_floor_ptr->inside_arena;
-    is_special_floor |= player_ptr->phase_out;
+    auto &floor = *player_ptr->current_floor_ptr;
+    bool is_special_floor = floor.is_in_quest() && !inside_quest(floor.get_random_quest_id());
+    is_special_floor |= floor.inside_arena;
+    is_special_floor |= AngbandSystem::get_instance().is_phase_out();
     if (is_special_floor) {
         msg_print(_("何も起きないようだ……", "Nothing seems to happen..."));
         return false;
     }
 
-    char typ;
-    while (!get_com(_("どの種類(文字)のモンスターを抹殺しますか: ", "Choose a monster race (by symbol) to genocide: "), &typ, false)) {
-        ;
-    }
-    bool result = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
-        if (!m_ptr->is_valid()) {
-            continue;
+    constexpr auto prompt = _("どの種類(文字)のモンスターを抹殺しますか: ", "Choose a monster race (by symbol) to genocide: ");
+    char symbol;
+    while (true) {
+        const auto command = input_command(prompt);
+        if (command) {
+            symbol = *command;
+            break;
         }
-        if (r_ptr->d_char != typ) {
+    }
+
+    auto result = false;
+    for (short i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
+        auto *r_ptr = &m_ptr->get_monrace();
+        if (!m_ptr->is_valid() || (r_ptr->d_char != symbol)) {
             continue;
         }
 
         result |= genocide_aux(player_ptr, i, power, player_cast, 4, _("抹殺", "Genocide"));
     }
 
-    if (result) {
-        chg_virtue(player_ptr, Virtue::VITALITY, -2);
-        chg_virtue(player_ptr, Virtue::CHANCE, -1);
+    if (!result) {
+        return false;
     }
 
-    return result;
+    chg_virtue(player_ptr, Virtue::VITALITY, -2);
+    chg_virtue(player_ptr, Virtue::CHANCE, -1);
+    return true;
 }
 
 /*!
@@ -163,17 +169,17 @@ bool symbol_genocide(PlayerType *player_ptr, int power, bool player_cast)
  */
 bool mass_genocide(PlayerType *player_ptr, int power, bool player_cast)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    bool is_special_floor = inside_quest(floor_ptr->quest_number) && !inside_quest(random_quest_number(player_ptr, floor_ptr->dun_level));
-    is_special_floor |= player_ptr->current_floor_ptr->inside_arena;
-    is_special_floor |= player_ptr->phase_out;
+    auto &floor = *player_ptr->current_floor_ptr;
+    bool is_special_floor = floor.is_in_quest() && !inside_quest(floor.get_random_quest_id());
+    is_special_floor |= floor.inside_arena;
+    is_special_floor |= AngbandSystem::get_instance().is_phase_out();
     if (is_special_floor) {
         return false;
     }
 
     bool result = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
+    for (MONSTER_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
         if (!m_ptr->is_valid()) {
             continue;
         }
@@ -200,18 +206,18 @@ bool mass_genocide(PlayerType *player_ptr, int power, bool player_cast)
  */
 bool mass_genocide_undead(PlayerType *player_ptr, int power, bool player_cast)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    bool is_special_floor = inside_quest(floor_ptr->quest_number) && !inside_quest(random_quest_number(player_ptr, floor_ptr->dun_level));
-    is_special_floor |= player_ptr->current_floor_ptr->inside_arena;
-    is_special_floor |= player_ptr->phase_out;
+    auto &floor = *player_ptr->current_floor_ptr;
+    bool is_special_floor = floor.is_in_quest() && !inside_quest(floor.get_random_quest_id());
+    is_special_floor |= floor.inside_arena;
+    is_special_floor |= AngbandSystem::get_instance().is_phase_out();
     if (is_special_floor) {
         return false;
     }
 
     bool result = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    for (MONSTER_IDX i = 1; i < floor.m_max; i++) {
+        auto *m_ptr = &floor.m_list[i];
+        auto *r_ptr = &m_ptr->get_monrace();
         if (!m_ptr->is_valid()) {
             continue;
         }
index 744b271..507e62d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f2e9362..1ecdfbc 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-grid.h"
+#include "spell-kind/spells-grid.h"
 #include "dungeon/quest.h"
 #include "floor/cave.h"
 #include "floor/floor-object.h"
@@ -8,6 +8,7 @@
 #include "grid/feature.h"
 #include "grid/grid.h"
 #include "grid/stair.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -70,17 +71,17 @@ void stair_creation(PlayerType *player_ptr)
     }
 
     bool down = true;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (inside_quest(quest_number(player_ptr, floor_ptr->dun_level)) || (floor_ptr->dun_level >= dungeons_info[player_ptr->dungeon_idx].maxdepth)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (inside_quest(floor.get_quest_id()) || (floor.dun_level >= floor.get_dungeon_definition().maxdepth)) {
         down = false;
     }
 
-    if (!floor_ptr->dun_level || (!up && !down) || (inside_quest(floor_ptr->quest_number) && QuestType::is_fixed(floor_ptr->quest_number)) || floor_ptr->inside_arena || player_ptr->phase_out) {
+    if (!floor.dun_level || (!up && !down) || (floor.is_in_quest() && QuestType::is_fixed(floor.quest_number)) || floor.inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         msg_print(_("効果がありません!", "There is no effect!"));
         return;
     }
 
-    if (!cave_valid_bold(floor_ptr, player_ptr->y, player_ptr->x)) {
+    if (!cave_valid_bold(&floor, player_ptr->y, player_ptr->x)) {
         msg_print(_("床上のアイテムが呪文を跳ね返した。", "The object resists the spell."));
         return;
     }
@@ -113,9 +114,9 @@ void stair_creation(PlayerType *player_ptr)
     }
 
     if (dest_floor_id) {
-        for (POSITION y = 0; y < floor_ptr->height; y++) {
-            for (POSITION x = 0; x < floor_ptr->width; x++) {
-                auto *g_ptr = &floor_ptr->grid_array[y][x];
+        for (POSITION y = 0; y < floor.height; y++) {
+            for (POSITION x = 0; x < floor.width; x++) {
+                auto *g_ptr = &floor.grid_array[y][x];
                 if (!g_ptr->special) {
                     continue;
                 }
@@ -128,7 +129,7 @@ void stair_creation(PlayerType *player_ptr)
 
                 /* Remove old stairs */
                 g_ptr->special = 0;
-                cave_set_feat(player_ptr, y, x, feat_ground_type[randint0(100)]);
+                cave_set_feat(player_ptr, y, x, rand_choice(feat_ground_type));
             }
         }
     } else {
@@ -144,13 +145,13 @@ void stair_creation(PlayerType *player_ptr)
     dest_sf_ptr = get_sf_ptr(dest_floor_id);
     if (up) {
         cave_set_feat(player_ptr, player_ptr->y, player_ptr->x,
-            (dest_sf_ptr->last_visit && (dest_sf_ptr->dun_level <= floor_ptr->dun_level - 2)) ? feat_state(player_ptr->current_floor_ptr, feat_up_stair, TerrainCharacteristics::SHAFT)
-                                                                                              : feat_up_stair);
+            (dest_sf_ptr->last_visit && (dest_sf_ptr->dun_level <= floor.dun_level - 2)) ? feat_state(&floor, feat_up_stair, TerrainCharacteristics::SHAFT)
+                                                                                         : feat_up_stair);
     } else {
         cave_set_feat(player_ptr, player_ptr->y, player_ptr->x,
-            (dest_sf_ptr->last_visit && (dest_sf_ptr->dun_level >= floor_ptr->dun_level + 2)) ? feat_state(player_ptr->current_floor_ptr, feat_down_stair, TerrainCharacteristics::SHAFT)
-                                                                                              : feat_down_stair);
+            (dest_sf_ptr->last_visit && (dest_sf_ptr->dun_level >= floor.dun_level + 2)) ? feat_state(&floor, feat_down_stair, TerrainCharacteristics::SHAFT)
+                                                                                         : feat_down_stair);
     }
 
-    floor_ptr->grid_array[player_ptr->y][player_ptr->x].special = dest_floor_id;
+    floor.grid_array[player_ptr->y][player_ptr->x].special = dest_floor_id;
 }
index b3471a3..9612be4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 46fdad5..7905359 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-launcher.h"
+#include "spell-kind/spells-launcher.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
 #include "floor/geometry.h"
index 2ae7b2a..11c8b32 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index 31bb236..b4a7c90 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-lite.h"
+#include "spell-kind/spells-lite.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
@@ -17,6 +17,7 @@
 #include "monster/monster-update.h"
 #include "player/special-defense-types.h"
 #include "spell-kind/spells-launcher.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -65,7 +66,7 @@ static void cave_temp_room_lite(PlayerType *player_ptr, const std::vector<Pos2D>
         if (g_ptr->m_idx) {
             PERCENTAGE chance = 25;
             auto *m_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
-            auto *r_ptr = &monraces_info[m_ptr->r_idx];
+            auto *r_ptr = &m_ptr->get_monrace();
             update_monster(player_ptr, g_ptr->m_idx, false);
             if (r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID)) {
                 chance = 10;
@@ -92,42 +93,30 @@ static void cave_temp_room_lite(PlayerType *player_ptr, const std::vector<Pos2D>
 /*!
  * @brief 指定した座標全てを暗くする。
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param points 暗くすべき座標たち
- * @details
- * <pre>
- * This routine clears the entire "temp" set.
- * This routine will "darken" all "temp" grids.
- * In addition, some of these grids will be "unmarked".
- * This routine is used (only) by "unlite_room()"
- * Also, process all affected monsters
- * </pre>
- * @todo この辺、xとyが引数になっているが、player_ptr->xとplayer_ptr->yで全て置き換えが効くはず……
+ * @param points 暗くすべき座標群
  */
 static void cave_temp_room_unlite(PlayerType *player_ptr, const std::vector<Pos2D> &points)
 {
+    auto &floor = *player_ptr->current_floor_ptr;
     for (const auto &point : points) {
-        const POSITION y = point.y;
-        const POSITION x = point.x;
-
-        auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-        bool do_dark = !g_ptr->is_mirror();
-        g_ptr->info &= ~(CAVE_TEMP);
+        auto &grid = floor.get_grid(point);
+        auto do_dark = !grid.is_mirror();
+        grid.info &= ~(CAVE_TEMP);
         if (!do_dark) {
             continue;
         }
 
-        if (player_ptr->current_floor_ptr->dun_level || !is_daytime()) {
+        if (floor.dun_level || !w_ptr->is_daytime()) {
             for (int j = 0; j < 9; j++) {
-                POSITION by = y + ddy_ddd[j];
-                POSITION bx = x + ddx_ddd[j];
-
-                if (in_bounds2(player_ptr->current_floor_ptr, by, bx)) {
-                    grid_type *cc_ptr = &player_ptr->current_floor_ptr->grid_array[by][bx];
+                const Pos2D pos_neighbor(point.y + ddy_ddd[j], point.x + ddx_ddd[j]);
+                if (!in_bounds2(&floor, pos_neighbor.y, pos_neighbor.x)) {
+                    continue;
+                }
 
-                    if (terrains_info[cc_ptr->get_feat_mimic()].flags.has(TerrainCharacteristics::GLOW)) {
-                        do_dark = false;
-                        break;
-                    }
+                const auto &grid_neighbor = floor.get_grid(pos_neighbor);
+                if (grid_neighbor.get_terrain_mimic().flags.has(TerrainCharacteristics::GLOW)) {
+                    do_dark = false;
+                    break;
                 }
             }
 
@@ -136,20 +125,20 @@ static void cave_temp_room_unlite(PlayerType *player_ptr, const std::vector<Pos2
             }
         }
 
-        g_ptr->info &= ~(CAVE_GLOW);
-        if (terrains_info[g_ptr->get_feat_mimic()].flags.has_not(TerrainCharacteristics::REMEMBER)) {
+        grid.info &= ~(CAVE_GLOW);
+        if (grid.get_terrain_mimic().flags.has_not(TerrainCharacteristics::REMEMBER)) {
             if (!view_torch_grids) {
-                g_ptr->info &= ~(CAVE_MARK);
+                grid.info &= ~(CAVE_MARK);
             }
-            note_spot(player_ptr, y, x);
+            note_spot(player_ptr, point.y, point.x);
         }
 
-        if (g_ptr->m_idx) {
-            update_monster(player_ptr, g_ptr->m_idx, false);
+        if (grid.m_idx) {
+            update_monster(player_ptr, grid.m_idx, false);
         }
 
-        lite_spot(player_ptr, y, x);
-        update_local_illumination(player_ptr, y, x);
+        lite_spot(player_ptr, point.y, point.x);
+        update_local_illumination(player_ptr, point.y, point.x);
     }
 }
 
@@ -233,7 +222,7 @@ static void cave_temp_room_aux(
         if (!in_bounds2(floor_ptr, y, x)) {
             return;
         }
-        if (distance(player_ptr->y, player_ptr->x, y, x) > get_max_range(player_ptr)) {
+        if (distance(player_ptr->y, player_ptr->x, y, x) > AngbandSystem::get_instance().get_max_range()) {
             return;
         }
 
@@ -391,23 +380,24 @@ bool starlight(PlayerType *player_ptr, bool magic)
     }
 
     int num = damroll(5, 3);
-    int attempts;
-    POSITION y = 0, x = 0;
+    auto y = 0;
+    auto x = 0;
     for (int k = 0; k < num; k++) {
-        attempts = 1000;
-
+        auto attempts = 1000;
         while (attempts--) {
             scatter(player_ptr, &y, &x, player_ptr->y, player_ptr->x, 4, PROJECT_LOS);
-            if (!cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
+            const Pos2D pos(y, x);
+            if (!cave_has_flag_bold(player_ptr->current_floor_ptr, pos.y, pos.x, TerrainCharacteristics::PROJECT)) {
                 continue;
             }
-            if (!player_bold(player_ptr, y, x)) {
+
+            if (!player_ptr->is_located_at(pos)) {
                 break;
             }
         }
 
-        project(player_ptr, 0, 0, y, x, damroll(6 + player_ptr->lev / 8, 10), AttributeType::LITE_WEAK,
-            (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_KILL | PROJECT_LOS));
+        constexpr uint flags = PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_KILL | PROJECT_LOS;
+        project(player_ptr, 0, 0, y, x, damroll(6 + player_ptr->lev / 8, 10), AttributeType::LITE_WEAK, flags);
     }
 
     return true;
@@ -422,7 +412,7 @@ bool starlight(PlayerType *player_ptr, bool magic)
  */
 bool lite_area(PlayerType *player_ptr, int dam, POSITION rad)
 {
-    if (dungeons_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
+    if (player_ptr->current_floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
         msg_print(_("ダンジョンが光を吸収した。", "The darkness of this dungeon absorbs your light."));
         return false;
     }
index a0ed340..d3347a0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 1d65974..95bc56b 100644 (file)
@@ -1,6 +1,4 @@
-#include "spell-kind/spells-neighbor.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "spell-kind/spells-neighbor.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
@@ -10,6 +8,7 @@
 #include "grid/grid.h"
 #include "spell-kind/earthquake.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 
 /*!
@@ -67,8 +66,9 @@ bool wall_stone(PlayerType *player_ptr)
 {
     BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
     bool dummy = project(player_ptr, 0, 1, player_ptr->y, player_ptr->x, 0, AttributeType::STONE_WALL, flg).notice;
-    player_ptr->update |= (PU_FLOW);
-    player_ptr->redraw |= (PR_MAP);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::FLOW);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
     return dummy;
 }
 
@@ -125,22 +125,24 @@ bool animate_dead(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSITION
  */
 void wall_breaker(PlayerType *player_ptr)
 {
-    POSITION y = 0, x = 0;
-    int attempts = 1000;
+    auto y = 0;
+    auto x = 0;
+    auto attempts = 1000;
     if (randint1(80 + player_ptr->lev) < 70) {
         while (attempts--) {
             scatter(player_ptr, &y, &x, player_ptr->y, player_ptr->x, 4, PROJECT_NONE);
-
             if (!cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
                 continue;
             }
 
-            if (!player_bold(player_ptr, y, x)) {
+            const Pos2D pos(y, x);
+            if (!player_ptr->is_located_at(pos)) {
                 break;
             }
         }
 
-        project(player_ptr, 0, 0, y, x, 20 + randint1(30), AttributeType::KILL_WALL, (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL));
+        constexpr auto flags = PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+        project(player_ptr, 0, 0, y, x, 20 + randint1(30), AttributeType::KILL_WALL, flags);
         return;
     }
 
@@ -153,12 +155,13 @@ void wall_breaker(PlayerType *player_ptr)
     for (int i = 0; i < num; i++) {
         while (true) {
             scatter(player_ptr, &y, &x, player_ptr->y, player_ptr->x, 10, PROJECT_NONE);
-
-            if (!player_bold(player_ptr, y, x)) {
+            const Pos2D pos(y, x);
+            if (!player_ptr->is_located_at(pos)) {
                 break;
             }
         }
 
-        project(player_ptr, 0, 0, y, x, 20 + randint1(30), AttributeType::KILL_WALL, (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL));
+        constexpr auto flags = PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+        project(player_ptr, 0, 0, y, x, 20 + randint1(30), AttributeType::KILL_WALL, flags);
     }
 }
index 4db70ac..11a0c1a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e23aedf..44e54de 100644 (file)
@@ -1,7 +1,6 @@
-#include "spell-kind/spells-perception.h"
+#include "spell-kind/spells-perception.h"
 #include "autopick/autopick.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
@@ -24,6 +23,7 @@
 #include "perception/object-perception.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
@@ -67,22 +67,34 @@ bool identify_item(PlayerType *player_ptr, ItemEntity *o_ptr)
     }
 
     object_aware(player_ptr, o_ptr);
-    object_known(o_ptr);
+    o_ptr->mark_as_known();
     o_ptr->marked.set(OmType::TOUCHED);
 
-    set_bits(player_ptr->update, PU_BONUS | PU_COMBINATION | PU_REORDER);
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
-
-    angband_strcpy(record_o_name, known_item_name.data(), MAX_NLEN);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
+    angband_strcpy(record_o_name, known_item_name, MAX_NLEN);
     record_turn = w_ptr->game_turn;
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
     if (record_fix_art && !old_known && o_ptr->is_fixed_artifact()) {
-        exe_write_diary(player_ptr, DIARY_ART, 0, item_name.data());
+        exe_write_diary(player_ptr, DiaryKind::ART, 0, item_name);
     }
 
     if (record_rand_art && !old_known && o_ptr->is_random_artifact()) {
-        exe_write_diary(player_ptr, DIARY_ART, 0, item_name.data());
+        exe_write_diary(player_ptr, DiaryKind::ART, 0, item_name);
     }
 
     return old_known;
@@ -114,26 +126,25 @@ bool ident_spell(PlayerType *player_ptr, bool only_equip)
         q = _("すべて鑑定済みです。 ", "All items are identified. ");
     }
 
-    concptr s = _("鑑定するべきアイテムがない。", "You have nothing to identify.");
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
+    constexpr auto s = _("鑑定するべきアイテムがない。", "You have nothing to identify.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
     if (!o_ptr) {
         return false;
     }
 
-    bool old_known = identify_item(player_ptr, o_ptr);
+    auto old_known = identify_item(player_ptr, o_ptr);
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
-    if (item >= INVEN_MAIN_HAND) {
-        msg_format(_("%s^: %s(%c)。", "%s^: %s (%c)."), describe_use(player_ptr, item), item_name.data(), index_to_label(item));
-    } else if (item >= 0) {
-        msg_format(_("ザック中: %s(%c)。", "In your pack: %s (%c)."), item_name.data(), index_to_label(item));
+    if (i_idx >= INVEN_MAIN_HAND) {
+        msg_format(_("%s^: %s(%c)。", "%s^: %s (%c)."), describe_use(player_ptr, i_idx), item_name.data(), index_to_label(i_idx));
+    } else if (i_idx >= 0) {
+        msg_format(_("ザック中: %s(%c)。", "In your pack: %s (%c)."), item_name.data(), index_to_label(i_idx));
     } else {
         msg_format(_("床上: %s。", "On the ground: %s."), item_name.data());
     }
 
-    autopick_alter_item(player_ptr, item, (bool)(destroy_identify && !old_known));
+    autopick_alter_item(player_ptr, i_idx, (bool)(destroy_identify && !old_known));
     return true;
 }
 
@@ -163,34 +174,30 @@ bool identify_fully(PlayerType *player_ptr, bool only_equip)
         q = _("すべて*鑑定*済みです。 ", "All items are *identified*. ");
     }
 
-    concptr s = _("*鑑定*するべきアイテムがない。", "You have nothing to *identify*.");
+    constexpr auto s = _("*鑑定*するべきアイテムがない。", "You have nothing to *identify*.");
 
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT), *item_tester);
     if (!o_ptr) {
         return false;
     }
 
-    bool old_known = identify_item(player_ptr, o_ptr);
+    auto old_known = identify_item(player_ptr, o_ptr);
 
     o_ptr->ident |= (IDENT_FULL_KNOWN);
 
-    /* Refrect item informaiton onto subwindows without updating inventory */
-    player_ptr->update &= ~(PU_COMBINATION | PU_REORDER);
-    handle_stuff(player_ptr);
-    player_ptr->update |= (PU_COMBINATION | PU_REORDER);
+    window_stuff(player_ptr);
 
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
-    if (item >= INVEN_MAIN_HAND) {
-        msg_format(_("%s^: %s(%c)。", "%s^: %s (%c)."), describe_use(player_ptr, item), item_name.data(), index_to_label(item));
-    } else if (item >= 0) {
-        msg_format(_("ザック中: %s(%c)。", "In your pack: %s (%c)."), item_name.data(), index_to_label(item));
+    if (i_idx >= INVEN_MAIN_HAND) {
+        msg_format(_("%s^: %s(%c)。", "%s^: %s (%c)."), describe_use(player_ptr, i_idx), item_name.data(), index_to_label(i_idx));
+    } else if (i_idx >= 0) {
+        msg_format(_("ザック中: %s(%c)。", "In your pack: %s (%c)."), item_name.data(), index_to_label(i_idx));
     } else {
         msg_format(_("床上: %s。", "On the ground: %s."), item_name.data());
     }
 
     (void)screen_object(player_ptr, o_ptr, 0L);
-    autopick_alter_item(player_ptr, item, (bool)(destroy_identify && !old_known));
+    autopick_alter_item(player_ptr, i_idx, (bool)(destroy_identify && !old_known));
     return true;
 }
index 9982962..8ec9c3d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3d7371b..038f204 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-pet.h"
+#include "spell-kind/spells-pet.h"
 #include "core/asking-player.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
@@ -35,7 +35,7 @@ void discharge_minion(PlayerType *player_ptr)
     }
 
     if (!okay || player_ptr->riding) {
-        if (!get_check(_("本当に全ペットを爆破しますか?", "You will blast all pets. Are you sure? "))) {
+        if (!input_check(_("本当に全ペットを爆破しますか?", "You will blast all pets. Are you sure? "))) {
             return;
         }
     }
@@ -47,7 +47,7 @@ void discharge_minion(PlayerType *player_ptr)
         }
 
         MonsterRaceInfo *r_ptr;
-        r_ptr = &monraces_info[m_ptr->r_idx];
+        r_ptr = &m_ptr->get_monrace();
         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
             const auto m_name = monster_desc(player_ptr, m_ptr, 0x00);
             msg_format(_("%sは爆破されるのを嫌がり、勝手に自分の世界へと帰った。", "%s^ resists being blasted and runs away."), m_name.data());
@@ -69,7 +69,7 @@ void discharge_minion(PlayerType *player_ptr)
 
         if (record_named_pet && m_ptr->is_named()) {
             const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-            exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_BLAST, m_name.data());
+            exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_BLAST, m_name);
         }
 
         delete_monster_idx(player_ptr, i);
index 4c3cfc6..3eb7bbe 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void discharge_minion(PlayerType *player_ptr);
index 899234d..d56991c 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-polymorph.h"
+#include "spell-kind/spells-polymorph.h"
 #include "core/stuff-handler.h"
 #include "floor/floor-object.h"
 #include "monster-floor/monster-generator.h"
@@ -11,6 +11,7 @@
 #include "monster/monster-list.h"
 #include "monster/monster-status.h"
 #include "monster/monster-util.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
@@ -40,7 +41,7 @@ static MonsterRaceId poly_r_idx(PlayerType *player_ptr, MonsterRaceId r_idx)
     DEPTH lev2 = r_ptr->level + ((randint1(20) / randint1(9)) + 1);
     MonsterRaceId r;
     for (int i = 0; i < 1000; i++) {
-        r = get_mon_num(player_ptr, 0, (player_ptr->current_floor_ptr->dun_level + r_ptr->level) / 2 + 5, 0);
+        r = get_mon_num(player_ptr, 0, (player_ptr->current_floor_ptr->dun_level + r_ptr->level) / 2 + 5, PM_NONE);
         if (!MonsterRace(r).is_valid()) {
             break;
         }
@@ -78,7 +79,7 @@ bool polymorph_monster(PlayerType *player_ptr, POSITION y, POSITION x)
     bool targeted = target_who == g_ptr->m_idx;
     bool health_tracked = player_ptr->health_who == g_ptr->m_idx;
 
-    if (floor_ptr->inside_arena || player_ptr->phase_out) {
+    if (floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         return false;
     }
     if ((player_ptr->riding == g_ptr->m_idx) || m_ptr->mflag2.has(MonsterConstantFlagType::KAGE)) {
@@ -107,13 +108,13 @@ bool polymorph_monster(PlayerType *player_ptr, POSITION y, POSITION x)
     m_ptr->hold_o_idx_list.clear();
     delete_monster_idx(player_ptr, g_ptr->m_idx);
     bool polymorphed = false;
-    if (place_monster_aux(player_ptr, 0, y, x, new_r_idx, mode)) {
+    if (place_specific_monster(player_ptr, 0, y, x, new_r_idx, mode)) {
         floor_ptr->m_list[hack_m_idx_ii].nickname = back_m.nickname;
         floor_ptr->m_list[hack_m_idx_ii].parent_m_idx = back_m.parent_m_idx;
         floor_ptr->m_list[hack_m_idx_ii].hold_o_idx_list = back_m.hold_o_idx_list;
         polymorphed = true;
     } else {
-        if (place_monster_aux(player_ptr, 0, y, x, old_r_idx, (mode | PM_NO_KAGE | PM_IGNORE_TERRAIN))) {
+        if (place_specific_monster(player_ptr, 0, y, x, old_r_idx, (mode | PM_NO_KAGE | PM_IGNORE_TERRAIN))) {
             floor_ptr->m_list[hack_m_idx_ii] = back_m;
             mproc_init(floor_ptr);
         } else {
index 0d457ba..39b0f15 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index af6ffa5..5d41789 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ダイス目により様々な効果を及ぼす魔法の処理
  * @date 2020/06/05
  * @author Hourier
  */
 void call_chaos(PlayerType *player_ptr)
 {
-    AttributeType hurt_types[32] = { AttributeType::ELEC, AttributeType::POIS, AttributeType::ACID, AttributeType::COLD, AttributeType::FIRE,
+    constexpr static auto hurt_types = { AttributeType::ELEC, AttributeType::POIS, AttributeType::ACID, AttributeType::COLD, AttributeType::FIRE,
         AttributeType::MISSILE, AttributeType::PLASMA, AttributeType::HOLY_FIRE, AttributeType::WATER, AttributeType::LITE,
         AttributeType::DARK, AttributeType::FORCE, AttributeType::INERTIAL, AttributeType::MANA, AttributeType::METEOR, AttributeType::ICE,
         AttributeType::CHAOS, AttributeType::NETHER, AttributeType::DISENCHANT, AttributeType::SHARDS, AttributeType::SOUND, AttributeType::NEXUS,
         AttributeType::CONFUSION, AttributeType::TIME, AttributeType::GRAVITY, AttributeType::ROCKET, AttributeType::NUKE, AttributeType::HELL_FIRE,
         AttributeType::DISINTEGRATE, AttributeType::PSY_SPEAR, AttributeType::VOID_MAGIC, AttributeType::ABYSS };
 
-    AttributeType chaos_type = hurt_types[randint0(32)];
+    const auto chaos_type = rand_choice(hurt_types);
     bool line_chaos = false;
     if (one_in_(4)) {
         line_chaos = true;
index fc23170..3662d78 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 2a1c0a5..9bb7fd1 100644 (file)
@@ -1,12 +1,10 @@
-#include "spell-kind/spells-sight.h"
+#include "spell-kind/spells-sight.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
-#include "floor/cave.h"
 #include "game-option/birth-options.h"
 #include "game-option/map-screen-options.h"
 #include "grid/grid.h"
@@ -28,6 +26,7 @@
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "term/screen-processor.h"
 #include "view/display-messages.h"
  */
 bool project_all_los(PlayerType *player_ptr, AttributeType typ, int dam)
 {
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        if (!m_ptr->is_valid()) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    for (short i = 1; i < floor.m_max; i++) {
+        auto &monster = floor.m_list[i];
+        if (!monster.is_valid()) {
             continue;
         }
 
-        POSITION y = m_ptr->fy;
-        POSITION x = m_ptr->fx;
-        if (!player_has_los_bold(player_ptr, y, x) || !projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
+        auto y = monster.fy;
+        auto x = monster.fx;
+        if (!floor.has_los({ y, x }) || !projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
             continue;
         }
 
-        m_ptr->mflag.set(MonsterTemporaryFlagType::LOS);
+        monster.mflag.set(MonsterTemporaryFlagType::LOS);
     }
 
     BIT_FLAGS flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE;
-    bool obvious = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        if (m_ptr->mflag.has_not(MonsterTemporaryFlagType::LOS)) {
+    auto obvious = false;
+    for (short i = 1; i < floor.m_max; i++) {
+        auto &monster = floor.m_list[i];
+        if (monster.mflag.has_not(MonsterTemporaryFlagType::LOS)) {
             continue;
         }
 
-        m_ptr->mflag.reset(MonsterTemporaryFlagType::LOS);
-        POSITION y = m_ptr->fy;
-        POSITION x = m_ptr->fx;
+        monster.mflag.reset(MonsterTemporaryFlagType::LOS);
+        auto y = monster.fy;
+        auto x = monster.fx;
 
         if (project(player_ptr, 0, 0, y, x, dam, typ, flg).notice) {
             obvious = true;
@@ -216,33 +216,32 @@ bool crusade(PlayerType *player_ptr)
  */
 void aggravate_monsters(PlayerType *player_ptr, MONSTER_IDX who)
 {
-    bool sleep = false;
-    bool speed = false;
-    for (MONSTER_IDX i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        if (!m_ptr->is_valid()) {
+    auto sleep = false;
+    auto speed = false;
+    auto &floor = *player_ptr->current_floor_ptr;
+    for (short i = 1; i < floor.m_max; i++) {
+        auto &monster = floor.m_list[i];
+        if (!monster.is_valid()) {
             continue;
         }
         if (i == who) {
             continue;
         }
 
-        if (m_ptr->cdis < MAX_PLAYER_SIGHT * 2) {
-            if (m_ptr->is_asleep()) {
+        if (monster.cdis < MAX_PLAYER_SIGHT * 2) {
+            if (monster.is_asleep()) {
                 (void)set_monster_csleep(player_ptr, i, 0);
                 sleep = true;
             }
 
-            if (!m_ptr->is_pet()) {
-                m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
+            if (!monster.is_pet()) {
+                monster.mflag2.set(MonsterConstantFlagType::NOPET);
             }
         }
 
-        if (player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx)) {
-            if (!m_ptr->is_pet()) {
-                (void)set_monster_fast(player_ptr, i, m_ptr->get_remaining_acceleration() + 100);
-                speed = true;
-            }
+        if (floor.has_los({ monster.fy, monster.fx }) && !monster.is_pet()) {
+            (void)set_monster_fast(player_ptr, i, monster.get_remaining_acceleration() + 100);
+            speed = true;
         }
     }
 
@@ -251,8 +250,9 @@ void aggravate_monsters(PlayerType *player_ptr, MONSTER_IDX who)
     } else if (sleep) {
         msg_print(_("何かが突如興奮したような騒々しい音が遠くに聞こえた!", "You hear a sudden stirring in the distance!"));
     }
+
     if (player_ptr->riding) {
-        player_ptr->update |= PU_BONUS;
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     }
 }
 
@@ -403,8 +403,8 @@ std::string probed_monster_info(PlayerType *player_ptr, MonsterEntity *m_ptr, Mo
     }
 
     const auto speed = m_ptr->get_temporary_speed() - STANDARD_SPEED;
-    std::string result = format(_("%s ... 属性:%s HP:%d/%d AC:%d 速度:%s%d 経験:", "%s ... align:%s HP:%d/%d AC:%d speed:%s%d exp:"), m_name.data(), align, (int)m_ptr->hp,
-        (int)m_ptr->maxhp, r_ptr->ac, (speed > 0) ? "+" : "", speed);
+    constexpr auto mes = _("%s ... 属性:%s HP:%d/%d AC:%d 速度:%s%d 経験:", "%s ... align:%s HP:%d/%d AC:%d speed:%s%d exp:");
+    auto result = format(mes, m_name.data(), align, (int)m_ptr->hp, (int)m_ptr->maxhp, r_ptr->ac, (speed > 0) ? "+" : "", speed);
 
     if (MonsterRace(r_ptr->next_r_idx).is_valid()) {
         result.append(format("%d/%d ", m_ptr->exp, r_ptr->next_exp));
@@ -441,17 +441,19 @@ bool probing(PlayerType *player_ptr)
     game_term->scr->cu = 0;
     game_term->scr->cv = 1;
 
-    bool probe = false;
-    for (int i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
-        if (!m_ptr->is_valid()) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    auto probe = false;
+    for (short i = 1; i < floor.m_max; i++) {
+        auto &monster = floor.m_list[i];
+        auto &monrace = monster.get_monrace();
+        if (!monster.is_valid()) {
             continue;
         }
-        if (!player_has_los_bold(player_ptr, m_ptr->fy, m_ptr->fx)) {
+        if (!floor.has_los({ monster.fy, monster.fx })) {
             continue;
         }
-        if (!m_ptr->ml) {
+        if (!monster.ml) {
             continue;
         }
 
@@ -460,22 +462,22 @@ bool probing(PlayerType *player_ptr)
         }
         msg_print(nullptr);
 
-        const auto probe_result = probed_monster_info(player_ptr, m_ptr, r_ptr);
-        prt(probe_result.data(), 0, 0);
+        const auto probe_result = probed_monster_info(player_ptr, &monster, &monrace);
+        prt(probe_result, 0, 0);
 
         message_add(probe_result);
-        player_ptr->window_flags |= (PW_MESSAGE);
+        rfu.set_flag(SubWindowRedrawingFlag::MESSAGE);
         handle_stuff(player_ptr);
-        move_cursor_relative(m_ptr->fy, m_ptr->fx);
+        move_cursor_relative(monster.fy, monster.fx);
         inkey();
-        term_erase(0, 0, 255);
-        if (lore_do_probe(player_ptr, m_ptr->r_idx)) {
+        term_erase(0, 0);
+        if (lore_do_probe(player_ptr, monster.r_idx)) {
 #ifdef JP
-            msg_format("%sについてさらに詳しくなった気がする。", r_ptr->name.data());
+            msg_format("%sについてさらに詳しくなった気がする。", monrace.name.data());
 #else
-            std::string nm = r_ptr->name;
+            std::string nm = monrace.name;
             /* Leave room for making it plural. */
-            nm.resize(r_ptr->name.length() + 16);
+            nm.resize(monrace.name.length() + 16);
             plural_aux(nm.data());
             msg_format("You now know more about %s.", nm.data());
 #endif
index 76eb392..7d051fe 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index 02d2950..5d3dee1 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-kind/spells-specific-bolt.h"
+#include "spell-kind/spells-specific-bolt.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "spell-kind/spells-launcher.h"
index 7f43302..662b5f2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 37d54a2..a2e290c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief テレポート魔法全般
  * @date 2020/06/04
  * @author Hourier
@@ -7,8 +7,8 @@
 #include "spell-kind/spells-teleport.h"
 #include "avatar/avatar.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
+#include "dungeon/quest.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "floor/cave.h"
 #include "monster/monster-update.h"
 #include "mutation/mutation-flag-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-class.h"
 #include "player/player-move.h"
 #include "player/player-status.h"
 #include "spell-kind/spells-launcher.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/grid-selector.h"
 #include "target/target-checker.h"
 #include "util/bit-flags-calculator.h"
@@ -69,7 +70,7 @@ bool teleport_swap(PlayerType *player_ptr, DIRECTION dir)
         return false;
     }
 
-    grid_type *g_ptr;
+    Grid *g_ptr;
     g_ptr = &player_ptr->current_floor_ptr->grid_array[ty][tx];
     if (!g_ptr->m_idx || (g_ptr->m_idx == player_ptr->riding)) {
         msg_print(_("それとは場所を交換できません。", "You can't trade places with that!"));
@@ -84,7 +85,7 @@ bool teleport_swap(PlayerType *player_ptr, DIRECTION dir)
     MonsterEntity *m_ptr;
     MonsterRaceInfo *r_ptr;
     m_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
-    r_ptr = &monraces_info[m_ptr->r_idx];
+    r_ptr = &m_ptr->get_monrace();
 
     (void)set_monster_csleep(player_ptr, g_ptr->m_idx, 0);
 
@@ -165,7 +166,7 @@ bool teleport_away(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION dis, tele
             if (!cave_monster_teleportable_bold(player_ptr, m_idx, ny, nx, mode)) {
                 continue;
             }
-            if (!(inside_quest(player_ptr->current_floor_ptr->quest_number) || player_ptr->current_floor_ptr->inside_arena)) {
+            if (!(player_ptr->current_floor_ptr->is_in_quest() || player_ptr->current_floor_ptr->inside_arena)) {
                 if (player_ptr->current_floor_ptr->grid_array[ny][nx].is_icky()) {
                     continue;
                 }
@@ -195,8 +196,8 @@ bool teleport_away(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION dis, tele
     lite_spot(player_ptr, oy, ox);
     lite_spot(player_ptr, ny, nx);
 
-    if (monraces_info[m_ptr->r_idx].brightness_flags.has_any_of(ld_mask)) {
-        player_ptr->update |= (PU_MONSTER_LITE);
+    if (m_ptr->get_monrace().brightness_flags.has_any_of(ld_mask)) {
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 
     return true;
@@ -276,8 +277,8 @@ void teleport_monster_to(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION ty,
     lite_spot(player_ptr, oy, ox);
     lite_spot(player_ptr, ny, nx);
 
-    if (monraces_info[m_ptr->r_idx].brightness_flags.has_any_of(ld_mask)) {
-        player_ptr->update |= (PU_MONSTER_LITE);
+    if (m_ptr->get_monrace().brightness_flags.has_any_of(ld_mask)) {
+        RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
     }
 }
 
@@ -360,15 +361,15 @@ bool teleport_player_aux(PlayerType *player_ptr, POSITION dis, bool is_quantum_e
     auto pick = randint1(cur_candidates);
 
     /* Search again the choosen location */
-    auto yy = top;
-    auto xx = 0;
-    for (; yy <= bottom; yy++) {
-        for (xx = left; xx <= right; xx++) {
-            if (!cave_player_teleportable_bold(player_ptr, yy, xx, mode)) {
+    auto y = top;
+    auto x = 0;
+    for (; y <= bottom; y++) {
+        for (x = left; x <= right; x++) {
+            if (!cave_player_teleportable_bold(player_ptr, yx, mode)) {
                 continue;
             }
 
-            int d = distance(player_ptr->y, player_ptr->x, yy, xx);
+            int d = distance(player_ptr->y, player_ptr->x, yx);
             if (d > dis) {
                 continue;
             }
@@ -387,7 +388,8 @@ bool teleport_player_aux(PlayerType *player_ptr, POSITION dis, bool is_quantum_e
         }
     }
 
-    if (player_bold(player_ptr, yy, xx)) {
+    const Pos2D pos(y, x);
+    if (player_ptr->is_located_at(pos)) {
         return false;
     }
 
@@ -397,7 +399,7 @@ bool teleport_player_aux(PlayerType *player_ptr, POSITION dis, bool is_quantum_e
         msg_format("『こっちだぁ、%s』", player_ptr->name);
     }
 #endif
-    (void)move_player_effect(player_ptr, yy, xx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
+    (void)move_player_effect(player_ptr, pos.y, pos.x, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
     return true;
 }
 
@@ -422,7 +424,7 @@ void teleport_player(PlayerType *player_ptr, POSITION dis, BIT_FLAGS mode)
             MONSTER_IDX tmp_m_idx = player_ptr->current_floor_ptr->grid_array[oy + yy][ox + xx].m_idx;
             if (tmp_m_idx && (player_ptr->riding != tmp_m_idx)) {
                 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[tmp_m_idx];
-                auto *r_ptr = &monraces_info[m_ptr->r_idx];
+                auto *r_ptr = &m_ptr->get_monrace();
 
                 bool can_follow = r_ptr->ability_flags.has(MonsterAbilityType::TPORT);
                 can_follow &= r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_TELEPORT);
@@ -444,7 +446,7 @@ void teleport_player(PlayerType *player_ptr, POSITION dis, BIT_FLAGS mode)
  */
 void teleport_player_away(MONSTER_IDX m_idx, PlayerType *player_ptr, POSITION dis, bool is_quantum_effect)
 {
-    if (player_ptr->phase_out) {
+    if (AngbandSystem::get_instance().is_phase_out()) {
         return;
     }
 
@@ -467,7 +469,7 @@ void teleport_player_away(MONSTER_IDX m_idx, PlayerType *player_ptr, POSITION di
             }
 
             auto *m_ptr = &player_ptr->current_floor_ptr->m_list[tmp_m_idx];
-            auto *r_ptr = &monraces_info[m_ptr->r_idx];
+            auto *r_ptr = &m_ptr->get_monrace();
 
             bool can_follow = r_ptr->ability_flags.has(MonsterAbilityType::TPORT);
             can_follow &= r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_TELEPORT);
@@ -545,7 +547,7 @@ void teleport_away_followable(PlayerType *player_ptr, MONSTER_IDX m_idx)
     bool is_followable = old_ml;
     is_followable &= old_cdis <= MAX_PLAYER_SIGHT;
     is_followable &= w_ptr->timewalk_m_idx == 0;
-    is_followable &= !player_ptr->phase_out;
+    is_followable &= !AngbandSystem::get_instance().is_phase_out();
     is_followable &= los(player_ptr, player_ptr->y, player_ptr->x, oldfy, oldfx);
     if (!is_followable) {
         return;
@@ -560,12 +562,9 @@ void teleport_away_followable(PlayerType *player_ptr, MONSTER_IDX m_idx)
 
         for (i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
             o_ptr = &player_ptr->inventory_list[i];
-            if (o_ptr->is_valid() && !o_ptr->is_cursed()) {
-                auto flags = object_flags(o_ptr);
-                if (flags.has(TR_TELEPORT)) {
-                    follow = true;
-                    break;
-                }
+            if (o_ptr->is_valid() && !o_ptr->is_cursed() && o_ptr->get_flags().has(TR_TELEPORT)) {
+                follow = true;
+                break;
             }
         }
     }
@@ -573,7 +572,7 @@ void teleport_away_followable(PlayerType *player_ptr, MONSTER_IDX m_idx)
     if (!follow) {
         return;
     }
-    if (!get_check_strict(player_ptr, _("ついていきますか?", "Do you follow it? "), CHECK_OKAY_CANCEL)) {
+    if (!input_check_strict(player_ptr, _("ついていきますか?", "Do you follow it? "), UserCheck::OKAY_CANCEL)) {
         return;
     }
 
@@ -600,8 +599,10 @@ bool exe_dimension_door(PlayerType *player_ptr, POSITION x, POSITION y)
     PLAYER_LEVEL plev = player_ptr->lev;
 
     player_ptr->energy_need += (int16_t)((int32_t)(60 - plev) * ENERGY_NEED() / 100L);
-
-    if (!cave_player_teleportable_bold(player_ptr, y, x, TELEPORT_SPONTANEOUS) || (distance(y, x, player_ptr->y, player_ptr->x) > plev / 2 + 10) || (!randint0(plev / 10 + 10))) {
+    auto is_successful = cave_player_teleportable_bold(player_ptr, y, x, TELEPORT_SPONTANEOUS);
+    is_successful &= distance(y, x, player_ptr->y, player_ptr->x) <= plev / 2 + 10;
+    is_successful &= !one_in_(plev / 10 + 10);
+    if (!is_successful) {
         player_ptr->energy_need += (int16_t)((int32_t)(60 - plev) * ENERGY_NEED() / 100L);
         teleport_player(player_ptr, (plev + 2) * 2, TELEPORT_PASSIVE);
         return false;
index 43c46df..bfeeba4 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 1296bac..c4f740d 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 帰還やテレポート・レベル等、フロアを跨ぐ魔法効果の処理
  * @author Hourier
  * @date 2022/10/10
@@ -7,9 +7,7 @@
 #include "spell-kind/spells-world.h"
 #include "cmd-io/cmd-save.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "dungeon/quest-completion-checker.h"
-#include "floor/cave.h"
 #include "floor/floor-mode-changer.h"
 #include "floor/floor-town.h"
 #include "floor/geometry.h"
 #include "monster-race/race-flags1.h"
 #include "monster/monster-describer.h"
 #include "monster/monster-description-types.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
 #include "target/target-setter.h"
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
 #include "world/world.h"
-
-/*!
- * @brief テレポート・レベルが効かないモンスターであるかどうかを判定する
- * @param player_ptr プレイヤーへの参照ポインタ
- * @param idx テレポート・レベル対象のモンスター
- * @todo 変数名が実態と合っているかどうかは要確認
- */
-bool is_teleport_level_ineffective(PlayerType *player_ptr, MONSTER_IDX idx)
-{
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    bool is_special_floor = floor_ptr->inside_arena || player_ptr->phase_out || (inside_quest(floor_ptr->quest_number) && !inside_quest(random_quest_number(player_ptr, floor_ptr->dun_level)));
-    bool is_invalid_floor = idx <= 0;
-    is_invalid_floor &= inside_quest(quest_number(player_ptr, floor_ptr->dun_level)) || (floor_ptr->dun_level >= dungeons_info[player_ptr->dungeon_idx].maxdepth);
-    is_invalid_floor &= player_ptr->current_floor_ptr->dun_level >= 1;
-    is_invalid_floor &= ironman_downward;
-    return is_special_floor || is_invalid_floor;
-}
+#include <algorithm>
 
 /*!
  * @brief プレイヤー及びモンスターをレベルテレポートさせる /
@@ -71,16 +55,16 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
 {
     std::string m_name;
     auto see_m = true;
-    auto &floor_ref = *player_ptr->current_floor_ptr;
+    auto &floor = *player_ptr->current_floor_ptr;
     if (m_idx <= 0) {
         m_name = _("あなた", "you");
     } else {
-        auto *m_ptr = &floor_ref.m_list[m_idx];
+        auto *m_ptr = &floor.m_list[m_idx];
         m_name = monster_desc(player_ptr, m_ptr, 0);
         see_m = is_seen(player_ptr, m_ptr);
     }
 
-    if (is_teleport_level_ineffective(player_ptr, m_idx)) {
+    if (floor.can_teleport_level(m_idx != 0)) {
         if (see_m) {
             msg_print(_("効果がなかった。", "There is no effect."));
         }
@@ -100,14 +84,15 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
     }
 
     if ((m_idx <= 0) && w_ptr->wizard) {
-        if (get_check("Force to go up? ")) {
+        if (input_check("Force to go up? ")) {
             go_up = true;
-        } else if (get_check("Force to go down? ")) {
+        } else if (input_check("Force to go down? ")) {
             go_up = false;
         }
     }
 
-    if ((ironman_downward && (m_idx <= 0)) || (floor_ref.dun_level <= dungeons_info[player_ptr->dungeon_idx].mindepth)) {
+    const auto &dungeon = floor.get_dungeon_definition();
+    if ((ironman_downward && (m_idx <= 0)) || (floor.dun_level <= dungeon.mindepth)) {
 #ifdef JP
         if (see_m) {
             msg_format("%s^は床を突き破って沈んでいく。", m_name.data());
@@ -118,22 +103,23 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
         }
 #endif
         if (m_idx <= 0) {
-            if (!floor_ref.is_in_dungeon()) {
-                player_ptr->dungeon_idx = ironman_downward ? DUNGEON_ANGBAND : player_ptr->recall_dungeon;
+            if (!floor.is_in_dungeon()) {
+                floor.set_dungeon_index(ironman_downward ? DUNGEON_ANGBAND : player_ptr->recall_dungeon);
                 player_ptr->oldpy = player_ptr->y;
                 player_ptr->oldpx = player_ptr->x;
             }
 
             if (record_stair) {
-                exe_write_diary(player_ptr, DIARY_TELEPORT_LEVEL, 1, nullptr);
+                exe_write_diary(player_ptr, DiaryKind::TELEPORT_LEVEL, 1);
             }
 
             if (autosave_l) {
                 do_cmd_save_game(player_ptr, true);
             }
 
-            if (!floor_ref.is_in_dungeon()) {
-                floor_ref.dun_level = dungeons_info[player_ptr->dungeon_idx].mindepth;
+            if (!floor.is_in_dungeon()) {
+                const auto &recall_dungeon = floor.get_dungeon_definition();
+                floor.dun_level = recall_dungeon.mindepth;
                 prepare_change_floor_mode(player_ptr, CFM_RAND_PLACE);
             } else {
                 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT);
@@ -141,7 +127,7 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
 
             player_ptr->leaving = true;
         }
-    } else if (inside_quest(quest_number(player_ptr, floor_ref.dun_level)) || (floor_ref.dun_level >= dungeons_info[player_ptr->dungeon_idx].maxdepth)) {
+    } else if (inside_quest(floor.get_quest_id()) || (floor.dun_level >= dungeon.maxdepth)) {
 #ifdef JP
         if (see_m) {
             msg_format("%s^は天井を突き破って宙へ浮いていく。", m_name.data());
@@ -154,7 +140,7 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
 
         if (m_idx <= 0) {
             if (record_stair) {
-                exe_write_diary(player_ptr, DIARY_TELEPORT_LEVEL, -1, nullptr);
+                exe_write_diary(player_ptr, DiaryKind::TELEPORT_LEVEL, -1);
             }
 
             if (autosave_l) {
@@ -164,7 +150,7 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
             prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_UP | CFM_RAND_PLACE | CFM_RAND_CONNECT);
 
             leave_quest_check(player_ptr);
-            floor_ref.quest_number = QuestId::NONE;
+            floor.quest_number = QuestId::NONE;
             player_ptr->leaving = true;
         }
     } else if (go_up) {
@@ -180,7 +166,7 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
 
         if (m_idx <= 0) {
             if (record_stair) {
-                exe_write_diary(player_ptr, DIARY_TELEPORT_LEVEL, -1, nullptr);
+                exe_write_diary(player_ptr, DiaryKind::TELEPORT_LEVEL, -1);
             }
 
             if (autosave_l) {
@@ -203,7 +189,7 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
 
         if (m_idx <= 0) {
             if (record_stair) {
-                exe_write_diary(player_ptr, DIARY_TELEPORT_LEVEL, 1, nullptr);
+                exe_write_diary(player_ptr, DiaryKind::TELEPORT_LEVEL, 1);
             }
             if (autosave_l) {
                 do_cmd_save_game(player_ptr, true);
@@ -219,11 +205,11 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx)
         return;
     }
 
-    auto *m_ptr = &floor_ref.m_list[m_idx];
+    auto *m_ptr = &floor.m_list[m_idx];
     QuestCompletionChecker(player_ptr, m_ptr).complete();
     if (record_named_pet && m_ptr->is_named_pet()) {
         const auto m2_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-        exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_TELE_LEVEL, m2_name.data());
+        exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_TELE_LEVEL, m2_name);
     }
 
     delete_monster_idx(player_ptr, m_idx);
@@ -237,27 +223,28 @@ bool teleport_level_other(PlayerType *player_ptr)
     if (!target_set(player_ptr, TARGET_KILL)) {
         return false;
     }
-    MONSTER_IDX target_m_idx = player_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx;
+
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(target_row, target_col);
+    const auto &grid = floor.get_grid(pos);
+    const auto target_m_idx = grid.m_idx;
     if (!target_m_idx) {
         return true;
     }
-    if (!player_has_los_bold(player_ptr, target_row, target_col)) {
+    if (!grid.has_los()) {
         return true;
     }
     if (!projectable(player_ptr, player_ptr->y, player_ptr->x, target_row, target_col)) {
         return true;
     }
 
-    MonsterEntity *m_ptr;
-    MonsterRaceInfo *r_ptr;
-    m_ptr = &player_ptr->current_floor_ptr->m_list[target_m_idx];
-    r_ptr = &monraces_info[m_ptr->r_idx];
-    const auto m_name = monster_desc(player_ptr, m_ptr, 0);
+    const auto &monster = floor.m_list[target_m_idx];
+    const auto &monrace = monster.get_monrace();
+    const auto m_name = monster_desc(player_ptr, &monster, 0);
     msg_format(_("%s^の足を指さした。", "You gesture at %s^'s feet."), m_name.data());
 
-    auto has_immune = r_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_NEXUS_MASK) || r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT);
-
-    if (has_immune || (r_ptr->flags1 & RF1_QUESTOR) || (r_ptr->level + randint1(50) > player_ptr->lev + randint1(60))) {
+    auto has_immune = monrace.resistance_flags.has_any_of(RFR_EFF_RESIST_NEXUS_MASK) || monrace.resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT);
+    if (has_immune || (monrace.flags1 & RF1_QUESTOR) || (monrace.level + randint1(50) > player_ptr->lev + randint1(60))) {
         msg_print(_("しかし効果がなかった!", format("%s^ is unaffected!", m_name.data())));
     } else {
         teleport_level(player_ptr, target_m_idx);
@@ -278,7 +265,7 @@ bool tele_town(PlayerType *player_ptr)
         return false;
     }
 
-    if (player_ptr->current_floor_ptr->inside_arena || player_ptr->phase_out) {
+    if (player_ptr->current_floor_ptr->inside_arena || AngbandSystem::get_instance().is_phase_out()) {
         msg_print(_("この魔法は外でしか使えない!", "This spell can only be used outside!"));
         return false;
     }
@@ -295,7 +282,7 @@ bool tele_town(PlayerType *player_ptr)
             continue;
         }
 
-        strnfmt(buf, sizeof(buf), "%c) %-20s", I2A(i - 1), towns_info[i].name);
+        strnfmt(buf, sizeof(buf), "%c) %-20s", I2A(i - 1), towns_info[i].name.data());
         prt(buf, 5 + i, 5);
         num++;
     }
@@ -339,7 +326,6 @@ bool tele_town(PlayerType *player_ptr)
     }
 
     player_ptr->leaving = true;
-    player_ptr->leave_bldg = true;
     player_ptr->teleport_town = true;
     screen_load();
     return true;
@@ -356,16 +342,17 @@ void reserve_alter_reality(PlayerType *player_ptr, TIME_EFFECT turns)
         return;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->alter_reality || turns == 0) {
         player_ptr->alter_reality = 0;
         msg_print(_("景色が元に戻った...", "The view around you returns to normal..."));
-        player_ptr->redraw |= PR_TIMED_EFFECT;
+        rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
         return;
     }
 
     player_ptr->alter_reality = turns;
     msg_print(_("回りの景色が変わり始めた...", "The view around you begins to change..."));
-    player_ptr->redraw |= PR_TIMED_EFFECT;
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
 }
 
 /*!
@@ -409,7 +396,8 @@ static DUNGEON_IDX choose_dungeon(concptr note, POSITION y, POSITION x)
             seiha = true;
         }
 
-        strnfmt(buf, sizeof(buf), _("      %c) %c%-12s : 最大 %d 階", "      %c) %c%-16s : Max level %d"), static_cast<char>('a' + dun.size()), seiha ? '!' : ' ', d_ref.name.data(), (int)max_dlv[d_ref.idx]);
+        constexpr auto fmt = _("      %c) %c%-12s : 最大 %d 階", "      %c) %c%-16s : Max level %d");
+        strnfmt(buf, sizeof(buf), fmt, static_cast<char>('a' + dun.size()), seiha ? '!' : ' ', d_ref.name.data(), (int)max_dlv[d_ref.idx]);
         prt(buf, y + dun.size(), x);
         dun.push_back(d_ref.idx);
     }
@@ -447,33 +435,34 @@ static DUNGEON_IDX choose_dungeon(concptr note, POSITION y, POSITION x)
  */
 bool recall_player(PlayerType *player_ptr, TIME_EFFECT turns)
 {
-    const auto &floor_ref = *player_ptr->current_floor_ptr;
-    if (floor_ref.inside_arena || ironman_downward) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.inside_arena || ironman_downward) {
         msg_print(_("何も起こらなかった。", "Nothing happens."));
         return true;
     }
 
-    bool is_special_floor = floor_ref.is_in_dungeon();
-    is_special_floor &= max_dlv[player_ptr->dungeon_idx] > floor_ref.dun_level;
-    is_special_floor &= !inside_quest(floor_ref.quest_number);
+    bool is_special_floor = floor.is_in_dungeon();
+    is_special_floor &= max_dlv[floor.dungeon_idx] > floor.dun_level;
+    is_special_floor &= !floor.is_in_quest();
     is_special_floor &= !player_ptr->word_recall;
     if (is_special_floor) {
-        if (get_check(_("ここは最深到達階より浅い階です。この階に戻って来ますか? ", "Reset recall depth? "))) {
-            max_dlv[player_ptr->dungeon_idx] = floor_ref.dun_level;
+        if (input_check(_("ここは最深到達階より浅い階です。この階に戻って来ますか? ", "Reset recall depth? "))) {
+            max_dlv[floor.dungeon_idx] = floor.dun_level;
             if (record_maxdepth) {
-                exe_write_diary(player_ptr, DIARY_TRUMP, player_ptr->dungeon_idx, _("帰還のときに", "when recalled from dungeon"));
+                exe_write_diary(player_ptr, DiaryKind::TRUMP, floor.dungeon_idx, _("帰還のときに", "when recalled from dungeon"));
             }
         }
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (player_ptr->word_recall || turns == 0) {
         player_ptr->word_recall = 0;
         msg_print(_("張りつめた大気が流れ去った...", "A tension leaves the air around you..."));
-        player_ptr->redraw |= (PR_TIMED_EFFECT);
+        rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
         return true;
     }
 
-    if (!floor_ref.is_in_dungeon()) {
+    if (!floor.is_in_dungeon()) {
         DUNGEON_IDX select_dungeon;
         select_dungeon = choose_dungeon(_("に帰還", "recall"), 2, 14);
         if (!select_dungeon) {
@@ -484,7 +473,7 @@ bool recall_player(PlayerType *player_ptr, TIME_EFFECT turns)
 
     player_ptr->word_recall = turns;
     msg_print(_("回りの大気が張りつめてきた...", "The air about you becomes charged..."));
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     return true;
 }
 
@@ -507,7 +496,7 @@ bool free_level_recall(PlayerType *player_ptr)
     }
 
     const auto mes = _("%sの何階にテレポートしますか?", "Teleport to which level of %s? ");
-    QUANTITY amt = get_quantity(format(mes, dungeon.name.data()), (QUANTITY)max_depth);
+    const auto amt = input_quantity(max_depth, format(mes, dungeon.name.data()));
     if (amt <= 0) {
         return false;
     }
@@ -517,12 +506,11 @@ bool free_level_recall(PlayerType *player_ptr)
     max_dlv[player_ptr->recall_dungeon] = ((amt > dungeon.maxdepth) ? dungeon.maxdepth
                                                                     : ((amt < dungeon.mindepth) ? dungeon.mindepth : amt));
     if (record_maxdepth) {
-        exe_write_diary(player_ptr, DIARY_TRUMP, select_dungeon, _("トランプタワーで", "at Trump Tower"));
+        exe_write_diary(player_ptr, DiaryKind::TRUMP, select_dungeon, _("トランプタワーで", "at Trump Tower"));
     }
 
     msg_print(_("回りの大気が張りつめてきた...", "The air about you becomes charged..."));
-
-    player_ptr->redraw |= PR_TIMED_EFFECT;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     return true;
 }
 
@@ -533,9 +521,7 @@ bool free_level_recall(PlayerType *player_ptr)
  */
 bool reset_recall(PlayerType *player_ptr)
 {
-    int select_dungeon, dummy = 0;
-
-    select_dungeon = choose_dungeon(_("をセット", "reset"), 2, 14);
+    auto select_dungeon = choose_dungeon(_("をセット", "reset"), 2, 14);
     if (ironman_downward) {
         msg_print(_("何も起こらなかった。", "Nothing happens."));
         return true;
@@ -544,35 +530,24 @@ bool reset_recall(PlayerType *player_ptr)
     if (!select_dungeon) {
         return false;
     }
-    char ppp[80];
-    strnfmt(ppp, sizeof(ppp), _("何階にセットしますか (%d-%d):", "Reset to which level (%d-%d): "), (int)dungeons_info[select_dungeon].mindepth, (int)max_dlv[select_dungeon]);
-    char tmp_val[160];
-    strnfmt(tmp_val, sizeof(tmp_val), "%d", (int)std::max(player_ptr->current_floor_ptr->dun_level, 1));
 
-    if (!get_string(ppp, tmp_val, 10)) {
+    constexpr auto prompt = _("何階にセットしますか?", "Reset to which level?");
+    const auto min_level = dungeons_info[select_dungeon].mindepth;
+    const auto max_level = max_dlv[select_dungeon];
+    const auto reset_level = input_numerics(prompt, min_level, max_level, player_ptr->current_floor_ptr->dun_level);
+    if (!reset_level) {
         return false;
     }
 
-    dummy = atoi(tmp_val);
-    if (dummy < 1) {
-        dummy = 1;
-    }
-    if (dummy > max_dlv[select_dungeon]) {
-        dummy = max_dlv[select_dungeon];
-    }
-    if (dummy < dungeons_info[select_dungeon].mindepth) {
-        dummy = dungeons_info[select_dungeon].mindepth;
-    }
-
-    max_dlv[select_dungeon] = dummy;
-
+    max_dlv[select_dungeon] = *reset_level;
     if (record_maxdepth) {
-        exe_write_diary(player_ptr, DIARY_TRUMP, select_dungeon, _("フロア・リセットで", "using a scroll of reset recall"));
+        constexpr auto note = _("フロア・リセットで", "using a scroll of reset recall");
+        exe_write_diary(player_ptr, DiaryKind::TRUMP, select_dungeon, note);
     }
 #ifdef JP
-    msg_format("%sの帰還レベルを %d 階にセット。", dungeons_info[select_dungeon].name.data(), dummy);
+    msg_format("%sの帰還レベルを %d 階にセット。", dungeons_info[select_dungeon].name.data(), *reset_level);
 #else
-    msg_format("Recall depth set to level %d (%d').", dummy, dummy * 50);
+    msg_format("Recall depth set to level %d (%d').", *reset_level, *reset_level * 50);
 #endif
     return true;
 }
index 588ab01..5e44612 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -7,7 +7,6 @@ void teleport_level(PlayerType *player_ptr, MONSTER_IDX m_idx);
 bool teleport_level_other(PlayerType *player_ptr);
 bool tele_town(PlayerType *player_ptr);
 void reserve_alter_reality(PlayerType *player_ptr, TIME_EFFECT turns);
-bool is_teleport_level_ineffective(PlayerType *player_ptr, MONSTER_IDX idx);
 bool recall_player(PlayerType *player_ptr, TIME_EFFECT turns);
 bool free_level_recall(PlayerType *player_ptr);
 bool reset_recall(PlayerType *player_ptr);
index ad4a2e5..f32568f 100644 (file)
@@ -1,10 +1,10 @@
-#include "spell-realm/spells-arcane.h"
-#include "core/player-update-types.h"
+#include "spell-realm/spells-arcane.h"
 #include "inventory/inventory-slot-types.h"
 #include "object/tval-types.h"
 #include "sv-definition/sv-lite-types.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -37,5 +37,5 @@ void phlogiston(PlayerType *player_ptr)
         msg_print(_("照明用アイテムは満タンになった。", "Your light is full."));
     }
 
-    player_ptr->update |= PU_TORCH;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::TORCH);
 }
index a4af0dd..4c15fec 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void phlogiston(PlayerType *player_ptr);
index 64f130b..72984ac 100644 (file)
@@ -1,6 +1,4 @@
-#include "spell-realm/spells-chaos.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "spell-realm/spells-chaos.h"
 #include "core/window-redrawer.h"
 #include "dungeon/quest.h"
 #include "effect/attribute-types.h"
@@ -21,6 +19,7 @@
 #include "system/grid-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/projection-path-calculator.h"
 #include "util/bit-flags-calculator.h"
  */
 void call_the_void(PlayerType *player_ptr)
 {
-    bool do_call = true;
-    auto *floor_ptr = player_ptr->current_floor_ptr;
+    auto do_call = true;
+    const auto &floor = *player_ptr->current_floor_ptr;
     for (int i = 0; i < 9; i++) {
-        auto *g_ptr = &floor_ptr->grid_array[player_ptr->y + ddy_ddd[i]][player_ptr->x + ddx_ddd[i]];
-
-        if (!g_ptr->cave_has_flag(TerrainCharacteristics::PROJECT)) {
-            if (!g_ptr->mimic || terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::PROJECT) || !permanent_wall(&terrains_info[g_ptr->feat])) {
+        const Pos2D p_pos_neighbor(player_ptr->y + ddy_ddd[i], player_ptr->x + ddx_ddd[i]);
+        const auto &grid = floor.get_grid(p_pos_neighbor);
+        if (!grid.cave_has_flag(TerrainCharacteristics::PROJECT)) {
+            if (!grid.mimic || grid.get_terrain_mimic_raw().flags.has_not(TerrainCharacteristics::PROJECT) || !grid.get_terrain().is_permanent_wall()) {
                 do_call = false;
                 break;
             }
@@ -69,8 +68,8 @@ void call_the_void(PlayerType *player_ptr)
         return;
     }
 
-    bool is_special_fllor = inside_quest(floor_ptr->quest_number) && QuestType::is_fixed(floor_ptr->quest_number);
-    is_special_fllor |= floor_ptr->dun_level == 0;
+    auto is_special_fllor = floor.is_in_quest() && QuestType::is_fixed(floor.quest_number);
+    is_special_fllor |= floor.dun_level == 0;
     if (is_special_fllor) {
         msg_print(_("地面が揺れた。", "The ground trembles."));
         return;
@@ -101,6 +100,46 @@ void call_the_void(PlayerType *player_ptr)
 }
 
 /*!
+ * @brief 与えられたグリッドを壁から床にする
+ * @param floor フロアへの参照
+ * @param pos グリッドの座標
+ * @todo FloorType/Grid のオブジェクトメソッドへ繰り込む
+ */
+static void erase_wall(FloorType &floor, const Pos2D &pos)
+{
+    auto &grid = floor.get_grid(pos);
+    const auto &terrain = grid.get_terrain_mimic_raw();
+    grid.info &= ~(CAVE_ROOM | CAVE_ICKY);
+    if ((grid.mimic == 0) || terrain.flags.has_not(TerrainCharacteristics::HURT_DISI)) {
+        return;
+    }
+
+    grid.mimic = feat_state(&floor, grid.mimic, TerrainCharacteristics::HURT_DISI);
+    const auto &terrain_changed = grid.get_terrain_mimic_raw();
+    if (terrain_changed.flags.has_not(TerrainCharacteristics::REMEMBER)) {
+        grid.info &= ~(CAVE_MARK);
+    }
+}
+
+/*!
+ * @brief フロアの全てを床にする
+ * @param floor フロアへの参照
+ * @todo FloorType のオブジェクトメソッドへ繰り込む
+ */
+static void erase_all_walls(FloorType &floor)
+{
+    for (auto x = 0; x < floor.width; x++) {
+        erase_wall(floor, { 0, x });
+        erase_wall(floor, { floor.height - 1, x });
+    }
+
+    for (auto y = 1; y < (floor.height - 1); y++) {
+        erase_wall(floor, { y, 0 });
+        erase_wall(floor, { y, floor.width - 1 });
+    }
+}
+
+/*!
  * @brief 虚無招来によるフロア中の全壁除去処理 /
  * Vanish all walls in this floor
  * @param player_ptr プレイヤーへの参照ポインタ
@@ -109,86 +148,52 @@ void call_the_void(PlayerType *player_ptr)
  */
 bool vanish_dungeon(PlayerType *player_ptr)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    bool is_special_floor = inside_quest(floor_ptr->quest_number) && QuestType::is_fixed(floor_ptr->quest_number);
-    is_special_floor |= (floor_ptr->dun_level == 0);
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto is_special_floor = floor.is_in_quest() && QuestType::is_fixed(floor.quest_number);
+    is_special_floor |= (floor.dun_level == 0);
     if (is_special_floor) {
         return false;
     }
 
-    for (POSITION y = 1; y < floor_ptr->height - 1; y++) {
-        for (POSITION x = 1; x < floor_ptr->width - 1; x++) {
-            auto *g_ptr = &floor_ptr->grid_array[y][x];
-
-            auto *f_ptr = &terrains_info[g_ptr->feat];
-            g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
-            auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
-            if (g_ptr->m_idx && m_ptr->is_asleep()) {
-                (void)set_monster_csleep(player_ptr, g_ptr->m_idx, 0);
-                if (m_ptr->ml) {
-                    const auto m_name = monster_desc(player_ptr, m_ptr, 0);
+    for (auto y = 1; y < floor.height - 1; y++) {
+        for (auto x = 1; x < floor.width - 1; x++) {
+            const Pos2D pos(y, x);
+            auto &grid = floor.get_grid(pos);
+            const auto &terrrain = grid.get_terrain();
+            grid.info &= ~(CAVE_ROOM | CAVE_ICKY);
+            const auto &monster = floor.m_list[grid.m_idx];
+            if (grid.m_idx && monster.is_asleep()) {
+                (void)set_monster_csleep(player_ptr, grid.m_idx, 0);
+                if (monster.ml) {
+                    const auto m_name = monster_desc(player_ptr, &monster, 0);
                     msg_format(_("%s^が目を覚ました。", "%s^ wakes up."), m_name.data());
                 }
             }
 
-            if (f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
+            if (terrrain.flags.has(TerrainCharacteristics::HURT_DISI)) {
                 cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_DISI);
             }
         }
     }
 
-    for (POSITION x = 0; x < floor_ptr->width; x++) {
-        auto *g_ptr = &floor_ptr->grid_array[0][x];
-        auto *f_ptr = &terrains_info[g_ptr->mimic];
-        g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
-
-        if (g_ptr->mimic && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
-            g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, TerrainCharacteristics::HURT_DISI);
-            if (terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::REMEMBER)) {
-                g_ptr->info &= ~(CAVE_MARK);
-            }
-        }
-
-        g_ptr = &floor_ptr->grid_array[floor_ptr->height - 1][x];
-        f_ptr = &terrains_info[g_ptr->mimic];
-        g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
-
-        if (g_ptr->mimic && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
-            g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, TerrainCharacteristics::HURT_DISI);
-            if (terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::REMEMBER)) {
-                g_ptr->info &= ~(CAVE_MARK);
-            }
-        }
-    }
-
-    /* Special boundary walls -- Left and right */
-    for (POSITION y = 1; y < (floor_ptr->height - 1); y++) {
-        auto *g_ptr = &floor_ptr->grid_array[y][0];
-        auto *f_ptr = &terrains_info[g_ptr->mimic];
-        g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
-
-        if (g_ptr->mimic && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
-            g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, TerrainCharacteristics::HURT_DISI);
-            if (terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::REMEMBER)) {
-                g_ptr->info &= ~(CAVE_MARK);
-            }
-        }
-
-        g_ptr = &floor_ptr->grid_array[y][floor_ptr->width - 1];
-        f_ptr = &terrains_info[g_ptr->mimic];
-        g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
-
-        if (g_ptr->mimic && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
-            g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, TerrainCharacteristics::HURT_DISI);
-            if (terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::REMEMBER)) {
-                g_ptr->info &= ~(CAVE_MARK);
-            }
-        }
-    }
-
-    player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTER_LITE | PU_MONSTER_STATUSES);
-    player_ptr->redraw |= (PR_MAP);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+    erase_all_walls(floor);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::UN_VIEW,
+        StatusRecalculatingFlag::UN_LITE,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::FLOW,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
     return true;
 }
 
@@ -221,7 +226,12 @@ void cast_meteor(PlayerType *player_ptr, int dam, POSITION rad)
             }
 
             auto *floor_ptr = player_ptr->current_floor_ptr;
-            if (!in_bounds(floor_ptr, y, x) || !projectable(player_ptr, player_ptr->y, player_ptr->x, y, x) || !cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
+            if (!in_bounds(floor_ptr, y, x)) {
+                continue;
+            }
+
+            const auto is_projectable = projectable(player_ptr, player_ptr->y, player_ptr->x, y, x);
+            if (!is_projectable || !cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
                 continue;
             }
 
index 359024f..573a5bc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 5d1b852..9cf7e9e 100644 (file)
@@ -1,8 +1,6 @@
-#include "spell-realm/spells-craft.h"
+#include "spell-realm/spells-craft.h"
 #include "avatar/avatar.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -12,7 +10,6 @@
 #include "io/input-key-acceptor.h"
 #include "object-enchant/object-ego.h"
 #include "object/item-use-flags.h"
-#include "object/object-flags.h"
 #include "player-info/equipment-info.h"
 #include "player/attack-defense-types.h"
 #include "player/special-defense-types.h"
@@ -21,6 +18,7 @@
 #include "sv-definition/sv-protector-types.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "view/display-messages.h"
@@ -64,32 +62,39 @@ bool set_ele_attack(PlayerType *player_ptr, uint32_t attack_type, TIME_EFFECT v)
     if ((v) && (attack_type)) {
         player_ptr->special_attack |= (attack_type);
         player_ptr->ele_attack = v;
-#ifdef JP
-        msg_format("%sで攻撃できるようになった!",
-            ((attack_type == ATTACK_ACID)
-                    ? "酸"
-                    : ((attack_type == ATTACK_ELEC)
-                              ? "電撃"
-                              : ((attack_type == ATTACK_FIRE) ? "火炎"
-                                                              : ((attack_type == ATTACK_COLD) ? "冷気" : ((attack_type == ATTACK_POIS) ? "毒" : "(なし)"))))));
-#else
-        msg_format("For a while, the blows you deal will %s",
-            ((attack_type == ATTACK_ACID)
-                    ? "melt with acid!"
-                    : ((attack_type == ATTACK_ELEC)
-                              ? "shock your foes!"
-                              : ((attack_type == ATTACK_FIRE)
-                                        ? "burn with fire!"
-                                        : ((attack_type == ATTACK_COLD) ? "chill to the bone!"
-                                                                        : ((attack_type == ATTACK_POIS) ? "poison your enemies!" : "do nothing special."))))));
-#endif
+        std::string element;
+        switch (attack_type) {
+        case ATTACK_ACID:
+            element = _("酸", "melt with acid!");
+            break;
+        case ATTACK_ELEC:
+            element = _("電撃", "shock your foes!");
+            break;
+        case ATTACK_FIRE:
+            element = _("火炎", "burn with fire!");
+            break;
+        case ATTACK_COLD:
+            element = _("冷気", "chill to the bone!");
+            break;
+        case ATTACK_POIS:
+            element = _("毒", "poison your enemies!");
+            break;
+        default: // @todo 本来はruntime_error を飛ばすべきだが、既存コードと同じように動くことを優先した.
+            element = _("(なし)", "do nothing special.");
+            break;
+        }
+
+        constexpr auto mes = _("%sで攻撃できるようになった!", "For a while, the blows you deal will %s");
+        msg_format(mes, element.data());
     }
 
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-    player_ptr->update |= (PU_BONUS);
+
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
 
     return true;
@@ -134,23 +139,38 @@ bool set_ele_immune(PlayerType *player_ptr, uint32_t immune_type, TIME_EFFECT v)
     if ((v) && (immune_type)) {
         player_ptr->special_defense |= (immune_type);
         player_ptr->ele_immune = v;
-        msg_format(_("%sの攻撃を受けつけなくなった!", "For a while, you are immune to %s"),
-            ((immune_type == DEFENSE_ACID)
-                    ? _("酸", "acid!")
-                    : ((immune_type == DEFENSE_ELEC)
-                              ? _("電撃", "electricity!")
-                              : ((immune_type == DEFENSE_FIRE)
-                                        ? _("火炎", "fire!")
-                                        : ((immune_type == DEFENSE_COLD)
-                                                  ? _("冷気", "cold!")
-                                                  : ((immune_type == DEFENSE_POIS) ? _("毒", "poison!") : _("(なし)", "nothing special.")))))));
+        std::string element;
+        switch (immune_type) {
+        case ATTACK_ACID:
+            element = _("酸", "acid!");
+            break;
+        case ATTACK_ELEC:
+            element = _("電撃", "electricity!");
+            break;
+        case ATTACK_FIRE:
+            element = _("火炎", "fire!");
+            break;
+        case ATTACK_COLD:
+            element = _("冷気", "cold!");
+            break;
+        case ATTACK_POIS:
+            element = _("毒", "poison!");
+            break;
+        default: // @todo 本来はruntime_error を飛ばすべきだが、既存コードと同じように動くことを優先した.
+            element = _("(なし)", "nothing special.");
+            break;
+        }
+
+        msg_format(_("%sの攻撃を受けつけなくなった!", "For a while, you are immune to %s"), element.data());
     }
 
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-    player_ptr->update |= (PU_BONUS);
+
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
 
     return true;
@@ -269,11 +289,11 @@ bool choose_ele_immune(PlayerType *player_ptr, TIME_EFFECT immune_turn)
  */
 bool pulish_shield(PlayerType *player_ptr)
 {
-    const auto q = _("どの盾を磨きますか?", "Polish which shield? ");
-    const auto s = _("磨く盾がありません。", "You have no shield to polish.");
+    constexpr auto q = _("どの盾を磨きますか?", "Polish which shield? ");
+    constexpr auto s = _("磨く盾がありません。", "You have no shield to polish.");
     const auto options = USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT;
-    short item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, options, TvalItemTester(ItemKindType::SHIELD));
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, TvalItemTester(ItemKindType::SHIELD));
     if (o_ptr == nullptr) {
         return false;
     }
@@ -286,10 +306,10 @@ bool pulish_shield(PlayerType *player_ptr)
 #ifdef JP
         msg_format("%sは輝いた!", item_name.data());
 #else
-        msg_format("%s %s shine%s!", ((item >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
+        msg_format("%s %s shine%s!", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
 #endif
         o_ptr->ego_idx = EgoType::REFLECTION;
-        enchant_equipment(player_ptr, o_ptr, randint0(3) + 4, ENCH_TOAC);
+        enchant_equipment(o_ptr, randint0(3) + 4, ENCH_TOAC);
         o_ptr->discount = 99;
         chg_virtue(player_ptr, Virtue::ENCHANT, 2);
         return true;
index cbd2d09..22e9bee 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f87b0d9..b91a5ff 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 破邪魔法処理
  * @date 2020/06/05
  * @author Hourier
@@ -6,8 +6,6 @@
 
 #include "spell-realm/spells-crusade.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "grid/feature-flag-types.h"
 #include "spell-realm/spells-crusade.h"
 #include "spell/range-calc.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
 #include "target/target-getter.h"
  */
 bool cast_wrath_of_the_god(PlayerType *player_ptr, int dam, POSITION rad)
 {
-    DIRECTION dir;
+    int dir;
     if (!get_aim_dir(player_ptr, &dir)) {
         return false;
     }
 
-    POSITION tx = player_ptr->x + 99 * ddx[dir];
-    POSITION ty = player_ptr->y + 99 * ddy[dir];
+    Pos2D pos_target(player_ptr->y + 99 * ddy[dir], player_ptr->x + 99 * ddx[dir]);
     if ((dir == 5) && target_okay(player_ptr)) {
-        tx = target_col;
-        ty = target_row;
+        pos_target.x = target_col;
+        pos_target.y = target_row;
     }
 
-    POSITION x = player_ptr->x;
-    POSITION y = player_ptr->y;
-    POSITION nx, ny;
+    Pos2D pos = player_ptr->get_position();
+    auto &floor = *player_ptr->current_floor_ptr;
     while (true) {
-        if ((y == ty) && (x == tx)) {
+        if (pos == pos_target) {
             break;
         }
 
-        ny = y;
-        nx = x;
-        mmove2(&ny, &nx, player_ptr->y, player_ptr->x, ty, tx);
-        if (get_max_range(player_ptr) <= distance(player_ptr->y, player_ptr->x, ny, nx)) {
+        const auto pos_to = mmove2(pos, player_ptr->get_position(), pos_target);
+        if (AngbandSystem::get_instance().get_max_range() <= distance(player_ptr->y, player_ptr->x, pos_to.y, pos_to.x)) {
             break;
         }
-        if (!cave_has_flag_bold(player_ptr->current_floor_ptr, ny, nx, TerrainCharacteristics::PROJECT)) {
+        if (!cave_has_flag_bold(&floor, pos_to.y, pos_to.x, TerrainCharacteristics::PROJECT)) {
             break;
         }
-        if ((dir != 5) && player_ptr->current_floor_ptr->grid_array[ny][nx].m_idx != 0) {
+        if ((dir != 5) && floor.get_grid(pos_to).m_idx != 0) {
             break;
         }
 
-        x = nx;
-        y = ny;
+        pos = pos_to;
     }
 
-    tx = x;
-    ty = y;
-
-    int b = 10 + randint1(10);
-    for (int i = 0; i < b; i++) {
-        int count = 20, d = 0;
-
+    pos_target = pos;
+    const auto b = 10 + randint1(10);
+    for (auto i = 0; i < b; i++) {
+        auto count = 20;
+        Pos2D pos_explode(pos_target.x, pos_target.y);
         while (count--) {
-            int dx, dy;
-
-            x = tx - 5 + randint0(11);
-            y = ty - 5 + randint0(11);
-
-            dx = (tx > x) ? (tx - x) : (x - tx);
-            dy = (ty > y) ? (ty - y) : (y - ty);
-
-            d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
+            const auto x = pos_target.x - 5 + randint0(11);
+            const auto y = pos_target.y - 5 + randint0(11);
+            const auto dx = (pos_target.x > x) ? (pos_target.x - x) : (x - pos_target.x);
+            const auto dy = (pos_target.y > y) ? (pos_target.y - y) : (y - pos_target.y);
+            const auto d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
             if (d < 5) {
+                pos_explode.x = x;
+                pos_explode.y = y;
                 break;
             }
         }
@@ -99,11 +90,15 @@ bool cast_wrath_of_the_god(PlayerType *player_ptr, int dam, POSITION rad)
             continue;
         }
 
-        if (!in_bounds(player_ptr->current_floor_ptr, y, x) || cave_stop_disintegration(player_ptr->current_floor_ptr, y, x) || !in_disintegration_range(player_ptr->current_floor_ptr, ty, tx, y, x)) {
+        auto should_cast = in_bounds(&floor, pos_explode.y, pos_explode.x);
+        should_cast &= !cave_stop_disintegration(&floor, pos_explode.y, pos_explode.x);
+        should_cast &= in_disintegration_range(&floor, pos_target.y, pos_target.x, pos_explode.y, pos_explode.x);
+        if (!should_cast) {
             continue;
         }
 
-        project(player_ptr, 0, rad, y, x, dam, AttributeType::DISINTEGRATE, PROJECT_JUMP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL);
+        constexpr auto mode = PROJECT_JUMP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
+        project(player_ptr, 0, rad, pos_explode.y, pos_explode.x, dam, AttributeType::DISINTEGRATE, mode);
     }
 
     return true;
@@ -141,8 +136,9 @@ bool set_tim_sh_holy(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         }
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     player_ptr->tim_sh_holy = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
 
     if (!notice) {
         return false;
@@ -151,7 +147,8 @@ bool set_tim_sh_holy(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -189,8 +186,9 @@ bool set_tim_eyeeye(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         }
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     player_ptr->tim_eyeeye = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
 
     if (!notice) {
         return false;
@@ -199,7 +197,8 @@ bool set_tim_eyeeye(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
index 45f5649..55865f5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 325118e..46381d3 100644 (file)
@@ -1,10 +1,9 @@
-#include "spell-realm/spells-demon.h"
+#include "spell-realm/spells-demon.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "game-option/disturbance-options.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -40,7 +39,8 @@ bool set_tim_sh_fire(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_sh_fire = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
 
     if (!notice) {
         return false;
@@ -49,7 +49,8 @@ bool set_tim_sh_fire(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
index 06e2bbf..0098a49 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 386fbfd..885958c 100644 (file)
@@ -1,7 +1,5 @@
-#include "spell-realm/spells-hex.h"
+#include "spell-realm/spells-hex.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
 #include "spell/spells-execution.h"
 #include "spell/technic-info-table.h"
 #include "status/action-setter.h"
+#include "system/angband-exceptions.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "util/bit-flags-calculator.h"
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
-
 #ifdef JP
 #else
 #include "monster/monster-describer.h"
 #include "monster/monster-description-types.h"
 #endif
 
-#include <iterator>
-
 /*!< 呪術の最大詠唱数 */
 constexpr int MAX_KEEP = 4;
 
@@ -50,7 +47,7 @@ SpellHex::SpellHex(PlayerType *player_ptr)
     HexSpellFlagGroup::get_flags(this->spell_hex_data->casting_spells, std::back_inserter(this->casting_spells));
 
     if (this->casting_spells.size() > MAX_KEEP) {
-        throw("Invalid numbers of hex magics keep!");
+        THROW_EXCEPTION(std::logic_error, "Invalid numbers of hex magics keep!");
     }
 }
 
@@ -74,8 +71,20 @@ void SpellHex::stop_all_spells()
         set_action(this->player_ptr, ACTION_NONE);
     }
 
-    this->player_ptr->update |= PU_BONUS | PU_HP | PU_MP | PU_SPELLS;
-    this->player_ptr->redraw |= PR_EXTRA | PR_HP | PR_MP;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
+    rfu.set_flags(flags_mwrf);
 }
 
 /*!
@@ -95,25 +104,36 @@ bool SpellHex::stop_spells_with_selection()
         return true;
     }
 
-    char out_val[160];
-    strnfmt(out_val, 78, _("どの呪文の詠唱を中断しますか?(呪文 %c-%c, 'l'全て, ESC)", "Which spell do you stop casting? (Spell %c-%c, 'l' to all, ESC)"),
-        I2A(0), I2A(casting_num - 1));
+    constexpr auto fmt = _("どの呪文の詠唱を中断しますか?(呪文 %c-%c, 'l'全て, ESC)", "Which spell do you stop casting? (Spell %c-%c, 'l' to all, ESC)");
+    const auto prompt = format(fmt, I2A(0), I2A(casting_num - 1));
     screen_save();
-    auto [is_all, is_selected, choice] = select_spell_stopping(out_val);
+    const auto &[is_all, choice] = select_spell_stopping(prompt);
     if (is_all) {
         return true;
     }
 
     screen_load();
-    if (is_selected) {
-        auto n = this->casting_spells[A2I(choice)];
+    if (choice) {
+        auto n = this->casting_spells[A2I(*choice)];
         exe_spell(this->player_ptr, REALM_HEX, n, SpellProcessType::STOP);
         this->reset_casting_flag(i2enum<spell_hex_type>(n));
     }
 
-    this->player_ptr->update |= PU_BONUS | PU_HP | PU_MP | PU_SPELLS;
-    this->player_ptr->redraw |= PR_EXTRA | PR_HP | PR_MP;
-    return is_selected;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+    };
+    rfu.set_flags(flags_mwrf);
+    return choice.has_value();
 }
 
 /*!
@@ -124,15 +144,16 @@ bool SpellHex::stop_spells_with_selection()
  * Item2: 選択が完了したらtrue、キャンセルならばfalse
  * Item3: 選択した呪文番号 (a~d、lの5択)
  */
-std::tuple<bool, bool, char> SpellHex::select_spell_stopping(char *out_val)
+std::pair<bool, std::optional<char>> SpellHex::select_spell_stopping(std::string_view prompt)
 {
     while (true) {
-        char choice = 0;
         this->display_casting_spells_list();
-        if (!get_com(out_val, &choice, true)) {
-            return std::make_tuple(false, false, choice);
+        const auto choice_opt = input_command(prompt, true);
+        if (!choice_opt) {
+            return { false, std::nullopt };
         }
 
+        auto choice = *choice_opt;
         if (isupper(choice)) {
             choice = static_cast<char>(tolower(choice));
         }
@@ -140,14 +161,14 @@ std::tuple<bool, bool, char> SpellHex::select_spell_stopping(char *out_val)
         if (choice == 'l') {
             screen_load();
             this->stop_all_spells();
-            return std::make_tuple(true, true, choice);
+            return { true, choice };
         }
 
         if ((choice < I2A(0)) || (choice > I2A(this->get_casting_num() - 1))) {
             continue;
         }
 
-        return std::make_tuple(false, true, choice);
+        return { false, choice };
     }
 }
 
@@ -156,10 +177,10 @@ void SpellHex::display_casting_spells_list()
     constexpr auto y = 1;
     constexpr auto x = 20;
     auto n = 0;
-    term_erase(x, y, 255);
+    term_erase(x, y);
     prt(_("     名前", "     Name"), y, x + 5);
     for (auto spell : this->casting_spells) {
-        term_erase(x, y + n + 1, 255);
+        term_erase(x, y + n + 1);
         const auto spell_name = exe_spell(this->player_ptr, REALM_HEX, spell, SpellProcessType::NAME);
         put_str(format("%c)  %s", I2A(n), spell_name->data()), y + n + 1, x + 2);
         n++;
@@ -215,17 +236,31 @@ bool SpellHex::process_mana_cost(const bool need_restart)
     }
 
     s64b_sub(&(this->player_ptr->csp), &(this->player_ptr->csp_frac), need_mana, need_mana_frac);
-    this->player_ptr->redraw |= PR_MP;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
     if (!need_restart) {
         return true;
     }
 
     msg_print(_("詠唱を再開した。", "You restart casting."));
     this->player_ptr->action = ACTION_SPELL;
-    this->player_ptr->update |= PU_BONUS | PU_HP;
-    this->player_ptr->redraw |= PR_MAP | PR_TIMED_EFFECT | PR_ACTION;
-    this->player_ptr->update |= PU_MONSTER_STATUSES;
-    this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::TIMED_EFFECT,
+        MainWindowRedrawingFlag::ACTION,
+    };
+    rfu.set_flags(flags_mwrf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
     return true;
 }
 
@@ -317,7 +352,7 @@ void SpellHex::store_vengeful_damage(int dam)
 bool SpellHex::check_hex_barrier(MONSTER_IDX m_idx, spell_hex_type type) const
 {
     const auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[m_idx];
-    const auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    const auto *r_ptr = &m_ptr->get_monrace();
     return this->is_spelling_specific(type) && ((this->player_ptr->lev * 3 / 2) >= randint1(r_ptr->level));
 }
 
@@ -345,7 +380,7 @@ void SpellHex::interrupt_spelling()
 void SpellHex::eyes_on_eyes()
 {
     if (this->monap_ptr == nullptr) {
-        throw("Invalid constructor was used!");
+        THROW_EXCEPTION(std::logic_error, "Invalid constructor was used!");
     }
 
     const auto is_eyeeye_finished = (this->player_ptr->tim_eyeeye == 0) && !this->is_spelling_specific(HEX_EYE_FOR_EYE);
@@ -370,7 +405,7 @@ void SpellHex::eyes_on_eyes()
 void SpellHex::thief_teleport()
 {
     if (this->monap_ptr == nullptr) {
-        throw("Invalid constructor was used!");
+        THROW_EXCEPTION(std::logic_error, "Invalid constructor was used!");
     }
 
     if (!this->monap_ptr->blinked || !this->monap_ptr->alive || this->player_ptr->is_dead) {
index 6ea3320..740a455 100644 (file)
@@ -1,8 +1,10 @@
-#pragma once
+#pragma once
 
 #include "realm/realm-hex-numbers.h"
 #include "system/angband.h"
-#include <tuple>
+#include <optional>
+#include <string_view>
+#include <utility>
 
 enum class SpellHexRevengeType : byte {
     NONE = 0,
@@ -47,7 +49,7 @@ private:
     MonsterAttackPlayer *monap_ptr = nullptr;
     std::shared_ptr<spell_hex_data_type> spell_hex_data;
 
-    std::tuple<bool, bool, char> select_spell_stopping(char *out_val);
+    std::pair<bool, std::optional<char>> select_spell_stopping(std::string_view prompt);
     void display_casting_spells_list();
     bool process_mana_cost(const bool need_restart);
     bool check_restart();
index da043c8..e6788ff 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-realm/spells-nature.h"
+#include "spell-realm/spells-nature.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "floor/floor-object.h"
  */
 bool rustproof(PlayerType *player_ptr)
 {
-    const auto q = _("どの防具に錆止めをしますか?", "Rustproof which piece of armour? ");
-    const auto s = _("錆止めできるものがありません。", "You have nothing to rustproof.");
-    OBJECT_IDX item;
+    constexpr auto q = _("どの防具に錆止めをしますか?", "Rustproof which piece of armour? ");
+    constexpr auto s = _("錆止めできるものがありません。", "You have nothing to rustproof.");
+    short i_idx;
     const auto options = USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, options, FuncItemTester(&ItemEntity::is_protector));
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, FuncItemTester(&ItemEntity::is_protector));
     if (o_ptr == nullptr) {
         return false;
     }
@@ -34,7 +34,7 @@ bool rustproof(PlayerType *player_ptr)
 #ifdef JP
         msg_format("%sは新品同様になった!", item_name.data());
 #else
-        msg_format("%s %s look%s as good as new!", ((item >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
+        msg_format("%s %s look%s as good as new!", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
 #endif
         o_ptr->to_a = 0;
     }
@@ -42,7 +42,7 @@ bool rustproof(PlayerType *player_ptr)
 #ifdef JP
     msg_format("%sは腐食しなくなった。", item_name.data());
 #else
-    msg_format("%s %s %s now protected against corrosion.", ((item >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "are" : "is"));
+    msg_format("%s %s %s now protected against corrosion.", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "are" : "is"));
 #endif
     calc_android_exp(player_ptr);
     return true;
index b2c88d0..2bc7a2b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool rustproof(PlayerType *player_ptr);
index 378b761..b7fcaa6 100644 (file)
@@ -1,7 +1,5 @@
-#include "spell-realm/spells-song.h"
+#include "spell-realm/spells-song.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "game-option/disturbance-options.h"
@@ -17,6 +15,7 @@
 #include "status/action-setter.h"
 #include "system/floor-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
@@ -50,23 +49,36 @@ void check_music(PlayerType *player_ptr)
     if (s64b_cmp(player_ptr->csp, player_ptr->csp_frac, need_mana, need_mana_frac) < 0) {
         stop_singing(player_ptr);
         return;
-    } else {
-        s64b_sub(&(player_ptr->csp), &(player_ptr->csp_frac), need_mana, need_mana_frac);
-
-        player_ptr->redraw |= PR_MP;
-        if (interupting_song_effect != 0) {
-            set_singing_song_effect(player_ptr, interupting_song_effect);
-            set_interrupting_song_effect(player_ptr, MUSIC_NONE);
-            msg_print(_("歌を再開した。", "You resume singing."));
-            player_ptr->action = ACTION_SING;
-            player_ptr->update |= (PU_BONUS | PU_HP | PU_MONSTER_STATUSES);
-            player_ptr->redraw |= (PR_MAP | PR_TIMED_EFFECT | PR_ACTION);
-            player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
-        }
     }
 
-    PlayerSkill(player_ptr).gain_continuous_spell_skill_exp(REALM_MUSIC, spell);
+    s64b_sub(&(player_ptr->csp), &(player_ptr->csp_frac), need_mana, need_mana_frac);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    if (interupting_song_effect != 0) {
+        set_singing_song_effect(player_ptr, interupting_song_effect);
+        set_interrupting_song_effect(player_ptr, MUSIC_NONE);
+        msg_print(_("歌を再開した。", "You resume singing."));
+        player_ptr->action = ACTION_SING;
+        static constexpr auto flags_srf = {
+            StatusRecalculatingFlag::BONUS,
+            StatusRecalculatingFlag::HP,
+            StatusRecalculatingFlag::MONSTER_STATUSES,
+        };
+        rfu.set_flags(flags_srf);
+        static constexpr auto flags_mwrf = {
+            MainWindowRedrawingFlag::MAP,
+            MainWindowRedrawingFlag::TIMED_EFFECT,
+            MainWindowRedrawingFlag::ACTION,
+        };
+        rfu.set_flags(flags_mwrf);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::OVERHEAD,
+            SubWindowRedrawingFlag::DUNGEON,
+        };
+        rfu.set_flags(flags_swrf);
+    }
 
+    PlayerSkill(player_ptr).gain_continuous_spell_skill_exp(REALM_MUSIC, spell);
     exe_spell(player_ptr, REALM_MUSIC, spell, SpellProcessType::CONTNUATION);
 }
 
@@ -103,8 +115,8 @@ bool set_tim_stealth(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_stealth = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -112,7 +124,8 @@ bool set_tim_stealth(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -142,8 +155,9 @@ void stop_singing(PlayerType *player_ptr)
     (void)exe_spell(player_ptr, REALM_MUSIC, get_singing_song_id(player_ptr), SpellProcessType::STOP);
     set_singing_song_effect(player_ptr, MUSIC_NONE);
     set_singing_song_id(player_ptr, 0);
-    set_bits(player_ptr->update, PU_BONUS);
-    set_bits(player_ptr->redraw, PR_TIMED_EFFECT);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
 }
 
 bool music_singing(PlayerType *player_ptr, int music_songs)
index 9053367..ab8ef1d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index a4bab23..601dba6 100644 (file)
@@ -1,6 +1,5 @@
-#include "spell-realm/spells-sorcery.h"
+#include "spell-realm/spells-sorcery.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "floor/floor-object.h"
@@ -12,6 +11,7 @@
 #include "object/object-value.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/z-form.h"
 #include "view/display-messages.h"
 
@@ -28,24 +28,23 @@ bool alchemy(PlayerType *player_ptr)
         force = true;
     }
 
-    concptr q = _("どのアイテムを金に変えますか?", "Turn which item to gold? ");
-    concptr s = _("金に変えられる物がありません。", "You have nothing to turn to gold.");
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR));
+    constexpr auto q = _("どのアイテムを金に変えますか?", "Turn which item to gold? ");
+    constexpr auto s = _("金に変えられる物がありません。", "You have nothing to turn to gold.");
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR));
     if (!o_ptr) {
         return false;
     }
 
-    int amt = 1;
+    auto amt = 1;
     if (o_ptr->number > 1) {
-        amt = get_quantity(std::nullopt, o_ptr->number);
+        amt = input_quantity(o_ptr->number);
         if (amt <= 0) {
             return false;
         }
     }
 
-    ITEM_NUMBER old_number = o_ptr->number;
+    const auto old_number = o_ptr->number;
     o_ptr->number = amt;
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
     o_ptr->number = old_number;
@@ -54,21 +53,21 @@ bool alchemy(PlayerType *player_ptr)
         if (confirm_destroy || (o_ptr->get_price() > 0)) {
             char out_val[MAX_NLEN + 40];
             strnfmt(out_val, sizeof(out_val), _("本当に%sを金に変えますか?", "Really turn %s to gold? "), item_name.data());
-            if (!get_check(out_val)) {
+            if (!input_check(out_val)) {
                 return false;
             }
         }
     }
 
-    if (!can_player_destroy_object(player_ptr, o_ptr)) {
+    if (!can_player_destroy_object(o_ptr)) {
         msg_format(_("%sを金に変えることに失敗した。", "You fail to turn %s to gold!"), item_name.data());
         return false;
     }
 
-    PRICE price = object_value_real(o_ptr);
+    auto price = object_value_real(o_ptr);
     if (price <= 0) {
         msg_format(_("%sをニセの金に変えた。", "You turn %s to fool's gold."), item_name.data());
-        vary_item(player_ptr, item, -amt);
+        vary_item(player_ptr, i_idx, -amt);
         return true;
     }
 
@@ -84,8 +83,9 @@ bool alchemy(PlayerType *player_ptr)
 
     msg_format(_("%sを$%d の金に変えた。", "You turn %s to %d coins worth of gold."), item_name.data(), price);
     player_ptr->au += price;
-    player_ptr->redraw |= PR_GOLD;
-    player_ptr->window_flags |= PW_PLAYER;
-    vary_item(player_ptr, item, -amt);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::GOLD);
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
+    vary_item(player_ptr, i_idx, -amt);
     return true;
 }
index f5ee7ea..ef79b4f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool alchemy(PlayerType *player_ptr);
index 1d81c07..444ba9e 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell-realm/spells-trump.h"
+#include "spell-realm/spells-trump.h"
 #include "avatar/avatar.h"
 #include "monster-floor/monster-summon.h"
 #include "monster-floor/place-monster-types.h"
index 6505f2c..93586b5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void cast_shuffle(PlayerType *player_ptr);
index 6ba891b..ed26630 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 魔法による距離やエリアの計算
  * @date 2014/07/10
  * @author Ben Harrison, James E. Wilson, Robert A. Koeneke, deskull and Hourier
@@ -212,7 +212,7 @@ void breath_shape(PlayerType *player_ptr, const projection_path &path, int dist,
     auto *floor_ptr = player_ptr->current_floor_ptr;
     while (bdis <= mdis) {
         if ((0 < dist) && (path_n < dist)) {
-            const auto [ny, nx] = path[path_n];
+            const auto &[ny, nx] = path[path_n];
             POSITION nd = distance(ny, nx, y1, x1);
 
             if (bdis >= nd) {
index 008207e..edbb6e1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
index 47ea2eb..6887faa 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell/spell-info.h"
+#include "spell/spell-info.h"
 #include "io/input-key-requester.h"
 #include "monster-race/monster-race.h"
 #include "player-base/player-class.h"
@@ -73,7 +73,7 @@ PERCENTAGE mod_spell_chance_1(PlayerType *player_ptr, PERCENTAGE chance)
 {
     chance += player_ptr->to_m_chance;
 
-    if (player_ptr->heavy_spell) {
+    if (player_ptr->hard_spell) {
         chance += 20;
     }
 
@@ -105,7 +105,7 @@ PERCENTAGE mod_spell_chance_2(PlayerType *player_ptr, PERCENTAGE chance)
     if (player_ptr->dec_mana) {
         chance--;
     }
-    if (player_ptr->heavy_spell) {
+    if (player_ptr->hard_spell) {
         chance += 5;
     }
     return std::max(chance, 0);
index 8322799..e076b9a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 7a9f16e..7991d7a 100644 (file)
@@ -1,11 +1,13 @@
-#include "spell/spells-describer.h"
+#include "spell/spells-describer.h"
+#include "locale/language-switcher.h"
+#include "object/tval-types.h"
 
 /*!
  * @brief 領域魔法に応じて技能の名称を返す。
  * @param tval 魔法書のtval
  * @return 領域魔法の技能名称を保管した文字列ポインタ
  */
-concptr spell_category_name(ItemKindType tval)
+std::string spell_category_name(ItemKindType tval)
 {
     switch (tval) {
     case ItemKindType::HISSATSU_BOOK:
index 0141a3b..9000b24 100644 (file)
@@ -1,6 +1,6 @@
-#pragma once
+#pragma once
 
-#include "object/tval-types.h"
-#include "system/angband.h"
+#include <string>
 
-concptr spell_category_name(ItemKindType tval);
+enum class ItemKindType : short;
+std::string spell_category_name(ItemKindType tval);
index 29fe241..7c4d1c7 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell/spells-diceroll.h"
+#include "spell/spells-diceroll.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags-resistance.h"
@@ -24,7 +24,7 @@
  */
 bool common_saving_throw_charm(PlayerType *player_ptr, int pow, MonsterEntity *m_ptr)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     if (player_ptr->current_floor_ptr->inside_arena) {
         return true;
@@ -38,9 +38,9 @@ bool common_saving_throw_charm(PlayerType *player_ptr, int pow, MonsterEntity *m
         return true;
     }
 
-    if (r_ptr->flags3 & RF3_NO_CONF) {
+    if (r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
         if (is_original_ap_and_seen(player_ptr, m_ptr)) {
-            r_ptr->r_flags3 |= (RF3_NO_CONF);
+            r_ptr->resistance_flags.set(MonsterResistanceType::NO_CONF);
         }
         return true;
     }
@@ -64,7 +64,7 @@ bool common_saving_throw_charm(PlayerType *player_ptr, int pow, MonsterEntity *m
  */
 bool common_saving_throw_control(PlayerType *player_ptr, int pow, MonsterEntity *m_ptr)
 {
-    auto *r_ptr = &monraces_info[m_ptr->r_idx];
+    auto *r_ptr = &m_ptr->get_monrace();
 
     if (player_ptr->current_floor_ptr->inside_arena) {
         return true;
index 9b3e32e..23850aa 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index a323d22..f45e79d 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell/spells-execution.h"
+#include "spell/spells-execution.h"
 #include "realm/realm-arcane.h"
 #include "realm/realm-chaos.h"
 #include "realm/realm-craft.h"
index c0a7fc3..2148ea5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index 61f6034..15d068c 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief アイテムに影響のある魔法の処理
  * @date 2019/01/22
  * @author deskull
@@ -7,7 +7,6 @@
 #include "spell/spells-object.h"
 #include "artifact/fixed-art-types.h"
 #include "avatar/avatar.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -41,6 +40,7 @@
 #include "system/item-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "util/bit-flags-calculator.h"
 #include "util/probability-table.h"
@@ -145,15 +145,15 @@ void generate_amusement(PlayerType *player_ptr, int num, bool known)
         std::optional<FixedArtifactId> opt_a_idx(std::nullopt);
         if (insta_art || fixed_art) {
             opt_a_idx = sweep_amusement_artifact(insta_art, bi_id);
-            if (!opt_a_idx.has_value()) {
+            if (!opt_a_idx) {
                 continue;
             }
         }
 
         ItemEntity item;
         item.prep(bi_id);
-        if (opt_a_idx.has_value()) {
-            item.fixed_artifact_idx = opt_a_idx.value();
+        if (opt_a_idx) {
+            item.fixed_artifact_idx = *opt_a_idx;
         }
 
         ItemMagicApplier(player_ptr, &item, 1, AM_NO_FIXED_ART).execute();
@@ -173,7 +173,7 @@ void generate_amusement(PlayerType *player_ptr, int num, bool known)
 
         if (known) {
             object_aware(player_ptr, &item);
-            object_known(&item);
+            item.mark_as_known();
         }
 
         (void)drop_near(player_ptr, &item, -1, player_ptr->y, player_ptr->x);
@@ -188,23 +188,16 @@ void generate_amusement(PlayerType *player_ptr, int num, bool known)
  * @param x1 配置したいフロアのX座標
  * @param num 獲得の処理回数
  * @param great TRUEならば必ず高級品以上を落とす
- * @param special TRUEならば必ず特別品を落とす
- * @param known TRUEならばオブジェクトが必ず*鑑定*済になる
  */
-void acquirement(PlayerType *player_ptr, POSITION y1, POSITION x1, int num, bool great, bool special, bool known)
+void acquirement(PlayerType *player_ptr, POSITION y1, POSITION x1, int num, bool great)
 {
-    auto mode = AM_GOOD | (great || special ? AM_GREAT : AM_NONE) | (special ? AM_SPECIAL : AM_NONE);
+    auto mode = AM_GOOD | (great ? AM_GREAT : AM_NONE);
     for (auto i = 0; i < num; i++) {
         ItemEntity item;
         if (!make_object(player_ptr, &item, mode)) {
             continue;
         }
 
-        if (known) {
-            object_aware(player_ptr, &item);
-            object_known(&item);
-        }
-
         (void)drop_near(player_ptr, &item, -1, y1, x1);
     }
 }
@@ -247,8 +240,18 @@ bool curse_armor(PlayerType *player_ptr)
     o_ptr->art_flags.clear();
     o_ptr->curse_flags.set(CurseTraitType::CURSED);
     o_ptr->ident |= IDENT_BROKEN;
-    player_ptr->update |= PU_BONUS | PU_MP;
-    player_ptr->window_flags |= PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::MP,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags_swrf);
     return true;
 }
 
@@ -293,8 +296,18 @@ bool curse_weapon_object(PlayerType *player_ptr, bool force, ItemEntity *o_ptr)
     o_ptr->art_flags.clear();
     o_ptr->curse_flags.set(CurseTraitType::CURSED);
     o_ptr->ident |= IDENT_BROKEN;
-    player_ptr->update |= PU_BONUS | PU_MP;
-    player_ptr->window_flags |= PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::MP,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags_swrf);
     return true;
 }
 
@@ -325,7 +338,7 @@ void brand_bolts(PlayerType *player_ptr)
 
         msg_print(_("クロスボウの矢が炎のオーラに包まれた!", "Your bolts are covered in a fiery aura!"));
         o_ptr->ego_idx = EgoType::FLAME;
-        enchant_equipment(player_ptr, o_ptr, randint0(3) + 4, ENCH_TOHIT | ENCH_TODAM);
+        enchant_equipment(o_ptr, randint0(3) + 4, ENCH_TOHIT | ENCH_TODAM);
         return;
     }
 
@@ -357,13 +370,12 @@ static void break_curse(ItemEntity *o_ptr)
 
 /*!
  * @brief 装備修正強化処理
- * @param player_ptr プレイヤーへの参照ポインタ
  * @param o_ptr 強化するアイテムの参照ポインタ
  * @param n 強化基本量
  * @param eflag 強化オプション(命中/ダメージ/AC)
  * @return 強化に成功した場合TRUEを返す
  */
-bool enchant_equipment(PlayerType *player_ptr, ItemEntity *o_ptr, int n, int eflag)
+bool enchant_equipment(ItemEntity *o_ptr, int n, int eflag)
 {
     auto prob = o_ptr->number * 100;
     if (o_ptr->is_ammo()) {
@@ -440,8 +452,21 @@ bool enchant_equipment(PlayerType *player_ptr, ItemEntity *o_ptr, int n, int efl
         return false;
     }
 
-    set_bits(player_ptr->update, PU_BONUS | PU_COMBINATION | PU_REORDER);
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
     return true;
 }
 
@@ -460,11 +485,11 @@ bool enchant_spell(PlayerType *player_ptr, HIT_PROB num_hit, int num_dam, ARMOUR
         item_tester = FuncItemTester(&ItemEntity::is_protector);
     }
 
-    const auto q = _("どのアイテムを強化しますか? ", "Enchant which item? ");
-    const auto s = _("強化できるアイテムがない。", "You have nothing to enchant.");
-    short item;
+    constexpr auto q = _("どのアイテムを強化しますか? ", "Enchant which item? ");
+    constexpr auto s = _("強化できるアイテムがない。", "You have nothing to enchant.");
+    short i_idx;
     const auto options = USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, options, item_tester);
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, item_tester);
     if (!o_ptr) {
         return false;
     }
@@ -473,19 +498,19 @@ bool enchant_spell(PlayerType *player_ptr, HIT_PROB num_hit, int num_dam, ARMOUR
 #ifdef JP
     msg_format("%s は明るく輝いた!", item_name.data());
 #else
-    msg_format("%s %s glow%s brightly!", ((item >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
+    msg_format("%s %s glow%s brightly!", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
 #endif
 
     auto is_enchant_successful = false;
-    if (enchant_equipment(player_ptr, o_ptr, num_hit, ENCH_TOHIT)) {
+    if (enchant_equipment(o_ptr, num_hit, ENCH_TOHIT)) {
         is_enchant_successful = true;
     }
 
-    if (enchant_equipment(player_ptr, o_ptr, num_dam, ENCH_TODAM)) {
+    if (enchant_equipment(o_ptr, num_dam, ENCH_TODAM)) {
         is_enchant_successful = true;
     }
 
-    if (enchant_equipment(player_ptr, o_ptr, num_ac, ENCH_TOAC)) {
+    if (enchant_equipment(o_ptr, num_ac, ENCH_TOAC)) {
         is_enchant_successful = true;
     }
 
@@ -512,11 +537,11 @@ bool enchant_spell(PlayerType *player_ptr, HIT_PROB num_hit, int num_dam, ARMOUR
  */
 void brand_weapon(PlayerType *player_ptr, int brand_type)
 {
-    const auto q = _("どの武器を強化しますか? ", "Enchant which weapon? ");
-    const auto s = _("強化できる武器がない。", "You have nothing to enchant.");
-    short item;
+    constexpr auto q = _("どの武器を強化しますか? ", "Enchant which weapon? ");
+    constexpr auto s = _("強化できる武器がない。", "You have nothing to enchant.");
+    short i_idx;
     const auto options = USE_EQUIP | IGNORE_BOTHHAND_SLOT;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, options, FuncItemTester(&ItemEntity::allow_enchant_melee_weapon));
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, FuncItemTester(&ItemEntity::allow_enchant_melee_weapon));
     if (o_ptr == nullptr) {
         return;
     }
@@ -627,7 +652,7 @@ void brand_weapon(PlayerType *player_ptr, int brand_type)
     }
 
     msg_format(_("あなたの%s%s", "Your %s %s"), item_name.data(), act);
-    enchant_equipment(player_ptr, o_ptr, randint0(3) + 4, ENCH_TOHIT | ENCH_TODAM);
+    enchant_equipment(o_ptr, randint0(3) + 4, ENCH_TOHIT | ENCH_TODAM);
     o_ptr->discount = 99;
     chg_virtue(player_ptr, Virtue::ENCHANT, 2);
     calc_android_exp(player_ptr);
index 8e71d04..99518c4 100644 (file)
@@ -1,11 +1,11 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 class ItemEntity;
 class PlayerType;
 void generate_amusement(PlayerType *player_ptr, int num, bool known);
-void acquirement(PlayerType *player_ptr, POSITION y1, POSITION x1, int num, bool great, bool special, bool known);
+void acquirement(PlayerType *player_ptr, POSITION y1, POSITION x1, int num, bool great);
 bool curse_armor(PlayerType *player_ptr);
 bool curse_weapon_object(PlayerType *player_ptr, bool force, ItemEntity *o_ptr);
 void brand_bolts(PlayerType *player_ptr);
@@ -17,6 +17,6 @@ void brand_bolts(PlayerType *player_ptr);
 #define ENCH_TODAM 0x02 /*!< 装備強化処理: ダメージ強化 / Enchant to damage */
 #define ENCH_TOAC 0x04 /*!< 装備強化処理: AC強化 / Enchant to AC */
 #define ENCH_FORCE 0x08 /*!< 装備強化処理: 無条件に成功させる / Force enchantment */
-bool enchant_equipment(PlayerType *player_ptr, ItemEntity *o_ptr, int n, int eflag);
+bool enchant_equipment(ItemEntity *o_ptr, int n, int eflag);
 bool enchant_spell(PlayerType *player_ptr, HIT_PROB num_hit, int num_dam, ARMOUR_CLASS num_ac);
 void brand_weapon(PlayerType *player_ptr, int brand_type);
index b65fccf..3659006 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell/spells-staff-only.h"
+#include "spell/spells-staff-only.h"
 #include "effect/attribute-types.h"
 #include "effect/effect-characteristics.h"
 #include "effect/effect-processor.h"
index 5a78f1a..6175258 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool cleansing_nova(PlayerType *player_ptr, bool magic, bool powerful);
index f63fe13..5a5c84f 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief スピード等のステータスに影響のある魔法の処理
  * @date 2019/01/22
  * @author deskull
@@ -8,8 +8,6 @@
 #include "avatar/avatar.h"
 #include "cmd-action/cmd-spell.h"
 #include "cmd-item/cmd-magiceat.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "effect/attribute-types.h"
@@ -50,6 +48,7 @@
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-getter.h"
 #include "timed-effect/player-acceleration.h"
 #include "timed-effect/player-cut.h"
@@ -214,9 +213,14 @@ bool time_walk(PlayerType *player_ptr)
     msg_print(nullptr);
 
     player_ptr->energy_need -= 1000 + (100 + player_ptr->csp - 50) * TURNS_PER_TICK / 10;
-    player_ptr->redraw |= (PR_MAP);
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-    player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags);
     handle_stuff(player_ptr);
     return true;
 }
@@ -253,13 +257,11 @@ void roll_hitdice(PlayerType *player_ptr, spell_operation options)
 
     player_ptr->knowledge &= ~(KNOW_HPRATE);
 
-    PERCENTAGE percent = (int)(((long)player_ptr->player_hp[PY_MAX_LEVEL - 1] * 200L) / (2 * player_ptr->hitdie + ((PY_MAX_LEVEL - 1 + 3) * (player_ptr->hitdie + 1))));
-
-    /* Update and redraw hitpoints */
-    player_ptr->update |= (PU_HP);
-    player_ptr->redraw |= (PR_HP);
-    player_ptr->window_flags |= (PW_PLAYER);
-
+    auto percent = (player_ptr->player_hp[PY_MAX_LEVEL - 1] * 200) / (2 * player_ptr->hitdie + ((PY_MAX_LEVEL - 1 + 3) * (player_ptr->hitdie + 1)));
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::HP);
+    rfu.set_flag(MainWindowRedrawingFlag::HP);
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
     if (!(options & SPOP_NO_UPDATE)) {
         handle_stuff(player_ptr);
     }
@@ -463,6 +465,7 @@ bool true_healing(PlayerType *player_ptr, int pow)
 
 bool restore_mana(PlayerType *player_ptr, bool magic_eater)
 {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     if (PlayerClass(player_ptr).equals(PlayerClassType::MAGIC_EATER) && magic_eater) {
         // 魔力復活による、魔道具術師の取り込んだ魔法の回復量
         // 取り込み数が10回未満: 3 回分回復
@@ -484,7 +487,7 @@ bool restore_mana(PlayerType *player_ptr, bool magic_eater)
         }
 
         msg_print(_("頭がハッキリとした。", "You feel your head clear."));
-        player_ptr->window_flags |= (PW_PLAYER);
+        rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
         return true;
     }
 
@@ -495,9 +498,12 @@ bool restore_mana(PlayerType *player_ptr, bool magic_eater)
     player_ptr->csp = player_ptr->msp;
     player_ptr->csp_frac = 0;
     msg_print(_("頭がハッキリとした。", "You feel your head clear."));
-    player_ptr->redraw |= (PR_MP);
-    player_ptr->window_flags |= (PW_PLAYER);
-    player_ptr->window_flags |= (PW_SPELL);
+    rfu.set_flag(MainWindowRedrawingFlag::MP);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::SPELL,
+        SubWindowRedrawingFlag::PLAYER,
+    };
+    rfu.set_flags(flags_swrf);
     return true;
 }
 
@@ -528,26 +534,27 @@ bool restore_all_status(PlayerType *player_ptr)
 bool fishing(PlayerType *player_ptr)
 {
     DIRECTION dir;
-    if (!get_direction(player_ptr, &dir, false, false)) {
+    if (!get_direction(player_ptr, &dir)) {
         return false;
     }
     POSITION y = player_ptr->y + ddy[dir];
     POSITION x = player_ptr->x + ddx[dir];
     player_ptr->fishing_dir = dir;
-    if (!cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::WATER)) {
+    auto *floor_ptr = player_ptr->current_floor_ptr;
+    if (!cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::WATER)) {
         msg_print(_("そこは水辺ではない。", "You can't fish here."));
         return false;
     }
 
-    if (player_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
-        const auto m_name = monster_desc(player_ptr, &player_ptr->current_floor_ptr->m_list[player_ptr->current_floor_ptr->grid_array[y][x].m_idx], 0);
+    if (floor_ptr->grid_array[y][x].m_idx) {
+        const auto m_name = monster_desc(player_ptr, &floor_ptr->m_list[floor_ptr->grid_array[y][x].m_idx], 0);
         msg_format(_("%sが邪魔だ!", "%s^ is standing in your way."), m_name.data());
         PlayerEnergy(player_ptr).reset_player_turn();
         return false;
     }
 
     set_action(player_ptr, ACTION_FISH);
-    player_ptr->redraw |= (PR_ACTION);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
     return true;
 }
 
@@ -665,10 +672,10 @@ void status_shuffle(PlayerType *player_ptr)
         ;
     }
 
-    BASE_STATUS max1 = player_ptr->stat_max[i];
-    BASE_STATUS cur1 = player_ptr->stat_cur[i];
-    BASE_STATUS max2 = player_ptr->stat_max[j];
-    BASE_STATUS cur2 = player_ptr->stat_cur[j];
+    const auto max1 = player_ptr->stat_max[i];
+    const auto cur1 = player_ptr->stat_cur[i];
+    const auto max2 = player_ptr->stat_max[j];
+    const auto cur2 = player_ptr->stat_cur[j];
 
     player_ptr->stat_max[i] = max2;
     player_ptr->stat_cur[i] = cur2;
@@ -684,5 +691,5 @@ void status_shuffle(PlayerType *player_ptr)
         }
     }
 
-    player_ptr->update |= PU_BONUS;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
 }
index 7af40eb..467b2f3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "spell/spells-util.h"
 #include "system/angband.h"
index c8e2c3a..33e1317 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell/spells-summon.h"
+#include "spell/spells-summon.h"
 #include "avatar/avatar.h"
 #include "effect/spells-effect-util.h"
 #include "floor/floor-object.h"
@@ -216,11 +216,10 @@ bool cast_summon_octopus(PlayerType *player_ptr)
  */
 bool cast_summon_greater_demon(PlayerType *player_ptr)
 {
-    concptr q = _("どの死体を捧げますか? ", "Sacrifice which corpse? ");
-    concptr s = _("捧げられる死体を持っていない。", "You have nothing to sacrifice.");
-    OBJECT_IDX item;
-    ItemEntity *o_ptr;
-    o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::is_offerable));
+    constexpr auto q = _("どの死体を捧げますか? ", "Sacrifice which corpse? ");
+    constexpr auto s = _("捧げられる死体を持っていない。", "You have nothing to sacrifice.");
+    short i_idx;
+    const auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::is_offerable));
     if (!o_ptr) {
         return false;
     }
@@ -232,7 +231,7 @@ bool cast_summon_greater_demon(PlayerType *player_ptr)
     if (summon_specific(player_ptr, -1, player_ptr->y, player_ptr->x, summon_lev, SUMMON_HI_DEMON, (PM_ALLOW_GROUP | PM_FORCE_PET))) {
         msg_print(_("硫黄の悪臭が充満した。", "The area fills with a stench of sulphur and brimstone."));
         msg_print(_("「ご用でございますか、ご主人様」", "'What is thy bidding... Master?'"));
-        vary_item(player_ptr, item, -1);
+        vary_item(player_ptr, i_idx, -1);
     } else {
         msg_print(_("悪魔は現れなかった。", "No Greater Demon arrives."));
     }
index a903e06..c5ac9fc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b226171..0cc2c06 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #define DETECT_RAD_DEFAULT 30
 #define DETECT_RAD_MAP 30
index 5a6f4ee..8d1a149 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* summon_specificで取り扱われる、召喚の種別定義 / Legal restrictions for "summon_specific()" */
 enum summon_type : int {
@@ -53,4 +53,5 @@ enum summon_type : int {
     SUMMON_APOCRYPHA_DRAGONS = 69, /*!< 召喚タイプ: 強力な古代ドラゴン */
     SUMMON_VESPOID = 70, /*!< 召喚タイプ: ランゴスタ */
     SUMMON_ANTI_TIGERS = 71, /*!< 召喚タイプ: トラ以外 */
+    SUMMON_DEAD_UNIQUE = 72, /*!< 召喚タイプ: 撃破済みユニーク */
 };
index 6ac5dbd..00b4784 100644 (file)
@@ -1,4 +1,4 @@
-#include "spell/technic-info-table.h"
+#include "spell/technic-info-table.h"
 
 /*!
  * @brief 歌、剣術、呪術領域情報テーブル
index 53f97e4..4fce9f7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "realm/realm-types.h"
 #include "system/angband.h"
index 4d91328..e9573c7 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーの継続行動処理
  * @date 2014/01/01
  * @author
@@ -12,8 +12,6 @@
  */
 
 #include "status/action-setter.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "player-base/player-class.h"
 #include "player-info/bluemage-data-type.h"
 #include "player-info/monk-data-type.h"
 #include "spell-realm/spells-hex.h"
 #include "spell-realm/spells-song.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
  * @brief プレイヤーの継続行動を設定する。
- * @param typ 継続行動のID\n
- * #ACTION_NONE / #ACTION_SEARCH / #ACTION_REST / #ACTION_LEARN / #ACTION_FISH / #ACTION_MONK_STANCE / #ACTION_SAMURAI_STANCE / #ACTION_SING / #ACTION_HAYAGAKE / #ACTION_SPELL
+ * @param typ 継続行動のID
+ * NONE / SEARCH / REST / LEARN / FISH / MONK_STANCE / SAMURAI_STANCE / SING / HAYAGAKE / SPELL
  * から選択。
  */
 void set_action(PlayerType *player_ptr, uint8_t typ)
 {
-    int prev_typ = player_ptr->action;
+    auto prev_typ = player_ptr->action;
     if (typ == prev_typ) {
         return;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     switch (prev_typ) {
-    case ACTION_SEARCH: {
+    case ACTION_SEARCH:
         msg_print(_("探索をやめた。", "You no longer walk carefully."));
-        player_ptr->redraw |= (PR_SPEED);
+        rfu.set_flag(MainWindowRedrawingFlag::SPEED);
         break;
-    }
-    case ACTION_REST: {
+    case ACTION_REST:
         player_ptr->resting = 0;
         break;
-    }
     case ACTION_LEARN: {
         msg_print(_("学習をやめた。", "You stop learning."));
         auto bluemage_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
         bluemage_data->new_magic_learned = false;
         break;
     }
-    case ACTION_MONK_STANCE: {
+    case ACTION_MONK_STANCE:
         msg_print(_("構えをといた。", "You stop assuming the special stance."));
         PlayerClass(player_ptr).set_monk_stance(MonkStanceType::NONE);
         break;
-    }
-    case ACTION_SAMURAI_STANCE: {
+    case ACTION_SAMURAI_STANCE:
         msg_print(_("型を崩した。", "You stop assuming the special stance."));
         PlayerClass(player_ptr).set_samurai_stance(SamuraiStanceType::NONE);
-        player_ptr->update |= (PU_MONSTER_STATUSES);
-        player_ptr->redraw |= (PR_TIMED_EFFECT);
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+        rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
         break;
-    }
-    case ACTION_SING: {
+    case ACTION_SING:
         msg_print(_("歌うのをやめた。", "You stop singing."));
         break;
-    }
-    case ACTION_HAYAGAKE: {
+    case ACTION_HAYAGAKE:
         msg_print(_("足が重くなった。", "You are no longer walking extremely fast."));
         PlayerEnergy(player_ptr).set_player_turn_energy(100);
         break;
-    }
-    case ACTION_SPELL: {
+    case ACTION_SPELL:
         msg_print(_("呪文の詠唱を中断した。", "You stopped casting."));
         break;
     }
-    }
 
     player_ptr->action = typ;
 
@@ -97,28 +90,23 @@ void set_action(PlayerType *player_ptr, uint8_t typ)
     }
 
     switch (player_ptr->action) {
-    case ACTION_SEARCH: {
+    case ACTION_SEARCH:
         msg_print(_("注意深く歩き始めた。", "You begin to walk carefully."));
-        player_ptr->redraw |= (PR_SPEED);
+        rfu.set_flag(MainWindowRedrawingFlag::SPEED);
         break;
-    }
-    case ACTION_LEARN: {
+    case ACTION_LEARN:
         msg_print(_("学習を始めた。", "You begin learning"));
         break;
-    }
-    case ACTION_FISH: {
+    case ACTION_FISH:
         msg_print(_("水面に糸を垂らした...", "You begin fishing..."));
         break;
-    }
-    case ACTION_HAYAGAKE: {
+    case ACTION_HAYAGAKE:
         msg_print(_("足が羽のように軽くなった。", "You begin to walk extremely fast."));
         break;
-    }
-    default: {
+    default:
         break;
     }
-    }
 
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->redraw |= (PR_ACTION);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(MainWindowRedrawingFlag::ACTION);
 }
index 1b5ae6b..d49ad7f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <stdint.h>
 
index ecfb6a1..abd3e5d 100644 (file)
@@ -1,8 +1,6 @@
-#include "status/bad-status-setter.h"
+#include "status/bad-status-setter.h"
 #include "avatar/avatar.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "game-option/disturbance-options.h"
@@ -18,7 +16,9 @@
 #include "spell-realm/spells-hex.h"
 #include "status/base-status.h"
 #include "status/buff-setter.h"
+#include "system/angband-exceptions.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/player-confusion.h"
 #include "timed-effect/player-cut.h"
@@ -83,7 +83,8 @@ bool BadStatusSetter::set_blindness(const TIME_EFFECT tmp_v)
     }
 
     blindness->set(v);
-    this->player_ptr->redraw |= PR_TIMED_EFFECT;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -92,9 +93,21 @@ bool BadStatusSetter::set_blindness(const TIME_EFFECT tmp_v)
         disturb(this->player_ptr, false, false);
     }
 
-    this->player_ptr->update |= PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_MONSTER_STATUSES | PU_MONSTER_LITE;
-    this->player_ptr->redraw |= PR_MAP;
-    this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::UN_VIEW,
+        StatusRecalculatingFlag::UN_LITE,
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+        StatusRecalculatingFlag::MONSTER_LITE,
+    };
+    rfu.set_flags(flags_srf);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
     handle_stuff(this->player_ptr);
     return true;
 }
@@ -117,24 +130,23 @@ bool BadStatusSetter::set_confusion(const TIME_EFFECT tmp_v)
         return false;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     auto is_confused = this->player_confusion->is_confused();
     if (v > 0) {
         if (!is_confused) {
             msg_print(_("あなたは混乱した!", "You are confused!"));
-
             if (this->player_ptr->action == ACTION_LEARN) {
                 msg_print(_("学習が続けられない!", "You cannot continue learning!"));
                 auto bluemage_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
                 bluemage_data->new_magic_learned = false;
-
-                this->player_ptr->redraw |= PR_ACTION;
+                rfu.set_flag(MainWindowRedrawingFlag::ACTION);
                 this->player_ptr->action = ACTION_NONE;
             }
             if (this->player_ptr->action == ACTION_MONK_STANCE) {
                 msg_print(_("構えがとけた。", "You lose your stance."));
                 PlayerClass(player_ptr).set_monk_stance(MonkStanceType::NONE);
-                this->player_ptr->update |= PU_BONUS;
-                this->player_ptr->redraw |= PR_ACTION;
+                rfu.set_flag(StatusRecalculatingFlag::BONUS);
+                rfu.set_flag(MainWindowRedrawingFlag::ACTION);
                 this->player_ptr->action = ACTION_NONE;
             } else if (this->player_ptr->action == ACTION_SAMURAI_STANCE) {
                 msg_print(_("型が崩れた。", "You lose your stance."));
@@ -162,7 +174,7 @@ bool BadStatusSetter::set_confusion(const TIME_EFFECT tmp_v)
     }
 
     this->player_confusion->set(v);
-    this->player_ptr->redraw |= PR_TIMED_EFFECT;
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -208,7 +220,7 @@ bool BadStatusSetter::set_poison(const TIME_EFFECT tmp_v)
     }
 
     player_poison->set(v);
-    this->player_ptr->redraw |= PR_TIMED_EFFECT;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -259,7 +271,7 @@ bool BadStatusSetter::set_fear(const TIME_EFFECT tmp_v)
     }
 
     fear->set(v);
-    this->player_ptr->redraw |= PR_TIMED_EFFECT;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -312,7 +324,7 @@ bool BadStatusSetter::set_paralysis(const TIME_EFFECT tmp_v)
     }
 
     paralysis->set(v);
-    this->player_ptr->redraw |= PR_TIMED_EFFECT;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -321,7 +333,7 @@ bool BadStatusSetter::set_paralysis(const TIME_EFFECT tmp_v)
         disturb(this->player_ptr, false, false);
     }
 
-    this->player_ptr->redraw |= PR_ACTION;
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
     handle_stuff(this->player_ptr);
     return true;
 }
@@ -367,7 +379,8 @@ bool BadStatusSetter::hallucination(const TIME_EFFECT tmp_v)
     }
 
     hallucination->set(v);
-    this->player_ptr->redraw |= PR_TIMED_EFFECT;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -376,9 +389,18 @@ bool BadStatusSetter::hallucination(const TIME_EFFECT tmp_v)
         disturb(this->player_ptr, false, true);
     }
 
-    this->player_ptr->redraw |= PR_MAP | PR_HEALTH | PR_UHEALTH;
-    this->player_ptr->update |= PU_MONSTER_STATUSES;
-    this->player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::MAP,
+        MainWindowRedrawingFlag::HEALTH,
+        MainWindowRedrawingFlag::UHEALTH,
+    };
+    rfu.set_flags(flags_mwrf);
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
     handle_stuff(this->player_ptr);
     return true;
 }
@@ -429,7 +451,7 @@ bool BadStatusSetter::set_deceleration(const TIME_EFFECT tmp_v, bool do_dec)
         disturb(this->player_ptr, false, false);
     }
 
-    this->player_ptr->update |= PU_BONUS;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(this->player_ptr);
     return true;
 }
@@ -467,8 +489,9 @@ bool BadStatusSetter::set_stun(const TIME_EFFECT tmp_v)
         disturb(this->player_ptr, false, false);
     }
 
-    this->player_ptr->update |= PU_BONUS;
-    this->player_ptr->redraw |= PR_STUN;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(MainWindowRedrawingFlag::STUN);
     handle_stuff(this->player_ptr);
     return true;
 }
@@ -506,8 +529,9 @@ bool BadStatusSetter::set_cut(const TIME_EFFECT tmp_v)
         disturb(this->player_ptr, false, false);
     }
 
-    this->player_ptr->update |= PU_BONUS;
-    this->player_ptr->redraw |= PR_CUT;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(MainWindowRedrawingFlag::CUT);
     handle_stuff(this->player_ptr);
     return true;
 }
@@ -600,7 +624,7 @@ void BadStatusSetter::decrease_int_wis(const short v)
 
         return;
     default:
-        throw("Invalid random number is specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid random number is specified!");
     }
 }
 
@@ -624,8 +648,7 @@ bool BadStatusSetter::process_cut_effect(const short v)
 
 void BadStatusSetter::decrease_charisma(const PlayerCutRank new_rank, const short v)
 {
-    auto player_cut = this->player_ptr->effects()->cut();
-    auto cut_mes = player_cut->get_cut_mes(new_rank);
+    auto cut_mes = PlayerCut::get_cut_mes(new_rank);
     msg_print(cut_mes);
     if (v <= randint1(1000) && !one_in_(16)) {
         return;
index 45da3bf..43c70b6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <memory>
index e11abfa..5865af9 100644 (file)
@@ -1,7 +1,5 @@
-#include "status/base-status.h"
+#include "status/base-status.h"
 #include "avatar/avatar.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "game-option/birth-options.h"
 #include "inventory/inventory-slot-types.h"
 #include "spell-kind/spells-floor.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
 
 /* Array of stat "descriptions" */
-static concptr desc_stat_pos[] = { _("強く", "stronger"), _("知的に", "smarter"), _("賢く", "wiser"), _("器用に", "more dextrous"), _("健康に", "healthier"), _("美しく", "cuter") };
+static concptr desc_stat_pos[] = {
+    _("強く", "stronger"),
+    _("知的に", "smarter"),
+    _("賢く", "wiser"),
+    _("器用に", "more dextrous"),
+    _("健康に", "healthier"),
+    _("美しく", "cuter")
+};
 
 /* Array of stat "descriptions" */
-static concptr desc_stat_neg[] = { _("弱く", "weaker"), _("無知に", "stupider"), _("愚かに", "more naive"), _("不器用に", "clumsier"), _("不健康に", "more sickly"), _("醜く", "uglier") };
+static concptr desc_stat_neg[] = {
+    _("弱く", "weaker"),
+    _("無知に", "stupider"),
+    _("愚かに", "more naive"),
+    _("不器用に", "clumsier"),
+    _("不健康に", "more sickly"),
+    _("醜く", "uglier")
+};
 
 /*!
  * @brief プレイヤーの基本能力値を増加させる / Increases a stat by one randomized level -RAK-
@@ -31,17 +44,15 @@ static concptr desc_stat_neg[] = { _("弱く", "weaker"), _("無知に", "stupid
  */
 bool inc_stat(PlayerType *player_ptr, int stat)
 {
-    BASE_STATUS gain;
-    BASE_STATUS value = player_ptr->stat_cur[stat];
+    auto value = player_ptr->stat_cur[stat];
     if (value >= player_ptr->stat_max_max[stat]) {
         return false;
     }
 
     if (value < 18) {
-        gain = ((randint0(100) < 75) ? 1 : 2);
-        value += gain;
+        value += (randint0(100) < 75) ? 1 : 2;
     } else if (value < (player_ptr->stat_max_max[stat] - 2)) {
-        gain = (((player_ptr->stat_max_max[stat]) - value) / 2 + 3) / 2;
+        auto gain = (((player_ptr->stat_max_max[stat]) - value) / 2 + 3) / 2;
         if (gain < 1) {
             gain = 1;
         }
@@ -59,7 +70,7 @@ bool inc_stat(PlayerType *player_ptr, int stat)
         player_ptr->stat_max[stat] = value;
     }
 
-    player_ptr->update |= PU_BONUS;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     return true;
 }
 
@@ -82,9 +93,9 @@ bool inc_stat(PlayerType *player_ptr, int stat)
  */
 bool dec_stat(PlayerType *player_ptr, int stat, int amount, int permanent)
 {
-    bool res = false;
-    BASE_STATUS cur = player_ptr->stat_cur[stat];
-    BASE_STATUS max = player_ptr->stat_max[stat];
+    auto res = false;
+    auto cur = player_ptr->stat_cur[stat];
+    auto max = player_ptr->stat_max[stat];
     int same = (cur == max);
     if (cur > 3) {
         if (cur <= 18) {
@@ -166,8 +177,9 @@ bool dec_stat(PlayerType *player_ptr, int stat, int amount, int permanent)
     if (res) {
         player_ptr->stat_cur[stat] = cur;
         player_ptr->stat_max[stat] = max;
-        player_ptr->redraw |= (PR_ABILITY_SCORE);
-        player_ptr->update |= (PU_BONUS);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
     }
 
     return res;
@@ -182,8 +194,9 @@ bool res_stat(PlayerType *player_ptr, int stat)
 {
     if (player_ptr->stat_cur[stat] != player_ptr->stat_max[stat]) {
         player_ptr->stat_cur[stat] = player_ptr->stat_max[stat];
-        player_ptr->update |= (PU_BONUS);
-        player_ptr->redraw |= (PR_ABILITY_SCORE);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(StatusRecalculatingFlag::BONUS);
+        rfu.set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
         return true;
     }
 
@@ -303,8 +316,21 @@ bool lose_all_info(PlayerType *player_ptr)
         o_ptr->ident &= ~(IDENT_SENSE);
     }
 
-    set_bits(player_ptr->update, PU_BONUS | PU_COMBINATION | PU_REORDER);
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
     wiz_dark(player_ptr);
     return true;
 }
index ea31c06..301f7be 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 bool inc_stat(PlayerType *player_ptr, int stat);
index 92fad3d..19a2ff1 100644 (file)
@@ -1,8 +1,6 @@
-#include "status/body-improvement.h"
+#include "status/body-improvement.h"
 #include "avatar/avatar.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
@@ -11,6 +9,7 @@
 #include "realm/realm-song-numbers.h"
 #include "spell-realm/spells-song.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -46,7 +45,7 @@ bool set_protevil(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->protevil = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
 
     if (!notice) {
         return false;
@@ -76,6 +75,11 @@ bool set_invuln(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         return false;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
     if (v) {
         if (player_ptr->invuln && !do_dec) {
             if (player_ptr->invuln > v) {
@@ -84,33 +88,27 @@ bool set_invuln(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         } else if (!is_invuln(player_ptr)) {
             msg_print(_("無敵だ!", "Invulnerability!"));
             notice = true;
-
             chg_virtue(player_ptr, Virtue::UNLIFE, -2);
             chg_virtue(player_ptr, Virtue::HONOUR, -2);
             chg_virtue(player_ptr, Virtue::SACRIFICE, -3);
             chg_virtue(player_ptr, Virtue::VALOUR, -5);
-
-            player_ptr->redraw |= (PR_MAP);
-            player_ptr->update |= (PU_MONSTER_STATUSES);
-
-            player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+            rfu.set_flag(MainWindowRedrawingFlag::MAP);
+            rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+            rfu.set_flags(flags_swrf);
         }
     } else {
         if (player_ptr->invuln && !music_singing(player_ptr, MUSIC_INVULN)) {
             msg_print(_("無敵ではなくなった。", "The invulnerability wears off."));
             notice = true;
-
-            player_ptr->redraw |= (PR_MAP);
-            player_ptr->update |= (PU_MONSTER_STATUSES);
-
-            player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
-
+            rfu.set_flag(MainWindowRedrawingFlag::MAP);
+            rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+            rfu.set_flags(flags_swrf);
             player_ptr->energy_need += ENERGY_NEED();
         }
     }
 
     player_ptr->invuln = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
 
     if (!notice) {
         return false;
@@ -120,7 +118,7 @@ bool set_invuln(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         disturb(player_ptr, false, false);
     }
 
-    player_ptr->update |= (PU_BONUS);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -158,8 +156,8 @@ bool set_tim_regen(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_regen = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -168,7 +166,7 @@ bool set_tim_regen(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         disturb(player_ptr, false, false);
     }
 
-    player_ptr->update |= (PU_BONUS);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -206,8 +204,8 @@ bool set_tim_reflect(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_reflect = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -216,7 +214,7 @@ bool set_tim_reflect(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         disturb(player_ptr, false, false);
     }
 
-    player_ptr->update |= (PU_BONUS);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -254,8 +252,8 @@ bool set_pass_wall(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_pass_wall = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -264,7 +262,7 @@ bool set_pass_wall(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         disturb(player_ptr, false, false);
     }
 
-    player_ptr->update |= (PU_BONUS);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
index 67114a7..b63832b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 1eb4c25..b09c0e1 100644 (file)
@@ -1,8 +1,6 @@
-#include "status/buff-setter.h"
+#include "status/buff-setter.h"
 #include "avatar/avatar.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/speed-table.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
@@ -19,6 +17,7 @@
 #include "status/buff-setter.h"
 #include "status/element-resistance.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-acceleration.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/player-confusion.h"
@@ -143,9 +142,13 @@ bool set_acceleration(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
             chg_virtue(player_ptr, Virtue::DILIGENCE, 1);
         }
     } else {
-        if (acceleration->is_fast() && !player_ptr->lightspeed && !music_singing(player_ptr, MUSIC_SPEED) && !music_singing(player_ptr, MUSIC_SHERO)) {
-            msg_print(_("動きの素早さがなくなったようだ。", "You feel yourself slow down."));
-            notice = true;
+        if (acceleration->is_fast() && !player_ptr->lightspeed) {
+            auto is_singing = music_singing(player_ptr, MUSIC_SPEED);
+            is_singing |= music_singing(player_ptr, MUSIC_SHERO);
+            if (!is_singing) {
+                msg_print(_("動きの素早さがなくなったようだ。", "You feel yourself slow down."));
+                notice = true;
+            }
         }
     }
 
@@ -157,7 +160,7 @@ bool set_acceleration(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -200,8 +203,8 @@ bool set_shield(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->shield = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -209,7 +212,8 @@ bool set_shield(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -247,8 +251,8 @@ bool set_magicdef(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->magicdef = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -256,7 +260,8 @@ bool set_magicdef(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -294,8 +299,8 @@ bool set_blessed(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->blessed = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -303,7 +308,8 @@ bool set_blessed(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -341,8 +347,8 @@ bool set_hero(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->hero = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -350,8 +356,12 @@ bool set_hero(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->update |= (PU_HP);
+
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     handle_stuff(player_ptr);
     return true;
 }
@@ -406,9 +416,17 @@ bool set_mimic(PlayerType *player_ptr, TIME_EFFECT v, MimicKindType mimic_race_i
         disturb(player_ptr, false, true);
     }
 
-    player_ptr->redraw |= (PR_BASIC | PR_TIMED_EFFECT);
-    player_ptr->update |= (PU_BONUS | PU_HP);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::TIMED_EFFECT,
+    };
+    rfu.set_flags(flags_mwrf);
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+    };
+    rfu.set_flags(flags_srf);
     handle_stuff(player_ptr);
     return true;
 }
@@ -451,8 +469,8 @@ bool set_shero(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->shero = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -460,8 +478,12 @@ bool set_shero(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->update |= (PU_HP);
+
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+    };
+    RedrawingFlagsUpdater::get_instance().set_flags(flags);
     handle_stuff(player_ptr);
     return true;
 }
@@ -482,6 +504,11 @@ bool set_wraith_form(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
         return false;
     }
 
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
     if (v) {
         if (player_ptr->wraith_form && !do_dec) {
             if (player_ptr->wraith_form > v) {
@@ -494,27 +521,22 @@ bool set_wraith_form(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
             chg_virtue(player_ptr, Virtue::HONOUR, -2);
             chg_virtue(player_ptr, Virtue::SACRIFICE, -2);
             chg_virtue(player_ptr, Virtue::VALOUR, -5);
-
-            player_ptr->redraw |= (PR_MAP);
-            player_ptr->update |= (PU_MONSTER_STATUSES);
-
-            player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+            rfu.set_flag(MainWindowRedrawingFlag::MAP);
+            rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+            rfu.set_flags(flags_swrf);
         }
     } else {
         if (player_ptr->wraith_form) {
             msg_print(_("不透明になった感じがする。", "You feel opaque."));
             notice = true;
-
-            player_ptr->redraw |= (PR_MAP);
-            player_ptr->update |= (PU_MONSTER_STATUSES);
-
-            player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+            rfu.set_flag(MainWindowRedrawingFlag::MAP);
+            rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+            rfu.set_flags(flags_swrf);
         }
     }
 
     player_ptr->wraith_form = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -522,7 +544,8 @@ bool set_wraith_form(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -566,8 +589,8 @@ bool set_tsuyoshi(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tsuyoshi = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -575,8 +598,12 @@ bool set_tsuyoshi(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->update |= (PU_HP);
+
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+    };
+    rfu.set_flags(flags);
     handle_stuff(player_ptr);
     return true;
 }
index bf549e8..ae7e0f0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e1f4097..997deef 100644 (file)
@@ -1,6 +1,5 @@
-#include "status/element-resistance.h"
+#include "status/element-resistance.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "core/stuff-handler.h"
 #include "game-option/disturbance-options.h"
 #include "player-base/player-class.h"
@@ -11,6 +10,7 @@
 #include "realm/realm-song-numbers.h"
 #include "spell-realm/spells-song.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -46,15 +46,15 @@ bool set_oppose_acid(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->oppose_acid = v;
-
     if (!notice) {
         return false;
     }
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
 
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
+
     handle_stuff(player_ptr);
     return true;
 }
@@ -93,15 +93,15 @@ bool set_oppose_elec(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->oppose_elec = v;
-
     if (!notice) {
         return false;
     }
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
 
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
+
     handle_stuff(player_ptr);
     return true;
 }
@@ -142,15 +142,15 @@ bool set_oppose_fire(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->oppose_fire = v;
-
     if (!notice) {
         return false;
     }
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
 
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
+
     handle_stuff(player_ptr);
     return true;
 }
@@ -188,15 +188,15 @@ bool set_oppose_cold(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->oppose_cold = v;
-
     if (!notice) {
         return false;
     }
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
 
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
+
     handle_stuff(player_ptr);
     return true;
 }
@@ -241,37 +241,56 @@ bool set_oppose_pois(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (!notice) {
         return false;
     }
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
 
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
+
     handle_stuff(player_ptr);
     return true;
 }
 
 bool is_oppose_acid(PlayerType *player_ptr)
 {
-    return player_ptr->oppose_acid || music_singing(player_ptr, MUSIC_RESIST) || PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU);
+    auto can_oppose_acid = player_ptr->oppose_acid != 0;
+    can_oppose_acid |= music_singing(player_ptr, MUSIC_RESIST);
+    can_oppose_acid |= PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU);
+    return can_oppose_acid;
 }
 
 bool is_oppose_elec(PlayerType *player_ptr)
 {
-    return player_ptr->oppose_elec || music_singing(player_ptr, MUSIC_RESIST) || PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU);
+    auto can_oppose_elec = player_ptr->oppose_elec != 0;
+    can_oppose_elec |= music_singing(player_ptr, MUSIC_RESIST);
+    can_oppose_elec |= PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU);
+    return can_oppose_elec;
 }
 
 bool is_oppose_fire(PlayerType *player_ptr)
 {
-    return player_ptr->oppose_fire || music_singing(player_ptr, MUSIC_RESIST) || (PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU) || (player_ptr->mimic_form == MimicKindType::DEMON) || (PlayerRace(player_ptr).equals(PlayerRaceType::BALROG) && player_ptr->lev > 44));
+    auto can_oppose_fire = player_ptr->oppose_fire != 0;
+    can_oppose_fire |= music_singing(player_ptr, MUSIC_RESIST);
+    can_oppose_fire |= PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU);
+    can_oppose_fire |= player_ptr->mimic_form == MimicKindType::DEMON;
+    can_oppose_fire |= (PlayerRace(player_ptr).equals(PlayerRaceType::BALROG) && player_ptr->lev > 44);
+    return can_oppose_fire;
 }
 
 bool is_oppose_cold(PlayerType *player_ptr)
 {
-    return player_ptr->oppose_cold || music_singing(player_ptr, MUSIC_RESIST) || PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU);
+    auto can_oppose_cold = player_ptr->oppose_cold != 0;
+    can_oppose_cold |= music_singing(player_ptr, MUSIC_RESIST);
+    can_oppose_cold |= PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU);
+    return can_oppose_cold;
 }
 
 bool is_oppose_pois(PlayerType *player_ptr)
 {
     PlayerClass pc(player_ptr);
-    return player_ptr->oppose_pois || music_singing(player_ptr, MUSIC_RESIST) || pc.samurai_stance_is(SamuraiStanceType::MUSOU) || pc.has_poison_resistance();
+    auto can_oppose_pois = player_ptr->oppose_pois != 0;
+    can_oppose_pois |= music_singing(player_ptr, MUSIC_RESIST);
+    can_oppose_pois |= pc.samurai_stance_is(SamuraiStanceType::MUSOU);
+    can_oppose_pois |= pc.has_poison_resistance();
+    return can_oppose_pois;
 }
index af8f57d..ca71cbf 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index f7f7f97..5f7ef08 100644 (file)
@@ -1,4 +1,4 @@
-#include "status/experience.h"
+#include "status/experience.h"
 #include "player-base/player-race.h"
 #include "player/player-status.h"
 #include "system/player-type-definition.h"
index 978a7f2..9812be2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index b1f8234..6484336 100644 (file)
@@ -1,11 +1,9 @@
-#include "status/shape-changer.h"
+#include "status/shape-changer.h"
 #include "autopick/autopick-reader-writer.h"
 #include "avatar/avatar.h"
 #include "birth/birth-body-spec.h"
 #include "birth/birth-stat.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "game-option/disturbance-options.h"
 #include "grid/grid.h"
@@ -24,6 +22,7 @@
 #include "status/bad-status-setter.h"
 #include "status/base-status.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-cut.h"
 #include "timed-effect/timed-effects.h"
 #include "util/enum-converter.h"
@@ -97,8 +96,9 @@ void change_race(PlayerType *player_ptr, PlayerRaceType new_race, concptr effect
 
     roll_hitdice(player_ptr, SPOP_NONE);
     check_experience(player_ptr);
-    player_ptr->redraw |= (PR_BASIC);
-    player_ptr->update |= (PU_BONUS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::BASIC);
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
 
     if (old_race != player_ptr->prace) {
index 2c16077..b891999 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-info/race-types.h"
 #include "system/angband.h"
index 6baa340..26c4206 100644 (file)
@@ -1,15 +1,35 @@
-#include "status/sight-setter.h"
+#include "status/sight-setter.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "game-option/disturbance-options.h"
 #include "player/player-status.h"
 #include "realm/realm-song-numbers.h"
 #include "spell-realm/spells-song.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
+static bool update_sight(PlayerType *player_ptr, const bool notice)
+{
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
+    if (!notice) {
+        return false;
+    }
+
+    if (disturb_state) {
+        disturb(player_ptr, false, false);
+    }
+
+    static constexpr auto flags = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags);
+    handle_stuff(player_ptr);
+    return true;
+}
+
 /*!
  * @brief 時限ESPの継続時間をセットする / Set "tim_esp", notice observable changes
  * @param v 継続時間
@@ -43,19 +63,7 @@ bool set_tim_esp(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_esp = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
-    if (!notice) {
-        return false;
-    }
-
-    if (disturb_state) {
-        disturb(player_ptr, false, false);
-    }
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-    handle_stuff(player_ptr);
-    return true;
+    return update_sight(player_ptr, notice);
 }
 
 /*!
@@ -91,19 +99,7 @@ bool set_tim_invis(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_invis = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
-    if (!notice) {
-        return false;
-    }
-
-    if (disturb_state) {
-        disturb(player_ptr, false, false);
-    }
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-    handle_stuff(player_ptr);
-    return true;
+    return update_sight(player_ptr, notice);
 }
 
 /*!
@@ -139,17 +135,5 @@ bool set_tim_infra(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_infra = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
-    if (!notice) {
-        return false;
-    }
-
-    if (disturb_state) {
-        disturb(player_ptr, false, false);
-    }
-    player_ptr->update |= (PU_BONUS);
-    player_ptr->update |= (PU_MONSTER_STATUSES);
-    handle_stuff(player_ptr);
-    return true;
+    return update_sight(player_ptr, notice);
 }
index 1bb7180..dc07616 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index a1411cc..052a374 100644 (file)
@@ -1,10 +1,9 @@
-#include "status/temporary-resistance.h"
+#include "status/temporary-resistance.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "game-option/disturbance-options.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "view/display-messages.h"
 
 /*!
@@ -40,8 +39,8 @@ bool set_tim_levitation(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_levitation = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -49,7 +48,8 @@ bool set_tim_levitation(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -73,9 +73,7 @@ bool set_ultimate_res(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
             msg_print(_("あらゆることに対して耐性がついた気がする!", "You feel resistant!"));
             notice = true;
         }
-    }
-
-    else {
+    } else {
         if (player_ptr->ult_res) {
             msg_print(_("あらゆることに対する耐性が薄れた気がする。", "You feel less resistant"));
             notice = true;
@@ -83,8 +81,8 @@ bool set_ultimate_res(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->ult_res = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -92,9 +90,9 @@ bool set_ultimate_res(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
-    handle_stuff(player_ptr);
 
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    handle_stuff(player_ptr);
     return true;
 }
 
@@ -127,8 +125,8 @@ bool set_tim_res_nether(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_res_nether = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -136,7 +134,8 @@ bool set_tim_res_nether(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
@@ -167,7 +166,8 @@ bool set_tim_res_time(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     }
 
     player_ptr->tim_res_time = v;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (!notice) {
         return false;
     }
@@ -175,7 +175,8 @@ bool set_tim_res_time(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
     if (disturb_state) {
         disturb(player_ptr, false, false);
     }
-    player_ptr->update |= (PU_BONUS);
+
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
     handle_stuff(player_ptr);
     return true;
 }
index 416f8a8..26bfe88 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index d1303f3..fd4f341 100644 (file)
@@ -1 +1 @@
-#include "stdafx.h"
+#include "stdafx.h"
index 5695a33..d152533 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include <algorithm>
 #include <array>
 #include <bitset>
index 140b6a0..36568f4 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/articles-on-sale.h"
+#include "store/articles-on-sale.h"
 #include "object/tval-types.h"
 #include "store/store-owners.h"
 #include "sv-definition/sv-amulet-types.h"
index 767bc92..4686d83 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <map>
 #include <vector>
index b15238b..7cbd2ab 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/black-market.h"
+#include "store/black-market.h"
 #include "floor/floor-town.h"
 #include "store/store-owners.h"
 #include "store/store-util.h"
@@ -40,7 +40,7 @@ bool black_market_crap(PlayerType *player_ptr, ItemEntity *o_ptr)
             continue;
         }
 
-        const auto &store = towns_info[player_ptr->town_num].store[enum2i(sst)];
+        const auto &store = towns_info[player_ptr->town_num].stores[sst];
         for (auto j = 0; j < store.stock_num; j++) {
             if (o_ptr->bi_id == store.stock[j].bi_id) {
                 return true;
index 1ea403a..27b623e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index a75b1e1..2626a33 100644 (file)
@@ -1,7 +1,5 @@
-#include "store/cmd-store.h"
+#include "store/cmd-store.h"
 #include "cmd-io/macro-util.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
@@ -27,6 +25,7 @@
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
@@ -57,15 +56,13 @@ void do_cmd_store(PlayerType *player_ptr)
         return;
     }
     TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, std::nullopt);
-    TERM_LEN w, h;
-    term_get_size(&w, &h);
-
-    xtra_stock = std::min(14 + 26, ((h > MAIN_TERM_MIN_ROWS) ? (h - MAIN_TERM_MIN_ROWS) : 0));
+    const auto &[wid, hgt] = term_get_size();
+    xtra_stock = std::min(14 + 26, ((hgt > MAIN_TERM_MIN_ROWS) ? (hgt - MAIN_TERM_MIN_ROWS) : 0));
     store_bottom = MIN_STOCK + xtra_stock;
 
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    const auto *g_ptr = &floor_ptr->grid_array[player_ptr->y][player_ptr->x];
-    if (!g_ptr->cave_has_flag(TerrainCharacteristics::STORE)) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.get_grid(player_ptr->get_position());
+    if (!grid.cave_has_flag(TerrainCharacteristics::STORE)) {
         msg_print(_("ここには店がありません。", "You see no store here."));
         return;
     }
@@ -77,48 +74,50 @@ void do_cmd_store(PlayerType *player_ptr)
     //   inner_town_num は、施設内で C コマンドなどを使ったときにそのままでは現在地の偽装がバレる
     //   ため、それを糊塗するためのグローバル変数。
     //   この辺はリファクタしたい。
-    StoreSaleType store_num = i2enum<StoreSaleType>(terrains_info[g_ptr->feat].subtype);
+    const auto store_num = i2enum<StoreSaleType>(grid.get_terrain().subtype);
     old_town_num = player_ptr->town_num;
     if ((store_num == StoreSaleType::HOME) || (store_num == StoreSaleType::MUSEUM)) {
         player_ptr->town_num = 1;
     }
 
-    if (floor_ptr->is_in_dungeon()) {
+    if (floor.is_in_dungeon()) {
         player_ptr->town_num = VALID_TOWNS;
     }
 
     inner_town_num = player_ptr->town_num;
-    if ((towns_info[player_ptr->town_num].store[enum2i(store_num)].store_open >= w_ptr->game_turn) || ironman_shops) {
+    auto &town = towns_info[player_ptr->town_num];
+    auto &store = town.stores[store_num];
+    if ((store.store_open >= w_ptr->game_turn) || ironman_shops) {
         msg_print(_("ドアに鍵がかかっている。", "The doors are locked."));
         player_ptr->town_num = old_town_num;
         return;
     }
 
-    int maintain_num = (w_ptr->game_turn - towns_info[player_ptr->town_num].store[enum2i(store_num)].last_visit) / (TURNS_PER_TICK * STORE_TICKS);
+    int maintain_num = (w_ptr->game_turn - store.last_visit) / (TURNS_PER_TICK * STORE_TICKS);
     if (maintain_num > 10) {
         maintain_num = 10;
     }
     if (maintain_num) {
         store_maintenance(player_ptr, player_ptr->town_num, store_num, maintain_num);
 
-        towns_info[player_ptr->town_num].store[enum2i(store_num)].last_visit = w_ptr->game_turn;
+        store.last_visit = w_ptr->game_turn;
     }
 
-    forget_lite(floor_ptr);
-    forget_view(floor_ptr);
+    forget_lite(&floor);
+    forget_view(&floor);
     w_ptr->character_icky_depth = 1;
     command_arg = 0;
     command_rep = 0;
     command_new = 0;
     get_com_no_macros = true;
-    cur_store_feat = g_ptr->feat;
-    st_ptr = &towns_info[player_ptr->town_num].store[enum2i(store_num)];
+    cur_store_feat = grid.feat;
+    st_ptr = &towns_info[player_ptr->town_num].stores[store_num];
     ot_ptr = &owners.at(store_num)[st_ptr->owner];
     store_top = 0;
     play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_BUILD);
     display_store(player_ptr, store_num);
     leave_store = false;
-
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     while (!leave_store) {
         prt("", 1, 0);
         clear_from(20 + xtra_stock);
@@ -153,12 +152,12 @@ void do_cmd_store(PlayerType *player_ptr)
         InputKeyRequestor(player_ptr, true).request_command();
         store_process_command(player_ptr, store_num);
 
-        bool need_redraw_store_inv = any_bits(player_ptr->update, PU_BONUS);
+        const auto should_redraw_store_inventory = rfu.has(StatusRecalculatingFlag::BONUS);
         w_ptr->character_icky_depth = 1;
         handle_stuff(player_ptr);
         if (player_ptr->inventory_list[INVEN_PACK].bi_id) {
-            INVENTORY_IDX item = INVEN_PACK;
-            auto *o_ptr = &player_ptr->inventory_list[item];
+            INVENTORY_IDX i_idx = INVEN_PACK;
+            auto *o_ptr = &player_ptr->inventory_list[i_idx];
             if (store_num != StoreSaleType::HOME) {
                 if (store_num == StoreSaleType::MUSEUM) {
                     msg_print(_("ザックからアイテムがあふれそうなので、あわてて博物館から出た...", "Your pack is so full that you flee the Museum..."));
@@ -178,8 +177,8 @@ void do_cmd_store(PlayerType *player_ptr)
                 q_ptr = &forge;
                 q_ptr->copy_from(o_ptr);
                 const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
-                msg_format(_("%sが落ちた。(%c)", "You drop %s (%c)."), item_name.data(), index_to_label(item));
-                vary_item(player_ptr, item, -255);
+                msg_format(_("%sが落ちた。(%c)", "You drop %s (%c)."), item_name.data(), index_to_label(i_idx));
+                vary_item(player_ptr, i_idx, -255);
                 handle_stuff(player_ptr);
 
                 item_pos = home_carry(player_ptr, q_ptr, store_num);
@@ -190,7 +189,7 @@ void do_cmd_store(PlayerType *player_ptr)
             }
         }
 
-        if (need_redraw_store_inv) {
+        if (should_redraw_store_inventory) {
             display_store_inventory(player_ptr, store_num);
         }
 
@@ -212,9 +211,23 @@ void do_cmd_store(PlayerType *player_ptr)
     msg_erase();
     term_clear();
 
-    player_ptr->update |= PU_VIEW | PU_LITE | PU_MONSTER_LITE;
-    player_ptr->update |= PU_MONSTER_STATUSES;
-    player_ptr->redraw |= PR_BASIC | PR_EXTRA | PR_EQUIPPY;
-    player_ptr->redraw |= PR_MAP;
-    player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::VIEW,
+        StatusRecalculatingFlag::LITE,
+        StatusRecalculatingFlag::MONSTER_LITE,
+        StatusRecalculatingFlag::MONSTER_STATUSES,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::EXTRA,
+        MainWindowRedrawingFlag::EQUIPPY,
+        MainWindowRedrawingFlag::MAP,
+    };
+    rfu.set_flags(flags_mwrf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags_swrf);
 }
index 42d3721..1564197 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_store(PlayerType *player_ptr);
index dd11d27..9f3dd3e 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/gold-magnification-table.h"
+#include "store/gold-magnification-table.h"
 
 /*
  * Buying and selling adjustments for race combinations.
index 5f65308..097f857 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-info/race-types.h"
 #include "system/angband.h"
index 8962b2e..bc4ff79 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/home.h"
+#include "store/home.h"
 #include "avatar/avatar.h"
 #include "floor/floor-town.h"
 #include "game-option/birth-options.h"
@@ -184,7 +184,7 @@ bool combine_and_reorder_home(PlayerType *player_ptr, const StoreSaleType store_
     bool old_stack_force_notes = stack_force_notes;
     bool old_stack_force_costs = stack_force_costs;
     store_type *old_st_ptr = st_ptr;
-    st_ptr = &towns_info[1].store[enum2i(store_num)];
+    st_ptr = &towns_info[1].stores[store_num];
     bool flag = false;
     if (store_num != StoreSaleType::HOME) {
         stack_force_notes = false;
index 7694b94..549f965 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
index ea37180..ac646ef 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/museum.h"
+#include "store/museum.h"
 #include "core/asking-player.h"
 #include "flavor/flavor-describer.h"
 #include "store/home.h"
@@ -25,22 +25,23 @@ void museum_remove_object(PlayerType *player_ptr)
         i = store_bottom;
     }
 
-    COMMAND_CODE item;
-    if (!get_stock(&item, _("どのアイテムの展示をやめさせますか?", "Which item do you want to order to remove? "), 0, i - 1, StoreSaleType::MUSEUM)) {
+    constexpr auto mes = _("どのアイテムの展示をやめさせますか?", "Which item do you want to order to remove? ");
+    auto item_num_opt = input_stock(mes, 0, i - 1, StoreSaleType::MUSEUM);
+    if (!item_num_opt) {
         return;
     }
 
-    item = item + store_top;
-    auto *o_ptr = &st_ptr->stock[item];
+    const short item_num = *item_num_opt + store_top;
+    auto *o_ptr = &st_ptr->stock[item_num];
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
     msg_print(_("展示をやめさせたアイテムは二度と見ることはできません!", "Once removed from the Museum, an item will be gone forever!"));
-    if (!get_check(format(_("本当に%sの展示をやめさせますか?", "Really order to remove %s from the Museum? "), item_name.data()))) {
+    if (!input_check(format(_("本当に%sの展示をやめさせますか?", "Really order to remove %s from the Museum? "), item_name.data()))) {
         return;
     }
 
     msg_format(_("%sの展示をやめさせた。", "You ordered to remove %s."), item_name.data());
-    store_item_increase(item, -o_ptr->number);
-    store_item_optimize(item);
+    store_item_increase(item_num, -o_ptr->number);
+    store_item_optimize(item_num);
     (void)combine_and_reorder_home(player_ptr, StoreSaleType::MUSEUM);
     if (st_ptr->stock_num == 0) {
         store_top = 0;
index e6a8db0..563e3e9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void museum_remove_object(PlayerType *player_ptr);
index ab57864..7281e16 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/pricing.h"
+#include "store/pricing.h"
 #include "object/object-value.h"
 #include "player/player-status-table.h"
 #include "store/gold-magnification-table.h"
index 7333ef8..8ab1ab3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 0324438..65f511b 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/purchase-order.h"
+#include "store/purchase-order.h"
 #include "autopick/autopick-finder.h"
 #include "autopick/autopick-util.h"
 #include "autopick/autopick.h"
@@ -37,6 +37,7 @@
 #include "view/display-store.h"
 #include "world/world.h"
 #include <optional>
+#include <string>
 
 /*!
  * @brief プレイヤーが購入する時の値切り処理メインルーチン /
@@ -53,7 +54,7 @@ static std::optional<PRICE> prompt_to_buy(PlayerType *player_ptr, ItemEntity *o_
 
     price_ask *= o_ptr->number;
     const auto s = format(_("買値 $%ld で買いますか?", "Do you buy for $%ld? "), static_cast<long>(price_ask));
-    if (get_check_strict(player_ptr, s, CHECK_DEFAULT_Y)) {
+    if (input_check_strict(player_ptr, s, UserCheck::DEFAULT_Y)) {
         return price_ask;
     }
 
@@ -62,17 +63,12 @@ static std::optional<PRICE> prompt_to_buy(PlayerType *player_ptr, ItemEntity *o_
 
 /*!
  * @brief 店舗から購入する際のアイテム選択プロンプト
- * @param item 店舗インベントリ番号(アドレス渡し)
  * @param i 店舗インベントリストック数
  * @return 選択したらtrue、しなかったらfalse
- * @details
- * 選択したインベントリ番号はitemに返る。
- * ブラックマーケットの時は別のメッセージ。
  */
-static bool show_store_select_item(COMMAND_CODE *item, const int i, StoreSaleType store_num)
+static std::optional<short> show_store_select_item(const int i, StoreSaleType store_num)
 {
-    concptr prompt;
-
+    std::string prompt;
     switch (store_num) {
     case StoreSaleType::HOME:
         prompt = _("どのアイテムを取りますか? ", "Which item do you want to take? ");
@@ -85,7 +81,7 @@ static bool show_store_select_item(COMMAND_CODE *item, const int i, StoreSaleTyp
         break;
     }
 
-    return get_stock(item, prompt, 0, i - 1, store_num) != 0;
+    return input_stock(prompt, 0, i - 1, store_num);
 }
 
 /*!
@@ -144,7 +140,8 @@ static void shuffle_store(PlayerType *player_ptr, StoreSaleType store_num)
     store_shuffle(player_ptr, store_num);
     prt("", 3, 0);
     put_str(format("%s (%s)", ot_ptr->owner_name, race_info[enum2i(ot_ptr->owner_race)].title), 3, 10);
-    prt(format("%s (%ld)", terrains_info[cur_store_feat].name.data(), (long)(ot_ptr->max_cost)), 3, 50);
+    const auto &terrains = TerrainList::get_instance();
+    prt(format("%s (%d)", terrains[cur_store_feat].name.data(), ot_ptr->max_cost), 3, 50);
 }
 
 static void switch_store_stock(PlayerType *player_ptr, const int i, const COMMAND_CODE item, StoreSaleType store_num)
@@ -196,14 +193,13 @@ void store_purchase(PlayerType *player_ptr, StoreSaleType store_num)
         i = store_bottom;
     }
 
-    COMMAND_CODE item;
-    if (!show_store_select_item(&item, i, store_num)) {
+    auto item_num_opt = show_store_select_item(i, store_num);
+    if (!item_num_opt) {
         return;
     }
 
-    item = item + store_top;
-    ItemEntity *o_ptr;
-    o_ptr = &st_ptr->stock[item];
+    const short item_num = *item_num_opt + store_top;
+    auto *o_ptr = &st_ptr->stock[item_num];
 
     ITEM_NUMBER amt = 1;
     ItemEntity forge;
@@ -221,13 +217,13 @@ void store_purchase(PlayerType *player_ptr, StoreSaleType store_num)
         return;
     }
 
-    PRICE best = price_item(player_ptr, j_ptr, ot_ptr->inflate, false, store_num);
+    const auto best = price_item(player_ptr, j_ptr, ot_ptr->inflate, false, store_num);
     if (o_ptr->number > 1) {
         if (store_num != StoreSaleType::HOME) {
-            msg_format(_("一つにつき $%ldです。", "That costs %ld gold per item."), (long)(best));
+            msg_format(_("一つにつき $%dです。", "That costs %d gold per item."), best);
         }
 
-        amt = get_quantity(std::nullopt, o_ptr->number);
+        amt = input_quantity(o_ptr->number);
         if (amt <= 0) {
             return;
         }
@@ -248,14 +244,13 @@ void store_purchase(PlayerType *player_ptr, StoreSaleType store_num)
     }
 
     if (store_num == StoreSaleType::HOME) {
-        take_item_from_home(player_ptr, o_ptr, j_ptr, item);
+        take_item_from_home(player_ptr, o_ptr, j_ptr, item_num);
         return;
     }
 
     COMMAND_CODE item_new;
-    PRICE price;
     const auto purchased_item_name = describe_flavor(player_ptr, j_ptr, 0);
-    msg_format(_("%s(%c)を購入する。", "Buying %s (%c)."), purchased_item_name.data(), I2A(item));
+    msg_format(_("%s(%c)を購入する。", "Buying %s (%c)."), purchased_item_name.data(), I2A(item_num));
     msg_print(nullptr);
 
     auto res = prompt_to_buy(player_ptr, j_ptr, store_num);
@@ -266,7 +261,7 @@ void store_purchase(PlayerType *player_ptr, StoreSaleType store_num)
         return;
     }
 
-    price = res.value();
+    const auto price = *res;
 
     if (player_ptr->au < price) {
         msg_print(_("お金が足りません。", "You do not have enough gold."));
@@ -287,16 +282,16 @@ void store_purchase(PlayerType *player_ptr, StoreSaleType store_num)
     object_aware(player_ptr, j_ptr);
 
     msg_format(_("%sを $%ldで購入しました。", "You bought %s for %ld gold."), purchased_item_name.data(), (long)price);
-    angband_strcpy(record_o_name, purchased_item_name.data(), MAX_NLEN);
+    angband_strcpy(record_o_name, purchased_item_name, MAX_NLEN);
     record_turn = w_ptr->game_turn;
 
     if (record_buy) {
-        exe_write_diary(player_ptr, DIARY_BUY, 0, purchased_item_name.data());
+        exe_write_diary(player_ptr, DiaryKind::BUY, 0, purchased_item_name);
     }
 
     const auto diary_item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
     if (record_rand_art && o_ptr->is_random_artifact()) {
-        exe_write_diary(player_ptr, DIARY_ART, 0, diary_item_name.data());
+        exe_write_diary(player_ptr, DiaryKind::ART, 0, diary_item_name);
     }
 
     j_ptr->inscription.reset();
@@ -304,7 +299,7 @@ void store_purchase(PlayerType *player_ptr, StoreSaleType store_num)
     j_ptr->ident &= ~(IDENT_STORE);
 
     const auto idx = find_autopick_list(player_ptr, j_ptr);
-    auto_inscribe_item(player_ptr, j_ptr, idx);
+    auto_inscribe_item(j_ptr, idx);
 
     item_new = store_item_to_inventory(player_ptr, j_ptr);
     handle_stuff(player_ptr);
@@ -317,7 +312,7 @@ void store_purchase(PlayerType *player_ptr, StoreSaleType store_num)
     }
 
     i = st_ptr->stock_num;
-    store_item_increase(item, -amt);
-    store_item_optimize(item);
-    switch_store_stock(player_ptr, i, item, store_num);
+    store_item_increase(item_num, -amt);
+    store_item_optimize(item_num);
+    switch_store_stock(player_ptr, i, item_num, store_num);
 }
index 6e10ce4..536b0b9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class StoreSaleType;
 class PlayerType;
index a82ca48..9d3549e 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/rumor.h"
+#include "store/rumor.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "floor/floor-town.h"
@@ -7,6 +7,7 @@
 #include "monster-race/monster-race.h"
 #include "object-enchant/special-object-flags.h"
 #include "object/object-kind-hook.h"
+#include "system/angband-exceptions.h"
 #include "system/artifact-type-definition.h"
 #include "system/baseitem-info.h"
 #include "system/dungeon-info.h"
@@ -97,8 +98,8 @@ void display_rumor(PlayerType *player_ptr, bool ex)
     auto opt_rumor = get_random_line("rumors.txt", section);
 #endif
     std::string rumor;
-    if (opt_rumor.has_value()) {
-        rumor = std::move(opt_rumor.value());
+    if (opt_rumor) {
+        rumor = std::move(*opt_rumor);
     } else {
         rumor = _("嘘の噂もある。", "Some rumors are wrong.");
     }
@@ -126,21 +127,13 @@ void display_rumor(PlayerType *player_ptr, bool ex)
         item.ident = IDENT_STORE;
         fullname = describe_flavor(player_ptr, &item, OD_NAME_ONLY);
     } else if (category == "MONSTER") {
-        MonsterRaceInfo *r_ptr;
         const auto &monster_name = tokens[1];
 
         // @details プレイヤーもダミーで入っているので、1つ引いておかないと数が合わなくなる.
         const auto monraces_size = static_cast<short>(monraces_info.size() - 1);
-        while (true) {
-            auto r_idx = i2enum<MonsterRaceId>(get_rumor_num(monster_name, monraces_size));
-            r_ptr = &monraces_info[r_idx];
-            if (!r_ptr->name.empty()) {
-                break;
-            }
-        }
-
+        auto monrace_id = i2enum<MonsterRaceId>(get_rumor_num(monster_name, monraces_size));
+        auto *r_ptr = &monraces_info[monrace_id];
         fullname = r_ptr->name;
-
         if (!r_ptr->r_sights) {
             r_ptr->r_sights++;
         }
@@ -167,7 +160,7 @@ void display_rumor(PlayerType *player_ptr, bool ex)
         const auto &town_name = tokens[1];
         while (true) {
             t_idx = get_rumor_num(town_name, VALID_TOWNS);
-            if (towns_info[t_idx].name[0] != '\0') {
+            if (!towns_info[t_idx].name.empty()) {
                 break;
             }
         }
@@ -179,7 +172,7 @@ void display_rumor(PlayerType *player_ptr, bool ex)
             rumor_eff_format = _("%sに行ったことがある気がする。", "You feel you have been to %s.");
         }
     } else {
-        throw std::runtime_error("Unknown token exists in rumor.txt");
+        THROW_EXCEPTION(std::runtime_error, "Unknown token exists in rumor.txt");
     }
 
     const auto rumor_msg = bind_rumor_name(tokens[2], fullname);
index 1b81fc7..65c22f2 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void display_rumor(PlayerType *player_ptr, bool ex);
index 79054c4..18488f0 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/say-comments.h"
+#include "store/say-comments.h"
 #include "avatar/avatar.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
@@ -18,9 +18,9 @@
 void store_owner_says_comment(PlayerType *player_ptr, StoreSaleType store_num)
 {
     if (store_num == StoreSaleType::BLACK) {
-        msg_print(comment_1_B[randint0(MAX_COMMENT_1)]);
+        msg_print(rand_choice(comment_1_B));
     } else {
-        msg_print(comment_1[randint0(MAX_COMMENT_1)]);
+        msg_print(rand_choice(comment_1));
     }
 
     if (one_in_(RUMOR_CHANCE)) {
@@ -42,7 +42,7 @@ void purchase_analyze(PlayerType *player_ptr, PRICE price, PRICE value, PRICE gu
 {
     /* Item was worthless, but we bought it */
     if ((value <= 0) && (price > value)) {
-        msg_print(comment_7a[randint0(MAX_COMMENT_7A)]);
+        msg_print(rand_choice(comment_7a));
         chg_virtue(player_ptr, Virtue::HONOUR, -1);
         chg_virtue(player_ptr, Virtue::JUSTICE, -1);
         sound(SOUND_STORE1);
@@ -51,7 +51,7 @@ void purchase_analyze(PlayerType *player_ptr, PRICE price, PRICE value, PRICE gu
 
     /* Item was cheaper than we thought, and we paid more than necessary */
     if ((value < guess) && (price > value)) {
-        msg_print(comment_7b[randint0(MAX_COMMENT_7B)]);
+        msg_print(rand_choice(comment_7b));
         chg_virtue(player_ptr, Virtue::JUSTICE, -1);
         if (one_in_(4)) {
             chg_virtue(player_ptr, Virtue::HONOUR, -1);
@@ -62,7 +62,7 @@ void purchase_analyze(PlayerType *player_ptr, PRICE price, PRICE value, PRICE gu
 
     /* Item was a good bargain, and we got away with it */
     if ((value > guess) && (value < (4 * guess)) && (price < value)) {
-        msg_print(comment_7c[randint0(MAX_COMMENT_7C)]);
+        msg_print(rand_choice(comment_7c));
         if (one_in_(4)) {
             chg_virtue(player_ptr, Virtue::HONOUR, -1);
         } else if (one_in_(4)) {
@@ -74,7 +74,7 @@ void purchase_analyze(PlayerType *player_ptr, PRICE price, PRICE value, PRICE gu
 
     /* Item was a great bargain, and we got away with it */
     if ((value > guess) && (price < value)) {
-        msg_print(comment_7d[randint0(MAX_COMMENT_7D)]);
+        msg_print(rand_choice(comment_7d));
         if (one_in_(2)) {
             chg_virtue(player_ptr, Virtue::HONOUR, -1);
         }
index b4529bb..f69d5db 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 368325e..7809480 100644 (file)
@@ -1,9 +1,8 @@
-#include "store/sell-order.h"
+#include "store/sell-order.h"
 #include "action/weapon-shield.h"
 #include "autopick/autopick.h"
 #include "avatar/avatar.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "flavor/flavor-describer.h"
@@ -34,6 +33,7 @@
 #include "store/store.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/screen-processor.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
@@ -55,7 +55,7 @@ static std::optional<PRICE> prompt_to_sell(PlayerType *player_ptr, ItemEntity *o
     price_ask = std::min(price_ask, ot_ptr->max_cost);
     price_ask *= o_ptr->number;
     const auto s = format(_("売値 $%ld で売りますか?", "Do you sell for $%ld? "), static_cast<long>(price_ask));
-    if (get_check_strict(player_ptr, s, CHECK_DEFAULT_Y)) {
+    if (input_check_strict(player_ptr, s, UserCheck::DEFAULT_Y)) {
         return price_ask;
     }
 
@@ -90,21 +90,21 @@ void store_sell(PlayerType *player_ptr, StoreSaleType store_num)
         break;
     }
 
-    OBJECT_IDX item;
+    short i_idx;
     const auto options = USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s_none, options, FuncItemTester(store_will_buy, player_ptr, store_num));
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s_none, options, FuncItemTester(store_will_buy, player_ptr, store_num));
     if (o_ptr == nullptr) {
         return;
     }
 
-    if ((item >= INVEN_MAIN_HAND) && o_ptr->is_cursed()) {
+    if ((i_idx >= INVEN_MAIN_HAND) && o_ptr->is_cursed()) {
         msg_print(_("ふーむ、どうやらそれは呪われているようだね。", "Hmmm, it seems to be cursed."));
         return;
     }
 
-    int amt = 1;
+    auto amt = 1;
     if (o_ptr->number > 1) {
-        amt = get_quantity(std::nullopt, o_ptr->number);
+        amt = input_quantity(o_ptr->number);
         if (amt <= 0) {
             return;
         }
@@ -129,16 +129,16 @@ void store_sell(PlayerType *player_ptr, StoreSaleType store_num)
         return;
     }
 
-    bool placed = false;
+    auto placed = false;
     if ((store_num != StoreSaleType::HOME) && (store_num != StoreSaleType::MUSEUM)) {
         const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
-        msg_format(_("%s(%c)を売却する。", "Selling %s (%c)."), item_name.data(), index_to_label(item));
+        msg_format(_("%s(%c)を売却する。", "Selling %s (%c)."), item_name.data(), index_to_label(i_idx));
         msg_print(nullptr);
 
         auto res = prompt_to_sell(player_ptr, q_ptr, store_num);
         placed = res.has_value();
         if (placed) {
-            const auto price = res.value();
+            const auto price = *res;
             store_owner_says_comment(player_ptr, store_num);
 
             sound(SOUND_SELL);
@@ -170,7 +170,7 @@ void store_sell(PlayerType *player_ptr, StoreSaleType store_num)
             msg_format(_("%sを $%dで売却しました。", "You sold %s for %d gold."), sold_item_name.data(), price);
 
             if (record_sell) {
-                exe_write_diary(player_ptr, DIARY_SELL, 0, sold_item_name.data());
+                exe_write_diary(player_ptr, DiaryKind::SELL, 0, sold_item_name);
             }
 
             if (!((tval == ItemKindType::FIGURINE) && (value > 0))) {
@@ -179,13 +179,13 @@ void store_sell(PlayerType *player_ptr, StoreSaleType store_num)
 
             distribute_charges(o_ptr, q_ptr, amt);
             q_ptr->timeout = 0;
-            inven_item_increase(player_ptr, item, -amt);
-            inven_item_describe(player_ptr, item);
+            inven_item_increase(player_ptr, i_idx, -amt);
+            inven_item_describe(player_ptr, i_idx);
             if (o_ptr->number > 0) {
-                autopick_alter_item(player_ptr, item, false);
+                autopick_alter_item(player_ptr, i_idx, false);
             }
 
-            inven_item_optimize(player_ptr, item);
+            inven_item_optimize(player_ptr, i_idx);
             int item_pos = store_carry(q_ptr);
             if (item_pos >= 0) {
                 store_top = (item_pos / store_bottom) * store_bottom;
@@ -200,7 +200,7 @@ void store_sell(PlayerType *player_ptr, StoreSaleType store_num)
             msg_print(_("博物館に寄贈したものは取り出すことができません!!", "You cannot take back items which have been donated to the Museum!!"));
         }
 
-        if (!get_check(format(_("本当に%sを寄贈しますか?", "Really give %s to the Museum? "), museum_item_name.data()))) {
+        if (!input_check(format(_("本当に%sを寄贈しますか?", "Really give %s to the Museum? "), museum_item_name.data()))) {
             return;
         }
 
@@ -208,10 +208,10 @@ void store_sell(PlayerType *player_ptr, StoreSaleType store_num)
         q_ptr->ident |= IDENT_FULL_KNOWN;
 
         distribute_charges(o_ptr, q_ptr, amt);
-        msg_format(_("%sを置いた。(%c)", "You drop %s (%c)."), museum_item_name.data(), index_to_label(item));
+        msg_format(_("%sを置いた。(%c)", "You drop %s (%c)."), museum_item_name.data(), index_to_label(i_idx));
         placed = true;
 
-        vary_item(player_ptr, item, -amt);
+        vary_item(player_ptr, i_idx, -amt);
 
         int item_pos = home_carry(player_ptr, q_ptr, store_num);
         if (item_pos >= 0) {
@@ -221,9 +221,9 @@ void store_sell(PlayerType *player_ptr, StoreSaleType store_num)
     } else {
         distribute_charges(o_ptr, q_ptr, amt);
         const auto item_name = describe_flavor(player_ptr, q_ptr, 0);
-        msg_format(_("%sを置いた。(%c)", "You drop %s (%c)."), item_name.data(), index_to_label(item));
+        msg_format(_("%sを置いた。(%c)", "You drop %s (%c)."), item_name.data(), index_to_label(i_idx));
         placed = true;
-        vary_item(player_ptr, item, -amt);
+        vary_item(player_ptr, i_idx, -amt);
         int item_pos = home_carry(player_ptr, q_ptr, store_num);
         if (item_pos >= 0) {
             store_top = (item_pos / store_bottom) * store_bottom;
@@ -231,12 +231,13 @@ void store_sell(PlayerType *player_ptr, StoreSaleType store_num)
         }
     }
 
-    set_bits(player_ptr->update, PU_BONUS);
-    set_bits(player_ptr->window_flags, PW_PLAYER);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::BONUS);
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
     handle_stuff(player_ptr);
 
-    if (placed && (item >= INVEN_MAIN_HAND)) {
+    if (placed && (i_idx >= INVEN_MAIN_HAND)) {
         calc_android_exp(player_ptr);
-        verify_equip_slot(player_ptr, item);
+        verify_equip_slot(player_ptr, i_idx);
     }
 }
index 74bdfd3..1538065 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class StoreSaleType;
 class PlayerType;
index a87fb54..3d771e3 100644 (file)
@@ -1,8 +1,7 @@
-#include "store/service-checker.h"
+#include "store/service-checker.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags3.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/object-value.h"
 #include "object/tval-types.h"
 #include "store/store-util.h"
@@ -23,8 +22,7 @@
  */
 static bool is_blessed_item(const ItemEntity *item_ptr)
 {
-    auto flags = object_flags(item_ptr);
-    return flags.has(TR_BLESSED);
+    return item_ptr->get_flags().has(TR_BLESSED);
 }
 
 static bool check_store_general(const ItemEntity &item)
index 80ac868..6bce887 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class StoreSaleType;
 class ItemEntity;
index f97af74..8f79d53 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/store-key-processor.h"
+#include "store/store-key-processor.h"
 #include "autopick/autopick-pref-processor.h"
 #include "cmd-action/cmd-mind.h"
 #include "cmd-action/cmd-spell.h"
@@ -95,7 +95,7 @@ void store_process_command(PlayerType *player_ptr, StoreSaleType store_num)
              * 隠しオプション(powerup_home)がセットされていないときは
              * 我が家では 2 ページまでしか表示しない
              */
-            auto inven_max = store_get_stock_max(StoreSaleType::HOME, powerup_home);
+            auto inven_max = store_get_stock_max(store_num, powerup_home);
             if (store_top >= st_ptr->stock_num || store_top >= inven_max) {
                 store_top = 0;
             }
@@ -150,7 +150,7 @@ void store_process_command(PlayerType *player_ptr, StoreSaleType store_num)
         break;
     }
     case KTRL('I'): {
-        toggle_inventory_equipment(player_ptr);
+        toggle_inventory_equipment();
         break;
     }
     case 'b': {
index da26395..63cac43 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 extern bool leave_store;
 
index 6e70393..6ac9255 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/store-owner-comments.h"
+#include "store/store-owner-comments.h"
 
 concptr comment_1[MAX_COMMENT_1] = {
     _("オーケーだ。", "Okay."),
index e7812f9..12fa511 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 69e4f1c..e4c0432 100644 (file)
@@ -1,4 +1,4 @@
-#include "store/store-owners.h"
+#include "store/store-owners.h"
 #include "player-info/race-types.h"
 #include "store/store-util.h"
 
index 1566671..8cc78a6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "player-info/race-types.h"
 #include "store/store-util.h"
index ef8ac2d..40598f2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 店舗処理関係のユーティリティ
  * @date 2020/03/20
  * @author Hourier
 store_type *st_ptr = nullptr;
 
 /*!
- * @brief 店舗のオブジェクト数を増やす /
- * Add the item "o_ptr" to a real stores inventory.
- * @param item 増やしたいアイテムのID
+ * @brief 店舗のオブジェクト数を増やす
+ * @param i_idx 増やしたいアイテムのインベントリID
  * @param num 増やしたい数
- * @details
- * <pre>
- * Increase, by a given amount, the number of a certain item
- * in a certain store. This can result in zero items.
- * </pre>
  */
-void store_item_increase(INVENTORY_IDX item, ITEM_NUMBER num)
+void store_item_increase(INVENTORY_IDX i_idx, ITEM_NUMBER num)
 {
     ItemEntity *o_ptr;
-    o_ptr = &st_ptr->stock[item];
+    o_ptr = &st_ptr->stock[i_idx];
     int cnt = o_ptr->number + num;
     if (cnt > 255) {
         cnt = 255;
@@ -41,19 +35,18 @@ void store_item_increase(INVENTORY_IDX item, ITEM_NUMBER num)
 }
 
 /*!
- * @brief 店舗のオブジェクト数を削除する /
- * Remove a slot if it is empty
- * @param item 削除したいアイテムのID
+ * @brief 店舗のオブジェクト数を削除する
+ * @param i_idx 削除したいアイテムのID
  */
-void store_item_optimize(INVENTORY_IDX item)
+void store_item_optimize(INVENTORY_IDX i_idx)
 {
-    const auto *o_ptr = &st_ptr->stock[item];
+    const auto *o_ptr = &st_ptr->stock[i_idx];
     if (!o_ptr->is_valid() || (o_ptr->number != 0)) {
         return;
     }
 
     st_ptr->stock_num--;
-    for (int j = item; j < st_ptr->stock_num; j++) {
+    for (int j = i_idx; j < st_ptr->stock_num; j++) {
         st_ptr->stock[j] = st_ptr->stock[j + 1];
     }
 
index 1e7bde9..1dfa67b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
@@ -58,7 +58,7 @@ extern store_type *st_ptr;
 class PlayerType;
 void store_delete(void);
 std::vector<PARAMETER_VALUE> store_same_magic_device_pvals(ItemEntity *j_ptr);
-void store_item_increase(INVENTORY_IDX item, ITEM_NUMBER num);
-void store_item_optimize(INVENTORY_IDX item);
+void store_item_increase(INVENTORY_IDX i_idx, ITEM_NUMBER num);
+void store_item_optimize(INVENTORY_IDX i_idx);
 int store_carry(ItemEntity *o_ptr);
 bool store_object_similar(ItemEntity *o_ptr, ItemEntity *j_ptr);
index 085f5db..2d15adf 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 店の処理 / Store commands
  * @date 2022/03/26
  * @author Hourier
 #include "object/object-value.h"
 #include "object/tval-types.h"
 #include "perception/identification.h"
-#include "perception/object-perception.h"
 #include "store/black-market.h"
 #include "store/service-checker.h"
 #include "store/store-owners.h"
 #include "store/store-util.h"
 #include "sv-definition/sv-lite-types.h"
 #include "sv-definition/sv-scroll-types.h"
+#include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/int-char-converter.h"
-#include "util/quarks.h"
 #include "view/display-messages.h"
 #include "world/world-object.h"
 
@@ -44,7 +43,7 @@ int16_t old_town_num = 0;
 int16_t inner_town_num = 0;
 
 /* We store the current "store feat" here so everyone can access it */
-int cur_store_feat;
+short cur_store_feat;
 
 /* Enable "increments" */
 bool allow_inc = false;
@@ -145,48 +144,46 @@ int store_check_num(ItemEntity *o_ptr, StoreSaleType store_num)
 }
 
 /*!
- * @brief 店舗からアイテムを選択する /
- * Get the ID of a store item and return its value     -RAK-
- * @param com_val 選択IDを返す参照ポインタ
+ * @brief 店舗からアイテムを選択する
  * @param pmt メッセージキャプション
- * @param i 選択範囲の最小値
- * @param j 選択範囲の最大値
- * @return 実際に選択したらTRUE、キャンセルしたらFALSE
+ * @param min 選択範囲の最小値
+ * @param max 選択範囲の最大値
+ * @return アイテムを選択したらそのインデックス ('a'等)、キャンセルしたらnullopt
+ * 繰り返しコマンドの時は前回の前回のインデックス
  */
-int get_stock(COMMAND_CODE *com_val, concptr pmt, int i, int j, [[maybe_unused]] StoreSaleType store_num)
+std::optional<short> input_stock(std::string_view fmt, int min, int max, [[maybe_unused]] StoreSaleType store_num)
 {
-    if (repeat_pull(com_val) && (*com_val >= i) && (*com_val <= j)) {
-        return true;
+    short repeat_command;
+    if (repeat_pull(&repeat_command) && (repeat_command >= min) && (repeat_command <= max)) {
+        return repeat_command;
     }
 
     msg_print(nullptr);
-    *com_val = (-1);
-    char lo = I2A(i);
-    char hi = (j > 25) ? toupper(I2A(j - 26)) : I2A(j);
-    char out_val[160];
+    const auto lo = I2A(min);
+    const auto hi = (max > 25) ? toupper(I2A(max - 26)) : I2A(max);
 #ifdef JP
-    strnfmt(out_val, sizeof(out_val), "(%s:%c-%c, ESCで中断) %s", (((store_num == StoreSaleType::HOME) || (store_num == StoreSaleType::MUSEUM)) ? "アイテム" : "商品"), lo, hi, pmt);
+    const auto title = (store_num == StoreSaleType::HOME) || (store_num == StoreSaleType::MUSEUM) ? "アイテム" : "商品";
+    const auto prompt = format("(%s:%c-%c, ESCで中断) %s", title, lo, hi, fmt.data());
 #else
-    strnfmt(out_val, sizeof(out_val), "(Items %c-%c, ESC to exit) %s", lo, hi, pmt);
+    const auto prompt = format("(Items %c-%c, ESC to exit) %s", lo, hi, fmt.data());
 #endif
 
-    char command;
+    std::optional<char> command;
     while (true) {
-        if (!get_com(out_val, &command, false)) {
+        const auto command_alpha = input_command(prompt);
+        if (!command_alpha) {
             break;
         }
 
-        COMMAND_CODE k;
-        if (islower(command)) {
-            k = A2I(command);
-        } else if (isupper(command)) {
-            k = A2I(tolower(command)) + 26;
-        } else {
-            k = -1;
+        std::optional<int> command_num;
+        if (islower(*command_alpha)) {
+            command_num = A2I(*command_alpha);
+        } else if (isupper(*command_alpha)) {
+            command_num = A2I(tolower(*command_alpha)) + 26;
         }
 
-        if ((k >= i) && (k <= j)) {
-            *com_val = k;
+        if (command_num && (*command_num >= min) && (*command_num <= max)) {
+            command = static_cast<short>(*command_num);
             break;
         }
 
@@ -194,12 +191,12 @@ int get_stock(COMMAND_CODE *com_val, concptr pmt, int i, int j, [[maybe_unused]]
     }
 
     prt("", 0, 0);
-    if (command == ESCAPE) {
-        return false;
+    if (!command) {
+        return std::nullopt;
     }
 
-    repeat_push(*com_val);
-    return true;
+    repeat_push(*command);
+    return command;
 }
 
 /*!
@@ -224,13 +221,14 @@ void store_examine(PlayerType *player_ptr, StoreSaleType store_num)
         i = store_bottom;
     }
 
-    COMMAND_CODE item;
-    if (!get_stock(&item, _("どれを調べますか?", "Which item do you want to examine? "), 0, i - 1, store_num)) {
+    constexpr auto mes = _("どれを調べますか?", "Which item do you want to examine? ");
+    auto item_num_opt = input_stock(mes, 0, i - 1, store_num);
+    if (!item_num_opt) {
         return;
     }
-    item = item + store_top;
-    ItemEntity *o_ptr;
-    o_ptr = &st_ptr->stock[item];
+
+    const auto item_num = *item_num_opt + store_top;
+    auto *o_ptr = &st_ptr->stock[item_num];
     if (!o_ptr->is_fully_known()) {
         msg_print(_("このアイテムについて特に知っていることはない。", "You have no special knowledge about that item."));
         return;
@@ -256,7 +254,7 @@ void store_shuffle(PlayerType *player_ptr, StoreSaleType store_num)
         return;
     }
 
-    st_ptr = &towns_info[player_ptr->town_num].store[enum2i(store_num)];
+    st_ptr = &towns_info[player_ptr->town_num].stores[store_num];
     int j = st_ptr->owner;
     while (true) {
         st_ptr->owner = (byte)randint0(owner_num);
@@ -272,7 +270,7 @@ void store_shuffle(PlayerType *player_ptr, StoreSaleType store_num)
                 continue;
             }
 
-            if (st_ptr->owner == towns_info[i].store[enum2i(store_num)].owner) {
+            if (st_ptr->owner == towns_info[i].stores[store_num].owner) {
                 break;
             }
         }
@@ -326,7 +324,7 @@ static void store_create(PlayerType *player_ptr, short fix_k_idx, StoreSaleType
         DEPTH level;
         if (store_num == StoreSaleType::BLACK) {
             level = 25 + randint0(25);
-            bi_id = get_obj_index(player_ptr, level, 0x00000000);
+            bi_id = get_obj_index(player_ptr->current_floor_ptr, level, 0x00000000);
             if (bi_id == 0) {
                 continue;
             }
@@ -334,7 +332,7 @@ static void store_create(PlayerType *player_ptr, short fix_k_idx, StoreSaleType
             bi_id = fix_k_idx;
             level = rand_range(1, ow_ptr->level);
         } else {
-            bi_id = st_ptr->table[randint0(st_ptr->table.size())];
+            bi_id = rand_choice(st_ptr->table);
             level = rand_range(1, ow_ptr->level);
         }
 
@@ -349,7 +347,7 @@ static void store_create(PlayerType *player_ptr, short fix_k_idx, StoreSaleType
 
         auto pvals = store_same_magic_device_pvals(q_ptr);
         if (pvals.size() >= 2) {
-            auto pval = pvals.at(randint0(pvals.size()));
+            auto pval = rand_choice(pvals);
             q_ptr->pval = pval;
         }
 
@@ -365,7 +363,7 @@ static void store_create(PlayerType *player_ptr, short fix_k_idx, StoreSaleType
             }
         }
 
-        object_known(q_ptr);
+        q_ptr->mark_as_known();
         q_ptr->ident |= IDENT_STORE;
         if (tval == ItemKindType::CHEST) {
             continue;
@@ -401,7 +399,7 @@ void store_maintenance(PlayerType *player_ptr, int town_num, StoreSaleType store
         return;
     }
 
-    st_ptr = &towns_info[town_num].store[enum2i(store_num)];
+    st_ptr = &towns_info[town_num].stores[store_num];
     ot_ptr = &owners.at(store_num)[st_ptr->owner];
     st_ptr->insult_cur = 0;
     if (store_num == StoreSaleType::BLACK) {
@@ -475,7 +473,7 @@ void store_maintenance(PlayerType *player_ptr, int town_num, StoreSaleType store
 void store_init(int town_num, StoreSaleType store_num)
 {
     int owner_num = owners.at(store_num).size();
-    st_ptr = &towns_info[town_num].store[enum2i(store_num)];
+    st_ptr = &towns_info[town_num].stores[store_num];
     const int towns_size = towns_info.size();
     while (true) {
         st_ptr->owner = (byte)randint0(owner_num);
@@ -489,7 +487,7 @@ void store_init(int town_num, StoreSaleType store_num)
             if (i == town_num) {
                 continue;
             }
-            if (st_ptr->owner == towns_info[i].store[enum2i(store_num)].owner) {
+            if (st_ptr->owner == towns_info[i].stores[store_num].owner) {
                 break;
             }
         }
index b822602..1a422b6 100644 (file)
@@ -1,7 +1,9 @@
-#pragma once
+#pragma once
 
 #include "store/store-util.h"
 #include "system/angband.h"
+#include <optional>
+#include <string_view>
 
 /* Store constants */
 #define STORE_INVEN_MAX 24 /* Max number of discrete objs in inven */
@@ -19,7 +21,7 @@ extern const owner_type *ot_ptr;
 extern int16_t old_town_num;
 extern int16_t inner_town_num;
 
-extern int cur_store_feat;
+extern short cur_store_feat;
 extern bool allow_inc;
 
 class PlayerType;
@@ -29,4 +31,4 @@ void store_maintenance(PlayerType *player_ptr, int town_num, StoreSaleType store
 void store_init(int town_num, StoreSaleType store_num);
 void store_examine(PlayerType *player_ptr, StoreSaleType store_num);
 int store_check_num(ItemEntity *o_ptr, StoreSaleType store_num);
-int get_stock(COMMAND_CODE *com_val, concptr pmt, int i, int j, StoreSaleType store_num);
+std::optional<short> input_stock(std::string_view fmt, int min, int max, StoreSaleType store_num);
index c39c58f..21f1d0f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_AMULET */
 enum sv_amulet_type {
index b4750c4..7b7270d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_SOFT_ARMOR */
 enum sv_soft_armor_type {
index 252a179..7e8eadc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_BOW (note information in "sval") */
 enum sv_bow_type {
index 452a35e..3cccf30 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_DIGGING */
 enum sv_digging_type {
index e03c2dd..70af587 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_FOOD */
 enum sv_food_type {
index fac6f2b..450aac7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The sval codes for TV_LITE */
 enum sv_lite_type {
index 136ef3f..03c109b 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief enumで表現することが却って高コストになりそうなSV (ベースアイテムのサブタイプ)定義をここに格納する
  * @date 2020/05/28
  * @author Hourier
index 06385b4..9eaff2c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_POTION */
 enum sv_potion_type {
index 16fb8e9..b432b0f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_SHIELD */
 enum sv_shield_type {
index 1c6f19c..8f952e5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The sval codes for TV_RING */
 enum sv_ring_type {
index 52b5f17..4db3791 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_ROD */
 enum sv_rod_type {
index 951f372..7cd0750 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_SCROLL */
 enum sv_scroll_type {
index 66967a1..058f3d0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_STAFF */
 enum sv_staff_type {
index ad2f50f..29fc51b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" codes for TV_WAND */
 enum sv_wand_type {
index 262b001..1b8c58b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /* The "sval" values for TV_HAFTED */
 enum sv_hafted_type {
index 3bfe963..95af3ba 100644 (file)
@@ -1,4 +1,4 @@
-#include "system/alloc-entries.h"
+#include "system/alloc-entries.h"
 #include "system/baseitem-info.h"
 
 /* The entries in the "race allocator table" */
index c753ebf..2ad7275 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief
  * @author
  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
index 846922e..9802729 100644 (file)
@@ -1,9 +1,36 @@
-#pragma once
+#pragma once
 
+#include <concepts>
+#include <filesystem>
+#include <sstream>
 #include <stdexcept>
+#include <string_view>
 
 class SaveDataNotSupportedException : public std::runtime_error {
 public:
     SaveDataNotSupportedException() = delete;
     using std::runtime_error::runtime_error;
 };
+
+namespace angband::exception::detail {
+
+template <std::derived_from<std::exception> T>
+[[noreturn]] void throw_exception(std::string_view msg, std::filesystem::path path, int line)
+{
+    std::stringstream ss;
+    ss << path.filename().string() << ':' << line << ": " << msg;
+    throw T(ss.str());
+}
+
+}
+
+/*!
+ * @brief EXCEPTION_T型の例外をスローする
+ *
+ * EXCEPTION_T型はstd::exceptionを継承している必要がある。
+ * 例外メッセージは "バージョン: ファイル名:行番号: MSG" となる
+ */
+#define THROW_EXCEPTION(EXCEPTION_T, MSG)                                                  \
+    do {                                                                                   \
+        angband::exception::detail::throw_exception<EXCEPTION_T>(MSG, __FILE__, __LINE__); \
+    } while (0)
diff --git a/src/system/angband-system.cpp b/src/system/angband-system.cpp
new file mode 100644 (file)
index 0000000..9255618
--- /dev/null
@@ -0,0 +1,27 @@
+#include "system/angband-system.h"
+
+AngbandSystem AngbandSystem::instance{};
+
+AngbandSystem &AngbandSystem::get_instance()
+{
+    return instance;
+}
+
+void AngbandSystem::set_phase_out(bool new_status)
+{
+    this->phase_out_stat = new_status;
+}
+
+bool AngbandSystem::is_phase_out() const
+{
+    return this->phase_out_stat;
+}
+
+/*!
+ * @brief プレイヤーの攻撃射程
+ * @return 射程
+ */
+int AngbandSystem::get_max_range() const
+{
+    return this->phase_out_stat ? 36 : 18;
+}
diff --git a/src/system/angband-system.h b/src/system/angband-system.h
new file mode 100644 (file)
index 0000000..9ed668d
--- /dev/null
@@ -0,0 +1,20 @@
+#pragma once
+
+class AngbandSystem {
+public:
+    AngbandSystem(const AngbandSystem &) = delete;
+    AngbandSystem(AngbandSystem &&) = delete;
+    AngbandSystem &operator=(const AngbandSystem &) = delete;
+    AngbandSystem &operator=(AngbandSystem &&) = delete;
+
+    static AngbandSystem &get_instance();
+    void set_phase_out(bool new_status);
+    bool is_phase_out() const;
+    int get_max_range() const;
+
+private:
+    AngbandSystem() = default;
+
+    static AngbandSystem instance;
+    bool phase_out_stat = false; // カジノ闘技場の観戦状態等に利用。NPCの処理の対象にならず自身もほとんどの行動ができない.
+};
index 6cde09f..215bad6 100644 (file)
@@ -1,4 +1,5 @@
-#include "system/angband-version.h"
+#include "system/angband-version.h"
+#include "system/angband-exceptions.h"
 #include "system/angband.h"
 
 std::string get_version()
@@ -18,7 +19,7 @@ std::string get_version()
         expr = "";
         break;
     default:
-        throw("Invalid version status was specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid version status was specified!");
     }
 
     if (VERSION_STATUS != VersionStatusType::RELEASE) {
index 9ebfe36..054d3ac 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <stdint.h>
 #include <string>
@@ -22,8 +22,8 @@ constexpr std::string_view ROOT_VARIANT_NAME("Hengband");
  */
 #define H_VER_MAJOR 3 //!< ゲームのバージョン定義(メジャー番号)
 #define H_VER_MINOR 0 //!< ゲームのバージョン定義(マイナー番号)
-#define H_VER_PATCH 0 //!< ゲームのバージョン定義(パッチ番号)
-#define H_VER_EXTRA 81 //!< ゲームのバージョン定義(エクストラ番号)
+#define H_VER_PATCH 1 //!< ゲームのバージョン定義(パッチ番号)
+#define H_VER_EXTRA 6 //!< ゲームのバージョン定義(エクストラ番号)
 
 /*!
  * @brief セーブファイルのバージョン(3.0.0から導入)
@@ -45,6 +45,6 @@ enum class VersionStatusType {
 /*!
  * @brief バージョンの立ち位置
  */
-constexpr VersionStatusType VERSION_STATUS = VersionStatusType::ALPHA;
+constexpr VersionStatusType VERSION_STATUS = VersionStatusType::BETA;
 
 std::string get_version();
index 66affa9..0205cd0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @file angband.h
index d4e7191..5c870e6 100644 (file)
@@ -1,4 +1,4 @@
-#include "system/artifact-type-definition.h"
+#include "system/artifact-type-definition.h"
 #include "artifact/fixed-art-types.h"
 #include "object/tval-types.h"
 
index 903e60b..d83ad8c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/tr-flags.h"
 #include "object-enchant/trg-types.h"
index 8141be7..6fef30a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ベースアイテム情報の構造体 / Information about object "kinds", including player knowledge.
  * @date 2019/05/01
  * @author deskull
 #include "sv-definition/sv-bow-types.h"
 #include "sv-definition/sv-food-types.h"
 #include "sv-definition/sv-lite-types.h"
+#include "sv-definition/sv-other-types.h"
 #include "sv-definition/sv-protector-types.h"
 #include "sv-definition/sv-rod-types.h"
 #include "sv-definition/sv-weapon-types.h"
+#include "system/angband-exceptions.h"
 #include <set>
-#include <stdexcept>
 #include <unordered_map>
 
 namespace {
@@ -26,12 +27,6 @@ constexpr auto ITEM_NOT_ROD = "This item is not a rod!";
 constexpr auto ITEM_NOT_LITE = "This item is not a lite!";
 }
 
-BaseitemKey::BaseitemKey(const ItemKindType type_value, const std::optional<int> &subtype_value)
-    : type_value(type_value)
-    , subtype_value(subtype_value)
-{
-}
-
 bool BaseitemKey::operator==(const BaseitemKey &other) const
 {
     return (this->type_value == other.type_value) && (this->subtype_value == other.subtype_value);
@@ -61,17 +56,22 @@ std::optional<int> BaseitemKey::sval() const
     return this->subtype_value;
 }
 
+bool BaseitemKey::is(ItemKindType tval) const
+{
+    return this->type_value == tval;
+}
+
 /*!
  * @brief 射撃武器に対応する矢/弾薬のベースアイテムIDを返す
  * @return 対応する矢/弾薬のベースアイテムID
  */
 ItemKindType BaseitemKey::get_arrow_kind() const
 {
-    if ((this->type_value != ItemKindType::BOW) || !this->subtype_value.has_value()) {
-        throw std::logic_error(ITEM_NOT_BOW);
+    if ((this->type_value != ItemKindType::BOW) || !this->subtype_value) {
+        THROW_EXCEPTION(std::logic_error, ITEM_NOT_BOW);
     }
 
-    switch (this->subtype_value.value()) {
+    switch (*this->subtype_value) {
     case SV_SLING:
         return ItemKindType::SHOT;
     case SV_SHORT_BOW:
@@ -278,32 +278,7 @@ bool BaseitemKey::is_weapon() const
 
 bool BaseitemKey::is_equipement() const
 {
-    switch (this->type_value) {
-    case ItemKindType::SHOT:
-    case ItemKindType::ARROW:
-    case ItemKindType::BOLT:
-    case ItemKindType::BOW:
-    case ItemKindType::DIGGING:
-    case ItemKindType::HAFTED:
-    case ItemKindType::POLEARM:
-    case ItemKindType::SWORD:
-    case ItemKindType::BOOTS:
-    case ItemKindType::GLOVES:
-    case ItemKindType::HELM:
-    case ItemKindType::CROWN:
-    case ItemKindType::SHIELD:
-    case ItemKindType::CLOAK:
-    case ItemKindType::SOFT_ARMOR:
-    case ItemKindType::HARD_ARMOR:
-    case ItemKindType::DRAG_ARMOR:
-    case ItemKindType::LITE:
-    case ItemKindType::AMULET:
-    case ItemKindType::RING:
-    case ItemKindType::CARD:
-        return true;
-    default:
-        return false;
-    }
+    return this->is_wearable() || this->is_ammo();
 }
 
 bool BaseitemKey::is_melee_ammo() const
@@ -343,11 +318,11 @@ bool BaseitemKey::is_broken_weapon() const
         return false;
     }
 
-    if (!this->subtype_value.has_value()) {
+    if (!this->subtype_value) {
         return false;
     }
 
-    switch (this->subtype_value.value()) {
+    switch (*this->subtype_value) {
     case SV_BROKEN_DAGGER:
     case SV_BROKEN_SWORD:
         return true;
@@ -401,13 +376,13 @@ bool BaseitemKey::is_rare() const
         { ItemKindType::DRAG_ARMOR, { /* Any */ } },
     };
 
-    if (!this->subtype_value.has_value()) {
+    if (!this->subtype_value) {
         return false;
     }
 
     if (auto it = rare_table.find(this->type_value); it != rare_table.end()) {
         const auto &svals = it->second;
-        return svals.empty() || (svals.find(this->subtype_value.value()) != svals.end());
+        return svals.empty() || (svals.find(*this->subtype_value) != svals.end());
     }
 
     return false;
@@ -415,11 +390,11 @@ bool BaseitemKey::is_rare() const
 
 short BaseitemKey::get_bow_energy() const
 {
-    if ((this->type_value != ItemKindType::BOW) || !this->subtype_value.has_value()) {
-        throw std::logic_error(ITEM_NOT_BOW);
+    if ((this->type_value != ItemKindType::BOW) || !this->subtype_value) {
+        THROW_EXCEPTION(std::logic_error, ITEM_NOT_BOW);
     }
 
-    switch (this->subtype_value.value()) {
+    switch (*this->subtype_value) {
     case SV_SLING:
         return 8000;
     case SV_NAMAKE_BOW:
@@ -435,11 +410,11 @@ short BaseitemKey::get_bow_energy() const
 
 int BaseitemKey::get_arrow_magnification() const
 {
-    if ((this->type_value != ItemKindType::BOW) || !this->subtype_value.has_value()) {
-        throw std::logic_error(ITEM_NOT_BOW);
+    if ((this->type_value != ItemKindType::BOW) || !this->subtype_value) {
+        THROW_EXCEPTION(std::logic_error, ITEM_NOT_BOW);
     }
 
-    switch (this->subtype_value.value()) {
+    switch (*this->subtype_value) {
     case SV_SLING:
     case SV_SHORT_BOW:
         return 2;
@@ -456,11 +431,11 @@ int BaseitemKey::get_arrow_magnification() const
 
 bool BaseitemKey::is_aiming_rod() const
 {
-    if ((this->type_value != ItemKindType::ROD) || !this->subtype_value.has_value()) {
-        throw std::logic_error(ITEM_NOT_ROD);
+    if ((this->type_value != ItemKindType::ROD) || !this->subtype_value) {
+        THROW_EXCEPTION(std::logic_error, ITEM_NOT_ROD);
     }
 
-    switch (this->subtype_value.value()) {
+    switch (*this->subtype_value) {
     case SV_ROD_TELEPORT_AWAY:
     case SV_ROD_DISARMING:
     case SV_ROD_LITE:
@@ -485,11 +460,11 @@ bool BaseitemKey::is_aiming_rod() const
 
 bool BaseitemKey::is_lite_requiring_fuel() const
 {
-    if ((this->type_value != ItemKindType::LITE) || !this->subtype_value.has_value()) {
-        throw std::logic_error(ITEM_NOT_LITE);
+    if ((this->type_value != ItemKindType::LITE) || !this->subtype_value) {
+        THROW_EXCEPTION(std::logic_error, ITEM_NOT_LITE);
     }
 
-    switch (this->subtype_value.value()) {
+    switch (*this->subtype_value) {
     case SV_LITE_TORCH:
     case SV_LITE_LANTERN:
         return true;
@@ -525,11 +500,11 @@ bool BaseitemKey::is_armour() const
 
 bool BaseitemKey::is_cross_bow() const
 {
-    if ((this->type_value != ItemKindType::BOW) || !this->subtype_value.has_value()) {
+    if ((this->type_value != ItemKindType::BOW) || !this->subtype_value) {
         return false;
     }
 
-    switch (this->subtype_value.value()) {
+    switch (*this->subtype_value) {
     case SV_LIGHT_XBOW:
     case SV_HEAVY_XBOW:
         return true;
@@ -538,13 +513,68 @@ bool BaseitemKey::is_cross_bow() const
     }
 }
 
+bool BaseitemKey::should_refuse_enchant() const
+{
+    return *this == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE);
+}
+
+/*!
+ * @brief ベースアイテムが発動効果を持つ時、その記述を生成する
+ * @return 発動効果
+ */
+std::string BaseitemKey::explain_activation() const
+{
+    switch (this->type_value) {
+    case ItemKindType::WHISTLE:
+        return _("ペット呼び寄せ : 100+d100ターン毎", "call pet every 100+d100 turns");
+    case ItemKindType::CAPTURE:
+        return _("モンスターを捕える、又は解放する。", "captures or releases a monster.");
+    default:
+        return _("何も起きない", "Nothing");
+    }
+}
+
+bool BaseitemKey::is_convertible() const
+{
+    auto is_convertible = this->is(ItemKindType::JUNK) || this->is(ItemKindType::SKELETON);
+    is_convertible |= *this == BaseitemKey(ItemKindType::CORPSE, SV_SKELETON);
+    return is_convertible;
+}
+
+bool BaseitemKey::is_fuel() const
+{
+    auto is_fuel = *this == BaseitemKey(ItemKindType::LITE, SV_LITE_TORCH);
+    is_fuel |= *this == BaseitemKey(ItemKindType::LITE, SV_LITE_LANTERN);
+    is_fuel |= *this == BaseitemKey(ItemKindType::FLASK, SV_FLASK_OIL);
+    return is_fuel;
+}
+
+bool BaseitemKey::is_lance() const
+{
+    auto is_lance = *this == BaseitemKey(ItemKindType::POLEARM, SV_LANCE);
+    is_lance |= *this == BaseitemKey(ItemKindType::POLEARM, SV_HEAVY_LANCE);
+    return is_lance;
+}
+
+bool BaseitemKey::is_readable() const
+{
+    auto can_read = this->is(ItemKindType::SCROLL);
+    can_read |= this->is(ItemKindType::PARCHMENT);
+    return can_read;
+}
+
+bool BaseitemKey::is_corpse() const
+{
+    return *this == BaseitemKey(ItemKindType::CORPSE, SV_CORPSE);
+}
+
 bool BaseitemKey::is_mushrooms() const
 {
-    if (!this->subtype_value.has_value()) {
+    if (!this->subtype_value) {
         return false;
     }
 
-    switch (this->subtype_value.value()) {
+    switch (*this->subtype_value) {
     case SV_FOOD_POISON:
     case SV_FOOD_BLINDNESS:
     case SV_FOOD_PARANOIA:
@@ -615,4 +645,12 @@ void BaseitemInfo::decide_easy_know()
     }
 }
 
+/*!
+ * @brief オブジェクトを試行済にする
+ */
+void BaseitemInfo::mark_as_tried()
+{
+    this->tried = true;
+}
+
 std::vector<BaseitemInfo> baseitems_info;
index 9043a34..5f7688f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/tr-flags.h"
 #include "object-enchant/trg-types.h"
 enum class ItemKindType : short;
 class BaseitemKey {
 public:
-    BaseitemKey(const ItemKindType type_value, const std::optional<int> &subtype_value = std::nullopt);
+    constexpr BaseitemKey(const ItemKindType type_value, const std::optional<int> &subtype_value = std::nullopt)
+        : type_value(type_value)
+        , subtype_value(subtype_value)
+    {
+    }
+
     bool operator==(const BaseitemKey &other) const;
     bool operator!=(const BaseitemKey &other) const
     {
@@ -37,6 +42,7 @@ public:
 
     ItemKindType tval() const;
     std::optional<int> sval() const;
+    bool is(ItemKindType tval) const;
 
     ItemKindType get_arrow_kind() const;
     bool is_spell_book() const;
@@ -65,6 +71,13 @@ public:
     bool is_junk() const;
     bool is_armour() const;
     bool is_cross_bow() const;
+    bool should_refuse_enchant() const;
+    std::string explain_activation() const;
+    bool is_convertible() const;
+    bool is_fuel() const;
+    bool is_lance() const;
+    bool is_readable() const;
+    bool is_corpse() const;
 
 private:
     ItemKindType type_value;
@@ -125,6 +138,8 @@ public:
     IDX flavor{}; /*!< 未鑑定名の何番目を当てるか(0は未鑑定名なし) / Special object flavor (or zero) */
     bool aware{}; /*!< ベースアイテムが鑑定済かどうか /  The player is "aware" of the item's effects */
     bool tried{}; /*!< ベースアイテムを未鑑定のまま試したことがあるか /  The player has "tried" one of the items */
+
+    void mark_as_tried();
 };
 
 extern std::vector<BaseitemInfo> baseitems_info;
index 42c2765..4e17882 100644 (file)
@@ -1,4 +1,4 @@
-#include "system/building-type-definition.h"
+#include "system/building-type-definition.h"
 
-building_type building[MAX_BLDG];
+std::array<building_type, MAX_BUILDINGS> buildings;
 MonsterRaceId battle_mon_list[4];
index 6edbc52..99bc16d 100644 (file)
@@ -1,31 +1,31 @@
-#pragma once
+#pragma once
 
 #include "player-info/class-types.h"
 #include "player-info/race-types.h"
 #include "realm/realm-types.h"
-#include "system/angband.h"
+#include <array>
 #include <vector>
 
-#define MAX_BLDG 32 /*!< 施設の種類最大数 / Number of buildings */
+constexpr auto MAX_BUILDINGS = 32; /*!< 施設の種類最大数 / Number of buildings */
 
-enum class MonsterRaceId : int16_t;
+enum class MonsterRaceId : short;
 
 struct building_type {
-    GAME_TEXT name[20]; /* proprietor name */
-    GAME_TEXT owner_name[20]; /* proprietor name */
-    GAME_TEXT owner_race[20]; /* proprietor race */
+    char name[20]{}; /* proprietor name */
+    char owner_name[20]{}; /* proprietor name */
+    char owner_race[20]{}; /* proprietor race */
 
-    GAME_TEXT act_names[8][30]; /* action names */
-    PRICE member_costs[8]; /* Costs for class members of building */
-    PRICE other_costs[8]; /* Costs for nonguild members */
-    char letters[8]; /* action letters */
-    int16_t actions[8]; /*!< 町の施設処理における行動ID */
-    int16_t action_restr[8]; /*!< 町の施設処理の規制処理ID */
+    char act_names[8][30]{}; /* action names */
+    int member_costs[8]{}; /* Costs for class members of building */
+    int other_costs[8]{}; /* Costs for nonguild members */
+    char letters[8]{}; /* action letters */
+    short actions[8]{}; /*!< 町の施設処理における行動ID */
+    short action_restr[8]{}; /*!< 町の施設処理の規制処理ID */
 
-    std::vector<short> member_class; /* which classes are part of guild */
-    std::vector<short> member_race; /* which races are part of guild */
-    std::vector<short> member_realm; /* 店主ごとの魔法領域 / which realms are part of guild */
+    std::vector<short> member_class{}; /* which classes are part of guild */
+    std::vector<short> member_race{}; /* which races are part of guild */
+    std::vector<short> member_realm{}; /* 店主ごとの魔法領域 / which realms are part of guild */
 };
 
-extern building_type building[MAX_BLDG];
+extern std::array<building_type, MAX_BUILDINGS> buildings;
 extern MonsterRaceId battle_mon_list[4];
index 6af774a..f7d39ea 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "floor/floor-base-definitions.h"
 #include "system/angband.h"
index 1c98437..35109a5 100644 (file)
@@ -1,4 +1,4 @@
-#include "system/dungeon-info.h"
+#include "system/dungeon-info.h"
 #include "dungeon/dungeon-flag-mask.h"
 
 /*
index b31b24a..22c9ff6 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "dungeon/dungeon-flag-types.h"
 #include "monster-race/race-ability-flags.h"
@@ -45,6 +45,7 @@ constexpr auto DUNGEON_FEAT_PROB_NUM = 3;
 
 enum class FixedArtifactId : short;
 enum class MonsterRaceId : int16_t;
+enum class MonsterSex;
 
 struct feat_prob {
     FEAT_IDX feat{}; /* Feature tile */
@@ -97,6 +98,7 @@ struct dungeon_type {
     EnumClassFlagGroup<MonsterPopulationType> mon_population_flags;
     EnumClassFlagGroup<MonsterSpeakType> mon_speak_flags;
     EnumClassFlagGroup<MonsterBrightnessType> mon_brightness_flags;
+    MonsterSex mon_sex{};
 
     std::vector<char> r_chars; /* Monster symbols allowed */
     short final_object{}; /* The object you'll find at the bottom */
index e247029..fa12e21 100644 (file)
@@ -1,6 +1,144 @@
-#include "system/floor-type-definition.h"
+#include "system/floor-type-definition.h"
+#include "dungeon/quest.h"
+#include "game-option/birth-options.h"
+#include "system/angband-system.h"
+#include "system/dungeon-info.h"
+#include "system/grid-type-definition.h"
+#include "system/item-entity.h"
+#include "system/monster-entity.h"
+#include "util/bit-flags-calculator.h"
+#include "util/enum-range.h"
+
+FloorType::FloorType()
+    : quest_number(QuestId::NONE)
+{
+}
+
+Grid &FloorType::get_grid(const Pos2D pos)
+{
+    return this->grid_array[pos.y][pos.x];
+}
+
+const Grid &FloorType::get_grid(const Pos2D pos) const
+{
+    return this->grid_array[pos.y][pos.x];
+}
 
 bool FloorType::is_in_dungeon() const
 {
     return this->dun_level > 0;
 }
+
+bool FloorType::is_in_quest() const
+{
+    return this->quest_number != QuestId::NONE;
+}
+
+void FloorType::set_dungeon_index(short dungeon_idx_)
+{
+    this->dungeon_idx = dungeon_idx_;
+}
+
+void FloorType::reset_dungeon_index()
+{
+    this->set_dungeon_index(0);
+}
+
+dungeon_type &FloorType::get_dungeon_definition() const
+{
+    return dungeons_info[this->dungeon_idx];
+}
+
+/*!
+ * @brief 新しく入ったダンジョンの階層に固定されているランダムクエストを探し出しIDを返す。
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @param level 検索対象になる階
+ * @return クエストIDを返す。該当がない場合0を返す。
+ */
+QuestId FloorType::get_random_quest_id(std::optional<int> level_opt) const
+{
+    if (this->dungeon_idx != DUNGEON_ANGBAND) {
+        return QuestId::NONE;
+    }
+
+    const auto level = level_opt.value_or(this->dun_level);
+    const auto &quest_list = QuestList::get_instance();
+    for (auto q_idx : EnumRange(QuestId::RANDOM_QUEST1, QuestId::RANDOM_QUEST10)) {
+        const auto &quest = quest_list[q_idx];
+        auto is_random_quest = (quest.type == QuestKindType::RANDOM);
+        is_random_quest &= (quest.status == QuestStatusType::TAKEN);
+        is_random_quest &= (quest.level == level);
+        is_random_quest &= (quest.dungeon == DUNGEON_ANGBAND);
+        if (is_random_quest) {
+            return q_idx;
+        }
+    }
+
+    return QuestId::NONE;
+}
+
+/*!
+ * @brief 新しく入ったダンジョンの階層に固定されている一般のクエストを探し出しIDを返す.
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @param bonus 検索対象になる階へのボーナス。通常0
+ * @return クエストIDを返す。該当がない場合0を返す。
+ */
+QuestId FloorType::get_quest_id(const int bonus) const
+{
+    const auto &quest_list = QuestList::get_instance();
+    if (this->is_in_quest()) {
+        return this->quest_number;
+    }
+
+    const auto level = this->dun_level + bonus;
+    for (const auto &[q_idx, quest] : quest_list) {
+        if (quest.status != QuestStatusType::TAKEN) {
+            continue;
+        }
+
+        auto depth_quest = (quest.type == QuestKindType::KILL_LEVEL);
+        depth_quest &= !(quest.flags & QUEST_FLAG_PRESET);
+        depth_quest &= (quest.level == level);
+        depth_quest &= (quest.dungeon == this->dungeon_idx);
+        if (depth_quest) {
+            return q_idx;
+        }
+    }
+
+    return this->get_random_quest_id(level);
+}
+
+/*
+ * @brief 与えられた座標のグリッドがLOSフラグを持つかを調べる
+ * @param pos 座標
+ * @return LOSフラグを持つか否か
+ */
+bool FloorType::has_los(const Pos2D pos) const
+{
+    return this->get_grid(pos).has_los();
+}
+
+/*!
+ * @brief 特別なフロアにいるかを判定する
+ * @return 固定クエスト、アリーナ、モンスター闘技場のいずれかならばtrue
+ */
+bool FloorType::is_special() const
+{
+    auto is_in_fixed_quest = this->is_in_quest();
+    is_in_fixed_quest &= !inside_quest(this->get_random_quest_id());
+    return is_in_fixed_quest || this->inside_arena || AngbandSystem::get_instance().is_phase_out();
+}
+
+/*!
+ * @brief テレポート・レベル無効フロアの判定
+ * @param to_player プレイヤーを対象としているか否か
+ * @return テレポート・レベルが不可能ならばtrue
+ */
+bool FloorType::can_teleport_level(bool to_player) const
+{
+    auto is_invalid_floor = to_player;
+    is_invalid_floor &= inside_quest(this->get_quest_id()) || (this->dun_level >= this->get_dungeon_definition().maxdepth);
+    is_invalid_floor &= this->dun_level >= 1;
+    is_invalid_floor &= ironman_downward;
+    return this->is_special() || is_invalid_floor;
+}
index 4cadfe9..1f9182a 100644 (file)
@@ -1,10 +1,11 @@
-#pragma once
+#pragma once
 
-#include "dungeon/quest.h"
 #include "floor/floor-base-definitions.h"
 #include "monster/monster-timed-effect-types.h"
 #include "system/angband.h"
+#include "util/point-2d.h"
 #include <array>
+#include <optional>
 #include <vector>
 
 /*!
@@ -33,14 +34,16 @@ constexpr auto VIEW_MAX = 1536;
  */
 constexpr auto REDRAW_MAX = 2298;
 
-struct grid_type;
+enum class QuestId : short;
+struct dungeon_type;
+class Grid;
 class MonsterEntity;
 class ItemEntity;
 class FloorType {
 public:
-    FloorType() = default;
-    DUNGEON_IDX dungeon_idx = 0;
-    std::vector<std::vector<grid_type>> grid_array;
+    FloorType();
+    short dungeon_idx = 0;
+    std::vector<std::vector<Grid>> grid_array;
     DEPTH dun_level = 0; /*!< 現在の実ダンジョン階層 base_level の参照元となる / Current dungeon level */
     DEPTH base_level = 0; /*!< 基本生成レベル、後述のobject_level, monster_levelの参照元となる / Base dungeon level */
     DEPTH object_level = 0; /*!< アイテムの生成レベル、 base_level を起点に一時変更する時に参照 / Current object creation level */
@@ -79,8 +82,19 @@ public:
     std::array<POSITION, REDRAW_MAX> redraw_x{};
 
     bool monster_noise = false;
-    QuestId quest_number = QuestId::NONE; /* Inside quest level */
+    QuestId quest_number;
     bool inside_arena = false; /* Is character inside on_defeat_arena_monster? */
 
+    Grid &get_grid(const Pos2D pos);
+    const Grid &get_grid(const Pos2D pos) const;
     bool is_in_dungeon() const;
+    bool is_in_quest() const;
+    void set_dungeon_index(short dungeon_idx_); /*!< @todo 後でenum class にする */
+    void reset_dungeon_index();
+    dungeon_type &get_dungeon_definition() const;
+    QuestId get_random_quest_id(std::optional<int> level_opt = std::nullopt) const;
+    QuestId get_quest_id(const int bonus = 0) const;
+    bool has_los(const Pos2D pos) const;
+    bool is_special() const;
+    bool can_teleport_level(bool to_player = false) const;
 };
index d9143fa..f4a8c70 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum game_option_types {
     OPT_PAGE_INPUT,
index 4db5533..1368f9c 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief ゲーム内で広範に使われる定数群の定義
  * @author Hourier
  * @date 2022/11/02
index ceac4dd..eef4c39 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * \file grafmode.c
+ * \file grafmode.cpp
  * \brief Load a list of possible graphics modes.
  *
  * Copyright (c) 2011 Brett Reid
@@ -16,7 +16,7 @@
  *    are included in all such copies.  Other copyrights may also apply.
  */
 /*
- * Imported from Angband 4.2.0 to support main-cocoa.m for Hengband.  Did not
+ * Imported from Angband 4.2.0 to support main-cocoa.mm for Hengband.  Did not
  * bring over the datafile parsing (datafile.h and datafile.c) so the
  * implementation here is different from that in Angband.
  */
@@ -24,6 +24,7 @@
 #include "system/grafmode.h"
 #include "io/files-util.h"
 #include "util/angband-files.h"
+#include "util/string-processor.h"
 #include "view/display-messages.h"
 
 #define GFPARSE_HAVE_NOTHING (0)
@@ -236,15 +237,14 @@ static void parse_line(GrafModeParserState* pgps, const char* line) {
                 * to separately store the base directory for the tile files.
                 */
                char chold = pgps->file_name[pgps->dir_len];
+               std::filesystem::path p;
 
                pgps->file_name[pgps->dir_len] = '\0';
-               path_build(
-                   pgps->list->path,
-                   sizeof(pgps->list->path),
-                   pgps->file_name,
-                   line + offset
-               );
+               p = path_build(std::filesystem::path(pgps->file_name,
+                       std::filesystem::path::native_format), line + offset);
                pgps->file_name[pgps->dir_len] = chold;
+               angband_strcpy(pgps->list->path, p.native().data(),
+                       sizeof(pgps->list->path));
            }
        }
        break;
@@ -458,12 +458,15 @@ bool init_graphics_modes(void) {
     char buf[1024];
     char line[1024];
     GrafModeParserState gps = { 0, buf, 0, 0, GFPARSE_HAVE_NOTHING, 0 };
+    std::filesystem::path p;
     FILE *f;
 
     /* Build the filename */
-    path_build(line, sizeof(line), ANGBAND_DIR_XTRA, "graf");
+    p = path_build(ANGBAND_DIR_XTRA, "graf");
+    angband_strcpy(line, p.native().data(), sizeof(line));
     gps.dir_len = strlen(line);
-    path_build(buf, sizeof(buf), line, "list.txt");
+    p = path_build(p, "list.txt");
+    angband_strcpy(buf, p.native().data(), sizeof(buf));
 
     f = angband_fopen(buf, FileOpenMode::READ);
     if (!f) {
index e6669e0..1a6e960 100644 (file)
@@ -1,5 +1,6 @@
-#include "system/grid-type-definition.h"
+#include "system/grid-type-definition.h"
 #include "monster-race/race-flags7.h"
+#include "system/angband-system.h"
 #include "system/monster-race-info.h"
 #include "system/terrain-type-definition.h"
 #include "util/bit-flags-calculator.h"
  * @param X 指定X座標
  * @return FLOOR属性を持っているならばTRUE
  */
-bool grid_type::is_floor() const
+bool Grid::is_floor() const
 {
     return any_bits(this->info, CAVE_FLOOR);
 }
 
-bool grid_type::is_room() const
+bool Grid::is_room() const
 {
     return any_bits(this->info, CAVE_ROOM);
 }
 
-bool grid_type::is_extra() const
+bool Grid::is_extra() const
 {
     return any_bits(this->info, CAVE_EXTRA);
 }
 
-bool grid_type::is_inner() const
+bool Grid::is_inner() const
 {
     return any_bits(this->info, CAVE_INNER);
 }
 
-bool grid_type::is_outer() const
+bool Grid::is_outer() const
 {
     return any_bits(this->info, CAVE_OUTER);
 }
 
-bool grid_type::is_solid() const
+bool Grid::is_solid() const
 {
     return any_bits(this->info, CAVE_SOLID);
 }
 
-bool grid_type::is_icky() const
+bool Grid::is_icky() const
 {
     return any_bits(this->info, CAVE_ICKY);
 }
 
-bool grid_type::is_lite() const
+bool Grid::is_lite() const
 {
     return any_bits(this->info, CAVE_LITE);
 }
 
-bool grid_type::is_redraw() const
+bool Grid::is_redraw() const
 {
     return any_bits(this->info, CAVE_REDRAW);
 }
 
-bool grid_type::is_view() const
+bool Grid::is_view() const
 {
     return any_bits(this->info, CAVE_VIEW);
 }
 
-bool grid_type::is_object() const
+bool Grid::is_object() const
 {
     return any_bits(this->info, CAVE_OBJECT);
 }
 
-bool grid_type::is_mark() const
+bool Grid::is_mark() const
 {
     return any_bits(this->info, CAVE_MARK);
 }
 
-bool grid_type::is_mirror() const
+bool Grid::is_mirror() const
 {
-    return this->is_object() && terrains_info[this->mimic].flags.has(TerrainCharacteristics::MIRROR);
+    return this->is_object() && TerrainList::get_instance()[this->mimic].flags.has(TerrainCharacteristics::MIRROR);
 }
 
 /*
  *  @brief 守りのルーンで守られているかを返す
  */
-bool grid_type::is_rune_protection() const
+bool Grid::is_rune_protection() const
 {
-    return this->is_object() && terrains_info[this->mimic].flags.has(TerrainCharacteristics::RUNE_PROTECTION);
+    return this->is_object() && TerrainList::get_instance()[this->mimic].flags.has(TerrainCharacteristics::RUNE_PROTECTION);
 }
 
 /*
  *  @brief 爆発のルーンが仕掛けられているかを返す
  */
-bool grid_type::is_rune_explosion() const
+bool Grid::is_rune_explosion() const
 {
-    return this->is_object() && terrains_info[this->mimic].flags.has(TerrainCharacteristics::RUNE_EXPLOSION);
+    return this->is_object() && TerrainList::get_instance()[this->mimic].flags.has(TerrainCharacteristics::RUNE_EXPLOSION);
 }
 
-byte grid_type::get_cost(MonsterRaceInfo *r_ptr) const
+byte Grid::get_cost(const MonsterRaceInfo *r_ptr) const
 {
     return this->costs[get_grid_flow_type(r_ptr)];
 }
 
-byte grid_type::get_distance(MonsterRaceInfo *r_ptr) const
+byte Grid::get_distance(const MonsterRaceInfo *r_ptr) const
 {
     return this->dists[get_grid_flow_type(r_ptr)];
 }
 
-flow_type grid_type::get_grid_flow_type(MonsterRaceInfo *r_ptr) const
+flow_type Grid::get_grid_flow_type(const MonsterRaceInfo *r_ptr) const
 {
     return r_ptr->feature_flags.has(MonsterFeatureType::CAN_FLY) ? FLOW_CAN_FLY : FLOW_NORMAL;
 }
@@ -111,14 +112,14 @@ flow_type grid_type::get_grid_flow_type(MonsterRaceInfo *r_ptr) const
  * @param g_ptr グリッドへの参照ポインタ
  * @return 地形情報
  */
-FEAT_IDX grid_type::get_feat_mimic() const
+FEAT_IDX Grid::get_feat_mimic() const
 {
-    return terrains_info[this->mimic ? this->mimic : this->feat].mimic;
+    return TerrainList::get_instance()[this->mimic ? this->mimic : this->feat].mimic;
 }
 
-bool grid_type::cave_has_flag(TerrainCharacteristics feature_flags) const
+bool Grid::cave_has_flag(TerrainCharacteristics feature_flags) const
 {
-    return terrains_info[this->feat].flags.has(feature_flags);
+    return this->get_terrain().flags.has(feature_flags);
 }
 
 /*!
@@ -126,7 +127,56 @@ bool grid_type::cave_has_flag(TerrainCharacteristics feature_flags) const
  * @param ch 指定するシンボル文字
  * @return シンボルが指定した記号か否か
  */
-bool grid_type::is_symbol(const int ch) const
+bool Grid::is_symbol(const int ch) const
 {
-    return terrains_info[this->feat].x_char[0] == ch;
+    return this->get_terrain().x_char[0] == ch;
+}
+
+void Grid::reset_costs()
+{
+    for (auto &cost : this->costs) {
+        cost = 0;
+    }
+}
+
+void Grid::reset_dists()
+{
+    for (auto &dist : this->dists) {
+        dist = 0;
+    }
+}
+
+bool Grid::has_los() const
+{
+    return any_bits(this->info, CAVE_VIEW) || AngbandSystem::get_instance().is_phase_out();
+}
+
+TerrainType &Grid::get_terrain()
+{
+    return TerrainList::get_instance()[this->feat];
+}
+
+const TerrainType &Grid::get_terrain() const
+{
+    return TerrainList::get_instance()[this->feat];
+}
+
+TerrainType &Grid::get_terrain_mimic()
+{
+    return TerrainList::get_instance()[this->get_feat_mimic()];
+}
+
+const TerrainType &Grid::get_terrain_mimic() const
+{
+    return TerrainList::get_instance()[this->get_feat_mimic()];
+}
+
+TerrainType &Grid::get_terrain_mimic_raw()
+{
+    return TerrainList::get_instance()[this->mimic];
+}
+
+const TerrainType &Grid::get_terrain_mimic_raw() const
+{
+    return TerrainList::get_instance()[this->mimic];
 }
index 5f70e0d..ed45104 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/object-index-list.h"
 #include "system/angband.h"
@@ -45,8 +45,9 @@ enum flow_type {
 };
 
 class MonsterRaceInfo;
+class TerrainType;
 enum class TerrainCharacteristics;
-struct grid_type {
+class Grid {
 public:
     BIT_FLAGS info{}; /* Hack -- grid flags */
 
@@ -82,12 +83,21 @@ public:
     bool is_mirror() const;
     bool is_rune_protection() const;
     bool is_rune_explosion() const;
-    byte get_cost(MonsterRaceInfo *r_ptr) const;
-    byte get_distance(MonsterRaceInfo *r_ptr) const;
+    byte get_cost(const MonsterRaceInfo *r_ptr) const;
+    byte get_distance(const MonsterRaceInfo *r_ptr) const;
     FEAT_IDX get_feat_mimic() const;
     bool cave_has_flag(TerrainCharacteristics feature_flags) const;
     bool is_symbol(const int ch) const;
+    void reset_costs();
+    void reset_dists();
+    bool has_los() const;
+    TerrainType &get_terrain();
+    const TerrainType &get_terrain() const;
+    TerrainType &get_terrain_mimic();
+    const TerrainType &get_terrain_mimic() const;
+    TerrainType &get_terrain_mimic_raw();
+    const TerrainType &get_terrain_mimic_raw() const;
 
 private:
-    flow_type get_grid_flow_type(MonsterRaceInfo *r_ptr) const;
+    flow_type get_grid_flow_type(const MonsterRaceInfo *r_ptr) const;
 };
index f322e7d..d5f081e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @file h-basic.h
index b6e9aaa..00c1590 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file h-config.h
  * @brief OSごとの差異を吸収してコンパイルするためのプリプロ群
  * The most basic "include" file.
index 9e8e95b..9ddb614 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file h-system.h
  * @brief 変愚蛮怒用システムヘッダーファイル /
  * The most basic "include" file.
index a173e2b..07e5f17 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @file h-type.h
@@ -53,12 +53,12 @@ typedef const char *concptr;
  */
 typedef int errr;
 
-#define MAX_UCHAR 255 /*!< Maximum value storable in a "byte" (hard-coded) */
-#define MAX_SHORT 32767 /*!< Maximum value storable in a "int16_t" (hard-coded) */
-
-#define MAX_NLEN 160 /*!< Maximum length of object's name */
+constexpr auto MAX_UCHAR = 255; /*!< Maximum value storable in a "byte" (hard-coded) */
+constexpr auto MAX_SHORT = 32767; /*!< Maximum value storable in a "int16_t" (hard-coded) */
+constexpr auto MAX_INT = 2147483647;
+constexpr auto MAX_NLEN = 160; /*!< Maximum length of object's name */
+constexpr auto MAX_MONSTER_NAME = 160; /*!< モンスター名称の最大バイト数 / Max characters of monster's name */
 #define MAX_INSCRIPTION _(76, 69) /*!< Maximum length of object's inscription */
-#define MAX_MONSTER_NAME 160 /*!< モンスター名称の最大バイト数 / Max characters of monster's name */
 
 /*!
  * @brief 符号なし整数の簡潔な定義
@@ -104,7 +104,6 @@ typedef char GAME_TEXT; /*!< ゲーム中のテキスト型定義 */
 typedef int32_t MANA_POINT; /*!< ゲーム中のMP型を定義 */
 
 typedef int16_t HIT_PROB; /*!< ゲーム中の装備命中修正値を定義 */
-typedef int16_t BASE_STATUS; /*!< ゲーム中の基礎能力値型を定義 */
 
 typedef int32_t MONSTER_NUMBER; /*!< ゲーム中のモンスター数型を定義 */
 typedef int32_t ITEM_NUMBER; /*!< ゲーム中のアイテム数型を定義 */
@@ -128,7 +127,6 @@ typedef int DIRECTION; /*!< ゲーム中の方角の型定義 */
 typedef int32_t EXP; /*!< ゲーム中の主経験値の型定義 */
 typedef int16_t SUB_EXP; /*!< ゲーム中の副経験値の型定義 */
 
-typedef int32_t OBJECT_SUBTYPE_VALUE; /*!< ゲーム中のアイテム副分類の型定義 */
 typedef int16_t PARAMETER_VALUE; /*!< ゲーム中のアイテム能力値の型定義 */
 typedef int32_t WEIGHT; /*!< ゲーム中の重量の型定義(ポンド) */
 
index 9c676b1..7ad0e3d 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @file item-entity.cpp
  * @brief アイテム実体とそれにまつわる判定処理群
  * @author Hourier
 #include "artifact/fixed-art-types.h"
 #include "artifact/random-art-effects.h"
 #include "monster-race/monster-race.h"
+#include "object-enchant/activation-info-table.h"
+#include "object-enchant/dragon-breaths-table.h"
+#include "object-enchant/item-feeling.h"
 #include "object-enchant/object-curse.h"
 #include "object-enchant/special-object-flags.h"
-#include "object/object-flags.h"
 #include "object/object-value.h"
 #include "object/tval-types.h"
 #include "smith/object-smith.h"
 #include "sv-definition/sv-lite-types.h"
-#include "sv-definition/sv-other-types.h"
+#include "sv-definition/sv-ring-types.h"
 #include "sv-definition/sv-weapon-types.h"
 #include "system/artifact-type-definition.h"
 #include "system/baseitem-info.h"
@@ -26,6 +28,7 @@
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
 #include "util/string-processor.h"
+#include <sstream>
 
 ItemEntity::ItemEntity()
     : bi_key(BaseitemKey(ItemKindType::NONE))
@@ -35,7 +38,6 @@ ItemEntity::ItemEntity()
 
 /*!
  * @brief アイテムを初期化する
- * Wipe an object clean.
  */
 void ItemEntity::wipe()
 {
@@ -44,8 +46,7 @@ void ItemEntity::wipe()
 
 /*!
  * @brief アイテムを複製する
- * Wipe an object clean.
- * @param j_ptr 複製元のオブジェクトの構造体参照ポインタ
+ * @param j_ptr 複製元アイテムへの参照ポインタ
  */
 void ItemEntity::copy_from(const ItemEntity *j_ptr)
 {
@@ -54,7 +55,6 @@ void ItemEntity::copy_from(const ItemEntity *j_ptr)
 
 /*!
  * @brief アイテム構造体にベースアイテムを作成する
- * @param player_ptr プレイヤーへの参照ポインタ
  * @param bi_id 新たに作成したいベースアイテム情報のID
  */
 void ItemEntity::prep(short new_bi_id)
@@ -108,9 +108,14 @@ void ItemEntity::prep(short new_bi_id)
     }
 }
 
+bool ItemEntity::is(ItemKindType tval) const
+{
+    return this->bi_key.is(tval);
+}
+
 /*!
- * @brief アイテムが武器として装備できるかどうかを返す / Check if an object is weapon (including bows)
- * @return æ­¦å\99¨ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 武器か否かを判定する
+ * @return æ­¦å\99¨ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_weapon() const
 {
@@ -118,8 +123,8 @@ bool ItemEntity::is_weapon() const
 }
 
 /*!
- * @brief アイテムが武器や矢弾として使用できるかを返す
- * @return æ­¦å\99¨ã\82\84ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 武器や矢弾として使用できるかを判定する
+ * @return æ­¦å\99¨ã\82\84ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_weapon_ammo() const
 {
@@ -127,8 +132,8 @@ bool ItemEntity::is_weapon_ammo() const
 }
 
 /*!
- * @brief アイテムが武器、防具、矢弾として使用できるかを返す / Check if an object is weapon, armour or ammo
- * @return æ­¦å\99¨ã\80\81é\98²å\85·ã\80\81ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 武器、防具、矢弾として使用できるかを判定する
+ * @return æ­¦å\99¨ã\80\81é\98²å\85·ã\80\81ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_weapon_armour_ammo() const
 {
@@ -136,8 +141,8 @@ bool ItemEntity::is_weapon_armour_ammo() const
 }
 
 /*!
- * @brief アイテムが近接武器として装備できるかを返す / Melee weapons
- * @return è¿\91æ\8e¥æ­¦å\99¨ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 近接武器として装備できるかを判定する
+ * @return è¿\91æ\8e¥æ­¦å\99¨ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_melee_weapon() const
 {
@@ -145,8 +150,8 @@ bool ItemEntity::is_melee_weapon() const
 }
 
 /*!
- * @brief エッセンスの付加可能な武器や矢弾かを返す
- * @return ã\82¨ã\83\83ã\82»ã\83³ã\82¹ã\81®ä»\98å\8a å\8f¯è\83½ã\81ªæ­¦å\99¨ã\81\8bç\9f¢å¼¾ã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99ã\80\82
+ * @brief エッセンスの付加可能な武器や矢弾かを判定する
+ * @return ã\82¨ã\83\83ã\82»ã\83³ã\82¹ã\81®ä»\98å\8a å\8f¯è\83½ã\81ªæ­¦å\99¨ã\81\8bç\9f¢å¼¾ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_melee_ammo() const
 {
@@ -154,8 +159,8 @@ bool ItemEntity::is_melee_ammo() const
 }
 
 /*!
- * @brief アイテムが装備可能であるかを返す / Wearable including all weapon, all armour, bow, light source, amulet, and ring
- * @return è£\85å\82\99å\8f¯è\83½ã\81ªã\82\89ã\81°TRUEã\82\92è¿\94ã\81\99
+ * @brief 装備可能であるかを判定する
+ * @return è£\85å\82\99å\8f¯è\83½ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_wearable() const
 {
@@ -163,8 +168,8 @@ bool ItemEntity::is_wearable() const
 }
 
 /*!
- * @brief アイテムが装備品であるかを返す(ItemEntity::is_wearableに矢弾を含む) / Equipment including all wearable objects and ammo
- * @return è£\85å\82\99å\93\81ã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 装備品であるかを判定する
+ * @return è£\85å\82\99å\93\81ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_equipment() const
 {
@@ -172,8 +177,8 @@ bool ItemEntity::is_equipment() const
 }
 
 /*!
- * @brief 武器匠の「武器」鑑定対象になるかを判定する。/ Hook to specify "weapon"
- * @return 対象になるならtrueを返す。
+ * @brief 武器匠の「武器」鑑定対象になるかを判定する
+ * @return 鑑定対象か否か
  */
 bool ItemEntity::is_orthodox_melee_weapons() const
 {
@@ -181,8 +186,8 @@ bool ItemEntity::is_orthodox_melee_weapons() const
 }
 
 /*!
- * @brief 修復対象となる壊れた武器かを判定する。 / Hook to specify "broken weapon"
- * @return ä¿®å¾©å¯¾è±¡ã\81«ã\81ªã\82\8bã\81ªã\82\89TRUEã\82\92è¿\94ã\81\99ã\80\82
+ * @brief 修復対象となる壊れた武器かを判定する
+ * @return ä¿®å¾©å¯¾è±¡ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_broken_weapon() const
 {
@@ -190,8 +195,8 @@ bool ItemEntity::is_broken_weapon() const
 }
 
 /*!
- * @brief アイテムが投射可能な武器かどうかを返す。
- * @return æ\8a\95å°\84å\8f¯è\83½ã\81ªæ­¦å\99¨ã\81ªã\82\89ã\81°true
+ * @brief 投射可能な武器かどうかを判定する
+ * @return æ\8a\95å°\84å\8f¯è\83½ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_throwable() const
 {
@@ -199,8 +204,8 @@ bool ItemEntity::is_throwable() const
 }
 
 /*!
- * @brief ã\82¢ã\82¤ã\83\86ã\83 ã\81\8cã\81©ã\81¡ã\82\89ã\81®æ\89\8bã\81«ã\82\82è£\85å\82\99ã\81§ã\81\8dã\82\8bæ­¦å\99¨ã\81\8bã\81©ã\81\86ã\81\8bã\81®å\88¤å®\9a
- * @return 左右両方の手で装備できるならばtrueを返す。
+ * @brief ã\81©ã\81¡ã\82\89ã\81®æ\89\8bã\81«ã\82\82è£\85å\82\99ã\81§ã\81\8dã\82\8bæ­¦å\99¨ã\81\8bã\82\92å\88¤å®\9aã\81\99ã\82\8b
+ * @return 左右両方の手で装備可能か否か
  */
 bool ItemEntity::is_wieldable_in_etheir_hand() const
 {
@@ -208,47 +213,35 @@ bool ItemEntity::is_wieldable_in_etheir_hand() const
 }
 
 /*!
- * @brief アイテムが強化不能武器であるかを返す / Poison needle can not be enchanted
- * @return 強化不能ならばtrueを返す
- */
-bool ItemEntity::refuse_enchant_weapon() const
-{
-    return this->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE);
-}
-
-/*!
- * @brief アイテムが強化可能武器であるかを返す /
- * Check if an object is weapon (including bows and ammo) and allows enchantment
- * @return 強化可能ならばtrueを返す
+ * @brief 強化可能武器であるかを判定する
+ * @return 強化可能か否か
  */
 bool ItemEntity::allow_enchant_weapon() const
 {
-    return this->is_weapon_ammo() && !this->refuse_enchant_weapon();
+    return this->is_weapon_ammo() && !this->should_refuse_enchant();
 }
 
 /*!
- * @brief アイテムが強化可能な近接武器であるかを返す /
- * Check if an object is melee weapon and allows enchantment
- * @return 強化可能な近接武器ならばtrueを返す
+ * @brief 強化可能な近接武器であるかを判定する
+ * @return 強化可能な近接武器か否か
  */
 bool ItemEntity::allow_enchant_melee_weapon() const
 {
-    return this->is_melee_weapon() && !this->refuse_enchant_weapon();
+    return this->is_melee_weapon() && !this->should_refuse_enchant();
 }
 
 /*!
- * @brief アイテムが両手持ち可能な武器かを返す /
- * Check if an object is melee weapon and allows wielding with two-hands
- * @return 両手持ち可能ならばTRUEを返す
+ * @brief 両手持ち可能な武器かを判定する
+ * @return 両手持ち可能か否か
  */
 bool ItemEntity::allow_two_hands_wielding() const
 {
-    return this->is_melee_weapon() && ((this->weight > 99) || (this->bi_key.tval() == ItemKindType::POLEARM));
+    return this->is_melee_weapon() && ((this->weight > 99) || this->is(ItemKindType::POLEARM));
 }
 
 /*!
- * @brief アイテムが矢弾として使用できるかどうかを返す / Check if an object is ammo
- * @return ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 矢弾として使用できるかどうかを判定する
+ * @return ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_ammo() const
 {
@@ -256,28 +249,22 @@ bool ItemEntity::is_ammo() const
 }
 
 /*!
- * @brief 対象のアイテムが矢やクロスボウの矢の材料になるかを返す。/
- * Hook to determine if an object is contertible in an arrow/bolt
- * @return 材料にできるならtrueを返す
+ * @brief 対象の矢やクロスボウの矢の材料になるかを判定する
+ * @return 材料にできるか否か
  */
 bool ItemEntity::is_convertible() const
 {
-    const auto tval = this->bi_key.tval();
-    auto is_convertible = (tval == ItemKindType::JUNK) || (tval == ItemKindType::SKELETON);
-    is_convertible |= this->bi_key == BaseitemKey(ItemKindType::CORPSE, SV_SKELETON);
-    return is_convertible;
+    return this->bi_key.is_convertible();
 }
 
 bool ItemEntity::is_lance() const
 {
-    auto is_lance = this->bi_key == BaseitemKey(ItemKindType::POLEARM, SV_LANCE);
-    is_lance |= this->bi_key == BaseitemKey(ItemKindType::POLEARM, SV_HEAVY_LANCE);
-    return is_lance;
+    return this->bi_key.is_lance();
 }
 
 /*!
- * @brief アイテムが防具として装備できるかどうかを返す
- * @return é\98²å\85·ã\81¨ã\81\97ã\81¦è£\85å\82\99ã\81§ã\81\8dã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 防具かを判定する
+ * @return é\98²å\85·ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_protector() const
 {
@@ -285,8 +272,8 @@ bool ItemEntity::is_protector() const
 }
 
 /*!
- * @brief ã\82¢ã\82¤ã\83\86ã\83 ã\81\8cã\82ªã\83¼ã\83©ã\82\92çº\8fã\81\88ã\82\8bé\98²å\85·ã\81\8bã\81©ã\81\86ã\81\8bã\82\92è¿\94ã\81\99
- * @return ã\82ªã\83¼ã\83©ã\82\92çº\8fã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief ã\82ªã\83¼ã\83©ã\82\92çº\8fã\81\88ã\82\8bé\98²å\85·ã\81\8bã\81©ã\81\86ã\81\8bã\82\92å\88¤å®\9aã\81\99ã\82\8b
+ * @return ã\82ªã\83¼ã\83©ã\82\92çº\8fã\81\88ã\82\8bã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::can_be_aura_protector() const
 {
@@ -294,9 +281,8 @@ bool ItemEntity::can_be_aura_protector() const
 }
 
 /*!
- * @brief アイテムがレアアイテムかどうかを返す /
- * Rare weapons/aromors including Blade of Chaos, Dragon armors, etc.
- * @return レアアイテムならばTRUEを返す
+ * @brief レアアイテムかどうかを判定する
+ * @return レアアイテムか否か
  */
 bool ItemEntity::is_rare() const
 {
@@ -304,8 +290,8 @@ bool ItemEntity::is_rare() const
 }
 
 /*!
- * @brief ã\82¢ã\82¤ã\83\86ã\83 ã\81\8cã\82¨ã\82´ã\82¢ã\82¤ã\83\86ã\83 ã\81\8bã\81©ã\81\86ã\81\8bã\82\92è¿\94ã\81\99
- * @return ã\82¨ã\82´ã\82¢ã\82¤ã\83\86ã\83 ã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief ã\82¨ã\82´ã\82¢ã\82¤ã\83\86ã\83 ã\81\8bã\81©ã\81\86ã\81\8bã\82\92å\88¤å®\9aã\81\99ã\82\8b
+ * @return ã\82¨ã\82´ã\82¢ã\82¤ã\83\86ã\83 ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_ego() const
 {
@@ -313,29 +299,26 @@ bool ItemEntity::is_ego() const
 }
 
 /*!
- * @brief アイテムが鍛冶師のエッセンス付加済みかを返す /
- * Check if an object is made by a smith's special ability
- * @return エッセンス付加済みならばTRUEを返す
+ * @brief 鍛冶師のエッセンス付加済かを判定する
+ * @return エッセンス付加済か否か
  */
 bool ItemEntity::is_smith() const
 {
-    return Smith::object_effect(this).has_value() || Smith::object_activation(this).has_value();
+    return Smith::object_effect(this) || Smith::object_activation(this);
 }
 
 /*!
- * @brief アイテムが固定アーティファクトもしくはランダムアーティファクトであるかを返す /
- * Check if an object is artifact
- * @return 固定アーティファクトもしくはランダムアーティファクトならばtrueを返す
+ * @brief 固定アーティファクトもしくはランダムアーティファクトであるかを判定する
+ * @return 固定アーティファクトもしくはランダムアーティファクトか否か
  */
 bool ItemEntity::is_fixed_or_random_artifact() const
 {
-    return this->is_fixed_artifact() || this->randart_name.has_value();
+    return this->is_fixed_artifact() || this->randart_name;
 }
 
 /*!
- * @brief アイテムが固定アーティファクトかを返す /
- * Check if an object is fixed artifact
- * @return 固定アーティファクトならばtrueを返す
+ * @brief 固定アーティファクトかを判定する
+ * @return 固定アーティファクトか否か
  */
 bool ItemEntity::is_fixed_artifact() const
 {
@@ -343,9 +326,8 @@ bool ItemEntity::is_fixed_artifact() const
 }
 
 /*!
- * @brief アイテムがランダムアーティファクトかを返す /
- * Check if an object is random artifact
- * @return ランダムアーティファクトならばtrueを返す
+ * @brief ランダムアーティファクトかを判定する
+ * @return ランダムアーティファクトか否か
  */
 bool ItemEntity::is_random_artifact() const
 {
@@ -353,9 +335,8 @@ bool ItemEntity::is_random_artifact() const
 }
 
 /*!
- * @brief アイテムが通常のアイテム(アーティファクト、エゴ、鍛冶師エッセンス付加いずれでもない)かを返す /
- * Check if an object is neither artifact, ego, nor 'smith' object
- * @return 通常のアイテムならばtrueを返す
+ * @brief 通常のアイテムかを返す
+ * @return アーティファクト、エゴ、鍛冶師エッセンス付加いずれでもないか、どれか1つであるか
  */
 bool ItemEntity::is_nameless() const
 {
@@ -383,9 +364,8 @@ bool ItemEntity::is_held_by_monster() const
 }
 
 /*
- * Determine if a given inventory item is "known"
- * Test One -- Check for special "known" tag
- * Test Two -- Check for "Easy Know" + "Aware"
+ * @brief 鑑定済かを判定する
+ * @return 鑑定済か否か
  */
 bool ItemEntity::is_known() const
 {
@@ -399,8 +379,8 @@ bool ItemEntity::is_fully_known() const
 }
 
 /*!
- * @brief 与えられたオブジェクトのベースアイテムが鑑定済かを返す / Determine if a given inventory item is "aware"
- * @return é\91\91å®\9aæ¸\88ã\81ªã\82\89true
+ * @brief ベースアイテムが鑑定済かを判定する
+ * @return é\91\91å®\9aæ¸\88ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_aware() const
 {
@@ -408,7 +388,8 @@ bool ItemEntity::is_aware() const
 }
 
 /*
- * Determine if a given inventory item is "tried"
+ * @brief ベースアイテムが試行済かを判定する
+ * @return 試行済か否か
  */
 bool ItemEntity::is_tried() const
 {
@@ -416,44 +397,38 @@ bool ItemEntity::is_tried() const
 }
 
 /*!
- * @brief アイテムが薬であるかを返す
- * @return オブジェクトが薬ならばtrueを返す
+ * @brief 薬であるかを判定する
+ * @return 薬か否か
  */
 bool ItemEntity::is_potion() const
 {
-    return this->bi_key.tval() == ItemKindType::POTION;
+    return this->bi_key.is(ItemKindType::POTION);
 }
 
 /*!
- * @brief アイテムをプレイヤーが読むことができるかを判定する /
- * Hook to determine if an object is readable
- * @return 読むことが可能ならばtrueを返す
+ * @brief 読めるアイテムかを判定する
+ * @return 読めるか否か
  */
 bool ItemEntity::is_readable() const
 {
-    const auto tval = this->bi_key.tval();
-    auto can_read = tval == ItemKindType::SCROLL;
-    can_read |= tval == ItemKindType::PARCHMENT;
+    auto can_read = this->bi_key.is_readable();
     can_read |= this->is_specific_artifact(FixedArtifactId::GHB);
     can_read |= this->is_specific_artifact(FixedArtifactId::POWER);
     return can_read;
 }
 
 /*!
- * @brief アイテムがランタンの燃料になるかどうかを判定する
- * An "item_tester_hook" for refilling lanterns
- * @return オブジェクトがランタンの燃料になるならばTRUEを返す
+ * @brief ランタンの燃料になるかを判定する
+ * @return ランタンの燃料になるか否か
  */
 bool ItemEntity::can_refill_lantern() const
 {
-    const auto tval = this->bi_key.tval();
-    return (tval == ItemKindType::FLASK) || (this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_LANTERN));
+    return this->is(ItemKindType::FLASK) || (this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_LANTERN));
 }
 
 /*!
- * @brief アイテムが松明に束ねられるかどうかを判定する
- * An "item_tester_hook" for refilling torches
- * @return オブジェクトが松明に束ねられるならばTRUEを返す
+ * @brief 松明に束ねられるかどうかを判定する
+ * @return 松明に束ねられるか否か
  */
 bool ItemEntity::can_refill_torch() const
 {
@@ -462,7 +437,7 @@ bool ItemEntity::can_refill_torch() const
 
 /*!
  * @brief 魔力充填が可能なアイテムかどうか判定する
- * @return é­\94å\8a\9bå\85\85å¡«ã\81\8cå\8f¯è\83½ã\81ªã\82\89ã\81°TRUEã\82\92è¿\94ã\81\99
+ * @return é­\94å\8a\9bå\85\85å¡«ã\81\8cå\8f¯è\83½ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::can_recharge() const
 {
@@ -470,12 +445,12 @@ bool ItemEntity::can_recharge() const
 }
 
 /*!
- * @brief 悪魔領域のグレーターデーモン召喚に利用可能な死体かどうかを返す。 / An "item_tester_hook" for offer
- * @return ç\94\9fè´\84ã\81«ä½¿ç\94¨å\8f¯è\83½ã\81ªæ­»ä½\93ã\81ªã\82\89ã\81°TRUEã\82\92è¿\94ã\81\99ã\80\82
+ * @brief 悪魔領域のグレーターデーモン召喚に利用可能な死体かどうかを判定する
+ * @return ç\94\9fè´\84ã\81«ä½¿ç\94¨å\8f¯è\83½ã\81ªæ­»ä½\93ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_offerable() const
 {
-    if (this->bi_key != BaseitemKey(ItemKindType::CORPSE, SV_CORPSE)) {
+    if (!this->is_corpse()) {
         return false;
     }
 
@@ -483,9 +458,8 @@ bool ItemEntity::is_offerable() const
 }
 
 /*!
- * @brief アイテムをプレイヤーが魔道具として発動できるかを判定する /
- * Hook to determine if an object is activatable
- * @return 魔道具として発動可能ならばTRUEを返す
+ * @brief 魔道具として発動できるかを判定する
+ * @return 発動可能か否か
  */
 bool ItemEntity::is_activatable() const
 {
@@ -493,24 +467,21 @@ bool ItemEntity::is_activatable() const
         return false;
     }
 
-    auto flags = object_flags(this);
+    const auto flags = this->get_flags();
     return flags.has(TR_ACTIVATE);
 }
 
 /*!
- * @brief アイテムが燃料として使えるかを判定する
+ * @brief 燃料として使えるかを判定する
  * @return 燃料か否か
  */
 bool ItemEntity::is_fuel() const
 {
-    auto is_fuel = this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_TORCH);
-    is_fuel |= this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_LANTERN);
-    is_fuel |= this->bi_key == BaseitemKey(ItemKindType::FLASK, SV_FLASK_OIL);
-    return is_fuel;
+    return this->bi_key.is_fuel();
 }
 
 /*!
- * @brief アイテムが魔法書かどうかを判定する
+ * @brief 魔法書かどうかを判定する
  * @return 魔法書か否か
  */
 bool ItemEntity::is_spell_book() const
@@ -519,7 +490,7 @@ bool ItemEntity::is_spell_book() const
 }
 
 /*!
- * @brief アイテムが同一の命中値上昇及びダメージ上昇があるかを判定する
+ * @brief 同一の命中値上昇及びダメージ上昇があるかを判定する
  * @return 同一修正か
  * @details 鍛冶師が篭手に殺戮エッセンスを付加した場合のみこの判定に意味がある
  */
@@ -541,7 +512,7 @@ bool ItemEntity::is_glove_same_temper(const ItemEntity *j_ptr) const
 }
 
 /*!
- * @brief ã\82¢ã\82¤ã\83\86ã\83 ã\81\8cã\80\8c\81¤ã\81®ï½\9eï½\9eã\80\8dã\81¨é\87\8dã\81­ã\82\89ã\82\8cã\82\8bã\81\8bã\82\92ä¸\80è\88¬ç\9a\84ã\81«å\88¤å®\9aã\81\99ã\82\8b
+ * @brief 「2つの~~」と重ねられるかを一般的に判定する
  * @return 重ねられるか
  * @details 個別のアイテムによっては別途条件があるが、それはこの関数では判定しない
  */
@@ -622,10 +593,10 @@ TERM_COLOR ItemEntity::get_color() const
         return baseitems_info[flavor].x_attr;
     }
 
-    auto has_attr = !this->is_valid();
-    has_attr |= this->bi_key != BaseitemKey(ItemKindType::CORPSE, SV_CORPSE);
-    has_attr |= baseitem.x_attr != TERM_DARK;
-    if (has_attr) {
+    auto has_attr = this->is_valid();
+    has_attr &= this->is_corpse();
+    has_attr &= baseitem.x_attr == TERM_DARK;
+    if (!has_attr) {
         return baseitem.x_attr;
     }
 
@@ -647,7 +618,7 @@ char ItemEntity::get_symbol() const
 
 /*!
  * @brief アイテム価格算出のメインルーチン
- * @return オブジェクトの判明している現価格
+ * @return 判明している現価格
  */
 int ItemEntity::get_price() const
 {
@@ -710,35 +681,23 @@ int ItemEntity::get_baseitem_price() const
 
 int ItemEntity::calc_figurine_value() const
 {
-    auto figure_r_idx = i2enum<MonsterRaceId>(this->pval);
-    auto level = monraces_info[figure_r_idx].level;
-    if (level < 20) {
-        return level * 50L;
-    }
-
-    if (level < 30) {
-        return 1000 + (level - 20) * 150;
-    }
-
-    if (level < 40) {
-        return 2500 + (level - 30) * 350;
-    }
-
-    if (level < 50) {
-        return 6000 + (level - 40) * 800;
-    }
-
-    return 14000 + (level - 50) * 2000;
+    const auto r_idx = i2enum<MonsterRaceId>(this->pval);
+    return MonraceList::get_instance().calc_figurine_value(r_idx);
 }
 
 int ItemEntity::calc_capture_value() const
 {
-    auto capture_r_idx = i2enum<MonsterRaceId>(this->pval);
-    if (!MonsterRace(capture_r_idx).is_valid()) {
-        return 1000;
-    }
+    const auto r_idx = i2enum<MonsterRaceId>(this->pval);
+    return MonraceList::get_instance().calc_capture_value(r_idx);
+}
 
-    return (monraces_info[capture_r_idx].level) * 50 + 1000;
+/*!
+ * @brief 強化不能武器であるかを判定する
+ * @return 強化不能か否か
+ */
+bool ItemEntity::should_refuse_enchant() const
+{
+    return this->bi_key.should_refuse_enchant();
 }
 
 bool ItemEntity::is_specific_artifact(FixedArtifactId id) const
@@ -801,11 +760,31 @@ bool ItemEntity::is_cross_bow() const
     return this->bi_key.is_cross_bow();
 }
 
+bool ItemEntity::is_corpse() const
+{
+    return this->bi_key.is_corpse();
+}
+
 bool ItemEntity::is_inscribed() const
 {
     return this->inscription != std::nullopt;
 }
 
+/*!
+ * @brief オブジェクトから発動効果構造体を取得する。
+ * @return 発動効果構造体 (なかったら無効イテレータ)
+ */
+std::vector<ActivationType>::const_iterator ItemEntity::find_activation_info() const
+{
+    const auto index = this->get_activation_index();
+    return std::find_if(activation_info.begin(), activation_info.end(), [index](const auto &x) { return x.index == index; });
+}
+
+bool ItemEntity::has_activation() const
+{
+    return this->get_activation_index() != RandomArtActType::NONE;
+}
+
 BaseitemInfo &ItemEntity::get_baseitem() const
 {
     return baseitems_info[this->bi_id];
@@ -820,3 +799,278 @@ ArtifactType &ItemEntity::get_fixed_artifact() const
 {
     return ArtifactsInfo::get_instance().get_artifact(this->fixed_artifact_idx);
 }
+
+TrFlags ItemEntity::get_flags() const
+{
+    const auto &baseitem = this->get_baseitem();
+    auto flags = baseitem.flags;
+
+    if (this->is_fixed_artifact()) {
+        flags = this->get_fixed_artifact().flags;
+    }
+
+    if (this->is_ego()) {
+        const auto &ego = this->get_ego();
+        flags.set(ego.flags);
+        this->modify_ego_lite_flags(flags);
+    }
+
+    flags.set(this->art_flags);
+    if (auto effect = Smith::object_effect(this); effect) {
+        auto tr_flags = Smith::get_effect_tr_flags(*effect);
+        flags.set(tr_flags);
+    }
+
+    if (Smith::object_activation(this)) {
+        flags.set(TR_ACTIVATE);
+    }
+
+    return flags;
+}
+
+TrFlags ItemEntity::get_flags_known() const
+{
+    TrFlags flags{};
+    if (!this->is_aware()) {
+        return flags;
+    }
+
+    const auto &baseitem = this->get_baseitem();
+    flags = baseitem.flags;
+    if (!this->is_known()) {
+        return flags;
+    }
+
+    if (this->is_ego()) {
+        const auto &ego = this->get_ego();
+        flags.set(ego.flags);
+        this->modify_ego_lite_flags(flags);
+    }
+
+    if (this->is_fully_known()) {
+        if (this->is_fixed_artifact()) {
+            flags = this->get_fixed_artifact().flags;
+        }
+
+        flags.set(this->art_flags);
+    }
+
+    if (auto effect = Smith::object_effect(this); effect) {
+        auto tr_flags = Smith::get_effect_tr_flags(*effect);
+        flags.set(tr_flags);
+    }
+
+    if (Smith::object_activation(this)) {
+        flags.set(TR_ACTIVATE);
+    }
+
+    return flags;
+}
+
+/*!
+ * @brief 発動効果の記述を生成する (メインルーチン)
+ * @return 発動効果
+ */
+std::string ItemEntity::explain_activation() const
+{
+    const auto flags = this->get_flags();
+    if (flags.has_not(TR_ACTIVATE)) {
+        return _("なし", "nothing");
+    }
+
+    if (this->has_activation()) {
+        return this->build_activation_description();
+    }
+
+    return this->bi_key.explain_activation();
+}
+
+std::string ItemEntity::build_timeout_description(const ActivationType &act) const
+{
+    const auto description = act.build_timeout_description();
+    if (description) {
+        return *description;
+    }
+
+    std::stringstream ss;
+    switch (act.index) {
+    case RandomArtActType::BR_FIRE:
+        ss << _("", "every ") << (this->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES) ? 200 : 250) << _(" ターン毎", " turns");
+        return ss.str();
+    case RandomArtActType::BR_COLD:
+        ss << _("", "every ") << (this->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE) ? 200 : 250) << _(" ターン毎", " turns");
+        return ss.str();
+    case RandomArtActType::TERROR:
+        return _("3*(レベル+10) ターン毎", "every 3 * (level+10) turns");
+    case RandomArtActType::MURAMASA:
+        return _("確率50%で壊れる", "(destroyed 50%)");
+    default:
+        return "undefined";
+    }
+}
+
+/*!
+ * @brief 発動効果の記述を生成する(サブルーチン/汎用)
+ * @return 発動効果
+ */
+std::string ItemEntity::build_activation_description() const
+{
+    const auto it = this->find_activation_info();
+    if (it == activation_info.end()) {
+        return _("未定義", "something undefined");
+    }
+
+    const auto activation_description = this->build_activation_description(*it);
+    const auto timeout_description = this->build_timeout_description(*it);
+    std::stringstream ss;
+    ss << activation_description << _(" : ", " ") << timeout_description;
+    return ss.str();
+}
+
+/*!
+ * @brief 鑑定済にする
+ */
+void ItemEntity::mark_as_known()
+{
+    this->feeling = FEEL_NONE;
+    this->ident &= ~(IDENT_SENSE);
+    this->ident &= ~(IDENT_EMPTY);
+    this->ident |= (IDENT_KNOWN);
+}
+
+/*!
+ * @brief 試行済にする
+ */
+void ItemEntity::mark_as_tried() const
+{
+    this->get_baseitem().mark_as_tried();
+}
+
+/*!
+ * @brief エゴ光源のフラグを修正する
+ *
+ * 寿命のある光源で寿命が0ターンの時、光源エゴアイテムに起因するフラグは
+ * 灼熱エゴの火炎耐性を除き付与されないようにする。
+ *
+ * @param flags フラグ情報を受け取る配列
+ */
+void ItemEntity::modify_ego_lite_flags(TrFlags &flags) const
+{
+    if (!this->bi_key.is(ItemKindType::LITE)) {
+        return;
+    }
+
+    if (!this->is_lite_requiring_fuel() || this->fuel != 0) {
+        return;
+    }
+
+    switch (this->ego_idx) {
+    case EgoType::LITE_AURA_FIRE:
+        flags.reset(TR_SH_FIRE);
+        return;
+    case EgoType::LITE_INFRA:
+        flags.reset(TR_INFRA);
+        return;
+    case EgoType::LITE_EYE:
+        flags.reset({ TR_RES_BLIND, TR_SEE_INVIS });
+        return;
+    default:
+        return;
+    }
+}
+
+/*!
+ * @brief 発動効果IDを取得する
+ * @details いくつかのケースで定義されている発動効果から、
+ * 鍛冶師による付与>固定アーティファクト>エゴ>ランダムアーティファクト>ベースアイテムの優先順位で走査する
+ * @return 発動効果ID
+ */
+RandomArtActType ItemEntity::get_activation_index() const
+{
+    if (auto act_idx = Smith::object_activation(this); act_idx) {
+        return *act_idx;
+    }
+
+    if (this->is_fixed_artifact()) {
+        const auto &artifact = this->get_fixed_artifact();
+        if (artifact.flags.has(TR_ACTIVATE)) {
+            return artifact.act_idx;
+        }
+    }
+
+    if (this->is_ego()) {
+        const auto &ego = this->get_ego();
+        if (ego.flags.has(TR_ACTIVATE)) {
+            return ego.act_idx;
+        }
+    }
+
+    if (!this->is_random_artifact()) {
+        const auto &baseitem = this->get_baseitem();
+        if (baseitem.flags.has(TR_ACTIVATE)) {
+            return baseitem.act_idx;
+        }
+    }
+
+    return this->activation_id;
+}
+
+std::string ItemEntity::build_activation_description(const ActivationType &act) const
+{
+    switch (act.index) {
+    case RandomArtActType::NONE:
+        return act.desc;
+    case RandomArtActType::BR_FIRE:
+        if (this->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES)) {
+            return _("火炎のブレス (200) と火への耐性", "breathe fire (200) and resist fire");
+        }
+
+        return act.desc;
+    case RandomArtActType::BR_COLD:
+        if (this->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE)) {
+            return _("冷気のブレス (200) と冷気への耐性", "breathe cold (200) and resist cold");
+        }
+
+        return act.desc;
+    case RandomArtActType::BR_DRAGON:
+        return this->build_activation_description_dragon_breath();
+    case RandomArtActType::AGGRAVATE:
+        if (this->is_specific_artifact(FixedArtifactId::HYOUSIGI)) {
+            return _("拍子木を打ちならす", "beat wooden clappers");
+        }
+
+        return act.desc;
+    case RandomArtActType::ACID_BALL_AND_RESISTANCE:
+        return _("アシッド・ボール (100) と酸への耐性", "ball of acid (100) and resist acid");
+    case RandomArtActType::FIRE_BALL_AND_RESISTANCE:
+        return _("ファイア・ボール (100) と火への耐性", "ball of fire (100) and resist fire");
+    case RandomArtActType::COLD_BALL_AND_RESISTANCE:
+        return _("アイス・ボール (100) と冷気への耐性", "ball of cold (100) and resist cold");
+    case RandomArtActType::ELEC_BALL_AND_RESISTANCE:
+        return _("サンダー・ボール (100) と電撃への耐性", "ball of elec (100) and resist elec");
+    case RandomArtActType::POIS_BALL_AND_RESISTANCE:
+        return _("ポイズン・ボール (100) と毒への耐性", "ball of poison (100) and resist elec");
+    case RandomArtActType::RESIST_ACID:
+        return _("一時的な酸への耐性", "temporary resist acid");
+    case RandomArtActType::RESIST_FIRE:
+        return _("一時的な火への耐性", "temporary resist fire");
+    case RandomArtActType::RESIST_COLD:
+        return _("一時的な冷気への耐性", "temporary resist cold");
+    case RandomArtActType::RESIST_ELEC:
+        return _("一時的な電撃への耐性", "temporary resist elec");
+    case RandomArtActType::RESIST_POIS:
+        return _("一時的な毒への耐性", "temporary resist elec");
+    default:
+        return act.desc;
+    }
+}
+
+/*!
+ * @brief 発動効果の記述を返す (ドラゴンブレス)
+ * @return 発動効果
+ */
+std::string ItemEntity::build_activation_description_dragon_breath() const
+{
+    const auto flags = this->get_flags();
+    return DragonBreaths::build_description(flags);
+}
index 5d4f5a9..def5268 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * @file item-entity.h
 #include "system/system-variables.h"
 #include "util/flag-group.h"
 #include <optional>
+#include <string>
+#include <vector>
 
 enum class FixedArtifactId : short;
 enum class ItemKindType : short;
 enum class SmithEffectType : int16_t;
 enum class RandomArtActType : short;
 
+class ActivationType;
 class ArtifactType;
-class EgoItemDefinition;
 class BaseitemInfo;
+class EgoItemDefinition;
 class ItemEntity {
 public:
     ItemEntity();
@@ -74,6 +77,7 @@ public:
     void wipe();
     void copy_from(const ItemEntity *j_ptr);
     void prep(short new_bi_id);
+    bool is(ItemKindType tval) const;
     bool is_weapon() const;
     bool is_weapon_ammo() const;
     bool is_weapon_armour_ammo() const;
@@ -85,7 +89,6 @@ public:
     bool is_broken_weapon() const;
     bool is_throwable() const;
     bool is_wieldable_in_etheir_hand() const;
-    bool refuse_enchant_weapon() const;
     bool allow_enchant_weapon() const;
     bool allow_enchant_melee_weapon() const;
     bool allow_two_hands_wielding() const;
@@ -135,14 +138,30 @@ public:
     bool is_junk() const;
     bool is_armour() const;
     bool is_cross_bow() const;
+    bool is_corpse() const;
     bool is_inscribed() const;
+    std::vector<ActivationType>::const_iterator find_activation_info() const;
+    bool has_activation() const;
 
     BaseitemInfo &get_baseitem() const;
     EgoItemDefinition &get_ego() const;
     ArtifactType &get_fixed_artifact() const;
+    TrFlags get_flags() const;
+    TrFlags get_flags_known() const;
+    std::string explain_activation() const;
+
+    void mark_as_known();
+    void mark_as_tried() const;
 
 private:
     int get_baseitem_price() const;
     int calc_figurine_value() const;
     int calc_capture_value() const;
+    bool should_refuse_enchant() const;
+    void modify_ego_lite_flags(TrFlags &flags) const;
+    RandomArtActType get_activation_index() const;
+    std::string build_activation_description() const;
+    std::string build_timeout_description(const ActivationType &act) const;
+    std::string build_activation_description(const ActivationType &act) const;
+    std::string build_activation_description_dragon_breath() const;
 };
index b5f06fb..e06e4e2 100644 (file)
@@ -1,11 +1,38 @@
-#include "system/monster-entity.h"
+#include "system/monster-entity.h"
 #include "game-option/birth-options.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-indice-types.h"
 #include "monster-race/race-kind-flags.h"
 #include "monster/monster-status.h"
+#include "system/angband-system.h"
 #include "system/monster-race-info.h"
+#include "term/term-color-types.h"
+#include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
+#include <algorithm>
+
+/*!
+ * @brief モンスターの属性に基づいた敵対関係の有無を返す
+ * @param sub_align1 モンスター1のサブフラグ
+ * @param sub_align2 モンスター2のサブフラグ
+ * @return 敵対関係にあるか否か
+ */
+bool MonsterEntity::check_sub_alignments(const byte sub_align1, const byte sub_align2)
+{
+    if (sub_align1 == sub_align2) {
+        return false;
+    }
+
+    auto this_evil = any_bits(sub_align1, SUB_ALIGN_EVIL);
+    this_evil &= any_bits(sub_align2, SUB_ALIGN_GOOD);
+    if (this_evil) {
+        return true;
+    }
+
+    auto this_good = any_bits(sub_align1, SUB_ALIGN_GOOD);
+    this_good &= any_bits(sub_align2, SUB_ALIGN_EVIL);
+    return this_good;
+}
 
 bool MonsterEntity::is_friendly() const
 {
@@ -22,6 +49,46 @@ bool MonsterEntity::is_hostile() const
     return !this->is_friendly() && !this->is_pet();
 }
 
+/*!
+ * @brief モンスターの属性の基づいた敵対関係の有無を返す
+ * @param other 比較対象モンスターへの参照
+ * @return 敵対関係にあるか否か
+ */
+bool MonsterEntity::is_hostile_to_melee(const MonsterEntity &other) const
+{
+    if (AngbandSystem::get_instance().is_phase_out()) {
+        return !this->is_pet() && !other.is_pet();
+    }
+
+    const auto &monrace1 = monraces_info[this->r_idx];
+    const auto &monrace2 = monraces_info[other.r_idx];
+    const auto is_m1_wild = monrace1.wilderness_flags.has_any_of({ MonsterWildernessType::WILD_TOWN, MonsterWildernessType::WILD_ALL });
+    const auto is_m2_wild = monrace2.wilderness_flags.has_any_of({ MonsterWildernessType::WILD_TOWN, MonsterWildernessType::WILD_ALL });
+    if (is_m1_wild && is_m2_wild) {
+        if (!this->is_pet() && !other.is_pet()) {
+            return false;
+        }
+    }
+
+    if (this->is_hostile_align(other.sub_align)) {
+        if (this->mflag2.has_not(MonsterConstantFlagType::CHAMELEON) || other.mflag2.has_not(MonsterConstantFlagType::CHAMELEON)) {
+            return true;
+        }
+    }
+
+    return this->is_hostile() != other.is_hostile();
+}
+
+/*!
+ * @brief モンスターの属性の基づいた敵対関係の有無を返す
+ * @param other 比較対象のサブフラグ
+ * @return 敵対関係にあるか否か
+ */
+bool MonsterEntity::is_hostile_align(const byte other_sub_align) const
+{
+    return MonsterEntity::check_sub_alignments(this->sub_align, other_sub_align);
+}
+
 bool MonsterEntity::is_named() const
 {
     return !this->nickname.empty();
@@ -54,7 +121,7 @@ bool MonsterEntity::is_mimicry() const
         return true;
     }
 
-    const auto &r_ref = monraces_info[this->ap_r_idx];
+    const auto &r_ref = this->get_appearance_monrace();
     const auto mimic_symbols = "/|\\()[]=$,.!?&`#%<>+~";
     if (angband_strchr(mimic_symbols, r_ref.d_char) == nullptr) {
         return false;
@@ -72,23 +139,33 @@ bool MonsterEntity::is_valid() const
     return MonsterRace(this->r_idx).is_valid();
 }
 
-MonsterRaceId MonsterEntity::get_real_r_idx() const
+MonsterRaceId MonsterEntity::get_real_monrace_id() const
 {
-    const auto &r_ref = monraces_info[this->r_idx];
+    const auto &monrace = this->get_monrace();
     if (this->mflag2.has_not(MonsterConstantFlagType::CHAMELEON)) {
         return this->r_idx;
     }
 
-    return r_ref.kind_flags.has(MonsterKindType::UNIQUE) ? MonsterRaceId::CHAMELEON_K : MonsterRaceId::CHAMELEON;
+    return monrace.kind_flags.has(MonsterKindType::UNIQUE) ? MonsterRaceId::CHAMELEON_K : MonsterRaceId::CHAMELEON;
 }
 
 /*!
- * @brief モンスターの真の種族を返す / Extract monster race pointer of a monster's true form
- * @return 本当のモンスター種族参照ポインタ
+ * @brief モンスターの真の種族定義を返す (CHAMAELEONフラグ専用)
+ * @return 真のモンスター種族参照
  */
-MonsterRaceInfo &MonsterEntity::get_real_r_ref() const
+MonsterRaceInfo &MonsterEntity::get_real_monrace() const
+{
+    return monraces_info[this->get_real_monrace_id()];
+}
+
+MonsterRaceInfo &MonsterEntity::get_appearance_monrace() const
 {
-    return monraces_info[this->get_real_r_idx()];
+    return monraces_info[this->ap_r_idx];
+}
+
+MonsterRaceInfo &MonsterEntity::get_monrace() const
+{
+    return monraces_info[this->r_idx];
 }
 
 short MonsterEntity::get_remaining_sleep() const
@@ -186,3 +263,69 @@ byte MonsterEntity::get_temporary_speed() const
 
     return speed;
 }
+
+/*!
+ * @brief モンスターが生命体かどうかを返す
+ * @param is_apperance たぬき、カメレオン、各種誤認ならtrue
+ * @return 生命体ならばtrue
+ * @todo kind_flags をMonsterEntityへコピーする (将来的なモンスター仕様の拡張)
+ */
+bool MonsterEntity::has_living_flag(bool is_apperance) const
+{
+    const auto &monrace = is_apperance ? this->get_appearance_monrace() : this->get_monrace();
+    return monrace.has_living_flag();
+}
+
+bool MonsterEntity::is_explodable() const
+{
+    const auto &monrace = this->get_monrace();
+    return monrace.is_explodable();
+}
+
+std::string MonsterEntity::get_died_message() const
+{
+    const auto &monrace = this->get_monrace();
+    return monrace.get_died_message();
+}
+
+/*!
+ * @brief モンスターの状態(無敵、起きているか、HPの割合)に応じてHPバーの色と長さを算出する
+ * @return HPバーの色と長さ(1-10)のペア
+ */
+std::pair<TERM_COLOR, int> MonsterEntity::get_hp_bar_data() const
+{
+    const auto percent = (this->maxhp > 0) ? (100 * this->hp / this->maxhp) : 0;
+    const auto len = std::clamp(percent / 10 + 1, 1, 10);
+
+    if (this->is_invulnerable()) {
+        return { TERM_WHITE, len };
+    }
+    if (this->is_asleep()) {
+        return { TERM_BLUE, len };
+    }
+    if (percent >= 100) {
+        return { TERM_L_GREEN, len };
+    }
+    if (percent >= 60) {
+        return { TERM_YELLOW, len };
+    }
+    if (percent >= 25) {
+        return { TERM_ORANGE, len };
+    }
+    if (percent >= 10) {
+        return { TERM_L_RED, len };
+    }
+    return { TERM_RED, len };
+}
+
+/*!
+ * @brief モンスターを敵に回す
+ */
+void MonsterEntity::set_hostile()
+{
+    if (AngbandSystem::get_instance().is_phase_out()) {
+        return;
+    }
+
+    this->mflag2.reset({ MonsterConstantFlagType::PET, MonsterConstantFlagType::FRIENDLY });
+}
index e83345a..24e023b 100644 (file)
@@ -1,10 +1,11 @@
-#pragma once
+#pragma once
 
 #include "monster/monster-flag-types.h"
 #include "monster/monster-timed-effect-types.h"
 #include "monster/smart-learn-types.h"
 #include "object/object-index-list.h"
 #include "util/flag-group.h"
+#include <string>
 
 /*!
  * @brief Monster information, for a specific monster.
@@ -54,16 +55,22 @@ public:
     EnumClassFlagGroup<MonsterSmartLearnType> smart{}; /*!< モンスターのプレイヤーに対する学習状態 / Field for "smart_learn" - Some bit-flags for the "smart" field */
     MONSTER_IDX parent_m_idx{}; /*!< 召喚主のモンスターID */
 
+    static bool check_sub_alignments(const byte sub_align1, const byte sub_align2);
+
     bool is_friendly() const;
     bool is_pet() const;
     bool is_hostile() const;
+    bool is_hostile_to_melee(const MonsterEntity &other) const;
+    bool is_hostile_align(const byte other_sub_align) const;
     bool is_named() const;
     bool is_named_pet() const;
     bool is_original_ap() const;
     bool is_mimicry() const;
     bool is_valid() const;
-    MonsterRaceId get_real_r_idx() const;
-    MonsterRaceInfo &get_real_r_ref() const;
+    MonsterRaceId get_real_monrace_id() const;
+    MonsterRaceInfo &get_real_monrace() const;
+    MonsterRaceInfo &get_appearance_monrace() const;
+    MonsterRaceInfo &get_monrace() const;
     short get_remaining_sleep() const;
     short get_remaining_acceleration() const;
     short get_remaining_deceleration() const;
@@ -80,4 +87,10 @@ public:
     bool is_fearful() const;
     bool is_invulnerable() const;
     byte get_temporary_speed() const;
+    bool has_living_flag(bool is_apperance = false) const;
+    bool is_explodable() const;
+    std::string get_died_message() const;
+    std::pair<TERM_COLOR, int> get_hp_bar_data() const;
+
+    void set_hostile();
 };
index f63e00b..9515079 100644 (file)
@@ -1,5 +1,8 @@
-#include "system/monster-race-info.h"
+#include "system/monster-race-info.h"
+#include "monster-race/monster-race.h"
+#include "monster-race/race-indice-types.h"
 #include "monster/horror-descriptions.h"
+#include <algorithm>
 
 /*!
  * @brief エルドリッチホラーの形容詞種別を決める
@@ -19,3 +22,253 @@ const std::string &MonsterRaceInfo::decide_horror_message() const
 
     return horror_desc_neutral[horror_num - horror_desc_common_size];
 }
+
+/*!
+ * @brief モンスターが生命体かどうかを返す
+ * @return 生命体ならばtrue
+ */
+bool MonsterRaceInfo::has_living_flag() const
+{
+    return this->kind_flags.has_none_of({ MonsterKindType::DEMON, MonsterKindType::UNDEAD, MonsterKindType::NONLIVING });
+}
+
+bool MonsterRaceInfo::is_explodable() const
+{
+    return std::any_of(std::begin(this->blows), std::end(this->blows),
+        [](const auto &blow) { return blow.method == RaceBlowMethodType::EXPLODE; });
+}
+
+/*!
+ * @brief モンスターを撃破した際の述語メッセージを返す
+ * @return 撃破されたモンスターの述語
+ */
+std::string MonsterRaceInfo::get_died_message() const
+{
+    const auto is_explodable = this->is_explodable();
+    if (this->has_living_flag()) {
+        return is_explodable ? _("は爆発して死んだ。", " explodes and dies.") : _("は死んだ。", " dies.");
+    }
+
+    return is_explodable ? _("は爆発して粉々になった。", " explodes into tiny shreds.") : _("を倒した。", " is destroyed.");
+}
+
+/*!
+ * @brief ユニークモンスターの撃破状態を更新する
+ * @todo 状態変更はモンスター「定義」ではないので将来的に別クラスへ分離する
+ */
+void MonsterRaceInfo::kill_unique()
+{
+    this->max_num = 0;
+    this->r_pkills++;
+    this->r_akills++;
+    if (this->r_tkills < MAX_SHORT) {
+        this->r_tkills++;
+    }
+}
+
+const std::map<MonsterRaceId, std::set<MonsterRaceId>> MonraceList::unified_uniques = {
+    { MonsterRaceId::BANORLUPART, { MonsterRaceId::BANOR, MonsterRaceId::LUPART } },
+};
+
+MonraceList MonraceList::instance{};
+
+const std::map<MonsterRaceId, std::set<MonsterRaceId>> &MonraceList::get_unified_uniques()
+{
+    return unified_uniques;
+}
+
+MonraceList &MonraceList::get_instance()
+{
+    return instance;
+}
+
+/*!
+ * @bried モンスター定義を種族IDから直接得る
+ * @param モンスター種族ID
+ * @return モンスター定義への参照
+ * @details モンスター実体からモンスター定義を得るためには使用しないこと
+ */
+MonsterRaceInfo &MonraceList::operator[](const MonsterRaceId r_idx)
+{
+    return monraces_info.at(r_idx);
+}
+
+/*!
+ * @bried モンスター定義を種族IDから直接得る
+ * @param モンスター種族ID
+ * @return モンスター定義への参照
+ * @details モンスター実体からモンスター定義を得るためには使用しないこと
+ */
+const MonsterRaceInfo &MonraceList::operator[](const MonsterRaceId r_idx) const
+{
+    return monraces_info.at(r_idx);
+}
+
+/*!
+ * @brief 合体/分離ユニーク判定
+ * @param r_idx 調査対象のモンスター種族ID
+ * @return 合体/分離ユニークか否か
+ * @details 合体/分離ユニークは、賞金首にもランダムクエスト討伐対象にもならない.
+ */
+bool MonraceList::can_unify_separate(const MonsterRaceId r_idx) const
+{
+    if (unified_uniques.contains(r_idx)) {
+        return true;
+    }
+
+    return std::any_of(unified_uniques.begin(), unified_uniques.end(), [&r_idx](const auto &x) { return x.second.contains(r_idx); });
+}
+
+/*!
+ * @brief 合体ユニークの死亡処理
+ * @details 分離/合体が A = B + C + D という図式の時、Aが死亡した場合BとCとDも死亡処理を行う。
+ * B・C・Dのいずれかが死亡した場合、その死亡したユニークに加えてAの死亡処理も行う。
+ * v3.0.0 α89現在は、分離後のユニーク数は2のみ。3以上は将来の拡張。
+ * @param r_idx 実際に死亡したモンスターの種族ID
+ */
+void MonraceList::kill_unified_unique(const MonsterRaceId r_idx)
+{
+    const auto it_unique = unified_uniques.find(r_idx);
+    if (it_unique != unified_uniques.end()) {
+        (*this)[it_unique->first].kill_unique();
+        for (const auto separate : it_unique->second) {
+            (*this)[separate].kill_unique();
+        }
+
+        return;
+    }
+
+    for (const auto &[unified_unique, separates] : unified_uniques) {
+        const auto it_separate = separates.find(r_idx);
+        if (it_separate != separates.end()) {
+            (*this)[*it_separate].kill_unique();
+            (*this)[unified_unique].kill_unique();
+            return;
+        }
+    }
+}
+
+/*!
+ * @brief 合体ユニークの生成可能確認
+ * @param r_idx 生成しようとしているモンスターの種族ID
+ * @return 合体後ユニークが生成可能か否か
+ * @details 分離も合体もしないならば常にtrue
+ * 分離ユニークもtrueだが、通常レアリティ255のためこのメソッドとは別処理で生成不能
+ * 分離/合体が A = B + C + D という図式の時、B・C・Dのいずれか1体がフロア内に生成済の場合、Aの生成を抑制する
+ */
+bool MonraceList::is_selectable(const MonsterRaceId r_idx) const
+{
+    const auto it = unified_uniques.find(r_idx);
+    if (it == unified_uniques.end()) {
+        return true;
+    }
+
+    return std::all_of(it->second.begin(), it->second.end(), [&](const auto x) { return (*this)[x].cur_num == 0; });
+}
+
+/*!
+ * @brief 合体ユニークが撃破済の状態でフロアから離脱した時に、各分離ユニークも撃破済状態へと変更する
+ */
+void MonraceList::defeat_separated_uniques()
+{
+    for (const auto &[unified_unique, separates] : unified_uniques) {
+        if ((*this)[unified_unique].max_num > 0) {
+            continue;
+        }
+
+        for (const auto separate : separates) {
+            auto &monrace = (*this)[separate];
+            if (monrace.max_num == 0) {
+                continue;
+            }
+
+            monrace.kill_unique();
+        }
+    }
+}
+
+bool MonraceList::is_unified(const MonsterRaceId r_idx) const
+{
+    return unified_uniques.contains(r_idx);
+}
+
+/*!
+ * @brief 合体ユニークの各分離ユニークが全員フロアにいるかをチェックする
+ * @param r_idx 合体ユニークの種族ID
+ * @return 全員が現在フロアに生成されているか
+ */
+bool MonraceList::exists_separates(const MonsterRaceId r_idx) const
+{
+    const auto &separates = unified_uniques.at(r_idx);
+    return std::all_of(separates.begin(), separates.end(), [&](const auto x) { return (*this)[x].cur_num > 0; });
+}
+
+/*!
+ * @brief 与えられたIDが分離ユニークのいずれかに一致するかをチェックする
+ * @param r_idx 調査対象のモンスター種族ID
+ */
+bool MonraceList::is_separated(const MonsterRaceId r_idx) const
+{
+    if (unified_uniques.contains(r_idx)) {
+        return false;
+    }
+
+    return std::any_of(unified_uniques.begin(), unified_uniques.end(), [&r_idx](const auto &x) { return x.second.contains(r_idx); });
+}
+
+/*!
+ * @brief 合体ユニークが分離魔法を唱えられるかをチェックする
+ * @param r_idx 分離ユニークの種族ID
+ * @param hp 分離ユニークの現在HP
+ * @param maxhp 分離ユニークの最大HP (衰弱を含)
+ */
+bool MonraceList::can_select_separate(const MonsterRaceId r_idx, const int hp, const int maxhp) const
+{
+    if (unified_uniques.contains(r_idx)) {
+        return false;
+    }
+
+    const auto end = unified_uniques.end();
+    const auto it = std::find_if(unified_uniques.begin(), end, [&r_idx](const auto &x) { return x.second.contains(r_idx); });
+    if (it == end) {
+        return false;
+    }
+
+    auto &found_separates = it->second;
+    if (hp >= (maxhp / static_cast<int>(found_separates.size()))) {
+        return false;
+    }
+
+    return std::all_of(found_separates.begin(), found_separates.end(), [&](const auto x) { return (*this)[x].max_num > 0; });
+}
+
+int MonraceList::calc_figurine_value(const MonsterRaceId r_idx) const
+{
+    const auto level = (*this)[r_idx].level;
+    if (level < 20) {
+        return level * 50;
+    }
+
+    if (level < 30) {
+        return 1000 + (level - 20) * 150;
+    }
+
+    if (level < 40) {
+        return 2500 + (level - 30) * 350;
+    }
+
+    if (level < 50) {
+        return 6000 + (level - 40) * 800;
+    }
+
+    return 14000 + (level - 50) * 2000;
+}
+
+int MonraceList::calc_capture_value(const MonsterRaceId r_idx) const
+{
+    if (r_idx == MonsterRaceId::PLAYER) {
+        return 1000;
+    }
+
+    return (*this)[r_idx].level * 50 + 1000;
+}
index 729e879..696efac 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "monster-attack/monster-attack-effect.h"
 #include "monster-attack/monster-attack-table.h"
 #include "monster-race/race-flags-resistance.h"
 #include "monster-race/race-kind-flags.h"
 #include "monster-race/race-population-flags.h"
+#include "monster-race/race-sex-const.h"
 #include "monster-race/race-speak-flags.h"
 #include "monster-race/race-visual-flags.h"
 #include "monster-race/race-wilderness-flags.h"
 #include "system/angband.h"
 #include "util/flag-group.h"
+#include <map>
+#include <set>
 #include <string>
 #include <tuple>
 #include <vector>
@@ -73,6 +76,7 @@ public:
     byte speed{}; //!< 加速(110で+0) / Speed (normally 110)
     EXP mexp{}; //!< 殺害時基本経験値 / Exp value for kill
     RARITY freq_spell{}; //!< 魔法&特殊能力仕様頻度(1/n) /  Spell frequency
+    MonsterSex sex{}; //!< 性別 / Sex
     BIT_FLAGS flags1{}; //!< Flags 1 (general)
     BIT_FLAGS flags2{}; //!< Flags 2 (abilities)
     BIT_FLAGS flags3{}; //!< Flags 3 (race/resist)
@@ -90,7 +94,7 @@ public:
     EnumClassFlagGroup<MonsterPopulationType> population_flags; //!< 能力フラグ(出現数関連) / Population Flags
     EnumClassFlagGroup<MonsterSpeakType> speak_flags; //!< 能力フラグ(セリフ) / Speaking Flags
     EnumClassFlagGroup<MonsterBrightnessType> brightness_flags; //!< 能力フラグ(明暗) / Speaking Lite or Dark
-    MonsterBlow blow[MAX_NUM_BLOWS]{}; //!< 打撃能力定義 / Up to four blows per round
+    MonsterBlow blows[MAX_NUM_BLOWS]{}; //!< 打撃能力定義 / Up to four blows per round
 
     //! 指定護衛リスト <モンスター種族ID,護衛数ダイス数,護衛数ダイス面>
     std::vector<std::tuple<MonsterRaceId, DICE_NUMBER, DICE_SID>> reinforces;
@@ -137,4 +141,38 @@ public:
     PERCENTAGE cur_hp_per{}; //!< 生成時現在HP率(%)
 
     const std::string &decide_horror_message() const;
+    bool has_living_flag() const;
+    bool is_explodable() const;
+    std::string get_died_message() const;
+    void kill_unique();
+};
+
+class MonraceList {
+public:
+    MonraceList(MonraceList &&) = delete;
+    MonraceList(const MonraceList &) = delete;
+    MonraceList &operator=(const MonraceList &) = delete;
+    MonraceList &operator=(MonraceList &&) = delete;
+    MonsterRaceInfo &operator[](const MonsterRaceId r_idx);
+    const MonsterRaceInfo &operator[](const MonsterRaceId r_idx) const;
+
+    static const std::map<MonsterRaceId, std::set<MonsterRaceId>> &get_unified_uniques();
+    static MonraceList &get_instance();
+    bool can_unify_separate(const MonsterRaceId r_idx) const;
+    void kill_unified_unique(const MonsterRaceId r_idx);
+    bool is_selectable(const MonsterRaceId r_idx) const;
+    void defeat_separated_uniques();
+    bool is_unified(const MonsterRaceId r_idx) const;
+    bool exists_separates(const MonsterRaceId r_idx) const;
+    bool is_separated(const MonsterRaceId r_idx) const;
+    bool can_select_separate(const MonsterRaceId r_idx, const int hp, const int maxhp) const;
+    int calc_figurine_value(const MonsterRaceId r_idx) const;
+    int calc_capture_value(const MonsterRaceId r_idx) const;
+
+private:
+    MonraceList() = default;
+
+    static MonraceList instance;
+
+    const static std::map<MonsterRaceId, std::set<MonsterRaceId>> unified_uniques;
 };
index 6983ec3..cc99678 100644 (file)
@@ -1,5 +1,6 @@
-#include "system/player-type-definition.h"
+#include "system/player-type-definition.h"
 #include "market/arena-info-table.h"
+#include "system/redrawing-flags-updater.h"
 #include "timed-effect/player-blindness.h"
 #include "timed-effect/player-confusion.h"
 #include "timed-effect/player-cut.h"
@@ -60,3 +61,66 @@ bool PlayerType::is_fully_healthy() const
     is_fully_healthy &= !this->alter_reality;
     return is_fully_healthy;
 }
+
+/*
+ * @brief ランダムに1つアビリティスコアを減少させる
+ * @return アビリティスコア減少メッセージ
+ * @todo stat_curにのみ依存するのでアビリティスコアを表すクラスへ移設する
+ */
+std::string PlayerType::decrease_ability_random()
+{
+    constexpr std::array<std::pair<int, std::string_view>, 6> candidates = { {
+        { A_STR, _("強く", "strong") },
+        { A_INT, _("聡明で", "bright") },
+        { A_WIS, _("賢明で", "wise") },
+        { A_DEX, _("器用で", "agile") },
+        { A_CON, _("健康で", "hale") },
+        { A_CHR, _("美しく", "beautiful") },
+    } };
+
+    const auto &[k, act] = rand_choice(candidates);
+    this->stat_cur[k] = (this->stat_cur[k] * 3) / 4;
+    if (this->stat_cur[k] < 3) {
+        this->stat_cur[k] = 3;
+    }
+
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
+    return format(_("あなたは以前ほど%sなくなってしまった...。", "You're not as %s as you used to be..."), act.data());
+}
+
+/*
+ * @brief 全てのアビリティスコアを減少させる
+ * @return アビリティスコア減少メッセージ
+ * @todo stat_curにのみ依存するのでアビリティスコアを表すクラスへ移設する
+ */
+std::string PlayerType::decrease_ability_all()
+{
+    for (auto i = 0; i < A_MAX; i++) {
+        this->stat_cur[i] = (this->stat_cur[i] * 7) / 8;
+        if (this->stat_cur[i] < 3) {
+            this->stat_cur[i] = 3;
+        }
+    }
+
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
+    return _("あなたは以前ほど力強くなくなってしまった...。", "You're not as powerful as you used to be...");
+}
+
+/*!
+ * @brief 現在地の瞬時値を返す
+ * @details プレイヤーが移動する前後の文脈で使用すると不整合を起こすので注意
+ */
+Pos2D PlayerType::get_position() const
+{
+    return Pos2D(this->y, this->x);
+}
+
+bool PlayerType::is_located_at_running_destination() const
+{
+    return (this->y == this->run_py) && (this->x == this->run_px);
+}
+
+bool PlayerType::is_located_at(const Pos2D &pos) const
+{
+    return (this->y == pos.y) && (this->x == pos.x);
+}
index b31f549..8088315 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "mutation/mutation-flag-types.h"
 #include "object-enchant/trc-types.h"
@@ -11,6 +11,7 @@
 #include "system/angband.h"
 #include "system/system-variables.h"
 #include "util/flag-group.h"
+#include "util/point-2d.h"
 #include <array>
 #include <map>
 #include <string>
@@ -30,10 +31,6 @@ public:
     PlayerType();
     bool is_true_winner() const;
 
-    int player_uid{};
-    int player_euid{};
-    int player_egid{};
-
     FloorType *current_floor_ptr{};
     POSITION oldpy{}; /* Previous player location -KMW- */
     POSITION oldpx{}; /* Previous player location -KMW- */
@@ -68,9 +65,7 @@ public:
 
     int16_t town_num{}; /* Current town number */
     int16_t arena_number{}; /* monster number in on_defeat_arena_monster -KMW- */
-    bool phase_out{}; /*!< フェイズアウト状態(闘技場観戦状態などに利用、NPCの処理の対象にならず自身もほとんどの行動ができない) */
 
-    DUNGEON_IDX dungeon_idx{}; /* current dungeon index */
     POSITION wilderness_x{}; /* Coordinates in the wilderness */
     POSITION wilderness_y{};
     bool wild_mode{};
@@ -86,9 +81,9 @@ public:
 
     int16_t max_plv{}; /* Max Player Level */
 
-    BASE_STATUS stat_max[A_MAX]{}; /* Current "maximal" stat values */
-    BASE_STATUS stat_max_max[A_MAX]{}; /* Maximal "maximal" stat values */
-    BASE_STATUS stat_cur[A_MAX]{}; /* Current "natural" stat values */
+    short stat_max[A_MAX]{}; /* Current "maximal" stat values */
+    short stat_max_max[A_MAX]{}; /* Maximal "maximal" stat values */
+    short stat_cur[A_MAX]{}; /* Current "natural" stat values */
 
     int16_t learned_spells{};
     int16_t add_spells{};
@@ -190,7 +185,7 @@ public:
 
     int player_hp[PY_MAX_LEVEL]{};
     std::string died_from{}; /* What killed the player */
-    concptr last_message{}; /* Last message on death or retirement */
+    std::string last_message = ""; /* Last message on death or retirement */
     char history[4][60]{}; /* Textual "history" for the Player */
 
     uint16_t panic_save{}; /* Panic save */
@@ -239,9 +234,6 @@ public:
 
     bool monk_notify_aux{};
 
-    byte leave_bldg{};
-    byte exit_bldg{}; /* Goal obtained in on_defeat_arena_monster? -KMW- */
-
     bool leaving_dungeon{}; /* True if player is leaving the dungeon */
     bool teleport_town{};
     bool enter_dungeon{}; /* Just enter the dungeon */
@@ -282,9 +274,6 @@ public:
 
     POSITION cur_lite{}; /* Radius of lite (if any) */
 
-    BIT_FLAGS update{}; /* Pending Updates */
-    BIT_FLAGS redraw{}; /* Normal Redraws */
-    BIT_FLAGS window_flags{}; /* Window Redraws */
     int16_t stat_use[A_MAX]{}; /* Current modified stats */
     int16_t stat_top[A_MAX]{}; /* Maximal modified stats */
 
@@ -346,7 +335,7 @@ public:
     BIT_FLAGS earthquake{}; //!< 地震を起こす装備をしている / Earthquake blows
     BIT_FLAGS dec_mana{};
     BIT_FLAGS easy_spell{};
-    BIT_FLAGS heavy_spell{};
+    BIT_FLAGS hard_spell{};
     BIT_FLAGS warning{};
     BIT_FLAGS mighty_throw{};
     BIT_FLAGS see_nocto{}; /* Noctovision */
@@ -411,6 +400,11 @@ public:
 
     std::shared_ptr<TimedEffects> effects() const;
     bool is_fully_healthy() const;
+    std::string decrease_ability_random();
+    std::string decrease_ability_all();
+    Pos2D get_position() const;
+    bool is_located_at_running_destination() const;
+    bool is_located_at(const Pos2D &pos) const;
 
 private:
     std::shared_ptr<TimedEffects> timed_effects;
index dfcb5dd..550f8f6 100644 (file)
@@ -1,4 +1,4 @@
-#include "system/redrawing-flags-updater.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/enum-range.h"
 
 RedrawingFlagsUpdater RedrawingFlagsUpdater::instance{};
@@ -33,7 +33,7 @@ bool RedrawingFlagsUpdater::has(SubWindowRedrawingFlag flag) const
     return this->sub_window_flags.has(flag);
 }
 
-bool RedrawingFlagsUpdater::has(StatusRedrawingFlag flag) const
+bool RedrawingFlagsUpdater::has(StatusRecalculatingFlag flag) const
 {
     return this->status_flags.has(flag);
 }
@@ -48,7 +48,7 @@ bool RedrawingFlagsUpdater::has_any_of(const EnumClassFlagGroup<SubWindowRedrawi
     return this->sub_window_flags.has_any_of(flags);
 }
 
-bool RedrawingFlagsUpdater::has_any_of(const EnumClassFlagGroup<StatusRedrawingFlag> &flags) const
+bool RedrawingFlagsUpdater::has_any_of(const EnumClassFlagGroup<StatusRecalculatingFlag> &flags) const
 {
     return this->status_flags.has_any_of(flags);
 }
@@ -63,7 +63,7 @@ void RedrawingFlagsUpdater::set_flag(SubWindowRedrawingFlag flag)
     this->sub_window_flags.set(flag);
 }
 
-void RedrawingFlagsUpdater::set_flag(StatusRedrawingFlag flag)
+void RedrawingFlagsUpdater::set_flag(StatusRecalculatingFlag flag)
 {
     this->status_flags.set(flag);
 }
@@ -78,7 +78,7 @@ void RedrawingFlagsUpdater::set_flags(const EnumClassFlagGroup<SubWindowRedrawin
     this->sub_window_flags.set(flags);
 }
 
-void RedrawingFlagsUpdater::set_flags(const EnumClassFlagGroup<StatusRedrawingFlag> &flags)
+void RedrawingFlagsUpdater::set_flags(const EnumClassFlagGroup<StatusRecalculatingFlag> &flags)
 {
     this->status_flags.set(flags);
 }
@@ -93,7 +93,7 @@ void RedrawingFlagsUpdater::reset_flag(SubWindowRedrawingFlag flag)
     this->sub_window_flags.reset(flag);
 }
 
-void RedrawingFlagsUpdater::reset_flag(StatusRedrawingFlag flag)
+void RedrawingFlagsUpdater::reset_flag(StatusRecalculatingFlag flag)
 {
     this->status_flags.reset(flag);
 }
@@ -108,14 +108,18 @@ void RedrawingFlagsUpdater::reset_flags(const EnumClassFlagGroup<SubWindowRedraw
     this->sub_window_flags.reset(flags);
 }
 
-void RedrawingFlagsUpdater::reset_flags(const EnumClassFlagGroup<StatusRedrawingFlag> &flags)
+void RedrawingFlagsUpdater::reset_flags(const EnumClassFlagGroup<StatusRecalculatingFlag> &flags)
 {
     this->status_flags.reset(flags);
 }
 
 void RedrawingFlagsUpdater::fill_up_sub_flags()
 {
-    for (const auto flag : EnumRange(SubWindowRedrawingFlag::INVENTORY, SubWindowRedrawingFlag::FOUND_ITEMS)) {
-        this->sub_window_flags.set(flag);
-    }
+    constexpr auto all_sub_window_flags = EnumRange(SubWindowRedrawingFlag::INVENTORY, SubWindowRedrawingFlag::FOUND_ITEMS);
+    this->sub_window_flags.set(all_sub_window_flags);
+}
+
+EnumClassFlagGroup<SubWindowRedrawingFlag> RedrawingFlagsUpdater::get_sub_intersection(const EnumClassFlagGroup<SubWindowRedrawingFlag> &flags)
+{
+    return this->sub_window_flags & flags;
 }
index 2293d44..b262c1e 100644 (file)
@@ -1,9 +1,8 @@
-#pragma once
+#pragma once
 
 #include "util/flag-group.h"
 
 enum class MainWindowRedrawingFlag {
-    MISC, /*!< 種族と職業 */
     TITLE, /*!< 称号 */
     LEVEL,
     EXP, /*!< 経験値 */
@@ -32,23 +31,26 @@ enum class MainWindowRedrawingFlag {
 };
 
 enum class SubWindowRedrawingFlag {
-    INVENTORY, /*!< 所持品-装備品 */
-    EQUIPMENT, /*!< 装備品-所持品 */
-    SPELL, /*!< 魔法一覧 */
-    PLAYER, /*!< プレイヤーのステータス */
-    SIGHT_MONSTERS, /*!< 視界内モンスターの一覧 */
-    MESSAGE, /*!< メッセージログ */
-    OVERHEAD, /*!< 周辺の光景 */
-    MONSTER_LORE, /*!< モンスターの思い出 */
-    ITEM_KNOWLEDGTE, /*!< アイテムの知識 */
-    DUNGEON, /*!< ダンジョンの地形 */
-    SNAPSHOT, /*!< 記念写真 */
-    FLOOR_ITEMS, /*!< 床上のアイテム一覧 */
-    FOUND_ITEMS, /*!< 発見済みのアイテム一覧 */
-    MAX,
+    INVENTORY = 0, /*!< 所持品-装備品 */
+    EQUIPMENT = 1, /*!< 装備品-所持品 */
+    SPELL = 2, /*!< 魔法一覧 */
+    PLAYER = 3, /*!< プレイヤーのステータス */
+    SIGHT_MONSTERS = 4, /*!< 視界内モンスターの一覧 */
+    PETS = 5, /*!< ペットの一覧 */
+    MESSAGE = 6, /*!< メッセージログ */
+    OVERHEAD = 7, /*!< 周辺の光景 */
+    MONSTER_LORE = 8, /*!< モンスターの思い出 */
+    ITEM_KNOWLEDGE = 9, /*!< アイテムの知識 */
+    DUNGEON = 10, /*!< ダンジョンの地形 */
+    SNAPSHOT = 11, /*!< 記念写真 */
+    FLOOR_ITEMS = 12, /*!< 床上のアイテム一覧 */
+    FOUND_ITEMS = 13, /*!< 発見済みのアイテム一覧 */
+    /*!< 14は予約領域 */
+    /*!< 15は予約領域 */
+    MAX = 16,
 };
 
-enum class StatusRedrawingFlag {
+enum class StatusRecalculatingFlag {
     BONUS, /*!< 能力値修正 */
     TORCH, /*!< 光源半径 */
     HP,
@@ -85,29 +87,30 @@ public:
 
     bool has(MainWindowRedrawingFlag flag) const;
     bool has(SubWindowRedrawingFlag flag) const;
-    bool has(StatusRedrawingFlag flag) const;
+    bool has(StatusRecalculatingFlag flag) const;
 
     bool has_any_of(const EnumClassFlagGroup<MainWindowRedrawingFlag> &flags) const;
     bool has_any_of(const EnumClassFlagGroup<SubWindowRedrawingFlag> &flags) const;
-    bool has_any_of(const EnumClassFlagGroup<StatusRedrawingFlag> &flags) const;
+    bool has_any_of(const EnumClassFlagGroup<StatusRecalculatingFlag> &flags) const;
 
     void set_flag(MainWindowRedrawingFlag flag);
     void set_flag(SubWindowRedrawingFlag flag);
-    void set_flag(StatusRedrawingFlag flag);
+    void set_flag(StatusRecalculatingFlag flag);
 
     void set_flags(const EnumClassFlagGroup<MainWindowRedrawingFlag> &flags);
     void set_flags(const EnumClassFlagGroup<SubWindowRedrawingFlag> &flags);
-    void set_flags(const EnumClassFlagGroup<StatusRedrawingFlag> &flags);
+    void set_flags(const EnumClassFlagGroup<StatusRecalculatingFlag> &flags);
 
     void reset_flag(MainWindowRedrawingFlag flag);
     void reset_flag(SubWindowRedrawingFlag flag);
-    void reset_flag(StatusRedrawingFlag flag);
+    void reset_flag(StatusRecalculatingFlag flag);
 
     void reset_flags(const EnumClassFlagGroup<MainWindowRedrawingFlag> &flags);
     void reset_flags(const EnumClassFlagGroup<SubWindowRedrawingFlag> &flags);
-    void reset_flags(const EnumClassFlagGroup<StatusRedrawingFlag> &flags);
+    void reset_flags(const EnumClassFlagGroup<StatusRecalculatingFlag> &flags);
 
     void fill_up_sub_flags();
+    EnumClassFlagGroup<SubWindowRedrawingFlag> get_sub_intersection(const EnumClassFlagGroup<SubWindowRedrawingFlag> &flags);
 
 private:
     RedrawingFlagsUpdater() = default;
@@ -116,5 +119,5 @@ private:
 
     EnumClassFlagGroup<MainWindowRedrawingFlag> main_window_flags{};
     EnumClassFlagGroup<SubWindowRedrawingFlag> sub_window_flags{};
-    EnumClassFlagGroup<StatusRedrawingFlag> status_flags{};
+    EnumClassFlagGroup<StatusRecalculatingFlag> status_flags{};
 };
index 2ed0cee..f143c3d 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief グローバル変数の残骸
  * @date 2013/12/31
  * @todo 呼び出し関係を良く読んで消す方針で進めたい.
@@ -31,4 +31,4 @@ init_flags_type init_flags; //!< @todo このグローバル変数何とかし
  */
 bool (*get_obj_index_hook)(short bi_id);
 
-OBJECT_SUBTYPE_VALUE coin_type;
+int coin_type;
index bb0399b..6780ca4 100644 (file)
@@ -1,8 +1,10 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-#define MAX_NAZGUL_NUM 5
+constexpr auto MAX_UNIQUE_NUM = 1;
+constexpr auto MAX_NAZGUL_NUM = 5;
+constexpr auto MAX_MONSTER_NUM = 100; /*!< 1種類の非ユニークモンスターが1フロアに存在できる最大数 */
 #define SCREEN_BUF_MAX_SIZE (1024 * 1024) /*!< Max size of screen dump buffer */
 #define PY_MAX_LEVEL 50 /*!< プレイヤーレベルの最大値 / Maximum level */
 #define PY_MAX_EXP 99999999L /*!< プレイヤー経験値の最大値 / Maximum exp */
@@ -27,5 +29,5 @@ extern concptr ANGBAND_SYS;
 extern concptr ANGBAND_KEYBOARD;
 extern concptr ANGBAND_GRAF;
 
-extern OBJECT_SUBTYPE_VALUE coin_type;
+extern int coin_type;
 extern bool (*get_obj_index_hook)(short bi_id);
index 05cd792..51e1dfb 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief 地形特性定義
  * @author Hourier
  * @date 2022/10/15
@@ -6,4 +6,64 @@
 
 #include "system/terrain-type-definition.h"
 
-std::vector<TerrainType> terrains_info;
+bool TerrainType::is_permanent_wall() const
+{
+    return this->flags.has_all_of({ TerrainCharacteristics::WALL, TerrainCharacteristics::PERMANENT });
+}
+
+TerrainList TerrainList::instance{};
+
+TerrainList &TerrainList::get_instance()
+{
+    return instance;
+}
+
+std::vector<TerrainType> &TerrainList::get_raw_vector()
+{
+    return this->terrains;
+}
+
+TerrainType &TerrainList::operator[](short terrain_id)
+{
+    return this->terrains.at(terrain_id);
+}
+
+const TerrainType &TerrainList::operator[](short terrain_id) const
+{
+    return this->terrains.at(terrain_id);
+}
+
+std::vector<TerrainType>::iterator TerrainList::begin()
+{
+    return this->terrains.begin();
+}
+
+const std::vector<TerrainType>::const_iterator TerrainList::begin() const
+{
+    return this->terrains.begin();
+}
+
+std::vector<TerrainType>::iterator TerrainList::end()
+{
+    return this->terrains.end();
+}
+
+const std::vector<TerrainType>::const_iterator TerrainList::end() const
+{
+    return this->terrains.end();
+}
+
+size_t TerrainList::size() const
+{
+    return this->terrains.size();
+}
+
+bool TerrainList::empty() const
+{
+    return this->terrains.empty();
+}
+
+void TerrainList::resize(size_t new_size)
+{
+    this->terrains.resize(new_size);
+}
index 411352f..4619c8e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "grid/feature-flag-types.h"
 #include "system/angband.h"
@@ -43,6 +43,32 @@ public:
     char d_char[F_LIT_MAX]{}; /*!< デフォルトの地形シンボルアルファベット / Default feature character */
     TERM_COLOR x_attr[F_LIT_MAX]{}; /*!< 設定変更後の地形シンボルカラー / Desired feature attribute */
     char x_char[F_LIT_MAX]{}; /*!< 設定変更後の地形シンボルアルファベット / Desired feature character */
+
+    bool is_permanent_wall() const;
 };
 
-extern std::vector<TerrainType> terrains_info;
+class TerrainList {
+public:
+    TerrainList(const TerrainList &) = delete;
+    TerrainList(TerrainList &&) = delete;
+    TerrainList operator=(const TerrainList &) = delete;
+    TerrainList operator=(TerrainList &&) = delete;
+    TerrainType &operator[](short terrain_id);
+    const TerrainType &operator[](short terrain_id) const;
+
+    static TerrainList &get_instance();
+    std::vector<TerrainType> &get_raw_vector();
+    std::vector<TerrainType>::iterator begin();
+    const std::vector<TerrainType>::const_iterator begin() const;
+    std::vector<TerrainType>::iterator end();
+    const std::vector<TerrainType>::const_iterator end() const;
+    size_t size() const;
+    bool empty() const;
+    void resize(size_t new_size);
+
+private:
+    TerrainList() = default;
+
+    static TerrainList instance;
+    std::vector<TerrainType> terrains{};
+};
index 9d5de46..09e05af 100644 (file)
@@ -1,6 +1,4 @@
-#include "target/grid-selector.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "target/grid-selector.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "floor/cave.h"
@@ -14,6 +12,7 @@
 #include "io/screen-util.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-checker.h"
 #include "term/screen-processor.h"
 #include "timed-effect/player-hallucination.h"
@@ -45,21 +44,19 @@ static bool tgt_pt_accept(PlayerType *player_ptr, POSITION y, POSITION x)
         return false;
     }
 
-    grid_type *g_ptr;
-    g_ptr = &floor_ptr->grid_array[y][x];
-    if (!g_ptr->is_mark()) {
+    auto &grid = floor_ptr->grid_array[y][x];
+    if (!grid.is_mark()) {
         return false;
     }
 
-    if (g_ptr->cave_has_flag(TerrainCharacteristics::LESS) || g_ptr->cave_has_flag(TerrainCharacteristics::MORE) || g_ptr->cave_has_flag(TerrainCharacteristics::QUEST_ENTER) || g_ptr->cave_has_flag(TerrainCharacteristics::QUEST_EXIT)) {
-        return true;
-    }
-
-    if (g_ptr->cave_has_flag(TerrainCharacteristics::STORE) || g_ptr->cave_has_flag(TerrainCharacteristics::BLDG)) {
-        return true;
-    }
-
-    return false;
+    using Tc = TerrainCharacteristics;
+    auto is_acceptable = grid.cave_has_flag(Tc::LESS);
+    is_acceptable |= grid.cave_has_flag(Tc::MORE);
+    is_acceptable |= grid.cave_has_flag(Tc::QUEST_ENTER);
+    is_acceptable |= grid.cave_has_flag(Tc::QUEST_EXIT);
+    is_acceptable |= grid.cave_has_flag(Tc::STORE);
+    is_acceptable |= grid.cave_has_flag(Tc::BLDG);
+    return is_acceptable;
 }
 
 /*
@@ -90,20 +87,20 @@ static void tgt_pt_prepare(PlayerType *player_ptr, std::vector<POSITION> &ys, st
 /*!
  * @brief 指定したシンボルのマスかどうかを判定するための条件式コールバック
  */
-std::unordered_map<int, std::function<bool(grid_type *)>> tgt_pt_symbol_call_back = {
-    { '<', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STAIRS) && g_ptr->cave_has_flag(TerrainCharacteristics::LESS); } },
-    { '>', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STAIRS) && g_ptr->cave_has_flag(TerrainCharacteristics::MORE); } },
-    { '+', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::BLDG); } },
-    { '0', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('0'); } },
-    { '!', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('1'); } },
-    { '"', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('2'); } },
-    { '#', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('3'); } },
-    { '$', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('4'); } },
-    { '%', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('5'); } },
-    { '&', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('6'); } },
-    { '\'', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('7'); } },
-    { '(', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('8'); } },
-    { ')', [](grid_type *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('9'); } },
+std::unordered_map<int, std::function<bool(Grid *)>> tgt_pt_symbol_call_back = {
+    { '<', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STAIRS) && g_ptr->cave_has_flag(TerrainCharacteristics::LESS); } },
+    { '>', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STAIRS) && g_ptr->cave_has_flag(TerrainCharacteristics::MORE); } },
+    { '+', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::BLDG); } },
+    { '0', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('0'); } },
+    { '!', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('1'); } },
+    { '"', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('2'); } },
+    { '#', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('3'); } },
+    { '$', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('4'); } },
+    { '%', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('5'); } },
+    { '&', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('6'); } },
+    { '\'', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('7'); } },
+    { '(', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('8'); } },
+    { ')', [](Grid *g_ptr) { return g_ptr->cave_has_flag(TerrainCharacteristics::STORE) && g_ptr->is_symbol('9'); } },
 };
 
 /*!
@@ -112,16 +109,21 @@ std::unordered_map<int, std::function<bool(grid_type *)>> tgt_pt_symbol_call_bac
  * ang_sort() を利用する関係上、y/x 座標それぞれについて配列を作る。
  */
 struct tgt_pt_info {
-    TERM_LEN wid; //!< 画面サイズ(幅)
-    TERM_LEN hgt; //!< 画面サイズ(高さ)
-    POSITION y; //!< 現在の指定位置(Y)
-    POSITION x; //!< 現在の指定位置(X)
-    std::vector<POSITION> ys; //!< "interesting" な座標たちを記録する配列(Y)
-    std::vector<POSITION> xs; //!< "interesting" な座標たちを記録する配列(X)
-    size_t n; //<! シンボル配列の何番目か
-    char ch; //<! 入力キー
-    char prev_ch; //<! 前回入力キー
-    std::function<bool(grid_type *)> callback; //<! 条件判定コールバック
+    tgt_pt_info()
+    {
+        std::tie(this->width, this->height) = get_screen_size();
+    };
+
+    int width; //!< 画面サイズ(幅)
+    int height; //!< 画面サイズ(高さ)
+    POSITION y = 0; //!< 現在の指定位置(Y)
+    POSITION x = 0; //!< 現在の指定位置(X)
+    std::vector<POSITION> ys{}; //!< "interesting" な座標たちを記録する配列(Y)
+    std::vector<POSITION> xs{}; //!< "interesting" な座標たちを記録する配列(X)
+    size_t n = 0; //<! シンボル配列の何番目か
+    char ch = '\0'; //<! 入力キー
+    char prev_ch = '\0'; //<! 前回入力キー
+    std::function<bool(Grid *)> callback{}; //<! 条件判定コールバック
 
     void move_to_symbol(PlayerType *player_ptr);
 };
@@ -161,15 +163,16 @@ void tgt_pt_info::move_to_symbol(PlayerType *player_ptr)
         this->y = player_ptr->y;
         this->x = player_ptr->x;
         verify_panel(player_ptr);
-        player_ptr->update |= PU_MONSTER_STATUSES;
-        player_ptr->redraw |= PR_MAP;
-        player_ptr->window_flags |= PW_OVERHEAD;
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+        rfu.set_flag(MainWindowRedrawingFlag::MAP);
+        rfu.set_flag(SubWindowRedrawingFlag::OVERHEAD);
         handle_stuff(player_ptr);
     } else {
         this->y = this->ys[this->n];
         this->x = this->xs[this->n];
-        dy = 2 * (this->y - cy) / this->hgt;
-        dx = 2 * (this->x - cx) / this->wid;
+        dy = 2 * (this->y - cy) / this->height;
+        dx = 2 * (this->x - cx) / this->width;
         if (dy || dx) {
             change_panel(player_ptr, dy, dx);
         }
@@ -186,8 +189,6 @@ void tgt_pt_info::move_to_symbol(PlayerType *player_ptr)
 bool tgt_pt(PlayerType *player_ptr, POSITION *x_ptr, POSITION *y_ptr)
 {
     tgt_pt_info info;
-    get_screen_size(&info.wid, &info.hgt);
-
     info.y = player_ptr->y;
     info.x = player_ptr->x;
     if (expand_list) {
@@ -210,7 +211,7 @@ bool tgt_pt(PlayerType *player_ptr, POSITION *x_ptr, POSITION *y_ptr)
         case ' ':
         case 't':
         case '.':
-            if (player_bold(player_ptr, info.y, info.x)) {
+            if (player_ptr->is_located_at({ info.y, info.x })) {
                 info.ch = 0;
             } else {
                 success = true;
@@ -244,7 +245,7 @@ bool tgt_pt(PlayerType *player_ptr, POSITION *x_ptr, POSITION *y_ptr)
                 }
             } else {
                 if (info.ch == '5' || info.ch == '0') {
-                    if (player_bold(player_ptr, info.y, info.x)) {
+                    if (player_ptr->is_located_at({ info.y, info.x })) {
                         info.ch = 0;
                     } else {
                         success = true;
@@ -265,7 +266,7 @@ bool tgt_pt(PlayerType *player_ptr, POSITION *x_ptr, POSITION *y_ptr)
             int dx = ddx[d];
             int dy = ddy[d];
             if (move_fast) {
-                int mag = std::min(info.wid / 2, info.hgt / 2);
+                int mag = std::min(info.width / 2, info.height / 2);
                 info.x += dx * mag;
                 info.y += dy * mag;
             } else {
@@ -273,15 +274,15 @@ bool tgt_pt(PlayerType *player_ptr, POSITION *x_ptr, POSITION *y_ptr)
                 info.y += dy;
             }
 
-            if (((info.x < panel_col_min + info.wid / 2) && (dx > 0)) || ((info.x > panel_col_min + info.wid / 2) && (dx < 0))) {
+            if (((info.x < panel_col_min + info.width / 2) && (dx > 0)) || ((info.x > panel_col_min + info.width / 2) && (dx < 0))) {
                 dx = 0;
             }
 
-            if (((info.y < panel_row_min + info.hgt / 2) && (dy > 0)) || ((info.y > panel_row_min + info.hgt / 2) && (dy < 0))) {
+            if (((info.y < panel_row_min + info.height / 2) && (dy > 0)) || ((info.y > panel_row_min + info.height / 2) && (dy < 0))) {
                 dy = 0;
             }
 
-            if ((info.y >= panel_row_min + info.hgt) || (info.y < panel_row_min) || (info.x >= panel_col_min + info.wid) || (info.x < panel_col_min)) {
+            if ((info.y >= panel_row_min + info.height) || (info.y < panel_row_min) || (info.x >= panel_col_min + info.width) || (info.x < panel_col_min)) {
                 change_panel(player_ptr, dy, dx);
             }
 
@@ -304,9 +305,10 @@ bool tgt_pt(PlayerType *player_ptr, POSITION *x_ptr, POSITION *y_ptr)
 
     prt("", 0, 0);
     verify_panel(player_ptr);
-    player_ptr->update |= PU_MONSTER_STATUSES;
-    player_ptr->redraw |= PR_MAP;
-    player_ptr->window_flags |= PW_OVERHEAD;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    rfu.set_flag(SubWindowRedrawingFlag::OVERHEAD);
     handle_stuff(player_ptr);
     *x_ptr = info.x;
     *y_ptr = info.y;
index fe879bb..2f8317e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 6c7d7a7..b406800 100644 (file)
@@ -1,9 +1,10 @@
-#include "target/projection-path-calculator.h"
+#include "target/projection-path-calculator.h"
 #include "effect/effect-characteristics.h"
 #include "effect/spells-effect-util.h"
 #include "floor/cave.h"
 #include "grid/feature-flag-types.h"
 #include "spell-class/spells-mirror-master.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
@@ -95,36 +96,38 @@ static void set_asxy(projection_path_type *pp_ptr)
 static bool project_stop(PlayerType *player_ptr, projection_path_type *pp_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-
-    if (none_bits(pp_ptr->flag, PROJECT_THRU) && (pp_ptr->x == pp_ptr->x2) && (pp_ptr->y == pp_ptr->y2)) {
+    const Pos2D pos(pp_ptr->y, pp_ptr->x);
+    const Pos2D pos2(pp_ptr->y2, pp_ptr->x2);
+    if (none_bits(pp_ptr->flag, PROJECT_THRU) && (pos == pos2)) {
         return true;
     }
 
     if (any_bits(pp_ptr->flag, PROJECT_DISI)) {
-        if (!pp_ptr->position->empty() && cave_stop_disintegration(floor_ptr, pp_ptr->y, pp_ptr->x)) {
+        if (!pp_ptr->position->empty() && cave_stop_disintegration(floor_ptr, pos.y, pos.x)) {
             return true;
         }
     } else if (any_bits(pp_ptr->flag, PROJECT_LOS)) {
-        if (!pp_ptr->position->empty() && !cave_los_bold(floor_ptr, pp_ptr->y, pp_ptr->x)) {
+        if (!pp_ptr->position->empty() && !cave_los_bold(floor_ptr, pos.y, pos.x)) {
             return true;
         }
     } else if (none_bits(pp_ptr->flag, PROJECT_PATH)) {
-        if (!pp_ptr->position->empty() && !cave_has_flag_bold(floor_ptr, pp_ptr->y, pp_ptr->x, TerrainCharacteristics::PROJECT)) {
+        if (!pp_ptr->position->empty() && !cave_has_flag_bold(floor_ptr, pos.y, pos.x, TerrainCharacteristics::PROJECT)) {
             return true;
         }
     }
 
+    const auto &grid = floor_ptr->get_grid(pos);
     if (any_bits(pp_ptr->flag, PROJECT_MIRROR)) {
-        if (!pp_ptr->position->empty() && floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].is_mirror()) {
+        if (!pp_ptr->position->empty() && grid.is_mirror()) {
             return true;
         }
     }
 
-    if (any_bits(pp_ptr->flag, PROJECT_STOP) && !pp_ptr->position->empty() && (player_bold(player_ptr, pp_ptr->y, pp_ptr->x) || floor_ptr->grid_array[pp_ptr->y][pp_ptr->x].m_idx != 0)) {
+    if (any_bits(pp_ptr->flag, PROJECT_STOP) && !pp_ptr->position->empty() && (player_ptr->is_located_at(pos) || grid.m_idx != 0)) {
         return true;
     }
 
-    if (!in_bounds(floor_ptr, pp_ptr->y, pp_ptr->x)) {
+    if (!in_bounds(floor_ptr, pos.y, pos.x)) {
         return true;
     }
 
@@ -277,12 +280,12 @@ projection_path::projection_path(PlayerType *player_ptr, POSITION range, POSITIO
  */
 bool projectable(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
 {
-    projection_path grid_g(player_ptr, (project_length ? project_length : get_max_range(player_ptr)), y1, x1, y2, x2, 0);
+    projection_path grid_g(player_ptr, (project_length ? project_length : AngbandSystem::get_instance().get_max_range()), y1, x1, y2, x2, 0);
     if (grid_g.path_num() == 0) {
         return true;
     }
 
-    const auto [y, x] = grid_g.back();
+    const auto &[y, x] = grid_g.back();
     if ((y != y2) || (x != x2)) {
         return false;
     }
@@ -290,16 +293,6 @@ bool projectable(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2,
     return true;
 }
 
-/*!
- * @briefプレイヤーの攻撃射程(マス) / Maximum range (spells, etc)
- * @param player_ptr プレイヤーへの参照ポインタ
- * @return 射程
- */
-int get_max_range(PlayerType *player_ptr)
-{
-    return player_ptr->phase_out ? 36 : 18;
-}
-
 /*
  * Convert a "grid" (G) into a "location" (Y)
  */
index a7f0b8d..9b0cff5 100644 (file)
@@ -1,9 +1,10 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <utility>
 #include <vector>
 
+// @todo pairをPos2Dとして再定義する.
 class PlayerType;
 class projection_path {
 public:
@@ -21,6 +22,5 @@ private:
     std::vector<std::pair<int, int>> position;
 };
 bool projectable(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2);
-int get_max_range(PlayerType *player_ptr);
 POSITION get_grid_y(uint16_t grid);
 POSITION get_grid_x(uint16_t grid);
index cb3824b..1c9e6b2 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief 雑多なその他の処理2 / effects of various "objects"
  * @date 2014/02/06
  * @author
@@ -11,8 +11,6 @@
 
 #include "target/target-checker.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/window-redrawer.h"
 #include "game-option/disturbance-options.h"
 #include "game-option/map-screen-options.h"
@@ -21,6 +19,7 @@
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/target-preparation.h"
 #include "target/target-types.h"
 #include "window/main-window-util.h"
@@ -44,8 +43,7 @@ void verify_panel(PlayerType *player_ptr)
 {
     POSITION y = player_ptr->y;
     POSITION x = player_ptr->x;
-    TERM_LEN wid, hgt;
-    get_screen_size(&wid, &hgt);
+    const auto &[wid, hgt] = get_screen_size();
     int max_prow_min = player_ptr->current_floor_ptr->height - hgt;
     int max_pcol_min = player_ptr->current_floor_ptr->width - wid;
     if (max_prow_min < 0) {
@@ -126,9 +124,14 @@ void verify_panel(PlayerType *player_ptr)
     }
 
     panel_bounds_center();
-    player_ptr->update |= PU_MONSTER_STATUSES;
-    player_ptr->redraw |= PR_MAP;
-    player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::DUNGEON,
+    };
+    rfu.set_flags(flags);
 }
 
 /*
index d0d63b4..77513d8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index c858ab9..bb3bd28 100644 (file)
@@ -1,4 +1,4 @@
-#include "target/target-describer.h"
+#include "target/target-describer.h"
 #include "action/travel-execution.h"
 #include "core/stuff-handler.h"
 #include "dungeon/quest.h"
 #include "window/display-sub-windows.h"
 #include "world/world.h"
 
-static const int16_t CONTINUOUS_DESCRIPTION = 256;
+namespace {
+constexpr short CONTINUOUS_DESCRIPTION = 256;
 
-bool show_gold_on_floor = false;
-
-// Examine grid
-struct eg_type {
+class GridExamination {
+public:
+    GridExamination(FloorType &floor, POSITION y, POSITION x, target_type mode, concptr info);
     POSITION y;
     POSITION x;
     target_type mode;
-    bool boring;
+    bool boring = true;
     concptr info;
-    concptr s1;
-    concptr s2;
-    concptr s3;
-    concptr x_info;
-    char query;
-    char out_val[MAX_NLEN + 80];
-    OBJECT_IDX floor_list[23];
-    ITEM_NUMBER floor_num;
-    grid_type *g_ptr;
+    concptr s1 = "";
+    concptr s2 = "";
+    concptr s3 = "";
+    concptr x_info = "";
+    char query = '\001';
+    char out_val[MAX_NLEN + 80]{};
+    OBJECT_IDX floor_list[23]{};
+    ITEM_NUMBER floor_num = 0;
+    Grid *g_ptr;
     MonsterEntity *m_ptr;
-    OBJECT_IDX next_o_idx;
-    FEAT_IDX feat;
-    TerrainType *f_ptr;
-    std::string name;
+    OBJECT_IDX next_o_idx = 0;
+    FEAT_IDX feat = 0;
+    TerrainType *terrain_ptr = nullptr;
+    std::string name = "";
 };
 
-static eg_type *initialize_eg_type(PlayerType *player_ptr, eg_type *eg_ptr, POSITION y, POSITION x, target_type mode, concptr info)
+GridExamination::GridExamination(FloorType &floor, POSITION y, POSITION x, target_type mode, concptr info)
+    : y(y)
+    , x(x)
+    , mode(mode)
+    , info(info)
 {
-    eg_ptr->y = y;
-    eg_ptr->x = x;
-    eg_ptr->boring = true;
-    eg_ptr->mode = mode;
-    eg_ptr->info = info;
-    eg_ptr->s1 = "";
-    eg_ptr->s2 = "";
-    eg_ptr->s3 = "";
-    eg_ptr->x_info = "";
-    eg_ptr->query = '\001';
-    eg_ptr->floor_num = 0;
-
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    eg_ptr->g_ptr = &floor_ptr->grid_array[y][x];
-    eg_ptr->m_ptr = &floor_ptr->m_list[eg_ptr->g_ptr->m_idx];
-    eg_ptr->next_o_idx = 0;
-    return eg_ptr;
+    this->g_ptr = &floor.grid_array[y][x];
+    this->m_ptr = &floor.m_list[this->g_ptr->m_idx];
+    this->next_o_idx = 0;
+}
 }
 
+bool show_gold_on_floor = false;
+
 /*
  * Evaluate number of kill needed to gain level
  */
 static std::string evaluate_monster_exp(PlayerType *player_ptr, MonsterEntity *m_ptr)
 {
-    MonsterRaceInfo *ap_r_ptr = &monraces_info[m_ptr->ap_r_idx];
+    MonsterRaceInfo *ap_r_ptr = &m_ptr->get_appearance_monrace();
     if ((player_ptr->lev >= PY_MAX_LEVEL) || PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
         return "**";
     }
@@ -131,36 +124,36 @@ static std::string evaluate_monster_exp(PlayerType *player_ptr, MonsterEntity *m
     return format("%03ld", (long int)num);
 }
 
-static void describe_scan_result(PlayerType *player_ptr, eg_type *eg_ptr)
+static void describe_scan_result(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
     if (!easy_floor) {
         return;
     }
 
-    eg_ptr->floor_num = scan_floor_items(player_ptr, eg_ptr->floor_list, eg_ptr->y, eg_ptr->x, SCAN_FLOOR_ONLY_MARKED, AllMatchItemTester());
-    if (eg_ptr->floor_num > 0) {
-        eg_ptr->x_info = _("x物 ", "x,");
+    ge_ptr->floor_num = scan_floor_items(player_ptr, ge_ptr->floor_list, ge_ptr->y, ge_ptr->x, SCAN_FLOOR_ONLY_MARKED, AllMatchItemTester());
+    if (ge_ptr->floor_num > 0) {
+        ge_ptr->x_info = _("x物 ", "x,");
     }
 }
 
-static void describe_target(PlayerType *player_ptr, eg_type *eg_ptr)
+static void describe_target(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
-    if (!player_bold(player_ptr, eg_ptr->y, eg_ptr->x)) {
-        eg_ptr->s1 = _("ターゲット:", "Target:");
+    if (!player_ptr->is_located_at({ ge_ptr->y, ge_ptr->x })) {
+        ge_ptr->s1 = _("ターゲット:", "Target:");
         return;
     }
 
 #ifdef JP
-    eg_ptr->s1 = "あなたは";
-    eg_ptr->s2 = "の上";
-    eg_ptr->s3 = "にいる";
+    ge_ptr->s1 = "あなたは";
+    ge_ptr->s2 = "の上";
+    ge_ptr->s3 = "にいる";
 #else
-    eg_ptr->s1 = "You are ";
-    eg_ptr->s2 = "on ";
+    ge_ptr->s1 = "You are ";
+    ge_ptr->s2 = "on ";
 #endif
 }
 
-static ProcessResult describe_hallucinated_target(PlayerType *player_ptr, eg_type *eg_ptr)
+static ProcessResult describe_hallucinated_target(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
     if (!player_ptr->effects()->hallucination()->is_hallucinated()) {
         return ProcessResult::PROCESS_CONTINUE;
@@ -168,37 +161,37 @@ static ProcessResult describe_hallucinated_target(PlayerType *player_ptr, eg_typ
 
     concptr name = _("何か奇妙な物", "something strange");
 #ifdef JP
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s [%s]", ge_ptr->s1, name, ge_ptr->s2, ge_ptr->s3, ge_ptr->info);
 #else
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, name, eg_ptr->info);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s [%s]", ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, name, ge_ptr->info);
 #endif
-    prt(eg_ptr->out_val, 0, 0);
-    move_cursor_relative(eg_ptr->y, eg_ptr->x);
-    eg_ptr->query = inkey();
-    if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n')) {
+    prt(ge_ptr->out_val, 0, 0);
+    move_cursor_relative(ge_ptr->y, ge_ptr->x);
+    ge_ptr->query = inkey();
+    if ((ge_ptr->query != '\r') && (ge_ptr->query != '\n')) {
         return ProcessResult::PROCESS_TRUE;
     }
 
     return ProcessResult::PROCESS_FALSE;
 }
 
-static bool describe_grid_lore(PlayerType *player_ptr, eg_type *eg_ptr)
+static bool describe_grid_lore(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
     screen_save();
-    screen_roff(player_ptr, eg_ptr->m_ptr->ap_r_idx, MONSTER_LORE_NORMAL);
-    term_addstr(-1, TERM_WHITE, format(_("  [r思 %s%s]", "  [r,%s%s]"), eg_ptr->x_info, eg_ptr->info));
-    eg_ptr->query = inkey();
+    screen_roff(player_ptr, ge_ptr->m_ptr->ap_r_idx, MONSTER_LORE_NORMAL);
+    term_addstr(-1, TERM_WHITE, format(_("  [r思 %s%s]", "  [r,%s%s]"), ge_ptr->x_info, ge_ptr->info));
+    ge_ptr->query = inkey();
     screen_load();
-    return eg_ptr->query != 'r';
+    return ge_ptr->query != 'r';
 }
 
-static void describe_grid_monster(PlayerType *player_ptr, eg_type *eg_ptr)
+static void describe_grid_monster(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
     bool recall = false;
-    const auto m_name = monster_desc(player_ptr, eg_ptr->m_ptr, MD_INDEF_VISIBLE);
+    const auto m_name = monster_desc(player_ptr, ge_ptr->m_ptr, MD_INDEF_VISIBLE);
     while (true) {
         if (recall) {
-            if (describe_grid_lore(player_ptr, eg_ptr)) {
+            if (describe_grid_lore(player_ptr, ge_ptr)) {
                 return;
             }
 
@@ -206,19 +199,19 @@ static void describe_grid_monster(PlayerType *player_ptr, eg_type *eg_ptr)
             continue;
         }
 
-        std::string acount = evaluate_monster_exp(player_ptr, eg_ptr->m_ptr);
-        const auto mon_desc = look_mon_desc(eg_ptr->m_ptr, 0x01);
+        std::string acount = evaluate_monster_exp(player_ptr, ge_ptr->m_ptr);
+        const auto mon_desc = look_mon_desc(ge_ptr->m_ptr, 0x01);
 #ifdef JP
-        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "[%s]%s%s(%s)%s%s [r思 %s%s]", acount.data(), eg_ptr->s1, m_name.data(), mon_desc.data(), eg_ptr->s2, eg_ptr->s3,
-            eg_ptr->x_info, eg_ptr->info);
+        strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "[%s]%s%s(%s)%s%s [r思 %s%s]", acount.data(), ge_ptr->s1, m_name.data(), mon_desc.data(), ge_ptr->s2, ge_ptr->s3,
+            ge_ptr->x_info, ge_ptr->info);
 #else
-        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "[%s]%s%s%s%s(%s) [r, %s%s]", acount.data(), eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, m_name.data(), mon_desc.data(),
-            eg_ptr->x_info, eg_ptr->info);
+        strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "[%s]%s%s%s%s(%s) [r, %s%s]", acount.data(), ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, m_name.data(), mon_desc.data(),
+            ge_ptr->x_info, ge_ptr->info);
 #endif
-        prt(eg_ptr->out_val, 0, 0);
-        move_cursor_relative(eg_ptr->y, eg_ptr->x);
-        eg_ptr->query = inkey();
-        if (eg_ptr->query != 'r') {
+        prt(ge_ptr->out_val, 0, 0);
+        move_cursor_relative(ge_ptr->y, ge_ptr->x);
+        ge_ptr->query = inkey();
+        if (ge_ptr->query != 'r') {
             return;
         }
 
@@ -226,226 +219,225 @@ static void describe_grid_monster(PlayerType *player_ptr, eg_type *eg_ptr)
     }
 }
 
-static void describe_monster_person(eg_type *eg_ptr)
+static void describe_monster_person(GridExamination *ge_ptr)
 {
-    MonsterRaceInfo *ap_r_ptr = &monraces_info[eg_ptr->m_ptr->ap_r_idx];
-    eg_ptr->s1 = _("それは", "It is ");
-    if (ap_r_ptr->flags1 & RF1_FEMALE) {
-        eg_ptr->s1 = _("彼女は", "She is ");
-    } else if (ap_r_ptr->flags1 & RF1_MALE) {
-        eg_ptr->s1 = _("彼は", "He is ");
+    const auto &monrace = ge_ptr->m_ptr->get_appearance_monrace();
+    ge_ptr->s1 = _("それは", "It is ");
+    if (monrace.sex == MonsterSex::FEMALE) {
+        ge_ptr->s1 = _("彼女は", "She is ");
+    } else if (monrace.sex == MonsterSex::MALE) {
+        ge_ptr->s1 = _("彼は", "He is ");
     }
 
 #ifdef JP
-    eg_ptr->s2 = "を";
-    eg_ptr->s3 = "持っている";
+    ge_ptr->s2 = "を";
+    ge_ptr->s3 = "持っている";
 #else
-    eg_ptr->s2 = "carrying ";
+    ge_ptr->s2 = "carrying ";
 #endif
 }
 
-static uint16_t describe_monster_item(PlayerType *player_ptr, eg_type *eg_ptr)
+static short describe_monster_item(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
-    for (const auto this_o_idx : eg_ptr->m_ptr->hold_o_idx_list) {
+    for (const auto this_o_idx : ge_ptr->m_ptr->hold_o_idx_list) {
         auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
         const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
 #ifdef JP
-        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, item_name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+        strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s[%s]", ge_ptr->s1, item_name.data(), ge_ptr->s2, ge_ptr->s3, ge_ptr->info);
 #else
-        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, item_name.data(), eg_ptr->info);
+        strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s [%s]", ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, item_name.data(), ge_ptr->info);
 #endif
-        prt(eg_ptr->out_val, 0, 0);
-        move_cursor_relative(eg_ptr->y, eg_ptr->x);
-        eg_ptr->query = inkey();
-        if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
-            return eg_ptr->query;
+        prt(ge_ptr->out_val, 0, 0);
+        move_cursor_relative(ge_ptr->y, ge_ptr->x);
+        ge_ptr->query = inkey();
+        if ((ge_ptr->query != '\r') && (ge_ptr->query != '\n') && (ge_ptr->query != ' ') && (ge_ptr->query != 'x')) {
+            return ge_ptr->query;
         }
 
-        if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
-            return eg_ptr->query;
+        if ((ge_ptr->query == ' ') && !(ge_ptr->mode & TARGET_LOOK)) {
+            return ge_ptr->query;
         }
 
-        eg_ptr->s2 = _("をまた", "also carrying ");
+        ge_ptr->s2 = _("をまた", "also carrying ");
     }
 
     return CONTINUOUS_DESCRIPTION;
 }
 
-static bool within_char_util(int16_t input)
+static bool within_char_util(const short input)
 {
     return (input > -127) && (input < 128);
 }
 
-static int16_t describe_grid(PlayerType *player_ptr, eg_type *eg_ptr)
+static short describe_grid(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
-    if ((eg_ptr->g_ptr->m_idx == 0) || !player_ptr->current_floor_ptr->m_list[eg_ptr->g_ptr->m_idx].ml) {
+    if ((ge_ptr->g_ptr->m_idx == 0) || !player_ptr->current_floor_ptr->m_list[ge_ptr->g_ptr->m_idx].ml) {
         return CONTINUOUS_DESCRIPTION;
     }
 
-    eg_ptr->boring = false;
-    monster_race_track(player_ptr, eg_ptr->m_ptr->ap_r_idx);
-    health_track(player_ptr, eg_ptr->g_ptr->m_idx);
+    ge_ptr->boring = false;
+    monster_race_track(player_ptr, ge_ptr->m_ptr->ap_r_idx);
+    health_track(player_ptr, ge_ptr->g_ptr->m_idx);
     handle_stuff(player_ptr);
-    describe_grid_monster(player_ptr, eg_ptr);
-    if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
-        return eg_ptr->query;
+    describe_grid_monster(player_ptr, ge_ptr);
+    if ((ge_ptr->query != '\r') && (ge_ptr->query != '\n') && (ge_ptr->query != ' ') && (ge_ptr->query != 'x')) {
+        return ge_ptr->query;
     }
 
-    if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
-        return eg_ptr->query;
+    if ((ge_ptr->query == ' ') && !(ge_ptr->mode & TARGET_LOOK)) {
+        return ge_ptr->query;
     }
 
-    describe_monster_person(eg_ptr);
-    uint16_t monster_item_description = describe_monster_item(player_ptr, eg_ptr);
+    describe_monster_person(ge_ptr);
+    const auto monster_item_description = describe_monster_item(player_ptr, ge_ptr);
     if (within_char_util(monster_item_description)) {
         return (char)monster_item_description;
     }
 
 #ifdef JP
-    eg_ptr->s2 = "の上";
-    eg_ptr->s3 = "にいる";
+    ge_ptr->s2 = "の上";
+    ge_ptr->s3 = "にいる";
 #else
-    eg_ptr->s2 = "on ";
+    ge_ptr->s2 = "on ";
 #endif
     return CONTINUOUS_DESCRIPTION;
 }
 
-static int16_t describe_footing(PlayerType *player_ptr, eg_type *eg_ptr)
+static short describe_footing(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
-    if (eg_ptr->floor_num != 1) {
+    if (ge_ptr->floor_num != 1) {
         return CONTINUOUS_DESCRIPTION;
     }
 
-    auto *o_ptr = &player_ptr->current_floor_ptr->o_list[eg_ptr->floor_list[0]];
+    auto *o_ptr = &player_ptr->current_floor_ptr->o_list[ge_ptr->floor_list[0]];
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
 #ifdef JP
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, item_name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s[%s]", ge_ptr->s1, item_name.data(), ge_ptr->s2, ge_ptr->s3, ge_ptr->info);
 #else
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, item_name.data(), eg_ptr->info);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s [%s]", ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, item_name.data(), ge_ptr->info);
 #endif
-    prt(eg_ptr->out_val, 0, 0);
-    move_cursor_relative(eg_ptr->y, eg_ptr->x);
-    eg_ptr->query = inkey();
-    return eg_ptr->query;
+    prt(ge_ptr->out_val, 0, 0);
+    move_cursor_relative(ge_ptr->y, ge_ptr->x);
+    ge_ptr->query = inkey();
+    return ge_ptr->query;
 }
 
-static int16_t describe_footing_items(eg_type *eg_ptr)
+static short describe_footing_items(GridExamination *ge_ptr)
 {
-    if (!eg_ptr->boring) {
+    if (!ge_ptr->boring) {
         return CONTINUOUS_DESCRIPTION;
     }
 
 #ifdef JP
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s %d個のアイテム%s%s ['x'で一覧, %s]", eg_ptr->s1, (int)eg_ptr->floor_num, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s %d個のアイテム%s%s ['x'で一覧, %s]", ge_ptr->s1, (int)ge_ptr->floor_num, ge_ptr->s2, ge_ptr->s3, ge_ptr->info);
 #else
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%sa pile of %d items [x,%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, (int)eg_ptr->floor_num, eg_ptr->info);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%sa pile of %d items [x,%s]", ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, (int)ge_ptr->floor_num, ge_ptr->info);
 #endif
-    prt(eg_ptr->out_val, 0, 0);
-    move_cursor_relative(eg_ptr->y, eg_ptr->x);
-    eg_ptr->query = inkey();
-    if (eg_ptr->query != 'x' && eg_ptr->query != ' ') {
-        return eg_ptr->query;
+    prt(ge_ptr->out_val, 0, 0);
+    move_cursor_relative(ge_ptr->y, ge_ptr->x);
+    ge_ptr->query = inkey();
+    if (ge_ptr->query != 'x' && ge_ptr->query != ' ') {
+        return ge_ptr->query;
     }
 
     return CONTINUOUS_DESCRIPTION;
 }
 
-static char describe_footing_many_items(PlayerType *player_ptr, eg_type *eg_ptr, int *min_width)
+static char describe_footing_many_items(PlayerType *player_ptr, GridExamination *ge_ptr, int *min_width)
 {
     while (true) {
         screen_save();
         show_gold_on_floor = true;
-        (void)show_floor_items(player_ptr, 0, eg_ptr->y, eg_ptr->x, min_width, AllMatchItemTester());
+        (void)show_floor_items(player_ptr, 0, ge_ptr->y, ge_ptr->x, min_width, AllMatchItemTester());
         show_gold_on_floor = false;
 #ifdef JP
-        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s %d個のアイテム%s%s [Enterで次へ, %s]", eg_ptr->s1, (int)eg_ptr->floor_num, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+        strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s %d個のアイテム%s%s [Enterで次へ, %s]", ge_ptr->s1, (int)ge_ptr->floor_num, ge_ptr->s2, ge_ptr->s3, ge_ptr->info);
 #else
-        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%sa pile of %d items [Enter,%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, (int)eg_ptr->floor_num, eg_ptr->info);
+        strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%sa pile of %d items [Enter,%s]", ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, (int)ge_ptr->floor_num, ge_ptr->info);
 #endif
-        prt(eg_ptr->out_val, 0, 0);
-        eg_ptr->query = inkey();
+        prt(ge_ptr->out_val, 0, 0);
+        ge_ptr->query = inkey();
         screen_load();
-        if (eg_ptr->query != '\n' && eg_ptr->query != '\r') {
-            return eg_ptr->query;
+        if (ge_ptr->query != '\n' && ge_ptr->query != '\r') {
+            return ge_ptr->query;
         }
 
-        if (eg_ptr->g_ptr->o_idx_list.size() < 2) {
+        if (ge_ptr->g_ptr->o_idx_list.size() < 2) {
             continue;
         }
 
-        eg_ptr->g_ptr->o_idx_list.rotate(player_ptr->current_floor_ptr);
+        ge_ptr->g_ptr->o_idx_list.rotate(player_ptr->current_floor_ptr);
 
         // ターゲットしている床の座標を渡す必要があるので、window_stuff経由ではなく直接呼び出す
-        fix_floor_item_list(player_ptr, eg_ptr->y, eg_ptr->x);
+        fix_floor_item_list(player_ptr, { ge_ptr->y, ge_ptr->x });
     }
 }
 
-static int16_t loop_describing_grid(PlayerType *player_ptr, eg_type *eg_ptr)
+static short loop_describing_grid(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
-    if (eg_ptr->floor_num == 0) {
+    if (ge_ptr->floor_num == 0) {
         return CONTINUOUS_DESCRIPTION;
     }
 
-    int min_width = 0;
+    auto min_width = 0;
     while (true) {
-        int16_t footing_description = describe_footing(player_ptr, eg_ptr);
+        const auto footing_description = describe_footing(player_ptr, ge_ptr);
         if (within_char_util(footing_description)) {
             return (char)footing_description;
         }
 
-        int16_t footing_descriptions = describe_footing_items(eg_ptr);
+        const auto footing_descriptions = describe_footing_items(ge_ptr);
         if (within_char_util(footing_descriptions)) {
             return (char)footing_descriptions;
         }
 
-        return describe_footing_many_items(player_ptr, eg_ptr, &min_width);
+        return describe_footing_many_items(player_ptr, ge_ptr, &min_width);
     }
 }
 
-static int16_t describe_footing_sight(PlayerType *player_ptr, eg_type *eg_ptr, ItemEntity *o_ptr)
+static short describe_footing_sight(PlayerType *player_ptr, GridExamination *ge_ptr, ItemEntity *o_ptr)
 {
     if (o_ptr->marked.has_not(OmType::FOUND)) {
         return CONTINUOUS_DESCRIPTION;
     }
 
-    eg_ptr->boring = false;
+    ge_ptr->boring = false;
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
 #ifdef JP
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, item_name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s[%s]", ge_ptr->s1, item_name.data(), ge_ptr->s2, ge_ptr->s3, ge_ptr->info);
 #else
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, item_name.data(), eg_ptr->info);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s [%s]", ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, item_name.data(), ge_ptr->info);
 #endif
-    prt(eg_ptr->out_val, 0, 0);
-    move_cursor_relative(eg_ptr->y, eg_ptr->x);
-    eg_ptr->query = inkey();
-    if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n') && (eg_ptr->query != ' ') && (eg_ptr->query != 'x')) {
-        return eg_ptr->query;
+    prt(ge_ptr->out_val, 0, 0);
+    move_cursor_relative(ge_ptr->y, ge_ptr->x);
+    ge_ptr->query = inkey();
+    if ((ge_ptr->query != '\r') && (ge_ptr->query != '\n') && (ge_ptr->query != ' ') && (ge_ptr->query != 'x')) {
+        return ge_ptr->query;
     }
 
-    if ((eg_ptr->query == ' ') && !(eg_ptr->mode & TARGET_LOOK)) {
-        return eg_ptr->query;
+    if ((ge_ptr->query == ' ') && !(ge_ptr->mode & TARGET_LOOK)) {
+        return ge_ptr->query;
     }
 
-    eg_ptr->s1 = _("それは", "It is ");
+    ge_ptr->s1 = _("それは", "It is ");
     if (o_ptr->number != 1) {
-        eg_ptr->s1 = _("それらは", "They are ");
+        ge_ptr->s1 = _("それらは", "They are ");
     }
 
 #ifdef JP
-    eg_ptr->s2 = "の上";
-    eg_ptr->s3 = "に見える";
+    ge_ptr->s2 = "の上";
+    ge_ptr->s3 = "に見える";
 #else
-    eg_ptr->s2 = "on ";
+    ge_ptr->s2 = "on ";
 #endif
     return CONTINUOUS_DESCRIPTION;
 }
 
-static int16_t sweep_footing_items(PlayerType *player_ptr, eg_type *eg_ptr)
+static int16_t sweep_footing_items(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
-    for (const auto this_o_idx : eg_ptr->g_ptr->o_idx_list) {
-        ItemEntity *o_ptr;
-        o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
-        int16_t ret = describe_footing_sight(player_ptr, eg_ptr, o_ptr);
+    for (const auto this_o_idx : ge_ptr->g_ptr->o_idx_list) {
+        auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
+        const auto ret = describe_footing_sight(player_ptr, ge_ptr, o_ptr);
         if (within_char_util(ret)) {
             return (char)ret;
         }
@@ -454,12 +446,13 @@ static int16_t sweep_footing_items(PlayerType *player_ptr, eg_type *eg_ptr)
     return CONTINUOUS_DESCRIPTION;
 }
 
-static std::string decide_target_floor(PlayerType *player_ptr, eg_type *eg_ptr)
+static std::string decide_target_floor(PlayerType *player_ptr, GridExamination *ge_ptr)
 {
-    if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER)) {
-        QuestId old_quest = player_ptr->current_floor_ptr->quest_number;
+    auto *floor_ptr = player_ptr->current_floor_ptr;
+    if (ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER)) {
+        QuestId old_quest = floor_ptr->quest_number;
         const auto &quest_list = QuestList::get_instance();
-        const QuestId number = i2enum<QuestId>(eg_ptr->g_ptr->special);
+        const QuestId number = i2enum<QuestId>(ge_ptr->g_ptr->special);
         const auto *q_ptr = &quest_list[number];
         std::string_view msg(_("クエスト「%s」(%d階相当)", "the entrance to the quest '%s'(level %d)"));
         for (int j = 0; j < 10; j++) {
@@ -467,57 +460,58 @@ static std::string decide_target_floor(PlayerType *player_ptr, eg_type *eg_ptr)
         }
 
         quest_text_line = 0;
-        player_ptr->current_floor_ptr->quest_number = number;
+        floor_ptr->quest_number = number;
         init_flags = INIT_NAME_ONLY;
         parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
-        player_ptr->current_floor_ptr->quest_number = old_quest;
+        floor_ptr->quest_number = old_quest;
         return format(msg.data(), q_ptr->name.data(), q_ptr->level);
     }
 
-    if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::BLDG) && !player_ptr->current_floor_ptr->inside_arena) {
-        return building[eg_ptr->f_ptr->subtype].name;
+    if (ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::BLDG) && !floor_ptr->inside_arena) {
+        return buildings[ge_ptr->terrain_ptr->subtype].name;
     }
 
-    if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::ENTRANCE)) {
-        return format(_("%s(%d階相当)", "%s(level %d)"), dungeons_info[eg_ptr->g_ptr->special].text.data(), dungeons_info[eg_ptr->g_ptr->special].mindepth);
+    if (ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::ENTRANCE)) {
+        const auto &dungeon = dungeons_info[ge_ptr->g_ptr->special];
+        return format(_("%s(%d階相当)", "%s(level %d)"), dungeon.text.data(), dungeon.mindepth);
     }
 
-    if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::TOWN)) {
-        return towns_info[eg_ptr->g_ptr->special].name;
+    if (ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::TOWN)) {
+        return towns_info[ge_ptr->g_ptr->special].name;
     }
 
-    if (player_ptr->wild_mode && (eg_ptr->feat == feat_floor)) {
+    if (player_ptr->wild_mode && (ge_ptr->feat == feat_floor)) {
         return _("道", "road");
     }
 
-    return eg_ptr->f_ptr->name.data();
+    return ge_ptr->terrain_ptr->name;
 }
 
-static void describe_grid_monster_all(eg_type *eg_ptr)
+static void describe_grid_monster_all(GridExamination *ge_ptr)
 {
     if (!w_ptr->wizard) {
 #ifdef JP
-        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, eg_ptr->name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+        strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s[%s]", ge_ptr->s1, ge_ptr->name.data(), ge_ptr->s2, ge_ptr->s3, ge_ptr->info);
 #else
-        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, eg_ptr->name.data(), eg_ptr->info);
+        strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s [%s]", ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, ge_ptr->name.data(), ge_ptr->info);
 #endif
         return;
     }
 
     std::string f_idx_str;
-    if (eg_ptr->g_ptr->mimic) {
-        f_idx_str = format("%d/%d", eg_ptr->g_ptr->feat, eg_ptr->g_ptr->mimic);
+    if (ge_ptr->g_ptr->mimic) {
+        f_idx_str = format("%d/%d", ge_ptr->g_ptr->feat, ge_ptr->g_ptr->mimic);
     } else {
-        f_idx_str = std::to_string(eg_ptr->g_ptr->feat);
+        f_idx_str = std::to_string(ge_ptr->g_ptr->feat);
     }
 
 #ifdef JP
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s] %x %s %d %d %d (%d,%d) %d", eg_ptr->s1, eg_ptr->name.data(), eg_ptr->s2, eg_ptr->s3, eg_ptr->info,
-        (uint)eg_ptr->g_ptr->info, f_idx_str.data(), eg_ptr->g_ptr->dists[FLOW_NORMAL], eg_ptr->g_ptr->costs[FLOW_NORMAL], eg_ptr->g_ptr->when, (int)eg_ptr->y,
-        (int)eg_ptr->x, travel.cost[eg_ptr->y][eg_ptr->x]);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s[%s] %x %s %d %d %d (%d,%d) %d", ge_ptr->s1, ge_ptr->name.data(), ge_ptr->s2, ge_ptr->s3, ge_ptr->info,
+        (uint)ge_ptr->g_ptr->info, f_idx_str.data(), ge_ptr->g_ptr->dists[FLOW_NORMAL], ge_ptr->g_ptr->costs[FLOW_NORMAL], ge_ptr->g_ptr->when, (int)ge_ptr->y,
+        (int)ge_ptr->x, travel.cost[ge_ptr->y][ge_ptr->x]);
 #else
-    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s] %x %s %d %d %d (%d,%d)", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, eg_ptr->name.data(), eg_ptr->info, eg_ptr->g_ptr->info,
-        f_idx_str.data(), eg_ptr->g_ptr->dists[FLOW_NORMAL], eg_ptr->g_ptr->costs[FLOW_NORMAL], eg_ptr->g_ptr->when, (int)eg_ptr->y, (int)eg_ptr->x);
+    strnfmt(ge_ptr->out_val, sizeof(ge_ptr->out_val), "%s%s%s%s [%s] %x %s %d %d %d (%d,%d)", ge_ptr->s1, ge_ptr->s2, ge_ptr->s3, ge_ptr->name.data(), ge_ptr->info, ge_ptr->g_ptr->info,
+        f_idx_str.data(), ge_ptr->g_ptr->dists[FLOW_NORMAL], ge_ptr->g_ptr->costs[FLOW_NORMAL], ge_ptr->g_ptr->when, (int)ge_ptr->y, (int)ge_ptr->x);
 #endif
 }
 
@@ -533,72 +527,85 @@ static void describe_grid_monster_all(eg_type *eg_ptr)
  */
 char examine_grid(PlayerType *player_ptr, const POSITION y, const POSITION x, target_type mode, concptr info)
 {
-    eg_type tmp_eg;
-    eg_type *eg_ptr = initialize_eg_type(player_ptr, &tmp_eg, y, x, mode, info);
-    describe_scan_result(player_ptr, eg_ptr);
-    describe_target(player_ptr, eg_ptr);
-    ProcessResult next_target = describe_hallucinated_target(player_ptr, eg_ptr);
+    GridExamination tmp_eg(*player_ptr->current_floor_ptr, y, x, mode, info);
+    GridExamination *ge_ptr = &tmp_eg;
+    describe_scan_result(player_ptr, ge_ptr);
+    describe_target(player_ptr, ge_ptr);
+    ProcessResult next_target = describe_hallucinated_target(player_ptr, ge_ptr);
     switch (next_target) {
     case ProcessResult::PROCESS_FALSE:
-        return 0;
+        return '\0';
     case ProcessResult::PROCESS_TRUE:
-        return eg_ptr->query;
+        return ge_ptr->query;
     default:
         break;
     }
 
-    int16_t description_grid = describe_grid(player_ptr, eg_ptr);
+    const auto description_grid = describe_grid(player_ptr, ge_ptr);
     if (within_char_util(description_grid)) {
         return (char)description_grid;
     }
 
-    int16_t loop_description = loop_describing_grid(player_ptr, eg_ptr);
+    const auto loop_description = loop_describing_grid(player_ptr, ge_ptr);
     if (within_char_util(loop_description)) {
         return (char)loop_description;
     }
 
-    int16_t footing_items_description = sweep_footing_items(player_ptr, eg_ptr);
+    const auto footing_items_description = sweep_footing_items(player_ptr, ge_ptr);
     if (within_char_util(footing_items_description)) {
         return (char)footing_items_description;
     }
 
-    eg_ptr->feat = eg_ptr->g_ptr->get_feat_mimic();
-    if (!eg_ptr->g_ptr->is_mark() && !player_can_see_bold(player_ptr, y, x)) {
-        eg_ptr->feat = feat_none;
+    ge_ptr->feat = ge_ptr->g_ptr->get_feat_mimic();
+    if (!ge_ptr->g_ptr->is_mark() && !player_can_see_bold(player_ptr, y, x)) {
+        ge_ptr->feat = feat_none;
     }
 
-    eg_ptr->f_ptr = &terrains_info[eg_ptr->feat];
-    if (!eg_ptr->boring && eg_ptr->f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
-        return (eg_ptr->query != '\r') && (eg_ptr->query != '\n') ? eg_ptr->query : 0;
+    ge_ptr->terrain_ptr = &TerrainList::get_instance()[ge_ptr->feat];
+    if (!ge_ptr->boring && ge_ptr->terrain_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
+        return (ge_ptr->query != '\r') && (ge_ptr->query != '\n') ? ge_ptr->query : 0;
     }
 
     /*
      * グローバル変数への代入をここで行っているので動かしたくない
      * 安全を確保できたら構造体から外すことも検討する
      */
-    eg_ptr->name = decide_target_floor(player_ptr, eg_ptr);
-    if (*eg_ptr->s2 && (eg_ptr->f_ptr->flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY }) || eg_ptr->f_ptr->flags.has_none_of({ TerrainCharacteristics::LOS, TerrainCharacteristics::TREE }) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::TOWN))) {
-        eg_ptr->s2 = _("の中", "in ");
+    ge_ptr->name = decide_target_floor(player_ptr, ge_ptr);
+    auto is_in = ge_ptr->terrain_ptr->flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY });
+    is_in |= ge_ptr->terrain_ptr->flags.has_none_of({ TerrainCharacteristics::LOS, TerrainCharacteristics::TREE });
+    is_in |= ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::TOWN);
+    if (*ge_ptr->s2 && is_in) {
+        ge_ptr->s2 = _("の中", "in ");
     }
 
-    if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::STORE) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER) || (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::BLDG) && !player_ptr->current_floor_ptr->inside_arena) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::ENTRANCE)) {
-        eg_ptr->s2 = _("の入口", "");
+    auto is_entrance = ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::STORE);
+    is_entrance |= ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER);
+    is_entrance |= ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::BLDG) && !player_ptr->current_floor_ptr->inside_arena;
+    is_entrance |= ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::ENTRANCE);
+    if (is_entrance) {
+        ge_ptr->s2 = _("の入口", "");
     }
 #ifdef JP
 #else
-    else if (eg_ptr->f_ptr->flags.has(TerrainCharacteristics::FLOOR) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::TOWN) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::SHALLOW) || eg_ptr->f_ptr->flags.has(TerrainCharacteristics::DEEP)) {
-        eg_ptr->s3 = "";
-    } else {
-        eg_ptr->s3 = (is_a_vowel(eg_ptr->name[0])) ? "an " : "a ";
+    else {
+        auto is_normal_terrain = ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::FLOOR);
+        is_normal_terrain |= ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::TOWN);
+        is_normal_terrain |= ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::SHALLOW);
+        is_normal_terrain |= ge_ptr->terrain_ptr->flags.has(TerrainCharacteristics::DEEP);
+        if (is_normal_terrain) {
+            ge_ptr->s3 = "";
+        } else {
+            ge_ptr->s3 = (is_a_vowel(ge_ptr->name[0])) ? "an " : "a ";
+        }
     }
 #endif
 
-    describe_grid_monster_all(eg_ptr);
-    prt(eg_ptr->out_val, 0, 0);
+    describe_grid_monster_all(ge_ptr);
+    prt(ge_ptr->out_val, 0, 0);
     move_cursor_relative(y, x);
-    eg_ptr->query = inkey();
-    if ((eg_ptr->query != '\r') && (eg_ptr->query != '\n')) {
-        return eg_ptr->query;
+    ge_ptr->query = inkey();
+    if ((ge_ptr->query != '\r') && (ge_ptr->query != '\n')) {
+        return ge_ptr->query;
     }
 
     return 0;
index ceaecd4..4043fc1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 91c95a2..fd3e1c3 100644 (file)
@@ -1,4 +1,4 @@
-#include "target/target-getter.h"
+#include "target/target-getter.h"
 #include "core/asking-player.h"
 #include "effect/spells-effect-util.h"
 #include "floor/geometry.h"
@@ -20,6 +20,7 @@
 #include "timed-effect/player-confusion.h"
 #include "timed-effect/timed-effects.h"
 #include "view/display-messages.h"
+#include <string>
 
 /*
  * Get an "aiming direction" from the user.
  *
  * Note that confusion over-rides any (explicit?) user choice.
  */
-bool get_aim_dir(PlayerType *player_ptr, DIRECTION *dp)
+bool get_aim_dir(PlayerType *player_ptr, int *dp)
 {
-    DIRECTION dir = command_dir;
+    auto dir = command_dir;
     if (use_old_target && target_okay(player_ptr)) {
         dir = 5;
     }
 
-    COMMAND_CODE code;
+    short code;
     if (repeat_pull(&code)) {
         if (!(code == 5 && !target_okay(player_ptr))) {
-            dir = (DIRECTION)code;
+            dir = code;
         }
     }
 
-    *dp = (DIRECTION)code;
-    char command;
-    while (!dir) {
-        concptr p;
+    *dp = code;
+    while (dir == 0) {
+        std::string prompt;
         if (!target_okay(player_ptr)) {
-            p = _("方向 ('*'でターゲット選択, ESCで中断)? ", "Direction ('*' to choose a target, Escape to cancel)? ");
+            prompt = _("方向 ('*'でターゲット選択, ESCで中断)? ", "Direction ('*' to choose a target, Escape to cancel)? ");
         } else {
-            p = _("方向 ('5'でターゲットへ, '*'でターゲット再選択, ESCで中断)? ", "Direction ('5' for target, '*' to re-target, Escape to cancel)? ");
+            prompt = _("方向 ('5'でターゲットへ, '*'でターゲット再選択, ESCで中断)? ", "Direction ('5' for target, '*' to re-target, Escape to cancel)? ");
         }
 
-        if (!get_com(p, &command, true)) {
+        const auto command_opt = input_command(prompt, true);
+        if (!command_opt) {
             break;
         }
 
+        auto command = *command_opt;
         if (use_menu && (command == '\r')) {
             command = 't';
         }
@@ -89,12 +91,12 @@ bool get_aim_dir(PlayerType *player_ptr, DIRECTION *dp)
             dir = 0;
         }
 
-        if (!dir) {
+        if (dir == 0) {
             bell();
         }
     }
 
-    if (!dir) {
+    if (dir == 0) {
         project_length = 0;
         return false;
     }
@@ -113,61 +115,32 @@ bool get_aim_dir(PlayerType *player_ptr, DIRECTION *dp)
     return true;
 }
 
-bool get_direction(PlayerType *player_ptr, DIRECTION *dp, bool allow_under, bool with_steed)
+bool get_direction(PlayerType *player_ptr, int *dp)
 {
-    DIRECTION dir = command_dir;
-    COMMAND_CODE code;
+    auto dir = command_dir;
+    short code;
     if (repeat_pull(&code)) {
-        dir = (DIRECTION)code;
+        dir = code;
     }
 
-    *dp = (DIRECTION)code;
-    concptr prompt = allow_under ? _("方向 ('.'足元, ESCで中断)? ", "Direction ('.' at feet, Escape to cancel)? ")
-                                 : _("方向 (ESCで中断)? ", "Direction (Escape to cancel)? ");
-
-    while (!dir) {
-        char ch;
-        if (!get_com(prompt, &ch, true)) {
-            break;
-        }
-
-        if ((allow_under) && ((ch == '5') || (ch == '-') || (ch == '.'))) {
-            dir = 5;
-            continue;
+    *dp = code;
+    constexpr auto prompt = _("方向 (ESCで中断)? ", "Direction (Escape to cancel)? ");
+    while (dir == 0) {
+        const auto command = input_command(prompt, true);
+        if (!command) {
+            return false;
         }
 
-        dir = get_keymap_dir(ch);
-        if (!dir) {
+        dir = get_keymap_dir(*command);
+        if (dir == 0) {
             bell();
         }
     }
 
-    if ((dir == 5) && (!allow_under)) {
-        dir = 0;
-    }
-
-    if (!dir) {
-        return false;
-    }
-
     command_dir = dir;
     auto is_confused = player_ptr->effects()->confusion()->is_confused();
-    if (is_confused) {
-        if (randint0(100) < 75) {
-            dir = ddd[randint0(8)];
-        }
-    } else if (player_ptr->riding && with_steed) {
-        auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
-        if (m_ptr->is_confused()) {
-            if (randint0(100) < 75) {
-                dir = ddd[randint0(8)];
-            }
-        } else if (r_ptr->behavior_flags.has(MonsterBehaviorType::RAND_MOVE_50) && r_ptr->behavior_flags.has(MonsterBehaviorType::RAND_MOVE_25) && (randint0(100) < 50)) {
-            dir = ddd[randint0(8)];
-        } else if (r_ptr->behavior_flags.has(MonsterBehaviorType::RAND_MOVE_50) && (randint0(100) < 25)) {
-            dir = ddd[randint0(8)];
-        }
+    if (is_confused && (randint0(100) < 75)) {
+        dir = ddd[randint0(8)];
     }
 
     if (command_dir != dir) {
@@ -185,7 +158,7 @@ bool get_direction(PlayerType *player_ptr, DIRECTION *dp, bool allow_under, bool
     }
 
     *dp = dir;
-    repeat_push((COMMAND_CODE)command_dir);
+    repeat_push(static_cast<short>(command_dir));
     return true;
 }
 
@@ -205,38 +178,35 @@ bool get_direction(PlayerType *player_ptr, DIRECTION *dp, bool allow_under, bool
  * This function tracks and uses the "global direction", and uses
  * that as the "desired direction", to which "confusion" is applied.
  */
-bool get_rep_dir(PlayerType *player_ptr, DIRECTION *dp, bool under)
+bool get_rep_dir(PlayerType *player_ptr, int *dp, bool under)
 {
-    DIRECTION dir = command_dir;
-    COMMAND_CODE code;
+    auto dir = command_dir;
+    short code;
     if (repeat_pull(&code)) {
-        dir = (DIRECTION)code;
+        dir = code;
     }
 
-    *dp = (DIRECTION)code;
-    concptr prompt = under ? _("方向 ('.'足元, ESCで中断)? ", "Direction ('.' at feet, Escape to cancel)? ") : _("方向 (ESCで中断)? ", "Direction (Escape to cancel)? ");
-    while (!dir) {
-        char ch;
-        if (!get_com(prompt, &ch, true)) {
-            break;
+    *dp = code;
+    const auto prompt = under ? _("方向 ('.'足元, ESCで中断)? ", "Direction ('.' at feet, Escape to cancel)? ")
+                              : _("方向 (ESCで中断)? ", "Direction (Escape to cancel)? ");
+    while (dir == 0) {
+        const auto command = input_command(prompt, true);
+        if (!command) {
+            return false;
         }
 
-        if ((under) && ((ch == '5') || (ch == '-') || (ch == '.'))) {
+        if (under && ((command == '5') || (command == '-') || (command == '.'))) {
             dir = 5;
-            continue;
+            break;
         }
 
-        dir = get_keymap_dir(ch);
-        if (!dir) {
+        dir = get_keymap_dir(*command);
+        if (dir == 0) {
             bell();
         }
     }
 
-    if ((dir == 5) && (!under)) {
-        dir = 0;
-    }
-
-    if (!dir) {
+    if ((dir == 5) && !under) {
         return false;
     }
 
@@ -248,7 +218,7 @@ bool get_rep_dir(PlayerType *player_ptr, DIRECTION *dp, bool under)
         }
     } else if (player_ptr->riding) {
         auto *m_ptr = &player_ptr->current_floor_ptr->m_list[player_ptr->riding];
-        auto *r_ptr = &monraces_info[m_ptr->r_idx];
+        auto *r_ptr = &m_ptr->get_monrace();
         if (m_ptr->is_confused()) {
             if (randint0(100) < 75) {
                 dir = ddd[randint0(8)];
@@ -275,6 +245,6 @@ bool get_rep_dir(PlayerType *player_ptr, DIRECTION *dp, bool under)
     }
 
     *dp = dir;
-    repeat_push((COMMAND_CODE)command_dir);
+    repeat_push(static_cast<short>(command_dir));
     return true;
 }
index 0024ca8..63f34bc 100644 (file)
@@ -1,8 +1,6 @@
-#pragma once
-
-#include "system/angband.h"
+#pragma once
 
 class PlayerType;
-bool get_aim_dir(PlayerType *player_ptr, DIRECTION *dp);
-bool get_direction(PlayerType *player_ptr, DIRECTION *dp, bool allow_under, bool with_steed);
-bool get_rep_dir(PlayerType *player_ptr, DIRECTION *dp, bool under);
+bool get_aim_dir(PlayerType *player_ptr, int *dp);
+bool get_direction(PlayerType *player_ptr, int *dp);
+bool get_rep_dir(PlayerType *player_ptr, int *dp, bool under = false);
index e22d506..467c23e 100644 (file)
@@ -1,4 +1,4 @@
-#include "target/target-preparation.h"
+#include "target/target-preparation.h"
 #include "floor/cave.h"
 #include "game-option/input-options.h"
 #include "grid/grid.h"
@@ -8,6 +8,7 @@
 #include "monster/monster-info.h"
 #include "monster/monster-status.h"
 #include "object/object-mark-types.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
@@ -70,14 +71,14 @@ bool target_able(PlayerType *player_ptr, MONSTER_IDX m_idx)
 /*
  * Determine if a given location is "interesting"
  */
-static bool target_set_accept(PlayerType *player_ptr, POSITION y, POSITION x)
+static bool target_set_accept(PlayerType *player_ptr, const Pos2D &pos)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!(in_bounds(floor_ptr, y, x))) {
+    auto &floor = *player_ptr->current_floor_ptr;
+    if (!(in_bounds(&floor, pos.y, pos.x))) {
         return false;
     }
 
-    if (player_bold(player_ptr, y, x)) {
+    if (player_ptr->is_located_at(pos)) {
         return true;
     }
 
@@ -85,34 +86,30 @@ static bool target_set_accept(PlayerType *player_ptr, POSITION y, POSITION x)
         return false;
     }
 
-    grid_type *g_ptr;
-    g_ptr = &floor_ptr->grid_array[y][x];
-    if (g_ptr->m_idx) {
-        auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
-        if (m_ptr->ml) {
+    const auto &grid = floor.get_grid(pos);
+    if (grid.m_idx) {
+        auto &monster = floor.m_list[grid.m_idx];
+        if (monster.ml) {
             return true;
         }
     }
 
-    for (const auto this_o_idx : g_ptr->o_idx_list) {
-        ItemEntity *o_ptr;
-        o_ptr = &floor_ptr->o_list[this_o_idx];
-        if (o_ptr->marked.has(OmType::FOUND)) {
+    for (const auto this_o_idx : grid.o_idx_list) {
+        const auto &item = floor.o_list[this_o_idx];
+        if (item.marked.has(OmType::FOUND)) {
             return true;
         }
     }
 
-    if (g_ptr->is_mark()) {
-        if (g_ptr->is_object()) {
-            return true;
-        }
+    if (!grid.is_mark()) {
+        return false;
+    }
 
-        if (terrains_info[g_ptr->get_feat_mimic()].flags.has(TerrainCharacteristics::NOTICE)) {
-            return true;
-        }
+    if (grid.is_object()) {
+        return true;
     }
 
-    return false;
+    return grid.get_terrain_mimic().flags.has(TerrainCharacteristics::NOTICE);
 }
 
 /*!
@@ -128,10 +125,11 @@ void target_set_prepare(PlayerType *player_ptr, std::vector<POSITION> &ys, std::
 {
     POSITION min_hgt, max_hgt, min_wid, max_wid;
     if (mode & TARGET_KILL) {
-        min_hgt = std::max((player_ptr->y - get_max_range(player_ptr)), 0);
-        max_hgt = std::min((player_ptr->y + get_max_range(player_ptr)), player_ptr->current_floor_ptr->height - 1);
-        min_wid = std::max((player_ptr->x - get_max_range(player_ptr)), 0);
-        max_wid = std::min((player_ptr->x + get_max_range(player_ptr)), player_ptr->current_floor_ptr->width - 1);
+        const auto max_range = AngbandSystem::get_instance().get_max_range();
+        min_hgt = std::max((player_ptr->y - max_range), 0);
+        max_hgt = std::min((player_ptr->y + max_range), player_ptr->current_floor_ptr->height - 1);
+        min_wid = std::max((player_ptr->x - max_range), 0);
+        max_wid = std::min((player_ptr->x + max_range), player_ptr->current_floor_ptr->width - 1);
     } else {
         min_hgt = panel_row_min;
         max_hgt = panel_row_max;
@@ -141,20 +139,21 @@ void target_set_prepare(PlayerType *player_ptr, std::vector<POSITION> &ys, std::
 
     ys.clear();
     xs.clear();
-
-    for (POSITION y = min_hgt; y <= max_hgt; y++) {
-        for (POSITION x = min_wid; x <= max_wid; x++) {
-            if (!target_set_accept(player_ptr, y, x)) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    for (auto y = min_hgt; y <= max_hgt; y++) {
+        for (auto x = min_wid; x <= max_wid; x++) {
+            const Pos2D pos(y, x);
+            if (!target_set_accept(player_ptr, pos)) {
                 continue;
             }
 
-            const auto &g_ref = player_ptr->current_floor_ptr->grid_array[y][x];
-            if ((mode & (TARGET_KILL)) && !target_able(player_ptr, g_ref.m_idx)) {
+            const auto &grid = floor.get_grid(pos);
+            if ((mode & (TARGET_KILL)) && !target_able(player_ptr, grid.m_idx)) {
                 continue;
             }
 
-            const auto &m_ref = player_ptr->current_floor_ptr->m_list[g_ref.m_idx];
-            if ((mode & (TARGET_KILL)) && !target_pet && m_ref.is_pet()) {
+            const auto &monster = floor.m_list[grid.m_idx];
+            if ((mode & (TARGET_KILL)) && !target_pet && monster.is_pet()) {
                 continue;
             }
 
@@ -204,34 +203,91 @@ void target_sensing_monsters_prepare(PlayerType *player_ptr, std::vector<MONSTER
     }
 
     auto comp_importance = [floor_ptr = player_ptr->current_floor_ptr](MONSTER_IDX idx1, MONSTER_IDX idx2) {
-        auto m_ptr1 = &floor_ptr->m_list[idx1];
-        auto m_ptr2 = &floor_ptr->m_list[idx2];
-        auto ap_r_ptr1 = &monraces_info[m_ptr1->ap_r_idx];
-        auto ap_r_ptr2 = &monraces_info[m_ptr2->ap_r_idx];
+        const auto &monster1 = floor_ptr->m_list[idx1];
+        const auto &monster2 = floor_ptr->m_list[idx2];
+        const auto &monrace1 = monraces_info[monster1.ap_r_idx];
+        const auto &monrace2 = monraces_info[monster2.ap_r_idx];
 
         /* Unique monsters first */
-        if (ap_r_ptr1->kind_flags.has(MonsterKindType::UNIQUE) != ap_r_ptr2->kind_flags.has(MonsterKindType::UNIQUE)) {
-            return ap_r_ptr1->kind_flags.has(MonsterKindType::UNIQUE);
+        if (monrace1.kind_flags.has(MonsterKindType::UNIQUE) != monrace2.kind_flags.has(MonsterKindType::UNIQUE)) {
+            return monrace1.kind_flags.has(MonsterKindType::UNIQUE);
         }
 
         /* Shadowers first (あやしい影) */
-        if (m_ptr1->mflag2.has(MonsterConstantFlagType::KAGE) != m_ptr2->mflag2.has(MonsterConstantFlagType::KAGE)) {
-            return m_ptr1->mflag2.has(MonsterConstantFlagType::KAGE);
+        if (monster1.mflag2.has(MonsterConstantFlagType::KAGE) != monster2.mflag2.has(MonsterConstantFlagType::KAGE)) {
+            return monster1.mflag2.has(MonsterConstantFlagType::KAGE);
         }
 
         /* Unknown monsters first */
-        if ((ap_r_ptr1->r_tkills == 0) != (ap_r_ptr2->r_tkills == 0)) {
-            return ap_r_ptr1->r_tkills == 0;
+        if ((monrace1.r_tkills == 0) != (monrace2.r_tkills == 0)) {
+            return monrace1.r_tkills == 0;
         }
 
         /* Higher level monsters first (if known) */
-        if (ap_r_ptr1->r_tkills && ap_r_ptr2->r_tkills && ap_r_ptr1->level != ap_r_ptr2->level) {
-            return ap_r_ptr1->level > ap_r_ptr2->level;
+        if (monrace1.r_tkills && monrace2.r_tkills && monrace1.level != monrace2.level) {
+            return monrace1.level > monrace2.level;
         }
 
         /* Sort by index if all conditions are same */
-        return m_ptr1->ap_r_idx > m_ptr2->ap_r_idx;
+        return monster1.ap_r_idx > monster2.ap_r_idx;
     };
 
     std::sort(monster_list.begin(), monster_list.end(), comp_importance);
 }
+
+/*!
+ * @brief プレイヤーのペットの一覧を得る
+ *
+ * プレイヤーのペットのモンスターIDのリストを取得する。
+ * リストは以下の通り、重要なペットと考えられる順にソートされる。
+ *
+ * - 乗馬している
+ * - 名前をつけている
+ * - ユニークモンスター
+ * - LV順(降順)
+ * - モンスターID順(昇順)
+ *
+ * @return ペットのモンスターIDのリスト
+ */
+std::vector<MONSTER_IDX> target_pets_prepare(PlayerType *player_ptr)
+{
+    std::vector<MONSTER_IDX> pets;
+    const auto &floor = *player_ptr->current_floor_ptr;
+
+    for (short i = 1; i < floor.m_max; ++i) {
+        const auto &monster = floor.m_list[i];
+
+        if (monster.is_valid() && monster.is_pet()) {
+            pets.push_back(i);
+        }
+    }
+
+    auto comp_importance = [riding_idx = player_ptr->riding, &floor](MONSTER_IDX idx1, MONSTER_IDX idx2) {
+        const auto &monster1 = floor.m_list[idx1];
+        const auto &monster2 = floor.m_list[idx2];
+        const auto &ap_monrace1 = monraces_info[monster1.ap_r_idx];
+        const auto &ap_monrace2 = monraces_info[monster2.ap_r_idx];
+
+        if ((riding_idx == idx1) != (riding_idx == idx2)) {
+            return riding_idx == idx1;
+        }
+
+        if (monster1.is_named_pet() != monster2.is_named_pet()) {
+            return monster1.is_named_pet();
+        }
+
+        if (ap_monrace1.kind_flags.has(MonsterKindType::UNIQUE) != ap_monrace2.kind_flags.has(MonsterKindType::UNIQUE)) {
+            return ap_monrace1.kind_flags.has(MonsterKindType::UNIQUE);
+        }
+
+        if (ap_monrace1.r_tkills && ap_monrace2.r_tkills && (ap_monrace1.level != ap_monrace2.level)) {
+            return ap_monrace1.level > ap_monrace2.level;
+        }
+
+        return idx1 < idx2;
+    };
+
+    std::sort(pets.begin(), pets.end(), comp_importance);
+
+    return pets;
+}
index 90f5a7e..1d9c8f0 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <vector>
 
@@ -8,3 +8,4 @@ class PlayerType;
 bool target_able(PlayerType *player_ptr, MONSTER_IDX m_idx);
 void target_set_prepare(PlayerType *player_ptr, std::vector<POSITION> &ys, std::vector<POSITION> &xs, BIT_FLAGS mode);
 void target_sensing_monsters_prepare(PlayerType *player_ptr, std::vector<MONSTER_IDX> &monster_list);
+std::vector<MONSTER_IDX> target_pets_prepare(PlayerType *player_ptr);
index 0e6b7c0..d97c9b4 100644 (file)
@@ -1,6 +1,4 @@
-#include "target/target-setter.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
+#include "target/target-setter.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "floor/geometry.h"
@@ -15,6 +13,7 @@
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "target/projection-path-calculator.h"
 #include "target/target-checker.h"
 #include "target/target-describer.h"
@@ -27,6 +26,7 @@
 #include "util/string-processor.h"
 #include "window/display-sub-windows.h"
 #include "window/main-window-util.h"
+#include <tuple>
 #include <vector>
 
 // "interesting" な座標たちを記録する配列。
@@ -45,7 +45,7 @@ struct ts_type {
     bool flag; // 移動コマンド入力時、"interesting" な座標へ飛ぶかどうか
     char query;
     char info[80];
-    grid_type *g_ptr;
+    Grid *g_ptr;
     TERM_LEN wid, hgt;
     int m; // "interesting" な座標たちのうち現在ターゲットしているもののインデックス
     int distance; // カーソルの移動方向 (1,2,3,4,6,7,8,9)
@@ -60,7 +60,7 @@ static ts_type *initialize_target_set_type(PlayerType *player_ptr, ts_type *ts_p
     ts_ptr->x = player_ptr->x;
     ts_ptr->done = false;
     ts_ptr->flag = true;
-    get_screen_size(&ts_ptr->wid, &ts_ptr->hgt);
+    std::tie(ts_ptr->wid, ts_ptr->hgt) = get_screen_size();
     ts_ptr->m = 0;
     return ts_ptr;
 }
@@ -78,9 +78,9 @@ static ts_type *initialize_target_set_type(PlayerType *player_ptr, ts_type *ts_p
  */
 static bool change_panel_xy(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    POSITION dy = 0, dx = 0;
-    TERM_LEN wid, hgt;
-    get_screen_size(&wid, &hgt);
+    auto dy = 0;
+    auto dx = 0;
+    [[maybe_unused]] const auto &[wid, hgt] = get_screen_size();
     if (y < panel_row_min) {
         dy = -1;
     }
@@ -254,9 +254,10 @@ static void switch_target_input(PlayerType *player_ptr, ts_type *ts_ptr)
         return;
     case 'p': {
         verify_panel(player_ptr);
-        player_ptr->update |= PU_MONSTER_STATUSES;
-        player_ptr->redraw |= PR_MAP;
-        player_ptr->window_flags |= PW_OVERHEAD;
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+        rfu.set_flag(MainWindowRedrawingFlag::MAP);
+        rfu.set_flag(SubWindowRedrawingFlag::OVERHEAD);
         handle_stuff(player_ptr);
         target_set_prepare(player_ptr, ys_interest, xs_interest, ts_ptr->mode);
         ts_ptr->y = player_ptr->y;
@@ -339,6 +340,7 @@ static bool check_panel_changed(PlayerType *player_ptr, ts_type *ts_ptr)
 static void sweep_targets(PlayerType *player_ptr, ts_type *ts_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     while (ts_ptr->flag && (ts_ptr->target_num < 0)) {
         // カーソル移動に伴い、必要なだけ描画範囲を更新。
         // "interesting" 座標リストおよび現在のターゲットも更新。
@@ -351,9 +353,9 @@ static void sweep_targets(PlayerType *player_ptr, ts_type *ts_ptr)
         panel_row_min = ts_ptr->y2;
         panel_col_min = ts_ptr->x2;
         panel_bounds_center();
-        player_ptr->update |= PU_MONSTER_STATUSES;
-        player_ptr->redraw |= PR_MAP;
-        player_ptr->window_flags |= PW_OVERHEAD;
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+        rfu.set_flag(MainWindowRedrawingFlag::MAP);
+        rfu.set_flag(SubWindowRedrawingFlag::OVERHEAD);
         handle_stuff(player_ptr);
         target_set_prepare(player_ptr, ys_interest, xs_interest, ts_ptr->mode);
         ts_ptr->flag = false;
@@ -394,7 +396,7 @@ static bool set_target_grid(PlayerType *player_ptr, ts_type *ts_ptr)
     }
 
     describe_projectablity(player_ptr, ts_ptr);
-    fix_floor_item_list(player_ptr, ts_ptr->y, ts_ptr->x);
+    fix_floor_item_list(player_ptr, { ts_ptr->y, ts_ptr->x });
 
     while (true) {
         ts_ptr->query = examine_grid(player_ptr, ts_ptr->y, ts_ptr->x, ts_ptr->mode, ts_ptr->info);
@@ -427,9 +429,11 @@ static void describe_grid_wizard(PlayerType *player_ptr, ts_type *ts_ptr)
         return;
     }
 
+    constexpr auto fmt = " X:%d Y:%d LOS:%d LOP:%d SPECIAL:%d";
     char cheatinfo[100];
-    strnfmt(cheatinfo, sizeof(cheatinfo), " X:%d Y:%d LOS:%d LOP:%d SPECIAL:%d", ts_ptr->x, ts_ptr->y, los(player_ptr, player_ptr->y, player_ptr->x, ts_ptr->y, ts_ptr->x),
-        projectable(player_ptr, player_ptr->y, player_ptr->x, ts_ptr->y, ts_ptr->x), ts_ptr->g_ptr->special);
+    const auto is_los = los(player_ptr, player_ptr->y, player_ptr->x, ts_ptr->y, ts_ptr->x);
+    const auto is_projectable = projectable(player_ptr, player_ptr->y, player_ptr->x, ts_ptr->y, ts_ptr->x);
+    strnfmt(cheatinfo, sizeof(cheatinfo), fmt, ts_ptr->x, ts_ptr->y, is_los, is_projectable, ts_ptr->g_ptr->special);
     angband_strcat(ts_ptr->info, cheatinfo, sizeof(ts_ptr->info));
 }
 
@@ -449,16 +453,18 @@ static void switch_next_grid_command(PlayerType *player_ptr, ts_type *ts_ptr)
         target_col = ts_ptr->x;
         ts_ptr->done = true;
         break;
-    case 'p':
+    case 'p': {
         verify_panel(player_ptr);
-        player_ptr->update |= PU_MONSTER_STATUSES;
-        player_ptr->redraw |= PR_MAP;
-        player_ptr->window_flags |= PW_OVERHEAD;
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+        rfu.set_flag(MainWindowRedrawingFlag::MAP);
+        rfu.set_flag(SubWindowRedrawingFlag::OVERHEAD);
         handle_stuff(player_ptr);
         target_set_prepare(player_ptr, ys_interest, xs_interest, ts_ptr->mode);
         ts_ptr->y = player_ptr->y;
         ts_ptr->x = player_ptr->x;
         break;
+    }
     case 'o':
         // ターゲット時の「m近」「o現」の切り替え
         // すでに「o現」の時にoを押してもなにも起きない
@@ -526,10 +532,12 @@ static void decide_change_panel(PlayerType *player_ptr, ts_type *ts_ptr)
         dy = 0;
     }
 
-    if ((ts_ptr->y >= panel_row_min + ts_ptr->hgt) || (ts_ptr->y < panel_row_min) || (ts_ptr->x >= panel_col_min + ts_ptr->wid) || (ts_ptr->x < panel_col_min)) {
-        if (change_panel(player_ptr, dy, dx)) {
-            target_set_prepare(player_ptr, ys_interest, xs_interest, ts_ptr->mode);
-        }
+    auto should_change_panel = ts_ptr->y >= panel_row_min + ts_ptr->hgt;
+    should_change_panel |= ts_ptr->y < panel_row_min;
+    should_change_panel |= ts_ptr->x >= panel_col_min + ts_ptr->wid;
+    should_change_panel |= ts_ptr->x < panel_col_min;
+    if (should_change_panel && change_panel(player_ptr, dy, dx)) {
+        target_set_prepare(player_ptr, ys_interest, xs_interest, ts_ptr->mode);
     }
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
@@ -561,10 +569,11 @@ static void sweep_target_grids(PlayerType *player_ptr, ts_type *ts_ptr)
         ts_ptr->g_ptr = &player_ptr->current_floor_ptr->grid_array[ts_ptr->y][ts_ptr->x];
         strcpy(ts_ptr->info, _("q止 t決 p自 m近 +次 -前", "q,t,p,m,+,-,<dir>"));
         describe_grid_wizard(player_ptr, ts_ptr);
-        fix_floor_item_list(player_ptr, ts_ptr->y, ts_ptr->x);
+        fix_floor_item_list(player_ptr, { ts_ptr->y, ts_ptr->x });
 
         /* Describe and Prompt (enable "TARGET_LOOK") */
-        while ((ts_ptr->query = examine_grid(player_ptr, ts_ptr->y, ts_ptr->x, i2enum<target_type>(ts_ptr->mode | TARGET_LOOK), ts_ptr->info)) == 0) {
+        const auto target = i2enum<target_type>(ts_ptr->mode | TARGET_LOOK);
+        while ((ts_ptr->query = examine_grid(player_ptr, ts_ptr->y, ts_ptr->x, target, ts_ptr->info)) == 0) {
             ;
         }
 
@@ -590,9 +599,14 @@ bool target_set(PlayerType *player_ptr, target_type mode)
     sweep_target_grids(player_ptr, ts_ptr);
     prt("", 0, 0);
     verify_panel(player_ptr);
-    set_bits(player_ptr->update, PU_MONSTER_STATUSES);
-    set_bits(player_ptr->redraw, PR_MAP);
-    set_bits(player_ptr->window_flags, PW_OVERHEAD | PW_FLOOR_ITEMS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
+    rfu.set_flag(MainWindowRedrawingFlag::MAP);
+    static constexpr auto flags = {
+        SubWindowRedrawingFlag::OVERHEAD,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+    };
+    rfu.set_flags(flags);
     handle_stuff(player_ptr);
     return target_who != 0;
 }
index f684c32..062c742 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <stdint.h>
 
index 225e2c9..8f53423 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 #include <stdint.h>
 
 /* target_set用関数の利用用途フラグ / Bit flags for the "target_set" function */
index bcb9e74..62197e5 100644 (file)
@@ -1,9 +1,9 @@
-#include "term/gameterm.h"
+#include "term/gameterm.h"
 #include "effect/attribute-types.h"
 #include "system/system-variables.h"
 #include "term/term-color-types.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
+#include <span>
 
 /*
  * Convert an "attr"/"char" pair into a "pict" (P)
@@ -111,7 +111,7 @@ const concptr window_flag_desc[32] = {
     _("呪文一覧", "Display spell list"),
     _("キャラクタ情報", "Display character"),
     _("視界内のモンスター表示", "Display monsters in sight"),
-    nullptr,
+    _("ペット一覧", "Display pets"),
     _("メッセージ", "Display messages"),
     _("ダンジョン全体図", "Display overhead view"),
     _("モンスターの思い出", "Display monster recall"),
@@ -379,40 +379,26 @@ std::map<AttributeType, std::string> gf_colors;
  */
 static TERM_COLOR mh_attr(int max)
 {
-    switch (randint1(max)) {
-    case 1:
-        return TERM_RED;
-    case 2:
-        return TERM_GREEN;
-    case 3:
-        return TERM_BLUE;
-    case 4:
-        return TERM_YELLOW;
-    case 5:
-        return TERM_ORANGE;
-    case 6:
-        return TERM_VIOLET;
-    case 7:
-        return TERM_L_RED;
-    case 8:
-        return TERM_L_GREEN;
-    case 9:
-        return TERM_L_BLUE;
-    case 10:
-        return TERM_UMBER;
-    case 11:
-        return TERM_L_UMBER;
-    case 12:
-        return TERM_SLATE;
-    case 13:
-        return TERM_WHITE;
-    case 14:
-        return TERM_L_WHITE;
-    case 15:
-        return TERM_L_DARK;
-    }
-
-    return TERM_WHITE;
+    constexpr static auto colors = {
+        TERM_RED,
+        TERM_GREEN,
+        TERM_BLUE,
+        TERM_YELLOW,
+        TERM_ORANGE,
+        TERM_VIOLET,
+        TERM_L_RED,
+        TERM_L_GREEN,
+        TERM_L_BLUE,
+        TERM_UMBER,
+        TERM_L_UMBER,
+        TERM_SLATE,
+        TERM_WHITE,
+        TERM_L_WHITE,
+        TERM_L_DARK,
+    };
+
+    std::span<const term_color_type> candidates(colors.begin(), max);
+    return rand_choice(candidates);
 }
 
 /*!
@@ -540,7 +526,7 @@ static TERM_COLOR spell_color(AttributeType type)
         }
 
         /* Pick a random color */
-        auto c = color[randint0(color.size())];
+        auto c = rand_choice(color);
 
         /* Lookup this color */
         a = angband_strchr(color_char, c) - color_char;
index dfa4131..9e013f1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <array>
index 06aeef2..2faa4c8 100644 (file)
@@ -1,4 +1,4 @@
-#include "term/screen-processor.h"
+#include "term/screen-processor.h"
 #include "io/input-key-acceptor.h"
 #include "locale/japanese.h"
 #include "term/term-color-types.h"
@@ -97,7 +97,7 @@ void put_str(std::string_view sv, TERM_LEN row, TERM_LEN col)
  */
 void c_prt(TERM_COLOR attr, std::string_view sv, TERM_LEN row, TERM_LEN col)
 {
-    term_erase(col, row, 255);
+    term_erase(col, row);
     term_addstr(-1, attr, sv);
 }
 
@@ -151,7 +151,7 @@ static std::vector<std::pair<TERM_COLOR, char>> c_roff_wrap(int x, int y, int w,
         }
     }
 
-    term_erase(wrap_col, y, 255);
+    term_erase(wrap_col, y);
     return wrap_chars;
 }
 
@@ -171,13 +171,11 @@ static std::vector<std::pair<TERM_COLOR, char>> c_roff_wrap(int x, int y, int w,
  */
 void c_roff(TERM_COLOR a, std::string_view str)
 {
-    int w, h;
-    (void)term_get_size(&w, &h);
-
+    const auto &[wid, hgt] = term_get_size();
     int x, y;
     (void)term_locate(&x, &y);
 
-    if (y == h - 1 && x > w - 3) {
+    if (y == hgt - 1 && x > wid - 3) {
         return;
     }
 
@@ -185,8 +183,8 @@ void c_roff(TERM_COLOR a, std::string_view str)
         const auto is_kanji = _(iskanji(*s), false);
 
         if (*s == '\n') {
-            if (y + 1 < h) {
-                term_erase(0, y + 1, 255);
+            if (y + 1 < hgt) {
+                term_erase(0, y + 1);
             }
 
             return;
@@ -194,15 +192,15 @@ void c_roff(TERM_COLOR a, std::string_view str)
 
         const auto ch = (is_kanji || isprint(*s)) ? *s : ' ';
 
-        if ((x >= ((is_kanji) ? w - 2 : w - 1)) && (ch != ' ')) {
-            const auto wrap_chars = c_roff_wrap(x, y, w, &*s);
+        if ((x >= ((is_kanji) ? wid - 2 : wid - 1)) && (ch != ' ')) {
+            const auto wrap_chars = c_roff_wrap(x, y, wid, &*s);
 
             y++;
-            if (y == h) {
+            if (y == hgt) {
                 return;
             }
 
-            term_erase(0, y, 255);
+            term_erase(0, y);
             for (const auto &[ca, cv] : wrap_chars) {
                 term_addch(ca, cv);
             }
@@ -216,8 +214,8 @@ void c_roff(TERM_COLOR a, std::string_view str)
             term_addch((a | 0x20), *s);
         }
 
-        if (++x > w) {
-            x = w;
+        if (++x > wid) {
+            x = wid;
         }
     }
 }
@@ -238,6 +236,6 @@ void clear_from(int row)
 {
     for (int y = row; y < game_term->hgt; y++) {
         TermOffsetSetter tos(0, std::nullopt);
-        term_erase(0, y, 255);
+        term_erase(0, y);
     }
 }
index ad1d4dc..542db89 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 9a1d135..66c0e42 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Angband "attributes" (with symbols, and base (R,G,B) codes)
index d37a306..c466481 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file z-form.cpp
  * @brief Low level text formatting
  * @date 2023/04/30
index faae436..9b2854c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*!
  * @file z-form.h
index ed8a73a..d85512c 100644 (file)
@@ -1,4 +1,4 @@
-/* File: z-rand.c */
+/* File: z-rand.c */
 
 /*
  * Copyright (c) 1997 Ben Harrison, and others
@@ -158,12 +158,12 @@ int32_t Rand_external(int32_t m)
 
     static std::optional<Xoshiro128StarStar> urbg_external;
 
-    if (!urbg_external.has_value()) {
+    if (!urbg_external) {
         /* Initialize with new seed */
         auto seed = static_cast<uint32_t>(time(nullptr));
         urbg_external = Xoshiro128StarStar(seed);
     }
 
     std::uniform_int_distribution<> d(0, m - 1);
-    return d(urbg_external.value());
+    return d(*urbg_external);
 }
index 37056a1..62d6d3b 100644 (file)
@@ -1,4 +1,4 @@
-/* File: z-rand.h */
+/* File: z-rand.h */
 
 /*
  * Copyright (c) 1997 Ben Harrison, and others
@@ -11,6 +11,7 @@
 #pragma once
 
 #include "system/h-basic.h"
+#include <initializer_list>
 #include <iterator>
 #include <type_traits>
 #include <utility>
@@ -108,3 +109,39 @@ void rand_shuffle(Iter first, Iter last)
         }
     }
 }
+
+/*!
+ * @brief 与えられた範囲から等確率で要素を1つ選ぶ
+ *
+ * @tparam T 範囲の型
+ * @param range 要素を選ぶ範囲
+ * @return 選んだ要素
+ *
+ * @todo MacOSでApple ClangのC++20 Ranges Libraryのサポートが浸透したら
+ * requires std::ranges::borrowed_range<T> && std::ranges::sized_range<T>
+ * をコンセプトに指定する
+ */
+template <typename T>
+decltype(auto) rand_choice(T &&range)
+{
+    using std::begin;
+    using std::size;
+    const auto index = randint0(size(range));
+
+    return *(std::next(begin(range), index));
+}
+
+/*!
+ * @brief 与えられたリストから等確率で要素を1つ選ぶ
+ *
+ * @tparam T リストの要素の型
+ * @param list 要素を選ぶリスト
+ * @return 選んだ要素
+ */
+template <typename T>
+T rand_choice(std::initializer_list<T> list)
+{
+    const auto index = randint0(list.size());
+
+    return *(list.begin() + index);
+}
index 7a0639c..c36c021 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*
  * @brief Purpose: a generic, efficient, terminal window package -BEN-
  * Copyright (c) 1997 Ben Harrison
  *
@@ -54,11 +54,11 @@ TermOffsetSetter::TermOffsetSetter(std::optional<TERM_LEN> x, std::optional<TERM
         return;
     }
 
-    if (x.has_value()) {
-        this->term->offset_x = (x.value() > 0) ? x.value() : 0;
+    if (x) {
+        this->term->offset_x = (*x > 0) ? *x : 0;
     }
-    if (y.has_value()) {
-        this->term->offset_y = (y.value() > 0) ? y.value() : 0;
+    if (y) {
+        this->term->offset_y = (*y > 0) ? *y : 0;
     }
 }
 
@@ -88,8 +88,12 @@ TermCenteredOffsetSetter::TermCenteredOffsetSetter(std::optional<TERM_LEN> width
     , orig_centered_wid(game_term != nullptr ? game_term->centered_wid : std::nullopt)
     , orig_centered_hgt(game_term != nullptr ? game_term->centered_hgt : std::nullopt)
 {
-    const auto offset_x = width.has_value() ? (game_term->wid - width.value()) / 2 : 0;
-    const auto offset_y = height.has_value() ? (game_term->hgt - height.value()) / 2 : 0;
+    if (game_term == nullptr) {
+        return;
+    }
+
+    const auto offset_x = width ? (game_term->wid - *width) / 2 : 0;
+    const auto offset_y = height ? (game_term->hgt - *height) / 2 : 0;
     this->tos.emplace(offset_x, offset_y);
 
     game_term->centered_wid = (width < game_term->wid) ? width : std::nullopt;
@@ -582,9 +586,7 @@ static void term_queue_chars(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, std::s
      * (条件追加:タイルの1文字目でない事を確かめるように。)
      */
     {
-        int w, h;
-        term_get_size(&w, &h);
-        if (x != w && !(scr_aa[x] & AF_TILE1) && (scr_aa[x] & AF_KANJI2)) {
+        if ((x < game_term->wid) && !(scr_aa[x] & AF_TILE1) && (scr_aa[x] & AF_KANJI2)) {
             scr_cc[x] = ' ';
             scr_aa[x] &= AF_KANJIC;
             if (x1 < 0) {
@@ -1602,7 +1604,7 @@ errr term_putstr(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, std::string_view s
 /*
  * Place cursor at (x,y), and clear the next "n" chars
  */
-errr term_erase(TERM_LEN x, TERM_LEN y, int n)
+errr term_erase(TERM_LEN x, TERM_LEN y, std::optional<int> n_opt)
 {
     TERM_LEN w = game_term->wid;
     /* int h = Term->hgt; */
@@ -1621,6 +1623,8 @@ errr term_erase(TERM_LEN x, TERM_LEN y, int n)
     x = game_term->scr->cx;
     y = game_term->scr->cy;
 
+    auto n = n_opt.value_or(w);
+
     /* Force legal size */
     if (x + n > w) {
         n = w - x;
@@ -1852,11 +1856,9 @@ errr term_get_cursor(int *v)
 /*
  * Extract the current window size
  */
-errr term_get_size(TERM_LEN *w, TERM_LEN *h)
+std::pair<int, int> term_get_size()
 {
-    (*w) = game_term->centered_wid.value_or(game_term->wid);
-    (*h) = game_term->centered_hgt.value_or(game_term->hgt);
-    return 0;
+    return { game_term->centered_wid.value_or(game_term->wid), game_term->centered_hgt.value_or(game_term->hgt) };
 }
 
 /*
index 1325e93..433aca9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Copyright (c) 1997 Ben Harrison
@@ -14,6 +14,7 @@
 #include <optional>
 #include <stack>
 #include <string_view>
+#include <utility>
 #include <vector>
 
 /*!
@@ -190,7 +191,6 @@ private:
 /**** Available Variables ****/
 extern term_type *game_term;
 
-errr term_win_nuke(term_win *s, TERM_LEN w, TERM_LEN h);
 errr term_user(int n);
 errr term_xtra(int n, int v);
 
@@ -208,13 +208,13 @@ errr term_add_bigch(TERM_COLOR a, char c);
 errr term_addstr(int n, TERM_COLOR a, std::string_view sv);
 errr term_putch(TERM_LEN x, TERM_LEN y, TERM_COLOR a, char c);
 errr term_putstr(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, std::string_view sv);
-errr term_erase(TERM_LEN x, TERM_LEN y, int n);
+errr term_erase(TERM_LEN x, TERM_LEN y, std::optional<int> n_opt = std::nullopt);
 errr term_clear(void);
 errr term_redraw(void);
 errr term_redraw_section(TERM_LEN x1, TERM_LEN y1, TERM_LEN x2, TERM_LEN y2);
 
 errr term_get_cursor(int *v);
-errr term_get_size(TERM_LEN *w, TERM_LEN *h);
+std::pair<int, int> term_get_size();
 errr term_locate(TERM_LEN *x, TERM_LEN *y);
 errr term_what(TERM_LEN x, TERM_LEN y, TERM_COLOR *a, char *c);
 
index a483632..be8481e 100644 (file)
@@ -1,4 +1,4 @@
-/* File: z-util.c */
+/* File: z-util.c */
 
 /*
  * Copyright (c) 1997 Ben Harrison
@@ -110,27 +110,30 @@ void quit(concptr str)
 void (*core_aux)(concptr) = nullptr;
 
 /*
- * Dump a core file, after printing a warning message
- * As with "quit()", try to use the "core_aux()" hook first.
+ * @brief 意図的にクラッシュさせ、コアファイルをダンプする
+ * @param str エラーメッセージ
+ * @details MSVC以外のコンパイラはpragma warning をコンパイルエラーにする.
+ * 汚いがプリプロで分岐する.
  */
 void core(concptr str)
 {
     char *crash = nullptr;
-
-    /* Use the aux function */
     if (core_aux) {
         (*core_aux)(str);
     }
 
-    /* Dump the warning string */
     if (str) {
         plog(str);
     }
 
-    /* Attempt to Crash */
-    (*crash) = (*crash);
-
-    /* Be sure we exited */
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 6011)
+#endif
+    *crash = *crash;
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
     quit("core() failed");
 }
 
index 81fa0e3..35b1da7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Copyright (c) 1997 Ben Harrison
index 0b6cbf4..00d12a9 100644 (file)
@@ -1,4 +1,4 @@
-/* File: z-virt.c */
+/* File: z-virt.c */
 
 /*
  * Copyright (c) 1997 Ben Harrison
index a2a2a19..fdd09ee 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 /*
  * Copyright (c) 1997 Ben Harrison
diff --git a/src/test/test-sha256.cpp b/src/test/test-sha256.cpp
new file mode 100644 (file)
index 0000000..513f08f
--- /dev/null
@@ -0,0 +1,111 @@
+/*!
+ * @brief sha256ハッシュ値計算クラスのテストプログラム
+ *
+ * srcディレクトリで以下のコマンドでコンパイルして実行する
+ *
+ * g++ -std=c++20 -I. term/z-util.cpp term/z-form.cpp system/angband-version.cpp util/sha256.cpp test/test-sha256.cpp
+ *
+ * 引数を指定した場合は、そのファイルのハッシュ値を計算する
+ * 引数がない場合は、RFC 6234のテストドライバより抜粋したSHA-256のテストパターンのハッシュ値を計算して比較する
+ */
+
+#include "util/sha256.h"
+
+#include <cassert>
+#include <iostream>
+#include <span>
+#include <string_view>
+
+/*
+ * RFC 6234 で定義されているテストパターン
+ */
+#define TEST1 "abc"
+#define TEST2_1 \
+    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+#define TEST2_2a \
+    "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+#define TEST2_2b \
+    "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+#define TEST2_2 TEST2_2a TEST2_2b
+#define TEST3 "a" /* times 1000000 */
+#define TEST4a "01234567012345670123456701234567"
+#define TEST4b "01234567012345670123456701234567"
+/* an exact multiple of 512 bits */
+#define TEST4 TEST4a TEST4b /* times 10 */
+
+#define TEST7_256 \
+    "\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73"
+#define TEST8_256 \
+    "\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3\x88\x7a\xb2\xcd\x68\x46\x52"
+#define TEST9_256                                                      \
+    "\x3e\x74\x03\x71\xc8\x10\xc2\xb9\x9f\xc0\x4e\x80\x49\x07\xef\x7c" \
+    "\xf2\x6b\xe2\x8b\x57\xcb\x58\xa3\xe2\xf3\xc0\x07\x16\x6e\x49\xc1" \
+    "\x2e\x9b\xa3\x4c\x01\x04\x06\x91\x29\xea\x76\x15\x64\x25\x45\x70" \
+    "\x3a\x2b\xd9\x01\xe1\x6e\xb0\xe0\x5d\xeb\xa0\x14\xeb\xff\x64\x06" \
+    "\xa0\x7d\x54\x36\x4e\xff\x74\x2d\xa7\x79\xb0\xb3"
+#define TEST10_256                                                     \
+    "\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1\x2b\x20\x52\x7a\xfe\xf0" \
+    "\x4d\x8a\x05\x69\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76\x00\x00" \
+    "\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08\x3a\xa3\x9d\x81\x0d\xb3\x10\x77" \
+    "\x7d\xab\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32\x5f\x8b\x23\x74" \
+    "\xde\x7a\x4b\x5a\x58\xcb\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b" \
+    "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65\x92\xec\xed\xaa\x66\xca" \
+    "\x82\xa2\x9d\x0c\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4\xc0\xa4" \
+    "\x3f\x8d\x79\xa3\x0a\x16\x5c\xba\xbe\x45\x2b\x77\x4b\x9c\x71\x09" \
+    "\xa9\x7d\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc\x10\x6a\xad\x5a" \
+    "\x9f\xdd\x30\x82\x57\x69\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39" \
+    "\x3d\x54\xd6"
+
+template <size_t N>
+constexpr auto length(const char (&)[N])
+{
+    return N - 1;
+}
+
+struct {
+    const char *test_pattern; ///< テストパターン
+    size_t length; ///< テストパターンのバイト長
+    long repeat_count; ///< テストパターンの繰り返し回数
+    std::byte extra_bits; ///< 追加ビット
+    int num_of_extra_bits; ///< 追加ビットのビット数
+    std::string expected; ///< 期待されるハッシュ値
+} tests[] = {
+    { TEST1, length(TEST1), 1, std::byte(0), 0, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" },
+    { TEST2_1, length(TEST2_1), 1, std::byte(0), 0, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" },
+    { TEST3, length(TEST3), 1000000, std::byte(0), 0, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" },
+    { TEST4, length(TEST4), 10, std::byte(0), 0, "594847328451bdfa85056225462cc1d867d877fb388df0ce35f25ab5562bfbb5" },
+    { "", 0, 0, std::byte(0x68), 5, "d6d3e02a31a84a8caa9718ed6c2057be09db45e7823eb5079ce7a573a3760f95" },
+    { "\x19", 1, 1, std::byte(0), 0, "68aa2e2ee5dff96e3355e6c7ee373e3d6a4e17f75f9518d843709c0c9bc3e3d4" },
+    { TEST7_256, length(TEST7_256), 1, std::byte(0x60), 3, "77ec1dc89c821ff2a1279089fa091b35b8cd960bcaf7de01c6a7680756beb972" },
+    { TEST8_256, length(TEST8_256), 1, std::byte(0), 0, "175ee69b02ba9b58e2b0a5fd13819cea573f3940a94f825128cf4209beabb4e8" },
+    { TEST9_256, length(TEST9_256), 1, std::byte(0xA0), 3, "3e9ad6468bbbad2ac3c2cdc292e018ba5fd70b960cf1679777fce708fdb066e9" },
+    { TEST10_256, length(TEST10_256), 1, std::byte(0), 0, "97dbca7df46d62c8a422c941dd7e835b8ad3361763f7e9b2d95f4f0da6e1ccbc" },
+};
+
+int main(int argc, char *argv[])
+{
+    if (argc > 1) {
+        for (auto arg : std::span(argv, argc).subspan(1)) {
+            auto hash = util::SHA256::compute_filehash(arg);
+            if (!hash) {
+                std::cout << "cannot open file: " << arg << std::endl;
+                continue;
+            }
+
+            std::cout << util::to_string(*hash) << "  " << arg << std::endl;
+        }
+        return 0;
+    }
+
+    util::SHA256 hash;
+    for (const auto &test : tests) {
+        hash.reset();
+        auto test_array = std::as_bytes(std::span(test.test_pattern, test.length));
+        for (auto i = 0; i < test.repeat_count; ++i) {
+            hash.update(test_array.data(), test_array.size());
+        }
+        hash.final_bits(test.extra_bits, test.num_of_extra_bits);
+
+        assert(util::to_string(hash.digest()) == test.expected);
+    }
+}
index 4897f7d..768630f 100644 (file)
@@ -1,11 +1,11 @@
-/*!
+/*!
  * @brief プレイヤーの一時加速ステータス変更と判定
  * @date 2022/08/15
  * @author Hourier
  */
 
 #include "timed-effect/player-acceleration.h"
-#include <stdexcept>
+#include "system/angband-exceptions.h"
 
 short PlayerAcceleration::current() const
 {
@@ -20,7 +20,7 @@ bool PlayerAcceleration::is_fast() const
 void PlayerAcceleration::set(short value)
 {
     if (value < 0) {
-        throw std::invalid_argument("Negative value can't be set in the player's acceleration parameter!");
+        THROW_EXCEPTION(std::invalid_argument, "Negative value can't be set in the player's acceleration parameter!");
     }
 
     this->acceleration = value;
index 43d0d63..16a6ce5 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerAcceleration {
 public:
index 9c22a18..e12c9cc 100644 (file)
@@ -1,11 +1,11 @@
-/*!
+/*!
  * @brief プレイヤーの盲目ステータス変更と判定
  * @date 2022/08/30
  * @author Hourier
  */
 
 #include "timed-effect/player-blindness.h"
-#include <stdexcept>
+#include "system/angband-exceptions.h"
 
 short PlayerBlindness::current() const
 {
@@ -20,7 +20,7 @@ bool PlayerBlindness::is_blind() const
 void PlayerBlindness::set(short value)
 {
     if (value < 0) {
-        throw std::invalid_argument("Negative value can't be set in the player's blindness parameter!");
+        THROW_EXCEPTION(std::invalid_argument, "Negative value can't be set in the player's blindness parameter!");
     }
 
     this->blindness = value;
index 877ba2b..4e3e78c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerBlindness {
 public:
index f1e4df2..74ca098 100644 (file)
@@ -1,4 +1,4 @@
-#include "timed-effect/player-confusion.h"
+#include "timed-effect/player-confusion.h"
 
 short PlayerConfusion::current() const
 {
index c4512ea..43def76 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerConfusion {
 public:
index 9e7eed7..42240b3 100644 (file)
@@ -1,4 +1,5 @@
-#include "timed-effect/player-cut.h"
+#include "timed-effect/player-cut.h"
+#include "system/angband-exceptions.h"
 #include "system/angband.h"
 
 PlayerCutRank PlayerCut::get_rank(short value)
@@ -34,7 +35,7 @@ PlayerCutRank PlayerCut::get_rank(short value)
     return PlayerCutRank::NONE;
 }
 
-std::string_view PlayerCut::get_cut_mes(PlayerCutRank stun_rank)
+std::string PlayerCut::get_cut_mes(PlayerCutRank stun_rank)
 {
     switch (stun_rank) {
     case PlayerCutRank::NONE:
@@ -54,7 +55,7 @@ std::string_view PlayerCut::get_cut_mes(PlayerCutRank stun_rank)
     case PlayerCutRank::MORTAL:
         return _("致命的な傷を負ってしまった。", "You have been given a mortal wound.");
     default:
-        throw("Invalid StunRank was specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid CutRank is specified!");
     }
 }
 
@@ -102,7 +103,7 @@ bool PlayerCut::is_cut() const
     return this->cut > 0;
 }
 
-std::tuple<term_color_type, std::string_view> PlayerCut::get_expr() const
+std::tuple<term_color_type, std::string> PlayerCut::get_expr() const
 {
     switch (this->get_rank()) {
     case PlayerCutRank::NONE: // dummy.
@@ -122,7 +123,7 @@ std::tuple<term_color_type, std::string_view> PlayerCut::get_expr() const
     case PlayerCutRank::MORTAL:
         return std::make_tuple(TERM_L_RED, _("致命傷      ", "Mortal wound"));
     default:
-        throw("Invalid StunRank was specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid CutRank is specified!");
     }
 }
 
@@ -146,7 +147,7 @@ int PlayerCut::get_damage() const
     case PlayerCutRank::MORTAL:
         return 200;
     default:
-        throw("Invalid StunRank was specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid CutRank is specified!");
     }
 }
 
index 7db7810..953a49d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "term/term-color-types.h"
 #include <string>
@@ -21,13 +21,13 @@ public:
     virtual ~PlayerCut() = default;
 
     static PlayerCutRank get_rank(short value);
-    static std::string_view get_cut_mes(PlayerCutRank stun_rank);
+    static std::string get_cut_mes(PlayerCutRank stun_rank);
     static short get_accumulation(int total, int damage);
 
     short current() const;
     PlayerCutRank get_rank() const;
     bool is_cut() const;
-    std::tuple<term_color_type, std::string_view> get_expr() const;
+    std::tuple<term_color_type, std::string> get_expr() const;
     int get_damage() const;
     void set(short value);
     void reset();
index f9f83af..1986510 100644 (file)
@@ -1,11 +1,11 @@
-/*!
+/*!
  * @brief プレイヤーの一時減速ステータス変更と判定
  * @date 2022/08/05
  * @author Hourier
  */
 
 #include "timed-effect/player-deceleration.h"
-#include <stdexcept>
+#include "system/angband-exceptions.h"
 
 short PlayerDeceleration::current() const
 {
@@ -20,7 +20,7 @@ bool PlayerDeceleration::is_slow() const
 void PlayerDeceleration::set(short value)
 {
     if (value < 0) {
-        throw std::invalid_argument("Negative value can't be set in the player's deceleration parameter!");
+        THROW_EXCEPTION(std::invalid_argument, "Negative value can't be set in the player's deceleration parameter!");
     }
 
     this->deceleration = value;
index 80b17e5..c77fc39 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerDeceleration {
 public:
index d12d482..6055e9b 100644 (file)
@@ -1,4 +1,4 @@
-#include "timed-effect/player-fear.h"
+#include "timed-effect/player-fear.h"
 
 short PlayerFear::current() const
 {
index 7ec63dc..76547b7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerFear {
 public:
index 24a778a..1e29df1 100644 (file)
@@ -1,4 +1,4 @@
-#include "timed-effect/player-hallucination.h"
+#include "timed-effect/player-hallucination.h"
 
 short PlayerHallucination::current() const
 {
index 70a44ec..3f89ef9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerHallucination {
 public:
index 5eb18c2..31121d6 100644 (file)
@@ -1,4 +1,4 @@
-#include "timed-effect/player-paralysis.h"
+#include "timed-effect/player-paralysis.h"
 
 short PlayerParalysis::current() const
 {
index bb944d2..534c388 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerParalysis {
 public:
index f883e6a..8172975 100644 (file)
@@ -1,11 +1,11 @@
-/*!
+/*!
  * @brief プレイヤーの一時減速ステータス変更と判定
  * @date 2022/08/16
  * @author Hourier
  */
 
 #include "timed-effect/player-poison.h"
-#include <stdexcept>
+#include "system/angband-exceptions.h"
 
 short PlayerPoison::current() const
 {
@@ -20,7 +20,7 @@ bool PlayerPoison::is_poisoned() const
 void PlayerPoison::set(short value)
 {
     if (value < 0) {
-        throw std::invalid_argument("Negative value can't be set in the player's poison parameter!");
+        THROW_EXCEPTION(std::invalid_argument, "Negative value can't be set in the player's poison parameter!");
     }
 
     this->poison = value;
index 6941bd6..b3d13f8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerPoison {
 public:
index 7e15666..5118609 100644 (file)
@@ -1,4 +1,5 @@
-#include "timed-effect/player-stun.h"
+#include "timed-effect/player-stun.h"
+#include "system/angband-exceptions.h"
 #include "system/angband.h"
 
 enum class PlayerStunRank {
@@ -51,7 +52,7 @@ std::string_view PlayerStun::get_stun_mes(PlayerStunRank stun_rank)
     case PlayerStunRank::KNOCKED:
         return _("あなたはぶっ倒れた!", "You are knocked out!!");
     default:
-        throw("Invalid StunRank was specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid StunRank is specified!");
     }
 }
 
@@ -161,7 +162,7 @@ int PlayerStun::get_magic_chance_penalty() const
     case PlayerStunRank::KNOCKED:
         return 100;
     default:
-        throw("Invalid stun rank is specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid StunRank is specified!");
     }
 }
 
@@ -186,7 +187,7 @@ int PlayerStun::get_item_chance_penalty() const
     case PlayerStunRank::KNOCKED:
         return 100;
     default:
-        throw("Invalid stun rank is specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid StunRank is specified!");
     }
 }
 
@@ -214,7 +215,7 @@ short PlayerStun::get_damage_penalty() const
     case PlayerStunRank::KNOCKED:
         return 100;
     default:
-        throw("Invalid stun rank is specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid StunRank is specified!");
     }
 }
 
@@ -252,7 +253,7 @@ std::tuple<term_color_type, std::string_view> PlayerStun::get_expr() const
     case PlayerStunRank::KNOCKED:
         return std::make_tuple(TERM_VIOLET, _("昏倒        ", "Knocked out "));
     default:
-        throw("Invalid stun rank is specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid StunRank is specified!");
     }
 }
 
index ecba967..755ad5e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "term/term-color-types.h"
 #include <string>
index 34f4a9c..5eb4a09 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーの時限効果を表すオブジェクト群を保持する
  * @date 2022/08/05
  * @author Hourier
index faa883f..c175d14 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <memory>
 
index 2fc2291..170f19a 100644 (file)
@@ -1,9 +1,12 @@
-#include "util/angband-files.h"
+#include "util/angband-files.h"
 #include "locale/japanese.h"
+#include "system/angband-exceptions.h"
 #include "util/string-processor.h"
 #include <sstream>
 #include <string>
 
+void (*file_open_hook)(const std::filesystem::path &path, const FileOpenType ftype) = 0;
+
 #ifdef SET_UID
 
 #ifndef HAVE_USLEEP
@@ -69,7 +72,7 @@ void user_name(char *buf, int id)
 
 #endif /* SET_UID */
 
-std::filesystem::path path_parse(std::string_view file)
+std::filesystem::path path_parse(const std::filesystem::path &path)
 #ifdef SET_UID
 {
     /*
@@ -79,6 +82,7 @@ std::filesystem::path path_parse(std::string_view file)
      * Replace "~user/" by the home directory of the user named "user"
      * Replace "~/" by the home directory of the current user
      */
+    const auto &file = path.string();
     if (file.empty() || (file[0] != '~')) {
         return file;
     }
@@ -88,7 +92,7 @@ std::filesystem::path path_parse(std::string_view file)
     constexpr auto user_size = 128;
     char user[user_size]{};
     if ((s != nullptr) && (s >= u + user_size)) {
-        throw std::runtime_error("User name is too long!");
+        THROW_EXCEPTION(std::runtime_error, "User name is too long!");
     }
 
     if (s != nullptr) {
@@ -112,7 +116,7 @@ std::filesystem::path path_parse(std::string_view file)
     }
 
     if (pw == nullptr) {
-        throw std::runtime_error("Failed to get User ID!");
+        THROW_EXCEPTION(std::runtime_error, "Failed to get User ID!");
     }
 
     if (s == nullptr) {
@@ -125,7 +129,7 @@ std::filesystem::path path_parse(std::string_view file)
 }
 #else
 {
-    return file;
+    return path;
 }
 #endif /* SET_UID */
 
@@ -138,7 +142,7 @@ std::filesystem::path path_parse(std::string_view file)
  */
 static errr path_temp(char *buf, int max)
 {
-    concptr s = tmpnam(nullptr);
+    auto s = tmpnam(nullptr);
     if (!s) {
         return -1;
     }
@@ -155,24 +159,24 @@ static errr path_temp(char *buf, int max)
 
 /*!
  * @brief OSの差異を吸収しつつ、絶対パスを生成する.
- * @param buf ファイルのフルを返すバッファ
- * @param max bufのサイズ
- * @param directory ディレクトリ
+ * @param path file 引数があるディレクトリ
  * @param file ファイル名またはディレクトリ名
- * @todo buf, max は削除してファイル名が長すぎたら例外を送出する。またreturn で絶対パスを返すように書き換える.
  */
-void path_build(char *buf, int max, const std::filesystem::path &path, std::string_view file)
+std::filesystem::path path_build(const std::filesystem::path &path, std::string_view file)
 {
-    if (file[0] == '~') {
-        (void)strnfmt(buf, max, "%s", file.data());
-    } else if (prefix(file, PATH_SEP)) {
-        (void)strnfmt(buf, max, "%s", file.data());
-    } else if (!path.string()[0]) {
-        (void)strnfmt(buf, max, "%s", file.data());
-    } else {
-        const auto &path_str = path.string();
-        (void)strnfmt(buf, max, "%s%s%s", path_str.data(), PATH_SEP, file.data());
+    if ((file[0] == '~') || (prefix(file, PATH_SEP)) || path.empty()) {
+        return file;
+    }
+
+    auto parsed_path = path_parse(path);
+    const auto &path_ret = parsed_path.append(file);
+    constexpr auto max_path_length = 1024;
+    const auto path_str = path_ret.string();
+    if (path_str.length() > max_path_length) {
+        THROW_EXCEPTION(std::runtime_error, format("Path is too long! %s", path_str.data()));
     }
+
+    return path_ret;
 }
 
 static std::string make_file_mode(const FileOpenMode mode, const bool is_binary)
@@ -189,7 +193,7 @@ static std::string make_file_mode(const FileOpenMode mode, const bool is_binary)
         ss << 'a';
         break;
     default:
-        throw std::logic_error("Invalid file mode is specified!");
+        THROW_EXCEPTION(std::logic_error, "Invalid file mode is specified!");
     }
 
     if (is_binary) {
@@ -201,16 +205,22 @@ static std::string make_file_mode(const FileOpenMode mode, const bool is_binary)
 
 /*!
  * @brief OSごとの差異を吸収してファイルを開く
- * @param file ファイルの相対パスまたは絶対パス
+ * @param path ファイルの相対パスまたは絶対パス
  * @param mode ファイルを開くモード
  * @param is_binary バイナリモードか否か (無指定の場合false:テキストモード)
  * @return ファイルポインタ
  */
-FILE *angband_fopen(const std::filesystem::path &file, const FileOpenMode mode, const bool is_binary)
+FILE *angband_fopen(const std::filesystem::path &path, const FileOpenMode mode, const bool is_binary, const FileOpenType ftype)
 {
-    const auto &path = path_parse(file.string());
+    FILE *result;
+
+    const auto &parsed_path = path_parse(path);
     const auto &open_mode = make_file_mode(mode, is_binary);
-    return fopen(path.string().data(), open_mode.data());
+    result = fopen(parsed_path.string().data(), open_mode.data());
+    if (result && mode != FileOpenMode::READ && file_open_hook) {
+        file_open_hook(path, ftype);
+    }
+    return result;
 }
 
 /*
@@ -266,12 +276,12 @@ errr angband_fgets(FILE *fff, char *buf, ulong n)
     // Reserve for null termination
     --n;
 
-    std::vector<char> file_read__tmp(FILE_READ_BUFF_SIZE);
-    if (fgets(file_read__tmp.data(), file_read__tmp.size(), fff)) {
+    std::vector<char> file_read_tmp(FILE_READ_BUFF_SIZE);
+    if (fgets(file_read_tmp.data(), file_read_tmp.size(), fff)) {
 #ifdef JP
-        guess_convert_to_system_encoding(file_read__tmp.data(), FILE_READ_BUFF_SIZE);
+        guess_convert_to_system_encoding(file_read_tmp.data(), FILE_READ_BUFF_SIZE);
 #endif
-        for (s = file_read__tmp.data(); *s; s++) {
+        for (s = file_read_tmp.data(); *s; s++) {
 #ifdef MACH_O_COCOA
             /*
              * Be nice to the Macintosh, where a file can have Mac or Unix
@@ -355,58 +365,49 @@ errr angband_fputs(FILE *fff, concptr buf, ulong n)
  * @brief OSごとの差異を吸収してファイルを削除する
  * @param file ファイルの相対パスまたは絶対パス
  */
-void fd_kill(std::string_view file)
+void fd_kill(const std::filesystem::path &path)
 {
-    const auto &path = path_parse(file);
-    if (!std::filesystem::exists(path)) {
-        return;
-    }
+    const auto &parsed_path = path_parse(path);
 
-    std::filesystem::remove(path);
+    std::error_code ec;
+    std::filesystem::remove(parsed_path, ec);
 }
 
 /*!
  * @brief OSごとの差異を吸収してファイルを移動する
- * @param from 移動元のファイルの相対パスまたは絶対パス
- * @param to 移動先のファイルの相対パスまたは絶対パス
+ * @param path_from 移動元のファイルの相対パスまたは絶対パス
+ * @param path_to 移動先のファイルの相対パスまたは絶対パス
  */
-void fd_move(std::string_view from, std::string_view to)
+void fd_move(const std::filesystem::path &path_from, const std::filesystem::path &path_to)
 {
-    const auto &path_from = path_parse(from);
-    if (!std::filesystem::exists(path_from)) {
-        return;
-    }
-
-    const auto &path_to = path_parse(to);
-    const auto directory = std::filesystem::path(path_to).remove_filename();
-    if (!std::filesystem::exists(directory)) {
-        std::filesystem::create_directory(directory);
-    }
+    const auto &abs_path_from = path_parse(path_from);
+    const auto &abs_path_to = path_parse(path_to);
 
-    std::filesystem::rename(path_from, path_to);
+    std::error_code ec;
+    std::filesystem::rename(abs_path_from, abs_path_to, ec);
 }
 
 /*!
  * @brief OSごとの差異を吸収してファイルを作成する
- * @param file 作成先ファイルの相対パスまたは絶対パス
+ * @param path 作成先ファイルの相対パスまたは絶対パス
  * @param can_write_group グループに書き込みを許可するか否か
  */
-int fd_make(std::string_view file, bool can_write_group)
+int fd_make(const std::filesystem::path &path, bool can_write_group)
 {
     const auto permission = can_write_group ? 0644 : 0664;
-    const auto &path = path_parse(file);
-    return open(path.string().data(), O_CREAT | O_EXCL | O_WRONLY | O_BINARY, permission);
+    const auto &parsed_path = path_parse(path);
+    return open(parsed_path.string().data(), O_CREAT | O_EXCL | O_WRONLY | O_BINARY, permission);
 }
 
 /*
  * @brief OSごとの差異を吸収してファイルを開く
- * @param file ファイルの相対パスまたは絶対パス
+ * @param path ファイルの相対パスまたは絶対パス
  * @param mode ファイルのオープンモード (読み書き、Append/Trunc等)
  */
-int fd_open(std::string_view file, int mode)
+int fd_open(const std::filesystem::path &path, int mode)
 {
-    const auto &path = path_parse(file);
-    return open(path.string().data(), mode | O_BINARY, 0);
+    const auto &path_abs = path_parse(path);
+    return open(path_abs.string().data(), mode | O_BINARY, 0);
 }
 
 /*
index 18770c6..8cfbc42 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <filesystem>
@@ -41,17 +41,27 @@ enum class FileOpenMode {
     APPEND,
 };
 
-std::filesystem::path path_parse(std::string_view file);
-void path_build(char *buf, int max, const std::filesystem::path &path, std::string_view file);
-FILE *angband_fopen(const std::filesystem::path &file, const FileOpenMode mode, const bool is_binary = false);
+// Specifies what king of thing a file is, when writing.  See file_open().
+enum class FileOpenType {
+    TEXT,
+    SAVE,
+    RAW,
+    HTML,
+};
+
+extern void (*file_open_hook)(const std::filesystem::path &path, const FileOpenType ftype);
+
+std::filesystem::path path_parse(const std::filesystem::path &path);
+std::filesystem::path path_build(const std::filesystem::path &path, std::string_view file);
+FILE *angband_fopen(const std::filesystem::path &path, const FileOpenMode mode, const bool is_binary = false, const FileOpenType ftype = FileOpenType::TEXT);
 FILE *angband_fopen_temp(char *buf, int max);
 errr angband_fgets(FILE *fff, char *buf, ulong n);
 errr angband_fputs(FILE *fff, concptr buf, ulong n);
 errr angband_fclose(FILE *fff);
-void fd_kill(std::string_view file);
-void fd_move(std::string_view from, std::string_view to);
-int fd_make(std::string_view file, bool can_write_group = false);
-int fd_open(std::string_view file, int mode);
+void fd_kill(const std::filesystem::path &path);
+void fd_move(const std::filesystem::path &path_from, const std::filesystem::path &path_to);
+int fd_make(const std::filesystem::path &path, bool can_write_group = false);
+int fd_open(const std::filesystem::path &path, int mode);
 errr fd_lock(int fd, int what);
 errr fd_seek(int fd, ulong n);
 errr fd_read(int fd, char *buf, ulong n);
index afe255c..e88774e 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <cassert>
 #include <type_traits>
index 06ac1e9..a7a8b73 100644 (file)
@@ -1,4 +1,4 @@
-#include "util/buffer-shaper.h"
+#include "util/buffer-shaper.h"
 #include "locale/japanese.h"
 #include <algorithm>
 #include <array>
index fbca07f..bd51f59 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
diff --git a/src/util/candidate-selector.cpp b/src/util/candidate-selector.cpp
new file mode 100644 (file)
index 0000000..087f0f5
--- /dev/null
@@ -0,0 +1,65 @@
+#include "util/candidate-selector.h"
+#include <algorithm>
+#include <iterator>
+
+/*!
+ * @brief 候補の選択に使用するシンボルのリスト
+ */
+const std::array<char, 62> CandidateSelector::i2sym = {
+    // clang-format off
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+    // clang-format on
+};
+
+/*!
+ * @brief CandidateSelectorクラスのコンストラクタ
+ *
+ * @param prompt 画面最上部に表示する文字列
+ * @param start_col 候補の表示を開始する列
+ */
+CandidateSelector::CandidateSelector(const std::string &prompt, int start_col)
+    : prompt(prompt)
+    , start_col(start_col)
+{
+    this->set_max_per_page();
+}
+
+std::pair<size_t, std::optional<size_t>> CandidateSelector::process_input(char cmd, size_t current_page, size_t page_max)
+{
+    switch (cmd) {
+    case ' ':
+        current_page++;
+        break;
+    case '-':
+        current_page += (page_max - 1);
+        break;
+    default:
+        if (auto select_sym_it = std::find(i2sym.begin(), i2sym.end(), cmd);
+            select_sym_it != i2sym.end()) {
+            const auto idx = static_cast<size_t>(std::distance(i2sym.begin(), select_sym_it));
+            return { current_page, idx };
+        }
+        break;
+    }
+
+    if (current_page >= page_max) {
+        current_page %= page_max;
+    }
+
+    return { current_page, std::nullopt };
+}
+
+/*!
+ * @brief 1ページに表示する候補の最大数を設定する
+ *
+ * 引数を省略した場合もしくは設定数が端末の高さより大きい場合は、端末の高さに合わせる
+ *
+ * @param max 1ページに表示する候補の最大数
+ */
+void CandidateSelector::set_max_per_page(size_t max)
+{
+    const auto &[wid, hgt] = term_get_size();
+    this->max_per_page = std::min<size_t>(max, hgt - 2);
+}
diff --git a/src/util/candidate-selector.h b/src/util/candidate-selector.h
new file mode 100644 (file)
index 0000000..b9a2b0c
--- /dev/null
@@ -0,0 +1,130 @@
+#pragma once
+
+#include "core/asking-player.h"
+#include "term/screen-processor.h"
+#include "util/finalizer.h"
+#include <array>
+#include <concepts>
+#include <limits>
+#include <optional>
+#include <sstream>
+#include <string>
+
+/// @note clang-formatによるconceptの整形が安定していないので抑制しておく
+// clang-format off
+/*!
+ * @brief 型Argのオブジェクトの説明を生成する関数の型Funcを表すコンセプト
+ */
+template <typename Func, typename Arg>
+concept Describer = requires(Func f, Arg a) {
+    { std::invoke(f, a) } -> std::convertible_to<std::string>;
+};
+
+/*!
+ * @brief サイズが既知のコンテナの型を表すコンセプト
+ */
+template <typename T>
+concept SizedContainer = requires(T t) {
+    { std::begin(t) } -> std::convertible_to<typename T::iterator>;
+    { std::end(t) } -> std::convertible_to<typename T::iterator>;
+    std::size(t);
+    typename T::value_type;
+};
+// clang-format on
+
+/*!
+ * @brief 候補を選択するためのクラス
+ */
+class CandidateSelector {
+public:
+    CandidateSelector(const std::string &prompt, int start_col = 0);
+
+    void set_max_per_page(size_t max_per_page = std::numeric_limits<size_t>::max());
+
+    /*!
+     * @brief 引数で与えられた候補リストを画面に表示し選択する
+     *
+     * 最上行に prompt を表示し、次の行から候補を
+     *
+     * <pre>
+     * a) 候補1
+     * b) 候補2
+     *    ︙
+     * </pre>
+     *
+     * のように表示する。
+     * 候補名は関数 describe_candidate によって生成する。
+     *
+     * 先頭の記号をキーボードで入力することによって選択する。
+     * 与えられた要素の数が max_per_page を超える場合はページ分けを行い、
+     * ' ' によって次ページ、'-' によって前ページへの切り替えを行う。
+     * ESCキーを押すと選択をキャンセルする。
+     *
+     * @param candidates 選択する候補
+     * @param describe_candidates 候補名を生成する関数
+     * @return 選択した要素を指すイテレータ
+     *         キャンセルした場合はstd::end(candidates)
+     */
+    template <SizedContainer Candidates, Describer<typename Candidates::value_type> F>
+    typename Candidates::const_iterator select(const Candidates &candidates, F &&describe_candidate)
+    {
+        const auto candidates_count = std::size(candidates);
+        const auto page_max = (candidates_count - 1) / this->max_per_page + 1;
+        auto current_page = 0U;
+
+        screen_save();
+        const auto finalizer = util::make_finalizer([] { screen_load(); });
+
+        while (true) {
+            this->display_page(current_page, candidates, describe_candidate);
+
+            const auto cmd = input_command(this->prompt);
+            if (!cmd) {
+                return std::end(candidates);
+            }
+
+            const auto page_base_idx = current_page * this->max_per_page;
+            const auto page_item_count = std::min(this->max_per_page, candidates_count - page_base_idx);
+
+            const auto [new_page, idx] = process_input(*cmd, current_page, page_max);
+            if (idx && *idx < page_item_count) {
+                return std::next(std::begin(candidates), page_base_idx + *idx);
+            }
+
+            current_page = new_page;
+        }
+    }
+
+private:
+    static std::pair<size_t, std::optional<size_t>> process_input(char cmd, size_t current_page, size_t page_max);
+
+    template <SizedContainer Candidates, Describer<typename Candidates::value_type> F>
+    void display_page(size_t page, const Candidates &candidates, F &&describe_candidate)
+    {
+        const auto candidates_count = std::size(candidates);
+        const auto page_max = (candidates_count - 1) / this->max_per_page + 1;
+        const auto page_base_idx = page * this->max_per_page;
+        const auto page_item_count = std::min(this->max_per_page, candidates_count - page_base_idx);
+
+        for (auto i = 0U; i < this->max_per_page + 1; ++i) {
+            term_erase(this->start_col, i + 1, 255);
+        }
+
+        auto it = std::next(std::begin(candidates), page_base_idx);
+        for (auto i = 0U; i < page_item_count; ++i, ++it) {
+            std::stringstream ss;
+            ss << i2sym[i] << ") " << std::invoke(describe_candidate, *it);
+            put_str(ss.str(), i + 1, this->start_col);
+        }
+        if (page_max > 1) {
+            const auto page_info = format("-- more (%lu/%lu) --", page + 1, page_max);
+            put_str(page_info, page_item_count + 1, this->start_col);
+        }
+    }
+
+    static const std::array<char, 62> i2sym;
+
+    std::string prompt;
+    int start_col;
+    size_t max_per_page;
+};
index 2da738b..1d6a729 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <type_traits>
 
index ca516c9..c5a1159 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <iterator>
 #include <type_traits>
@@ -21,9 +21,7 @@ public:
         // std::iterator_traits に対応するための定義
         using difference_type = int;
         using value_type = EnumType;
-        using pointer = const EnumType *;
-        using reference = const EnumType &;
-        using iterator_category = std::input_iterator_tag;
+        using iterator_concept = std::input_iterator_tag;
 
         /*!
          * @brief 引数で与えた列挙値を指すイテレータオブジェクトを生成する
@@ -46,36 +44,37 @@ public:
         }
 
         /*!
-         * @brief イテレータをインクリメントする
+         * @brief イテレータを前置インクリメントする
          *
          * @return *this の参照
          */
-        iterator &operator++() noexcept
+        constexpr iterator &operator++() noexcept
         {
             ++index;
             return *this;
         }
 
         /*!
-         * @brief 2つのイテレータが指している列挙値が等しいかどうか調べ
+         * @brief イテレータを後置インクリメントす
          *
-         * @param other 比較対象となるイテレータ
-         * @return 2つのイテレータが指している列挙値が等しければ true、そうでなければ false
+         * @return *this の参照
          */
-        constexpr bool operator==(const iterator &other) const noexcept
+        constexpr iterator operator++(int) noexcept
         {
-            return index == other.index;
+            auto old = *this;
+            ++*this;
+            return old;
         }
 
         /*!
-         * @brief 2ã\81¤ã\81®ã\82¤ã\83\86ã\83¬ã\83¼ã\82¿ã\81\8cæ\8c\87ã\81\97ã\81¦ã\81\84ã\82\8bå\88\97æ\8c\99å\80¤ã\81\8cç­\89ã\81\97ã\81\8fã\81ªã\81\84ã\81\8bã\81©ã\81\86ã\81\8b調ã\81¹ã\82\8b
+         * @brief 2つのイテレータが指している列挙値が等しいかどうか調べる
          *
          * @param other 比較対象となるイテレータ
-         * @return 2ã\81¤ã\81®ã\82¤ã\83\86ã\83¬ã\83¼ã\82¿ã\81\8cæ\8c\87ã\81\97ã\81¦ã\81\84ã\82\8bå\88\97æ\8c\99å\80¤ã\81\8cç­\89ã\81\97ã\81\8fã\81ªã\81\91ã\82\8cã\81° trueã\80\81ã\81\9dã\81\86ã\81§ã\81ªã\81\91ã\82\8cã\81° false
+         * @return 2つのイテレータが指している列挙値が等しければ true、そうでなければ false
          */
-        constexpr bool operator!=(const iterator &other) const noexcept
+        constexpr bool operator==(const iterator &other) const noexcept
         {
-            return !this->operator==(other);
+            return index == other.index;
         }
 
     private:
diff --git a/src/util/finalizer.h b/src/util/finalizer.h
new file mode 100644 (file)
index 0000000..933ef01
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <concepts>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+namespace util {
+
+/*!
+ * @brief オブジェクトがスコープを抜ける際に、コンストラクタで渡された関数を実行するクラス
+ *
+ * コード例:
+ * @code
+ * void func()
+ * {
+ *     auto finalizer = util::make_finalizer([] { std::cout << "finally" << std::endl; });
+ *     std::cout << "do something" << std::endl;
+ * }
+ * @endcode
+ * この場合、func()が終了する際に"finally"と表示される。
+ *
+ * @param func 実行する関数
+ */
+template <std::invocable Func>
+class Finalizer {
+public:
+    explicit Finalizer(const Func &func) noexcept
+        : func_{ func }
+    {
+    }
+    explicit Finalizer(Func &&func) noexcept
+        : func_{ std::move(func) }
+    {
+    }
+
+    ~Finalizer() noexcept
+    {
+        std::invoke(func_);
+    }
+
+    Finalizer(const Finalizer &) = delete;
+    void operator=(const Finalizer &) = delete;
+    Finalizer(Finalizer &&) = delete;
+    void operator=(Finalizer &&) = delete;
+
+private:
+    Func func_;
+};
+
+/*!
+ * @brief Finalizerオブジェクトを生成するファクトリ関数
+ * @param func Finalizerオブジェクトのコンストラクタに渡す関数
+ */
+template <typename Func>
+[[nodiscard]] auto make_finalizer(Func &&func) noexcept
+{
+    return Finalizer<std::decay_t<Func>>{ std::forward<Func>(func) };
+}
+
+}
index 3d0cf24..98e1114 100644 (file)
@@ -1,11 +1,31 @@
-#pragma once
+#pragma once
 
+#include "info-reader/info-reader-util.h"
 #include <bitset>
+#include <concepts>
+#include <iterator>
 #include <optional>
+#include <stdint.h>
+#include <type_traits>
 
 template <typename T>
 class EnumRange;
 
+namespace flag_group {
+
+/**
+ * @brief 型がFlagGroupクラスで使用するフラグを指すイテレータであることを表すコンセプト
+ *
+ * Iter の型が以下の要件を満たすことを表す
+ *
+ * - 入力イテレータである
+ * - そのイテレータが指す要素の型が FlagType である
+ */
+template <typename Iter, typename FlagType>
+concept FlagIter = std::input_iterator<Iter> && std::same_as<std::iter_value_t<Iter>, FlagType>;
+
+}
+
 namespace flag_group::detail {
 
 template <typename Func, size_t BITSET_SIZE>
@@ -44,6 +64,16 @@ void write_bitset(const std::bitset<BITSET_SIZE> &bs, Func wr_byte_func, size_t
     }
 }
 
+template <typename InputIter>
+constexpr unsigned long long calc_bitset_val(InputIter first, InputIter last) noexcept
+{
+    auto result = 0ULL;
+    for (; first != last; ++first) {
+        result |= 1ULL << static_cast<int>(*first);
+    }
+    return result;
+}
+
 }
 
 /**
@@ -76,7 +106,7 @@ public:
      *
      * すべてのフラグがOFFの状態のFlagGroupクラスのインスタンスを生成する
      */
-    FlagGroup() = default;
+    constexpr FlagGroup() = default;
 
     /**
      * @brief FlagGroupクラスのコンストラクタ
@@ -86,7 +116,7 @@ public:
      *
      * @param il ONの状態で生成するフラグを指定した initializer_list
      */
-    FlagGroup(std::initializer_list<FlagType> il)
+    constexpr FlagGroup(std::initializer_list<FlagType> il)
         : FlagGroup(il.begin(), il.end())
     {
     }
@@ -99,7 +129,7 @@ public:
      *
      * @param range 範囲を示すEnumRangeクラスのオブジェクト
      */
-    FlagGroup(const EnumRange<FlagType> &range)
+    constexpr FlagGroup(const EnumRange<FlagType> &range)
         : FlagGroup(range.begin(), range.end())
     {
     }
@@ -110,15 +140,44 @@ public:
      * 入力イテレータで指定した範囲のリストに含まれるフラグがON、
      * それ以外のフラグがOFFの状態のFlagGroupクラスのインスタンスを生成する
      *
+     * FLAG_TYPE_MAXがunsigned long longのビットサイズ以下の場合、
+     * unsigned long longの値を引数に取るstd::bitsetのconstexpr化された
+     * コンストラクタが使用できるので、FlagGroupクラスでも
+     * constexprコンストラクタとしてこちらを選択する。
+     *
      * @tparam InputIter 入力イテレータの型
      * @param first 範囲の開始位置を示す入力イテレータ
      * @param last 範囲の終了位置を示す入力イテレータ
      */
-    template <typename InputIter>
-    FlagGroup(InputIter first, InputIter last)
+    template <flag_group::FlagIter<FlagType> InputIter>
+        requires(FLAG_TYPE_MAX <= sizeof(unsigned long long) * 8)
+    constexpr FlagGroup(InputIter first, InputIter last)
+        : bs_(flag_group::detail::calc_bitset_val(first, last))
     {
-        static_assert(std::is_same<typename std::iterator_traits<InputIter>::value_type, FlagType>::value, "Iterator value type is invalid");
+    }
 
+    /**
+     * @brief FlagGroupクラスのコンストラクタ
+     *
+     * 入力イテレータで指定した範囲のリストに含まれるフラグがON、
+     * それ以外のフラグがOFFの状態のFlagGroupクラスのインスタンスを生成する
+     *
+     * FLAG_TYPE_MAXがunsigned long longのビットサイズより大きい場合、
+     * C++20の範囲ではstd::bitsetをconstexprコンストラクタで初期化することは
+     * できないため、constexprではない通常のコンストラクタとしてこちらを選択する。
+     *
+     * @todo C++23以降であればstd::bitsetの多くのメンバ関数がconstepxr化されているので
+     * FLAG_TYPE_MAXがunsigned long longのビットサイズより大きくてもconstexpr化が
+     * 可能になると思われる。
+     *
+     * @tparam InputIter 入力イテレータの型
+     * @param first 範囲の開始位置を示す入力イテレータ
+     * @param last 範囲の終了位置を示す入力イテレータ
+     */
+    template <flag_group::FlagIter<FlagType> InputIter>
+        requires(FLAG_TYPE_MAX > sizeof(unsigned long long) * 8)
+    FlagGroup(InputIter first, InputIter last)
+    {
         for (; first != last; ++first) {
             set(*first);
         }
@@ -127,93 +186,184 @@ public:
     /**
      * @brief フラグ集合に含まれるフラグをすべてOFFにする
      *
-     * @return *thisを返す
+     * @return *thisã\81®å\8f\82ç\85§ã\82\92è¿\94ã\81\99
      */
-    FlagGroup<FlagType, MAX> &clear() noexcept
+    FlagGroup<FlagType, MAX> &clear() &noexcept
     {
         bs_.reset();
         return *this;
     }
 
     /**
+     * @brief フラグ集合に含まれるフラグをすべてOFFにする
+     *
+     * @return *thisを返す
+     */
+    FlagGroup<FlagType, MAX> clear() &&noexcept
+    {
+        this->clear();
+        return std::move(*this);
+    }
+
+    /**
      * @brief 指定したフラグを指定した値にセットする
      *
      * @param flag 値をセットするフラグを指定する
      * @param val セットする値。trueならフラグをON、falseならフラグをOFFにする。
      *            引数を省略した場合はフラグをONにする。
-     * @return *thisを返す
+     * @return *thisã\81®å\8f\82ç\85§ã\82\92è¿\94ã\81\99
      */
-    FlagGroup<FlagType, MAX> &set(FlagType flag, bool val = true)
+    FlagGroup<FlagType, MAX> &set(FlagType flag, bool val = true) &
     {
         bs_.set(static_cast<size_t>(flag), val);
         return *this;
     }
 
     /**
+     * @brief 指定したフラグを指定した値にセットする
+     *
+     * @param flag 値をセットするフラグを指定する
+     * @param val セットする値。trueならフラグをON、falseならフラグをOFFにする。
+     *            引数を省略した場合はフラグをONにする。
+     * @return *thisを返す
+     */
+    FlagGroup<FlagType, MAX> set(FlagType flag, bool val = true) &&
+    {
+        this->set(flag, val);
+        return std::move(*this);
+    }
+
+    /**
      * @brief 入力イテレータで指定した範囲のリストに含まれるフラグをONにする
      *
      * @tparam InputIter 入力イテレータの型
      * @param first 範囲の開始位置を示す入力イテレータ
      * @param last 範囲の終了位置を示す入力イテレータ
-     * @return *thisを返す
+     * @return *thisã\81®å\8f\82ç\85§ã\82\92è¿\94ã\81\99
      */
-    template <typename InputIter>
-    FlagGroup<FlagType, MAX> &set(InputIter first, InputIter last)
+    template <flag_group::FlagIter<FlagType> InputIter>
+    FlagGroup<FlagType, MAX> &set(InputIter first, InputIter last) &
     {
         return set(FlagGroup(first, last));
     }
 
     /**
+     * @brief 入力イテレータで指定した範囲のリストに含まれるフラグをONにする
+     *
+     * @tparam InputIter 入力イテレータの型
+     * @param first 範囲の開始位置を示す入力イテレータ
+     * @param last 範囲の終了位置を示す入力イテレータ
+     * @return *thisを返す
+     */
+    template <flag_group::FlagIter<FlagType> InputIter>
+    FlagGroup<FlagType, MAX> set(InputIter first, InputIter last) &&
+    {
+        this->set(first, last);
+        return std::move(*this);
+    }
+
+    /**
      * @brief 指定したFlagGroupのインスンタンスのONになっているフラグをONにする
      *
      * @param rhs ONにするフラグがONになっているFlagGroupのインスタンス
-     * @return *thisを返す
+     * @return *thisã\81®å\8f\82ç\85§ã\82\92è¿\94ã\81\99
      */
-    FlagGroup<FlagType, MAX> &set(const FlagGroup<FlagType, MAX> &rhs)
+    FlagGroup<FlagType, MAX> &set(const FlagGroup<FlagType, MAX> &rhs) &
     {
         bs_ |= rhs.bs_;
         return *this;
     }
 
     /**
+     * @brief 指定したFlagGroupのインスンタンスのONになっているフラグをONにする
+     *
+     * @param rhs ONにするフラグがONになっているFlagGroupのインスタンス
+     * @return *thisを返す
+     */
+    FlagGroup<FlagType, MAX> set(const FlagGroup<FlagType, MAX> &rhs) &&
+    {
+        this->set(rhs);
+        return std::move(*this);
+    }
+
+    /**
      * @brief 指定したフラグをOFFにする
      *
      * @param flag OFFにするフラグを指定する
-     * @return *thisを返す
+     * @return *thisã\81®å\8f\82ç\85§ã\82\92è¿\94ã\81\99
      */
-    FlagGroup<FlagType, MAX> &reset(FlagType flag)
+    FlagGroup<FlagType, MAX> &reset(FlagType flag) &
     {
         bs_.reset(static_cast<size_t>(flag));
         return *this;
     }
 
     /**
+     * @brief 指定したフラグをOFFにする
+     *
+     * @param flag OFFにするフラグを指定する
+     * @return *thisを返す
+     */
+    FlagGroup<FlagType, MAX> reset(FlagType flag) &&
+    {
+        this->reset(flag);
+        return std::move(*this);
+    }
+
+    /**
      * @brief 入力イテレータで指定した範囲のリストに含まれるフラグをOFFにする
      *
      * @tparam InputIter 入力イテレータの型
      * @param first 範囲の開始位置を示す入力イテレータ
      * @param last 範囲の終了位置を示す入力イテレータ
-     * @return *thisを返す
+     * @return *thisã\81®å\8f\82ç\85§ã\82\92è¿\94ã\81\99
      */
-    template <typename InputIter>
-    FlagGroup<FlagType, MAX> &reset(InputIter first, InputIter last)
+    template <flag_group::FlagIter<FlagType> InputIter>
+    FlagGroup<FlagType, MAX> &reset(InputIter first, InputIter last) &
     {
         return reset(FlagGroup(first, last));
     }
 
     /**
+     * @brief 入力イテレータで指定した範囲のリストに含まれるフラグをOFFにする
+     *
+     * @tparam InputIter 入力イテレータの型
+     * @param first 範囲の開始位置を示す入力イテレータ
+     * @param last 範囲の終了位置を示す入力イテレータ
+     * @return *thisを返す
+     */
+    template <flag_group::FlagIter<FlagType> InputIter>
+    FlagGroup<FlagType, MAX> reset(InputIter first, InputIter last) &&
+    {
+        this->reset(first, last);
+        return std::move(*this);
+    }
+
+    /**
      * @brief 指定したFlagGroupのインスンタンスのONになっているフラグをOFFにする
      *
      * @param rhs OFFにするフラグがONになっているFlagGroupのインスタンス
-     * @return *thisを返す
+     * @return *thisã\81®å\8f\82ç\85§ã\82\92è¿\94ã\81\99
      */
-    FlagGroup<FlagType, MAX> &reset(const FlagGroup<FlagType, MAX> &rhs)
+    FlagGroup<FlagType, MAX> &reset(const FlagGroup<FlagType, MAX> &rhs) &
     {
         bs_ &= ~rhs.bs_;
         return *this;
     }
 
     /**
+     * @brief 指定したFlagGroupのインスンタンスのONになっているフラグをOFFにする
+     *
+     * @param rhs OFFにするフラグがONになっているFlagGroupのインスタンス
+     * @return *thisを返す
+     */
+    FlagGroup<FlagType, MAX> reset(const FlagGroup<FlagType, MAX> &rhs) &&
+    {
+        this->reset(rhs);
+        return std::move(*this);
+    }
+
+    /**
      * @brief 指定したフラグがONかOFFか調べる
      *
      * @param f 調べるフラグを指定する
@@ -269,7 +419,7 @@ public:
      * @param last 範囲の終了位置を示す入力イテレータ
      * @return すべてのフラグがONであればtrue、そうでなければfalse
      */
-    template <typename InputIter>
+    template <flag_group::FlagIter<FlagType> InputIter>
     [[nodiscard]] bool has_all_of(InputIter first, InputIter last) const
     {
         return has_all_of(FlagGroup(first, last));
@@ -294,7 +444,7 @@ public:
      * @param last 範囲の終了位置を示す入力イテレータ
      * @return いずれかのフラグがONであればtrue、そうでなければfalse
      */
-    template <typename InputIter>
+    template <flag_group::FlagIter<FlagType> InputIter>
     [[nodiscard]] bool has_any_of(InputIter first, InputIter last) const
     {
         return has_any_of(FlagGroup(first, last));
@@ -319,7 +469,7 @@ public:
      * @param last 範囲の終了位置を示す入力イテレータ
      * @return すべてのフラグがOFFであればtrue、そうでなければfalse
      */
-    template <typename InputIter>
+    template <flag_group::FlagIter<FlagType> InputIter>
     [[nodiscard]] bool has_none_of(InputIter first, InputIter last) const
     {
         return !has_any_of(first, last);
@@ -524,23 +674,21 @@ public:
      * @brief 文字列からフラグへのマップを指定した検索キーで検索し、
      *        見つかった場合はフラグ集合に該当するフラグをセットする
      *
-     * @tparam Map std::map<string_view, FlagType> もしくは std::unordered_map<string_view, FlagType>
      * @param fg フラグをセットするフラグ集合
      * @param dict 文字列からフラグへのマップ
      * @param what マップの検索キー
      * @return 検索キーでフラグが見つかり、フラグをセットした場合 true
      *         見つからなかった場合 false
      */
-    template <typename Map>
-    static bool grab_one_flag(FlagGroup<FlagType, MAX> &fg, const Map &dict, std::string_view what)
+    template <typename Key, DictIndexedBy<Key> Dict>
+    static bool grab_one_flag(FlagGroup<FlagType, MAX> &fg, const Dict &dict, Key &&what)
     {
-        auto it = dict.find(what);
-        if (it == dict.end()) {
-            return false;
+        auto val = info_get_const(dict, std::forward<Key>(what));
+        if (val) {
+            fg.set(*val);
+            return true;
         }
-
-        fg.set(it->second);
-        return true;
+        return false;
     }
 
 private:
index 288902b..fa8d50d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index fab8df4..2497a75 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief オブジェクトのソート処理
  * @date 2020/06/03
  * @author Hourier
index 1838e8b..e381c4b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 08d1179..968bef3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/h-type.h"
 
@@ -14,6 +14,16 @@ struct Point2D {
         , x(x)
     {
     }
+
+    constexpr bool operator==(const Point2D &other) const
+    {
+        return (this->y == other.y) && (this->x == other.x);
+    }
+
+    constexpr bool operator!=(const Point2D &other) const
+    {
+        return !(*this == other);
+    }
 };
 
 //! ゲームの平面マップ上の座標位置を表す構造体
index b4355d2..2f89f4c 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 
+#include "system/angband-exceptions.h"
 #include "term/z-rand.h"
-
 #include <algorithm>
 #include <exception>
 #include <stdexcept>
@@ -109,7 +109,7 @@ public:
     IdType pick_one_at_random() const
     {
         if (empty()) {
-            throw std::runtime_error("There is no entry in the probability table.");
+            THROW_EXCEPTION(std::runtime_error, "There is no entry in the probability table.");
         }
 
         // probの合計の範囲からランダムでkeyを取得し、二分探索で選択する項目を決定する
diff --git a/src/util/quarks.cpp b/src/util/quarks.cpp
deleted file mode 100644 (file)
index b394804..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "util/quarks.h"
-
-#include <string>
-#include <vector>
-
-namespace {
-/*!
- * @brief 銘情報の最大数 / Maximum number of "quarks"
- * @note
- * Default: assume at most 512 different inscriptions are used<br>
- * Was 512... 256 quarks added for random artifacts<br>
- */
-constexpr auto QUARK_MAX = 768;
-
-/*
- * The pointers to the quarks [QUARK_MAX]
- */
-std::vector<std::string> quark__str;
-}
-
-/*
- * Initialize the quark array
- */
-void quark_init(void)
-{
-    //! @note [0]は使用しない、[1]は空文字列固定
-    quark__str.assign(2, {});
-    quark__str[1] = "";
-}
-
-/*
- * Add a new "quark" to the set of quarks.
- */
-ushort quark_add(concptr str)
-{
-    for (uint16_t i = 1; i < quark__str.size(); i++) {
-        if (streq(quark__str[i], str)) {
-            return i;
-        }
-    }
-
-    if (quark__str.size() >= QUARK_MAX) {
-        return 1;
-    }
-
-    quark__str.emplace_back(str);
-    return static_cast<uint16_t>(quark__str.size() - 1);
-}
-
-/*
- * This function looks up a quark
- */
-concptr quark_str(ushort i)
-{
-    concptr q;
-
-    /* Return nullptr for an invalid index */
-    if ((i < 1) || (i >= quark__str.size())) {
-        return nullptr;
-    }
-
-    /* Access the quark */
-    q = quark__str[i].data();
-
-    /* Return the quark */
-    return q;
-}
diff --git a/src/util/quarks.h b/src/util/quarks.h
deleted file mode 100644 (file)
index ed8fa92..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-#include "system/angband.h"
-
-concptr quark_str(ushort num);
-void quark_init(void);
-ushort quark_add(concptr str);
index da438e9..051e7a8 100644 (file)
@@ -1,4 +1,4 @@
-#include "util/rng-xoshiro.h"
+#include "util/rng-xoshiro.h"
 
 namespace {
 
index 68c4f53..74aaf0b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include <array>
 #include <cstdint>
diff --git a/src/util/sha256.cpp b/src/util/sha256.cpp
new file mode 100644 (file)
index 0000000..99a39ed
--- /dev/null
@@ -0,0 +1,331 @@
+/*!
+ * @brief SHA-256ハッシュ値計算クラスの定義
+ *
+ * RFC 6234のリファレンス実装を参考にC++20で実装
+ */
+
+/***************** See RFC 6234 for details. *******************/
+/* Copyright (c) 2011 IETF Trust and the persons identified as */
+/* authors of the code.  All rights reserved.                  */
+/* See sha256.h for terms of use and redistribution.           */
+
+#include "util/sha256.h"
+#include "system/angband-exceptions.h"
+#include "util/enum-converter.h"
+#include <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <limits>
+#include <span>
+#include <sstream>
+
+namespace util {
+
+namespace {
+
+    constexpr auto shift_right(uint32_t word, uint32_t shift)
+    {
+        return word >> shift;
+    }
+
+    constexpr auto rotate_right(uint32_t word, uint32_t shift)
+    {
+        return (word >> shift) | (word << (32 - shift));
+    }
+
+    constexpr auto big_sigma0(uint32_t word)
+    {
+        return rotate_right(word, 2) ^ rotate_right(word, 13) ^ rotate_right(word, 22);
+    }
+
+    constexpr auto big_sigma1(uint32_t word)
+    {
+        return rotate_right(word, 6) ^ rotate_right(word, 11) ^ rotate_right(word, 25);
+    }
+
+    constexpr auto small_sigma0(uint32_t word)
+    {
+        return rotate_right(word, 7) ^ rotate_right(word, 18) ^ shift_right(word, 3);
+    }
+
+    constexpr auto small_sigma1(uint32_t word)
+    {
+        return rotate_right(word, 17) ^ rotate_right(word, 19) ^ shift_right(word, 10);
+    }
+
+    constexpr auto sha_ch(uint32_t x, uint32_t y, uint32_t z)
+    {
+        return (x & (y ^ z)) ^ z;
+    }
+
+    constexpr auto sha_maj(uint32_t x, uint32_t y, uint32_t z)
+    {
+        return (x & (y | z)) | (y & z);
+    }
+
+    /// @brief SHA-256の初期ハッシュ値
+    constexpr std::array<uint32_t, SHA256::DIGEST_SIZE / 4> INITIAL_HASH{ {
+        // clang-format off
+        0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+        0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
+        // clang-format on
+    } };
+}
+
+struct SHA256::Impl {
+    void add_length(size_t length);
+    void process_message_block();
+    void finalize(std::byte pad_byte);
+    void pad_message(std::byte pad_byte);
+
+    std::array<uint32_t, SHA256::DIGEST_SIZE / 4> hash = INITIAL_HASH;
+    uint64_t length = 0;
+    int message_block_index = 0;
+    std::array<std::byte, SHA256::BLOCK_SIZE> message_block{};
+    bool computed = false;
+};
+
+SHA256::SHA256()
+    : pimpl(std::make_unique<Impl>())
+{
+}
+
+SHA256::~SHA256() = default;
+
+/*!
+ * @brief ハッシュ値計算をリセットする
+ */
+void SHA256::reset()
+{
+    this->pimpl->hash = INITIAL_HASH;
+    this->pimpl->length = 0;
+    this->pimpl->message_block_index = 0;
+    this->pimpl->message_block.fill(std::byte(0));
+    this->pimpl->computed = false;
+}
+
+/*!
+ * @brief メッセージ(バイト列)をハッシュ値に追加する
+ *
+ * @param message_array 追加するメッセージ
+ * @param length メッセージのバイト数
+ */
+void SHA256::update(const std::byte *message_array, size_t length)
+{
+    if (length == 0) {
+        return;
+    }
+
+    if (this->pimpl->computed) {
+        THROW_EXCEPTION(std::logic_error, "SHA256::update() called after compute.");
+    }
+
+    this->pimpl->add_length(8 * length);
+
+    std::span remain(message_array, length);
+    while (!remain.empty()) {
+        const auto copy_size = std::min<int>(remain.size(), BLOCK_SIZE - this->pimpl->message_block_index);
+        std::copy_n(remain.begin(), copy_size, this->pimpl->message_block.begin() + this->pimpl->message_block_index);
+        this->pimpl->message_block_index += copy_size;
+        remain = remain.subspan(copy_size);
+
+        if (this->pimpl->message_block_index == BLOCK_SIZE) {
+            this->pimpl->process_message_block();
+        }
+    }
+}
+
+/*!
+ * @brief メッセージ(文字列)をハッシュ値に追加する
+ *
+ * @param message 追加するメッセージ
+ */
+void SHA256::update(std::string_view message)
+{
+    const auto message_as_byte = std::as_bytes(std::span(message.begin(), message.end()));
+    this->update(message_as_byte.data(), message_as_byte.size_bytes());
+}
+
+/*!
+ * @brief 最終ブロックのビット列をハッシュ値に追加する
+ *
+ * 最終ブロックのデータが1バイトに満たない場合に使用される。
+ * 一般的にはバイト単位での追加を行うため、通常このメソッドは呼び出されない。
+ *
+ * @param message_bits 追加するビット列
+ * @param length 追加するビット列の長さ(0~7)
+ */
+void SHA256::final_bits(std::byte message_bits, size_t length)
+{
+    if (this->pimpl->computed) {
+        THROW_EXCEPTION(std::logic_error, "SHA256::final_bits() called after compute.");
+    }
+
+    if (length >= 8) {
+        THROW_EXCEPTION(std::invalid_argument, "SHA256::final_bits() called with length >= 8.");
+    }
+
+    // clang-format off
+    static constexpr std::array<std::byte, 8> masks{ {
+        std::byte(0x00), std::byte(0x80), std::byte(0xC0), std::byte(0xE0),
+        std::byte(0xF0), std::byte(0xF8), std::byte(0xFC), std::byte(0xFE) } };
+    static constexpr std::array<std::byte, 8> markbits{ {
+        std::byte(0x80), std::byte(0x40), std::byte(0x20), std::byte(0x10),
+        std::byte(0x08), std::byte(0x04), std::byte(0x02), std::byte(0x01) } };
+    // clang-format on
+
+    this->pimpl->add_length(length);
+    this->pimpl->finalize((message_bits & masks[length]) | markbits[length]);
+}
+
+/*!
+ * @brief ハッシュ値を取得する
+ *
+ * @return ハッシュ値
+ */
+SHA256::Digest SHA256::digest()
+{
+    if (!this->pimpl->computed) {
+        this->pimpl->finalize(std::byte(0x80));
+    }
+
+    Digest result{};
+    for (auto i = 0; i < SHA256::DIGEST_SIZE; ++i) {
+        result[i] = std::byte(this->pimpl->hash[i / 4] >> 8 * (3 - (i % 4)));
+    }
+
+    return result;
+}
+
+void SHA256::Impl::add_length(size_t len)
+{
+    if (std::numeric_limits<decltype(this->length)>::max() - len < this->length) {
+        THROW_EXCEPTION(std::overflow_error, "SHA256::add_length() overflow.");
+    }
+
+    this->length += len;
+}
+
+void SHA256::Impl::process_message_block()
+{
+    static constexpr std::array<uint32_t, BLOCK_SIZE> k{ {
+        // clang-format off
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
+        0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
+        0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
+        0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+        0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
+        0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+        0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
+        0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
+        0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
+        0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
+        0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+        0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+        // clang-format on
+    } };
+    std::array<uint32_t, BLOCK_SIZE> w{};
+
+    for (auto i = 0, i4 = 0; i4 < BLOCK_SIZE; ++i, i4 += 4) {
+        w[i] = (static_cast<uint32_t>(this->message_block[i4]) << 24) |
+               (static_cast<uint32_t>(this->message_block[i4 + 1]) << 16) |
+               (static_cast<uint32_t>(this->message_block[i4 + 2]) << 8) |
+               (static_cast<uint32_t>(this->message_block[i4 + 3]));
+    }
+
+    for (auto i = 16; i < BLOCK_SIZE; ++i) {
+        w[i] = small_sigma1(w[i - 2]) + w[i - 7] + small_sigma0(w[i - 15]) + w[i - 16];
+    }
+
+    auto h = this->hash;
+
+    for (auto i = 0; i < BLOCK_SIZE; ++i) {
+        const auto tmp1 = h[7] + big_sigma1(h[4]) + sha_ch(h[4], h[5], h[6]) + k[i] + w[i];
+        const auto tmp2 = big_sigma0(h[0]) + sha_maj(h[0], h[1], h[2]);
+        std::copy_backward(h.begin(), h.end() - 1, h.end());
+        h[4] += tmp1;
+        h[0] = tmp1 + tmp2;
+    }
+
+    std::transform(this->hash.begin(), this->hash.end(), h.begin(),
+        this->hash.begin(), std::plus<uint32_t>{});
+
+    this->message_block_index = 0;
+}
+
+void SHA256::Impl::finalize(std::byte pad_byte)
+{
+    this->pad_message(pad_byte);
+    this->message_block.fill(std::byte(0));
+    this->length = 0;
+    this->computed = true;
+}
+
+void SHA256::Impl::pad_message(std::byte pad_byte)
+{
+    this->message_block[this->message_block_index++] = pad_byte;
+
+    const std::span whole(this->message_block);
+
+    if (const auto remain = whole.subspan(this->message_block_index); remain.size() < 8) {
+        std::fill(remain.begin(), remain.end(), std::byte(0));
+        this->process_message_block();
+    }
+
+    const auto zerofill_span = whole.first(BLOCK_SIZE - 8).subspan(this->message_block_index);
+    std::fill(zerofill_span.begin(), zerofill_span.end(), std::byte(0));
+
+    const auto length_span = whole.last(8);
+    for (auto i = 0; i < 8; ++i) {
+        length_span[i] = std::byte((this->length >> (BLOCK_SIZE - 8 - i * 8)) & 0xff);
+    }
+
+    this->process_message_block();
+}
+
+/*!
+ * @brief ファイルのSHA-256ハッシュ値を計算する
+ *
+ * @param path ファイルパス
+ * @return ハッシュ値を返す。ファイルの読み込みに失敗した場合はstd::nulloptを返す。
+ */
+std::optional<SHA256::Digest> SHA256::compute_filehash(const std::filesystem::path &path)
+{
+    std::ifstream ifs(path, std::ios::binary);
+    if (!ifs) {
+        return std::nullopt;
+    }
+
+    SHA256 hash;
+    std::array<char, 1024> buf{};
+    const auto buf_as_bytes = std::as_bytes(std::span(buf));
+    while (ifs) {
+        ifs.read(buf.data(), buf.size());
+        hash.update(buf_as_bytes.data(), ifs.gcount());
+    }
+
+    if (ifs.bad()) {
+        return std::nullopt;
+    }
+
+    return hash.digest();
+}
+
+/*!
+ * @brief ハッシュ値を文字列に変換する
+ *
+ * @param digest ハッシュ値
+ * @return ハッシュ値を16進数文字列表記に変換したもの
+ */
+std::string to_string(const SHA256::Digest &digest)
+{
+    std::stringstream ss;
+    for (const auto byte : digest) {
+        ss << std::hex << std::setfill('0') << std::setw(2) << std::to_integer<int>(byte);
+    }
+
+    return ss.str();
+}
+
+}
diff --git a/src/util/sha256.h b/src/util/sha256.h
new file mode 100644 (file)
index 0000000..dfb891b
--- /dev/null
@@ -0,0 +1,85 @@
+/*!
+ * @brief SHA-256ハッシュ値計算クラスの宣言
+ */
+
+/***************** See RFC 6234 for details. *******************/
+/*
+   Copyright (c) 2011 IETF Trust and the persons identified as
+   authors of the code.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or
+   without modification, are permitted provided that the following
+   conditions are met:
+
+   - Redistributions of source code must retain the above
+     copyright notice, this list of conditions and
+     the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above
+     copyright notice, this list of conditions and the following
+     disclaimer in the documentation and/or other materials provided
+     with the distribution.
+
+   - Neither the name of Internet Society, IETF or IETF Trust, nor
+     the names of specific contributors, may be used to endorse or
+     promote products derived from this software without specific
+     prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+   EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <filesystem>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+
+namespace util {
+
+/*!
+ * @brief SHA-256ハッシュ値計算クラス
+ */
+class SHA256 {
+public:
+    static constexpr auto DIGEST_SIZE = 32; ///< ハッシュ値のバイト数
+    static constexpr auto BLOCK_SIZE = 64; ///< ブロックサイズ
+    using Digest = std::array<std::byte, DIGEST_SIZE>; ///< ハッシュ値の型
+
+    SHA256();
+    ~SHA256();
+    SHA256(const SHA256 &) = delete;
+    SHA256 &operator=(const SHA256 &) = delete;
+    SHA256(SHA256 &&) = delete;
+    SHA256 &operator=(SHA256 &&) = delete;
+
+    void reset();
+    void update(const std::byte *message_array, size_t length);
+    void update(std::string_view message);
+    void final_bits(std::byte message_bits, size_t length);
+    Digest digest();
+
+    static std::optional<Digest> compute_filehash(const std::filesystem::path &path);
+
+private:
+    struct Impl;
+    std::unique_ptr<Impl> pimpl;
+};
+
+std::string to_string(const SHA256::Digest &hash);
+}
index 07c3eac..c1d3668 100644 (file)
@@ -1,4 +1,4 @@
-#include "util/sort.h"
+#include "util/sort.h"
 #include "artifact/fixed-art-types.h"
 #include "dungeon/quest.h"
 #include "grid/grid.h"
@@ -119,13 +119,13 @@ bool ang_sort_comp_distance(PlayerType *player_ptr, vptr u, vptr v, int a, int b
  */
 bool ang_sort_comp_importance(PlayerType *player_ptr, vptr u, vptr v, int a, int b)
 {
-    POSITION *x = (POSITION *)(u);
-    POSITION *y = (POSITION *)(v);
-    grid_type *ca_ptr = &player_ptr->current_floor_ptr->grid_array[y[a]][x[a]];
-    grid_type *cb_ptr = &player_ptr->current_floor_ptr->grid_array[y[b]][x[b]];
-    MonsterEntity *ma_ptr = &player_ptr->current_floor_ptr->m_list[ca_ptr->m_idx];
-    MonsterEntity *mb_ptr = &player_ptr->current_floor_ptr->m_list[cb_ptr->m_idx];
-    MonsterRaceInfo *ap_ra_ptr, *ap_rb_ptr;
+    auto *x = static_cast<int *>(u);
+    auto *y = static_cast<int *>(v);
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid_a = floor.get_grid({ y[a], x[a] });
+    const auto &grid_b = floor.get_grid({ y[b], x[b] });
+    const auto &monster_a = floor.m_list[grid_a.m_idx];
+    const auto &monster_b = floor.m_list[grid_b.m_idx];
 
     /* The player grid */
     if (y[a] == player_ptr->y && x[a] == player_ptr->x) {
@@ -137,86 +137,90 @@ bool ang_sort_comp_importance(PlayerType *player_ptr, vptr u, vptr v, int a, int
     }
 
     /* Extract monster race */
-    if (ca_ptr->m_idx && ma_ptr->ml) {
-        ap_ra_ptr = &monraces_info[ma_ptr->ap_r_idx];
+    MonsterRaceInfo *ap_r_ptr_a;
+    if (grid_a.m_idx && monster_a.ml) {
+        ap_r_ptr_a = &monster_a.get_appearance_monrace();
     } else {
-        ap_ra_ptr = nullptr;
+        ap_r_ptr_a = nullptr;
     }
 
-    if (cb_ptr->m_idx && mb_ptr->ml) {
-        ap_rb_ptr = &monraces_info[mb_ptr->ap_r_idx];
+    MonsterRaceInfo *ap_r_ptr_b;
+    if (grid_b.m_idx && monster_b.ml) {
+        ap_r_ptr_b = &monster_b.get_appearance_monrace();
     } else {
-        ap_rb_ptr = nullptr;
+        ap_r_ptr_b = nullptr;
     }
 
-    if (ap_ra_ptr && !ap_rb_ptr) {
+    if (ap_r_ptr_a && !ap_r_ptr_b) {
         return true;
     }
 
-    if (!ap_ra_ptr && ap_rb_ptr) {
+    if (!ap_r_ptr_a && ap_r_ptr_b) {
         return false;
     }
 
     /* Compare two monsters */
-    if (ap_ra_ptr && ap_rb_ptr) {
+    if (ap_r_ptr_a && ap_r_ptr_b) {
         /* Unique monsters first */
-        if (ap_ra_ptr->kind_flags.has(MonsterKindType::UNIQUE) && ap_rb_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
+        if (ap_r_ptr_a->kind_flags.has(MonsterKindType::UNIQUE) && ap_r_ptr_b->kind_flags.has_not(MonsterKindType::UNIQUE)) {
             return true;
         }
-        if (ap_ra_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) && ap_rb_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
+        if (ap_r_ptr_a->kind_flags.has_not(MonsterKindType::UNIQUE) && ap_r_ptr_b->kind_flags.has(MonsterKindType::UNIQUE)) {
             return false;
         }
 
         /* Shadowers first (あやしい影) */
-        if (ma_ptr->mflag2.has(MonsterConstantFlagType::KAGE) && mb_ptr->mflag2.has_not(MonsterConstantFlagType::KAGE)) {
+        if (monster_a.mflag2.has(MonsterConstantFlagType::KAGE) && monster_b.mflag2.has_not(MonsterConstantFlagType::KAGE)) {
             return true;
         }
-        if (ma_ptr->mflag2.has_not(MonsterConstantFlagType::KAGE) && mb_ptr->mflag2.has(MonsterConstantFlagType::KAGE)) {
+        if (monster_a.mflag2.has_not(MonsterConstantFlagType::KAGE) && monster_b.mflag2.has(MonsterConstantFlagType::KAGE)) {
             return false;
         }
 
         /* Unknown monsters first */
-        if (!ap_ra_ptr->r_tkills && ap_rb_ptr->r_tkills) {
+        if (!ap_r_ptr_a->r_tkills && ap_r_ptr_b->r_tkills) {
             return true;
         }
-        if (ap_ra_ptr->r_tkills && !ap_rb_ptr->r_tkills) {
+        if (ap_r_ptr_a->r_tkills && !ap_r_ptr_b->r_tkills) {
             return false;
         }
 
         /* Higher level monsters first (if known) */
-        if (ap_ra_ptr->r_tkills && ap_rb_ptr->r_tkills) {
-            if (ap_ra_ptr->level > ap_rb_ptr->level) {
+        if (ap_r_ptr_a->r_tkills && ap_r_ptr_b->r_tkills) {
+            if (ap_r_ptr_a->level > ap_r_ptr_b->level) {
                 return true;
             }
-            if (ap_ra_ptr->level < ap_rb_ptr->level) {
+            if (ap_r_ptr_a->level < ap_r_ptr_b->level) {
                 return false;
             }
         }
 
         /* Sort by index if all conditions are same */
-        if (ma_ptr->ap_r_idx > mb_ptr->ap_r_idx) {
+        if (monster_a.ap_r_idx > monster_b.ap_r_idx) {
             return true;
         }
-        if (ma_ptr->ap_r_idx < mb_ptr->ap_r_idx) {
+        if (monster_a.ap_r_idx < monster_b.ap_r_idx) {
             return false;
         }
     }
 
     /* An object get higher priority */
-    if (!player_ptr->current_floor_ptr->grid_array[y[a]][x[a]].o_idx_list.empty() && player_ptr->current_floor_ptr->grid_array[y[b]][x[b]].o_idx_list.empty()) {
+    if (!grid_a.o_idx_list.empty() && grid_b.o_idx_list.empty()) {
         return true;
     }
 
-    if (player_ptr->current_floor_ptr->grid_array[y[a]][x[a]].o_idx_list.empty() && !player_ptr->current_floor_ptr->grid_array[y[b]][x[b]].o_idx_list.empty()) {
+    if (grid_a.o_idx_list.empty() && !grid_b.o_idx_list.empty()) {
         return false;
     }
 
     /* Priority from the terrain */
-    if (terrains_info[ca_ptr->feat].priority > terrains_info[cb_ptr->feat].priority) {
+    const auto &terrain_a = grid_a.get_terrain();
+    const auto &terrain_b = grid_b.get_terrain();
+    if (terrain_a.priority > terrain_b.priority) {
         return true;
     }
 
-    if (terrains_info[ca_ptr->feat].priority < terrains_info[cb_ptr->feat].priority) {
+    if (terrain_a.priority < terrain_b.priority) {
         return false;
     }
 
@@ -288,8 +292,8 @@ bool ang_sort_art_comp(PlayerType *player_ptr, vptr u, vptr v, int a, int b)
     /* Sort by monster level */
     if (*why >= 2) {
         /* Extract levels */
-        z1 = artifact_w1.bi_key.sval().value();
-        z2 = artifact_w2.bi_key.sval().value();
+        z1 = *artifact_w1.bi_key.sval();
+        z2 = *artifact_w2.bi_key.sval();
 
         /* Compare levels */
         if (z1 < z2) {
@@ -382,40 +386,40 @@ bool ang_sort_comp_pet(PlayerType *player_ptr, vptr u, vptr v, int a, int b)
     int w1 = who[a];
     int w2 = who[b];
 
-    MonsterEntity *m_ptr1 = &player_ptr->current_floor_ptr->m_list[w1];
-    MonsterEntity *m_ptr2 = &player_ptr->current_floor_ptr->m_list[w2];
-    MonsterRaceInfo *r_ptr1 = &monraces_info[m_ptr1->r_idx];
-    MonsterRaceInfo *r_ptr2 = &monraces_info[m_ptr2->r_idx];
+    const auto &monster1 = player_ptr->current_floor_ptr->m_list[w1];
+    const auto &monster2 = player_ptr->current_floor_ptr->m_list[w2];
+    const auto &monrace1 = monraces_info[monster1.r_idx];
+    const auto &monrace2 = monraces_info[monster2.r_idx];
 
-    if (m_ptr1->is_named() && !m_ptr2->is_named()) {
+    if (monster1.is_named() && !monster2.is_named()) {
         return true;
     }
 
-    if (m_ptr2->is_named() && !m_ptr1->is_named()) {
+    if (monster2.is_named() && !monster1.is_named()) {
         return false;
     }
 
-    if (r_ptr1->kind_flags.has(MonsterKindType::UNIQUE) && r_ptr2->kind_flags.has_not(MonsterKindType::UNIQUE)) {
+    if (monrace1.kind_flags.has(MonsterKindType::UNIQUE) && monrace2.kind_flags.has_not(MonsterKindType::UNIQUE)) {
         return true;
     }
 
-    if (r_ptr2->kind_flags.has(MonsterKindType::UNIQUE) && r_ptr1->kind_flags.has_not(MonsterKindType::UNIQUE)) {
+    if (monrace2.kind_flags.has(MonsterKindType::UNIQUE) && monrace1.kind_flags.has_not(MonsterKindType::UNIQUE)) {
         return false;
     }
 
-    if (r_ptr1->level > r_ptr2->level) {
+    if (monrace1.level > monrace2.level) {
         return true;
     }
 
-    if (r_ptr2->level > r_ptr1->level) {
+    if (monrace2.level > monrace1.level) {
         return false;
     }
 
-    if (m_ptr1->hp > m_ptr2->hp) {
+    if (monster1.hp > monster2.hp) {
         return true;
     }
 
-    if (m_ptr2->hp > m_ptr1->hp) {
+    if (monster2.hp > monster1.hp) {
         return false;
     }
 
@@ -589,10 +593,10 @@ bool ang_sort_comp_pet_dismiss(PlayerType *player_ptr, vptr u, vptr v, int a, in
     int w1 = who[a];
     int w2 = who[b];
 
-    MonsterEntity *m_ptr1 = &player_ptr->current_floor_ptr->m_list[w1];
-    MonsterEntity *m_ptr2 = &player_ptr->current_floor_ptr->m_list[w2];
-    MonsterRaceInfo *r_ptr1 = &monraces_info[m_ptr1->r_idx];
-    MonsterRaceInfo *r_ptr2 = &monraces_info[m_ptr2->r_idx];
+    const auto &monster1 = player_ptr->current_floor_ptr->m_list[w1];
+    const auto &monster2 = player_ptr->current_floor_ptr->m_list[w2];
+    const auto &monrace1 = monraces_info[monster1.r_idx];
+    const auto &monrace2 = monraces_info[monster2.r_idx];
 
     if (w1 == player_ptr->riding) {
         return true;
@@ -602,43 +606,43 @@ bool ang_sort_comp_pet_dismiss(PlayerType *player_ptr, vptr u, vptr v, int a, in
         return false;
     }
 
-    if (m_ptr1->is_named() && !m_ptr2->is_named()) {
+    if (monster1.is_named() && !monster2.is_named()) {
         return true;
     }
 
-    if (m_ptr2->is_named() && !m_ptr1->is_named()) {
+    if (monster2.is_named() && !monster1.is_named()) {
         return false;
     }
 
-    if (!m_ptr1->parent_m_idx && m_ptr2->parent_m_idx) {
+    if (!monster1.parent_m_idx && monster2.parent_m_idx) {
         return true;
     }
 
-    if (!m_ptr2->parent_m_idx && m_ptr1->parent_m_idx) {
+    if (!monster2.parent_m_idx && monster1.parent_m_idx) {
         return false;
     }
 
-    if (r_ptr1->kind_flags.has(MonsterKindType::UNIQUE) && r_ptr2->kind_flags.has_not(MonsterKindType::UNIQUE)) {
+    if (monrace1.kind_flags.has(MonsterKindType::UNIQUE) && monrace2.kind_flags.has_not(MonsterKindType::UNIQUE)) {
         return true;
     }
 
-    if (r_ptr2->kind_flags.has(MonsterKindType::UNIQUE) && r_ptr1->kind_flags.has_not(MonsterKindType::UNIQUE)) {
+    if (monrace2.kind_flags.has(MonsterKindType::UNIQUE) && monrace1.kind_flags.has_not(MonsterKindType::UNIQUE)) {
         return false;
     }
 
-    if (r_ptr1->level > r_ptr2->level) {
+    if (monrace1.level > monrace2.level) {
         return true;
     }
 
-    if (r_ptr2->level > r_ptr1->level) {
+    if (monrace2.level > monrace1.level) {
         return false;
     }
 
-    if (m_ptr1->hp > m_ptr2->hp) {
+    if (monster1.hp > monster2.hp) {
         return true;
     }
 
-    if (m_ptr2->hp > m_ptr1->hp) {
+    if (monster2.hp > monster1.hp) {
         return false;
     }
 
index 24de67b..b87282f 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 5f42c36..c5b3632 100644 (file)
@@ -1,4 +1,4 @@
-#include "util/string-processor.h"
+#include "util/string-processor.h"
 #include "util/int-char-converter.h"
 
 /*!
@@ -403,11 +403,11 @@ void ascii_to_text(char *buf, std::string_view sv, size_t bufsize)
  *
  * This function should be equivalent to the strlcpy() function in BSD.
  */
-size_t angband_strcpy(char *buf, concptr src, size_t bufsize)
+size_t angband_strcpy(char *buf, std::string_view src, size_t bufsize)
 {
 #ifdef JP
     char *d = buf;
-    concptr s = src;
+    const char *s = src.data();
     size_t len = 0;
 
     if (bufsize > 0) {
@@ -437,19 +437,18 @@ size_t angband_strcpy(char *buf, concptr src, size_t bufsize)
     return len;
 
 #else
-    size_t len = strlen(src);
-    size_t ret = len;
+    auto len = src.length();
     if (bufsize == 0) {
-        return ret;
+        return len;
     }
 
     if (len >= bufsize) {
         len = bufsize - 1;
     }
 
-    (void)memcpy(buf, src, len);
+    (void)src.copy(buf, len);
     buf[len] = '\0';
-    return ret;
+    return src.length();
 #endif
 }
 
@@ -464,13 +463,13 @@ size_t angband_strcpy(char *buf, concptr src, size_t bufsize)
  *
  * This function should be equivalent to the strlcat() function in BSD.
  */
-size_t angband_strcat(char *buf, concptr src, size_t bufsize)
+size_t angband_strcat(char *buf, std::string_view src, size_t bufsize)
 {
     size_t dlen = strlen(buf);
     if (dlen < bufsize - 1) {
         return dlen + angband_strcpy(buf + dlen, src, bufsize - dlen);
     } else {
-        return dlen + strlen(src);
+        return dlen + src.length();
     }
 }
 
@@ -479,23 +478,26 @@ size_t angband_strcat(char *buf, concptr src, size_t bufsize)
  *
  * angband_strstr() can handle Kanji strings correctly.
  */
-char *angband_strstr(concptr haystack, concptr needle)
+char *angband_strstr(const char *haystack, std::string_view needle)
 {
-    int l1 = strlen(haystack);
-    int l2 = strlen(needle);
+    std::string_view haystack_view(haystack);
+    auto l1 = haystack_view.length();
+    auto l2 = needle.length();
+    if (l1 < l2) {
+        return nullptr;
+    }
 
-    if (l1 >= l2) {
-        for (int i = 0; i <= l1 - l2; i++) {
-            if (!strncmp(haystack + i, needle, l2)) {
-                return (char *)haystack + i;
-            }
+    for (size_t i = 0; i <= l1 - l2; i++) {
+        const auto part = haystack_view.substr(i);
+        if (part.starts_with(needle)) {
+            return const_cast<char *>(haystack) + i;
+        }
 
 #ifdef JP
-            if (iskanji(*(haystack + i))) {
-                i++;
-            }
-#endif
+        if (iskanji(*(haystack + i))) {
+            i++;
         }
+#endif
     }
 
     return nullptr;
@@ -593,6 +595,16 @@ int strrncmp(const char *s1, const char *s2, int len)
     return 0;
 }
 
+/*
+ * @brief マルチバイト文字のダメ文字('\')を考慮しつつ文字列比較を行う
+ * @param src 比較元の文字列
+ * @param find 比較したい文字列
+ */
+bool str_find(const std::string &src, std::string_view find)
+{
+    return angband_strstr(src.data(), find) != nullptr;
+}
+
 /**
  * @brief 文字列の両端の空白を削除する
  *
@@ -798,7 +810,7 @@ static std::pair<size_t, size_t> adjust_substr_pos(std::string_view sv, size_t p
  */
 std::string str_substr(std::string_view sv, size_t pos, size_t n)
 {
-    const auto [mb_pos, mb_n] = adjust_substr_pos(sv, pos, n);
+    const auto &[mb_pos, mb_n] = adjust_substr_pos(sv, pos, n);
     return std::string(sv.substr(mb_pos, mb_n));
 }
 
@@ -817,7 +829,7 @@ std::string str_substr(std::string_view sv, size_t pos, size_t n)
  */
 std::string str_substr(std::string &&str, size_t pos, size_t n)
 {
-    const auto [mb_pos, mb_n] = adjust_substr_pos(str, pos, n);
+    const auto &[mb_pos, mb_n] = adjust_substr_pos(str, pos, n);
     str.erase(mb_pos + mb_n);
     str.erase(0, mb_pos);
     return std::move(str);
index 97034b6..fd49025 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
@@ -22,13 +22,14 @@ extern concptr macro_trigger_keycode[2][MAX_MACRO_TRIG];
 
 void text_to_ascii(char *buf, std::string_view sv, size_t bufsize);
 void ascii_to_text(char *buf, std::string_view sv, size_t bufsize);
-size_t angband_strcpy(char *buf, concptr src, size_t bufsize);
-size_t angband_strcat(char *buf, concptr src, size_t bufsize);
-char *angband_strstr(concptr haystack, concptr needle);
+size_t angband_strcpy(char *buf, std::string_view src, size_t bufsize);
+size_t angband_strcat(char *buf, std::string_view src, size_t bufsize);
+char *angband_strstr(const char *haystack, std::string_view needle);
 char *angband_strchr(concptr ptr, char ch);
 char *ltrim(char *p);
 char *rtrim(char *p);
 int strrncmp(const char *s1, const char *s2, int len);
+bool str_find(const std::string &src, std::string_view find);
 std::string str_trim(std::string_view str);
 std::string str_rtrim(std::string_view str);
 std::string str_ltrim(std::string_view str);
index 7312876..6398460 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-birth.h"
+#include "view/display-birth.h"
 #include "birth/auto-roller.h"
 #include "birth/birth-stat.h"
 #include "game-option/birth-options.h"
index b038c6d..dfa00c9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void birth_put_stats(PlayerType *player_ptr);
index 4087e51..5f625c6 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief キャラクタの特性を表示する
  * @date 2020/02/25
  * @author Hourier
@@ -12,7 +12,6 @@
 #include "object-enchant/special-object-flags.h"
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trc-types.h"
-#include "object/object-flags.h"
 #include "perception/object-perception.h"
 #include "player/permanent-resistances.h"
 #include "player/race-resistances.h"
@@ -110,7 +109,7 @@ static void process_cursed_equipment_characteristics(PlayerType *player_ptr, uin
         auto *o_ptr = &player_ptr->inventory_list[i];
         auto is_known = o_ptr->is_known();
         auto is_sensed = is_known || o_ptr->ident & IDENT_SENSE;
-        auto flags = object_flags_known(o_ptr);
+        auto flags = o_ptr->get_flags_known();
 
         if (flags.has(TR_ADD_L_CURSE) || flags.has(TR_ADD_H_CURSE)) {
             if (is_known) {
@@ -157,7 +156,7 @@ static void process_light_equipment_characteristics(PlayerType *player_ptr, all_
     int max_i = (mode & DP_WP) ? INVEN_BOW + 1 : INVEN_TOTAL;
     for (int i = INVEN_MAIN_HAND; i < max_i; i++) {
         auto *o_ptr = &player_ptr->inventory_list[i];
-        auto flags = object_flags_known(o_ptr);
+        auto flags = o_ptr->get_flags_known();
 
         auto b = false;
         for (auto flg : lite_flags) {
@@ -206,7 +205,7 @@ static void process_inventory_characteristic(PlayerType *player_ptr, tr_type fla
     int max_i = (mode & DP_WP) ? INVEN_BOW + 1 : INVEN_TOTAL;
     for (int i = INVEN_MAIN_HAND; i < max_i; i++) {
         auto *o_ptr = &player_ptr->inventory_list[i];
-        auto flags = object_flags_known(o_ptr);
+        auto flags = o_ptr->get_flags_known();
 
         auto f_imm = flag_to_greater_flag.find(flag);
         if (f_imm != flag_to_greater_flag.end()) {
@@ -302,7 +301,7 @@ static void process_one_characteristic(PlayerType *player_ptr, TERM_LEN row, TER
         }
     }
 
-    c_put_str(row_clr, header.data(), row, col);
+    c_put_str(row_clr, header, row, col);
     col += header.length() + 1;
 
     for (auto s : char_stat.syms) {
@@ -316,7 +315,7 @@ static void process_one_characteristic(PlayerType *player_ptr, TERM_LEN row, TER
         if (s == "." && (!char_stat.has_imm && !char_stat.has_vul)) {
             clr = TERM_L_DARK;
         }
-        c_put_str(clr, s.data(), row, col++);
+        c_put_str(clr, s, row, col++);
     }
 }
 
index d4ce241..ab0fcd1 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index fbb12b4..562ab73 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-fruit.h"
+#include "view/display-fruit.h"
 #include "system/angband.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
index 9391685..18652d2 100644 (file)
@@ -1,3 +1,3 @@
-#pragma once
+#pragma once
 
 void display_fruit(int row, int col, int fruit);
index 94018a1..ed89328 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-inventory.h"
+#include "view/display-inventory.h"
 #include "flavor/flavor-describer.h"
 #include "game-option/special-options.h"
 #include "game-option/text-display-options.h"
@@ -32,16 +32,15 @@ COMMAND_CODE show_inventory(PlayerType *player_ptr, int target_item, BIT_FLAGS m
     int k, l, z = 0;
     ItemEntity *o_ptr;
     char tmp_val[80];
-    COMMAND_CODE out_index[23];
-    TERM_COLOR out_color[23];
+    COMMAND_CODE out_index[23]{};
+    TERM_COLOR out_color[23]{};
     std::array<std::string, 23> out_desc{};
     COMMAND_CODE target_item_label = 0;
     char inven_label[52 + 1];
 
-    int col = command_gap;
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-    int len = wid - col - 1;
+    auto col = command_gap;
+    const auto &[wid, hgt] = term_get_size();
+    auto len = wid - col - 1;
     for (i = 0; i < INVEN_PACK; i++) {
         o_ptr = &player_ptr->inventory_list[i];
         if (!o_ptr->is_valid()) {
@@ -142,14 +141,11 @@ void display_inventory(PlayerType *player_ptr, const ItemTester &item_tester)
     int i, z = 0;
     TERM_COLOR attr = TERM_WHITE;
     char tmp_val[80];
-    TERM_LEN wid, hgt;
-
     if (!player_ptr || !player_ptr->inventory_list) {
         return;
     }
 
-    term_get_size(&wid, &hgt);
-
+    const auto &[wid, hgt] = term_get_size();
     for (i = 0; i < INVEN_PACK; i++) {
         auto o_ptr = &player_ptr->inventory_list[i];
         if (!o_ptr->is_valid()) {
@@ -172,7 +168,7 @@ void display_inventory(PlayerType *player_ptr, const ItemTester &item_tester)
         }
 
         int cur_col = 3;
-        term_erase(cur_col, i, 255);
+        term_erase(cur_col, i);
         term_putstr(0, i, cur_col, TERM_WHITE, tmp_val);
         const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
         attr = tval_to_attr[enum2i(o_ptr->bi_key.tval()) % 128];
@@ -203,6 +199,6 @@ void display_inventory(PlayerType *player_ptr, const ItemTester &item_tester)
     }
 
     for (i = z; i < hgt; i++) {
-        term_erase(0, i, 255);
+        term_erase(0, i);
     }
 }
index 99adb48..ba3b08b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 3e8dc60..2cefd41 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-lore-attacks.h"
+#include "view/display-lore-attacks.h"
 #include "locale/japanese.h"
 #include "lore/combat-types-setter.h"
 #include "lore/lore-calculator.h"
@@ -35,23 +35,22 @@ static void display_monster_blow_jp(lore_type *lore_ptr, int attack_numbers, int
 
     /* XXしてYYし/XXしてYYする/XXし/XXする */
     if (lore_ptr->q != nullptr) {
-        jverb(lore_ptr->p, lore_ptr->jverb_buf, JVERB_TO);
+        const auto verb = conjugate_jverb(lore_ptr->p, JVerbConjugationType::TO);
+        hook_c_roff(lore_ptr->pc, verb);
     } else if (attack_numbers != lore_ptr->count - 1) {
-        jverb(lore_ptr->p, lore_ptr->jverb_buf, JVERB_AND);
+        const auto verb = conjugate_jverb(lore_ptr->p, JVerbConjugationType::AND);
+        hook_c_roff(lore_ptr->pc, verb);
     } else {
-        strcpy(lore_ptr->jverb_buf, lore_ptr->p);
+        hook_c_roff(lore_ptr->pc, lore_ptr->p);
     }
 
-    hook_c_roff(lore_ptr->pc, lore_ptr->jverb_buf);
-
     if (lore_ptr->q) {
         if (attack_numbers != lore_ptr->count - 1) {
-            jverb(lore_ptr->q, lore_ptr->jverb_buf, JVERB_AND);
+            const auto verb = conjugate_jverb(lore_ptr->q, JVerbConjugationType::AND);
+            hook_c_roff(lore_ptr->qc, verb);
         } else {
-            strcpy(lore_ptr->jverb_buf, lore_ptr->q);
+            hook_c_roff(lore_ptr->qc, lore_ptr->q);
         }
-
-        hook_c_roff(lore_ptr->qc, lore_ptr->jverb_buf);
     }
 
     if (attack_numbers != lore_ptr->count - 1) {
@@ -102,8 +101,8 @@ static void display_monster_blow_en(lore_type *lore_ptr, int attack_numbers, int
  */
 void display_monster_blow(lore_type *lore_ptr, int m, int attack_numbers)
 {
-    int d1 = lore_ptr->r_ptr->blow[m].d_dice;
-    int d2 = lore_ptr->r_ptr->blow[m].d_side;
+    int d1 = lore_ptr->r_ptr->blows[m].d_dice;
+    int d2 = lore_ptr->r_ptr->blows[m].d_side;
     void (*display_monster_blows_pf)(lore_type *, int, int, int, int) = _(display_monster_blow_jp, display_monster_blow_en);
     (*display_monster_blows_pf)(lore_ptr, attack_numbers, d1, d2, m);
 }
@@ -116,7 +115,7 @@ void display_monster_blows(lore_type *lore_ptr)
 {
     const int max_attack_numbers = 4;
     for (int m = 0; m < max_attack_numbers; m++) {
-        if (lore_ptr->r_ptr->blow[m].method == RaceBlowMethodType::NONE || (lore_ptr->r_ptr->blow[m].method == RaceBlowMethodType::SHOOT)) {
+        if (lore_ptr->r_ptr->blows[m].method == RaceBlowMethodType::NONE || (lore_ptr->r_ptr->blows[m].method == RaceBlowMethodType::SHOOT)) {
             continue;
         }
 
@@ -127,7 +126,7 @@ void display_monster_blows(lore_type *lore_ptr)
 
     int attack_numbers = 0;
     for (int m = 0; m < max_attack_numbers; m++) {
-        if (lore_ptr->r_ptr->blow[m].method == RaceBlowMethodType::NONE || (lore_ptr->r_ptr->blow[m].method == RaceBlowMethodType::SHOOT) || (((lore_ptr->r_ptr->r_blows[m] == 0) && !lore_ptr->know_everything))) {
+        if (lore_ptr->r_ptr->blows[m].method == RaceBlowMethodType::NONE || (lore_ptr->r_ptr->blows[m].method == RaceBlowMethodType::SHOOT) || (((lore_ptr->r_ptr->r_blows[m] == 0) && !lore_ptr->know_everything))) {
             continue;
         }
 
index bee4580..146dff8 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct lore_type;
 void display_monster_blows(lore_type *lore_ptr);
index f6aae39..f381124 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-lore-drops.h"
+#include "view/display-lore-drops.h"
 #include "lore/lore-util.h"
 #include "monster-race/race-flags1.h"
 #include "util/bit-flags-calculator.h"
index c311543..febbf16 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct lore_type;
 void display_monster_drop_quantity(lore_type *lore_ptr);
index 11b851c..d4bc6c9 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-lore-magics.h"
+#include "view/display-lore-magics.h"
 #include "lore/lore-util.h"
 #include "monster-race/race-flags2.h"
 #include "system/monster-race-info.h"
index 8b0b786..c398c70 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct lore_type;
 void display_monster_breath(lore_type *lore_ptr);
index 1150ef9..51a02a0 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-lore-status.h"
+#include "view/display-lore-status.h"
 #include "locale/japanese.h"
 #include "lore/lore-calculator.h"
 #include "lore/lore-util.h"
@@ -102,8 +102,8 @@ void display_monster_abilities(lore_type *lore_ptr)
     for (int n = 0; n < lore_ptr->vn; n++) {
 #ifdef JP
         if (n != lore_ptr->vn - 1) {
-            jverb(lore_ptr->vp[n], lore_ptr->jverb_buf, JVERB_AND);
-            hook_c_roff(lore_ptr->color[n], lore_ptr->jverb_buf);
+            const auto verb = conjugate_jverb(lore_ptr->vp[n], JVerbConjugationType::AND);
+            hook_c_roff(lore_ptr->color[n], verb);
             hooked_roff("、");
         } else {
             hook_c_roff(lore_ptr->color[n], lore_ptr->vp[n]);
@@ -312,6 +312,11 @@ void display_monster_concrete_resistances(lore_type *lore_ptr)
         lore_ptr->color[lore_ptr->vn++] = TERM_SLATE;
     }
 
+    if (lore_ptr->resistance_flags.has(MonsterResistanceType::RESIST_METEOR)) {
+        lore_ptr->vp[lore_ptr->vn] = _("隕石", "meteor");
+        lore_ptr->color[lore_ptr->vn++] = TERM_UMBER;
+    }
+
     if (lore_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
         lore_ptr->vp[lore_ptr->vn] = _("あらゆる攻撃", "all");
         lore_ptr->color[lore_ptr->vn++] = TERM_YELLOW;
@@ -368,22 +373,22 @@ void display_monster_evolution(lore_type *lore_ptr)
 
 void display_monster_concrete_immunities(lore_type *lore_ptr)
 {
-    if (lore_ptr->flags3 & RF3_NO_STUN) {
+    if (lore_ptr->resistance_flags.has(MonsterResistanceType::NO_STUN)) {
         lore_ptr->vp[lore_ptr->vn] = _("朦朧としない", "stunned");
         lore_ptr->color[lore_ptr->vn++] = TERM_ORANGE;
     }
 
-    if (lore_ptr->flags3 & RF3_NO_FEAR) {
+    if (lore_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
         lore_ptr->vp[lore_ptr->vn] = _("恐怖を感じない", "frightened");
         lore_ptr->color[lore_ptr->vn++] = TERM_SLATE;
     }
 
-    if (lore_ptr->flags3 & RF3_NO_CONF) {
+    if (lore_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
         lore_ptr->vp[lore_ptr->vn] = _("混乱しない", "confused");
         lore_ptr->color[lore_ptr->vn++] = TERM_L_UMBER;
     }
 
-    if (lore_ptr->flags3 & RF3_NO_SLEEP) {
+    if (lore_ptr->resistance_flags.has(MonsterResistanceType::NO_SLEEP)) {
         lore_ptr->vp[lore_ptr->vn] = _("眠らされない", "slept");
         lore_ptr->color[lore_ptr->vn++] = TERM_BLUE;
     }
@@ -392,6 +397,11 @@ void display_monster_concrete_immunities(lore_type *lore_ptr)
         lore_ptr->vp[lore_ptr->vn] = _("テレポートされない", "teleported");
         lore_ptr->color[lore_ptr->vn++] = TERM_ORANGE;
     }
+
+    if (lore_ptr->resistance_flags.has(MonsterResistanceType::NO_INSTANTLY_DEATH) || lore_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
+        lore_ptr->vp[lore_ptr->vn] = _("即死しない", "instantly killed");
+        lore_ptr->color[lore_ptr->vn++] = TERM_L_DARK;
+    }
 }
 
 void display_monster_immunities(lore_type *lore_ptr)
index a798d04..4d0e21b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct lore_type;
 void display_monster_hp_ac(lore_type *lore_ptr);
index f26926a..be51ea9 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief モンスターの思い出を表示する処理
  * @date 2020/06/09
  * @author Hourier
@@ -49,7 +49,7 @@ void roff_top(MonsterRaceId r_idx)
     TERM_COLOR a1 = r_ptr->d_attr;
     TERM_COLOR a2 = r_ptr->x_attr;
 
-    term_erase(0, 0, 255);
+    term_erase(0, 0);
     term_gotoxy(0, 0);
 
 #ifdef JP
@@ -65,7 +65,7 @@ void roff_top(MonsterRaceId r_idx)
         term_addstr(-1, TERM_WHITE, "] ");
     }
 
-    term_addstr(-1, TERM_WHITE, (r_ptr->name.data()));
+    term_addstr(-1, TERM_WHITE, r_ptr->name);
 
     term_addstr(-1, TERM_WHITE, " ('");
     term_add_bigch(a1, c1);
@@ -85,7 +85,7 @@ void roff_top(MonsterRaceId r_idx)
 void screen_roff(PlayerType *player_ptr, MonsterRaceId r_idx, monster_lore_mode mode)
 {
     msg_erase();
-    term_erase(0, 1, 255);
+    term_erase(0, 1);
     hook_c_roff = c_roff;
     process_monster_lore(player_ptr, r_idx, mode);
     roff_top(r_idx);
@@ -99,7 +99,7 @@ void screen_roff(PlayerType *player_ptr, MonsterRaceId r_idx, monster_lore_mode
 void display_roff(PlayerType *player_ptr)
 {
     for (int y = 0; y < game_term->hgt; y++) {
-        term_erase(0, y, 255);
+        term_erase(0, y);
     }
 
     term_gotoxy(0, 1);
@@ -536,11 +536,18 @@ static void display_monster_escort_contents(lore_type *lore_ptr)
 
 #ifdef JP
 #else
-    hooked_roff(" contain ");
+    hooked_roff(" contain");
+    auto max_idx = lore_ptr->r_ptr->reinforces.size() - 1;
+    auto idx = 0 * max_idx;
 #endif
 
     for (auto [r_idx, dd, ds] : lore_ptr->r_ptr->reinforces) {
         auto is_reinforced = MonsterRace(r_idx).is_valid();
+#ifndef JP
+        const char *prefix = (idx == 0) ? " " : (idx == max_idx) ? " and "
+                                                                 : ", ";
+        ++idx;
+#endif
         is_reinforced &= dd > 0;
         is_reinforced &= ds > 0;
         if (!is_reinforced) {
@@ -549,7 +556,7 @@ static void display_monster_escort_contents(lore_type *lore_ptr)
 
         const auto *rf_ptr = &monraces_info[r_idx];
         if (rf_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
-            hooked_roff(format(_("、%s", ", %s"), rf_ptr->name.data()));
+            hooked_roff(format("%s%s", _("、", prefix), rf_ptr->name.data()));
             continue;
         }
 
@@ -562,11 +569,11 @@ static void display_monster_escort_contents(lore_type *lore_ptr)
         if (plural) {
             plural_aux(name);
         }
-        hooked_roff(format(",%dd%d %s", dd, ds, name));
+        hooked_roff(format("%s%dd%d %s", prefix, dd, ds, name));
 #endif
     }
 
-    hooked_roff(_("で成り立っている。", "."));
+    hooked_roff(_("で成り立っている。", ".  "));
 }
 
 void display_monster_collective(lore_type *lore_ptr)
@@ -606,11 +613,11 @@ void display_monster_launching(PlayerType *player_ptr, lore_type *lore_ptr)
     int n = 0; /* Number of blows */
     const int max_blows = 4;
     for (int m = 0; m < max_blows; m++) {
-        if (lore_ptr->r_ptr->blow[m].method != RaceBlowMethodType::NONE) {
+        if (lore_ptr->r_ptr->blows[m].method != RaceBlowMethodType::NONE) {
             n++;
         } /* Count blows */
 
-        if (lore_ptr->r_ptr->blow[m].method == RaceBlowMethodType::SHOOT) {
+        if (lore_ptr->r_ptr->blows[m].method == RaceBlowMethodType::SHOOT) {
             p = m; /* Remember position */
             break;
         }
@@ -626,8 +633,8 @@ void display_monster_launching(PlayerType *player_ptr, lore_type *lore_ptr)
     }
 
     if (know_armour(lore_ptr->r_idx, lore_ptr->know_everything)) {
-        strnfmt(lore_ptr->tmp_msg[lore_ptr->vn], sizeof(lore_ptr->tmp_msg[lore_ptr->vn]), _("威力 %dd%d の射撃をする", "fire an arrow (Power:%dd%d)"), lore_ptr->r_ptr->blow[p].d_dice,
-            lore_ptr->r_ptr->blow[p].d_side);
+        strnfmt(lore_ptr->tmp_msg[lore_ptr->vn], sizeof(lore_ptr->tmp_msg[lore_ptr->vn]), _("威力 %dd%d の射撃をする", "fire an arrow (Power:%dd%d)"), lore_ptr->r_ptr->blows[p].d_dice,
+            lore_ptr->r_ptr->blows[p].d_side);
     } else {
         angband_strcpy(lore_ptr->tmp_msg[lore_ptr->vn], _("射撃をする", "fire an arrow"), sizeof(lore_ptr->tmp_msg[lore_ptr->vn]));
     }
@@ -647,8 +654,8 @@ void display_monster_sometimes(lore_type *lore_ptr)
     for (int n = 0; n < lore_ptr->vn; n++) {
 #ifdef JP
         if (n != lore_ptr->vn - 1) {
-            jverb(lore_ptr->vp[n], lore_ptr->jverb_buf, JVERB_OR);
-            hook_c_roff(lore_ptr->color[n], lore_ptr->jverb_buf);
+            const auto verb = conjugate_jverb(lore_ptr->vp[n], JVerbConjugationType::OR);
+            hook_c_roff(lore_ptr->color[n], verb);
             hook_c_roff(lore_ptr->color[n], "り");
             hooked_roff("、");
         } else {
index 5126c9f..c02d7d3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "lore/lore-util.h"
 #include "system/angband.h"
index beabda5..2fde7a1 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-map.h"
+#include "view/display-map.h"
 #include "autopick/autopick-finder.h"
 #include "autopick/autopick-methods-table.h"
 #include "autopick/autopick-util.h"
 #include "util/bit-flags-calculator.h"
 #include "window/main-window-util.h"
 #include "world/world.h"
+#include <span>
 
 byte display_autopick; /*!< 自動拾い状態の設定フラグ */
 
+namespace {
 /* 一般的にオブジェクトシンボルとして扱われる記号を定義する(幻覚処理向け) /  Hack -- Legal object codes */
-char image_object_hack[MAX_IMAGE_OBJECT_HACK] = "?/|\\\"!$()_-=[]{},~";
+const std::string image_objects = R"(?/|\"!$()_-=[]{},~)";
 
 /* 一般的にモンスターシンボルとして扱われる記号を定義する(幻覚処理向け) / Hack -- Legal monster codes */
-char image_monster_hack[MAX_IMAGE_MONSTER_HACK] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+const std::string image_monsters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+}
 
 /*!
  * @brief オブジェクトの表示を幻覚状態に差し替える / Hallucinatory object
@@ -51,8 +54,7 @@ static void image_object(TERM_COLOR *ap, char *cp)
         return;
     }
 
-    size_t n = sizeof(image_object_hack) - 1;
-    *cp = image_object_hack[randint0(n)];
+    *cp = rand_choice(image_objects);
     *ap = randint1(15);
 }
 
@@ -71,7 +73,7 @@ static void image_monster(TERM_COLOR *ap, char *cp)
         return;
     }
 
-    *cp = (one_in_(25) ? image_object_hack[randint0(sizeof(image_object_hack) - 1)] : image_monster_hack[randint0(sizeof(image_monster_hack) - 1)]);
+    *cp = one_in_(25) ? rand_choice(image_objects) : rand_choice(image_monsters);
     *ap = randint1(15);
 }
 
@@ -92,7 +94,6 @@ static void image_random(TERM_COLOR *ap, char *cp)
 /*!
  * @brief マップに表示されるべき地形(壁)かどうかを判定する
  * @param floor_ptr 階の情報への参照ポインタ
- * @param f_ptr 地形の情報への参照ポインタ
  * @param y グリッドy座標
  * @param x グリッドx座標
  * @return 表示されるべきならtrue、そうでないならfalse
@@ -100,46 +101,50 @@ static void image_random(TERM_COLOR *ap, char *cp)
  * 周り全てが壁に囲まれている壁についてはオプション状態による。
  * 1か所でも空きがあるか、壁ではない地形、金を含む地形、永久岩は表示。
  */
-static bool is_revealed_wall(FloorType *floor_ptr, TerrainType *f_ptr, POSITION y, POSITION x)
+static bool is_revealed_wall(FloorType *floor_ptr, int y, int x)
 {
+    const auto &grid = floor_ptr->grid_array[y][x];
     if (view_hidden_walls) {
         if (view_unsafe_walls) {
             return true;
         }
-        if (none_bits(floor_ptr->grid_array[y][x].info, CAVE_UNSAFE)) {
+        if (none_bits(grid.info, CAVE_UNSAFE)) {
             return true;
         }
     }
 
-    if (f_ptr->flags.has_not(TerrainCharacteristics::WALL) || f_ptr->flags.has(TerrainCharacteristics::HAS_GOLD)) {
+    const auto &terrain = grid.get_terrain_mimic();
+    if (terrain.flags.has_not(TerrainCharacteristics::WALL) || terrain.flags.has(TerrainCharacteristics::HAS_GOLD)) {
         return true;
     }
 
-    if (in_bounds(floor_ptr, y, x) && f_ptr->flags.has(TerrainCharacteristics::PERMANENT)) {
+    if (in_bounds(floor_ptr, y, x) && terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
         return true;
     }
 
-    int n = 0;
-    for (int i = 0; i < 8; i++) {
-        int dy = y + ddy_cdd[i];
-        int dx = x + ddx_cdd[i];
+    constexpr auto neighbors = 8;
+    const auto &terrains = TerrainList::get_instance();
+    auto n = 0;
+    for (auto i = 0; i < neighbors; i++) {
+        const auto dy = y + ddy_cdd[i];
+        const auto dx = x + ddx_cdd[i];
         if (!in_bounds(floor_ptr, dy, dx)) {
             n++;
             continue;
         }
 
-        FEAT_IDX f_idx = floor_ptr->grid_array[dy][dx].feat;
-        TerrainType *n_ptr = &terrains_info[f_idx];
-        if (n_ptr->flags.has(TerrainCharacteristics::WALL)) {
+        const auto terrain_id = floor_ptr->grid_array[dy][dx].feat;
+        const auto &terrain_neighbor = terrains[terrain_id];
+        if (terrain_neighbor.flags.has(TerrainCharacteristics::WALL)) {
             n++;
         }
     }
 
-    return n != 8;
+    return n != neighbors;
 }
 
 /*!
- * @brief 指定した座標の地形の表示属性を取得する / Extract the attr/char to display at the given (legal) map location
+ * @brief 指定した座標の地形の表示属性を取得する
  * @param player_ptr プレイヤー情報への参照ポインタ
  * @param y 階の中のy座標
  * @param x 階の中のy座標
@@ -147,107 +152,109 @@ static bool is_revealed_wall(FloorType *floor_ptr, TerrainType *f_ptr, POSITION
  * @param cp 文字種属性
  * @param tap 文字色属性(タイル)
  * @param tcp 文字種属性(タイル)
+ * @todo 強力発動コピペの嵐…ポインタ引数の嵐……Fuuu^h^hck!!
  */
 void map_info(PlayerType *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, char *cp, TERM_COLOR *tap, char *tcp)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    auto *g_ptr = &floor_ptr->grid_array[y][x];
-    FEAT_IDX feat = g_ptr->get_feat_mimic();
-    auto *f_ptr = &terrains_info[feat];
+    auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(y, x);
+    auto &grid = floor.get_grid(pos);
+    auto &terrains = TerrainList::get_instance();
+    auto *terrain_mimic_ptr = &grid.get_terrain_mimic();
     TERM_COLOR a;
     char c;
-    if (f_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
-        auto is_visible = any_bits(g_ptr->info, (CAVE_MARK | CAVE_LITE | CAVE_MNLT));
-        auto is_glowing = match_bits(g_ptr->info, CAVE_GLOW | CAVE_MNDK, CAVE_GLOW);
-        auto can_view = g_ptr->is_view() && (is_glowing || player_ptr->see_nocto);
+    if (terrain_mimic_ptr->flags.has_not(TerrainCharacteristics::REMEMBER)) {
+        auto is_visible = any_bits(grid.info, (CAVE_MARK | CAVE_LITE | CAVE_MNLT));
+        auto is_glowing = match_bits(grid.info, CAVE_GLOW | CAVE_MNDK, CAVE_GLOW);
+        auto can_view = grid.is_view() && (is_glowing || player_ptr->see_nocto);
         const auto is_blind = player_ptr->effects()->blindness()->is_blind();
         if (!is_blind && (is_visible || can_view)) {
-            a = f_ptr->x_attr[F_LIT_STANDARD];
-            c = f_ptr->x_char[F_LIT_STANDARD];
+            a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
+            c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
             if (player_ptr->wild_mode) {
-                if (view_special_lite && !is_daytime()) {
-                    a = f_ptr->x_attr[F_LIT_DARK];
-                    c = f_ptr->x_char[F_LIT_DARK];
+                if (view_special_lite && !w_ptr->is_daytime()) {
+                    a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                    c = terrain_mimic_ptr->x_char[F_LIT_DARK];
                 }
-            } else if (darkened_grid(player_ptr, g_ptr)) {
-                feat = (view_unsafe_grids && (g_ptr->info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
-                f_ptr = &terrains_info[feat];
-                a = f_ptr->x_attr[F_LIT_STANDARD];
-                c = f_ptr->x_char[F_LIT_STANDARD];
+            } else if (darkened_grid(player_ptr, &grid)) {
+                const auto unsafe_terrain_id = (view_unsafe_grids && (grid.info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
+                terrain_mimic_ptr = &terrains[unsafe_terrain_id];
+                a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
+                c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
             } else if (view_special_lite) {
-                if (g_ptr->info & (CAVE_LITE | CAVE_MNLT)) {
+                if (grid.info & (CAVE_LITE | CAVE_MNLT)) {
                     if (view_yellow_lite) {
-                        a = f_ptr->x_attr[F_LIT_LITE];
-                        c = f_ptr->x_char[F_LIT_LITE];
+                        a = terrain_mimic_ptr->x_attr[F_LIT_LITE];
+                        c = terrain_mimic_ptr->x_char[F_LIT_LITE];
                     }
-                } else if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
-                    a = f_ptr->x_attr[F_LIT_DARK];
-                    c = f_ptr->x_char[F_LIT_DARK];
-                } else if (!(g_ptr->info & CAVE_VIEW)) {
+                } else if ((grid.info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
+                    a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                    c = terrain_mimic_ptr->x_char[F_LIT_DARK];
+                } else if (!(grid.info & CAVE_VIEW)) {
                     if (view_bright_lite) {
-                        a = f_ptr->x_attr[F_LIT_DARK];
-                        c = f_ptr->x_char[F_LIT_DARK];
+                        a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                        c = terrain_mimic_ptr->x_char[F_LIT_DARK];
                     }
                 }
             }
         } else {
-            feat = (view_unsafe_grids && (g_ptr->info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
-            f_ptr = &terrains_info[feat];
-            a = f_ptr->x_attr[F_LIT_STANDARD];
-            c = f_ptr->x_char[F_LIT_STANDARD];
+            const auto unsafe_terrain_id = (view_unsafe_grids && (grid.info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
+            terrain_mimic_ptr = &terrains[unsafe_terrain_id];
+            a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
+            c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
         }
     } else {
-        if (g_ptr->is_mark() && is_revealed_wall(floor_ptr, f_ptr, y, x)) {
-            a = f_ptr->x_attr[F_LIT_STANDARD];
-            c = f_ptr->x_char[F_LIT_STANDARD];
+        if (grid.is_mark() && is_revealed_wall(&floor, y, x)) {
+            a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
+            c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
             const auto is_blind = player_ptr->effects()->blindness()->is_blind();
             if (player_ptr->wild_mode) {
-                if (view_granite_lite && (is_blind || !is_daytime())) {
-                    a = f_ptr->x_attr[F_LIT_DARK];
-                    c = f_ptr->x_char[F_LIT_DARK];
+                if (view_granite_lite && (is_blind || !w_ptr->is_daytime())) {
+                    a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                    c = terrain_mimic_ptr->x_char[F_LIT_DARK];
                 }
-            } else if (darkened_grid(player_ptr, g_ptr) && !is_blind) {
-                if (f_ptr->flags.has_all_of({ TerrainCharacteristics::LOS, TerrainCharacteristics::PROJECT })) {
-                    feat = (view_unsafe_grids && (g_ptr->info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
-                    f_ptr = &terrains_info[feat];
-                    a = f_ptr->x_attr[F_LIT_STANDARD];
-                    c = f_ptr->x_char[F_LIT_STANDARD];
+            } else if (darkened_grid(player_ptr, &grid) && !is_blind) {
+                if (terrain_mimic_ptr->flags.has_all_of({ TerrainCharacteristics::LOS, TerrainCharacteristics::PROJECT })) {
+                    const auto unsafe_terrain_id = (view_unsafe_grids && (grid.info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
+                    terrain_mimic_ptr = &terrains[unsafe_terrain_id];
+                    a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
+                    c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
                 } else if (view_granite_lite && view_bright_lite) {
-                    a = f_ptr->x_attr[F_LIT_DARK];
-                    c = f_ptr->x_char[F_LIT_DARK];
+                    a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                    c = terrain_mimic_ptr->x_char[F_LIT_DARK];
                 }
             } else if (view_granite_lite) {
                 if (is_blind) {
-                    a = f_ptr->x_attr[F_LIT_DARK];
-                    c = f_ptr->x_char[F_LIT_DARK];
-                } else if (g_ptr->info & (CAVE_LITE | CAVE_MNLT)) {
+                    a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                    c = terrain_mimic_ptr->x_char[F_LIT_DARK];
+                } else if (grid.info & (CAVE_LITE | CAVE_MNLT)) {
                     if (view_yellow_lite) {
-                        a = f_ptr->x_attr[F_LIT_LITE];
-                        c = f_ptr->x_char[F_LIT_LITE];
+                        a = terrain_mimic_ptr->x_attr[F_LIT_LITE];
+                        c = terrain_mimic_ptr->x_char[F_LIT_LITE];
                     }
                 } else if (view_bright_lite) {
-                    if (!(g_ptr->info & CAVE_VIEW)) {
-                        a = f_ptr->x_attr[F_LIT_DARK];
-                        c = f_ptr->x_char[F_LIT_DARK];
-                    } else if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
-                        a = f_ptr->x_attr[F_LIT_DARK];
-                        c = f_ptr->x_char[F_LIT_DARK];
-                    } else if (f_ptr->flags.has_not(TerrainCharacteristics::LOS) && !check_local_illumination(player_ptr, y, x)) {
-                        a = f_ptr->x_attr[F_LIT_DARK];
-                        c = f_ptr->x_char[F_LIT_DARK];
+                    if (!(grid.info & CAVE_VIEW)) {
+                        a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                        c = terrain_mimic_ptr->x_char[F_LIT_DARK];
+                    } else if ((grid.info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
+                        a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                        c = terrain_mimic_ptr->x_char[F_LIT_DARK];
+                    } else if (terrain_mimic_ptr->flags.has_not(TerrainCharacteristics::LOS) && !check_local_illumination(player_ptr, y, x)) {
+                        a = terrain_mimic_ptr->x_attr[F_LIT_DARK];
+                        c = terrain_mimic_ptr->x_char[F_LIT_DARK];
                     }
                 }
             }
         } else {
-            feat = (view_unsafe_grids && (g_ptr->info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
-            f_ptr = &terrains_info[feat];
-            a = f_ptr->x_attr[F_LIT_STANDARD];
-            c = f_ptr->x_char[F_LIT_STANDARD];
+            const auto unsafe_terrain_id = (view_unsafe_grids && (grid.info & CAVE_UNSAFE)) ? feat_undetected : feat_none;
+            terrain_mimic_ptr = &terrains[unsafe_terrain_id];
+            a = terrain_mimic_ptr->x_attr[F_LIT_STANDARD];
+            c = terrain_mimic_ptr->x_char[F_LIT_STANDARD];
         }
     }
 
     if (feat_priority == -1) {
-        feat_priority = f_ptr->priority;
+        feat_priority = terrain_mimic_ptr->priority;
     }
 
     (*tap) = a;
@@ -260,9 +267,9 @@ void map_info(PlayerType *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, ch
         image_random(ap, cp);
     }
 
-    for (const auto this_o_idx : g_ptr->o_idx_list) {
+    for (const auto this_o_idx : grid.o_idx_list) {
         ItemEntity *o_ptr;
-        o_ptr = &floor_ptr->o_list[this_o_idx];
+        o_ptr = &floor.o_list[this_o_idx];
         if (o_ptr->marked.has_not(OmType::FOUND)) {
             continue;
         }
@@ -295,18 +302,18 @@ void map_info(PlayerType *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, ch
         break;
     }
 
-    if (g_ptr->m_idx && display_autopick != 0) {
+    if (grid.m_idx && display_autopick != 0) {
         set_term_color(player_ptr, y, x, ap, cp);
         return;
     }
 
-    auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
+    auto *m_ptr = &floor.m_list[grid.m_idx];
     if (!m_ptr->ml) {
         set_term_color(player_ptr, y, x, ap, cp);
         return;
     }
 
-    auto *r_ptr = &monraces_info[m_ptr->ap_r_idx];
+    auto *r_ptr = &m_ptr->get_appearance_monrace();
     feat_priority = 30;
     if (is_hallucinated) {
         if (r_ptr->visual_flags.has_all_of({ MonsterVisualType::CLEAR, MonsterVisualType::CLEAR_COLOR })) {
@@ -339,32 +346,20 @@ void map_info(PlayerType *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, ch
         if (r_ptr->visual_flags.has(MonsterVisualType::ANY_COLOR)) {
             *ap = randint1(15);
         } else {
-            switch (randint1(7)) {
-            case 1:
-                *ap = TERM_RED;
-                break;
-            case 2:
-                *ap = TERM_L_RED;
-                break;
-            case 3:
-                *ap = TERM_WHITE;
-                break;
-            case 4:
-                *ap = TERM_L_GREEN;
-                break;
-            case 5:
-                *ap = TERM_BLUE;
-                break;
-            case 6:
-                *ap = TERM_L_DARK;
-                break;
-            case 7:
-                *ap = TERM_GREEN;
-                break;
-            }
+            constexpr static auto colors = {
+                TERM_RED,
+                TERM_L_RED,
+                TERM_WHITE,
+                TERM_L_GREEN,
+                TERM_BLUE,
+                TERM_L_DARK,
+                TERM_GREEN,
+            };
+
+            *ap = rand_choice(colors);
         }
     } else if (r_ptr->visual_flags.has(MonsterVisualType::RANDOM_COLOR) && !use_graphics) {
-        *ap = g_ptr->m_idx % 15 + 1;
+        *ap = grid.m_idx % 15 + 1;
     } else {
         *ap = a;
     }
@@ -381,7 +376,7 @@ void map_info(PlayerType *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, ch
             *cp = tmp_r_ptr->x_char;
             *ap = tmp_r_ptr->x_attr;
         } else {
-            *cp = (one_in_(25) ? image_object_hack[randint0(sizeof(image_object_hack) - 1)] : image_monster_hack[randint0(sizeof(image_monster_hack) - 1)]);
+            *cp = one_in_(25) ? rand_choice(image_objects) : rand_choice(image_monsters);
         }
 
         set_term_color(player_ptr, y, x, ap, cp);
index 87acb95..4c73653 100644 (file)
@@ -1,13 +1,8 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
-#define MAX_IMAGE_OBJECT_HACK 19
-#define MAX_IMAGE_MONSTER_HACK 53
-
 extern byte display_autopick;
-extern char image_object_hack[MAX_IMAGE_OBJECT_HACK];
-extern char image_monster_hack[MAX_IMAGE_MONSTER_HACK];
 
 class PlayerType;
 void map_info(PlayerType *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, char *cp, TERM_COLOR *tap, char *tcp);
index 784d0fa..36a94af 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-messages.h"
+#include "view/display-messages.h"
 #include "core/window-redrawer.h"
 #include "game-option/cheat-options.h"
 #include "game-option/input-options.h"
@@ -7,11 +7,11 @@
 #include "io/input-key-acceptor.h"
 #include "main/sound-of-music.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "term/gameterm.h"
 #include "term/term-color-types.h"
 #include "util/int-char-converter.h"
 #include "world/world.h"
-
 #include <deque>
 #include <map>
 #include <memory>
@@ -80,13 +80,13 @@ int32_t message_num(void)
  * @param age メッセージの世代
  * @return メッセージの文字列ポインタ
  */
-concptr message_str(int age)
+std::shared_ptr<const std::string> message_str(int age)
 {
     if ((age < 0) || (age >= message_num())) {
-        return "";
+        return std::make_shared<const std::string>("");
     }
 
-    return message_history[age]->data();
+    return message_history[age];
 }
 
 static void message_add_aux(std::string str)
@@ -197,7 +197,7 @@ bool is_msg_window_flowed(void)
 {
     auto i = 0U;
     for (; i < angband_terms.size(); ++i) {
-        if (angband_terms[i] && (window_flag[i] & PW_MESSAGE)) {
+        if (angband_terms[i] && g_window_flags[i].has(SubWindowRedrawingFlag::MESSAGE)) {
             break;
         }
     }
@@ -253,7 +253,7 @@ static void msg_flush(PlayerType *player_ptr, int x)
         }
     }
 
-    term_erase(0, 0, 255);
+    term_erase(0, 0);
 }
 
 void msg_erase(void)
@@ -331,7 +331,7 @@ void msg_print(std::string_view msg)
     }
 
     if (!msg_flag) {
-        term_erase(0, 0, 255);
+        term_erase(0, 0);
         msg_head_pos = 0;
     }
 
@@ -362,7 +362,7 @@ void msg_print(std::string_view msg)
     }
 
     term_putstr(msg_head_pos, 0, msg.size(), TERM_WHITE, msg.data());
-    p_ptr->window_flags |= (PW_MESSAGE);
+    RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::MESSAGE);
     window_stuff(p_ptr);
 
     msg_flag = true;
@@ -380,7 +380,7 @@ void msg_print(std::nullptr_t)
     }
 
     if (!msg_flag) {
-        term_erase(0, 0, 255);
+        term_erase(0, 0);
         msg_head_pos = 0;
     }
 
@@ -391,19 +391,6 @@ void msg_print(std::nullptr_t)
     }
 }
 
-/*
- * Display a formatted message, using "vstrnfmt()" and "msg_print()".
- */
-void msg_format(std::string_view fmt, ...)
-{
-    va_list vp;
-    char buf[1024];
-    va_start(vp, fmt);
-    (void)vstrnfmt(buf, sizeof(buf), fmt.data(), vp);
-    va_end(vp);
-    msg_print(buf);
-}
-
 void msg_format(const char *fmt, ...)
 {
     va_list vp;
index 5263c25..2559271 100644 (file)
@@ -1,7 +1,9 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <concepts>
+#include <memory>
+#include <string>
 #include <string_view>
 
 /*
@@ -14,10 +16,9 @@ extern bool msg_flag;
 extern COMMAND_CODE now_message;
 
 int32_t message_num(void);
-concptr message_str(int age);
+std::shared_ptr<const std::string> message_str(int age);
 void message_add(std::string_view msg);
 void msg_erase(void);
 void msg_print(std::string_view msg);
 void msg_print(std::nullptr_t);
-void msg_format(std::string_view fmt, ...);
 void msg_format(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
index 2c02956..01cfbe5 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-monster-status.h"
+#include "view/display-monster-status.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster/monster-flag-types.h"
  */
 std::string look_mon_desc(MonsterEntity *m_ptr, BIT_FLAGS mode)
 {
-    bool living = monster_living(m_ptr->ap_r_idx);
-    int perc = m_ptr->maxhp > 0 ? 100L * m_ptr->hp / m_ptr->maxhp : 0;
+    auto living = m_ptr->has_living_flag(true);
+    auto perc = m_ptr->maxhp > 0 ? 100L * m_ptr->hp / m_ptr->maxhp : 0;
 
     concptr desc;
-    if (m_ptr->hp >= m_ptr->maxhp) {
+    if (!m_ptr->ml) {
+        desc = _("損傷具合不明", "damage unknown");
+    } else if (m_ptr->hp >= m_ptr->maxhp) {
         desc = living ? _("無傷", "unhurt") : _("無ダメージ", "undamaged");
     } else if (perc >= 60) {
         desc = living ? _("軽傷", "somewhat wounded") : _("小ダメージ", "somewhat damaged");
@@ -40,7 +42,7 @@ std::string look_mon_desc(MonsterEntity *m_ptr, BIT_FLAGS mode)
     }
 
     concptr clone = m_ptr->mflag2.has(MonsterConstantFlagType::CLONED) ? ", clone" : "";
-    MonsterRaceInfo *ap_r_ptr = &monraces_info[m_ptr->ap_r_idx];
+    MonsterRaceInfo *ap_r_ptr = &m_ptr->get_appearance_monrace();
     if (ap_r_ptr->r_tkills && m_ptr->mflag2.has_not(MonsterConstantFlagType::KAGE)) {
         return format(_("レベル%d, %s%s%s", "Level %d, %s%s%s"), ap_r_ptr->level, desc, attitude, clone);
     }
index 09848ee..2460173 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string>
index c3f8896..acbfc48 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-player-middle.h"
+#include "view/display-player-middle.h"
 #include "combat/shoot.h"
 #include "game-option/birth-options.h"
 #include "game-option/special-options.h"
@@ -53,7 +53,7 @@ static void display_player_melee_bonus(PlayerType *player_ptr, int hand, int han
 
     show_tohit += player_ptr->skill_thn / BTH_PLUS_ADJ;
 
-    std::string buf = format("(%+d,%+d)", (int)show_tohit, (int)show_todam);
+    const auto buf = format("(%+d,%+d)", (int)show_tohit, (int)show_todam);
     if (!has_melee_weapon(player_ptr, INVEN_MAIN_HAND) && !has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
         display_player_one_line(ENTRY_BARE_HAND, buf, TERM_L_BLUE);
     } else if (has_two_handed_weapons(player_ptr)) {
@@ -113,7 +113,7 @@ static void display_bow_hit_damage(PlayerType *player_ptr)
     if (tval == ItemKindType::NONE) {
         show_tohit += (weapon_exps[0] - median_skill_exp) / bow_magnification;
     } else {
-        const auto sval = item.bi_key.sval().value();
+        const auto sval = *item.bi_key.sval();
         const auto weapon_exp = weapon_exps[sval];
         if (item.is_cross_bow()) {
             show_tohit += weapon_exp / xbow_magnification;
@@ -280,20 +280,15 @@ static void display_player_exp(PlayerType *player_ptr)
 /*!
  * @brief ゲーム内の経過時間を表示する
  * @param player_ptr プレイヤーへの参照ポインタ
+ * @details fmt をstring で受けているのはClang対策
  */
 static void display_playtime_in_game(PlayerType *player_ptr)
 {
-    int day, hour, min;
-    extract_day_hour_min(player_ptr, &day, &hour, &min);
-
-    std::string buf;
-    if (day < MAX_DAYS) {
-        buf = format(_("%d日目 %2d:%02d", "Day %d %2d:%02d"), day, hour, min);
-    } else {
-        buf = format(_("*****日目 %2d:%02d", "Day ***** %2d:%02d"), hour, min);
-    }
-
-    display_player_one_line(ENTRY_DAY, buf, TERM_L_GREEN);
+    const auto &[day, hour, min] = w_ptr->extract_date_time(player_ptr->start_race);
+    const auto is_days_countable = day < MAX_DAYS;
+    const std::string fmt = is_days_countable ? _("%d日目 %2d:%02d", "Day %d %2d:%02d") : _("*****日目 %2d:%02d", "Day ***** %2d:%02d");
+    const auto mes = is_days_countable ? format(fmt.data(), day, hour, min) : format(fmt.data(), hour, min);
+    display_player_one_line(ENTRY_DAY, mes, TERM_L_GREEN);
 
     if (player_ptr->chp >= player_ptr->mhp) {
         display_player_one_line(ENTRY_HP, format("%4d/%4d", player_ptr->chp, player_ptr->mhp), TERM_L_GREEN);
index d41e8d8..a40a40d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void display_player_middle(PlayerType *player_ptr);
index 7cbaa18..40dba8b 100644 (file)
@@ -1,4 +1,5 @@
-#include "player-info/class-info.h"
+#include "view/display-player-misc-info.h"
+#include "player-info/class-info.h"
 #include "player-info/mimic-info-table.h"
 #include "player/player-personality.h"
 #include "player/player-sex.h"
@@ -7,6 +8,33 @@
 #include "term/term-color-types.h"
 #include "term/z-form.h"
 #include "view/display-player-stat-info.h"
+#include <sstream>
+
+/*!
+ * @brief 画面上部にプレイヤーの名前を表示する
+ *
+ * @param name_only trueならば名前のみ表示する。falseならばプレイヤーの性格も表示する。
+ */
+void display_player_name(PlayerType *player_ptr, bool name_only)
+{
+    std::stringstream ss;
+    if (!name_only) {
+        ss << ap_ptr->title << _(ap_ptr->no == 1 ? "の" : "", " ");
+    }
+    ss << player_ptr->name;
+    const auto display_name = ss.str();
+
+    constexpr std::string_view header = _("名前  : ", "Name  : ");
+    const auto length = header.length() + display_name.length();
+
+    const auto &[wid, hgt] = term_get_size();
+    const auto center_col = (wid - length) / 2 - 4; // ヘッダがあるぶん少し左に寄せたほうが見やすい
+    constexpr auto row = 1;
+
+    term_erase(0, row);
+    term_putstr(center_col, row, -1, TERM_WHITE, header);
+    term_putstr(center_col + header.length(), row, -1, TERM_L_BLUE, display_name);
+}
 
 /*!
  * @brief プレイヤーの特性フラグ一覧表示2a /
  */
 void display_player_misc_info(PlayerType *player_ptr)
 {
-    put_str(_("名前  :", "Name  :"), 1, 26);
+    display_player_name(player_ptr);
+
     put_str(_("性別  :", "Sex   :"), 3, 1);
     put_str(_("種族  :", "Race  :"), 4, 1);
     put_str(_("職業  :", "Class :"), 5, 1);
 
-    std::string tmp = ap_ptr->title;
-    tmp.append(_(ap_ptr->no == 1 ? "の" : "", " ")).append(player_ptr->name);
-
-    c_put_str(TERM_L_BLUE, tmp, 1, 34);
     c_put_str(TERM_L_BLUE, sp_ptr->title, 3, 9);
     c_put_str(TERM_L_BLUE, (player_ptr->mimic_form != MimicKindType::NONE ? mimic_info.at(player_ptr->mimic_form).title : rp_ptr->title), 4, 9);
     c_put_str(TERM_L_BLUE, cp_ptr->title, 5, 9);
index 3014f6a..71f84cc 100644 (file)
@@ -1,4 +1,5 @@
-#pragma once
+#pragma once
 
 class PlayerType;
+void display_player_name(PlayerType *player_ptr, bool name_only = false);
 void display_player_misc_info(PlayerType *player_ptr);
index a51e2f4..eb54221 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーの耐性と能力値を表示する
  * @date 2020/02/27
  * @author Hourier
@@ -10,7 +10,6 @@
 #include "inventory/inventory-slot-types.h"
 #include "mutation/mutation-flag-types.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "player-base/player-race.h"
 #include "player-info/class-info.h"
 #include "player-info/mimic-info-table.h"
@@ -209,7 +208,7 @@ static void display_equipments_compensation(PlayerType *player_ptr, int row, int
     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
         ItemEntity *o_ptr;
         o_ptr = &player_ptr->inventory_list[i];
-        auto flags = object_flags_known(o_ptr);
+        auto flags = o_ptr->get_flags_known();
         for (int stat = 0; stat < A_MAX; stat++) {
             TERM_COLOR a = TERM_SLATE;
             char c = '.';
index 6103578..5350f14 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void display_player_stat_info(PlayerType *player_ptr);
index 1cd1d69..5453a22 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤーのステータス表示メインルーチン群
  * @date 2020/02/25
  * @author Hourier
@@ -13,6 +13,7 @@
 #include "info-reader/fixed-map-parser.h"
 #include "inventory/inventory-slot-types.h"
 #include "knowledge/knowledge-mutations.h"
+#include "locale/japanese.h"
 #include "mind/mind-elementalist.h"
 #include "mutation/mutation-flag-types.h"
 #include "object/object-info.h"
@@ -83,10 +84,7 @@ static bool display_player_info(PlayerType *player_ptr, int mode)
  */
 static void display_player_basic_info(PlayerType *player_ptr)
 {
-    std::string tmp = ap_ptr->title;
-    tmp.append(_(ap_ptr->no == 1 ? "の" : "", " ")).append(player_ptr->name);
-
-    display_player_one_line(ENTRY_NAME, tmp, TERM_L_BLUE);
+    display_player_name(player_ptr);
     display_player_one_line(ENTRY_SEX, sp_ptr->title, TERM_L_BLUE);
     display_player_one_line(ENTRY_RACE, (player_ptr->mimic_form != MimicKindType::NONE ? mimic_info.at(player_ptr->mimic_form).title : rp_ptr->title), TERM_L_BLUE);
     display_player_one_line(ENTRY_CLASS, cp_ptr->title, TERM_L_BLUE);
@@ -125,8 +123,8 @@ static void display_phisique(PlayerType *player_ptr)
 {
 #ifdef JP
     display_player_one_line(ENTRY_AGE, format("%d才", (int)player_ptr->age), TERM_L_BLUE);
-    display_player_one_line(ENTRY_HEIGHT, format("%dcm", (int)((player_ptr->ht * 254) / 100)), TERM_L_BLUE);
-    display_player_one_line(ENTRY_WEIGHT, format("%dkg", (int)((player_ptr->wt * 4536) / 10000)), TERM_L_BLUE);
+    display_player_one_line(ENTRY_HEIGHT, format("%dcm", inch_to_cm(player_ptr->ht)), TERM_L_BLUE);
+    display_player_one_line(ENTRY_WEIGHT, format("%dkg", lb_to_kg(player_ptr->wt)), TERM_L_BLUE);
     display_player_one_line(ENTRY_SOCIAL, format("%d  ", (int)player_ptr->sc), TERM_L_BLUE);
 #else
     display_player_one_line(ENTRY_AGE, format("%d", (int)player_ptr->age), TERM_L_BLUE);
@@ -176,19 +174,20 @@ static std::optional<std::string> search_death_cause(PlayerType *player_ptr)
     }
 
     if (w_ptr->total_winner) {
-        return std::string(format(_("…あなたは勝利の後%sした。", "...You %s after winning."),
-            streq(player_ptr->died_from, "Seppuku") ? _("切腹", "committed seppuku") : _("引退", "retired from the adventure")));
+        return format(_("…あなたは勝利の後%sした。", "...You %s after winning."),
+            streq(player_ptr->died_from, "Seppuku") ? _("切腹", "committed seppuku") : _("引退", "retired from the adventure"));
     }
 
     if (!floor_ptr->dun_level) {
+        constexpr auto killed_monster = _("…あなたは%sで%sに殺された。", "...You were killed by %s in %s.");
 #ifdef JP
-        return std::string(format("…あなたは%sで%sに殺された。", map_name(player_ptr), player_ptr->died_from.data()));
+        return format(killed_monster, map_name(player_ptr).data(), player_ptr->died_from.data());
 #else
-        return std::string(format("...You were killed by %s in %s.", player_ptr->died_from.data(), map_name(player_ptr)));
+        return format(killed_monster, player_ptr->died_from.data(), map_name(player_ptr).data());
 #endif
     }
 
-    if (inside_quest(floor_ptr->quest_number) && QuestType::is_fixed(floor_ptr->quest_number)) {
+    if (floor_ptr->is_in_quest() && QuestType::is_fixed(floor_ptr->quest_number)) {
         const auto &quest_list = QuestList::get_instance();
 
         /* Get the quest text */
@@ -197,17 +196,19 @@ static std::optional<std::string> search_death_cause(PlayerType *player_ptr)
         parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
 
         const auto *q_ptr = &quest_list[floor_ptr->quest_number];
+        constexpr auto killed_quest = _("…あなたは、クエスト「%s」で%sに殺された。", "...You were killed by %s in the quest '%s'.");
 #ifdef JP
-        return std::string(format("…あなたは、クエスト「%s」で%sに殺された。", q_ptr->name.data(), player_ptr->died_from.data()));
+        return format(killed_quest, q_ptr->name.data(), player_ptr->died_from.data());
 #else
-        return std::string(format("...You were killed by %s in the quest '%s'.", player_ptr->died_from.data(), q_ptr->name.data()));
+        return format(killed_quest, player_ptr->died_from.data(), q_ptr->name.data());
 #endif
     }
 
+    constexpr auto killed_floor = _("…あなたは、%sの%d階で%sに殺された。", "...You were killed by %s on level %d of %s.");
 #ifdef JP
-    return std::string(format("…あなたは、%sの%d階で%sに殺された。", map_name(player_ptr), (int)floor_ptr->dun_level, player_ptr->died_from.data()));
+    return format(killed_floor, map_name(player_ptr).data(), (int)floor_ptr->dun_level, player_ptr->died_from.data());
 #else
-    return std::string(format("...You were killed by %s on level %d of %s.", player_ptr->died_from.data(), floor_ptr->dun_level, map_name(player_ptr)));
+    return format(killed_floor, player_ptr->died_from.data(), floor_ptr->dun_level, map_name(player_ptr).data());
 #endif
 }
 
@@ -220,7 +221,7 @@ static std::optional<std::string> search_death_cause(PlayerType *player_ptr)
 static std::optional<std::string> decide_death_in_quest(PlayerType *player_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (!inside_quest(floor_ptr->quest_number) || !QuestType::is_fixed(floor_ptr->quest_number)) {
+    if (!floor_ptr->is_in_quest() || !QuestType::is_fixed(floor_ptr->quest_number)) {
         return std::nullopt;
     }
 
@@ -243,23 +244,24 @@ static std::optional<std::string> decide_death_in_quest(PlayerType *player_ptr)
 static std::string decide_current_floor(PlayerType *player_ptr)
 {
     if (auto death_cause = search_death_cause(player_ptr);
-        death_cause.has_value() || !w_ptr->character_dungeon) {
+        death_cause || !w_ptr->character_dungeon) {
         return death_cause.value_or("");
     }
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
     if (floor_ptr->dun_level == 0) {
-        return std::string(format(_("…あなたは現在、 %s にいる。", "...Now, you are in %s."), map_name(player_ptr)));
+        return format(_("…あなたは現在、 %s にいる。", "...Now, you are in %s."), map_name(player_ptr).data());
     }
 
-    if (auto decision = decide_death_in_quest(player_ptr); decision.has_value()) {
-        return decision.value();
+    if (auto decision = decide_death_in_quest(player_ptr); decision) {
+        return *decision;
     }
 
+    constexpr auto mes = _("…あなたは現在、 %s の %d 階で探索している。", "...Now, you are exploring level %d of %s.");
 #ifdef JP
-    return std::string(format("…あなたは現在、 %s の %d 階で探索している。", map_name(player_ptr), (int)floor_ptr->dun_level));
+    return format(mes, map_name(player_ptr).data(), (int)floor_ptr->dun_level);
 #else
-    return std::string(format("...Now, you are exploring level %d of %s.", (int)floor_ptr->dun_level, map_name(player_ptr)));
+    return format(mes, (int)floor_ptr->dun_level, map_name(player_ptr).data());
 #endif
 }
 
index 02531f4..82b2a84 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <optional>
index b6da843..f125f55 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-scores.h"
+#include "view/display-scores.h"
 #include "core/score-util.h"
 #include "io/files-util.h"
 #include "io/input-key-acceptor.h"
@@ -208,9 +208,9 @@ void display_scores(int from, int to, int note, high_score *score)
  */
 void display_scores(int from, int to)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
-    highscore_fd = fd_open(buf, O_RDONLY);
+    const auto &path = path_build(ANGBAND_DIR_APEX, "scores.raw");
+    const auto &filename = path.string();
+    highscore_fd = fd_open(filename, O_RDONLY);
     if (highscore_fd < 0) {
         quit(_("スコア・ファイルが使用できません。", "Score file unavailable."));
     }
index 78202ad..b9f372a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 struct high_score;
 void display_scores(int from, int to, int note, high_score *score);
index 362b36c..48c6e72 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-self-info.h"
+#include "view/display-self-info.h"
 #include "avatar/avatar.h"
 #include "io/input-key-acceptor.h"
 #include "player-info/alignment.h"
@@ -72,7 +72,7 @@ void display_virtue(PlayerType *player_ptr, self_info_type *self_ptr)
             vir_desc = format(_("[%s]の具現者 (%d)", "You are the living embodiment of %s (%d)."), vir_name, tester);
         }
 
-        angband_strcpy(self_ptr->v_string[v_nr], vir_desc.data(), sizeof(self_ptr->v_string[v_nr]));
+        angband_strcpy(self_ptr->v_string[v_nr], vir_desc, sizeof(self_ptr->v_string[v_nr]));
         self_ptr->info[self_ptr->line++] = self_ptr->v_string[v_nr];
     }
 }
index c54c2de..b86b8dc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 struct self_info_type;
index 18bffb6..8f947d4 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-store.h"
+#include "view/display-store.h"
 #include "flavor/flavor-describer.h"
 #include "game-option/birth-options.h"
 #include "game-option/special-options.h"
@@ -68,9 +68,8 @@ void display_entry(PlayerType *player_ptr, int pos, StoreSaleType store_num)
             maxwid -= 10;
         }
 
-        // 元々マルチバイト文字のことが考慮されていない.
-        const auto item_name = describe_flavor(player_ptr, o_ptr, 0).substr(0, maxwid);
-        c_put_str(tval_to_attr[enum2i(o_ptr->bi_key.tval())], item_name.data(), i + 6, cur_col);
+        const auto item_name = describe_flavor(player_ptr, o_ptr, 0, maxwid);
+        c_put_str(tval_to_attr[enum2i(o_ptr->bi_key.tval())], item_name, i + 6, cur_col);
 
         if (show_weights) {
             WEIGHT wgt = o_ptr->weight;
@@ -85,9 +84,8 @@ void display_entry(PlayerType *player_ptr, int pos, StoreSaleType store_num)
         maxwid -= 7;
     }
 
-    // 元々マルチバイト文字のことが考慮されていない.
-    const auto item_name = describe_flavor(player_ptr, o_ptr, 0).substr(0, maxwid);
-    c_put_str(tval_to_attr[enum2i(o_ptr->bi_key.tval())], item_name.data(), i + 6, cur_col);
+    const auto item_name = describe_flavor(player_ptr, o_ptr, 0, maxwid);
+    c_put_str(tval_to_attr[enum2i(o_ptr->bi_key.tval())], item_name, i + 6, cur_col);
 
     if (show_weights) {
         int wgt = o_ptr->weight;
@@ -169,12 +167,12 @@ void display_store(PlayerType *player_ptr, StoreSaleType store_num)
         return;
     }
 
-    concptr store_name = terrains_info[cur_store_feat].name.data();
-    concptr owner_name = (ot_ptr->owner_name);
-    concptr race_name = race_info[enum2i(ot_ptr->owner_race)].title;
+    const auto &store_name = TerrainList::get_instance()[cur_store_feat].name;
+    const auto owner_name = ot_ptr->owner_name;
+    const auto race_name = race_info[enum2i(ot_ptr->owner_race)].title;
     put_str(format("%s (%s)", owner_name, race_name), 3, 10);
 
-    prt(format("%s (%ld)", store_name, (long)(ot_ptr->max_cost)), 3, 50);
+    prt(format("%s (%d)", store_name.data(), ot_ptr->max_cost), 3, 50);
 
     put_str(_("商品の一覧", "Item Description"), 5, 5);
     if (show_weights) {
index d3f2069..564b945 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 enum class StoreSaleType;
 class PlayerType;
index 71a9d59..262fea9 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/display-util.h"
+#include "view/display-util.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "util/buffer-shaper.h"
index 629ddfc..d36ce24 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <string_view>
index 6e17106..73f7975 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/object-describer.h"
+#include "view/object-describer.h"
 #include "cmd-action/cmd-spell.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
@@ -44,9 +44,9 @@ void inven_item_charges(const ItemEntity &item)
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param item 残量を表示したいプレイヤーのアイテム所持スロット
  */
-void inven_item_describe(PlayerType *player_ptr, short item)
+void inven_item_describe(PlayerType *player_ptr, short i_idx)
 {
-    auto *o_ptr = &player_ptr->inventory_list[item];
+    auto *o_ptr = &player_ptr->inventory_list[i_idx];
     const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
 #ifdef JP
     if (o_ptr->number <= 0) {
@@ -71,14 +71,14 @@ void display_koff(PlayerType *player_ptr)
     }
 
     for (auto y = 0; y < game_term->hgt; y++) {
-        term_erase(0, y, 255);
+        term_erase(0, y);
     }
 
     ItemEntity item;
     item.prep(player_ptr->tracking_bi_id);
     const auto item_name = describe_flavor(player_ptr, &item, (OD_OMIT_PREFIX | OD_NAME_ONLY | OD_STORE));
     term_putstr(0, 0, -1, TERM_WHITE, item_name);
-    const auto sval = item.bi_key.sval().value();
+    const auto sval = *item.bi_key.sval();
     const short use_realm = tval2realm(item.bi_key.tval());
 
     if (player_ptr->realm1 || player_ptr->realm2) {
index b0ab659..06603c0 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
 class PlayerType;
 void inven_item_charges(const ItemEntity &item);
-void inven_item_describe(PlayerType *player_ptr, short item);
+void inven_item_describe(PlayerType *player_ptr, short i_idx);
 void display_koff(PlayerType *player_ptr);
index c09d562..58059d4 100644 (file)
@@ -1,4 +1,4 @@
-#include "view/status-bars-table.h"
+#include "view/status-bars-table.h"
 #include "term/term-color-types.h"
 
 stat_bar stat_bars[MAX_STAT_BARS] = { { TERM_YELLOW, _("つ", "Ts"), _("つよし", "Tsuyoshi") }, { TERM_VIOLET, _("幻", "Ha"), _("幻覚", "Halluc") },
index 2e508de..f30750a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 74ff216..cca56ac 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @file status-first-page.c
  * @brief キャラ基本情報及び技能値の表示
  * @date 2020/02/23
@@ -14,7 +14,6 @@
 #include "mutation/mutation-flag-types.h"
 #include "object-enchant/special-object-flags.h"
 #include "object-enchant/tr-types.h"
-#include "object/object-flags.h"
 #include "object/tval-types.h"
 #include "perception/object-perception.h"
 #include "player-base/player-class.h"
@@ -276,7 +275,7 @@ static void calc_two_hands(PlayerType *player_ptr, int *damage, int *to_h)
         }
 
         basedam = ((o_ptr->dd + player_ptr->to_dd[i]) * (o_ptr->ds + player_ptr->to_ds[i] + 1)) * 50;
-        auto flags = object_flags_known(o_ptr);
+        auto flags = o_ptr->get_flags_known();
 
         bool impact = player_ptr->impact != 0;
         basedam = calc_expect_crit(player_ptr, o_ptr->weight, to_h[i], basedam, player_ptr->dis_to_h[i], poison_needle, impact);
index 89b7ebb..5063b0d 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #define ENTRY_BARE_HAND 0
 #define ENTRY_TWO_HANDS 1
index 65470a8..5d544a0 100644 (file)
@@ -1,5 +1,4 @@
-#include "window/display-sub-windows.h"
-#include "core/window-redrawer.h"
+#include "window/display-sub-windows.h"
 #include "flavor/flavor-describer.h"
 #include "floor/cave.h"
 #include "game-option/option-flags.h"
@@ -7,7 +6,6 @@
 #include "game-option/text-display-options.h"
 #include "grid/feature.h"
 #include "inventory/inventory-describer.h"
-#include "inventory/inventory-slot-types.h"
 #include "inventory/inventory-util.h"
 #include "locale/japanese.h"
 #include "main/sound-of-music.h"
 #include "mind/mind-sniper.h"
 #include "mind/mind-types.h"
 #include "monster-race/monster-race.h"
-#include "monster-race/race-flags1.h"
-#include "monster/monster-flag-types.h"
-#include "monster/monster-info.h"
-#include "monster/monster-status.h"
+#include "monster/monster-describer.h"
+#include "monster/monster-description-types.h"
 #include "object/item-tester-hooker.h"
 #include "object/object-info.h"
-#include "object/object-mark-types.h"
 #include "player-base/player-class.h"
 #include "player-info/class-info.h"
 #include "player/player-status-flags.h"
 #include "player/player-status-table.h"
 #include "player/player-status.h"
 #include "realm/realm-names-table.h"
-#include "spell-kind/magic-item-recharger.h"
 #include "spell/spells-execution.h"
-#include "spell/technic-info-table.h"
-#include "system/baseitem-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
-#include "system/player-type-definition.h"
 #include "system/terrain-type-definition.h"
-#include "target/target-describer.h"
 #include "target/target-preparation.h"
-#include "target/target-setter.h"
-#include "target/target-types.h"
 #include "term/gameterm.h"
 #include "term/screen-processor.h"
-#include "term/term-color-types.h"
-#include "term/z-form.h"
 #include "timed-effect/player-hallucination.h"
 #include "timed-effect/player-stun.h"
 #include "timed-effect/timed-effects.h"
-#include "util/bit-flags-calculator.h"
 #include "util/int-char-converter.h"
 #include "view/display-lore.h"
 #include "view/display-map.h"
@@ -90,7 +75,7 @@ FixItemTesterSetter::~FixItemTesterSetter()
  * @param pw_flag 描画を行うフラグ
  * @param display_func 描画を行う関数
  */
-static void display_sub_windows(window_redraw_type pw_flag, std::invocable auto display_func)
+static void display_sub_windows(SubWindowRedrawingFlag pw_flag, std::invocable auto display_func)
 {
     auto current_term = game_term;
 
@@ -100,7 +85,7 @@ static void display_sub_windows(window_redraw_type pw_flag, std::invocable auto
             continue;
         }
 
-        if (none_bits(window_flag[i], pw_flag)) {
+        if (!g_window_flags[i].has(pw_flag)) {
             continue;
         }
 
@@ -118,7 +103,7 @@ static void display_sub_windows(window_redraw_type pw_flag, std::invocable auto
  */
 void fix_inventory(PlayerType *player_ptr)
 {
-    display_sub_windows(PW_INVENTORY,
+    display_sub_windows(SubWindowRedrawingFlag::INVENTORY,
         [player_ptr] {
             display_inventory(player_ptr, *fix_item_tester);
         });
@@ -146,7 +131,7 @@ static void print_monster_line(TERM_LEN x, TERM_LEN y, MonsterEntity *m_ptr, int
     MonsterRaceId r_idx = m_ptr->ap_r_idx;
     auto *r_ptr = &monraces_info[r_idx];
 
-    term_erase(0, y, 255);
+    term_erase(0, y);
     term_gotoxy(x, y);
     if (!r_ptr) {
         return;
@@ -228,7 +213,51 @@ void print_monster_list(FloorType *floor_ptr, const std::vector<MONSTER_IDX> &mo
     }
 
     for (; line < max_lines; line++) {
-        term_erase(0, line, 255);
+        term_erase(0, line);
+    }
+}
+
+static void print_pet_list_oneline(PlayerType *player_ptr, const MonsterEntity &monster, TERM_LEN x, TERM_LEN y, TERM_LEN width)
+{
+    const auto &monrace = monster.get_appearance_monrace();
+    const auto name = monster_desc(player_ptr, &monster, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE | MD_NO_OWNER);
+    const auto &[bar_color, bar_len] = monster.get_hp_bar_data();
+    const auto is_visible = monster.ml && !player_ptr->effects()->hallucination()->is_hallucinated();
+
+    term_erase(0, y);
+    if (is_visible) {
+        term_putstr(x, y, -1, TERM_WHITE, "[----------]");
+        term_putstr(x + 1, y, bar_len, bar_color, "**********");
+    }
+
+    term_gotoxy(x + 13, y);
+    term_add_bigch(monrace.x_attr, monrace.x_char);
+    term_addstr(-1, TERM_WHITE, " ");
+    term_addstr(-1, TERM_WHITE, name);
+
+    if (width >= 50) {
+        const auto location = format(" (X:%3d Y:%3d)", monster.fx, monster.fy);
+        prt(is_visible ? location : "", y, width - location.length());
+    }
+}
+
+static void print_pet_list(PlayerType *player_ptr, const std::vector<MONSTER_IDX> &pets, TERM_LEN x, TERM_LEN y, TERM_LEN width, TERM_LEN height)
+{
+    for (auto n = 0U; n < pets.size(); ++n) {
+        const auto &monster = player_ptr->current_floor_ptr->m_list[pets[n]];
+        const int line = y + n;
+
+        print_pet_list_oneline(player_ptr, monster, x, line, width);
+
+        if ((line == height - 2) && (n < pets.size() - 2)) {
+            term_erase(0, line + 1);
+            term_putstr(x, line + 1, -1, TERM_WHITE, "-- and more --");
+            break;
+        }
+    }
+
+    for (int n = pets.size(); n < height; ++n) {
+        term_erase(0, y + n);
     }
 }
 
@@ -241,12 +270,11 @@ void fix_monster_list(PlayerType *player_ptr)
     static std::vector<MONSTER_IDX> monster_list;
     std::once_flag once;
 
-    display_sub_windows(PW_SIGHT_MONSTERS,
+    display_sub_windows(SubWindowRedrawingFlag::SIGHT_MONSTERS,
         [player_ptr, &once] {
-            int w, h;
-            term_get_size(&w, &h);
+            const auto &[wid, hgt] = term_get_size();
             std::call_once(once, target_sensing_monsters_prepare, player_ptr, monster_list);
-            print_monster_list(player_ptr->current_floor_ptr, monster_list, 0, 0, h);
+            print_monster_list(player_ptr->current_floor_ptr, monster_list, 0, 0, hgt);
         });
 
     if (use_music && has_monster_music) {
@@ -256,6 +284,19 @@ void fix_monster_list(PlayerType *player_ptr)
 }
 
 /*!
+ * @brief 視界内のペットのリストをサブウィンドウに表示する
+ */
+void fix_pet_list(PlayerType *player_ptr)
+{
+    display_sub_windows(SubWindowRedrawingFlag::PETS,
+        [player_ptr] {
+            const auto &[wid, hgt] = term_get_size();
+            const auto pets = target_pets_prepare(player_ptr);
+            print_pet_list(player_ptr, pets, 0, 0, wid, hgt);
+        });
+}
+
+/*!
  * @brief 装備アイテム一覧を表示する /
  * Choice window "shadow" of the "show_equip()" function
  */
@@ -265,8 +306,7 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
         return;
     }
 
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
+    const auto &[wid, hgt] = term_get_size();
     byte attr = TERM_WHITE;
     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
         int cur_row = i - INVEN_MAIN_HAND;
@@ -284,7 +324,7 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
         }
 
         int cur_col = 3;
-        term_erase(cur_col, cur_row, 255);
+        term_erase(cur_col, cur_row);
         term_putstr(0, cur_row, cur_col, TERM_WHITE, tmp_val);
 
         std::string item_name;
@@ -328,7 +368,7 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
     }
 
     for (int i = INVEN_TOTAL - INVEN_MAIN_HAND; i < hgt; i++) {
-        term_erase(0, i, 255);
+        term_erase(0, i);
     }
 }
 
@@ -339,7 +379,7 @@ static void display_equipment(PlayerType *player_ptr, const ItemTester &item_tes
  */
 void fix_equip(PlayerType *player_ptr)
 {
-    display_sub_windows(PW_EQUIPMENT,
+    display_sub_windows(SubWindowRedrawingFlag::EQUIPMENT,
         [player_ptr] {
             display_equipment(player_ptr, *fix_item_tester);
         });
@@ -352,8 +392,8 @@ void fix_equip(PlayerType *player_ptr)
  */
 void fix_player(PlayerType *player_ptr)
 {
-    update_playtime();
-    display_sub_windows(PW_PLAYER,
+    w_ptr->update_playtime();
+    display_sub_windows(SubWindowRedrawingFlag::PLAYER,
         [player_ptr] {
             display_player(player_ptr, 0);
         });
@@ -366,15 +406,14 @@ void fix_player(PlayerType *player_ptr)
  */
 void fix_message(void)
 {
-    display_sub_windows(PW_MESSAGE,
+    display_sub_windows(SubWindowRedrawingFlag::MESSAGE,
         [] {
-            TERM_LEN w, h;
-            term_get_size(&w, &h);
-            for (int i = 0; i < h; i++) {
-                term_putstr(0, (h - 1) - i, -1, (byte)((i < now_message) ? TERM_WHITE : TERM_SLATE), message_str((int16_t)i));
+            const auto &[wid, hgt] = term_get_size();
+            for (short i = 0; i < hgt; i++) {
+                term_putstr(0, (hgt - 1) - i, -1, (byte)((i < now_message) ? TERM_WHITE : TERM_SLATE), *message_str(i));
                 TERM_LEN x, y;
                 term_locate(&x, &y);
-                term_erase(x, y, 255);
+                term_erase(x, y);
             }
         });
 }
@@ -389,10 +428,9 @@ void fix_message(void)
  */
 void fix_overhead(PlayerType *player_ptr)
 {
-    display_sub_windows(PW_OVERHEAD,
+    display_sub_windows(SubWindowRedrawingFlag::OVERHEAD,
         [player_ptr] {
-            TERM_LEN wid, hgt;
-            term_get_size(&wid, &hgt);
+            const auto &[wid, hgt] = term_get_size();
             if (wid > COL_MAP + 2 && hgt > ROW_MAP + 2) {
                 int cy, cx;
                 display_map(player_ptr, &cy, &cx);
@@ -414,9 +452,9 @@ static void display_dungeon(PlayerType *player_ptr)
             TERM_COLOR a;
             char c;
             if (!in_bounds2(player_ptr->current_floor_ptr, y, x)) {
-                auto *f_ptr = &terrains_info[feat_none];
-                a = f_ptr->x_attr[F_LIT_STANDARD];
-                c = f_ptr->x_char[F_LIT_STANDARD];
+                const auto &terrain = TerrainList::get_instance()[feat_none];
+                a = terrain.x_attr[F_LIT_STANDARD];
+                c = terrain.x_char[F_LIT_STANDARD];
                 term_queue_char(x - player_ptr->x + game_term->wid / 2 - 1, y - player_ptr->y + game_term->hgt / 2 - 1, a, c, ta, tc);
                 continue;
             }
@@ -444,7 +482,7 @@ static void display_dungeon(PlayerType *player_ptr)
  */
 void fix_dungeon(PlayerType *player_ptr)
 {
-    display_sub_windows(PW_DUNGEON,
+    display_sub_windows(SubWindowRedrawingFlag::DUNGEON,
         [player_ptr] {
             display_dungeon(player_ptr);
         });
@@ -460,7 +498,7 @@ void fix_monster(PlayerType *player_ptr)
     if (!MonsterRace(player_ptr->monster_race_idx).is_valid()) {
         return;
     }
-    display_sub_windows(PW_MONSTER_LORE,
+    display_sub_windows(SubWindowRedrawingFlag::MONSTER_LORE,
         [player_ptr] {
             display_roff(player_ptr);
         });
@@ -473,7 +511,7 @@ void fix_monster(PlayerType *player_ptr)
  */
 void fix_object(PlayerType *player_ptr)
 {
-    display_sub_windows(PW_ITEM_KNOWLEDGTE,
+    display_sub_windows(SubWindowRedrawingFlag::ITEM_KNOWLEDGE,
         [player_ptr] {
             display_koff(player_ptr);
         });
@@ -487,7 +525,7 @@ void fix_object(PlayerType *player_ptr)
  * @details
  * Lookコマンドでカーソルを合わせた場合に合わせてミミックは考慮しない。
  */
-static const MonsterEntity *monster_on_floor_items(FloorType *floor_ptr, const grid_type *g_ptr)
+static const MonsterEntity *monster_on_floor_items(FloorType *floor_ptr, const Grid *g_ptr)
 {
     if (g_ptr->m_idx == 0) {
         return nullptr;
@@ -507,63 +545,58 @@ static const MonsterEntity *monster_on_floor_items(FloorType *floor_ptr, const g
  * @param y 参照する座標グリッドのy座標
  * @param x 参照する座標グリッドのx座標
  */
-static void display_floor_item_list(PlayerType *player_ptr, const int y, const int x)
+static void display_floor_item_list(PlayerType *player_ptr, const Pos2D &pos)
 {
-    // Term の行数を取得。
-    TERM_LEN term_h;
-    {
-        TERM_LEN term_w;
-        term_get_size(&term_w, &term_h);
-    }
-    if (term_h <= 0) {
+    const auto &[wid, hgt] = term_get_size();
+    if (hgt <= 0) {
         return;
     }
 
     term_clear();
     term_gotoxy(0, 0);
 
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    const auto *g_ptr = &floor_ptr->grid_array[y][x];
+    auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.get_grid(pos);
     std::string line;
 
     // 先頭行を書く。
     auto is_hallucinated = player_ptr->effects()->hallucination()->is_hallucinated();
-    if (player_bold(player_ptr, y, x)) {
-        line = format(_("(X:%03d Y:%03d) あなたの足元のアイテム一覧", "Items at (%03d,%03d) under you"), x, y);
-    } else if (const auto *m_ptr = monster_on_floor_items(floor_ptr, g_ptr); m_ptr != nullptr) {
+    if (player_ptr->is_located_at(pos)) {
+        line = format(_("(X:%03d Y:%03d) あなたの足元のアイテム一覧", "Items at (%03d,%03d) under you"), pos.x, pos.y);
+    } else if (const auto *m_ptr = monster_on_floor_items(&floor, &grid); m_ptr != nullptr) {
         if (is_hallucinated) {
-            line = format(_("(X:%03d Y:%03d) 何か奇妙な物の足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under something strange"), x, y);
+            line = format(_("(X:%03d Y:%03d) 何か奇妙な物の足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under something strange"), pos.x, pos.y);
         } else {
-            const MonsterRaceInfo *const r_ptr = &monraces_info[m_ptr->ap_r_idx];
-            line = format(_("(X:%03d Y:%03d) %sの足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under %s"), x, y, r_ptr->name.data());
+            const MonsterRaceInfo *const r_ptr = &m_ptr->get_appearance_monrace();
+            line = format(_("(X:%03d Y:%03d) %sの足元の発見済みアイテム一覧", "Found items at (%03d,%03d) under %s"), pos.x, pos.y, r_ptr->name.data());
         }
     } else {
-        const TerrainType *const f_ptr = &terrains_info[g_ptr->feat];
-        concptr fn = f_ptr->name.data();
+        const auto &terrain = grid.get_terrain();
+        const auto fn = terrain.name.data();
         std::string buf;
-
-        if (f_ptr->flags.has(TerrainCharacteristics::STORE) || (f_ptr->flags.has(TerrainCharacteristics::BLDG) && !floor_ptr->inside_arena)) {
+        if (terrain.flags.has(TerrainCharacteristics::STORE) || (terrain.flags.has(TerrainCharacteristics::BLDG) && !floor.inside_arena)) {
             buf = format(_("%sの入口", "on the entrance of %s"), fn);
-        } else if (f_ptr->flags.has(TerrainCharacteristics::WALL)) {
+        } else if (terrain.flags.has(TerrainCharacteristics::WALL)) {
             buf = format(_("%sの中", "in %s"), fn);
         } else {
             buf = format(_("%s", "on %s"), fn);
         }
-        line = format(_("(X:%03d Y:%03d) %sの上の発見済みアイテム一覧", "Found items at (X:%03d Y:%03d) %s"), x, y, buf.data());
+
+        line = format(_("(X:%03d Y:%03d) %sの上の発見済みアイテム一覧", "Found items at (X:%03d Y:%03d) %s"), pos.x, pos.y, buf.data());
     }
     term_addstr(-1, TERM_WHITE, line);
 
     // (y,x) のアイテムを1行に1個ずつ書く。
     TERM_LEN term_y = 1;
-    for (const auto o_idx : g_ptr->o_idx_list) {
-        auto *const o_ptr = &floor_ptr->o_list[o_idx];
-        const auto tval = o_ptr->bi_key.tval();
-        if (o_ptr->marked.has_not(OmType::FOUND) || tval == ItemKindType::GOLD) {
+    for (const auto o_idx : grid.o_idx_list) {
+        const auto &item = floor.o_list[o_idx];
+        const auto tval = item.bi_key.tval();
+        if (item.marked.has_not(OmType::FOUND) || tval == ItemKindType::GOLD) {
             continue;
         }
 
         // 途中で行数が足りなくなったら最終行にその旨追記して終了。
-        if (term_y >= term_h) {
+        if (term_y >= hgt) {
             term_addstr(-1, TERM_WHITE, "-- more --");
             break;
         }
@@ -573,7 +606,7 @@ static void display_floor_item_list(PlayerType *player_ptr, const int y, const i
         if (is_hallucinated) {
             term_addstr(-1, TERM_WHITE, _("何か奇妙な物", "something strange"));
         } else {
-            const auto item_name = describe_flavor(player_ptr, o_ptr, 0);
+            const auto item_name = describe_flavor(player_ptr, &item, 0);
             TERM_COLOR attr = tval_to_attr[enum2i(tval) % 128];
             term_addstr(-1, attr, item_name);
         }
@@ -585,11 +618,11 @@ static void display_floor_item_list(PlayerType *player_ptr, const int y, const i
 /*!
  * @brief (y,x) のアイテム一覧をサブウィンドウに表示する / display item at (y,x) in sub-windows
  */
-void fix_floor_item_list(PlayerType *player_ptr, const int y, const int x)
+void fix_floor_item_list(PlayerType *player_ptr, const Pos2D &pos)
 {
-    display_sub_windows(PW_FLOOR_ITEMS,
-        [player_ptr, y, x] {
-            display_floor_item_list(player_ptr, y, x);
+    display_sub_windows(SubWindowRedrawingFlag::FLOOR_ITEMS,
+        [player_ptr, pos] {
+            display_floor_item_list(player_ptr, pos);
         });
 }
 
@@ -599,12 +632,8 @@ void fix_floor_item_list(PlayerType *player_ptr, const int y, const int x)
  */
 static void display_found_item_list(PlayerType *player_ptr)
 {
-    // Term の行数を取得。
-    TERM_LEN term_h;
-    TERM_LEN term_w;
-    term_get_size(&term_w, &term_h);
-
-    if (term_h <= 0) {
+    const auto &[wid, hgt] = term_get_size();
+    if (hgt <= 0) {
         return;
     }
 
@@ -617,9 +646,12 @@ static void display_found_item_list(PlayerType *player_ptr)
     // ItemKindTypeがGOLD
     std::vector<ItemEntity *> found_item_list;
     for (auto &item : floor_ptr->o_list) {
-        auto item_entity_ptr = &item;
-        if (item_entity_ptr->is_valid() && item_entity_ptr->marked.has(OmType::FOUND) && item_entity_ptr->bi_key.tval() != ItemKindType::GOLD) {
-            found_item_list.push_back(item_entity_ptr);
+        const auto is_item_to_display =
+            item.is_valid() && (item.number > 0) &&
+            item.marked.has(OmType::FOUND) && (item.bi_key.tval() != ItemKindType::GOLD);
+
+        if (is_item_to_display) {
+            found_item_list.push_back(&item);
         }
     }
 
@@ -639,7 +671,7 @@ static void display_found_item_list(PlayerType *player_ptr)
     TERM_LEN term_y = 1;
     for (auto item : found_item_list) {
         // 途中で行数が足りなくなったら終了。
-        if (term_y >= term_h) {
+        if (term_y >= hgt) {
             break;
         }
 
@@ -647,17 +679,17 @@ static void display_found_item_list(PlayerType *player_ptr)
 
         // アイテムシンボル表示
         const auto symbol_code = item->get_symbol();
-        const std::string symbol = format(" %c ", symbol_code);
+        const auto symbol = format(" %c ", symbol_code);
         const auto color_code_for_symbol = item->get_color();
-        term_addstr(-1, color_code_for_symbol, symbol.data());
+        term_addstr(-1, color_code_for_symbol, symbol);
 
         const auto item_name = describe_flavor(player_ptr, item, 0);
         const auto color_code_for_item = tval_to_attr[enum2i(item->bi_key.tval()) % 128];
         term_addstr(-1, color_code_for_item, item_name);
 
         // アイテム座標表示
-        const std::string item_location = format("(X:%3d Y:%3d)", item->ix, item->iy);
-        prt(item_location.data(), term_y, term_w - item_location.length() - 1);
+        const auto item_location = format("(X:%3d Y:%3d)", item->ix, item->iy);
+        prt(item_location, term_y, wid - item_location.length() - 1);
 
         ++term_y;
     }
@@ -668,7 +700,7 @@ static void display_found_item_list(PlayerType *player_ptr)
  */
 void fix_found_item_list(PlayerType *player_ptr)
 {
-    display_sub_windows(PW_FOUND_ITEMS,
+    display_sub_windows(SubWindowRedrawingFlag::FOUND_ITEMS,
         [player_ptr] {
             display_found_item_list(player_ptr);
         });
@@ -684,7 +716,7 @@ void fix_found_item_list(PlayerType *player_ptr)
 static void display_spell_list(PlayerType *player_ptr)
 {
     TERM_LEN y, x;
-    int m[9];
+    int m[9]{};
     const magic_type *s_ptr;
     GAME_TEXT name[MAX_NLEN];
 
@@ -775,8 +807,8 @@ static void display_spell_list(PlayerType *player_ptr)
             }
 
             const auto comment = mindcraft_info(player_ptr, use_mind, i);
-
-            term_putstr(x, y + i + 1, -1, a, format("  %c) %-30s%2d %4d %3d%%%s", I2A(i), spell.name, spell.min_lev, spell.mana_cost, chance, comment.data()));
+            constexpr auto fmt = "  %c) %-30s%2d %4d %3d%%%s";
+            term_putstr(x, y + i + 1, -1, a, format(fmt, I2A(i), spell.name, spell.min_lev, spell.mana_cost, chance, comment.data()));
         }
 
         return;
@@ -800,7 +832,8 @@ static void display_spell_list(PlayerType *player_ptr)
                 s_ptr = &mp_ptr->info[((j < 1) ? player_ptr->realm1 : player_ptr->realm2) - 1][i % 32];
             }
 
-            const auto spell_name = exe_spell(player_ptr, (j < 1) ? player_ptr->realm1 : player_ptr->realm2, i % 32, SpellProcessType::NAME);
+            const auto realm = (j < 1) ? player_ptr->realm1 : player_ptr->realm2;
+            const auto spell_name = exe_spell(player_ptr, realm, i % 32, SpellProcessType::NAME);
             strcpy(name, spell_name->data());
 
             if (s_ptr->slevel >= 99) {
@@ -828,34 +861,34 @@ static void display_spell_list(PlayerType *player_ptr)
  */
 void fix_spell(PlayerType *player_ptr)
 {
-    display_sub_windows(PW_SPELL,
+    display_sub_windows(SubWindowRedrawingFlag::SPELL,
         [player_ptr] {
             display_spell_list(player_ptr);
         });
 }
 
 /*!
- * @brief サブウィンドウに所持品、装備品リストの表示を行う /
- * Flip "inven" and "equip" in any sub-windows
+ * @brief サブウィンドウに所持品、装備品リストの表示を行う
  */
-void toggle_inventory_equipment(PlayerType *player_ptr)
+void toggle_inventory_equipment()
 {
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
     for (auto i = 0U; i < angband_terms.size(); ++i) {
         if (!angband_terms[i]) {
             continue;
         }
 
-        if (window_flag[i] & (PW_INVENTORY)) {
-            window_flag[i] &= ~(PW_INVENTORY);
-            window_flag[i] |= (PW_EQUIPMENT);
-            player_ptr->window_flags |= (PW_EQUIPMENT);
+        if (g_window_flags[i].has(SubWindowRedrawingFlag::INVENTORY)) {
+            g_window_flags[i].reset(SubWindowRedrawingFlag::INVENTORY);
+            g_window_flags[i].set(SubWindowRedrawingFlag::EQUIPMENT);
+            rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
             continue;
         }
 
-        if (window_flag[i] & PW_EQUIPMENT) {
-            window_flag[i] &= ~(PW_EQUIPMENT);
-            window_flag[i] |= PW_INVENTORY;
-            player_ptr->window_flags |= PW_INVENTORY;
+        if (g_window_flags[i].has(SubWindowRedrawingFlag::EQUIPMENT)) {
+            g_window_flags[i].reset(SubWindowRedrawingFlag::EQUIPMENT);
+            g_window_flags[i].set(SubWindowRedrawingFlag::INVENTORY);
+            rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
         }
     }
 }
index 902c9aa..0354f61 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
-
+#include "util/point-2d.h"
 #include <vector>
 
 class FloorType;
@@ -10,6 +10,7 @@ class ItemTester;
 void fix_inventory(PlayerType *player_ptr);
 void print_monster_list(FloorType *floor_ptr, const std::vector<MONSTER_IDX> &monster_list, TERM_LEN x, TERM_LEN y, TERM_LEN max_lines);
 void fix_monster_list(PlayerType *player_ptr);
+void fix_pet_list(PlayerType *player_ptr);
 void fix_equip(PlayerType *player_ptr);
 void fix_player(PlayerType *player_ptr);
 void fix_message(void);
@@ -17,10 +18,10 @@ void fix_overhead(PlayerType *player_ptr);
 void fix_dungeon(PlayerType *player_ptr);
 void fix_monster(PlayerType *player_ptr);
 void fix_object(PlayerType *player_ptr);
-void fix_floor_item_list(PlayerType *player_ptr, const int y, const int x);
+void fix_floor_item_list(PlayerType *player_ptr, const Pos2D &pos);
 void fix_found_item_list(PlayerType *player_ptr);
 void fix_spell(PlayerType *player_ptr);
-void toggle_inventory_equipment(PlayerType *player_ptr);
+void toggle_inventory_equipment();
 
 /*!
  * @brief サブウィンドウ表示用の ItemTester オブジェクトを設定するクラス
index 0eb3bf9..224cdc0 100644 (file)
@@ -1,4 +1,4 @@
-#include "window/main-window-equipments.h"
+#include "window/main-window-equipments.h"
 #include "flavor/flavor-describer.h"
 #include "game-option/special-options.h"
 #include "game-option/text-display-options.h"
@@ -35,15 +35,14 @@ COMMAND_CODE show_equipment(PlayerType *player_ptr, int target_item, BIT_FLAGS m
     int j, k, l;
     ItemEntity *o_ptr;
     char tmp_val[80];
-    COMMAND_CODE out_index[23];
-    TERM_COLOR out_color[23];
+    COMMAND_CODE out_index[23]{};
+    TERM_COLOR out_color[23]{};
     std::array<std::string, 23> out_desc{};
     COMMAND_CODE target_item_label = 0;
-    TERM_LEN wid, hgt;
     char equip_label[52 + 1];
-    int col = command_gap;
-    term_get_size(&wid, &hgt);
-    int len = wid - col - 1;
+    auto col = command_gap;
+    const auto &[wid, hgt] = term_get_size();
+    auto len = wid - col - 1;
     for (k = 0, i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
         o_ptr = &player_ptr->inventory_list[i];
         auto only_slot = !(player_ptr->select_ring_slot ? is_ring_slot(i) : (item_tester.okay(o_ptr) || any_bits(mode, USE_FULL)));
index bc6260a..0d4dcc9 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "object/tval-types.h"
 
index 91d935a..bcaa854 100644 (file)
@@ -1,4 +1,5 @@
-#include "window/main-window-left-frame.h"
+#include "window/main-window-left-frame.h"
+#include "dungeon/quest.h"
 #include "game-option/special-options.h"
 #include "game-option/text-display-options.h"
 #include "market/arena-info-table.h"
@@ -8,6 +9,7 @@
 #include "player-info/class-info.h"
 #include "player-info/mimic-info-table.h"
 #include "player/player-status-table.h"
+#include "system/angband-system.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
@@ -48,7 +50,7 @@ void print_title(PlayerType *player_ptr)
             p = _("***勝利者***", "***WINNER***");
         }
     } else {
-        angband_strcpy(str, player_titles[enum2i(player_ptr->pclass)][(player_ptr->lev - 1) / 5].data(), sizeof(str));
+        angband_strcpy(str, player_titles[enum2i(player_ptr->pclass)][(player_ptr->lev - 1) / 5], sizeof(str));
         p = str;
     }
 
@@ -60,7 +62,7 @@ void print_title(PlayerType *player_ptr)
  */
 void print_level(PlayerType *player_ptr)
 {
-    std::string tmp = format("%5d", player_ptr->lev);
+    const auto tmp = format("%5d", player_ptr->lev);
     if (player_ptr->lev >= player_ptr->max_plv) {
         put_str(_("レベル ", "LEVEL "), ROW_LEVEL, 0);
         c_put_str(TERM_L_GREEN, tmp, ROW_LEVEL, COL_LEVEL + 7);
@@ -174,9 +176,7 @@ void print_gold(PlayerType *player_ptr)
 void print_depth(PlayerType *player_ptr)
 {
     TERM_COLOR attr = TERM_WHITE;
-
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
+    const auto &[wid, hgt] = term_get_size();
     TERM_LEN col_depth = wid + COL_DEPTH;
     TERM_LEN row_depth = hgt + ROW_DEPTH;
 
@@ -186,7 +186,7 @@ void print_depth(PlayerType *player_ptr)
         return;
     }
 
-    if (inside_quest(floor_ptr->quest_number) && !player_ptr->dungeon_idx) {
+    if (floor_ptr->is_in_quest() && !floor_ptr->dungeon_idx) {
         c_prt(attr, format("%7s", _("地上", "Quest")), row_depth, col_depth);
         return;
     }
@@ -286,8 +286,9 @@ static void print_health_monster_in_arena_for_wizard(PlayerType *player_ptr)
 
         auto &monster = player_ptr->current_floor_ptr->m_list[monster_list_index];
         if (MonsterRace(monster.r_idx).is_valid()) {
-            term_putstr(col - 2, row + row_offset, 2, monraces_info[monster.r_idx].x_attr,
-                format("%c", monraces_info[monster.r_idx].x_char));
+            const auto &monrace = monster.get_monrace();
+            term_putstr(col - 2, row + row_offset, 2, monrace.x_attr,
+                format("%c", monrace.x_char));
             term_putstr(col - 1, row + row_offset, 5, TERM_WHITE, format("%5d", monster.hp));
             term_putstr(col + 5, row + row_offset, 6, TERM_WHITE, format("%5d", monster.max_maxhp));
         }
@@ -329,36 +330,6 @@ static std::vector<condition_layout_info> get_condition_layout_info(const Monste
 }
 
 /*!
- * @brief 対象のモンスターの状態(無敵、起きているか、HPの割合)に応じてHPバーの色を算出する
- * @param monster 対象のモンスター
- * @return HPバーの色
- */
-static TERM_COLOR get_monster_hp_point_bar_color(const MonsterEntity &monster)
-{
-    auto pct = monster.maxhp > 0 ? 100 * monster.hp / monster.maxhp : 0;
-
-    if (monster.is_invulnerable()) {
-        return TERM_WHITE;
-    }
-    if (monster.is_asleep()) {
-        return TERM_BLUE;
-    }
-    if (pct >= 100) {
-        return TERM_L_GREEN;
-    }
-    if (pct >= 60) {
-        return TERM_YELLOW;
-    }
-    if (pct >= 25) {
-        return TERM_ORANGE;
-    }
-    if (pct >= 10) {
-        return TERM_L_RED;
-    }
-    return TERM_RED;
-}
-
-/*!
  * @brief モンスターの体力ゲージを表示する
  * @param riding TRUEならば騎乗中のモンスターの体力、FALSEならターゲットモンスターの体力を表示する。表示位置は固定。
  * @details
@@ -390,7 +361,7 @@ void print_health(PlayerType *player_ptr, bool riding)
         col = COL_RIDING_INFO;
     } else {
         // ウィザードモードで闘技場観戦時の表示
-        if (w_ptr->wizard && player_ptr->phase_out) {
+        if (w_ptr->wizard && AngbandSystem::get_instance().is_phase_out()) {
             print_health_monster_in_arena_for_wizard(player_ptr);
             return;
         }
@@ -401,32 +372,25 @@ void print_health(PlayerType *player_ptr, bool riding)
         col = COL_INFO;
     }
 
-    const int max_width = 12; // 表示幅
-
-    TERM_LEN width, height;
-    term_get_size(&width, &height);
-    const auto extra_line_count = riding ? 0 : height - MAIN_TERM_MIN_ROWS;
+    const auto max_width = 12; // 表示幅
+    const auto &[wid, hgt] = term_get_size();
+    const auto extra_line_count = riding ? 0 : hgt - MAIN_TERM_MIN_ROWS;
     for (auto y = row; y < row + extra_line_count + 1; ++y) {
         term_erase(col, y, max_width);
     }
 
-    if (!monster_idx.has_value()) {
+    if (!monster_idx) {
         return;
     }
 
-    const auto &monster = player_ptr->current_floor_ptr->m_list[monster_idx.value()];
+    const auto &monster = player_ptr->current_floor_ptr->m_list[*monster_idx];
 
     if ((!monster.ml) || (player_ptr->effects()->hallucination()->is_hallucinated()) || monster.is_dead()) {
         term_putstr(col, row, max_width, TERM_WHITE, "[----------]");
         return;
     }
 
-    // HPの割合計算
-    int pct2 = monster.maxhp > 0 ? 100L * monster.hp / monster.max_maxhp : 0;
-    int len = (pct2 < 10) ? 1 : (pct2 < 90) ? (pct2 / 10 + 1)
-                                            : 10;
-    auto hit_point_bar_color = get_monster_hp_point_bar_color(monster);
-
+    const auto &[hit_point_bar_color, len] = monster.get_hp_bar_data();
     term_putstr(col, row, max_width, TERM_WHITE, "[----------]");
     term_putstr(col + 1, row, len, hit_point_bar_color, "**********");
 
@@ -444,7 +408,7 @@ void print_health(PlayerType *player_ptr, bool riding)
         if (row_offset > extra_line_count) {
             break;
         }
-        if (col_offset + info.label.length() - 1 > max_width) { // 改行が必要かどうかチェック。length() - 1してるのは\0の分を文字数から取り除くため
+        if (col_offset + info.label.length() > max_width) { // 改行が必要かどうかチェック
             col_offset = 0;
             row_offset++;
         }
index 35b8493..055fbcc 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void print_title(PlayerType *player_ptr);
index 87942a6..5103f19 100644 (file)
@@ -1,4 +1,4 @@
-#include "window/main-window-row-column.h"
+#include "window/main-window-row-column.h"
 #include "locale/language-switcher.h"
 
 const std::map<monster_timed_effect_type, std::string> effect_type_to_label = {
index 13b1efb..80e5149 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "monster/monster-timed-effect-types.h"
 #include <map>
index 2edacb2..06b36d1 100644 (file)
@@ -1,4 +1,4 @@
-#include "window/main-window-stat-poster.h"
+#include "window/main-window-stat-poster.h"
 #include "io/input-key-requester.h"
 #include "mind/stances-table.h"
 #include "monster/monster-status.h"
@@ -88,7 +88,7 @@ void print_cut(PlayerType *player_ptr)
     }
 
     auto [color, stat] = player_cut->get_expr();
-    c_put_str(color, stat.data(), ROW_CUT, COL_CUT);
+    c_put_str(color, stat, ROW_CUT, COL_CUT);
 }
 
 /*!
@@ -104,7 +104,7 @@ void print_stun(PlayerType *player_ptr)
     }
 
     auto [color, stat] = player_stun->get_expr();
-    c_put_str(color, stat.data(), ROW_STUN, COL_STUN);
+    c_put_str(color, stat, ROW_STUN, COL_STUN);
 }
 
 /*!
@@ -255,10 +255,9 @@ void print_state(PlayerType *player_ptr)
  */
 void print_speed(PlayerType *player_ptr)
 {
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-    TERM_LEN col_speed = wid + COL_SPEED;
-    TERM_LEN row_speed = hgt + ROW_SPEED;
+    const auto &[wid, hgt] = term_get_size();
+    auto col_speed = wid + COL_SPEED;
+    auto row_speed = hgt + ROW_SPEED;
 
     const auto speed = player_ptr->pspeed - STANDARD_SPEED;
     auto *floor_ptr = player_ptr->current_floor_ptr;
@@ -317,11 +316,9 @@ void print_speed(PlayerType *player_ptr)
  */
 void print_study(PlayerType *player_ptr)
 {
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-    TERM_LEN col_study = wid + COL_STUDY;
-    TERM_LEN row_study = hgt + ROW_STUDY;
-
+    const auto &[wid, hgt] = term_get_size();
+    const auto col_study = wid + COL_STUDY;
+    const auto row_study = hgt + ROW_STUDY;
     if (player_ptr->new_spells) {
         put_str(_("学習", "Stud"), row_study, col_study);
     } else {
@@ -335,11 +332,9 @@ void print_study(PlayerType *player_ptr)
  */
 void print_imitation(PlayerType *player_ptr)
 {
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-    TERM_LEN col_study = wid + COL_STUDY;
-    TERM_LEN row_study = hgt + ROW_STUDY;
-
+    const auto &[wid, hgt] = term_get_size();
+    const auto col_study = wid + COL_STUDY;
+    const auto row_study = hgt + ROW_STUDY;
     PlayerClass pc(player_ptr);
     if (!pc.equals(PlayerClassType::IMITATOR)) {
         return;
@@ -450,16 +445,11 @@ static void add_hex_status_flags(PlayerType *player_ptr, BIT_FLAGS *bar_flags)
  */
 void print_status(PlayerType *player_ptr)
 {
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-    TERM_LEN row_statbar = hgt + ROW_STATBAR;
-    TERM_LEN max_col_statbar = wid + MAX_COL_STATBAR;
-
+    const auto &[wid, hgt] = term_get_size();
+    const auto row_statbar = hgt + ROW_STATBAR;
+    const auto max_col_statbar = wid + MAX_COL_STATBAR;
     term_erase(0, row_statbar, max_col_statbar);
-
-    BIT_FLAGS bar_flags[3];
-    bar_flags[0] = bar_flags[1] = bar_flags[2] = 0L;
-
+    BIT_FLAGS bar_flags[3]{};
     auto effects = player_ptr->effects();
     if (player_ptr->tsuyoshi) {
         ADD_BAR_FLAG(BAR_TSUYOSHI);
@@ -489,7 +479,7 @@ void print_status(PlayerType *player_ptr)
         ADD_BAR_FLAG(BAR_SENSEUNSEEN);
     }
 
-    auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
+    auto sniper_data = PlayerClass(player_ptr).get_specific_data<SniperData>();
     if (sniper_data && (sniper_data->concent >= CONCENT_RADAR_THRESHOLD)) {
         ADD_BAR_FLAG(BAR_SENSEUNSEEN);
         ADD_BAR_FLAG(BAR_NIGHTSIGHT);
index 13bab0f..78a3075 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void print_stat(PlayerType *player_ptr, int stat);
index d7e5d0c..dba6905 100644 (file)
@@ -1,4 +1,4 @@
-#include "window/main-window-util.h"
+#include "window/main-window-util.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "floor/cave.h"
@@ -71,9 +71,7 @@ void print_field(concptr info, TERM_LEN row, TERM_LEN col)
  */
 void print_map(PlayerType *player_ptr)
 {
-    TERM_LEN wid, hgt;
-    term_get_size(&wid, &hgt);
-
+    auto [wid, hgt] = term_get_size();
     wid -= COL_MAP + 2;
     hgt -= ROW_MAP + 2;
 
@@ -180,9 +178,8 @@ void display_map(PlayerType *player_ptr, int *cy, int *cx)
     bool old_view_special_lite = view_special_lite;
     bool old_view_granite_lite = view_granite_lite;
 
-    TERM_LEN border_width = use_bigtile ? 2 : 1; //!< @note 枠線幅
-    TERM_LEN hgt, wid, yrat, xrat;
-    term_get_size(&wid, &hgt);
+    auto border_width = use_bigtile ? 2 : 1; //!< @note 枠線幅
+    auto [wid, hgt] = term_get_size();
     hgt -= 2;
     wid -= 12 + border_width * 2; //!< @note 描画桁数(枠線抜)
     if (use_bigtile) {
@@ -190,8 +187,8 @@ void display_map(PlayerType *player_ptr, int *cy, int *cx)
     }
 
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    yrat = (floor_ptr->height + hgt - 1) / hgt;
-    xrat = (floor_ptr->width + wid - 1) / wid;
+    const auto yrat = (floor_ptr->height + hgt - 1) / hgt;
+    const auto xrat = (floor_ptr->width + wid - 1) / wid;
     view_special_lite = false;
     view_granite_lite = false;
 
@@ -317,7 +314,7 @@ void display_map(PlayerType *player_ptr, int *cy, int *cx)
 
 void set_term_color(PlayerType *player_ptr, POSITION y, POSITION x, TERM_COLOR *ap, char *cp)
 {
-    if (!player_bold(player_ptr, y, x)) {
+    if (!player_ptr->is_located_at({ y, x })) {
         return;
     }
 
index 3196536..5acfee3 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 9501ffb..0879e11 100644 (file)
@@ -1,11 +1,10 @@
-#include "wizard/artifact-analyzer.h"
+#include "wizard/artifact-analyzer.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "locale/japanese.h"
 #include "object-enchant/object-ego.h"
 #include "object-enchant/trc-types.h"
 #include "object-enchant/trg-types.h"
-#include "object/object-flags.h"
 #include "object/object-info.h"
 #include "system/artifact-type-definition.h"
 #include "system/item-entity.h"
 #include "util/bit-flags-calculator.h"
 #include "util/enum-converter.h"
 #include "util/enum-range.h"
-#include "util/quarks.h"
 #include "util/string-processor.h"
 #include "wizard/spoiler-util.h"
-
-/*!
- * @brief アーティファクトの特性一覧を出力する /
- * Write a line to the spoiler file and then "underline" it with hypens
- * @param art_flags アーティファクトのフラグ群
- * @param flag_ptr フラグ記述情報の参照ポインタ
- * @param desc_ptr 記述内容を返すための文字列参照ポインタ
- * @param n_elmnts フラグの要素数
- * @return desc_ptrと同じアドレス
- * @details
- * <pre>
- * This function does most of the actual "analysis". Given a set of bit flags
- * (which will be from one of the flags fields from the object in question),
- * a "flag description structure", a "description list", and the number of
- * elements in the "flag description structure", this function sets the
- * "description list" members to the appropriate descriptions contained in
- * the "flag description structure".
- * The possibly updated description pointer is returned.
- * </pre>
- */
-static concptr *spoiler_flag_aux(const TrFlags &art_flags, const flag_desc *flag_ptr, concptr *desc_ptr, const int n_elmnts)
-{
-    for (int i = 0; i < n_elmnts; ++i) {
-        if (art_flags.has(flag_ptr[i].flag)) {
-            *desc_ptr++ = flag_ptr[i].desc;
-        }
-    }
-
-    return desc_ptr;
-}
+#include <sstream>
 
 /*!
  * @brief アイテムの特定記述内容を返す /
@@ -53,50 +22,21 @@ static concptr *spoiler_flag_aux(const TrFlags &art_flags, const flag_desc *flag
  * @param o_ptr 記述を得たいオブジェクトの参照ポインタ
  * @param desc_ptr 記述内容を返すための文字列参照ポインタ
  */
-static std::string analyze_general(PlayerType *player_ptr, ItemEntity *o_ptr)
+static std::string analyze_general(PlayerType *player_ptr, const ItemEntity *o_ptr)
 {
     return describe_flavor(player_ptr, o_ptr, OD_NAME_AND_ENCHANT | OD_STORE | OD_DEBUG);
 }
 
 /*!
- * @brief アーティファクトがプレイヤーに与えるpval修正を構造体に収める /
- * List "player traits" altered by an artifact's pval. These include stats,
- * speed, infravision, tunneling, stealth, searching, and extra attacks.
- * @param o_ptr オブジェクト構造体の参照ポインタ
- * @param pi_ptr pval修正構造体の参照ポインタ
- */
-static void analyze_pval(ItemEntity *o_ptr, pval_info_type *pi_ptr)
-{
-    concptr *affects_list;
-    if (!o_ptr->pval) {
-        pi_ptr->pval_desc[0] = '\0';
-        return;
-    }
-
-    auto flags = object_flags(o_ptr);
-    affects_list = pi_ptr->pval_affects;
-    strnfmt(pi_ptr->pval_desc, sizeof(pi_ptr->pval_desc), "%s%d", o_ptr->pval >= 0 ? "+" : "", o_ptr->pval);
-    if (flags.has_all_of(EnumRange(TR_STR, TR_CHR))) {
-        *affects_list++ = _("全能力", "All stats");
-    } else if (flags.has_any_of(EnumRange(TR_STR, TR_CHR))) {
-        affects_list = spoiler_flag_aux(flags, stat_flags_desc, affects_list, N_ELEMENTS(stat_flags_desc));
-    }
-
-    affects_list = spoiler_flag_aux(flags, pval_flags1_desc, affects_list, N_ELEMENTS(pval_flags1_desc));
-    *affects_list = nullptr;
-}
-
-/*!
  * @brief アーティファクトの種族スレイ特性を構造体に収める /
  * Note the slaying specialties of a weapon
  * @param o_ptr オブジェクト構造体の参照ポインタ
  * @param slay_list 種族スレイ構造体の参照ポインタ
  */
-static void analyze_slay(ItemEntity *o_ptr, concptr *slay_list)
+static std::vector<std::string> analyze_slay(const ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
-    slay_list = spoiler_flag_aux(flags, slay_flags_desc, slay_list, N_ELEMENTS(slay_flags_desc));
-    *slay_list = nullptr;
+    const auto flags = o_ptr->get_flags();
+    return extract_spoiler_flags(flags, slay_flags_desc);
 }
 
 /*!
@@ -105,11 +45,10 @@ static void analyze_slay(ItemEntity *o_ptr, concptr *slay_list)
  * @param o_ptr オブジェクト構造体の参照ポインタ
  * @param brand_list 属性ブランド構造体の参照ポインタ
  */
-static void analyze_brand(ItemEntity *o_ptr, concptr *brand_list)
+static std::vector<std::string> analyze_brand(const ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
-    brand_list = spoiler_flag_aux(flags, brand_flags_desc, brand_list, N_ELEMENTS(brand_flags_desc));
-    *brand_list = nullptr;
+    const auto flags = o_ptr->get_flags();
+    return extract_spoiler_flags(flags, brand_flags_desc);
 }
 
 /*!
@@ -118,11 +57,10 @@ static void analyze_brand(ItemEntity *o_ptr, concptr *brand_list)
  * @param o_ptr オブジェクト構造体の参照ポインタ
  * @param resist_list 通常耐性構造体の参照ポインタ
  */
-static void analyze_resist(ItemEntity *o_ptr, concptr *resist_list)
+static std::vector<std::string> analyze_resist(const ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
-    resist_list = spoiler_flag_aux(flags, resist_flags_desc, resist_list, N_ELEMENTS(resist_flags_desc));
-    *resist_list = nullptr;
+    const auto flags = o_ptr->get_flags();
+    return extract_spoiler_flags(flags, resist_flags_desc);
 }
 
 /*!
@@ -131,11 +69,10 @@ static void analyze_resist(ItemEntity *o_ptr, concptr *resist_list)
  * @param o_ptr オブジェクト構造体の参照ポインタ
  * @param immune_list 免疫構造体の参照ポインタ
  */
-static void analyze_immune(ItemEntity *o_ptr, concptr *immune_list)
+static std::vector<std::string> analyze_immune(const ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
-    immune_list = spoiler_flag_aux(flags, immune_flags_desc, immune_list, N_ELEMENTS(immune_flags_desc));
-    *immune_list = nullptr;
+    const auto flags = o_ptr->get_flags();
+    return extract_spoiler_flags(flags, immune_flags_desc);
 }
 
 /*!
@@ -144,11 +81,10 @@ static void analyze_immune(ItemEntity *o_ptr, concptr *immune_list)
  * @param o_ptr オブジェクト構造体の参照ポインタ
  * @param immune_list 弱点構造体の参照ポインタ
  */
-static void analyze_vulnerable(ItemEntity *o_ptr, concptr *vulnerable_list)
+static std::vector<std::string> analyze_vulnerable(const ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
-    vulnerable_list = spoiler_flag_aux(flags, vulnerable_flags_desc, vulnerable_list, N_ELEMENTS(vulnerable_flags_desc));
-    *vulnerable_list = nullptr;
+    const auto flags = o_ptr->get_flags();
+    return extract_spoiler_flags(flags, vulnerable_flags_desc);
 }
 
 /*!
@@ -157,16 +93,18 @@ static void analyze_vulnerable(ItemEntity *o_ptr, concptr *vulnerable_list)
  * @param o_ptr オブジェクト構造体の参照ポインタ
  * @param sustain_list 維持特性構造体の参照ポインタ
  */
-static void analyze_sustains(ItemEntity *o_ptr, concptr *sustain_list)
+static std::vector<std::string> analyze_sustains(const ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
+    const auto flags = o_ptr->get_flags();
     if (flags.has_all_of(EnumRange(TR_SUST_STR, TR_SUST_CHR))) {
-        *sustain_list++ = _("全能力", "All stats");
-    } else if (flags.has_any_of(EnumRange(TR_SUST_STR, TR_SUST_CHR))) {
-        sustain_list = spoiler_flag_aux(flags, sustain_flags_desc, sustain_list, N_ELEMENTS(sustain_flags_desc));
+        return { _("全能力", "All stats") };
+    }
+
+    if (flags.has_any_of(EnumRange(TR_SUST_STR, TR_SUST_CHR))) {
+        return extract_spoiler_flags(flags, sustain_flags_desc);
     }
 
-    *sustain_list = nullptr;
+    return {};
 }
 
 /*!
@@ -176,11 +114,14 @@ static void analyze_sustains(ItemEntity *o_ptr, concptr *sustain_list)
  * @param o_ptr オブジェクト構造体の参照ポインタ
  * @param misc_list その他の特性構造体の参照ポインタ
  */
-static void analyze_misc_magic(ItemEntity *o_ptr, concptr *misc_list)
+static std::vector<std::string> analyze_misc_magic(const ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
-    misc_list = spoiler_flag_aux(flags, misc_flags2_desc, misc_list, N_ELEMENTS(misc_flags2_desc));
-    misc_list = spoiler_flag_aux(flags, misc_flags3_desc, misc_list, N_ELEMENTS(misc_flags3_desc));
+    std::vector<std::string> descriptions{};
+    const auto flags = o_ptr->get_flags();
+    const auto &flags2_descriptions = extract_spoiler_flags(flags, misc_flags2_desc);
+    descriptions.insert(descriptions.end(), flags2_descriptions.begin(), flags2_descriptions.end());
+    const auto &flags3_descriptions = extract_spoiler_flags(flags, misc_flags3_desc);
+    descriptions.insert(descriptions.end(), flags3_descriptions.begin(), flags3_descriptions.end());
     POSITION rad = 0;
     if (flags.has(TR_LITE_1)) {
         rad += 1;
@@ -224,30 +165,30 @@ static void analyze_misc_magic(ItemEntity *o_ptr, concptr *misc_list)
     }
 
     if (rad != 0) {
-        *misc_list++ = quark_str(quark_add(desc.data()));
+        descriptions.push_back(std::move(desc));
     }
 
     if (flags.has(TR_TY_CURSE)) {
-        *misc_list++ = _("太古の怨念", "Ancient Curse");
+        descriptions.emplace_back(_("太古の怨念", "Ancient Curse"));
     }
 
     if (o_ptr->curse_flags.has(CurseTraitType::PERMA_CURSE)) {
-        *misc_list++ = _("永遠の呪い", "Permanently Cursed");
+        descriptions.emplace_back(_("永遠の呪い", "Permanently Cursed"));
     } else if (o_ptr->curse_flags.has(CurseTraitType::HEAVY_CURSE)) {
-        *misc_list++ = _("強力な呪い", "Heavily Cursed");
+        descriptions.emplace_back(_("強力な呪い", "Heavily Cursed"));
     } else if (o_ptr->curse_flags.has(CurseTraitType::CURSED)) {
-        *misc_list++ = _("呪い", "Cursed");
+        descriptions.emplace_back(_("呪い", "Cursed"));
     }
 
     if (flags.has(TR_ADD_L_CURSE)) {
-        *misc_list++ = _("呪いを増やす", "Cursing");
+        descriptions.emplace_back(_("呪いを増やす", "Cursing"));
     }
 
     if (flags.has(TR_ADD_H_CURSE)) {
-        *misc_list++ = _("強力な呪いを増やす", "Heavily Cursing");
+        descriptions.emplace_back(_("強力な呪いを増やす", "Heavily Cursing"));
     }
 
-    *misc_list = nullptr;
+    return descriptions;
 }
 
 /*!
@@ -257,33 +198,36 @@ static void analyze_misc_magic(ItemEntity *o_ptr, concptr *misc_list)
  * @param addition 追加ランダム耐性構造体の参照ポインタ
  * @param addition_sz addition に書き込めるバイト数
  */
-static void analyze_addition(ItemEntity *o_ptr, char *addition, size_t addition_sz)
+static std::string analyze_addition(const ItemEntity *o_ptr)
 {
     const auto &artifact = o_ptr->get_fixed_artifact();
-    strcpy(addition, "");
-
+    std::stringstream ss;
     if (artifact.gen_flags.has_all_of({ ItemGenerationTraitType::XTRA_POWER, ItemGenerationTraitType::XTRA_H_RES })) {
-        angband_strcat(addition, _("能力and耐性", "Ability and Resistance"), addition_sz);
+        ss << _("能力and耐性", "Ability and Resistance");
     } else if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_POWER)) {
-        angband_strcat(addition, _("能力", "Ability"), addition_sz);
+        ss << _("能力", "Ability");
         if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_RES_OR_POWER)) {
-            angband_strcat(addition, _("(1/2でand耐性)", "(plus Resistance about 1/2)"), addition_sz);
+            ss << _("(1/2でand耐性)", "(plus Resistance about 1/2)");
         }
     } else if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_H_RES)) {
-        angband_strcat(addition, _("耐性", "Resistance"), addition_sz);
+        ss << _("耐性", "Resistance");
         if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_RES_OR_POWER)) {
-            angband_strcat(addition, _("(1/2でand能力)", "(plus Ability about 1/2)"), addition_sz);
+            ss << _("(1/2でand能力)", "(plus Ability about 1/2)");
         }
     } else if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_RES_OR_POWER)) {
-        angband_strcat(addition, _("能力or耐性", "Ability or Resistance"), addition_sz);
+        ss << _("能力or耐性", "Ability or Resistance");
     }
 
-    if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_DICE)) {
-        if (strlen(addition) > 0) {
-            angband_strcat(addition, _("、", ", "), addition_sz);
-        }
-        angband_strcat(addition, _("ダイス数", "Dice number"), addition_sz);
+    if (artifact.gen_flags.has_not(ItemGenerationTraitType::XTRA_DICE)) {
+        return ss.str();
+    }
+
+    if (ss.tellp() > 0) {
+        ss << _("、", ", ");
     }
+
+    ss << _("ダイス数", "Dice number");
+    return ss.str();
 }
 
 /*!
@@ -294,57 +238,60 @@ static void analyze_addition(ItemEntity *o_ptr, char *addition, size_t addition_
  * @param misc_desc 基本情報を収める文字列参照ポインタ
  * @param misc_desc_sz misc_desc に書き込めるバイト数
  */
-static void analyze_misc(ItemEntity *o_ptr, char *misc_desc, size_t misc_desc_sz)
+static std::string analyze_misc(const ItemEntity *o_ptr)
 {
     const auto &artifact = o_ptr->get_fixed_artifact();
-    const auto *mes = _("レベル %d, 希少度 %u, %d.%d kg, $%ld", "Level %d, Rarity %u, %d.%d lbs, %ld Gold");
-    strnfmt(misc_desc, misc_desc_sz, mes, (int)artifact.level, artifact.rarity,
-        _(lb_to_kg_integer(artifact.weight), artifact.weight / 10), _(lb_to_kg_fraction(artifact.weight), artifact.weight % 10), (long int)artifact.cost);
+    constexpr auto fmt = _("レベル %d, 希少度 %u, %d.%d kg, $%d", "Level %d, Rarity %u, %d.%d lbs, %d Gold");
+    const auto weight_integer = _(lb_to_kg_integer(artifact.weight), artifact.weight / 10);
+    const auto weight_fraction = _(lb_to_kg_fraction(artifact.weight), artifact.weight % 10);
+    return format(fmt, artifact.level, artifact.rarity, weight_integer, weight_fraction, artifact.cost);
 }
 
 /*!
- * @brief アーティファクトの情報全体を構造体に収める /
- * Fill in an object description structure for a given object
- * and its value in gold pieces
+ * @brief アーティファクトの情報全体を構造体に収める
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param o_ptr オブジェクト構造体の参照ポインタ
- * @param desc_ptr 全アーティファクト情報を収める文字列参照ポインタ
  */
-void object_analyze(PlayerType *player_ptr, ItemEntity *o_ptr, obj_desc_list *desc_ptr)
+ArtifactsDumpInfo object_analyze(PlayerType *player_ptr, const ItemEntity *o_ptr)
 {
-    angband_strcpy(desc_ptr->description, analyze_general(player_ptr, o_ptr).data(), MAX_NLEN);
-    analyze_pval(o_ptr, &desc_ptr->pval_info);
-    analyze_brand(o_ptr, desc_ptr->brands);
-    analyze_slay(o_ptr, desc_ptr->slays);
-    analyze_immune(o_ptr, desc_ptr->immunities);
-    analyze_resist(o_ptr, desc_ptr->resistances);
-    analyze_vulnerable(o_ptr, desc_ptr->vulnerables);
-    analyze_sustains(o_ptr, desc_ptr->sustains);
-    analyze_misc_magic(o_ptr, desc_ptr->misc_magic);
-    analyze_addition(o_ptr, desc_ptr->addition, sizeof(desc_ptr->addition));
-    analyze_misc(o_ptr, desc_ptr->misc_desc, sizeof(desc_ptr->misc_desc));
-    desc_ptr->activation = activation_explanation(o_ptr);
+    ArtifactsDumpInfo info{};
+    info.description = analyze_general(player_ptr, o_ptr);
+    info.pval_info.analyze(*o_ptr);
+    info.brands = analyze_brand(o_ptr);
+    info.slays = analyze_slay(o_ptr);
+    info.immunities = analyze_immune(o_ptr);
+    info.resistances = analyze_resist(o_ptr);
+    info.vulnerabilities = analyze_vulnerable(o_ptr);
+    info.sustenances = analyze_sustains(o_ptr);
+    info.misc_magic = analyze_misc_magic(o_ptr);
+    info.addition = analyze_addition(o_ptr);
+    info.misc_desc = analyze_misc(o_ptr);
+    info.activation = o_ptr->explain_activation();
+    return info;
 }
 
 /*!
- * @brief ランダムアーティファクト1件を解析する /
- * Fill in an object description structure for a given object
+ * @brief ランダムアーティファクト1件を解析する
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param o_ptr ランダムアーティファクトのオブジェクト構造体参照ポインタ
  * @param desc_ptr 記述内容を収める構造体参照ポインタ
  */
-void random_artifact_analyze(PlayerType *player_ptr, ItemEntity *o_ptr, obj_desc_list *desc_ptr)
+ArtifactsDumpInfo random_artifact_analyze(PlayerType *player_ptr, const ItemEntity *o_ptr)
 {
-    angband_strcpy(desc_ptr->description, analyze_general(player_ptr, o_ptr).data(), MAX_NLEN);
-    analyze_pval(o_ptr, &desc_ptr->pval_info);
-    analyze_brand(o_ptr, desc_ptr->brands);
-    analyze_slay(o_ptr, desc_ptr->slays);
-    analyze_immune(o_ptr, desc_ptr->immunities);
-    analyze_resist(o_ptr, desc_ptr->resistances);
-    analyze_vulnerable(o_ptr, desc_ptr->vulnerables);
-    analyze_sustains(o_ptr, desc_ptr->sustains);
-    analyze_misc_magic(o_ptr, desc_ptr->misc_magic);
-    desc_ptr->activation = activation_explanation(o_ptr);
-    strnfmt(desc_ptr->misc_desc, sizeof(desc_ptr->misc_desc), _("重さ %d.%d kg", "Weight %d.%d lbs"), _(lb_to_kg_integer(o_ptr->weight), o_ptr->weight / 10),
-        _(lb_to_kg_fraction(o_ptr->weight), o_ptr->weight % 10));
+    ArtifactsDumpInfo info{};
+    info.description = analyze_general(player_ptr, o_ptr);
+    info.pval_info.analyze(*o_ptr);
+    info.brands = analyze_brand(o_ptr);
+    info.slays = analyze_slay(o_ptr);
+    info.immunities = analyze_immune(o_ptr);
+    info.resistances = analyze_resist(o_ptr);
+    info.vulnerabilities = analyze_vulnerable(o_ptr);
+    info.sustenances = analyze_sustains(o_ptr);
+    info.misc_magic = analyze_misc_magic(o_ptr);
+    info.activation = o_ptr->explain_activation();
+    constexpr auto weight_mes = _("重さ %d.%d kg", "Weight %d.%d lbs");
+    const auto weight_integer = _(lb_to_kg_integer(o_ptr->weight), o_ptr->weight / 10);
+    const auto weight_fraction = _(lb_to_kg_fraction(o_ptr->weight), o_ptr->weight % 10);
+    info.misc_desc = format(weight_mes, weight_integer, weight_fraction);
+    return info;
 }
index 4c5ad17..6b422b8 100644 (file)
@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 
 class ItemEntity;
-struct obj_desc_list;
+class ArtifactsDumpInfo;
 class PlayerType;
-void object_analyze(PlayerType *player_ptr, ItemEntity *o_ptr, obj_desc_list *desc_ptr);
-void random_artifact_analyze(PlayerType *player_ptr, ItemEntity *o_ptr, obj_desc_list *desc_ptr);
+ArtifactsDumpInfo object_analyze(PlayerType *player_ptr, const ItemEntity *o_ptr);
+ArtifactsDumpInfo random_artifact_analyze(PlayerType *player_ptr, const ItemEntity *o_ptr);
index 66e2ca6..54820eb 100644 (file)
@@ -1,4 +1,4 @@
-#include "wizard/artifact-bias-table.h"
+#include "wizard/artifact-bias-table.h"
 
 /*!
  * @brief ランダムアーティファクトのバイアス名称テーブル
index 0fb1d03..7141e6b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "artifact/random-art-bias-types.h"
 #include "system/angband.h"
index 4e1b3cd..fe01715 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief デバッグコマンドの分岐実装
  * @date 2020/08/01
  * @author Hourier
@@ -35,6 +35,7 @@
 #include "wizard/wizard-special-process.h"
 #include "wizard/wizard-spells.h"
 #include "wizard/wizard-spoiler.h"
+#include <algorithm>
 #include <sstream>
 #include <string>
 #include <tuple>
@@ -70,7 +71,8 @@ constexpr std::array debug_menu_table = {
     std::make_tuple('p', _("ショート・テレポート", "Phase door")),
     std::make_tuple('P', _("プレイヤー設定変更メニュー", "Modify player configurations")),
     std::make_tuple('r', _("カオスパトロンの報酬", "Get reward of chaos patron")),
-    std::make_tuple('s', _("フロア相当のモンスター召喚", "Summon monster which be in target depth")),
+    std::make_tuple('s', _("フロア相当のモンスター生成", "Generate monster which be in target depth")),
+    std::make_tuple('S', _("フロア相当のモンスター召喚", "Summon monster which be in target depth")),
     std::make_tuple('t', _("テレポート", "Teleport self")),
     std::make_tuple('u', _("啓蒙(忍者以外)", "Wiz-lite all floor except Ninja")),
     std::make_tuple('w', _("啓蒙(忍者配慮)", "Wiz-lite all floor")),
@@ -109,7 +111,7 @@ void display_debug_menu(int page, int max_page, int page_size, int max_line)
         std::stringstream ss;
         const auto &[symbol, desc] = debug_menu_table[pos];
         ss << symbol << ") " << desc;
-        put_str(ss.str().data(), r++, c);
+        put_str(ss.str(), r++, c);
     }
     if (max_page > 1) {
         put_str("-- more --", r++, c);
@@ -133,28 +135,28 @@ bool exe_cmd_debug(PlayerType *player_ptr, char cmd)
     case ESCAPE:
     case '\n':
     case '\r':
-        break;
+        return true;
     case 'a':
         wiz_cure_all(player_ptr);
-        break;
+        return true;
     case 'b':
         wiz_teleport_back(player_ptr);
-        break;
+        return true;
     case 'c':
         wiz_create_item(player_ptr);
-        break;
+        return true;
     case 'C':
         wiz_create_named_art(player_ptr);
-        break;
+        return true;
     case 'd':
         detect_all(player_ptr, DETECT_RAD_ALL * 3);
-        break;
+        return true;
     case 'D':
         wiz_dimension_door(player_ptr);
-        break;
+        return true;
     case 'e':
         wiz_change_status(player_ptr);
-        break;
+        return true;
     case 'E':
         switch (player_ptr->pclass) {
         case PlayerClassType::BLUE_MAGE:
@@ -166,65 +168,67 @@ bool exe_cmd_debug(PlayerType *player_ptr, char cmd)
         default:
             break;
         }
-        break;
+
+        return true;
     case 'f':
         identify_fully(player_ptr, false);
-        break;
+        return true;
     case 'F':
         wiz_create_feature(player_ptr);
-        break;
+        return true;
     case 'G':
         wizard_game_modifier(player_ptr);
-        break;
+        return true;
     case 'H':
         wiz_summon_horde(player_ptr);
-        break;
+        return true;
     case 'i':
         (void)ident_spell(player_ptr, false);
-        break;
+        return true;
     case 'I':
         wizard_item_modifier(player_ptr);
-        break;
+        return true;
     case 'j':
         wiz_jump_to_dungeon(player_ptr);
-        break;
+        return true;
     case 'k':
         wiz_kill_target(player_ptr, 0, (AttributeType)command_arg, true);
-        break;
+        return true;
     case 'm':
         map_area(player_ptr, DETECT_RAD_ALL * 3);
-        break;
-    case 'r':
-        patron_list[player_ptr->chaos_patron].gain_level_reward(player_ptr, command_arg);
-        break;
+        return true;
+    case 'n':
+        wiz_summon_specific_monster(player_ptr, i2enum<MonsterRaceId>(command_arg));
+        return true;
     case 'N':
         wiz_summon_pet(player_ptr, i2enum<MonsterRaceId>(command_arg));
-        break;
-    case 'n':
-        wiz_summon_specific_enemy(player_ptr, i2enum<MonsterRaceId>(command_arg));
-        break;
-    case 'O':
-        wiz_dump_options();
-        break;
+        return true;
     case 'o':
         wiz_modify_item(player_ptr);
-        break;
+        return true;
+    case 'O':
+        wiz_dump_options();
+        return true;
     case 'p':
         teleport_player(player_ptr, 10, TELEPORT_SPONTANEOUS);
-        break;
+        return true;
     case 'P':
         wizard_player_modifier(player_ptr);
-        break;
+        return true;
+    case 'r':
+        patron_list[player_ptr->chaos_patron].gain_level_reward(player_ptr, command_arg);
+        return true;
     case 's':
-        if (command_arg <= 0) {
-            command_arg = 1;
-        }
-
-        wiz_summon_random_enemy(player_ptr, command_arg);
-        break;
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_generate_random_monster(player_ptr, command_arg);
+        return true;
+    case 'S':
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_summon_random_monster(player_ptr, command_arg);
+        return true;
     case 't':
         teleport_player(player_ptr, 100, TELEPORT_SPONTANEOUS);
-        break;
+        return true;
     case 'u':
         for (int y = 0; y < player_ptr->current_floor_ptr->height; y++) {
             for (int x = 0; x < player_ptr->current_floor_ptr->width; x++) {
@@ -233,13 +237,13 @@ bool exe_cmd_debug(PlayerType *player_ptr, char cmd)
         }
 
         wiz_lite(player_ptr, false);
-        break;
+        return true;
     case 'w':
         wiz_lite(player_ptr, PlayerClass(player_ptr).equals(PlayerClassType::NINJA));
-        break;
+        return true;
     case 'x':
         gain_exp(player_ptr, command_arg ? command_arg : (player_ptr->exp + 1));
-        break;
+        return true;
     case 'X':
         for (INVENTORY_IDX i = INVEN_TOTAL - 1; i >= 0; i--) {
             if (player_ptr->inventory_list[i].is_valid()) {
@@ -248,37 +252,35 @@ bool exe_cmd_debug(PlayerType *player_ptr, char cmd)
         }
 
         player_outfit(player_ptr);
-        break;
+        return true;
     case 'y':
         wiz_kill_target(player_ptr);
-        break;
+        return true;
     case 'Y':
         wiz_kill_target(player_ptr, 0, (AttributeType)command_arg);
-        break;
+        return true;
     case 'z':
         wiz_zap_surrounding_monsters(player_ptr);
-        break;
+        return true;
     case 'Z':
         wiz_zap_floor_monsters(player_ptr);
-        break;
+        return true;
     case '_':
         probing(player_ptr);
-        break;
+        return true;
     case '@':
         wiz_debug_spell(player_ptr);
-        break;
+        return true;
     case '"':
         exe_output_spoilers();
-        break;
+        return true;
     case '?':
         do_cmd_help(player_ptr);
-        break;
+        return true;
     default:
         msg_print("That is not a valid debug command.");
-        break;
+        return true;
     }
-
-    return true;
 }
 
 /*!
@@ -291,23 +293,18 @@ bool exe_cmd_debug(PlayerType *player_ptr, char cmd)
  */
 void do_cmd_debug(PlayerType *player_ptr)
 {
-    TERM_LEN hgt, wid;
-    term_get_size(&wid, &hgt);
-
-    size_t max_line = debug_menu_table.size();
-    int page_size = hgt - 5;
-    int max_page = max_line / page_size + 1;
-    int page = 0;
-    char cmd;
-
+    const auto &[wid, hgt] = term_get_size();
+    const auto max_line = debug_menu_table.size();
+    const auto page_size = hgt - 5;
+    const auto max_page = max_line / page_size + 1;
+    auto page = 0;
     while (true) {
         screen_save();
         display_debug_menu(page, max_page, page_size, max_line);
-        get_com("Debug Command: ", &cmd, false);
+        const auto command = input_command("Debug Command: ");
         screen_load();
-
-        if (exe_cmd_debug(player_ptr, cmd)) {
-            break;
+        if (exe_cmd_debug(player_ptr, command.value_or(ESCAPE))) {
+            return;
         }
 
         page = (page + 1) % max_page;
index b6be59a..c4be183 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void do_cmd_debug(PlayerType *player_ptr);
index cbd6735..fd55571 100644 (file)
@@ -1,4 +1,4 @@
-#include "wizard/fixed-artifacts-spoiler.h"
+#include "wizard/fixed-artifacts-spoiler.h"
 #include "io/files-util.h"
 #include "object/object-kind-hook.h"
 #include "system/angband-version.h"
 #include "view/display-messages.h"
 #include "wizard/artifact-analyzer.h"
 #include "wizard/spoiler-util.h"
+#include <sstream>
 
 /*!
  * @brief フラグ名称を出力する汎用関数
  * @param header ヘッダに出力するフラグ群の名前
- * @param list フラグ名リスト
+ * @param descriptions フラグ名リスト
  * @param separator フラグ表示の区切り記号
- * @todo 固定アーティファクトとランダムアーティファクトで共用、ここに置くべきかは要調整.
  */
-void spoiler_outlist(concptr header, concptr *list, char separator)
+void spoiler_outlist(std::string_view header, const std::vector<std::string> &descriptions, char separator, std::ofstream &ofs)
 {
-    if (*list == nullptr) {
+    if (descriptions.empty()) {
         return;
     }
 
-    std::string line = spoiler_indent;
-    if (header && (header[0])) {
-        line.append(header).append(" ");
+    std::stringstream line;
+    line << spoiler_indent;
+    if (!header.empty()) {
+        line << header << " ";
     }
 
-    while (true) {
-        std::string elem = *list;
-        if (list[1]) {
-            elem.push_back(separator);
-            elem.push_back(' ');
+    std::stringstream ss;
+    ss << list_separator << ' ';
+    const auto last_separator = ss.str();
+    for (size_t i = 0; i < descriptions.size(); i++) {
+        std::stringstream element;
+        element << descriptions[i];
+        if (i < descriptions.size() - 1) {
+            element << separator << ' ';
         }
 
-        if (line.length() + elem.length() <= MAX_LINE_LEN) {
-            line.append(elem);
-        } else {
-            if (line.length() > 1 && line[line.length() - 1] == ' ' && line[line.length() - 2] == list_separator) {
-                line[line.length() - 2] = '\0';
-                fprintf(spoiler_file, "%s\n", line.data());
-                line = spoiler_indent;
-                line.append(elem);
-            } else {
-                fprintf(spoiler_file, "%s\n", line.data());
-                line = "      ";
-                line.append(elem);
-            }
+        const auto element_str = element.str();
+        const int line_length = line.tellp();
+        constexpr auto max_line_length = 75;
+        if (line_length + element_str.length() <= max_line_length) {
+            line << element_str;
+            continue;
         }
 
-        if (!*++list) {
-            break;
+        const auto line_str = line.str();
+        if (line_str.ends_with(last_separator)) {
+            ofs << std::string_view(line_str).substr(0, line_str.length() - 2) << '\n';
+            line.str("");
+            line.clear(std::stringstream::goodbit);
+            line << spoiler_indent << element_str;
+        } else {
+            ofs << line_str << '\n';
+            line.str("");
+            line.clear(std::stringstream::goodbit);
+            line << "      " << element_str;
         }
     }
 
-    fprintf(spoiler_file, "%s\n", line.data());
+    ofs << line.str() << '\n';
 }
 
 /*!
- * @brief アーティファクト情報を出力するためにダミー生成を行う /
- * Hack -- Create a "forged" artifact
- * @param o_ptr 一時生成先を保管するオブジェクト構造体
+ * @brief アーティファクト情報を出力するためにダミー生成を行う
  * @param fixed_artifact_idx 生成するアーティファクトID
- * @return ç\94\9fæ\88\90ã\81\8cæ\88\90å\8a\9fã\81\97ã\81\9få ´å\90\88TRUEã\82\92è¿\94ã\81\99
+ * @return ç\94\9fæ\88\90ã\81\97ã\81\9fã\82¢ã\83¼ã\83\86ã\82£ã\83\95ã\82¡ã\82¯ã\83\88 (é\80£ç\95ªã\81§å\9f\8bã\81¾ã\81£ã\81¦ã\81\84ã\82\8bã\81®ã\81§ä¸\8då­\98å\9c¨ä¾\8bå¤\96ã\81¯å\90\90ã\81\8bã\81ªã\81\84)
  */
-static bool make_fake_artifact(ItemEntity *o_ptr, FixedArtifactId fixed_artifact_idx)
+static ItemEntity make_fake_artifact(FixedArtifactId fixed_artifact_idx)
 {
     const auto &artifact = ArtifactsInfo::get_instance().get_artifact(fixed_artifact_idx);
-    if (artifact.name.empty()) {
-        return false;
-    }
-
     const auto bi_id = lookup_baseitem_id(artifact.bi_key);
-    if (bi_id == 0) {
-        return false;
-    }
-
-    o_ptr->prep(bi_id);
-    o_ptr->fixed_artifact_idx = fixed_artifact_idx;
-    o_ptr->pval = artifact.pval;
-    o_ptr->ac = artifact.ac;
-    o_ptr->dd = artifact.dd;
-    o_ptr->ds = artifact.ds;
-    o_ptr->to_a = artifact.to_a;
-    o_ptr->to_h = artifact.to_h;
-    o_ptr->to_d = artifact.to_d;
-    o_ptr->weight = artifact.weight;
-    return true;
+    ItemEntity item;
+    item.prep(bi_id);
+    item.fixed_artifact_idx = fixed_artifact_idx;
+    item.pval = artifact.pval;
+    item.ac = artifact.ac;
+    item.dd = artifact.dd;
+    item.ds = artifact.ds;
+    item.to_a = artifact.to_a;
+    item.to_h = artifact.to_h;
+    item.to_d = artifact.to_d;
+    item.weight = artifact.weight;
+    return item;
 }
 
 /*!
@@ -96,52 +93,54 @@ static bool make_fake_artifact(ItemEntity *o_ptr, FixedArtifactId fixed_artifact
  * Create a spoiler file entry for an artifact
  * @param art_ptr アーティファクト情報をまとめた構造体の参照ポインタ
  */
-static void spoiler_print_art(obj_desc_list *art_ptr)
+static void spoiler_print_art(const ArtifactsDumpInfo *art_ptr, std::ofstream &ofs)
 {
-    pval_info_type *pval_ptr = &art_ptr->pval_info;
-    fprintf(spoiler_file, "%s\n", art_ptr->description);
-    if (pval_ptr->pval_desc[0]) {
-        spoiler_outlist(std::string(pval_ptr->pval_desc).append(_("の修正:", " to")).data(), pval_ptr->pval_affects, item_separator);
+    const auto *pval_ptr = &art_ptr->pval_info;
+    ofs << art_ptr->description << '\n';
+    if (!pval_ptr->pval_desc.empty()) {
+        std::stringstream ss;
+        ss << pval_ptr->pval_desc << _("の修正:", " to");
+        spoiler_outlist(ss.str(), pval_ptr->pval_affects, item_separator, ofs);
     }
 
-    spoiler_outlist(_("対:", "Slay"), art_ptr->slays, item_separator);
-    spoiler_outlist(_("武器属性:", ""), art_ptr->brands, list_separator);
-    spoiler_outlist(_("免疫:", "Immunity to"), art_ptr->immunities, item_separator);
-    spoiler_outlist(_("耐性:", "Resist"), art_ptr->resistances, item_separator);
-    spoiler_outlist(_("弱点:", "Vulnerable"), art_ptr->vulnerables, item_separator);
-    spoiler_outlist(_("維持:", "Sustain"), art_ptr->sustains, item_separator);
-    spoiler_outlist("", art_ptr->misc_magic, list_separator);
+    spoiler_outlist(_("対:", "Slay"), art_ptr->slays, item_separator, ofs);
+    spoiler_outlist(_("武器属性:", ""), art_ptr->brands, list_separator, ofs);
+    spoiler_outlist(_("免疫:", "Immunity to"), art_ptr->immunities, item_separator, ofs);
+    spoiler_outlist(_("耐性:", "Resist"), art_ptr->resistances, item_separator, ofs);
+    spoiler_outlist(_("弱点:", "Vulnerable"), art_ptr->vulnerabilities, item_separator, ofs);
+    spoiler_outlist(_("維持:", "Sustain"), art_ptr->sustenances, item_separator, ofs);
+    spoiler_outlist("", art_ptr->misc_magic, list_separator, ofs);
 
-    if (art_ptr->addition[0]) {
-        fprintf(spoiler_file, _("%s追加: %s\n", "%sAdditional %s\n"), spoiler_indent, art_ptr->addition);
+    if (!art_ptr->addition.empty()) {
+        ofs << format(_("%s追加: %s\n", "%sAdditional %s\n"), spoiler_indent.data(), art_ptr->addition.data());
     }
 
-    if (art_ptr->activation) {
-        fprintf(spoiler_file, _("%s発動: %s\n", "%sActivates for %s\n"), spoiler_indent, art_ptr->activation);
+    if (!art_ptr->activation.empty()) {
+        ofs << format(_("%s発動: %s\n", "%sActivates for %s\n"), spoiler_indent.data(), art_ptr->activation.data());
     }
 
-    fprintf(spoiler_file, "%s%s\n\n", spoiler_indent, art_ptr->misc_desc);
+    ofs << format("%s%s\n\n", spoiler_indent.data(), art_ptr->misc_desc.data());
 }
 
 /*!
- * @brief アーティファクト情報のスポイラー出力を行うメインルーチン /
- * Create a spoiler file for artifacts
- * @param fname 生成ファイル名
+ * @brief アーティファクト情報のスポイラー出力を行うメインルーチン
+ * @details エラーコードと実際のエラー処理が不一致だが、後でまとめて修正する.
  */
-SpoilerOutputResultType spoil_fixed_artifact(concptr fname)
+SpoilerOutputResultType spoil_fixed_artifact()
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
-    spoiler_file = angband_fopen(buf, FileOpenMode::WRITE);
-    if (!spoiler_file) {
+    const auto &path = path_build(ANGBAND_DIR_USER, "artifact.txt");
+    std::ofstream ofs(path);
+    if (!ofs) {
         return SpoilerOutputResultType::FILE_OPEN_FAILED;
     }
 
-    spoiler_underline(std::string("Artifact Spoilers for Hengband Version ").append(get_version()).data());
+    std::stringstream ss;
+    ss << "Artifact Spoilers for Hengband Version " << get_version();
+    spoiler_underline(ss.str(), ofs);
     for (const auto &[tval_list, name] : group_artifact_list) {
-        spoiler_blanklines(2);
-        spoiler_underline(name);
-        spoiler_blanklines(1);
+        spoiler_blanklines(2, ofs);
+        spoiler_underline(name, ofs);
+        spoiler_blanklines(1, ofs);
 
         for (auto tval : tval_list) {
             for (const auto &[a_idx, artifact] : artifacts_info) {
@@ -149,19 +148,13 @@ SpoilerOutputResultType spoil_fixed_artifact(concptr fname)
                     continue;
                 }
 
-                ItemEntity item;
-                if (!make_fake_artifact(&item, a_idx)) {
-                    continue;
-                }
-
+                const auto item = make_fake_artifact(a_idx);
                 PlayerType dummy;
-                obj_desc_list artifact_descriptions;
-                object_analyze(&dummy, &item, &artifact_descriptions);
-                spoiler_print_art(&artifact_descriptions);
+                const auto artifacts_list = object_analyze(&dummy, &item);
+                spoiler_print_art(&artifacts_list, ofs);
             }
         }
     }
 
-    return ferror(spoiler_file) || angband_fclose(spoiler_file) ? SpoilerOutputResultType::FILE_CLOSE_FAILED
-                                                                : SpoilerOutputResultType::SUCCESSFUL;
+    return ofs.good() ? SpoilerOutputResultType::SUCCESSFUL : SpoilerOutputResultType::FILE_CLOSE_FAILED;
 }
index 6dcc1ff..079ba8c 100644 (file)
@@ -1,7 +1,10 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
-#include "wizard/spoiler-util.h"
+#include <fstream>
+#include <string>
+#include <string_view>
+#include <vector>
 
-void spoiler_outlist(concptr header, concptr *list, char separator);
-SpoilerOutputResultType spoil_fixed_artifact(concptr fname);
+enum class SpoilerOutputResultType;
+void spoiler_outlist(std::string_view header, const std::vector<std::string> &descriptions, char seperator, std::ofstream &ofs);
+SpoilerOutputResultType spoil_fixed_artifact();
index ec8f0ed..2919299 100644 (file)
@@ -1,4 +1,4 @@
-#include "wizard/items-spoiler.h"
+#include "wizard/items-spoiler.h"
 #include "flavor/flavor-describer.h"
 #include "flavor/object-flavor-types.h"
 #include "io/files-util.h"
 #include "view/display-messages.h"
 #include "wizard/spoiler-util.h"
 #include <algorithm>
+#include <sstream>
 
 /*!
- * @brief ベースアイテムの各情報を文字列化する
- * @param player_ptr プレイヤーへの参照ポインタ
- * @param name 名称を返すバッファ参照ポインタ
- * @param damage_desc ダメージダイス記述を返すバッファ参照ポインタ
- * @param weight_desc 重量記述を返すバッファ参照ポインタ
- * @param level 生成階記述を返すバッファ参照ポインタ
- * @param chance 生成機会を返すバッファ参照ポインタ
- * @param value 価値を返すバッファ参照ポインタ
- * @param bi_id ベースアイテムID
+ * @brief アイテムの生成階層と価格を得る
+ *
+ * @param item アイテム
+ * @return 階層と価格のペア
  */
-static void describe_baseitem_info(PlayerType *player_ptr,
-    char *name, std::string *damage_desc, std::string *weight_desc, std::string *chance_desc, DEPTH *level_desc, PRICE *value, short bi_id)
+static std::pair<DEPTH, PRICE> get_info(const ItemEntity &item)
 {
-    ItemEntity forge;
-    auto *q_ptr = &forge;
-    q_ptr->prep(bi_id);
-    q_ptr->ident |= IDENT_KNOWN;
-    q_ptr->pval = 0;
-    q_ptr->to_a = 0;
-    q_ptr->to_h = 0;
-    q_ptr->to_d = 0;
-    *level_desc = q_ptr->get_baseitem().level;
-    *value = q_ptr->get_price();
-    if (!name || !damage_desc || !chance_desc || !weight_desc) {
-        return;
-    }
+    const auto level = item.get_baseitem().level;
+    const auto price = item.get_price();
+    return { level, price };
+}
 
-    auto item_name = describe_flavor(player_ptr, q_ptr, OD_NAME_ONLY | OD_STORE);
-    name = item_name.data();
-    switch (q_ptr->bi_key.tval()) {
+/*!
+ * @brief アイテムのダメージもしくはACの文字列表記を得る
+ *
+ * @param item アイテム
+ * @return ダメージもしくはACの文字列表記
+ */
+static std::string describe_dam_or_ac(const ItemEntity &item)
+{
+    switch (item.bi_key.tval()) {
     case ItemKindType::SHOT:
     case ItemKindType::BOLT:
     case ItemKindType::ARROW:
-        *damage_desc = format("%dd%d", q_ptr->dd, q_ptr->ds);
-        break;
+        return format("%dd%d", item.dd, item.ds);
     case ItemKindType::HAFTED:
     case ItemKindType::POLEARM:
     case ItemKindType::SWORD:
     case ItemKindType::DIGGING:
-        *damage_desc = format("%dd%d", q_ptr->dd, q_ptr->ds);
-        break;
+        return format("%dd%d", item.dd, item.ds);
     case ItemKindType::BOOTS:
     case ItemKindType::GLOVES:
     case ItemKindType::CLOAK:
@@ -66,42 +56,76 @@ static void describe_baseitem_info(PlayerType *player_ptr,
     case ItemKindType::SOFT_ARMOR:
     case ItemKindType::HARD_ARMOR:
     case ItemKindType::DRAG_ARMOR:
-        *damage_desc = format("%d", q_ptr->ac);
-        break;
+        return format("%d", item.ac);
     default:
-        damage_desc->clear();
-        break;
+        return {};
     }
+}
+
+/*!
+ * @brief アイテムの生成確率の文字列表記を得る
+ *
+ * @param item アイテム
+ * @return 生成確率の文字列表記
+ */
+static std::string describe_chance(const ItemEntity &item)
+{
+    std::stringstream ss;
 
-    chance_desc->clear();
-    const auto &baseitem = q_ptr->get_baseitem();
+    const auto &baseitem = item.get_baseitem();
     for (auto i = 0U; i < baseitem.alloc_tables.size(); i++) {
         const auto &[level, chance] = baseitem.alloc_tables[i];
         if (chance > 0) {
-            chance_desc->append(format("%s%3dF:%+4d", (i != 0 ? "/" : ""), level, 100 / chance));
+            ss << format("%s%3dF:%+4d", (i != 0 ? "/" : ""), level, 100 / chance);
         }
     }
 
-    *weight_desc = format("%3d.%d", (int)(q_ptr->weight / 10), (int)(q_ptr->weight % 10));
+    return ss.str();
 }
 
 /*!
- * @brief 各ベースアイテムの情報を一行毎に記述する /
- * Create a spoiler file for items
- * @param fname ファイル名
+ * @brief アイテムの重量の文字列表記を得る
+ *
+ * @param item アイテム
+ * @return アイテムの重量の文字列表記
  */
-SpoilerOutputResultType spoil_obj_desc(concptr fname)
+static std::string describe_weight(const ItemEntity &item)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
-    spoiler_file = angband_fopen(buf, FileOpenMode::WRITE);
-    if (!spoiler_file) {
+    return format("%3d.%d", (int)(item.weight / 10), (int)(item.weight % 10));
+}
+
+/*!
+ * @brief obj-desc.txt出力用にベースアイテムIDからItemEntityオブジェクトを生成する
+ *
+ * @param bi_id ベースアイテムID
+ * @return obj-desc.txt出力用に使用するItemEntityオブジェクト
+ */
+static ItemEntity prepare_item_for_obj_desc(short bi_id)
+{
+    ItemEntity item;
+    item.prep(bi_id);
+    item.ident |= IDENT_KNOWN;
+    item.pval = 0;
+    item.to_a = 0;
+    item.to_h = 0;
+    item.to_d = 0;
+    return item;
+}
+
+/*!
+ * @brief 各ベースアイテムの情報を一行毎に記述する
+ */
+SpoilerOutputResultType spoil_obj_desc()
+{
+    const auto &path = path_build(ANGBAND_DIR_USER, "obj-desc.txt");
+    std::ofstream ofs(path);
+    if (!ofs) {
         return SpoilerOutputResultType::FILE_OPEN_FAILED;
     }
 
-    fprintf(spoiler_file, "Spoiler File -- Basic Items (%s)\n\n\n", get_version().data());
-    fprintf(spoiler_file, "%-37s%8s%7s%5s %40s%9s\n", "Description", "Dam/AC", "Wgt", "Lev", "Chance", "Cost");
-    fprintf(spoiler_file, "%-37s%8s%7s%5s %40s%9s\n", "-------------------------------------", "------", "---", "---", "----------------", "----");
+    ofs << format("Spoiler File -- Basic Items (%s)\n\n\n", get_version().data());
+    ofs << format("%-37s%8s%7s%5s %40s%9s\n", "Description", "Dam/AC", "Wgt", "Lev", "Chance", "Cost");
+    ofs << format("%-37s%8s%7s%5s %40s%9s\n", "-------------------------------------", "------", "---", "---", "----------------", "----");
 
     for (const auto &[tval_list, name] : group_item_list) {
         std::vector<short> whats;
@@ -116,28 +140,27 @@ SpoilerOutputResultType spoil_obj_desc(concptr fname)
             continue;
         }
 
-        std::stable_sort(whats.begin(), whats.end(), [](auto k1_idx, auto k2_idx) {
-            PlayerType dummy;
-            DEPTH d1, d2;
-            PRICE p1, p2;
-            describe_baseitem_info(&dummy, nullptr, nullptr, nullptr, nullptr, &d1, &p1, k1_idx);
-            describe_baseitem_info(&dummy, nullptr, nullptr, nullptr, nullptr, &d2, &p2, k2_idx);
-            return (p1 != p2) ? p1 < p2 : d1 < d2;
+        std::stable_sort(whats.begin(), whats.end(), [](auto bi_id1, auto bi_id2) {
+            const auto item1 = prepare_item_for_obj_desc(bi_id1);
+            const auto item2 = prepare_item_for_obj_desc(bi_id2);
+            const auto [depth1, price1] = get_info(item1);
+            const auto [depth2, price2] = get_info(item2);
+            return (price1 != price2) ? price1 < price2 : depth1 < depth2;
         });
 
-        fprintf(spoiler_file, "\n\n%s\n\n", name);
+        ofs << "\n\n"
+            << name << "\n\n";
         for (const auto &bi_id : whats) {
-            DEPTH e;
-            PRICE v;
-            std::string wgt, chance, dam;
             PlayerType dummy;
-            describe_baseitem_info(&dummy, buf, &dam, &wgt, &chance, &e, &v, bi_id);
-            fprintf(spoiler_file, "  %-35s%8s%7s%5d %-40s%9ld\n", buf,
-                dam.data(), wgt.data(), static_cast<int>(e), chance.data(),
-                static_cast<long>(v));
+            const auto item = prepare_item_for_obj_desc(bi_id);
+            const auto item_name = describe_flavor(&dummy, &item, OD_NAME_ONLY | OD_STORE);
+            const auto &[depth, price] = get_info(item);
+            const auto dam_or_ac = describe_dam_or_ac(item);
+            const auto weight = describe_weight(item);
+            const auto chance = describe_chance(item);
+            ofs << format("  %-35s%8s%7s%5d %-40s%9d\n", item_name.data(), dam_or_ac.data(), weight.data(), depth, chance.data(), price);
         }
     }
 
-    return ferror(spoiler_file) || angband_fclose(spoiler_file) ? SpoilerOutputResultType::FILE_CLOSE_FAILED
-                                                                : SpoilerOutputResultType::SUCCESSFUL;
+    return ofs.good() ? SpoilerOutputResultType::SUCCESSFUL : SpoilerOutputResultType::FILE_CLOSE_FAILED;
 }
index 59e503b..e7236d7 100644 (file)
@@ -1,6 +1,4 @@
-#pragma once
+#pragma once
 
-#include "system/angband.h"
-#include "wizard/spoiler-util.h"
-
-SpoilerOutputResultType spoil_obj_desc(concptr fname);
+enum class SpoilerOutputResultType;
+SpoilerOutputResultType spoil_obj_desc();
index f3a0628..198126c 100644 (file)
@@ -1,4 +1,4 @@
-#include "wizard/monster-info-spoiler.h"
+#include "wizard/monster-info-spoiler.h"
 #include "io/files-util.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
@@ -14,6 +14,7 @@
 #include "util/string-processor.h"
 #include "view/display-lore.h"
 #include "view/display-messages.h"
+#include "wizard/spoiler-util.h"
 
 /*!
  * @brief シンボル職の記述名を返す /
@@ -73,30 +74,29 @@ static concptr attr_to_text(MonsterRaceInfo *r_ptr)
     return _("変な色の", "Icky");
 }
 
-SpoilerOutputResultType spoil_mon_desc(concptr fname, std::function<bool(const MonsterRaceInfo *)> filter_monster)
+SpoilerOutputResultType spoil_mon_desc(std::string_view filename, std::function<bool(const MonsterRaceInfo *)> filter_monster)
 {
     PlayerType dummy;
     uint16_t why = 2;
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
-    spoiler_file = angband_fopen(buf, FileOpenMode::WRITE);
-    if (!spoiler_file) {
+    const auto &path = path_build(ANGBAND_DIR_USER, filename);
+    std::ofstream ofs(path);
+    if (!ofs) {
         return SpoilerOutputResultType::FILE_OPEN_FAILED;
     }
 
-    fprintf(spoiler_file, "Monster Spoilers for %s\n", get_version().data());
-    fprintf(spoiler_file, "------------------------------------------\n\n");
-    fprintf(spoiler_file, "%-45.45s%4s %4s %4s %7s %7s  %19.19s\n", "Name", "Lev", "Rar", "Spd", "Hp", "Ac", "Visual Info");
-    fprintf(spoiler_file, "%-45.45s%4s %4s %4s %7s %7s  %4.19s\n",
+    ofs << format("Monster Spoilers for %s\n", get_version().data());
+    ofs << "------------------------------------------\n\n";
+    ofs << format("%-45.45s%4s %4s %4s %7s %7s  %19.19s\n", "Name", "Lev", "Rar", "Spd", "Hp", "Ac", "Visual Info");
+    ofs << format("%-45.45s%4s %4s %4s %7s %7s  %4.19s\n",
         "---------------------------------------------"
         "----"
         "----------",
         "---", "---", "---", "-----", "-----", "-------------------");
 
     std::vector<MonsterRaceId> who;
-    for (const auto &[r_idx, r_ref] : monraces_info) {
-        if (MonsterRace(r_ref.idx).is_valid() && !r_ref.name.empty()) {
-            who.push_back(r_ref.idx);
+    for (const auto &[monrace_id, monrace] : monraces_info) {
+        if (MonsterRace(monrace_id).is_valid()) {
+            who.push_back(monrace_id);
         }
     }
 
@@ -122,10 +122,10 @@ SpoilerOutputResultType spoil_mon_desc(concptr fname, std::function<bool(const M
         }
         nam.append(name.front());
 
-        std::string lev = format("%d", (int)r_ptr->level);
-        std::string rar = format("%d", (int)r_ptr->rarity);
-        std::string spd = format("%+d", r_ptr->speed - STANDARD_SPEED);
-        std::string ac = format("%d", r_ptr->ac);
+        const auto lev = format("%d", r_ptr->level);
+        const auto rar = format("%d", (int)r_ptr->rarity);
+        const auto spd = format("%+d", r_ptr->speed - STANDARD_SPEED);
+        const auto ac = format("%d", r_ptr->ac);
         std::string hp;
         if (any_bits(r_ptr->flags1, RF1_FORCE_MAXHP) || (r_ptr->hside == 1)) {
             hp = format("%d", r_ptr->hdice * r_ptr->hside);
@@ -133,19 +133,18 @@ SpoilerOutputResultType spoil_mon_desc(concptr fname, std::function<bool(const M
             hp = format("%dd%d", r_ptr->hdice, r_ptr->hside);
         }
 
-        std::string symbol = format("%s '%c'", attr_to_text(r_ptr), r_ptr->d_char);
-        fprintf(spoiler_file, "%-45.45s%4s %4s %4s %7s %7s  %19.19s\n",
+        const auto symbol = format("%s '%c'", attr_to_text(r_ptr), r_ptr->d_char);
+        ofs << format("%-45.45s%4s %4s %4s %7s %7s  %19.19s\n",
             nam.data(), lev.data(), rar.data(), spd.data(), hp.data(),
             ac.data(), symbol.data());
 
         for (auto i = 1U; i < name.size(); ++i) {
-            fprintf(spoiler_file, "    %s\n", name[i].data());
+            ofs << format("    %s\n", name[i].data());
         }
     }
 
-    fprintf(spoiler_file, "\n");
-    return ferror(spoiler_file) || angband_fclose(spoiler_file) ? SpoilerOutputResultType::FILE_CLOSE_FAILED
-                                                                : SpoilerOutputResultType::SUCCESSFUL;
+    ofs << '\n';
+    return ofs.good() ? SpoilerOutputResultType::SUCCESSFUL : SpoilerOutputResultType::FILE_CLOSE_FAILED;
 }
 
 /*!
@@ -157,7 +156,7 @@ SpoilerOutputResultType spoil_mon_desc(concptr fname, std::function<bool(const M
 static void roff_func(TERM_COLOR attr, std::string_view str)
 {
     (void)attr;
-    spoil_out(str.data());
+    spoil_out(str);
 }
 
 /*!
@@ -165,12 +164,11 @@ static void roff_func(TERM_COLOR attr, std::string_view str)
  * Create a spoiler file for monsters (-SHAWN-)
  * @param fname ファイル名
  */
-SpoilerOutputResultType spoil_mon_info(concptr fname)
+SpoilerOutputResultType spoil_mon_info()
 {
     PlayerType dummy;
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname);
-    spoiler_file = angband_fopen(buf, FileOpenMode::WRITE);
+    const auto &path = path_build(ANGBAND_DIR_USER, "mon-info.txt");
+    spoiler_file = angband_fopen(path, FileOpenMode::WRITE);
     if (!spoiler_file) {
         return SpoilerOutputResultType::FILE_OPEN_FAILED;
     }
@@ -179,9 +177,9 @@ SpoilerOutputResultType spoil_mon_info(concptr fname)
     spoil_out("------------------------------------------\n\n");
 
     std::vector<MonsterRaceId> who;
-    for (const auto &[r_idx, r_ref] : monraces_info) {
-        if (MonsterRace(r_ref.idx).is_valid() && !r_ref.name.empty()) {
-            who.push_back(r_ref.idx);
+    for (const auto &[monrace_id, monrace] : monraces_info) {
+        if (MonsterRace(monrace_id).is_valid()) {
+            who.push_back(monrace_id);
         }
     }
 
index a9670c4..e5030e2 100644 (file)
@@ -1,11 +1,9 @@
-#pragma once
-
-#include "system/angband.h"
-#include "wizard/spoiler-util.h"
+#pragma once
 
 #include <functional>
+#include <string_view>
 
+enum class SpoilerOutputResultType;
 class MonsterRaceInfo;
-SpoilerOutputResultType spoil_mon_desc_all(concptr fname);
-SpoilerOutputResultType spoil_mon_desc(concptr fname, std::function<bool(const MonsterRaceInfo *)> filter_monster = nullptr);
-SpoilerOutputResultType spoil_mon_info(concptr fname);
+SpoilerOutputResultType spoil_mon_desc(std::string_view filename, std::function<bool(const MonsterRaceInfo *)> filter_monster = nullptr);
+SpoilerOutputResultType spoil_mon_info();
index af7db90..7fcbbea 100644 (file)
@@ -1,4 +1,4 @@
-#include "wizard/spoiler-table.h"
+#include "wizard/spoiler-table.h"
 
 /* The basic items categorized by type */
 const std::vector<grouper> group_item_list = {
@@ -67,15 +67,15 @@ const std::vector<grouper> group_artifact_list = {
     { { ItemKindType::RING }, _("指輪", "Rings") },
 };
 
-flag_desc stat_flags_desc[MAX_STAT_FLAGS_DESCRIPTION] = { { TR_STR, _("腕力", "STR") }, { TR_INT, _("知能", "INT") }, { TR_WIS, _("賢さ", "WIS") },
+const std::vector<flag_desc> stat_flags_desc = { { TR_STR, _("腕力", "STR") }, { TR_INT, _("知能", "INT") }, { TR_WIS, _("賢さ", "WIS") },
     { TR_DEX, _("器用さ", "DEX") },
     { TR_CON, _("耐久力", "CON") }, { TR_CHR, _("魅力", "CHR") } };
 
-flag_desc pval_flags1_desc[MAX_PVAL_FLAGS_DESCRIPTION] = { { TR_MAGIC_MASTERY, _("魔法道具使用能力", "Magic Mastery") }, { TR_STEALTH, _("隠密", "Stealth") },
+const std::vector<flag_desc> pval_flags1_desc = { { TR_MAGIC_MASTERY, _("魔法道具使用能力", "Magic Mastery") }, { TR_STEALTH, _("隠密", "Stealth") },
     { TR_SEARCH, _("探索", "Searching") }, { TR_INFRA, _("赤外線視力", "Infravision") }, { TR_TUNNEL, _("採掘", "Tunneling") },
     { TR_BLOWS, _("攻撃回数", "Attacks") }, { TR_SPEED, _("スピード", "Speed") } };
 
-flag_desc slay_flags_desc[MAX_SLAY_FLAGS_DESCRIPTION] = {
+const std::vector<flag_desc> slay_flags_desc = {
     { TR_SLAY_ANIMAL, _("動物", "Animal") },
     { TR_KILL_ANIMAL, _("*動物*", "XAnimal") },
     { TR_SLAY_EVIL, _("邪悪", "Evil") },
@@ -99,7 +99,7 @@ flag_desc slay_flags_desc[MAX_SLAY_FLAGS_DESCRIPTION] = {
 };
 
 /* Elemental brands for weapons */
-flag_desc brand_flags_desc[MAX_BRAND_FLAGS_DESCRIPTION] = {
+const std::vector<flag_desc> brand_flags_desc = {
     { TR_BRAND_ACID, _("溶解", "Acid Brand") },
     { TR_BRAND_ELEC, _("電撃", "Lightning Brand") },
     { TR_BRAND_FIRE, _("焼棄", "Flame Tongue") },
@@ -114,7 +114,7 @@ flag_desc brand_flags_desc[MAX_BRAND_FLAGS_DESCRIPTION] = {
     { TR_IMPACT, _("強撃", "Smash hit") },
 };
 
-const flag_desc resist_flags_desc[MAX_RESISTANCE_FLAGS_DESCRIPTION] = {
+const std::vector<flag_desc> resist_flags_desc = {
     { TR_RES_ACID, _("酸", "Acid") },
     { TR_RES_ELEC, _("電撃", "Lightning") },
     { TR_RES_FIRE, _("火炎", "Fire") },
@@ -136,7 +136,7 @@ const flag_desc resist_flags_desc[MAX_RESISTANCE_FLAGS_DESCRIPTION] = {
     { TR_RES_CURSE, _("呪力", "Curse") },
 };
 
-const flag_desc vulnerable_flags_desc[MAX_VULNERABLE_FLAGS_DESCRIPTION] = {
+const std::vector<flag_desc> vulnerable_flags_desc = {
     { TR_VUL_ACID, _("酸", "Acid") },
     { TR_VUL_ELEC, _("電撃", "Lightning") },
     { TR_VUL_FIRE, _("火炎", "Fire") },
@@ -146,7 +146,7 @@ const flag_desc vulnerable_flags_desc[MAX_VULNERABLE_FLAGS_DESCRIPTION] = {
 };
 
 /* Elemental immunities (along with poison) */
-const flag_desc immune_flags_desc[MAX_IMMUNITY_FLAGS_DESCRIPTION] = {
+const std::vector<flag_desc> immune_flags_desc = {
     { TR_IM_ACID, _("酸", "Acid") },
     { TR_IM_ELEC, _("電撃", "Lightning") },
     { TR_IM_FIRE, _("火炎", "Fire") },
@@ -154,7 +154,7 @@ const flag_desc immune_flags_desc[MAX_IMMUNITY_FLAGS_DESCRIPTION] = {
 };
 
 /* Sustain stats -  these are given their "own" line in the spoiler file, mainly for simplicity */
-const flag_desc sustain_flags_desc[MAX_SUSTAINER_FLAGS_DESCRIPTION] = {
+const std::vector<flag_desc> sustain_flags_desc = {
     { TR_SUST_STR, _("腕力", "STR") },
     { TR_SUST_INT, _("知能", "INT") },
     { TR_SUST_WIS, _("賢さ", "WIS") },
@@ -164,7 +164,7 @@ const flag_desc sustain_flags_desc[MAX_SUSTAINER_FLAGS_DESCRIPTION] = {
 };
 
 /* Miscellaneous magic given by an object's "flags2" field */
-const flag_desc misc_flags2_desc[] = {
+const std::vector<flag_desc> misc_flags2_desc = {
     { TR_THROW, _("投擲", "Throwing") },
     { TR_REFLECT, _("反射", "Reflection") },
     { TR_FREE_ACT, _("麻痺知らず", "Free Action") },
@@ -172,7 +172,7 @@ const flag_desc misc_flags2_desc[] = {
 };
 
 /* Miscellaneous magic given by an object's "flags3" field */
-const flag_desc misc_flags3_desc[MAX_MISC3_FLAGS_DESCRIPTION] = {
+const std::vector<flag_desc> misc_flags3_desc = {
     { TR_SH_FIRE, _("火炎オーラ", "Fiery Aura") },
     { TR_SH_ELEC, _("電撃オーラ", "Electric Aura") },
     { TR_SH_COLD, _("冷気オーラ", "Coldly Aura") },
index 9c25893..5b4387a 100644 (file)
@@ -1,22 +1,10 @@
-#pragma once
+#pragma once
 
 #include "object-enchant/tr-types.h"
 #include "object/tval-types.h"
 #include "system/angband.h"
-
 #include <vector>
 
-#define MAX_STAT_FLAGS_DESCRIPTION 6
-#define MAX_PVAL_FLAGS_DESCRIPTION 7
-#define MAX_SLAY_FLAGS_DESCRIPTION 20
-#define MAX_BRAND_FLAGS_DESCRIPTION 12
-#define MAX_RESISTANCE_FLAGS_DESCRIPTION 19
-#define MAX_VULNERABLE_FLAGS_DESCRIPTION 6
-#define MAX_IMMUNITY_FLAGS_DESCRIPTION 4
-#define MAX_SUSTAINER_FLAGS_DESCRIPTION 6
-#define MAX_MISC2_FLAGS_DESCRIPTION 4
-#define MAX_MISC3_FLAGS_DESCRIPTION 39
-
 /* A tval grouper */
 struct grouper {
     std::vector<ItemKindType> tval_set;
@@ -36,13 +24,13 @@ struct flag_desc {
 
 extern const std::vector<grouper> group_item_list;
 extern const std::vector<grouper> group_artifact_list;
-extern flag_desc stat_flags_desc[MAX_STAT_FLAGS_DESCRIPTION];
-extern flag_desc pval_flags1_desc[MAX_PVAL_FLAGS_DESCRIPTION];
-extern flag_desc slay_flags_desc[MAX_SLAY_FLAGS_DESCRIPTION];
-extern flag_desc brand_flags_desc[MAX_BRAND_FLAGS_DESCRIPTION];
-extern const flag_desc resist_flags_desc[MAX_RESISTANCE_FLAGS_DESCRIPTION];
-extern const flag_desc vulnerable_flags_desc[MAX_VULNERABLE_FLAGS_DESCRIPTION];
-extern const flag_desc immune_flags_desc[MAX_IMMUNITY_FLAGS_DESCRIPTION];
-extern const flag_desc sustain_flags_desc[MAX_SUSTAINER_FLAGS_DESCRIPTION];
-extern const flag_desc misc_flags2_desc[MAX_MISC2_FLAGS_DESCRIPTION];
-extern const flag_desc misc_flags3_desc[MAX_MISC3_FLAGS_DESCRIPTION];
+extern const std::vector<flag_desc> stat_flags_desc;
+extern const std::vector<flag_desc> pval_flags1_desc;
+extern const std::vector<flag_desc> slay_flags_desc;
+extern const std::vector<flag_desc> brand_flags_desc;
+extern const std::vector<flag_desc> resist_flags_desc;
+extern const std::vector<flag_desc> vulnerable_flags_desc;
+extern const std::vector<flag_desc> immune_flags_desc;
+extern const std::vector<flag_desc> sustain_flags_desc;
+extern const std::vector<flag_desc> misc_flags2_desc;
+extern const std::vector<flag_desc> misc_flags3_desc;
index e04e6e3..19dedc3 100644 (file)
@@ -1,23 +1,43 @@
-#include "wizard/spoiler-util.h"
+#include "wizard/spoiler-util.h"
+#include "system/item-entity.h"
+#include <fstream>
 
 const char item_separator = ',';
 const char list_separator = _(',', ';');
 const int max_evolution_depth = 64;
-concptr spoiler_indent = "    ";
+const std::string spoiler_indent = "    ";
 
 /* The spoiler file being created */
 FILE *spoiler_file = nullptr;
 
 /*!
+ * @brief 特性フラグ定義から表記すべき特性を抽出する
+ * @param art_flags 出力するアーティファクトの特性一覧
+ * @param definitions 表記対象の特性一覧
+ * @return 表記すべき特性一覧
+ */
+std::vector<std::string> extract_spoiler_flags(const TrFlags &art_flags, const std::vector<flag_desc> &definitions)
+{
+    std::vector<std::string> descriptions{};
+    for (const auto &definition : definitions) {
+        if (art_flags.has(definition.flag)) {
+            descriptions.push_back(definition.desc);
+        }
+    }
+
+    return descriptions;
+}
+
+/*!
  * @brief ファイルポインタ先に同じ文字を複数出力する /
  * Write out `n' of the character `c' to the spoiler file
  * @param n 出力する数
  * @param c 出力するキャラクタ
  */
-static void spoiler_out_n_chars(int n, char c)
+static void spoiler_out_n_chars(int n, char c, std::ofstream &ofs)
 {
-    while (--n >= 0) {
-        fputc(c, spoiler_file);
+    for (auto i = 0; i < n; i++) {
+        ofs << c;
     }
 }
 
@@ -26,9 +46,9 @@ static void spoiler_out_n_chars(int n, char c)
  * Write out `n' blank lines to the spoiler file
  * @param n 改行を出力する数
  */
-void spoiler_blanklines(int n)
+void spoiler_blanklines(int n, std::ofstream &ofs)
 {
-    spoiler_out_n_chars(n, '\n');
+    spoiler_out_n_chars(n, '\n', ofs);
 }
 
 /*!
@@ -36,11 +56,11 @@ void spoiler_blanklines(int n)
  * Write a line to the spoiler file and then "underline" it with hypens
  * @param str 出力したい文字列
  */
-void spoiler_underline(concptr str)
+void spoiler_underline(std::string_view str, std::ofstream &ofs)
 {
-    fprintf(spoiler_file, "%s\n", str);
-    spoiler_out_n_chars(strlen(str), '-');
-    fprintf(spoiler_file, "\n");
+    ofs << str.data() << '\n';
+    spoiler_out_n_chars(str.length(), '-', ofs);
+    ofs << '\n';
 }
 
 /*!
@@ -222,3 +242,22 @@ void spoil_out(std::string_view sv, bool flush_buffer)
         *roff_p++ = ch;
     }
 }
+
+void ParameterValueInfo::analyze(const ItemEntity &item)
+{
+    if (item.pval == 0) {
+        return;
+    }
+
+    const auto flags = item.get_flags();
+    this->pval_desc = format("%+d", item.pval);
+    if (flags.has_all_of(EnumRange(TR_STR, TR_CHR))) {
+        this->pval_affects.push_back(_("全能力", "All stats"));
+    } else if (flags.has_any_of(EnumRange(TR_STR, TR_CHR))) {
+        const auto descriptions_stat = extract_spoiler_flags(flags, stat_flags_desc);
+        this->pval_affects.insert(this->pval_affects.end(), descriptions_stat.begin(), descriptions_stat.end());
+    }
+
+    const auto descriptions_pval1 = extract_spoiler_flags(flags, pval_flags1_desc);
+    this->pval_affects.insert(this->pval_affects.end(), descriptions_pval1.begin(), descriptions_pval1.end());
+}
index 5ee021c..54b3117 100644 (file)
@@ -1,14 +1,12 @@
-#pragma once
+#pragma once
 
+#include "object-enchant/tr-flags.h"
 #include "system/angband.h"
 #include "wizard/spoiler-table.h"
+#include <fstream>
+#include <string>
 #include <string_view>
-
-/* MAX_LINE_LEN specifies when a line should wrap. */
-#define MAX_LINE_LEN 75
-
-/* Given an array, determine how many elements are in the array */
-#define N_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
+#include <vector>
 
 enum class SpoilerOutputResultType {
     CANCELED,
@@ -17,41 +15,45 @@ enum class SpoilerOutputResultType {
     FILE_CLOSE_FAILED,
 };
 
-/* A special type used just for deailing with pvals */
-struct pval_info_type {
-    char pval_desc[12]; /* This will contain a string such as "+2", "-10", etc. */
+class ItemEntity;
+class ParameterValueInfo {
+public:
+    ParameterValueInfo() = default;
+
+    std::string pval_desc = ""; /* This will contain a string such as "+2", "-10", etc. */
 
     /* A list of various player traits affected by an object's pval such as stats, speed, stealth, etc. */
-    concptr pval_affects[N_ELEMENTS(stat_flags_desc) - 1 + N_ELEMENTS(pval_flags1_desc) + 1];
+    std::vector<std::string> pval_affects{};
+
+    void analyze(const ItemEntity &item);
 };
 
-struct obj_desc_list {
-    char description[MAX_NLEN]{}; /* "The Longsword Dragonsmiter (6d4) (+20, +25)" */
-    pval_info_type pval_info; /* Description of what is affected by an object's pval */
-    concptr slays[N_ELEMENTS(slay_flags_desc) + 1]; /* A list of an object's slaying preferences */
-    concptr brands[N_ELEMENTS(brand_flags_desc) + 1]; /* A list if an object's elemental brands */
-    concptr immunities[N_ELEMENTS(immune_flags_desc) + 1]; /* A list of immunities granted by an object */
-    concptr resistances[N_ELEMENTS(resist_flags_desc) + 1]; /* A list of resistances granted by an object */
-    concptr vulnerables[N_ELEMENTS(vulnerable_flags_desc) + 1]; /* A list of resistances granted by an object */
-    concptr sustains[N_ELEMENTS(sustain_flags_desc) - 1 + 1]; /* A list of stats sustained by an object */
-
-    /* A list of various magical qualities an object may have */
-    concptr misc_magic[N_ELEMENTS(misc_flags2_desc) + N_ELEMENTS(misc_flags3_desc) + 1 /* Permanent Light */
-                       + 1 /* TY curse */
-                       + 1 /* type of curse */
-                       + 1]; /* sentinel nullptr */
-
-    char addition[80]; /* Additional ability or resistance */
-    concptr activation; /* A string describing an artifact's activation */
-    char misc_desc[80]; /* "Level 20, Rarity 30, 3.0 lbs, 20000 Gold" */
+class ArtifactsDumpInfo {
+public:
+    ArtifactsDumpInfo() = default;
+    std::string description = ""; /* "The Longsword Dragonsmiter (6d4) (+20, +25)" */
+    ParameterValueInfo pval_info{}; /* Description of what is affected by an object's pval */
+    std::vector<std::string> slays{}; /* A list of an object's slaying preferences */
+    std::vector<std::string> brands{}; /* A list if an object's elemental brands */
+    std::vector<std::string> immunities{}; /* A list of immunities granted by an object */
+    std::vector<std::string> resistances{}; /* A list of resistances granted by an object */
+    std::vector<std::string> vulnerabilities{}; /* A list of resistances granted by an object */
+    std::vector<std::string> sustenances{}; /* A list of stats sustained by an object */
+    std::vector<std::string> misc_magic{}; // その他の特性 (呪い、光源範囲等)
+
+    std::string addition = ""; /* Additional ability or resistance */
+    std::string activation = ""; /* A string describing an artifact's activation */
+    std::string misc_desc = ""; /* "Level 20, Rarity 30, 3.0 lbs, 20000 Gold" */
 };
 
 extern const char item_separator;
 extern const char list_separator;
 extern const int max_evolution_depth;
-extern concptr spoiler_indent;
+extern const std::string spoiler_indent;
 extern FILE *spoiler_file;
 
-void spoiler_blanklines(int n);
-void spoiler_underline(concptr str);
+struct flag_desc;
+std::vector<std::string> extract_spoiler_flags(const TrFlags &art_flags, const std::vector<flag_desc> &definitions);
+void spoiler_blanklines(int n, std::ofstream &ofs);
+void spoiler_underline(std::string_view str, std::ofstream &ofs);
 void spoil_out(std::string_view sv, bool flush_buffer = false);
index 4b8ab16..d025f5c 100644 (file)
@@ -1,4 +1,4 @@
-#include "wizard/tval-descriptions-table.h"
+#include "wizard/tval-descriptions-table.h"
 #include "object/tval-types.h"
 
 /*!
@@ -42,7 +42,7 @@ const std::vector<tval_desc> tvals = {
     { ItemKindType::MUSIC_BOOK, _("歌集", "Music Spellbook") },
     { ItemKindType::HISSATSU_BOOK, _("武芸の書", "Book of Kendo") },
     { ItemKindType::HEX_BOOK, _("呪術の魔法書", "Hex Spellbook") },
-    { ItemKindType::PARCHMENT, _("冒険者のための中つ国ガイド", "Parchment") },
+    { ItemKindType::PARCHMENT, _("羊皮紙", "Parchment") },
     { ItemKindType::WHISTLE, _("笛", "Whistle") },
     { ItemKindType::SPIKE, _("くさび", "Spikes") },
     { ItemKindType::DIGGING, _("シャベル/つるはし", "Digger") },
index 0a2a2ce..32e3828 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 #include <vector>
index 5c87b10..47feb6a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ゲーム属性を変更するデバッグコマンド
  * @date 2021/03/07
  */
@@ -12,6 +12,7 @@
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
 #include "monster-race/race-flags7.h"
+#include "monster-race/race-indice-types.h"
 #include "player-info/self-info.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-race-info.h"
@@ -57,7 +58,7 @@ void display_wizard_game_modifier_menu()
     for (const auto &[symbol, desc] : wizard_game_modifier_menu_table) {
         std::stringstream ss;
         ss << symbol << ") " << desc;
-        put_str(ss.str().data(), r++, c);
+        put_str(ss.str(), r++, c);
     }
 }
 
@@ -70,8 +71,8 @@ void wizard_game_modifier(PlayerType *player_ptr)
     screen_save();
     display_wizard_game_modifier_menu();
 
-    char cmd;
-    get_com("Player Command: ", &cmd, false);
+    const auto command = input_command("Player Command: ");
+    const auto cmd = command.value_or(ESCAPE);
     screen_load();
 
     switch (cmd) {
@@ -104,13 +105,14 @@ void wizard_game_modifier(PlayerType *player_ptr)
  */
 void wiz_enter_quest(PlayerType *player_ptr)
 {
-    auto quest_num = 0;
     auto &quest_list = QuestList::get_instance();
     const auto quest_max = enum2i(quest_list.rbegin()->first);
-    if (!get_value("QuestID", 0, quest_max - 1, &quest_num)) {
+    const auto quest_num = input_numerics("QuestID", 0, quest_max - 1, QuestId::NONE);
+    if (!quest_num) {
         return;
     }
-    auto q_idx = i2enum<QuestId>(quest_num);
+
+    auto q_idx = *quest_num;
     init_flags = i2enum<init_flags_type>(INIT_SHOW_TEXT | INIT_ASSIGN);
     player_ptr->current_floor_ptr->quest_number = q_idx;
     parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
@@ -126,7 +128,7 @@ void wiz_enter_quest(PlayerType *player_ptr)
  */
 void wiz_complete_quest(PlayerType *player_ptr)
 {
-    if (!inside_quest(player_ptr->current_floor_ptr->quest_number)) {
+    if (!player_ptr->current_floor_ptr->is_in_quest()) {
         msg_print("No current quest");
         msg_print(nullptr);
         return;
@@ -141,34 +143,29 @@ void wiz_complete_quest(PlayerType *player_ptr)
 void wiz_restore_monster_max_num(MonsterRaceId r_idx)
 {
     if (!MonsterRace(r_idx).is_valid()) {
-        int val = 1;
-        if (!get_value("MonsterID", 1, monraces_info.size() - 1, &val)) {
+        const auto restore_monrace_id = input_numerics("MonsterID", 1, monraces_info.size() - 1, MonsterRaceId::FILTHY_URCHIN);
+        if (!restore_monrace_id) {
             return;
         }
-        r_idx = static_cast<MonsterRaceId>(val);
-    }
 
-    auto *r_ptr = &monraces_info[r_idx];
-    if (r_ptr->name.empty()) {
-        msg_print("そのモンスターは存在しません。");
-        msg_print(nullptr);
-        return;
+        r_idx = *restore_monrace_id;
     }
 
-    auto n = 0;
+    auto *r_ptr = &monraces_info[r_idx];
+    std::optional<int> max_num;
     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
-        n = 1;
+        max_num = MAX_UNIQUE_NUM;
     } else if (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) {
-        n = MAX_NAZGUL_NUM;
+        max_num = MAX_NAZGUL_NUM;
     }
 
-    if (n == 0) {
-        msg_print("出現数に制限がないモンスターです。");
+    if (!max_num) {
+        msg_print(_("出現数に制限がないモンスターです。", "This monster can appear any time."));
         msg_print(nullptr);
         return;
     }
 
-    r_ptr->max_num = n;
+    r_ptr->max_num = *max_num;
     r_ptr->r_pkills = 0;
     r_ptr->r_akills = 0;
 
index 4fa26f0..5d15e26 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void wizard_game_modifier(PlayerType *player_ptr);
index 1df147e..04391ca 100644 (file)
@@ -1,10 +1,9 @@
-#include "wizard/wizard-item-modifier.h"
+#include "wizard/wizard-item-modifier.h"
 #include "artifact/fixed-art-generator.h"
 #include "artifact/fixed-art-types.h"
 #include "artifact/random-art-effects.h"
 #include "artifact/random-art-generator.h"
 #include "core/asking-player.h"
-#include "core/player-update-types.h"
 #include "core/show-file.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
@@ -21,7 +20,6 @@
 #include "object-enchant/special-object-flags.h"
 #include "object-enchant/tr-types.h"
 #include "object/item-use-flags.h"
-#include "object/object-flags.h"
 #include "object/object-info.h"
 #include "object/object-kind-hook.h"
 #include "object/object-mark-types.h"
@@ -34,6 +32,7 @@
 #include "system/floor-type-definition.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/system-variables.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
 #include "util/int-char-converter.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
+#include "wizard/wizard-messages.h"
 #include "wizard/wizard-special-process.h"
 #include "world/world.h"
 #include <algorithm>
 #include <limits>
 #include <sstream>
+#include <string>
 #include <tuple>
 #include <vector>
 
@@ -59,15 +60,19 @@ namespace {
 constexpr std::array wizard_sub_menu_table = {
     std::make_tuple('a', _("アーティファクト出現フラグリセット", "Restore aware flag of fixed artifact")),
     std::make_tuple('A', _("アーティファクトを出現済みにする", "Make a fixed artifact awared")),
-    std::make_tuple('e', _("高級品獲得ドロップ", "Drop excellent object")),
+    std::make_tuple('B', _("フロア相当の呪物ドロップ", "Drop cursed item")),
+    std::make_tuple('c', _("フロア相当の一般品獲得ドロップ (★不許可)", "Drop normal item (excluding fixed artifacts)")),
+    std::make_tuple('C', _("フロア相当の一般品獲得ドロップ (★許可)", "Drop normal item (including fixed artifacts)")),
+    std::make_tuple('d', _("フロア相当の上質品獲得ドロップ", "Drop good item")),
+    std::make_tuple('D', _("フロア相当の高級品獲得ドロップ", "Drop excellent item")),
+    std::make_tuple('e', _("フロア相当のエゴ品獲得ドロップ", "Drop excellent item")),
+    std::make_tuple('E', _("フロア相当の特別品獲得ドロップ", "Drop special item")),
     std::make_tuple('f', _("*鑑定*", "*Idenfity*")),
     std::make_tuple('i', _("鑑定", "Idenfity")),
-    std::make_tuple('I', _("インベントリ全*鑑定*", "Idenfity all objects fully in inventory")),
-    std::make_tuple('l', _("指定アイテム番号まで一括鑑定", "Make objects awared to target object id")),
-    std::make_tuple('g', _("上質なアイテムドロップ", "Drop good object")),
-    std::make_tuple('s', _("特別品獲得ドロップ", "Drop special object")),
-    std::make_tuple('w', _("願い", "Wishing")),
+    std::make_tuple('I', _("インベントリ全*鑑定*", "Idenfity all items fully in inventory")),
+    std::make_tuple('l', _("指定アイテム番号まで一括鑑定", "Make items awared to target item id")),
     std::make_tuple('U', _("発動を変更する", "Modify item activation")),
+    std::make_tuple('w', _("願い", "Wishing")),
 };
 
 /*!
@@ -84,26 +89,58 @@ void display_wizard_sub_menu()
     for (const auto &[symbol, desc] : wizard_sub_menu_table) {
         std::stringstream ss;
         ss << symbol << ") " << desc;
-        put_str(ss.str().data(), r++, c);
+        put_str(ss.str(), r++, c);
     }
 }
 }
 
-/*!
- * @brief キャスト先の型の最小値、最大値でclampする。
- */
-template <typename T>
-T clamp_cast(int val)
-{
-    return static_cast<T>(std::clamp(val,
-        static_cast<int>(std::numeric_limits<T>::min()),
-        static_cast<int>(std::numeric_limits<T>::max())));
-}
-
 void wiz_restore_aware_flag_of_fixed_arfifact(FixedArtifactId reset_artifact_idx, bool aware = false);
 void wiz_modify_item_activation(PlayerType *player_ptr);
 void wiz_identify_full_inventory(PlayerType *player_ptr);
 
+static void wiz_item_drop(PlayerType *player_ptr, const int num_items, const EnumClassFlagGroup<ItemMagicAppliance> &appliance)
+{
+    uint mode = AM_NONE;
+    const auto is_cursed = appliance.has(ItemMagicAppliance::CURSED);
+    if (is_cursed) {
+        mode |= AM_CURSED;
+    }
+
+    if (appliance.has(ItemMagicAppliance::GOOD)) {
+        mode |= AM_GOOD;
+    }
+
+    if (appliance.has(ItemMagicAppliance::GREAT)) {
+        mode |= AM_GREAT;
+    }
+
+    if (appliance.has(ItemMagicAppliance::SPECIAL)) {
+        mode |= AM_SPECIAL;
+    }
+
+    for (auto i = 0; i < num_items; i++) {
+        ItemEntity item;
+        if (!make_object(player_ptr, &item, mode)) {
+            continue;
+        }
+
+        if (is_cursed && !item.is_cursed()) {
+            i--;
+            continue;
+        }
+
+        if (appliance.has(ItemMagicAppliance::EGO) && !item.is_ego()) {
+            i--;
+            continue;
+        }
+
+        if (!drop_near(player_ptr, &item, -1, player_ptr->y, player_ptr->x)) {
+            msg_print_wizard(player_ptr, 0, "No item dropping space!");
+            return;
+        }
+    }
+}
+
 /*!
  * @brief ゲーム設定コマンドの入力を受け付ける
  * @param player_ptr プレイヤーの情報へのポインタ
@@ -113,8 +150,8 @@ void wizard_item_modifier(PlayerType *player_ptr)
     screen_save();
     display_wizard_sub_menu();
 
-    char cmd;
-    get_com("Player Command: ", &cmd, false);
+    const auto command = input_command("Player Command: ");
+    const auto cmd = command.value_or(ESCAPE);
     screen_load();
 
     switch (cmd) {
@@ -129,23 +166,37 @@ void wizard_item_modifier(PlayerType *player_ptr)
     case 'A':
         wiz_restore_aware_flag_of_fixed_arfifact(i2enum<FixedArtifactId>(command_arg), true);
         break;
+    case 'B':
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_item_drop(player_ptr, command_arg, { ItemMagicAppliance::CURSED });
+        break;
+    case 'c':
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_item_drop(player_ptr, command_arg, { ItemMagicAppliance::NO_FIXED_ART });
+        break;
+    case 'C':
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_item_drop(player_ptr, command_arg, {});
+        break;
+    case 'd':
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_item_drop(player_ptr, command_arg, { ItemMagicAppliance::GOOD });
+        break;
+    case 'D':
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_item_drop(player_ptr, command_arg, { ItemMagicAppliance::GOOD, ItemMagicAppliance::GREAT });
+        break;
     case 'e':
-        if (command_arg <= 0) {
-            command_arg = 1;
-        }
-
-        acquirement(player_ptr, player_ptr->y, player_ptr->x, command_arg, true, false, true);
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_item_drop(player_ptr, command_arg, { ItemMagicAppliance::GOOD, ItemMagicAppliance::GREAT, ItemMagicAppliance::EGO });
+        break;
+    case 'E':
+        command_arg = std::clamp<short>(command_arg, 1, 999);
+        wiz_item_drop(player_ptr, command_arg, { ItemMagicAppliance::GOOD, ItemMagicAppliance::GREAT, ItemMagicAppliance::SPECIAL });
         break;
     case 'f':
         identify_fully(player_ptr, false);
         break;
-    case 'g':
-        if (command_arg <= 0) {
-            command_arg = 1;
-        }
-
-        acquirement(player_ptr, player_ptr->y, player_ptr->x, command_arg, false, false, true);
-        break;
     case 'i':
         (void)ident_spell(player_ptr, false);
         break;
@@ -155,13 +206,6 @@ void wizard_item_modifier(PlayerType *player_ptr)
     case 'l':
         wiz_learn_items_all(player_ptr);
         break;
-    case 's':
-        if (command_arg <= 0) {
-            command_arg = 1;
-        }
-
-        acquirement(player_ptr, player_ptr->y, player_ptr->x, command_arg, true, true, true);
-        break;
     case 'U':
         wiz_modify_item_activation(player_ptr);
         break;
@@ -173,21 +217,26 @@ void wizard_item_modifier(PlayerType *player_ptr)
 
 /*!
  * @brief 固定アーティファクトの出現フラグをリセットする
- * @param a_idx 指定したアーティファクトID
- * @details 外からはenum class を受け取るが、この関数内では数値の直指定処理なので数値型にキャストする.
+ * @param reset_artifact_idx 指定したアーティファクトID
  */
 void wiz_restore_aware_flag_of_fixed_arfifact(FixedArtifactId reset_artifact_idx, bool aware)
 {
-    auto max_a_idx = enum2i(artifacts_info.rbegin()->first);
-    int int_a_idx = enum2i(reset_artifact_idx);
-    if (int_a_idx <= 0) {
-        if (!get_value("Artifact ID", 1, max_a_idx, &int_a_idx)) {
-            return;
-        }
+    const auto max_a_idx = enum2i(artifacts_info.rbegin()->first);
+    const auto message = aware ? "Modified." : "Restored.";
+    auto &artifacts = ArtifactsInfo::get_instance();
+    if (reset_artifact_idx != FixedArtifactId::NONE) {
+        artifacts.get_artifact(reset_artifact_idx).is_generated = aware;
+        msg_print(message);
+        return;
     }
 
-    ArtifactsInfo::get_instance().get_artifact(i2enum<FixedArtifactId>(int_a_idx)).is_generated = aware;
-    msg_print(aware ? "Modified." : "Restored.");
+    const auto input_artifact_id = input_numerics("Artifact ID", 1, max_a_idx, FixedArtifactId::GALADRIEL_PHIAL);
+    if (!input_artifact_id) {
+        return;
+    }
+
+    artifacts.get_artifact(*input_artifact_id).is_generated = aware;
+    msg_print(message);
 }
 
 /*!
@@ -196,20 +245,22 @@ void wiz_restore_aware_flag_of_fixed_arfifact(FixedArtifactId reset_artifact_idx
  */
 void wiz_modify_item_activation(PlayerType *player_ptr)
 {
-    constexpr auto q = _("どのアイテムの発動を変更しますか? ", "Which object? ");
+    constexpr auto q = _("どのアイテムの発動を変更しますか? ", "Which item? ");
     constexpr auto s = _("発動を変更するアイテムがない。", "Nothing to do with.");
-    short item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT);
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT);
     if (!o_ptr) {
         return;
     }
 
-    int val;
-    if (!get_value("Activation ID", enum2i(RandomArtActType::NONE), enum2i(RandomArtActType::MAX) - 1, &val)) {
+    constexpr auto min = enum2i(RandomArtActType::NONE);
+    constexpr auto max = enum2i(RandomArtActType::MAX) - 1;
+    const auto act_id = input_numerics<RandomArtActType>("Activation ID", min, max);
+    if (!act_id) {
         return;
     }
 
-    auto act_idx = i2enum<RandomArtActType>(val);
+    auto act_idx = *act_id;
     o_ptr->art_flags.set(TR_ACTIVATE);
     o_ptr->activation_id = act_idx;
 }
@@ -232,11 +283,17 @@ void wiz_identify_full_inventory(PlayerType *player_ptr)
         o_ptr->marked.set(OmType::TOUCHED);
     }
 
-    /* Refrect item informaiton onto subwindows without updating inventory */
-    reset_bits(player_ptr->update, PU_COMBINATION | PU_REORDER);
-    handle_stuff(player_ptr);
-    set_bits(player_ptr->update, PU_COMBINATION | PU_REORDER);
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
@@ -323,7 +380,6 @@ static void prt_binary(BIT_FLAGS flags, const int row, int col)
  */
 static void wiz_display_item(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
-    auto flags = object_flags(o_ptr);
     auto get_seq_32bits = [](const TrFlags &flags, uint start) {
         BIT_FLAGS result = 0U;
         for (auto i = 0U; i < 32 && start + i < flags.size(); i++) {
@@ -345,7 +401,7 @@ static void wiz_display_item(PlayerType *player_ptr, ItemEntity *o_ptr)
     auto line = 4;
     const auto &bi_key = o_ptr->bi_key;
     const auto item_level = o_ptr->get_baseitem().level;
-    prt(format("kind = %-5d  level = %-4d  tval = %-5d  sval = %-5d", o_ptr->bi_id, item_level, enum2i(bi_key.tval()), bi_key.sval().value()), line, j);
+    prt(format("kind = %-5d  level = %-4d  tval = %-5d  sval = %-5d", o_ptr->bi_id, item_level, enum2i(bi_key.tval()), *bi_key.sval()), line, j);
     prt(format("number = %-3d  wgt = %-6d  ac = %-5d    damage = %dd%d", o_ptr->number, o_ptr->weight, o_ptr->ac, o_ptr->dd, o_ptr->ds), ++line, j);
     prt(format("pval = %-5d  toac = %-5d  tohit = %-4d  todam = %-4d", o_ptr->pval, o_ptr->to_a, o_ptr->to_h, o_ptr->to_d), ++line, j);
     prt(format("fixed_artifact_idx = %-4d  ego_idx = %-4d  cost = %d", enum2i(o_ptr->fixed_artifact_idx), enum2i(o_ptr->ego_idx), object_value_real(o_ptr)), ++line, j);
@@ -355,6 +411,7 @@ static void wiz_display_item(PlayerType *player_ptr, ItemEntity *o_ptr)
     prt(format("cursed  = %-4lX  captured_monster_speed = %-4d", o_ptr->curse_flags.to_ulong(), o_ptr->captured_monster_speed), ++line, j);
     prt(format("captured_monster_max_hp = %-4d  captured_monster_max_hp = %-4d", o_ptr->captured_monster_current_hp, o_ptr->captured_monster_max_hp), ++line, j);
 
+    const auto flags = o_ptr->get_flags();
     prt("+------------FLAGS1------------+", ++line, j);
     prt("AFFECT........SLAY........BRAND.", ++line, j);
     prt("      mf      cvae      xsqpaefc", ++line, j);
@@ -402,86 +459,88 @@ static void wiz_display_item(PlayerType *player_ptr, ItemEntity *o_ptr)
  */
 static void wiz_statistics(PlayerType *player_ptr, ItemEntity *o_ptr)
 {
-    concptr q = "Rolls: %ld  Correct: %ld  Matches: %ld  Better: %ld  Worse: %ld  Other: %ld";
-    concptr p = "Enter number of items to roll: ";
-    char tmp_val[80];
-
+    constexpr auto prompt = "Roll for [n]ormal, [g]ood, or [e]xcellent treasure? ";
     if (o_ptr->is_fixed_artifact()) {
         o_ptr->get_fixed_artifact().is_generated = false;
     }
 
-    uint32_t i, matches, better, worse, other, correct;
-    uint32_t test_roll = 1000000;
-    char ch;
-    concptr quality;
-    BIT_FLAGS mode;
+    auto rolls = 1000000;
     while (true) {
-        concptr pmt = "Roll for [n]ormal, [g]ood, or [e]xcellent treasure? ";
         wiz_display_item(player_ptr, o_ptr);
-        if (!get_com(pmt, &ch, false)) {
+        const auto command = input_command(prompt);
+        if (!command) {
             break;
         }
 
-        if (ch == 'n' || ch == 'N') {
+        BIT_FLAGS mode;
+        std::string quality;
+        if (command == 'n' || command == 'N') {
             mode = 0L;
             quality = "normal";
-        } else if (ch == 'g' || ch == 'G') {
+        } else if (command == 'g' || command == 'G') {
             mode = AM_GOOD;
             quality = "good";
-        } else if (ch == 'e' || ch == 'E') {
+        } else if (command == 'e' || command == 'E') {
             mode = AM_GOOD | AM_GREAT;
             quality = "excellent";
         } else {
             break;
         }
 
-        strnfmt(tmp_val, sizeof(tmp_val), "%ld", (long int)test_roll);
-        if (get_string(p, tmp_val, 10)) {
-            test_roll = atol(tmp_val);
+        constexpr auto p = "Enter number of items to roll: ";
+        const auto rolls_opt = input_numerics(p, 0, MAX_INT, rolls);
+        if (rolls_opt) {
+            rolls = *rolls_opt;
         }
-        test_roll = std::max<uint>(1, test_roll);
-        msg_format("Creating a lot of %s items. Base level = %d.", quality, player_ptr->current_floor_ptr->dun_level);
-        msg_print(nullptr);
 
-        correct = matches = better = worse = other = 0;
-        for (i = 0; i <= test_roll; i++) {
-            if ((i < 100) || (i % 100 == 0)) {
+        constexpr auto q = "Rolls: %d  Correct: %d  Matches: %d  Better: %d  Worse: %d  Other: %d";
+        msg_format("Creating a lot of %s items. Base level = %d.", quality.data(), player_ptr->current_floor_ptr->dun_level);
+        msg_print(nullptr);
+        auto correct = 0;
+        auto matches = 0;
+        auto better = 0;
+        auto worse = 0;
+        auto other = 0;
+        auto count = 0;
+        for (; count <= rolls; count++) {
+            if ((count < 100) || (count % 100 == 0)) {
                 inkey_scan = true;
                 if (inkey()) {
                     flush();
                     break; // stop rolling
                 }
 
-                prt(format(q, i, correct, matches, better, worse, other), 0, 0);
+                prt(format(q, count, correct, matches, better, worse, other), 0, 0);
                 term_fresh();
             }
 
-            ItemEntity forge;
-            auto *q_ptr = &forge;
-            q_ptr->wipe();
-            make_object(player_ptr, q_ptr, mode);
-            if (q_ptr->is_fixed_artifact()) {
-                q_ptr->get_fixed_artifact().is_generated = false;
+            ItemEntity item;
+            if (!make_object(player_ptr, &item, mode)) {
+                continue;
+            }
+
+            if (item.is_fixed_artifact()) {
+                item.get_fixed_artifact().is_generated = false;
             }
 
-            if (o_ptr->bi_key != q_ptr->bi_key) {
+            if (o_ptr->bi_key != item.bi_key) {
                 continue;
             }
 
             correct++;
-            const auto is_same_fixed_artifact_idx = o_ptr->is_specific_artifact(q_ptr->fixed_artifact_idx);
-            if ((q_ptr->pval == o_ptr->pval) && (q_ptr->to_a == o_ptr->to_a) && (q_ptr->to_h == o_ptr->to_h) && (q_ptr->to_d == o_ptr->to_d) && is_same_fixed_artifact_idx) {
+            const auto is_same_fixed_artifact_idx = o_ptr->is_specific_artifact(item.fixed_artifact_idx);
+            if ((item.pval == o_ptr->pval) && (item.to_a == o_ptr->to_a) && (item.to_h == o_ptr->to_h) && (item.to_d == o_ptr->to_d) && is_same_fixed_artifact_idx) {
                 matches++;
-            } else if ((q_ptr->pval >= o_ptr->pval) && (q_ptr->to_a >= o_ptr->to_a) && (q_ptr->to_h >= o_ptr->to_h) && (q_ptr->to_d >= o_ptr->to_d)) {
+            } else if ((item.pval >= o_ptr->pval) && (item.to_a >= o_ptr->to_a) && (item.to_h >= o_ptr->to_h) && (item.to_d >= o_ptr->to_d)) {
                 better++;
-            } else if ((q_ptr->pval <= o_ptr->pval) && (q_ptr->to_a <= o_ptr->to_a) && (q_ptr->to_h <= o_ptr->to_h) && (q_ptr->to_d <= o_ptr->to_d)) {
+            } else if ((item.pval <= o_ptr->pval) && (item.to_a <= o_ptr->to_a) && (item.to_h <= o_ptr->to_h) && (item.to_d <= o_ptr->to_d)) {
                 worse++;
             } else {
                 other++;
             }
         }
 
-        msg_format(q, i, correct, matches, better, worse, other);
+        msg_format(q, count, correct, matches, better, worse, other);
         msg_print(nullptr);
     }
 
@@ -502,15 +561,15 @@ static void wiz_reroll_item(PlayerType *player_ptr, ItemEntity *o_ptr)
     }
 
     ItemEntity forge;
-    ItemEntity *q_ptr;
-    q_ptr = &forge;
+    auto *q_ptr = &forge;
     q_ptr->copy_from(o_ptr);
 
-    char ch;
-    bool changed = false;
+    auto changed = false;
+    constexpr auto prompt = "[a]ccept, [w]orthless, [c]ursed, [n]ormal, [g]ood, [e]xcellent, [s]pecial? ";
     while (true) {
         wiz_display_item(player_ptr, q_ptr);
-        if (!get_com("[a]ccept, [w]orthless, [c]ursed, [n]ormal, [g]ood, [e]xcellent, [s]pecial? ", &ch, false)) {
+        const auto command = input_command(prompt);
+        if (!command) {
             if (q_ptr->is_fixed_artifact()) {
                 q_ptr->get_fixed_artifact().is_generated = false;
                 q_ptr->fixed_artifact_idx = FixedArtifactId::NONE;
@@ -520,7 +579,7 @@ static void wiz_reroll_item(PlayerType *player_ptr, ItemEntity *o_ptr)
             break;
         }
 
-        if (ch == 'A' || ch == 'a') {
+        if (command == 'A' || command == 'a') {
             changed = true;
             break;
         }
@@ -530,7 +589,7 @@ static void wiz_reroll_item(PlayerType *player_ptr, ItemEntity *o_ptr)
             q_ptr->fixed_artifact_idx = FixedArtifactId::NONE;
         }
 
-        switch (tolower(ch)) {
+        switch (tolower(*command)) {
         /* Apply bad magic, but first clear object */
         case 'w':
             q_ptr->prep(o_ptr->bi_id);
@@ -579,8 +638,22 @@ static void wiz_reroll_item(PlayerType *player_ptr, ItemEntity *o_ptr)
     }
 
     o_ptr->copy_from(q_ptr);
-    set_bits(player_ptr->update, PU_BONUS | PU_COMBINATION | PU_REORDER);
-    set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_SPELL | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::COMBINATION,
+        StatusRecalculatingFlag::REORDER,
+    };
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_swrf = {
+        SubWindowRedrawingFlag::INVENTORY,
+        SubWindowRedrawingFlag::EQUIPMENT,
+        SubWindowRedrawingFlag::SPELL,
+        SubWindowRedrawingFlag::PLAYER,
+        SubWindowRedrawingFlag::FLOOR_ITEMS,
+        SubWindowRedrawingFlag::FOUND_ITEMS,
+    };
+    rfu.set_flags(flags_swrf);
 }
 
 /*!
@@ -594,45 +667,38 @@ static void wiz_tweak_item(PlayerType *player_ptr, ItemEntity *o_ptr)
         return;
     }
 
-    concptr p = "Enter new 'pval' setting: ";
-    char tmp_val[80];
-    strnfmt(tmp_val, sizeof(tmp_val), "%d", o_ptr->pval);
-    if (!get_string(p, tmp_val, 5)) {
+    const auto pval = input_numerics("Enter new 'pval' setting: ", -MAX_SHORT, MAX_SHORT, o_ptr->pval);
+    if (!pval) {
         return;
     }
 
-    o_ptr->pval = clamp_cast<int16_t>(atoi(tmp_val));
+    o_ptr->pval = *pval;
     wiz_display_item(player_ptr, o_ptr);
-    p = "Enter new 'to_a' setting: ";
-    strnfmt(tmp_val, sizeof(tmp_val), "%d", o_ptr->to_a);
-    if (!get_string(p, tmp_val, 5)) {
+    const auto bonus_ac = input_numerics("Enter new AC Bonus setting: ", -MAX_SHORT, MAX_SHORT, o_ptr->to_a);
+    if (!bonus_ac) {
         return;
     }
 
-    o_ptr->to_a = clamp_cast<int16_t>(atoi(tmp_val));
+    o_ptr->to_a = *bonus_ac;
     wiz_display_item(player_ptr, o_ptr);
-    p = "Enter new 'to_h' setting: ";
-    strnfmt(tmp_val, sizeof(tmp_val), "%d", o_ptr->to_h);
-    if (!get_string(p, tmp_val, 5)) {
+    const auto bonus_hit = input_numerics("Enter new Hit Bonus setting: ", -MAX_SHORT, MAX_SHORT, o_ptr->to_h);
+    if (!bonus_hit) {
         return;
     }
 
-    o_ptr->to_h = clamp_cast<int16_t>(atoi(tmp_val));
+    o_ptr->to_h = *bonus_hit;
     wiz_display_item(player_ptr, o_ptr);
-    p = "Enter new 'to_d' setting: ";
-    strnfmt(tmp_val, sizeof(tmp_val), "%d", (int)o_ptr->to_d);
-    if (!get_string(p, tmp_val, 5)) {
+    const auto bonus_damage = input_numerics("Enter new Damage Bonus setting: ", -MAX_SHORT, MAX_SHORT, o_ptr->to_d);
+    if (!bonus_damage) {
         return;
     }
 
-    o_ptr->to_d = clamp_cast<int16_t>(atoi(tmp_val));
+    o_ptr->to_d = *bonus_damage;
     wiz_display_item(player_ptr, o_ptr);
 }
 
 /*!
- * @brief 検査対象のアイテムの数を変更する /
- * Change the quantity of a the item
- * @param player_ptr プレイヤーへの参照ポインタ
+ * @brief 検査対象のアイテムの数を変更する
  * @param o_ptr 変更するアイテム情報構造体の参照ポインタ
  */
 static void wiz_quantity_item(ItemEntity *o_ptr)
@@ -641,24 +707,14 @@ static void wiz_quantity_item(ItemEntity *o_ptr)
         return;
     }
 
-    int tmp_qnt = o_ptr->number;
-    char tmp_val[100];
-    strnfmt(tmp_val, sizeof(tmp_val), "%d", (int)o_ptr->number);
-    if (get_string("Quantity: ", tmp_val, 2)) {
-        int tmp_int = atoi(tmp_val);
-        if (tmp_int < 1) {
-            tmp_int = 1;
-        }
-
-        if (tmp_int > 99) {
-            tmp_int = 99;
-        }
-
-        o_ptr->number = (byte)tmp_int;
+    const auto quantity = input_numerics("Quantity: ", 1, 99, o_ptr->number);
+    if (!quantity) {
+        return;
     }
 
+    o_ptr->number = *quantity;
     if (o_ptr->bi_key.tval() == ItemKindType::ROD) {
-        o_ptr->pval = o_ptr->pval * o_ptr->number / tmp_qnt;
+        o_ptr->pval = o_ptr->pval * o_ptr->number / *quantity;
     }
 }
 
@@ -675,8 +731,8 @@ void wiz_modify_item(PlayerType *player_ptr)
 {
     constexpr auto q = "Play with which object? ";
     constexpr auto s = "You have nothing to play with.";
-    short item;
-    auto *o_ptr = choose_object(player_ptr, &item, q, s, USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT);
+    short i_idx;
+    auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT);
     if (!o_ptr) {
         return;
     }
@@ -684,36 +740,36 @@ void wiz_modify_item(PlayerType *player_ptr)
     screen_save();
 
     ItemEntity forge;
-    ItemEntity *q_ptr;
-    q_ptr = &forge;
+    auto *q_ptr = &forge;
     q_ptr->copy_from(o_ptr);
-    char ch;
-    bool changed = false;
+    auto changed = false;
+    constexpr auto prompt = "[a]ccept [s]tatistics [r]eroll [t]weak [q]uantity? ";
     while (true) {
         wiz_display_item(player_ptr, q_ptr);
-        if (!get_com("[a]ccept [s]tatistics [r]eroll [t]weak [q]uantity? ", &ch, false)) {
+        const auto command = input_command(prompt);
+        if (!command) {
             changed = false;
             break;
         }
 
-        if (ch == 'A' || ch == 'a') {
+        if (command == 'A' || command == 'a') {
             changed = true;
             break;
         }
 
-        if (ch == 's' || ch == 'S') {
+        if (command == 's' || command == 'S') {
             wiz_statistics(player_ptr, q_ptr);
         }
 
-        if (ch == 'r' || ch == 'R') {
+        if (command == 'r' || command == 'R') {
             wiz_reroll_item(player_ptr, q_ptr);
         }
 
-        if (ch == 't' || ch == 'T') {
+        if (command == 't' || command == 'T') {
             wiz_tweak_item(player_ptr, q_ptr);
         }
 
-        if (ch == 'q' || ch == 'Q') {
+        if (command == 'q' || command == 'Q') {
             wiz_quantity_item(q_ptr);
         }
     }
@@ -723,8 +779,22 @@ void wiz_modify_item(PlayerType *player_ptr)
         msg_print("Changes accepted.");
 
         o_ptr->copy_from(q_ptr);
-        set_bits(player_ptr->update, PU_BONUS | PU_COMBINATION | PU_REORDER);
-        set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_SPELL | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
+        auto &rfu = RedrawingFlagsUpdater::get_instance();
+        static constexpr auto flags_srf = {
+            StatusRecalculatingFlag::BONUS,
+            StatusRecalculatingFlag::COMBINATION,
+            StatusRecalculatingFlag::REORDER,
+        };
+        rfu.set_flags(flags_srf);
+        static constexpr auto flags_swrf = {
+            SubWindowRedrawingFlag::INVENTORY,
+            SubWindowRedrawingFlag::EQUIPMENT,
+            SubWindowRedrawingFlag::SPELL,
+            SubWindowRedrawingFlag::PLAYER,
+            SubWindowRedrawingFlag::FLOOR_ITEMS,
+            SubWindowRedrawingFlag::FOUND_ITEMS,
+        };
+        rfu.set_flags(flags_swrf);
     } else {
         msg_print("Changes ignored.");
     }
@@ -768,7 +838,7 @@ static void wishing_puff_of_smoke(void)
  */
 WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art, bool allow_ego, bool confirm)
 {
-    concptr fixed_str[] = {
+    const std::array<std::string, _(4, 6)> fixed_expressions = {
 #ifdef JP
         "燃えない",
         "錆びない",
@@ -782,44 +852,49 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
         "corrodeproof",
         "fixed",
 #endif
-        nullptr,
     };
 
-    char buf[MAX_NLEN] = "\0";
-    char *str = buf;
     ItemEntity forge;
     auto *o_ptr = &forge;
-    bool wish_art = false;
-    bool wish_randart = false;
-    bool wish_ego = false;
-    bool exam_base = true;
-    bool ok_art = randint0(100) < prob;
-    bool ok_ego = randint0(100) < 50 + prob;
-    bool must = prob < 0;
-    bool blessed = false;
-    bool fixed = true;
-
-    while (1) {
-        if (get_string(_("何をお望み? ", "For what do you wish?"), buf, (MAX_NLEN - 1))) {
+    auto wish_art = false;
+    auto wish_randart = false;
+    auto wish_ego = false;
+    auto exam_base = true;
+    auto ok_art = randint0(100) < prob;
+    auto ok_ego = randint0(100) < 50 + prob;
+    auto must = prob < 0;
+    auto blessed = false;
+    auto fixed = true;
+
+    std::string pray;
+    while (true) {
+        const auto pray_opt = input_string(_("何をお望み? ", "For what do you wish?"), MAX_NLEN);
+        if (pray_opt) {
+            pray = *pray_opt;
             break;
         }
+
         if (confirm) {
-            if (!get_check(_("何も願いません。本当によろしいですか?", "Do you wish nothing, really? "))) {
+            if (!input_check(_("何も願いません。本当によろしいですか?", "Do you wish nothing, really? "))) {
                 continue;
             }
         }
+
         return WishResultType::NOTHING;
     }
 
+    auto *str = pray.data();
 #ifndef JP
     str_tolower(str);
-
-    /* remove 'a' */
-    if (!strncmp(buf, "a ", 2)) {
-        str = ltrim(str + 1);
-    } else if (!strncmp(buf, "an ", 3)) {
-        str = ltrim(str + 2);
+    const std::string article_single("a ");
+    const std::string article_multi("an ");
+    if (pray.starts_with("a ")) {
+        str += article_single.length();
+    } else if (pray.starts_with("an ")) {
+        str += article_multi.length();
     }
+
+    str = ltrim(str);
 #endif // !JP
 
     str = rtrim(str);
@@ -829,9 +904,9 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
         blessed = true;
     }
 
-    for (int i = 0; fixed_str[i] != nullptr; i++) {
-        int len = strlen(fixed_str[i]);
-        if (!strncmp(str, fixed_str[i], len)) {
+    for (const auto &expression : fixed_expressions) {
+        auto len = expression.length();
+        if (std::string_view(str).starts_with(expression)) {
             str = ltrim(str + len);
             fixed = true;
             break;
@@ -869,13 +944,13 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
     }
 
     if (cheat_xtra) {
-        msg_format("Wishing %s....", buf);
+        msg_format("Wishing %s....", pray.data());
     }
 
-    std::vector<short> k_ids;
-    std::vector<EgoType> e_ids;
+    std::vector<short> baseitem_ids;
+    std::vector<EgoType> ego_ids;
     if (exam_base) {
-        int max_len = 0;
+        auto max_len = 0;
         for (const auto &baseitem : baseitems_info) {
             if (baseitem.idx == 0 || baseitem.name.empty()) {
                 continue;
@@ -895,14 +970,14 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
             const int len = item_name.length();
             if (std::string(str).find(item_name) != std::string::npos) {
                 if (len > max_len) {
-                    k_ids.push_back(baseitem.idx);
+                    baseitem_ids.push_back(baseitem.idx);
                     max_len = len;
                 }
             }
         }
 
-        if (allow_ego && k_ids.size() == 1) {
-            short bi_id = k_ids.back();
+        if (allow_ego && baseitem_ids.size() == 1) {
+            short bi_id = baseitem_ids.back();
             o_ptr->prep(bi_id);
 
             for (const auto &[e_idx, ego] : egos_info) {
@@ -924,20 +999,20 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
                         continue;
                     }
 
-                    e_ids.push_back(ego.idx);
+                    ego_ids.push_back(ego.idx);
                 }
             }
         }
     }
 
-    std::vector<FixedArtifactId> a_ids;
+    std::vector<FixedArtifactId> artifact_ids;
 
     if (allow_art) {
         char a_desc[MAX_NLEN] = "\0";
         char *a_str = a_desc;
 
         int len;
-        int mlen = 0;
+        auto mlen = 0;
         for (const auto &[a_idx, artifact] : artifacts_info) {
             if (a_idx == FixedArtifactId::NONE || artifact.name.empty()) {
                 continue;
@@ -981,7 +1056,7 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
             /* remove quotes */
             if (a_str[0] == '\'') {
                 a_str += 1;
-                char *s = strchr(a_desc, '\'');
+                auto *s = angband_strchr(a_desc, '\'');
                 *s = '\0';
             }
             /* remove 'of ' */
@@ -1001,7 +1076,7 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
                 if (!strcmp(str, l.at(c))) {
                     len = strlen(l.at(c));
                     if (len > mlen) {
-                        a_ids.push_back(a_idx);
+                        artifact_ids.push_back(a_idx);
                         mlen = len;
                     }
                 }
@@ -1009,13 +1084,13 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
         }
     }
 
-    if (w_ptr->wizard && (a_ids.size() > 1 || e_ids.size() > 1)) {
+    if (w_ptr->wizard && ((artifact_ids.size() > 1) || (ego_ids.size() > 1))) {
         msg_print(_("候補が多すぎる!", "Too many matches!"));
         return WishResultType::FAIL;
     }
 
-    if (a_ids.size() == 1) {
-        const auto a_idx = a_ids.back();
+    if (artifact_ids.size() == 1) {
+        const auto a_idx = artifact_ids.back();
         const auto &artifact = ArtifactsInfo::get_instance().get_artifact(a_idx);
         if (must || (ok_art && !artifact.is_generated)) {
             (void)create_named_art(player_ptr, a_idx, player_ptr->y, player_ptr->x);
@@ -1026,13 +1101,13 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
         return WishResultType::ARTIFACT;
     }
 
-    if (!allow_ego && (wish_ego || e_ids.size() > 0)) {
+    if (!allow_ego && (wish_ego || ego_ids.size() > 0)) {
         msg_print(_("エゴアイテムは願えない!", "Can not wish ego item."));
         return WishResultType::NOTHING;
     }
 
-    if (k_ids.size() == 1) {
-        const auto bi_id = k_ids.back();
+    if (baseitem_ids.size() == 1) {
+        const auto bi_id = baseitem_ids.back();
         const auto &baseitem = baseitems_info[bi_id];
         auto a_idx = FixedArtifactId::NONE;
         if (baseitem.gen_flags.has(ItemGenerationTraitType::INSTA_ART)) {
@@ -1074,15 +1149,15 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
         }
 
         WishResultType res = WishResultType::NOTHING;
-        if (allow_ego && (wish_ego || e_ids.size() > 0)) {
+        if (allow_ego && (wish_ego || ego_ids.size() > 0)) {
             if (must || ok_ego) {
-                if (e_ids.size() > 0) {
+                if (ego_ids.size() > 0) {
                     o_ptr->prep(bi_id);
-                    o_ptr->ego_idx = e_ids[0];
+                    o_ptr->ego_idx = ego_ids[0];
                     apply_ego(o_ptr, player_ptr->current_floor_ptr->base_level);
                 } else {
-                    int max_roll = 1000;
-                    int i = 0;
+                    auto max_roll = 1000;
+                    auto i = 0;
                     for (i = 0; i < max_roll; i++) {
                         o_ptr->prep(bi_id);
                         ItemMagicApplier(player_ptr, o_ptr, baseitem.level, AM_GREAT | AM_NO_FIXED_ART).execute();
@@ -1094,8 +1169,8 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
                             break;
                         }
 
-                        EgoType e_idx = EgoType::NONE;
-                        for (auto e : e_ids) {
+                        auto e_idx = EgoType::NONE;
+                        for (auto e : ego_ids) {
                             if (o_ptr->ego_idx == e) {
                                 e_idx = e;
                                 break;
@@ -1118,13 +1193,14 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
 
             res = WishResultType::EGO;
         } else {
-            for (int i = 0; i < 100; i++) {
+            for (auto i = 0; i < 100; i++) {
                 o_ptr->prep(bi_id);
                 ItemMagicApplier(player_ptr, o_ptr, 0, AM_NO_FIXED_ART).execute();
                 if (!o_ptr->is_cursed()) {
                     break;
                 }
             }
+
             res = WishResultType::NORMAL;
         }
 
@@ -1138,7 +1214,6 @@ WishResultType do_cmd_wishing(PlayerType *player_ptr, int prob, bool allow_art,
         }
 
         (void)drop_near(player_ptr, o_ptr, -1, player_ptr->y, player_ptr->x);
-
         return res;
     }
 
index 1748419..14029ae 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index fc81716..cf70a8b 100644 (file)
@@ -1,39 +1,50 @@
-#include "wizard/wizard-messages.h"
+#include "wizard/wizard-messages.h"
 #include "game-option/cheat-options.h"
 #include "game-option/cheat-types.h"
 #include "io/write-diary.h"
+#include "system/angband-exceptions.h"
 #include "view/display-messages.h"
+#include <array>
+#include <sstream>
 #include <string>
 
-void msg_print_wizard(PlayerType *player_ptr, int cheat_type, concptr msg)
+void msg_print_wizard(PlayerType *player_ptr, int cheat_type, std::string_view msg)
 {
+    constexpr auto max_type = 4;
+    if ((cheat_type < 0) || (cheat_type >= max_type)) {
+        THROW_EXCEPTION(std::logic_error, "Invalid cheat type is specified!");
+    }
+
     if (!cheat_room && cheat_type == CHEAT_DUNGEON) {
         return;
     }
+
     if (!cheat_peek && cheat_type == CHEAT_OBJECT) {
         return;
     }
+
     if (!cheat_hear && cheat_type == CHEAT_MONSTER) {
         return;
     }
+
     if (!cheat_xtra && cheat_type == CHEAT_MISC) {
         return;
     }
 
-    concptr cheat_mes[] = { "ITEM:", "MONS:", "DUNG:", "MISC:" };
-    std::string buf = "WIZ-";
-    buf.append(cheat_mes[cheat_type]).append(msg);
-    msg_print(buf);
-
+    static const std::array<std::string, max_type> cheat_mes = { { "ITEM:", "MONS:", "DUNG:", "MISC:" } };
+    std::stringstream ss;
+    ss << "WIZ-" << cheat_mes[cheat_type] << msg;
+    const auto mes = ss.str();
+    msg_print(mes);
     if (cheat_diary_output) {
-        exe_write_diary(player_ptr, DIARY_WIZARD_LOG, 0, buf.data());
+        exe_write_diary(player_ptr, DiaryKind::WIZARD_LOG, 0, mes);
     }
 }
 
 /*
  * Display a formatted message, using "vstrnfmt()" and "msg_print()".
  */
-void msg_format_wizard(PlayerType *player_ptr, int cheat_type, concptr fmt, ...)
+void msg_format_wizard(PlayerType *player_ptr, int cheat_type, const char *fmt, ...)
 {
     if (!cheat_room && cheat_type == CHEAT_DUNGEON) {
         return;
index 6d2c51a..c58ffef 100644 (file)
@@ -1,7 +1,8 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
+#include <string_view>
 
 class PlayerType;
-void msg_print_wizard(PlayerType *player_ptr, int cheat_type, concptr msg);
-void msg_format_wizard(PlayerType *player_ptr, int cheat_type, concptr fmt, ...) __attribute__((format(printf, 3, 4)));
+void msg_print_wizard(PlayerType *player_ptr, int cheat_type, std::string_view msg);
+void msg_format_wizard(PlayerType *player_ptr, int cheat_type, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
index 8192f1b..0cebb6a 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief プレイヤー属性を変更するデバッグコマンド
  * @date 2021/03/07
  */
@@ -48,7 +48,7 @@ void display_wizard_player_modifier_menu()
     for (const auto &[symbol, desc] : wizard_player_modifier_menu_table) {
         std::stringstream ss;
         ss << symbol << ") " << desc;
-        put_str(ss.str().data(), r++, c);
+        put_str(ss.str(), r++, c);
     }
 }
 
@@ -61,8 +61,8 @@ void wizard_player_modifier(PlayerType *player_ptr)
     screen_save();
     display_wizard_player_modifier_menu();
 
-    char cmd;
-    get_com("Player Command: ", &cmd, false);
+    const auto command = input_command("Player Command: ");
+    const auto cmd = command.value_or(ESCAPE);
     screen_load();
 
     switch (cmd) {
index 5f0b764..9f6f03a 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void wizard_player_modifier(PlayerType *player_ptr);
index 6475f46..bb3ebe8 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ウィザードモードの処理(特別処理中心) / Wizard commands
  * @date 2014/09/07
  * @author
@@ -18,8 +18,6 @@
 #include "cmd-io/cmd-save.h"
 #include "cmd-visual/cmd-draw.h"
 #include "core/asking-player.h"
-#include "core/player-redraw-types.h"
-#include "core/player-update-types.h"
 #include "core/stuff-handler.h"
 #include "core/window-redrawer.h"
 #include "dungeon/quest.h"
@@ -78,6 +76,7 @@
 #include "spell/spells-summon.h"
 #include "status/bad-status-setter.h"
 #include "status/experience.h"
+#include "system/angband-system.h"
 #include "system/angband-version.h"
 #include "system/artifact-type-definition.h"
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/monster-entity.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "system/terrain-type-definition.h"
 #include "target/grid-selector.h"
 #include "term/screen-processor.h"
 #include "term/z-form.h"
 #include "util/angband-files.h"
 #include "util/bit-flags-calculator.h"
+#include "util/candidate-selector.h"
 #include "util/enum-converter.h"
+#include "util/finalizer.h"
 #include "util/int-char-converter.h"
 #include "view/display-messages.h"
 #include "wizard/spoiler-table.h"
 #include "wizard/tval-descriptions-table.h"
+#include "wizard/wizard-messages.h"
 #include "wizard/wizard-spells.h"
 #include "wizard/wizard-spoiler.h"
 #include "world/world.h"
 #include <algorithm>
 #include <optional>
+#include <span>
 #include <sstream>
 #include <tuple>
 #include <vector>
@@ -127,22 +131,21 @@ void wiz_cure_all(PlayerType *player_ptr)
 static std::optional<short> wiz_select_tval()
 {
     short list;
-    char ch;
     for (list = 0; (list < 80) && (tvals[list].tval > ItemKindType::NONE); list++) {
         auto row = 2 + (list % 20);
         auto col = _(32, 24) * (list / 20);
-        ch = listsym[list];
-        prt(format("[%c] %s", ch, tvals[list].desc), row, col);
+        prt(format("[%c] %s", listsym[list], tvals[list].desc), row, col);
     }
 
-    auto max_num = list;
-    if (!get_com(_("アイテム種別を選んで下さい", "Get what type of object? "), &ch, false)) {
+    const auto item_type = input_command(_("アイテム種別を選んで下さい", "Get what type of object? "));
+    if (!item_type) {
         return std::nullopt;
     }
 
     short selection;
+    auto max_num = list;
     for (selection = 0; selection < max_num; selection++) {
-        if (listsym[selection] == ch) {
+        if (listsym[selection] == item_type) {
             break;
         }
     }
@@ -154,11 +157,10 @@ static std::optional<short> wiz_select_tval()
     return selection;
 }
 
-static short wiz_select_sval(const ItemKindType tval, concptr tval_description)
+static short wiz_select_sval(const ItemKindType tval, std::string_view tval_description)
 {
     auto num = 0;
     short choice[80]{};
-    char ch;
     for (const auto &baseitem : baseitems_info) {
         if (num >= 80) {
             break;
@@ -170,20 +172,21 @@ static short wiz_select_sval(const ItemKindType tval, concptr tval_description)
 
         auto row = 2 + (num % 20);
         auto col = _(30, 32) * (num / 20);
-        ch = listsym[num];
         const auto buf = strip_name(baseitem.idx);
-        prt(format("[%c] %s", ch, buf.data()), row, col);
+        prt(format("[%c] %s", listsym[num], buf.data()), row, col);
         choice[num++] = baseitem.idx;
     }
 
     auto max_num = num;
-    if (!get_com(format(_("%s群の具体的なアイテムを選んで下さい", "What Kind of %s? "), tval_description), &ch, false)) {
+    const auto prompt = format(_("%s群の具体的なアイテムを選んで下さい", "What Kind of %s? "), tval_description.data());
+    const auto command = input_command(prompt);
+    if (!command) {
         return 0;
     }
 
     short selection;
     for (selection = 0; selection < max_num; selection++) {
-        if (listsym[selection] == ch) {
+        if (listsym[selection] == command) {
             break;
         }
     }
@@ -208,12 +211,12 @@ static short wiz_create_itemtype()
 {
     term_clear();
     auto selection = wiz_select_tval();
-    if (!selection.has_value()) {
+    if (!selection) {
         return 0;
     }
 
-    auto tval = tvals[selection.value()].tval;
-    auto tval_description = tvals[selection.value()].desc;
+    auto tval = tvals[*selection].tval;
+    auto tval_description = tvals[*selection].desc;
     term_clear();
     return wiz_select_sval(tval, tval_description);
 }
@@ -270,7 +273,7 @@ static std::string wiz_make_named_artifact_desc(PlayerType *player_ptr, FixedArt
     ItemEntity item;
     item.prep(lookup_baseitem_id(artifact.bi_key));
     item.fixed_artifact_idx = a_idx;
-    object_known(&item);
+    item.mark_as_known();
     return describe_flavor(player_ptr, &item, OD_NAME_ONLY);
 }
 
@@ -282,53 +285,11 @@ static std::string wiz_make_named_artifact_desc(PlayerType *player_ptr, FixedArt
  */
 static std::optional<FixedArtifactId> wiz_select_named_artifact(PlayerType *player_ptr, const std::vector<FixedArtifactId> &a_idx_list)
 {
-    constexpr auto MAX_PER_PAGE = 20UL;
-    const auto page_max = (a_idx_list.size() - 1) / MAX_PER_PAGE + 1;
-    auto current_page = 0UL;
-
-    screen_save();
-
-    std::optional<FixedArtifactId> selected_a_idx;
+    CandidateSelector cs("Which artifact: ", 15);
 
-    while (!selected_a_idx.has_value()) {
-        const auto page_base_idx = current_page * MAX_PER_PAGE;
-        for (auto i = 0U; i < MAX_PER_PAGE + 1; ++i) {
-            term_erase(14, i + 1, 255);
-        }
-        const auto page_item_count = std::min(MAX_PER_PAGE, a_idx_list.size() - page_base_idx);
-        for (auto i = 0U; i < page_item_count; ++i) {
-            std::stringstream ss;
-            ss << I2A(i) << ") " << wiz_make_named_artifact_desc(player_ptr, a_idx_list[page_base_idx + i]);
-            put_str(ss.str().data(), i + 1, 15);
-        }
-        if (page_max > 1) {
-            put_str(format("-- more (%lu/%lu) --", current_page + 1, page_max), page_item_count + 1, 15);
-        }
-
-        char cmd = ESCAPE;
-        get_com("Which artifact: ", &cmd, false);
-        switch (cmd) {
-        case ESCAPE:
-            screen_load();
-            return selected_a_idx;
-        case ' ':
-            current_page++;
-            if (current_page >= page_max) {
-                current_page = 0;
-            }
-            break;
-        default:
-            const auto select_idx = A2I(cmd) + page_base_idx;
-            if (select_idx < a_idx_list.size()) {
-                selected_a_idx = a_idx_list[select_idx];
-            }
-            break;
-        }
-    }
-
-    screen_load();
-
-    return selected_a_idx;
+    auto describe_artifact = [player_ptr](FixedArtifactId a_idx) { return wiz_make_named_artifact_desc(player_ptr, a_idx); };
+    const auto it = cs.select(a_idx_list, describe_artifact);
+    return (it != a_idx_list.end()) ? std::make_optional(*it) : std::nullopt;
 }
 
 /**
@@ -362,30 +323,29 @@ void wiz_create_named_art(PlayerType *player_ptr)
         const auto &[tval_lit, name] = group_artifact_list[i];
         std::stringstream ss;
         ss << I2A(i) << ") " << name;
-        term_erase(14, i + 1, 255);
-        put_str(ss.str().data(), i + 1, 15);
+        term_erase(14, i + 1);
+        put_str(ss.str(), i + 1, 15);
     }
 
     std::optional<FixedArtifactId> create_a_idx;
-    while (!create_a_idx.has_value()) {
-        char cmd = ESCAPE;
-        get_com("Kind of artifact: ", &cmd, false);
-        switch (cmd) {
-        case ESCAPE:
+    while (!create_a_idx) {
+        const auto command = input_command("Kind of artifact: ");
+        if (!command) {
             screen_load();
             return;
-        default:
-            if (auto idx = A2I(cmd); idx < group_artifact_list.size()) {
-                const auto &a_idx_list = wiz_collect_group_a_idx(group_artifact_list[idx]);
-                create_a_idx = wiz_select_named_artifact(player_ptr, a_idx_list);
-            }
+        }
 
-            break;
+        const auto idx = A2I(*command);
+        if (idx >= group_artifact_list.size()) {
+            continue;
         }
+
+        const auto a_idx_list = wiz_collect_group_a_idx(group_artifact_list[idx]);
+        create_a_idx = wiz_select_named_artifact(player_ptr, a_idx_list);
     }
 
     screen_load();
-    const auto a_idx = create_a_idx.value();
+    const auto a_idx = *create_a_idx;
     const auto &artifact = ArtifactsInfo::get_instance().get_artifact(a_idx);
     if (artifact.is_generated) {
         msg_print("It's already allocated.");
@@ -396,50 +356,88 @@ void wiz_create_named_art(PlayerType *player_ptr)
     msg_print("Allocated.");
 }
 
+static void wiz_change_status_max(PlayerType *player_ptr)
+{
+    for (auto i = 0; i < A_MAX; ++i) {
+        player_ptr->stat_cur[i] = player_ptr->stat_max_max[i];
+        player_ptr->stat_max[i] = player_ptr->stat_max_max[i];
+    }
+
+    for (auto tval : TV_WEAPON_RANGE) {
+        for (auto &exp : player_ptr->weapon_exp[tval]) {
+            exp = PlayerSkill::weapon_exp_at(PlayerSkillRank::MASTER);
+        }
+    }
+    PlayerSkill(player_ptr).limit_weapon_skills_by_max_value();
+
+    for (auto &[type, exp] : player_ptr->skill_exp) {
+        exp = class_skills_info[enum2i(player_ptr->pclass)].s_max[type];
+    }
+
+    const std::span spells_exp_span(player_ptr->spell_exp);
+    for (auto &exp : spells_exp_span.first(32)) {
+        exp = PlayerSkill::spell_exp_at(PlayerSkillRank::MASTER);
+    }
+    for (auto &exp : spells_exp_span.last(32)) {
+        exp = PlayerSkill::spell_exp_at(PlayerSkillRank::EXPERT);
+    }
+
+    player_ptr->au = 999999999;
+
+    if (PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
+        return;
+    }
+
+    player_ptr->max_exp = 99999999;
+    player_ptr->exp = 99999999;
+    player_ptr->exp_frac = 0;
+}
+
 /*!
  * @brief プレイヤーの現能力値を調整する / Change various "permanent" player variables.
  * @param player_ptr プレイヤーへの参照ポインタ
  */
 void wiz_change_status(PlayerType *player_ptr)
 {
-    int tmp_int;
-    char tmp_val[160];
-    char ppp[80];
+    const auto finalizer = util::make_finalizer([player_ptr]() {
+        check_experience(player_ptr);
+        do_cmd_redraw(player_ptr);
+    });
+
+    constexpr auto msg = _("全てのステータスを最大にしますか?", "Maximize all statuses? ");
+    if (input_check_strict(player_ptr, msg, { UserCheck::NO_ESCAPE, UserCheck::NO_HISTORY })) {
+        wiz_change_status_max(player_ptr);
+        return;
+    }
+
     for (int i = 0; i < A_MAX; i++) {
-        strnfmt(ppp, sizeof(ppp), "%s (3-%d): ", stat_names[i], player_ptr->stat_max_max[i]);
-        strnfmt(tmp_val, sizeof(tmp_val), "%d", player_ptr->stat_max[i]);
-        if (!get_string(ppp, tmp_val, 3)) {
+        const auto max_max_ability_score = player_ptr->stat_max_max[i];
+        const auto max_ability_score = player_ptr->stat_max[i];
+        const auto new_ability_score = input_numerics(stat_names[i], 3, max_max_ability_score, max_ability_score);
+        if (!new_ability_score) {
             return;
         }
 
-        tmp_int = atoi(tmp_val);
-        if (tmp_int > player_ptr->stat_max_max[i]) {
-            tmp_int = player_ptr->stat_max_max[i];
-        } else if (tmp_int < 3) {
-            tmp_int = 3;
-        }
-
-        player_ptr->stat_cur[i] = player_ptr->stat_max[i] = (BASE_STATUS)tmp_int;
+        player_ptr->stat_cur[i] = *new_ability_score;
+        player_ptr->stat_max[i] = *new_ability_score;
     }
 
-    strnfmt(tmp_val, sizeof(tmp_val), "%d", PlayerSkill::weapon_exp_at(PlayerSkillRank::MASTER));
-    if (!get_string(_("熟練度: ", "Proficiency: "), tmp_val, 4)) {
+    const auto unskilled = PlayerSkill::weapon_exp_at(PlayerSkillRank::UNSKILLED);
+    const auto master = PlayerSkill::weapon_exp_at(PlayerSkillRank::MASTER);
+    const auto proficiency = input_numerics(_("熟練度", "Proficiency"), unskilled, master, static_cast<short>(master));
+    if (!proficiency) {
         return;
     }
 
-    auto tmp_s16b = std::clamp(static_cast<SUB_EXP>(atoi(tmp_val)),
-        PlayerSkill::weapon_exp_at(PlayerSkillRank::UNSKILLED),
-        PlayerSkill::weapon_exp_at(PlayerSkillRank::MASTER));
-
     for (auto tval : TV_WEAPON_RANGE) {
         for (int i = 0; i < 64; i++) {
-            player_ptr->weapon_exp[tval][i] = tmp_s16b;
+            player_ptr->weapon_exp[tval][i] = *proficiency;
         }
     }
-    PlayerSkill(player_ptr).limit_weapon_skills_by_max_value();
 
+    PlayerSkill(player_ptr).limit_weapon_skills_by_max_value();
     for (auto j : PLAYER_SKILL_KIND_TYPE_RANGE) {
-        player_ptr->skill_exp[j] = tmp_s16b;
+        player_ptr->skill_exp[j] = *proficiency;
         auto short_pclass = enum2i(player_ptr->pclass);
         if (player_ptr->skill_exp[j] > class_skills_info[short_pclass].s_max[j]) {
             player_ptr->skill_exp[j] = class_skills_info[short_pclass].s_max[j];
@@ -448,42 +446,31 @@ void wiz_change_status(PlayerType *player_ptr)
 
     int k;
     for (k = 0; k < 32; k++) {
-        player_ptr->spell_exp[k] = std::min(PlayerSkill::spell_exp_at(PlayerSkillRank::MASTER), tmp_s16b);
+        player_ptr->spell_exp[k] = std::min(PlayerSkill::spell_exp_at(PlayerSkillRank::MASTER), *proficiency);
     }
 
     for (; k < 64; k++) {
-        player_ptr->spell_exp[k] = std::min(PlayerSkill::spell_exp_at(PlayerSkillRank::EXPERT), tmp_s16b);
+        player_ptr->spell_exp[k] = std::min(PlayerSkill::spell_exp_at(PlayerSkillRank::EXPERT), *proficiency);
     }
 
-    strnfmt(tmp_val, sizeof(tmp_val), "%ld", (long)(player_ptr->au));
-    if (!get_string("Gold: ", tmp_val, 9)) {
+    const auto gold = input_numerics("Gold: ", 0, MAX_INT, player_ptr->au);
+    if (!gold) {
         return;
     }
 
-    long tmp_long = atol(tmp_val);
-    if (tmp_long < 0) {
-        tmp_long = 0L;
-    }
-
-    player_ptr->au = tmp_long;
-    strnfmt(tmp_val, sizeof(tmp_val), "%ld", (long)(player_ptr->max_exp));
-    if (!get_string("Experience: ", tmp_val, 9)) {
+    player_ptr->au = *gold;
+    if (PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
         return;
     }
 
-    tmp_long = atol(tmp_val);
-    if (tmp_long < 0) {
-        tmp_long = 0L;
-    }
-
-    if (PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
+    const auto experience = input_numerics("Experience: ", 0, MAX_INT, player_ptr->max_exp);
+    if (!experience) {
         return;
     }
 
-    player_ptr->max_exp = tmp_long;
-    player_ptr->exp = tmp_long;
-    check_experience(player_ptr);
-    do_cmd_redraw(player_ptr);
+    player_ptr->max_exp = *experience;
+    player_ptr->exp = *experience;
+    player_ptr->exp_frac = 0;
 }
 
 /*!
@@ -493,39 +480,36 @@ void wiz_change_status(PlayerType *player_ptr)
  */
 void wiz_create_feature(PlayerType *player_ptr)
 {
-    int f_val1, f_val2;
     POSITION y, x;
     if (!tgt_pt(player_ptr, &x, &y)) {
         return;
     }
 
-    grid_type *g_ptr;
-    g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-
-    f_val1 = g_ptr->feat;
-    if (!get_value(_("実地形ID", "FeatureID"), 0, terrains_info.size() - 1, &f_val1)) {
+    const Pos2D pos(y, x);
+    auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const int max = TerrainList::get_instance().size() - 1;
+    const auto f_val1 = input_numerics(_("実地形ID", "FeatureID"), 0, max, grid.feat);
+    if (!f_val1) {
         return;
     }
 
-    f_val2 = f_val1;
-    if (!get_value(_("偽装地形ID", "FeatureID"), 0, terrains_info.size() - 1, &f_val2)) {
+    const auto f_val2 = input_numerics(_("偽装地形ID", "FeatureID"), 0, max, *f_val1);
+    if (!f_val2) {
         return;
     }
 
-    cave_set_feat(player_ptr, y, x, static_cast<FEAT_IDX>(f_val1));
-    g_ptr->mimic = (int16_t)f_val2;
-    TerrainType *f_ptr;
-    f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
-
-    if (f_ptr->flags.has(TerrainCharacteristics::RUNE_PROTECTION) || f_ptr->flags.has(TerrainCharacteristics::RUNE_EXPLOSION)) {
-        g_ptr->info |= CAVE_OBJECT;
-    } else if (f_ptr->flags.has(TerrainCharacteristics::MIRROR)) {
-        g_ptr->info |= CAVE_GLOW | CAVE_OBJECT;
+    cave_set_feat(player_ptr, y, x, *f_val1);
+    grid.mimic = *f_val2;
+    const auto &terrain = grid.get_terrain_mimic();
+    if (terrain.flags.has(TerrainCharacteristics::RUNE_PROTECTION) || terrain.flags.has(TerrainCharacteristics::RUNE_EXPLOSION)) {
+        grid.info |= CAVE_OBJECT;
+    } else if (terrain.flags.has(TerrainCharacteristics::MIRROR)) {
+        grid.info |= CAVE_GLOW | CAVE_OBJECT;
     }
 
     note_spot(player_ptr, y, x);
     lite_spot(player_ptr, y, x);
-    player_ptr->update |= PU_FLOW;
+    RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::FLOW);
 }
 
 /*!
@@ -533,73 +517,33 @@ void wiz_create_feature(PlayerType *player_ptr)
  * @param player_ptr プレイヤーへの参照ポインタ
  * @details 範囲外の値が選択されたら再入力を促す
  */
-static bool select_debugging_dungeon(PlayerType *player_ptr, DUNGEON_IDX *dungeon_type)
+static std::optional<short> select_debugging_dungeon(short initial_dungeon_id)
 {
     if (command_arg > 0) {
-        return true;
+        return static_cast<short>(std::clamp(static_cast<int>(command_arg), DUNGEON_ANGBAND, DUNGEON_DARKNESS));
     }
 
-    while (true) {
-        char tmp_val[160];
-        strnfmt(tmp_val, sizeof(tmp_val), "%d", player_ptr->dungeon_idx);
-        if (!get_string("Jump which dungeon : ", tmp_val, 2)) {
-            return false;
-        }
-
-        *dungeon_type = (DUNGEON_IDX)atoi(tmp_val);
-        if ((*dungeon_type < DUNGEON_ANGBAND) || (*dungeon_type > DUNGEON_MAX)) {
-            msg_print("Invalid dungeon. Please re-input.");
-            continue;
-        }
-
-        return true;
-    }
+    return input_numerics("Jump which dungeon", DUNGEON_ANGBAND, DUNGEON_DARKNESS, initial_dungeon_id);
 }
 
 /*
- * @brief é\81¸æ\8a\9eã\81\97ã\81\9fã\83\80ã\83³ã\82¸ã\83§ã\83³ã\81®ä»»æ\84\8fã\83\95ã\83­ã\82¢を選択する
+ * @brief é\81¸æ\8a\9eã\81\97ã\81\9fã\83\80ã\83³ã\82¸ã\83§ã\83³ã\81®ä»»æ\84\8fã\83¬ã\83\99ã\83«を選択する
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param dungeon_type ダンジョン番号
- * @return フロアを選択したらtrue、キャンセルならfalse
- * @details 0を指定すると地上に飛ぶが、元いた場所にしか飛ばない
- * @todo 可能ならダンジョンの入口 (例:ルルイエなら大洋の真ん中)へ飛べるようにしたい
+ * @param dungeon_id ダンジョン番号
+ * @return レベルを選択したらその値、キャンセルならnullopt
  */
-static bool select_debugging_floor(PlayerType *player_ptr, int dungeon_type)
+static std::optional<int> select_debugging_floor(const FloorType &floor, int dungeon_id)
 {
-    auto max_depth = dungeons_info[dungeon_type].maxdepth;
-    if ((max_depth == 0) || (dungeon_type > static_cast<int>(dungeons_info.size()))) {
-        dungeon_type = DUNGEON_ANGBAND;
-    }
-
-    auto min_depth = (int)dungeons_info[dungeon_type].mindepth;
-    while (true) {
-        char ppp[80];
-        char tmp_val[160];
-        strnfmt(ppp, sizeof(ppp), "Jump to level (0, %d-%d): ", min_depth, max_depth);
-        strnfmt(tmp_val, sizeof(tmp_val), "%d", (int)player_ptr->current_floor_ptr->dun_level);
-        if (!get_string(ppp, tmp_val, 10)) {
-            return false;
-        }
-
-        auto tmp_command_arg = (COMMAND_ARG)atoi(tmp_val);
-        if (tmp_command_arg == 0) {
-            command_arg = tmp_command_arg;
-            break;
-        }
-
-        auto is_valid_floor = tmp_command_arg > 0;
-        is_valid_floor &= tmp_command_arg >= min_depth;
-        is_valid_floor &= tmp_command_arg <= max_depth;
-        if (is_valid_floor) {
-            command_arg = tmp_command_arg;
-            break;
-        }
-
-        msg_print("Invalid floor. Please re-input.");
-        continue;
+    const auto &dungeon = dungeons_info[dungeon_id];
+    const auto max_depth = dungeon.maxdepth;
+    const auto min_depth = dungeon.mindepth;
+    const auto is_current_dungeon = floor.dungeon_idx == dungeon_id;
+    auto initial_depth = floor.dun_level;
+    if (!is_current_dungeon) {
+        initial_depth = min_depth;
     }
 
-    return true;
+    return input_numerics("Jump to level", min_depth, max_depth, initial_depth);
 }
 
 /*!
@@ -608,22 +552,23 @@ static bool select_debugging_floor(PlayerType *player_ptr, int dungeon_type)
  */
 static void wiz_jump_floor(PlayerType *player_ptr, DUNGEON_IDX dun_idx, DEPTH depth)
 {
-    player_ptr->dungeon_idx = dun_idx;
-    auto &floor_ref = *player_ptr->current_floor_ptr;
-    floor_ref.dun_level = depth;
+    auto &floor = *player_ptr->current_floor_ptr;
+    floor.set_dungeon_index(dun_idx);
+    floor.dun_level = depth;
     prepare_change_floor_mode(player_ptr, CFM_RAND_PLACE);
-    if (!floor_ref.is_in_dungeon()) {
-        player_ptr->dungeon_idx = 0;
+    if (!floor.is_in_dungeon()) {
+        floor.reset_dungeon_index();
     }
 
-    floor_ref.inside_arena = false;
+    floor.inside_arena = false;
     player_ptr->wild_mode = false;
     leave_quest_check(player_ptr);
-    if (record_stair) {
-        exe_write_diary(player_ptr, DIARY_WIZ_TELE, 0, nullptr);
-    }
-
-    floor_ref.quest_number = QuestId::NONE;
+    auto to = !floor.is_in_dungeon()
+                  ? _("地上", "the surface")
+                  : format(_("%d階(%s)", "level %d of %s"), floor.dun_level, floor.get_dungeon_definition().name.data());
+    constexpr auto mes = _("%sへとウィザード・テレポートで移動した。\n", "You wizard-teleported to %s.\n");
+    msg_print_wizard(player_ptr, 2, format(mes, to.data()));
+    floor.quest_number = QuestId::NONE;
     PlayerEnergy(player_ptr).reset_player_turn();
     player_ptr->energy_need = 0;
     prepare_change_floor_mode(player_ptr, CFM_FIRST_FLOOR);
@@ -636,34 +581,37 @@ static void wiz_jump_floor(PlayerType *player_ptr, DUNGEON_IDX dun_idx, DEPTH de
  */
 void wiz_jump_to_dungeon(PlayerType *player_ptr)
 {
-    DUNGEON_IDX dungeon_type = 1;
-    if (!select_debugging_dungeon(player_ptr, &dungeon_type)) {
-        return;
-    }
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto is_in_dungeon = floor.is_in_dungeon();
+    const auto dungeon_idx = is_in_dungeon ? floor.dungeon_idx : static_cast<short>(DUNGEON_ANGBAND);
+    const auto dungeon_id = select_debugging_dungeon(dungeon_idx);
+    if (!dungeon_id) {
+        if (!is_in_dungeon) {
+            return;
+        }
 
-    if (!select_debugging_floor(player_ptr, dungeon_type)) {
-        return;
-    }
+        if (input_check(("Jump to the ground?"))) {
+            wiz_jump_floor(player_ptr, 0, 0);
+        }
 
-    if (command_arg < dungeons_info[dungeon_type].mindepth) {
-        command_arg = 0;
+        return;
     }
 
-    if (command_arg > dungeons_info[dungeon_type].maxdepth) {
-        command_arg = (COMMAND_ARG)dungeons_info[dungeon_type].maxdepth;
+    const auto level = select_debugging_floor(floor, *dungeon_id);
+    if (!level) {
+        return;
     }
 
-    msg_format("You jump to dungeon level %d.", command_arg);
+    msg_format("You jump to dungeon level %d.", *level);
     if (autosave_l) {
         do_cmd_save_game(player_ptr, true);
     }
 
-    wiz_jump_floor(player_ptr, dungeon_type, command_arg);
+    wiz_jump_floor(player_ptr, *dungeon_id, *level);
 }
 
 /*!
- * @brief 全ベースアイテムを鑑定済みにする /
- * Become aware of a lot of objects
+ * @brief 全ベースアイテムを鑑定済みにする
  * @param player_ptr プレイヤーへの参照ポインタ
  */
 void wiz_learn_items_all(PlayerType *player_ptr)
@@ -679,22 +627,39 @@ void wiz_learn_items_all(PlayerType *player_ptr)
     }
 }
 
+static void change_birth_flags()
+{
+    auto &rfu = RedrawingFlagsUpdater::get_instance();
+    static constexpr auto flags_srf = {
+        StatusRecalculatingFlag::BONUS,
+        StatusRecalculatingFlag::HP,
+        StatusRecalculatingFlag::MP,
+        StatusRecalculatingFlag::SPELLS,
+    };
+    rfu.set_flag(SubWindowRedrawingFlag::PLAYER);
+    rfu.set_flags(flags_srf);
+    static constexpr auto flags_mwrf = {
+        MainWindowRedrawingFlag::BASIC,
+        MainWindowRedrawingFlag::HP,
+        MainWindowRedrawingFlag::MP,
+        MainWindowRedrawingFlag::ABILITY_SCORE,
+    };
+    rfu.set_flags(flags_mwrf);
+}
+
 /*!
  * @brief プレイヤーの種族を変更する
  */
 void wiz_reset_race(PlayerType *player_ptr)
 {
-    int val = enum2i<PlayerRaceType>(player_ptr->prace);
-    if (!get_value("RaceID", 0, MAX_RACES - 1, &val)) {
+    const auto new_race = input_numerics("RaceID", 0, MAX_RACES - 1, player_ptr->prace);
+    if (!new_race) {
         return;
     }
 
-    player_ptr->prace = i2enum<PlayerRaceType>(val);
+    player_ptr->prace = *new_race;
     rp_ptr = &race_info[enum2i(player_ptr->prace)];
-
-    player_ptr->window_flags |= PW_PLAYER;
-    player_ptr->update |= PU_BONUS | PU_HP | PU_MP | PU_SPELLS;
-    player_ptr->redraw |= PR_BASIC | PR_HP | PR_MP | PR_ABILITY_SCORE;
+    change_birth_flags();
     handle_stuff(player_ptr);
 }
 
@@ -704,18 +669,18 @@ void wiz_reset_race(PlayerType *player_ptr)
  */
 void wiz_reset_class(PlayerType *player_ptr)
 {
-    int val = enum2i<PlayerClassType>(player_ptr->pclass);
-    if (!get_value("ClassID", 0, PLAYER_CLASS_TYPE_MAX - 1, &val)) {
+    const auto new_class_opt = input_numerics("ClassID", 0, PLAYER_CLASS_TYPE_MAX - 1, player_ptr->pclass);
+    if (!new_class_opt) {
         return;
     }
 
-    player_ptr->pclass = i2enum<PlayerClassType>(val);
-    cp_ptr = &class_info[val];
-    mp_ptr = &class_magics_info[val];
+    const auto new_class_enum = *new_class_opt;
+    const auto new_class = enum2i(new_class_enum);
+    player_ptr->pclass = new_class_enum;
+    cp_ptr = &class_info[new_class];
+    mp_ptr = &class_magics_info[new_class];
     PlayerClass(player_ptr).init_specific_data();
-    player_ptr->window_flags |= PW_PLAYER;
-    player_ptr->update |= PU_BONUS | PU_HP | PU_MP | PU_SPELLS;
-    player_ptr->redraw |= PR_BASIC | PR_HP | PR_MP | PR_ABILITY_SCORE;
+    change_birth_flags();
     handle_stuff(player_ptr);
 }
 
@@ -725,21 +690,19 @@ void wiz_reset_class(PlayerType *player_ptr)
  */
 void wiz_reset_realms(PlayerType *player_ptr)
 {
-    int val1 = player_ptr->realm1;
-    if (!get_value("1st Realm (None=0)", 0, MAX_REALM - 1, &val1)) {
+    const auto new_realm1 = input_numerics("1st Realm (None=0)", 0, MAX_REALM - 1, player_ptr->realm1);
+    if (!new_realm1) {
         return;
     }
 
-    int val2 = player_ptr->realm2;
-    if (!get_value("2nd Realm (None=0)", 0, MAX_REALM - 1, &val2)) {
+    const auto new_realm2 = input_numerics("2nd Realm (None=0)", 0, MAX_REALM - 1, player_ptr->realm2);
+    if (!new_realm2) {
         return;
     }
 
-    player_ptr->realm1 = static_cast<int16_t>(val1);
-    player_ptr->realm2 = static_cast<int16_t>(val2);
-    player_ptr->window_flags |= PW_PLAYER;
-    player_ptr->update |= PU_BONUS | PU_HP | PU_MP | PU_SPELLS;
-    player_ptr->redraw |= PR_BASIC;
+    player_ptr->realm1 = *new_realm1;
+    player_ptr->realm2 = *new_realm2;
+    change_birth_flags();
     handle_stuff(player_ptr);
 }
 
@@ -750,11 +713,11 @@ void wiz_reset_realms(PlayerType *player_ptr)
  */
 void wiz_dump_options(void)
 {
-    char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "opt_info.txt");
-    auto *fff = angband_fopen(buf, FileOpenMode::APPEND);
+    const auto &path = path_build(ANGBAND_DIR_USER, "opt_info.txt");
+    const auto &filename = path.string();
+    auto *fff = angband_fopen(path, FileOpenMode::APPEND);
     if (fff == nullptr) {
-        msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), buf);
+        msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), filename.data());
         msg_print(nullptr);
         return;
     }
@@ -785,7 +748,7 @@ void wiz_dump_options(void)
     }
 
     angband_fclose(fff);
-    msg_format(_("オプションbit使用状況をファイル %s に書き出しました。", "Option bits usage dump saved to file %s."), buf);
+    msg_format(_("オプションbit使用状況をファイル %s に書き出しました。", "Option bits usage dump saved to file %s."), filename.data());
 }
 
 /*!
@@ -794,12 +757,12 @@ void wiz_dump_options(void)
  */
 void set_gametime(void)
 {
-    int game_time = 0;
-    if (!get_value("Dungeon Turn", 0, w_ptr->dungeon_turn_limit - 1, &game_time)) {
+    const auto game_time = input_integer("Dungeon Turn", 0, w_ptr->dungeon_turn_limit - 1);
+    if (!game_time) {
         return;
     }
 
-    w_ptr->dungeon_turn = w_ptr->game_turn = game_time;
+    w_ptr->dungeon_turn = w_ptr->game_turn = *game_time;
 }
 
 /*!
@@ -815,7 +778,7 @@ void wiz_zap_surrounding_monsters(PlayerType *player_ptr)
 
         if (record_named_pet && m_ptr->is_named_pet()) {
             const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-            exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_WIZ_ZAP, m_name.data());
+            exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_WIZ_ZAP, m_name);
         }
 
         delete_monster_idx(player_ptr, i);
@@ -836,7 +799,7 @@ void wiz_zap_floor_monsters(PlayerType *player_ptr)
 
         if (record_named_pet && m_ptr->is_named_pet()) {
             const auto m_name = monster_desc(player_ptr, m_ptr, MD_INDEF_VISIBLE);
-            exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_WIZ_ZAP, m_name.data());
+            exe_write_diary(player_ptr, DiaryKind::NAMED_PET, RECORD_NAMED_PET_WIZ_ZAP, m_name);
         }
 
         delete_monster_idx(player_ptr, i);
@@ -866,13 +829,14 @@ void cheat_death(PlayerType *player_ptr)
     auto *floor_ptr = player_ptr->current_floor_ptr;
     floor_ptr->dun_level = 0;
     floor_ptr->inside_arena = false;
-    player_ptr->phase_out = false;
+    AngbandSystem::get_instance().set_phase_out(false);
     leaving_quest = QuestId::NONE;
     floor_ptr->quest_number = QuestId::NONE;
-    if (player_ptr->dungeon_idx) {
-        player_ptr->recall_dungeon = player_ptr->dungeon_idx;
+    if (floor_ptr->dungeon_idx) {
+        player_ptr->recall_dungeon = floor_ptr->dungeon_idx;
     }
-    player_ptr->dungeon_idx = 0;
+
+    floor_ptr->reset_dungeon_index();
     if (lite_town || vanilla_town) {
         player_ptr->wilderness_y = 1;
         player_ptr->wilderness_x = 1;
@@ -892,7 +856,7 @@ void cheat_death(PlayerType *player_ptr)
 
     player_ptr->wild_mode = false;
     player_ptr->leaving = true;
-
-    exe_write_diary(player_ptr, DIARY_DESCRIPTION, 1, _("                            しかし、生き返った。", "                            but revived."));
+    constexpr auto note = _("                            しかし、生き返った。", "                            but revived.");
+    exe_write_diary(player_ptr, DiaryKind::DESCRIPTION, 1, note);
     leave_floor(player_ptr);
 }
index 41d2ae3..b6f056b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index 4a1819d..ac9c95e 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief ウィザードモード専用のスペル処理
  * @date 2020/06/27
  * @author Hourier
@@ -19,6 +19,7 @@
 #include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-ability-flags.h"
+#include "monster-race/race-indice-types.h"
 #include "mutation/mutation-processor.h"
 #include "object-activation/activation-others.h"
 #include "player-base/player-class.h"
@@ -41,6 +42,7 @@
 #include "util/enum-converter.h"
 #include "util/flag-group.h"
 #include "view/display-messages.h"
+#include "wizard/wizard-messages.h"
 #include <string_view>
 #include <vector>
 
@@ -55,51 +57,46 @@ static const std::vector<debug_spell_command> debug_spell_commands_list = {
 
 /*!
  * @brief コマンド入力により任意にスペル効果を起こす / Wizard spells
- * @return 実際にテレポートを行ったらTRUEを返す
+ * @param player_ptr プレイヤーへの参照ポインタ
  */
-bool wiz_debug_spell(PlayerType *player_ptr)
+void wiz_debug_spell(PlayerType *player_ptr)
 {
-    char tmp_val[50] = "\0";
-    int tmp_int;
-
-    if (!get_string("SPELL: ", tmp_val, 32)) {
-        return false;
+    const auto spell = input_string("SPELL: ", 50);
+    if (!spell) {
+        return;
     }
 
     for (const auto &d : debug_spell_commands_list) {
-        if (strcmp(tmp_val, d.command_name) != 0) {
+        if (*spell != d.command_name) {
             continue;
         }
 
         switch (d.type) {
         case 2:
             (d.command_function.spell2.spell_function)(player_ptr);
-            return true;
-            break;
-        case 3:
-            tmp_val[0] = '\0';
-            if (!get_string("POWER:", tmp_val, 32)) {
-                return false;
+            return;
+        case 3: {
+            const auto power = input_integer("POWER", -MAX_INT, MAX_INT);
+            if (!power) {
+                return;
             }
-            tmp_int = atoi(tmp_val);
-            (d.command_function.spell3.spell_function)(player_ptr, tmp_int);
-            return true;
-            break;
-        case 4:
-            (d.command_function.spell4.spell_function)(player_ptr, true, &tmp_int);
-            return true;
-            break;
+
+            (d.command_function.spell3.spell_function)(player_ptr, *power);
+            return;
+        }
+        case 4: {
+            auto count = 0;
+            (d.command_function.spell4.spell_function)(player_ptr, true, &count);
+            return;
+        }
         case 5:
             (d.command_function.spell5.spell_function)(player_ptr);
-            return true;
-            break;
+            return;
         default:
-            break;
+            msg_format("Command not found.");
+            return;
         }
     }
-
-    msg_format("Command not found.");
-    return false;
 }
 
 /*!
@@ -181,15 +178,39 @@ void wiz_fillup_all_smith_essences(PlayerType *player_ptr)
 }
 
 /*!
- * @brief 現在のフロアに合ったモンスターをランダムに召喚する /
- * Summon some creatures
+ * @brief 現在のフロアに合ったモンスターをランダムに生成する
  * @param player_ptr プレイヤーへの参照ポインタ
  * @param num 生成処理回数
+ * @details 半径5マス以内に生成する。生成場所がなかったらキャンセル。
  */
-void wiz_summon_random_enemy(PlayerType *player_ptr, int num)
+void wiz_generate_random_monster(PlayerType *player_ptr, int num)
 {
-    for (int i = 0; i < num; i++) {
-        (void)summon_specific(player_ptr, 0, player_ptr->y, player_ptr->x, player_ptr->current_floor_ptr->dun_level, SUMMON_NONE, PM_ALLOW_GROUP | PM_ALLOW_UNIQUE);
+    constexpr auto flags = PM_ALLOW_SLEEP | PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_QUEST;
+    for (auto i = 0; i < num; i++) {
+        if (!alloc_monster(player_ptr, 0, flags, summon_specific, 5)) {
+            msg_print_wizard(player_ptr, 1, "Monster isn't generated correctly...");
+            return;
+        }
+    }
+}
+
+/*!
+ * @brief 現在のフロアに合ったモンスターをランダムに召喚する
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @param num 生成処理回数
+ * @details 現在のレベル+5F からランダムに選定する。生成場所がなかったらキャンセル。
+ */
+void wiz_summon_random_monster(PlayerType *player_ptr, int num)
+{
+    const auto level = player_ptr->current_floor_ptr->dun_level;
+    constexpr auto flags = PM_ALLOW_GROUP | PM_ALLOW_UNIQUE;
+    const auto y = player_ptr->y;
+    const auto x = player_ptr->x;
+    for (auto i = 0; i < num; i++) {
+        if (!summon_specific(player_ptr, 0, y, x, level, SUMMON_NONE, flags)) {
+            msg_print_wizard(player_ptr, 1, "Monster isn't summoned correctly...");
+            return;
+        }
     }
 }
 
@@ -200,15 +221,17 @@ void wiz_summon_random_enemy(PlayerType *player_ptr, int num)
  * @details
  * This function is rather dangerous
  */
-void wiz_summon_specific_enemy(PlayerType *player_ptr, MonsterRaceId r_idx)
+void wiz_summon_specific_monster(PlayerType *player_ptr, MonsterRaceId r_idx)
 {
     if (!MonsterRace(r_idx).is_valid()) {
-        int val = 1;
-        if (!get_value("MonsterID", 1, monraces_info.size() - 1, &val)) {
+        const auto new_monrace_id = input_numerics("MonsterID", 1, monraces_info.size() - 1, MonsterRaceId::FILTHY_URCHIN);
+        if (!new_monrace_id) {
             return;
         }
-        r_idx = static_cast<MonsterRaceId>(val);
+
+        r_idx = *new_monrace_id;
     }
+
     (void)summon_named_creature(player_ptr, 0, player_ptr->y, player_ptr->x, r_idx, PM_ALLOW_SLEEP | PM_ALLOW_GROUP);
 }
 
@@ -222,12 +245,14 @@ void wiz_summon_specific_enemy(PlayerType *player_ptr, MonsterRaceId r_idx)
 void wiz_summon_pet(PlayerType *player_ptr, MonsterRaceId r_idx)
 {
     if (!MonsterRace(r_idx).is_valid()) {
-        int val = 1;
-        if (!get_value("MonsterID", 1, monraces_info.size() - 1, &val)) {
+        const auto new_monrace_id = input_numerics("MonsterID", 1, monraces_info.size() - 1, MonsterRaceId::FILTHY_URCHIN);
+        if (!new_monrace_id) {
             return;
         }
-        r_idx = static_cast<MonsterRaceId>(val);
+
+        r_idx = *new_monrace_id;
     }
+
     (void)summon_named_creature(player_ptr, 0, player_ptr->y, player_ptr->x, r_idx, PM_ALLOW_SLEEP | PM_ALLOW_GROUP | PM_FORCE_PET);
 }
 
@@ -238,19 +263,21 @@ void wiz_summon_pet(PlayerType *player_ptr, MonsterRaceId r_idx)
  * @param self 自分に与えるか否か
  * @details デフォルトは100万・GF_ARROW(射撃)。RES_ALL持ちも一撃で殺せる。
  */
-void wiz_kill_target(PlayerType *player_ptr, int dam, AttributeType effect_idx, const bool self)
+void wiz_kill_target(PlayerType *player_ptr, int initial_dam, AttributeType effect_idx, const bool self)
 {
+    auto dam = initial_dam;
     if (dam <= 0) {
-        dam = 1000000;
-        if (!get_value("Damage", 1, 1000000, &dam)) {
+        const auto input_dam = input_integer("Damage", 1, 1000000, 1000000);
+        if (!input_dam) {
             return;
         }
+
+        dam = *input_dam;
     }
 
     constexpr auto max = enum2i(AttributeType::MAX);
-    auto idx = enum2i(effect_idx);
-
-    if (idx <= 0) {
+    auto idx = effect_idx;
+    if (effect_idx == AttributeType::NONE) {
         screen_save();
         for (auto i = 1; i <= 23; i++) {
             prt("", i, 0);
@@ -263,23 +290,24 @@ void wiz_kill_target(PlayerType *player_ptr, int dam, AttributeType effect_idx,
             put_str(format("%03d:%-.10s^", num, name.data()), 1 + i / 5, 1 + (i % 5) * 16);
         }
 
-        if (!get_value("EffectID", 1, max - 1, &idx)) {
+        const auto input_effect_id = input_numerics("EffectID", 1, max - 1, idx);
+        if (!input_effect_id) {
             screen_load();
             return;
         }
 
+        idx = *input_effect_id;
         screen_load();
     }
 
     if (self) {
-        project(player_ptr, -1, 0, player_ptr->y, player_ptr->x, dam, i2enum<AttributeType>(idx), PROJECT_KILL | PROJECT_PLAYER);
+        project(player_ptr, -1, 0, player_ptr->y, player_ptr->x, dam, idx, PROJECT_KILL | PROJECT_PLAYER);
         return;
     }
 
-    effect_idx = i2enum<AttributeType>(idx);
     DIRECTION dir;
     if (!get_aim_dir(player_ptr, &dir)) {
         return;
     }
-    fire_ball(player_ptr, effect_idx, dir, dam, 0);
+    fire_ball(player_ptr, idx, dir, dam, 0);
 }
index 0371595..cfe5513 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "effect/attribute-types.h"
 #include "system/angband.h"
@@ -36,13 +36,14 @@ struct debug_spell_command {
     spell_functions command_function;
 };
 
-bool wiz_debug_spell(PlayerType *player_ptr);
+void wiz_debug_spell(PlayerType *player_ptr);
 void wiz_dimension_door(PlayerType *player_ptr);
 void wiz_summon_horde(PlayerType *player_ptr);
 void wiz_teleport_back(PlayerType *player_ptr);
 void wiz_learn_blue_magic_all(PlayerType *player_ptr);
 void wiz_fillup_all_smith_essences(PlayerType *player_ptr);
-void wiz_summon_random_enemy(PlayerType *player_ptr, int num);
-void wiz_summon_specific_enemy(PlayerType *player_ptr, MonsterRaceId r_idx);
+void wiz_generate_random_monster(PlayerType *player_ptr, int num);
+void wiz_summon_random_monster(PlayerType *player_ptr, int num);
+void wiz_summon_specific_monster(PlayerType *player_ptr, MonsterRaceId r_idx);
 void wiz_summon_pet(PlayerType *player_ptr, MonsterRaceId r_idx);
-void wiz_kill_target(PlayerType *player_ptr, int dam = 1000000, AttributeType effect_idx = AttributeType::DEBUG, const bool self = false);
+void wiz_kill_target(PlayerType *player_ptr, int initial_dam = 1000000, AttributeType effect_idx = AttributeType::DEBUG, const bool self = false);
index 6c06ac0..11c81aa 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief スポイラー出力処理 (行数の都合でモンスター進化ツリーもここに入っている)
  * @date 2014/02/17
  * @author
@@ -47,6 +47,7 @@
 #include <set>
 #include <sstream>
 #include <string>
+#include <string_view>
 
 static constexpr std::array<std::string_view, 6> wiz_spell_stat = { {
     _("腕力", "STR"),
@@ -62,7 +63,7 @@ static constexpr std::array<std::string_view, 6> wiz_spell_stat = { {
  *
  * @return 進化ツリーの一番根元となるモンスターのIDのリスト(std::setで、evol_root_sortによりソートされている)
  */
-static auto get_mon_evol_roots(void)
+static auto get_mon_evol_roots()
 {
     std::set<MonsterRaceId> evol_parents;
     std::set<MonsterRaceId> evol_children;
@@ -93,15 +94,14 @@ static auto get_mon_evol_roots(void)
 }
 
 /*!
- * @brief 進化ツリーをスポイラー出力するメインルーチン /
- * Print monsters' evolution information to file
- * @param fname 出力ファイル名
+ * @brief 進化ツリーをスポイラー出力するメインルーチン
+ *
+ * fprintf() に'%' (壁)を渡すとフォーマット指定子扱いされるので、関数の外でフォーマットしてはいけない.
  */
-static SpoilerOutputResultType spoil_mon_evol(concptr fname)
+static SpoilerOutputResultType spoil_mon_evol()
 {
-    char buf[1024];
-    path_build(buf, sizeof buf, ANGBAND_DIR_USER, fname);
-    spoiler_file = angband_fopen(buf, FileOpenMode::WRITE);
+    const auto &path = path_build(ANGBAND_DIR_USER, "mon-evol.txt");
+    spoiler_file = angband_fopen(path, FileOpenMode::WRITE);
     if (!spoiler_file) {
         return SpoilerOutputResultType::FILE_OPEN_FAILED;
     }
@@ -112,14 +112,14 @@ static SpoilerOutputResultType spoil_mon_evol(concptr fname)
     spoil_out("------------------------------------------\n\n");
     for (auto r_idx : get_mon_evol_roots()) {
         auto r_ptr = &monraces_info[r_idx];
-        fprintf(spoiler_file, _("[%d]: %s (レベル%d, '%c')\n", "[%d]: %s (Level %d, '%c')\n"), enum2i(r_idx), r_ptr->name.data(), (int)r_ptr->level, r_ptr->d_char);
-
+        constexpr auto fmt_before = _("[%d]: %s (レベル%d, '%c')\n", "[%d]: %s (Level %d, '%c')\n");
+        fprintf(spoiler_file, fmt_before, enum2i(r_idx), r_ptr->name.data(), (int)r_ptr->level, r_ptr->d_char);
         for (auto n = 1; MonsterRace(r_ptr->next_r_idx).is_valid(); n++) {
             fprintf(spoiler_file, "%*s-(%d)-> ", n * 2, "", r_ptr->next_exp);
             fprintf(spoiler_file, "[%d]: ", enum2i(r_ptr->next_r_idx));
             r_ptr = &monraces_info[r_ptr->next_r_idx];
-
-            fprintf(spoiler_file, _("%s (レベル%d, '%c')\n", "%s (Level %d, '%c')\n"), r_ptr->name.data(), (int)r_ptr->level, r_ptr->d_char);
+            constexpr auto fmt_after = _("%s (レベル%d, '%c')\n", "%s (Level %d, '%c')\n");
+            fprintf(spoiler_file, fmt_after, r_ptr->name.data(), (int)r_ptr->level, r_ptr->d_char);
         }
 
         fputc('\n', spoiler_file);
@@ -175,11 +175,10 @@ static SpoilerOutputResultType spoil_categorized_mon_desc()
     return status;
 }
 
-static SpoilerOutputResultType spoil_player_spell(concptr fname)
+static SpoilerOutputResultType spoil_player_spell()
 {
-    char buf[1024];
-    path_build(buf, sizeof buf, ANGBAND_DIR_USER, fname);
-    spoiler_file = angband_fopen(buf, FileOpenMode::WRITE);
+    const auto &path = path_build(ANGBAND_DIR_USER, "spells.txt");
+    spoiler_file = angband_fopen(path, FileOpenMode::WRITE);
     if (!spoiler_file) {
         return SpoilerOutputResultType::FILE_OPEN_FAILED;
     }
@@ -194,20 +193,21 @@ static SpoilerOutputResultType spoil_player_spell(concptr fname)
         spoil_out(format("[[Class: %s]]\n", class_ptr->title));
 
         auto magic_ptr = &class_magics_info[c];
-        auto book_name = "なし";
+        std::string book_name = _("なし", "None");
         if (magic_ptr->spell_book != ItemKindType::NONE) {
             ItemEntity book;
             auto o_ptr = &book;
             o_ptr->prep(lookup_baseitem_id({ magic_ptr->spell_book, 0 }));
-            const auto item_name = describe_flavor(&dummy_p, o_ptr, OD_NAME_ONLY);
-            book_name = item_name.data();
-            char *s = angband_strchr(book_name, '[');
-            *s = '\0';
+            book_name = describe_flavor(&dummy_p, o_ptr, OD_NAME_ONLY);
+            auto *s = angband_strchr(book_name.data(), '[');
+            if (s != nullptr) {
+                book_name.erase(s - book_name.data());
+            }
         }
 
         constexpr auto mes = "BookType:%s Stat:%s Xtra:%x Type:%d Weight:%d\n";
         const auto &spell = wiz_spell_stat[magic_ptr->spell_stat];
-        spoil_out(format(mes, book_name, spell.data(), magic_ptr->spell_xtra, magic_ptr->spell_type, magic_ptr->spell_weight));
+        spoil_out(format(mes, book_name.data(), spell.data(), magic_ptr->spell_xtra, magic_ptr->spell_type, magic_ptr->spell_weight));
         if (magic_ptr->spell_book == ItemKindType::NONE) {
             spoil_out(_("呪文なし\n\n", "No spells.\n\n"));
             continue;
@@ -253,10 +253,10 @@ void exe_output_spoilers(void)
             screen_load();
             return;
         case '1':
-            status = spoil_obj_desc("obj-desc.txt");
+            status = spoil_obj_desc();
             break;
         case '2':
-            status = spoil_fixed_artifact("artifact.txt");
+            status = spoil_fixed_artifact();
             break;
         case '3':
             status = spoil_mon_desc("mon-desc.txt");
@@ -265,13 +265,13 @@ void exe_output_spoilers(void)
             status = spoil_categorized_mon_desc();
             break;
         case '5':
-            status = spoil_mon_info("mon-info.txt");
+            status = spoil_mon_info();
             break;
         case '6':
-            status = spoil_mon_evol("mon-evol.txt");
+            status = spoil_mon_evol();
             break;
         case '7':
-            status = spoil_player_spell("spells.txt");
+            status = spoil_player_spell();
             break;
         default:
             bell();
@@ -300,14 +300,14 @@ void exe_output_spoilers(void)
  * Create Spoiler files -BEN-
  * @return 成功時SPOILER_OUTPUT_SUCCESS / 失敗時エラー状態
  */
-SpoilerOutputResultType output_all_spoilers(void)
+SpoilerOutputResultType output_all_spoilers()
 {
-    auto status = spoil_obj_desc("obj-desc.txt");
+    auto status = spoil_obj_desc();
     if (status != SpoilerOutputResultType::SUCCESSFUL) {
         return status;
     }
 
-    status = spoil_fixed_artifact("artifact.txt");
+    status = spoil_fixed_artifact();
     if (status != SpoilerOutputResultType::SUCCESSFUL) {
         return status;
     }
@@ -322,12 +322,12 @@ SpoilerOutputResultType output_all_spoilers(void)
         return status;
     }
 
-    status = spoil_mon_info("mon-info.txt");
+    status = spoil_mon_info();
     if (status != SpoilerOutputResultType::SUCCESSFUL) {
         return status;
     }
 
-    status = spoil_mon_evol("mon-evol.txt");
+    status = spoil_mon_evol();
     if (status != SpoilerOutputResultType::SUCCESSFUL) {
         return status;
     }
index db8d56b..106afa7 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
index e1882de..561e3f6 100644 (file)
@@ -1,7 +1,6 @@
-#include "world/world-movement-processor.h"
+#include "world/world-movement-processor.h"
 #include "cmd-io/cmd-save.h"
 #include "core/disturbance.h"
-#include "core/player-redraw-types.h"
 #include "dungeon/quest.h"
 #include "floor/floor-mode-changer.h"
 #include "game-option/birth-options.h"
 #include "main/sound-of-music.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
 #include "util/enum-range.h"
 #include "view/display-messages.h"
 #include "world/world.h"
 void check_random_quest_auto_failure(PlayerType *player_ptr)
 {
     auto &quest_list = QuestList::get_instance();
-    if (player_ptr->dungeon_idx != DUNGEON_ANGBAND) {
+    const auto &floor = *player_ptr->current_floor_ptr;
+    if (floor.dungeon_idx != DUNGEON_ANGBAND) {
         return;
     }
     for (auto q_idx : EnumRange(QuestId::RANDOM_QUEST1, QuestId::RANDOM_QUEST10)) {
         auto &quest = quest_list[q_idx];
         auto is_taken_quest = (quest.type == QuestKindType::RANDOM);
         is_taken_quest &= (quest.status == QuestStatusType::TAKEN);
-        is_taken_quest &= (quest.level < player_ptr->current_floor_ptr->dun_level);
+        is_taken_quest &= (quest.level < floor.dun_level);
         if (!is_taken_quest) {
             continue;
         }
 
         quest.status = QuestStatusType::FAILED;
         quest.complev = (byte)player_ptr->lev;
-        update_playtime();
+        w_ptr->update_playtime();
         quest.comptime = w_ptr->play_time;
         monraces_info[quest.r_idx].flags1 &= ~(RF1_QUESTOR);
     }
@@ -61,54 +63,54 @@ void execute_recall(PlayerType *player_ptr)
         return;
     }
 
-    if (autosave_l && (player_ptr->word_recall == 1) && !player_ptr->phase_out) {
+    if (autosave_l && (player_ptr->word_recall == 1) && !AngbandSystem::get_instance().is_phase_out()) {
         do_cmd_save_game(player_ptr, true);
     }
 
     player_ptr->word_recall--;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (player_ptr->word_recall != 0) {
         return;
     }
 
     disturb(player_ptr, false, true);
     auto *floor_ptr = player_ptr->current_floor_ptr;
-    if (floor_ptr->dun_level || inside_quest(player_ptr->current_floor_ptr->quest_number) || player_ptr->enter_dungeon) {
+    if (floor_ptr->dun_level || floor_ptr->is_in_quest() || player_ptr->enter_dungeon) {
         msg_print(_("上に引っ張りあげられる感じがする!", "You feel yourself yanked upwards!"));
-        if (player_ptr->dungeon_idx) {
-            player_ptr->recall_dungeon = player_ptr->dungeon_idx;
+        if (floor_ptr->dungeon_idx) {
+            player_ptr->recall_dungeon = floor_ptr->dungeon_idx;
         }
         if (record_stair) {
-            exe_write_diary(player_ptr, DIARY_RECALL, floor_ptr->dun_level, nullptr);
+            exe_write_diary(player_ptr, DiaryKind::RECALL, floor_ptr->dun_level);
         }
 
         floor_ptr->dun_level = 0;
-        player_ptr->dungeon_idx = 0;
+        floor_ptr->reset_dungeon_index();
         leave_quest_check(player_ptr);
         leave_tower_check(player_ptr);
-        player_ptr->current_floor_ptr->quest_number = QuestId::NONE;
+        floor_ptr->quest_number = QuestId::NONE;
         player_ptr->leaving = true;
         sound(SOUND_TPLEVEL);
         return;
     }
 
     msg_print(_("下に引きずり降ろされる感じがする!", "You feel yourself yanked downwards!"));
-    player_ptr->dungeon_idx = player_ptr->recall_dungeon;
+    floor_ptr->set_dungeon_index(player_ptr->recall_dungeon);
     if (record_stair) {
-        exe_write_diary(player_ptr, DIARY_RECALL, floor_ptr->dun_level, nullptr);
+        exe_write_diary(player_ptr, DiaryKind::RECALL, floor_ptr->dun_level);
     }
 
-    floor_ptr->dun_level = max_dlv[player_ptr->dungeon_idx];
+    floor_ptr->dun_level = max_dlv[floor_ptr->dungeon_idx];
     if (floor_ptr->dun_level < 1) {
         floor_ptr->dun_level = 1;
     }
-    if (ironman_nightmare && !randint0(666) && (player_ptr->dungeon_idx == DUNGEON_ANGBAND)) {
+    if (ironman_nightmare && !randint0(666) && (floor_ptr->dungeon_idx == DUNGEON_ANGBAND)) {
         if (floor_ptr->dun_level < 50) {
             floor_ptr->dun_level *= 2;
         } else if (floor_ptr->dun_level < 99) {
             floor_ptr->dun_level = (floor_ptr->dun_level + 99) / 2;
         } else if (floor_ptr->dun_level > 100) {
-            floor_ptr->dun_level = dungeons_info[player_ptr->dungeon_idx].maxdepth - 1;
+            floor_ptr->dun_level = floor_ptr->get_dungeon_definition().maxdepth - 1;
         }
     }
 
@@ -140,23 +142,23 @@ void execute_recall(PlayerType *player_ptr)
  */
 void execute_floor_reset(PlayerType *player_ptr)
 {
-    auto *floor_ptr = player_ptr->current_floor_ptr;
+    const auto &floor = *player_ptr->current_floor_ptr;
     if (player_ptr->alter_reality == 0) {
         return;
     }
 
-    if (autosave_l && (player_ptr->alter_reality == 1) && !player_ptr->phase_out) {
+    if (autosave_l && (player_ptr->alter_reality == 1) && !AngbandSystem::get_instance().is_phase_out()) {
         do_cmd_save_game(player_ptr, true);
     }
 
     player_ptr->alter_reality--;
-    player_ptr->redraw |= (PR_TIMED_EFFECT);
+    RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
     if (player_ptr->alter_reality != 0) {
         return;
     }
 
     disturb(player_ptr, false, true);
-    if (!inside_quest(quest_number(player_ptr, floor_ptr->dun_level)) && floor_ptr->dun_level) {
+    if (!inside_quest(floor.get_quest_id()) && floor.dun_level) {
         msg_print(_("世界が変わった!", "The world changes!"));
 
         /*
index 9f4cb7e..177c15b 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 void check_random_quest_auto_failure(PlayerType *player_ptr);
index 528c598..34351dc 100644 (file)
@@ -1,4 +1,4 @@
-#include "world/world-object.h"
+#include "world/world-object.h"
 #include "dungeon/dungeon-flag-types.h"
 #include "object-enchant/item-apply-magic.h"
 #include "object/tval-types.h"
@@ -66,13 +66,13 @@ OBJECT_IDX o_pop(FloorType *floor_ptr)
  * Note that if no objects are "appropriate", then this function will\n
  * fail, and return zero, but this should *almost* never happen.\n
  */
-OBJECT_IDX get_obj_index(PlayerType *player_ptr, DEPTH level, BIT_FLAGS mode)
+OBJECT_IDX get_obj_index(const FloorType *floor_ptr, DEPTH level, BIT_FLAGS mode)
 {
     if (level > MAX_DEPTH - 1) {
         level = MAX_DEPTH - 1;
     }
 
-    if ((level > 0) && dungeons_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::BEGINNER)) {
+    if ((level > 0) && floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::BEGINNER)) {
         if (one_in_(CHANCE_BASEITEM_LEVEL_BOOST)) {
             level = 1 + (level * MAX_DEPTH / randint1(MAX_DEPTH));
         }
index 2f2e684..9448d29 100644 (file)
@@ -1,8 +1,7 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
 
 class FloorType;
-class PlayerType;
 OBJECT_IDX o_pop(FloorType *floor_ptr);
-OBJECT_IDX get_obj_index(PlayerType *player_ptr, DEPTH level, BIT_FLAGS mode);
+OBJECT_IDX get_obj_index(const FloorType *floor_ptr, DEPTH level, BIT_FLAGS mode);
index c92fc25..3ea111d 100644 (file)
@@ -1,8 +1,9 @@
-#include "world/world-turn-processor.h"
+#include "world/world-turn-processor.h"
 #include "cmd-building/cmd-building.h"
 #include "cmd-io/cmd-save.h"
 #include "core/disturbance.h"
 #include "core/magic-effects-timeout-reducer.h"
+#include "dungeon/quest.h"
 #include "floor/floor-events.h"
 #include "floor/floor-mode-changer.h"
 #include "floor/wild.h"
@@ -29,6 +30,7 @@
 #include "store/store-owners.h"
 #include "store/store-util.h"
 #include "store/store.h"
+#include "system/angband-system.h"
 #include "system/dungeon-info.h"
 #include "system/floor-type-definition.h"
 #include "system/grid-type-definition.h"
@@ -55,12 +57,10 @@ WorldTurnProcessor::WorldTurnProcessor(PlayerType *player_ptr)
  */
 void WorldTurnProcessor::process_world()
 {
-    const int32_t a_day = TURNS_PER_TICK * TOWN_DAWN;
-    int32_t prev_turn_in_today = ((w_ptr->game_turn - TURNS_PER_TICK) % a_day + a_day / 4) % a_day;
-    int prev_min = (1440 * prev_turn_in_today / a_day) % 60;
-
-    int dummy_day;
-    extract_day_hour_min(this->player_ptr, &dummy_day, &this->hour, &this->min);
+    const int a_day = TURNS_PER_TICK * TOWN_DAWN;
+    const int prev_turn_in_today = ((w_ptr->game_turn - TURNS_PER_TICK) % a_day + a_day / 4) % a_day;
+    const int prev_min = (1440 * prev_turn_in_today / a_day) % 60;
+    std::tie(std::ignore, this->hour, this->min) = w_ptr->extract_date_time(this->player_ptr->start_race);
     update_dungeon_feeling(this->player_ptr);
     process_downward();
     process_monster_arena();
@@ -76,9 +76,9 @@ void WorldTurnProcessor::process_world()
 
     process_change_daytime_night();
     process_world_monsters();
-    if (!this->hour && !this->min) {
+    if ((this->hour == 0) && (this->min == 0)) {
         if (this->min != prev_min) {
-            exe_write_diary(this->player_ptr, DIARY_DIALY, 0, nullptr);
+            exe_write_diary(this->player_ptr, DiaryKind::DIALY, 0);
             determine_daily_bounty(this->player_ptr, false);
         }
     }
@@ -103,13 +103,12 @@ void WorldTurnProcessor::process_world()
  */
 void WorldTurnProcessor::print_time()
 {
-    TERM_LEN width, height;
-    term_get_size(&width, &height);
-    const auto row = height + ROW_DAY;
+    const auto &[wid, hgt] = term_get_size();
+    const auto row = hgt + ROW_DAY;
 
-    int day;
     c_put_str(TERM_WHITE, "             ", row, COL_DAY);
-    extract_day_hour_min(this->player_ptr, &day, &this->hour, &this->min);
+    auto day = 0;
+    std::tie(day, this->hour, this->min) = w_ptr->extract_date_time(this->player_ptr->start_race);
     if (day < 1000) {
         c_put_str(TERM_WHITE, format(_("%2d日目", "Day%3d"), day), row, COL_DAY);
     } else {
@@ -122,13 +121,13 @@ void WorldTurnProcessor::print_time()
 void WorldTurnProcessor::process_downward()
 {
     /* 帰還無しモード時のレベルテレポバグ対策 / Fix for level teleport bugs on ironman_downward.*/
-    if (!ironman_downward || (this->player_ptr->dungeon_idx == DUNGEON_ANGBAND) || (this->player_ptr->dungeon_idx == 0)) {
+    auto *floor_ptr = this->player_ptr->current_floor_ptr;
+    if (!ironman_downward || (floor_ptr->dungeon_idx == DUNGEON_ANGBAND) || (floor_ptr->dungeon_idx == 0)) {
         return;
     }
 
-    auto *floor_ptr = this->player_ptr->current_floor_ptr;
     floor_ptr->dun_level = 0;
-    this->player_ptr->dungeon_idx = 0;
+    floor_ptr->reset_dungeon_index();
     prepare_change_floor_mode(this->player_ptr, CFM_FIRST_FLOOR | CFM_RAND_PLACE);
     floor_ptr->inside_arena = false;
     this->player_ptr->wild_mode = false;
@@ -137,7 +136,7 @@ void WorldTurnProcessor::process_downward()
 
 void WorldTurnProcessor::process_monster_arena()
 {
-    if (!this->player_ptr->phase_out || this->player_ptr->leaving) {
+    if (!AngbandSystem::get_instance().is_phase_out() || this->player_ptr->leaving) {
         return;
     }
 
@@ -211,7 +210,7 @@ void WorldTurnProcessor::decide_auto_save()
     }
 
     auto should_save = autosave_t;
-    should_save &= !this->player_ptr->phase_out;
+    should_save &= !AngbandSystem::get_instance().is_phase_out();
     should_save &= w_ptr->game_turn % ((int32_t)autosave_freq * TURNS_PER_TICK) == 0;
     if (should_save) {
         do_cmd_save_game(this->player_ptr, true);
@@ -221,7 +220,7 @@ void WorldTurnProcessor::decide_auto_save()
 void WorldTurnProcessor::process_change_daytime_night()
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    if (!floor_ptr->dun_level && !inside_quest(floor_ptr->quest_number) && !this->player_ptr->phase_out && !floor_ptr->inside_arena) {
+    if (!floor_ptr->dun_level && !floor_ptr->is_in_quest() && !AngbandSystem::get_instance().is_phase_out() && !floor_ptr->inside_arena) {
         if (!(w_ptr->game_turn % ((TURNS_PER_TICK * TOWN_DAWN) / 2))) {
             auto dawn = w_ptr->game_turn % (TURNS_PER_TICK * TOWN_DAWN) == 0;
             if (dawn) {
@@ -235,7 +234,7 @@ void WorldTurnProcessor::process_change_daytime_night()
     }
 
     auto is_in_dungeon = vanilla_town;
-    is_in_dungeon |= lite_town && (!inside_quest(floor_ptr->quest_number)) && !this->player_ptr->phase_out && !floor_ptr->inside_arena;
+    is_in_dungeon |= lite_town && !floor_ptr->is_in_quest() && !AngbandSystem::get_instance().is_phase_out() && !floor_ptr->inside_arena;
     is_in_dungeon &= floor_ptr->dun_level != 0;
     if (!is_in_dungeon) {
         return;
@@ -251,7 +250,7 @@ void WorldTurnProcessor::process_change_daytime_night()
 void WorldTurnProcessor::process_world_monsters()
 {
     decide_alloc_monster();
-    if (!(w_ptr->game_turn % (TURNS_PER_TICK * 10)) && !this->player_ptr->phase_out) {
+    if (!(w_ptr->game_turn % (TURNS_PER_TICK * 10)) && !AngbandSystem::get_instance().is_phase_out()) {
         regenerate_monsters(this->player_ptr);
     }
 
@@ -277,24 +276,24 @@ void WorldTurnProcessor::shuffle_shopkeeper()
     }
 
     int n;
-    do {
+    while (true) {
         n = randint0(MAX_STORES);
         if ((n == enum2i(StoreSaleType::HOME)) || (n == enum2i(StoreSaleType::MUSEUM))) {
             break;
         }
-    } while (true);
+    }
 
-    for (const auto &f_ref : terrains_info) {
-        if (f_ref.name.empty() || f_ref.flags.has_not(TerrainCharacteristics::STORE)) {
+    for (const auto &terrain : TerrainList::get_instance()) {
+        if (terrain.name.empty() || terrain.flags.has_not(TerrainCharacteristics::STORE)) {
             continue;
         }
 
-        if (f_ref.subtype != n) {
+        if (terrain.subtype != n) {
             continue;
         }
 
         if (cheat_xtra) {
-            msg_format(_("%sの店主をシャッフルします。", "Shuffle a Shopkeeper of %s."), f_ref.name.data());
+            msg_format(_("%sの店主をシャッフルします。", "Shuffle a Shopkeeper of %s."), terrain.name.data());
         }
 
         store_shuffle(this->player_ptr, i2enum<StoreSaleType>(n));
@@ -305,10 +304,10 @@ void WorldTurnProcessor::shuffle_shopkeeper()
 void WorldTurnProcessor::decide_alloc_monster()
 {
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
-    auto should_alloc = one_in_(dungeons_info[this->player_ptr->dungeon_idx].max_m_alloc_chance);
+    auto should_alloc = one_in_(floor_ptr->get_dungeon_definition().max_m_alloc_chance);
     should_alloc &= !floor_ptr->inside_arena;
-    should_alloc &= !inside_quest(floor_ptr->quest_number);
-    should_alloc &= !this->player_ptr->phase_out;
+    should_alloc &= !floor_ptr->is_in_quest();
+    should_alloc &= !AngbandSystem::get_instance().is_phase_out();
     if (should_alloc) {
         (void)alloc_monster(this->player_ptr, MAX_PLAYER_SIGHT + 5, 0, summon_specific);
     }
index 9e6cda9..f8318cf 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
 
 class PlayerType;
 class WorldTurnProcessor {
index 6dda5ae..8f67d11 100644 (file)
-#include "world/world.h"
+#include "world/world.h"
 #include "player-info/race-types.h"
 #include "system/player-type-definition.h"
+#include "term/term-color-types.h"
 #include "util/bit-flags-calculator.h"
 
-world_type world;
-world_type *w_ptr = &world;
+AngbandWorld world;
+AngbandWorld *w_ptr = &world;
 
 /*!
- * @brief ゲーム時間が日中かどうかを返す /
- * Whether daytime or not
- * @return 日中ならばTRUE、夜ならばFALSE
+ * @brief アリーナへの入場/退出状態を更新する
+ * @param 入場ならばtrue、退出ならばfalse
  */
-bool is_daytime(void)
+void AngbandWorld::set_arena(const bool new_status)
 {
-    int32_t len = TURNS_PER_TICK * TOWN_DAWN;
-    if ((w_ptr->game_turn % len) < (len / 2)) {
-        return true;
-    } else {
-        return false;
-    }
+    this->is_out_arena = new_status;
+}
+
+/*!
+ * @brief アリーナへの入場/退出状態を取得する
+ * @return アリーナ状態
+ */
+bool AngbandWorld::get_arena() const
+{
+    return this->is_out_arena;
 }
 
 /*!
- * @brief 現在の日数、時刻を返す /
- * Extract day, hour, min
- * @param player_ptr プレイヤーへの参照ポインタ
- * @param day 日数を返すための参照ポインタ
- * @param hour 時数を返すための参照ポインタ
- * @param min 分数を返すための参照ポインタ
+ * @brief ゲーム時間が日中かどうかを返す
+ * @return 日中ならばTRUE、夜ならばFALSE
  */
-void extract_day_hour_min(PlayerType *player_ptr, int *day, int *hour, int *min)
+bool AngbandWorld::is_daytime() const
 {
-    const int32_t A_DAY = TURNS_PER_TICK * TOWN_DAWN;
-    int32_t turn_in_today = (w_ptr->game_turn + A_DAY / 4) % A_DAY;
+    int a_day = TURNS_PER_TICK * TOWN_DAWN;
+    return (this->game_turn % a_day) < (a_day / 2);
+}
 
-    switch (player_ptr->start_race) {
+/*!
+ * @brief プレイ開始からの経過時間を計算する
+ * @param start_race 開始時のプレイヤー種族
+ * @return 日数、時間、分
+ */
+std::tuple<int, int, int> AngbandWorld::extract_date_time(PlayerRaceType start_race) const
+{
+    const auto a_day = TURNS_PER_TICK * TOWN_DAWN;
+    const auto turn_in_today = (this->game_turn + a_day / 4) % a_day;
+    int day;
+    switch (start_race) {
     case PlayerRaceType::VAMPIRE:
     case PlayerRaceType::SKELETON:
     case PlayerRaceType::ZOMBIE:
     case PlayerRaceType::SPECTRE:
-        *day = (w_ptr->game_turn - A_DAY * 3 / 4) / A_DAY + 1;
+        day = (this->game_turn - a_day * 3 / 4) / a_day + 1;
         break;
     default:
-        *day = (w_ptr->game_turn + A_DAY / 4) / A_DAY + 1;
+        day = (this->game_turn + a_day / 4) / a_day + 1;
         break;
     }
-    *hour = (24 * turn_in_today / A_DAY) % 24;
-    *min = (1440 * turn_in_today / A_DAY) % 60;
+
+    auto hour = (24 * turn_in_today / a_day) % 24;
+    auto min = (1440 * turn_in_today / a_day) % 60;
+    return { day, hour, min };
 }
 
 /*!
  * @brief 実ゲームプレイ時間を更新する
  */
-void update_playtime(void)
+void AngbandWorld::update_playtime()
 {
-    if (w_ptr->start_time != 0) {
-        uint32_t tmp = (uint32_t)time(nullptr);
-        w_ptr->play_time += (tmp - w_ptr->start_time);
-        w_ptr->start_time = tmp;
+    if (this->start_time == 0) {
+        return;
     }
+
+    const auto current_time = static_cast<uint32_t>(time(nullptr));
+    this->play_time += (current_time - this->start_time);
+    this->start_time = current_time;
 }
 
 /*!
  * @brief 勝利したクラスを追加する
  */
-void add_winner_class(PlayerClassType c)
+void AngbandWorld::add_winner_class(PlayerClassType c)
 {
-    if (!w_ptr->noscore) {
-        w_ptr->sf_winner.set(c);
+    if (!this->noscore) {
+        this->sf_winner.set(c);
     }
 }
 
 /*!
  * @brief 引退したクラスを追加する
  */
-void add_retired_class(PlayerClassType c)
+void AngbandWorld::add_retired_class(PlayerClassType c)
+{
+    if (!this->noscore) {
+        this->sf_retired.set(c);
+    }
+}
+
+term_color_type AngbandWorld::get_birth_class_color(PlayerClassType c) const
 {
-    if (!w_ptr->noscore) {
-        w_ptr->sf_retired.set(c);
+    if (c >= PlayerClassType::MAX) {
+        return TERM_WHITE;
+    }
+
+    if (this->is_retired_class(c)) {
+        return TERM_L_DARK;
     }
+
+    return this->is_winner_class(c) ? TERM_SLATE : TERM_WHITE;
 }
 
 /*!
  * @brief 勝利したクラスか判定する
  */
-bool is_winner_class(PlayerClassType c)
+bool AngbandWorld::is_winner_class(PlayerClassType c) const
 {
     if (c == PlayerClassType::MAX) {
         return false;
     }
-    return w_ptr->sf_winner.has(c);
+
+    return this->sf_winner.has(c);
 }
 
 /*!
  * @brief 引退したクラスか判定する
  */
-bool is_retired_class(PlayerClassType c)
+bool AngbandWorld::is_retired_class(PlayerClassType c) const
 {
     if (c == PlayerClassType::MAX) {
         return false;
     }
-    return w_ptr->sf_retired.has(c);
+
+    return this->sf_retired.has(c);
 }
index 2e873d2..58abdfc 100644 (file)
@@ -1,17 +1,22 @@
-#pragma once
+#pragma once
 
 #include "market/bounty-type-definition.h"
 #include "player-info/class-types.h"
 #include "system/angband.h"
 #include "util/flag-group.h"
 #include "util/rng-xoshiro.h"
+#include <tuple>
 
 constexpr auto MAX_BOUNTY = 20;
 
 /*!
  * @brief 世界情報構造体
  */
-struct world_type {
+enum term_color_type : unsigned char;
+enum class PlayerRaceType;
+class AngbandWorld {
+public:
+    AngbandWorld() = default;
 
     POSITION max_wild_x{}; /*!< Maximum size of the wilderness */
     POSITION max_wild_y{}; /*!< Maximum size of the wilderness */
@@ -67,15 +72,21 @@ struct world_type {
 
     OBJECT_IDX max_o_idx = 1024; /*!< 1フロアに存在可能な最大アイテム数 */
     MONSTER_IDX max_m_idx = 1024; /*!< 1フロアに存在可能な最大モンスター数 */
-};
 
-extern world_type *w_ptr;
+    void set_arena(const bool new_status);
+    bool get_arena() const;
+    std::tuple<int, int, int> extract_date_time(PlayerRaceType start_race) const;
+    bool is_daytime() const;
+    void update_playtime();
+    void add_winner_class(PlayerClassType c);
+    void add_retired_class(PlayerClassType c);
+    term_color_type get_birth_class_color(PlayerClassType c) const;
+
+private:
+    bool is_out_arena = false; // アリーナ外部にいる時だけtrue.
+
+    bool is_winner_class(PlayerClassType c) const;
+    bool is_retired_class(PlayerClassType c) const;
+};
 
-class PlayerType;
-bool is_daytime(void);
-void extract_day_hour_min(PlayerType *player_ptr, int *day, int *hour, int *min);
-void update_playtime(void);
-void add_winner_class(PlayerClassType c);
-void add_retired_class(PlayerClassType c);
-bool is_winner_class(PlayerClassType c);
-bool is_retired_class(PlayerClassType c);
+extern AngbandWorld *w_ptr;