name: Build test on Ubuntu-20.04
runs-on: ubuntu-20.04
env:
- CFLAGS: "-pipe -O3 -Werror -Wall -Wextra -Wno-switch -Wno-sign-compare -Wno-unused-parameter -Wno-unused-function"
+ CXXFLAGS: "-pipe -O3 -Werror -Wall -Wextra"
steps:
- uses: actions/checkout@v2
libncursesw5-dev \
libcurl4-openssl-dev \
nkf \
+ clang-11 \
- name: Generate configure
run: ./bootstrap
run: ./configure
- name: Build Japanese version
- run: make -j$(nproc)
+ run: make -j$(nproc) 1> /dev/null
- name: Clean source tree
run: make clean
- - name: Configure for English versoin
+ - name: Configure for English version
run: ./configure --disable-japanese
- name: Build English version
- run: make -j$(nproc)
+ run: make -j$(nproc) 1> /dev/null
+
+ - name: Clean source tree
+ run: make clean
+
+ - name: Configure for compiling with clang
+ run: ./configure
+ env:
+ CXX: clang++-11
+ CXXFLAGS: "-pipe -O3 -Werror -Wall -Wextra -Wno-unused-const-variable -Wno-invalid-source-encoding"
+
+ - name: Build with clang
+ run: make -j$(nproc) 1> /dev/null
<AdditionalIncludeDirectories>..\..\src;curl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
<LanguageStandard>stdcpplatest</LanguageStandard>\r
<ExceptionHandling>SyncCThrow</ExceptionHandling>\r
+ <PrecompiledHeader>Use</PrecompiledHeader>\r
+ <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>\r
</ClCompile>\r
<Link>\r
<GenerateDebugInformation>true</GenerateDebugInformation>\r
<Command>\r
</Command>\r
</PreBuildEvent>\r
+ <ResourceCompile>\r
+ <Culture>0x0411</Culture>\r
+ <PreprocessorDefinitions>JP</PreprocessorDefinitions>\r
+ </ResourceCompile>\r
</ItemDefinitionGroup>\r
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='English-Debug|Win32'">\r
<ClCompile>\r
<AdditionalIncludeDirectories>..\..\src;curl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
<ExceptionHandling>SyncCThrow</ExceptionHandling>\r
<LanguageStandard>stdcpplatest</LanguageStandard>\r
+ <PrecompiledHeader>Use</PrecompiledHeader>\r
+ <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>\r
</ClCompile>\r
<Link>\r
<GenerateDebugInformation>true</GenerateDebugInformation>\r
<CompileAs>CompileAsCpp</CompileAs>\r
<ExceptionHandling>SyncCThrow</ExceptionHandling>\r
<LanguageStandard>stdcpplatest</LanguageStandard>\r
+ <PrecompiledHeader>Use</PrecompiledHeader>\r
+ <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>\r
</ClCompile>\r
<Link>\r
<TargetMachine>MachineX86</TargetMachine>\r
<EnableCOMDATFolding>true</EnableCOMDATFolding>\r
<SubSystem>Windows</SubSystem>\r
</Link>\r
+ <ResourceCompile>\r
+ <PreprocessorDefinitions>JP</PreprocessorDefinitions>\r
+ </ResourceCompile>\r
+ <ResourceCompile>\r
+ <Culture>0x0411</Culture>\r
+ </ResourceCompile>\r
</ItemDefinitionGroup>\r
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='English-Release|Win32'">\r
<ClCompile>\r
<ExceptionHandling>SyncCThrow</ExceptionHandling>\r
<LanguageStandard>stdcpplatest</LanguageStandard>\r
<CompileAs>CompileAsCpp</CompileAs>\r
+ <PrecompiledHeader>Use</PrecompiledHeader>\r
+ <ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>\r
</ClCompile>\r
<Link>\r
<AdditionalDependencies>winmm.lib;Ws2_32.lib;Wldap32.lib;Crypt32.lib;Normaliz.lib;curl\x86 Release\libcurl_a.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
<ClCompile Include="..\..\src\io\store-key-processor.cpp" />\r
<ClCompile Include="..\..\src\load\info-loader.cpp" />\r
<ClCompile Include="..\..\src\locale\utf-8.cpp" />\r
+ <ClCompile Include="..\..\src\main-win\main-win-file-utils.cpp" />\r
+ <ClCompile Include="..\..\src\main-win\main-win-mci.cpp" />\r
+ <ClCompile Include="..\..\src\main-win\main-win-music.cpp" />\r
+ <ClCompile Include="..\..\src\main-win\main-win-sound.cpp" />\r
+ <ClCompile Include="..\..\src\main-win\main-win-tokenizer.cpp" />\r
<ClCompile Include="..\..\src\main\angband-headers.cpp" />\r
<ClCompile Include="..\..\src\main\game-data-initializer.cpp" />\r
<ClCompile Include="..\..\src\main\info-initializer.cpp" />\r
<ClCompile Include="..\..\src\main\init-error-messages-table.cpp" />\r
+ <ClCompile Include="..\..\src\main-win\main-win-bg.cpp" />\r
<ClCompile Include="..\..\src\market\building-initializer.cpp" />\r
<ClCompile Include="..\..\src\melee\melee-spell-flags-checker.cpp" />\r
<ClCompile Include="..\..\src\melee\melee-spell-util.cpp" />\r
<ClCompile Include="..\..\src\mind\mind-berserker.cpp" />\r
<ClCompile Include="..\..\src\mind\mind-blue-mage.cpp" />\r
<ClCompile Include="..\..\src\mind\mind-chaos-warrior.cpp" />\r
+ <ClCompile Include="..\..\src\mind\mind-elementalist.cpp" />\r
<ClCompile Include="..\..\src\mind\mind-explanations-table.cpp" />\r
<ClCompile Include="..\..\src\mind\mind-hobbit.cpp" />\r
<ClCompile Include="..\..\src\mind\mind-info.cpp" />\r
<ClCompile Include="..\..\src\load\quest-loader.cpp" />\r
<ClCompile Include="..\..\src\view\display-store.cpp" />\r
<ClCompile Include="..\..\src\action\throw-util.cpp" />\r
+ <ClCompile Include="stdafx.cpp">\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='English-Release|Win32'">Create</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='English-Debug|Win32'">Create</PrecompiledHeader>\r
+ </ClCompile>\r
<ClInclude Include="..\..\src\action\action-limited.h" />\r
<ClInclude Include="..\..\src\action\activation-execution.h" />\r
<ClInclude Include="..\..\src\action\mutation-execution.h" />\r
<ClInclude Include="..\..\src\load\info-loader.h" />\r
<ClInclude Include="..\..\src\locale\language-switcher.h" />\r
<ClInclude Include="..\..\src\locale\utf-8.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-file-utils.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-mci.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-mmsystem.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-music.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-sound.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-define.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-tokenizer.h" />\r
<ClInclude Include="..\..\src\main\angband-headers.h" />\r
<ClInclude Include="..\..\src\main\game-data-initializer.h" />\r
<ClInclude Include="..\..\src\main\info-initializer.h" />\r
<ClInclude Include="..\..\src\main\init-error-messages-table.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-bg.h" />\r
+ <ClInclude Include="..\..\src\main-win\main-win-windows.h" />\r
<ClInclude Include="..\..\src\market\building-initializer.h" />\r
<ClInclude Include="..\..\src\melee\melee-spell-flags-checker.h" />\r
<ClInclude Include="..\..\src\melee\melee-spell-util.h" />\r
<ClInclude Include="..\..\src\mind\mind-berserker.h" />\r
<ClInclude Include="..\..\src\mind\mind-blue-mage.h" />\r
<ClInclude Include="..\..\src\mind\mind-chaos-warrior.h" />\r
+ <ClInclude Include="..\..\src\mind\mind-elementalist.h" />\r
<ClInclude Include="..\..\src\mind\mind-explanations-table.h" />\r
<ClInclude Include="..\..\src\mind\mind-hobbit.h" />\r
<ClInclude Include="..\..\src\mind\mind-info.h" />\r
<ClInclude Include="..\..\src\mspell\mspell-type.h" />\r
<ClInclude Include="..\..\src\mspell\mspell-util.h" />\r
<ClInclude Include="..\..\src\mspell\mspell-ball.h" />\r
+ <ClInclude Include="..\..\src\mspell\mspell.h" />\r
<ClInclude Include="..\..\src\player\player-personalities-types.h" />\r
<ClInclude Include="..\..\src\player\player-race-types.h" />\r
<ClInclude Include="..\..\src\player\player-classes-types.h" />\r
<ClCompile Include="..\..\src\room\rooms-trap.cpp" />\r
<ClCompile Include="..\..\src\room\rooms-vault.cpp" />\r
<ClCompile Include="..\..\src\room\rooms-builder.cpp" />\r
- <ClCompile Include="..\..\src\room\pit-nest-kinds-table.cpp" />\r
<ClCompile Include="..\..\src\store\rumor.cpp" />\r
<ClCompile Include="..\..\src\save\save.cpp" />\r
<ClCompile Include="..\..\src\core\scores.cpp" />\r
<ClInclude Include="..\..\src\player\race-info-table.h" />\r
<ClInclude Include="..\..\src\player\race-resistances.h" />\r
<ClInclude Include="..\..\src\player\temporary-resistances.h" />\r
- <ClInclude Include="..\..\src\room\pit-nest-kinds-table.h" />\r
<ClInclude Include="..\..\src\io\signal-handlers.h" />\r
<ClInclude Include="..\..\src\io\uid-checker.h" />\r
<ClInclude Include="..\..\src\spell-realm\spells-song.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="stdafx.h" />\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\..\src\system\angband.h" />\r
-<?xml version="1.0" encoding="utf-8"?>\r
+<?xml version="1.0" encoding="utf-8"?>\r
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
<ItemGroup>\r
<ClCompile Include="..\..\src\main-win.cpp" />\r
<ClCompile Include="..\..\src\autopick\autopick-describer.cpp">\r
<Filter>autopick</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\..\src\room\pit-nest-kinds-table.cpp">\r
- <Filter>room</Filter>\r
- </ClCompile>\r
<ClCompile Include="..\..\src\io\signal-handlers.cpp">\r
<Filter>io</Filter>\r
</ClCompile>\r
<ClCompile Include="..\..\src\player-status\player-charisma.cpp">\r
<Filter>player-status</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\src\mind\mind-elementalist.cpp">\r
+ <Filter>mind</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\src\main-win\main-win-bg.cpp">\r
+ <Filter>main-win</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\src\main-win\main-win-music.cpp">\r
+ <Filter>main-win</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\src\main-win\main-win-sound.cpp">\r
+ <Filter>main-win</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\src\main-win\main-win-mci.cpp">\r
+ <Filter>main-win</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\src\main-win\main-win-tokenizer.cpp">\r
+ <Filter>main-win</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\src\main-win\main-win-file-utils.cpp">\r
+ <Filter>main-win</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="stdafx.cpp" />\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\..\src\combat\shoot.h">\r
<ClInclude Include="..\..\src\autopick\autopick-describer.h">\r
<Filter>autopick</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\..\src\room\pit-nest-kinds-table.h">\r
- <Filter>room</Filter>\r
- </ClInclude>\r
<ClInclude Include="..\..\src\io\signal-handlers.h">\r
<Filter>io</Filter>\r
</ClInclude>\r
<ClInclude Include="..\..\src\mspell\mspell-lite.h">\r
<Filter>mspell</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\src\mspell\mspell.h">\r
+ <Filter>mspell</Filter>\r
+ </ClInclude>\r
<ClInclude Include="..\..\src\object-use\read-execution.h">\r
<Filter>object-use</Filter>\r
</ClInclude>\r
<ClInclude Include="..\..\src\util\flag-group.h">\r
<Filter>util</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\src\mind\mind-elementalist.h">\r
+ <Filter>mind</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-bg.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-windows.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-music.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-sound.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-mmsystem.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-define.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-mci.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-tokenizer.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\main-win-file-utils.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="stdafx.h" />\r
</ItemGroup>\r
<ItemGroup>\r
<None Include="..\..\src\wall.bmp" />\r
<Filter Include="player-status">\r
<UniqueIdentifier>{d6c9dc68-d79b-4509-bf9c-34ff9620bbf4}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="main-win">\r
+ <UniqueIdentifier>{8175f3d1-c8b3-4f2b-8536-8631d77eb53c}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ResourceCompile Include="..\..\src\angband.rc" />\r
--- /dev/null
+#include "stdafx.h"
--- /dev/null
+#pragma once
+#include <algorithm>
+#include <array>
+#include <bitset>
+#include <iterator>
+#include <functional>
+#include <map>
+#include <queue>
+#include <sstream>
+#include <stack>
+#include <string>
+#include <string_view>
+#include <unordered_map>
+#include <utility>
+#include <vector>
visual_studio_files = \
Hengband/Hengband.sln \
+ 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/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/Hengband.vcxproj \
Hengband/Hengband/Hengband.vcxproj.filters \
- Hengband/Hengband/packages.config
+ Hengband/Hengband/packages.config \
+ Hengband/Hengband/stdafx.cpp \
+ Hengband/Hengband/stdafx.h
EXTRA_DIST = \
autopick.txt \
dnl Checks for programs.
AC_LANG(C++)
AC_PROG_CXX
-AX_CXX_COMPILE_STDCXX_17
+m4_ifdef([AX_CXX_COMPILE_STDCXX_17], [
+ AX_CXX_COMPILE_STDCXX_17
+], [
+ AC_MSG_ERROR([AX_CXX_COMPILE_STDCXX_17 macro is not defined. You need to install autoconf-archive.])
+])
PKG_PROG_PKG_CONFIG
AC_ARG_ENABLE(japanese,
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 3.0.0Alpha10
+PROJECT_NUMBER = 3.0.0Alpha13
# 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
# members will be omitted, etc.
# The default value is: NO.
-OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_FOR_C = NO
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
# Python sources only. Doxygen will then generate output that is more tailored
# scope will be hidden.
# The default value is: NO.
-HIDE_SCOPE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
# append additional text to a page's title, such as Class Reference. If set to
# *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
- *.h
+ *.h \
+ *.cpp
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# Fortran comments will always remain visible.
# The default value is: YES.
-STRIP_CODE_COMMENTS = NO
+STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
# entity all documented functions referencing it will be listed.
# Crusade
R:9:0
+
+
+### Elementalist ###
+N:28
+I:NONE:WIS:0x00:0:1:430
+# Life
+R:0:0
+
+# Sorcery
+R:1:0
+
+# Neture
+R:2:0
+
+# Chaos
+R:3:0
+
+# Death
+R:4:0
+
+# Trump
+R:5:0
+
+# Arcane
+R:6:0
+
+# Craft
+R:7:0
+
+# Deamon
+R:8:0
+
+# Crusade
+R:9:0
S:1:0:1000 # NITOURYU
S:2:0:0 # RIDING
S:3:0:0 # SHIELD
+
+### ELEMENTALIST ###
+N:28
+# Bow
+W:0:0:0:1 # 0
+W:0:1:0:1 #
+W:0:2:1:2 # SLING
+W:0:3:0:1 #
+W:0:4:0:1 #
+W:0:5:0:1 #
+W:0:6:0:1 #
+W:0:7:0:1 #
+W:0:8:0:1 #
+W:0:9:0:1 #
+W:0:10:0:1 # 10
+W:0:11:0:1 #
+W:0:12:0:1 # SHORT_BOW
+W:0:13:0:1 # LONG_BOW
+W:0:14:0:1 #
+W:0:15:0:1 #
+W:0:16:0:1 #
+W:0:17:0:1 #
+W:0:18:0:1 #
+W:0:19:0:1 #
+W:0:20:0:1 # 20
+W:0:21:0:1 #
+W:0:22:0:1 #
+W:0:23:0:1 # LIGHT_XBOW
+W:0:24:0:1 # HEAVY_XBOW
+W:0:25:0:1 #
+W:0:26:0:1 #
+W:0:27:0:1 #
+W:0:28:0:1 #
+W:0:29:0:1 #
+W:0:30:0:1 # 30
+W:0:31:0:1 #
+W:0:32:0:1 #
+W:0:33:0:1 #
+W:0:34:0:1 #
+W:0:35:0:1 #
+W:0:36:0:1 #
+W:0:37:0:1 #
+W:0:38:0:1 #
+W:0:39:0:1 #
+W:0:40:0:1 # 40
+W:0:41:0:1 #
+W:0:42:0:1 #
+W:0:43:0:1 #
+W:0:44:0:1 #
+W:0:45:0:1 #
+W:0:46:0:1 #
+W:0:47:0:1 #
+W:0:48:0:1 #
+W:0:49:0:1 #
+W:0:50:0:1 # 50
+W:0:51:0:1 #
+W:0:52:0:1 #
+W:0:53:0:1 #
+W:0:54:0:1 #
+W:0:55:0:1 #
+W:0:56:0:1 #
+W:0:57:0:1 #
+W:0:58:0:1 #
+W:0:59:0:1 #
+W:0:60:0:1 # 60
+W:0:61:0:1 #
+W:0:62:0:1 #
+W:0:63:0:4 # NAMAKE
+# Digging
+W:1:0:0:1 # 0
+W:1:1:0:1 # SHOVEL
+W:1:2:0:1 # GNOMISH_SHOVEL
+W:1:3:0:1 # DWARVEN_SHOVEL
+W:1:4:0:1 # PICK
+W:1:5:0:1 # ORCISH_PICK
+W:1:6:0:1 # DWARVEN_PICK
+W:1:7:0:1 # MATTOCK
+W:1:8:0:1 #
+W:1:9:0:1 #
+W:1:10:0:1 # 10
+W:1:11:0:1 #
+W:1:12:0:1 #
+W:1:13:0:1 #
+W:1:14:0:1 #
+W:1:15:0:1 #
+W:1:16:0:1 #
+W:1:17:0:1 #
+W:1:18:0:1 #
+W:1:19:0:1 #
+W:1:20:0:1 # 20
+W:1:21:0:1 #
+W:1:22:0:1 #
+W:1:23:0:1 #
+W:1:24:0:1 #
+W:1:25:0:1 #
+W:1:26:0:1 #
+W:1:27:0:1 #
+W:1:28:0:1 #
+W:1:29:0:1 #
+W:1:30:0:1 # 30
+W:1:31:0:1 #
+W:1:32:0:1 #
+W:1:33:0:1 #
+W:1:34:0:1 #
+W:1:35:0:1 #
+W:1:36:0:1 #
+W:1:37:0:1 #
+W:1:38:0:1 #
+W:1:39:0:1 #
+W:1:40:0:1 # 40
+W:1:41:0:1 #
+W:1:42:0:1 #
+W:1:43:0:1 #
+W:1:44:0:1 #
+W:1:45:0:1 #
+W:1:46:0:1 #
+W:1:47:0:1 #
+W:1:48:0:1 #
+W:1:49:0:1 #
+W:1:50:0:1 # 50
+W:1:51:0:1 #
+W:1:52:0:1 #
+W:1:53:0:1 #
+W:1:54:0:1 #
+W:1:55:0:1 #
+W:1:56:0:1 #
+W:1:57:0:1 #
+W:1:58:0:1 #
+W:1:59:0:1 #
+W:1:60:0:1 # 60
+W:1:61:0:1 #
+W:1:62:0:1 #
+W:1:63:0:1 #
+# Hafted
+W:2:0:0:1 # 0
+W:2:1:0:1 # CLUB
+W:2:2:0:1 # WHIP
+W:2:3:1:4 # QUARTERSTAFF
+W:2:4:0:0 # NUNCHAKU
+W:2:5:0:1 # MACE
+W:2:6:0:1 # BALL_AND_CHAIN
+W:2:7:0:1 # JO_STAFF
+W:2:8:0:1 # WAR_HAMMER
+W:2:9:0:1 #
+W:2:10:0:1 # 10
+W:2:11:0:1 # THREE_PIECE_ROD
+W:2:12:0:1 # MORNING_STAR
+W:2:13:0:1 # FLAIL
+W:2:14:0:1 # BO_STAFF
+W:2:15:0:1 # LEAD_FILLED_MACE
+W:2:16:0:1 # TETSUBO
+W:2:17:0:1 #
+W:2:18:0:1 # TWO_HANDED_FLAIL
+W:2:19:0:1 # GREAT_HAMMER
+W:2:20:0:1 # MACE_OF_DISRUPTION
+W:2:21:1:4 # WIZSTAFF
+W:2:22:0:1 #
+W:2:23:0:1 #
+W:2:24:0:1 #
+W:2:25:0:1 #
+W:2:26:0:1 #
+W:2:27:0:1 #
+W:2:28:0:1 #
+W:2:29:0:1 #
+W:2:30:0:1 # 30
+W:2:31:0:1 #
+W:2:32:0:1 #
+W:2:33:0:1 #
+W:2:34:0:1 #
+W:2:35:0:1 #
+W:2:36:0:1 #
+W:2:37:0:1 #
+W:2:38:0:1 #
+W:2:39:0:1 #
+W:2:40:0:0 # TSURIZAO
+W:2:41:0:1 #
+W:2:42:0:1 #
+W:2:43:0:1 #
+W:2:44:0:1 #
+W:2:45:0:1 #
+W:2:46:0:1 #
+W:2:47:0:1 #
+W:2:48:0:1 #
+W:2:49:0:1 #
+W:2:50:0:1 # GROND
+W:2:51:0:1 #
+W:2:52:0:1 #
+W:2:53:0:1 #
+W:2:54:0:1 #
+W:2:55:0:1 #
+W:2:56:0:1 #
+W:2:57:0:1 #
+W:2:58:0:1 #
+W:2:59:0:1 #
+W:2:60:0:1 # 60
+W:2:61:0:1 #
+W:2:62:0:1 #
+W:2:63:0:4 # NAMAKE
+# Polearm
+W:3:0:0:1 # 0
+W:3:1:0:1 # HATCHET
+W:3:2:0:1 # SPEAR
+W:3:3:0:1 # SICKLE
+W:3:4:0:1 # AWL_PIKE
+W:3:5:0:1 # TRIDENT
+W:3:6:0:1 # FAUCHARD
+W:3:7:0:1 # BROAD_SPEAR
+W:3:8:0:1 # PIKE
+W:3:9:0:1 # NAGINATA
+W:3:10:0:1 # BEAKED_AXE
+W:3:11:0:1 # BROAD_AXE
+W:3:12:0:1 # LUCERNE_HAMMER
+W:3:13:0:1 # GLAIVE
+W:3:14:0:1 # LAJATANG
+W:3:15:0:1 # HALBERD
+W:3:16:0:1 # GUISARME
+W:3:17:0:1 # SCYTHE
+W:3:18:0:1 #
+W:3:19:0:1 #
+W:3:20:0:1 # LANCE
+W:3:21:0:1 #
+W:3:22:0:1 # BATTLE_AXE
+W:3:23:0:1 #
+W:3:24:0:1 #
+W:3:25:0:1 # GREAT_AXE
+W:3:26:0:1 # TRIFURCATE_SPEAR
+W:3:27:0:1 #
+W:3:28:0:1 # LOCHABER_AXE
+W:3:29:0:1 # HEAVY_LANCE
+W:3:30:0:1 # SCYTHE_OF_SLICING
+W:3:31:0:1 #
+W:3:32:0:1 #
+W:3:33:0:1 #
+W:3:34:0:1 #
+W:3:35:0:1 #
+W:3:36:0:1 #
+W:3:37:0:1 #
+W:3:38:0:1 #
+W:3:39:0:1 #
+W:3:40:0:1 # 40
+W:3:41:0:1 #
+W:3:42:0:1 #
+W:3:43:0:1 #
+W:3:44:0:1 #
+W:3:45:0:1 #
+W:3:46:0:1 #
+W:3:47:0:1 #
+W:3:48:0:1 #
+W:3:49:0:1 #
+W:3:50:0:1 # DEATH_SCYTHE
+W:3:51:0:1 #
+W:3:52:0:1 #
+W:3:53:0:1 #
+W:3:54:0:1 #
+W:3:55:0:1 #
+W:3:56:0:1 #
+W:3:57:0:1 #
+W:3:58:0:1 #
+W:3:59:0:1 #
+W:3:60:0:1 # 60
+W:3:61:0:1 #
+W:3:62:0:1 #
+W:3:63:0:1 #
+# Sword
+W:4:0:0:1 # 0
+W:4:1:0:1 # BROKEN_DAGGER
+W:4:2:0:1 # BROKEN_SWORD
+W:4:3:0:1 #
+W:4:4:1:4 # DAGGER
+W:4:5:0:1 # MAIN_GAUCHE
+W:4:6:0:2 # TANTO
+W:4:7:0:1 # RAPIER
+W:4:8:0:1 # SMALL_SWORD
+W:4:9:0:1 # BASILLARD
+W:4:10:0:1 # SHORT_SWORD
+W:4:11:0:1 # SABRE
+W:4:12:0:1 # CUTLASS
+W:4:13:0:1 # WAKIZASHI
+W:4:14:0:1 # KHOPESH
+W:4:15:0:1 # TULWAR
+W:4:16:0:1 # BROAD_SWORD
+W:4:17:0:1 # LONG_SWORD
+W:4:18:0:1 # SCIMITAR
+W:4:19:0:1 # NINJATO
+W:4:20:0:1 # KATANA
+W:4:21:0:1 # BASTARD_SWORD
+W:4:22:0:1 # GREAT_SCIMITAR
+W:4:23:0:1 # CLAYMORE
+W:4:24:0:1 # ESPADON
+W:4:25:0:1 # TWO_HANDED_SWORD
+W:4:26:0:1 # FLAMBERGE
+W:4:27:0:1 # NO_DACHI
+W:4:28:0:1 # EXECUTIOERS_SWORD
+W:4:29:0:1 # ZWEIHANDER
+W:4:30:0:1 # BLADE_OF_CHAOS
+W:4:31:0:1 # DIAMOND_EDGE
+W:4:32:0:4 # DOKUBARI
+W:4:33:0:1 #
+W:4:34:0:1 #
+W:4:35:0:1 #
+W:4:36:0:1 #
+W:4:37:0:1 #
+W:4:38:0:1 #
+W:4:39:0:1 #
+W:4:40:0:1 # 40
+W:4:41:0:1 #
+W:4:42:0:1 #
+W:4:43:0:1 #
+W:4:44:0:1 #
+W:4:45:0:1 #
+W:4:46:0:1 #
+W:4:47:0:1 #
+W:4:48:0:1 #
+W:4:49:0:1 #
+W:4:50:0:1 # 50
+W:4:51:0:1 #
+W:4:52:0:1 #
+W:4:53:0:1 #
+W:4:54:0:1 #
+W:4:55:0:1 #
+W:4:56:0:1 #
+W:4:57:0:1 #
+W:4:58:0:1 #
+W:4:59:0:1 #
+W:4:60:0:1 # 60
+W:4:61:0:1 #
+W:4:62:0:1 #
+W:4:63:0:1 #
+# Skill
+S:0:0:4000 # SUDE
+S:1:0:0 # NITOURYU
+S:2:0:0 # RIDING
+S:3:0:0 # SHIELD
F:a:BUILDING_0:3
F:@:FLOOR:3:0:0:0:223
+# Quest 27 rewarding (Elementalist gets The Stone of Laputa)
+?:[AND [EQU $QUEST27 3] [EQU $CLASS Elementalist] ]
+F:a:BUILDING_0:3
+F:@:FLOOR:3:0:0:0:147
+
# Quest 27 finished, no new quest is available
?:[EQU $QUEST27 4]
F:a:BUILDING_0:3
mind/mind-blue-mage.cpp mind/mind-blue-mage.h \
mind/mind-cavalry.cpp mind/mind-cavalry.h \
mind/mind-chaos-warrior.cpp mind/mind-chaos-warrior.h \
+ mind/mind-elementalist.cpp mind/mind-elementalist.h \
mind/mind-explanations-table.cpp mind/mind-explanations-table.h \
mind/mind-force-trainer.cpp mind/mind-force-trainer.h \
mind/mind-info.cpp mind/mind-info.h \
mspell/mspell-status.cpp mspell/mspell-status.h \
mspell/mspell-particularity.cpp mspell/mspell-particularity.h \
mspell/mspell-selector.cpp mspell/mspell-selector.h \
+ mspell/mspell.h \
mspell/smart-mspell-util.cpp mspell/smart-mspell-util.h \
mspell/specified-summon.cpp mspell/specified-summon.h \
mspell/summon-checker.cpp mspell/summon-checker.h \
room/rooms-trap.cpp room/rooms-trap.h \
room/rooms-vault.cpp room/rooms-vault.h \
room/space-finder.cpp room/space-finder.h \
- room/pit-nest-kinds-table.cpp room/pit-nest-kinds-table.h \
room/treasure-deployment.cpp room/treasure-deployment.h \
room/vault-builder.cpp room/vault-builder.h \
\
util/flag-group.h \
util/int-char-converter.h \
util/object-sort.cpp util/object-sort.h \
+ util/probability-table.h \
util/quarks.cpp util/quarks.h \
util/sort.cpp util/sort.h \
util/string-processor.cpp util/string-processor.h \
world/world-turn-processor.cpp world/world-turn-processor.h
EXTRA_hengband_SOURCES = \
- angband.ico angband.rc ang_eng.rc maid-x11.cpp main-win.cpp \
+ angband.ico angband.rc ang_eng.rc ang_jp.rc maid-x11.cpp main-win.cpp \
+ main-win/main-win-bg.cpp main-win/main-win-bg.h \
+ main-win/main-win-define.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-mmsystem.h \
+ main-win/main-win-music.cpp main-win/main-win-music.h \
+ main-win/main-win-sound.cpp main-win/main-win-sound.h \
+ main-win/main-win-tokenizer.cpp main-win/main-win-tokenizer.h \
+ main-win/main-win-windows.h \
makefile.bcc makefile.std term/readdib.cpp term/readdib.h wall.bmp
EXTRA_DIST = \
gcc-wrap
DEFAULT_INCLUDES = -I$(srcdir) -I$(top_builddir)/src
-CFLAGS += $(XFT_CFLAGS) $(libcurl_CFLAGS)
+CPPFLAGS += $(XFT_CFLAGS) $(libcurl_CFLAGS)
LIBS += $(XFT_LIBS) $(libcurl_LIBS)
COMPILE = $(srcdir)/gcc-wrap $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CXXCOMPILE = $(srcdir)/gcc-wrap $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CXXFLAGS)
install-exec-hook:
if SET_GID
return FALSE;
}
- if (!switch_activation(user_ptr, o_ptr, act_ptr, name))
+ if (!switch_activation(user_ptr, &o_ptr, act_ptr, name))
return FALSE;
if (act_ptr->timeout.constant >= 0) {
MENUITEM "Term-7 window", 227
}
+ MENUITEM "&Always display subwindows", 280
+
MENUITEM SEPARATOR
/*
POPUP "Bizarre Display"
MENUITEM "&Bigtile mode", 409
}
+ MENUITEM "&Music", 411
MENUITEM "&Sound", 410
MENUITEM "&Back ground pict", 440
MENUITEM "Choose BG pict", 441
POPUP "&Help"
{
MENUITEM "&Contents", 901
+ MENUITEM "&Spoilers", 902
}
*/
}
--- /dev/null
+/* File: angband.rc */
+
+ANGBAND MENU
+{
+ POPUP "\83t\83@\83C\83\8b(&F)"
+ {
+ MENUITEM "\90V\8bK(&N)", 100
+ MENUITEM "\8aJ\82(&O)...", 101
+ MENUITEM SEPARATOR
+ MENUITEM "\95Û\91¶(&S)", 110
+ MENUITEM SEPARATOR
+ MENUITEM "\83X\83R\83A(&C)", 120
+ MENUITEM "\83\80\81[\83r\81[(&M)", 121
+ MENUITEM SEPARATOR
+ MENUITEM "\8fI\97¹(&X)", 130
+ }
+
+ POPUP "\83E\83B\83\93\83h\83E(&W)"
+ {
+ POPUP "\95\\8e¦(&V)"
+ {
+ MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 200
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 201
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 202
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 203
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 204
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 205
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 206
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 207
+ }
+
+ POPUP "\83t\83H\83\93\83g(&F)"
+ {
+ MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 210
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 211
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 212
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 213
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 214
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 215
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 216
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 217
+ }
+
+ POPUP "\91O\96Ê\82É\8cÅ\92è"
+ {
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 221
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 222
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 223
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 224
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 225
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 226
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 227
+ }
+
+ MENUITEM "\8fí\82É\83T\83u\83E\83B\83\93\83h\83E\82ð\95\\8e¦(&K)", 280
+
+ MENUITEM SEPARATOR
+
+ /* POPUP "Bizarre Display"
+ {
+ MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 230
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 231
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 232
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 233
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 234
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 235
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 236
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 237
+ }
+ */
+
+ POPUP "\83^\83C\83\8b\82Ì\95\9d\82ð\8dL\82°\82é"
+ {
+ MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 240
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 241
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 242
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 243
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 244
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 245
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 246
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 247
+ }
+
+ POPUP "\83^\83C\83\8b\82Ì\95\9d\82ð\8fk\82ß\82é"
+ {
+ MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 250
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 251
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 252
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 253
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 254
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 255
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 256
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 257
+ }
+
+ POPUP "\83^\83C\83\8b\82Ì\8d\82\82³\82ð\8dL\82°\82é"
+ {
+ MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 260
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 261
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 262
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 263
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 264
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 265
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 266
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 267
+ }
+
+ POPUP "\83^\83C\83\8b\82Ì\8d\82\82³\82ð\8fk\82ß\82é"
+ {
+ MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 270
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 271
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 272
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 273
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 274
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 275
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 276
+ MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 277
+ }
+ }
+
+ POPUP "\83I\83v\83V\83\87\83\93(&O)"
+ {
+ POPUP "\83O\83\89\83t\83B\83N\83X(&G)"
+ {
+ MENUITEM "\82È\82µ(&N)", 400
+ MENUITEM "\8b\8c\83^\83C\83\8b(&O)", 401
+ MENUITEM "&Adam Bolt\82³\82ñ\83^\83C\83\8b", 402
+ MENUITEM "\90V\83^\83C\83\8b", 403
+ MENUITEM "\83^\83C\83\8b\82ð2\94{\95\9d\82Å\95\\8e¦", 409
+ }
+ MENUITEM "BGM(&M)", 411
+ MENUITEM "\8cø\89Ê\89¹(&S)", 410
+ MENUITEM "\95Ç\8e\86\82ð\8eg\82¤(&B)", 440
+ MENUITEM "\95Ç\8e\86\82ð\91I\91ð(&O)...", 441
+ MENUITEM "\89æ\96Ê\82ðHTML\82Å\95Û\91¶(&H)...", 450
+ /* MENUITEM "\92n\90}(&M)", 430 */
+ /* MENUITEM SEPARATOR
+ MENUITEM "\96¢\8eg\97p", 410
+ MENUITEM "\96¢\8eg\97p", 411*/
+ }
+
+ /*
+ POPUP "\83w\83\8b\83v(&H)"
+ {
+ MENUITEM "\88ê\94Ê(&G)", 901
+ MENUITEM "\83X\83|\83C\83\89\81[(&S)", 902
+ }
+ */
+}
+
+ANGBAND ICON "angband.ico"
+
+ANGBAND BITMAP "wall.bmp"
/* File: angband.rc */
-
-ANGBAND MENU
-{
- POPUP "\83t\83@\83C\83\8b(&F)"
- {
- MENUITEM "\90V\8bK(&N)", 100
- MENUITEM "\8aJ\82(&O)...", 101
- MENUITEM SEPARATOR
- MENUITEM "\95Û\91¶(&S)", 110
- MENUITEM SEPARATOR
- MENUITEM "\83X\83R\83A(&C)", 120
- MENUITEM "\83\80\81[\83r\81[(&M)", 121
- MENUITEM SEPARATOR
- MENUITEM "\8fI\97¹(&X)", 130
- }
-
- POPUP "\83E\83B\83\93\83h\83E(&W)"
- {
- POPUP "\95\\8e¦(&V)"
- {
- MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 200
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 201
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 202
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 203
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 204
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 205
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 206
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 207
- }
-
- POPUP "\83t\83H\83\93\83g(&F)"
- {
- MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 210
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 211
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 212
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 213
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 214
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 215
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 216
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 217
- }
-
- POPUP "\91O\96Ê\82É\8cÅ\92è"
- {
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 221
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 222
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 223
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 224
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 225
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 226
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 227
- }
-
- MENUITEM "\8fí\82É\83T\83u\83E\83B\83\93\83h\83E\82ð\95\\8e¦(&K)", 280
-
- MENUITEM SEPARATOR
-
- /* POPUP "Bizarre Display"
- {
- MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 230
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 231
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 232
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 233
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 234
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 235
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 236
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 237
- }
- */
-
- POPUP "\83^\83C\83\8b\82Ì\95\9d\82ð\8dL\82°\82é"
- {
- MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 240
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 241
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 242
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 243
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 244
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 245
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 246
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 247
- }
-
- POPUP "\83^\83C\83\8b\82Ì\95\9d\82ð\8fk\82ß\82é"
- {
- MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 250
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 251
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 252
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 253
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 254
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 255
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 256
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 257
- }
-
- POPUP "\83^\83C\83\8b\82Ì\8d\82\82³\82ð\8dL\82°\82é"
- {
- MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 260
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 261
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 262
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 263
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 264
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 265
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 266
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 267
- }
-
- POPUP "\83^\83C\83\8b\82Ì\8d\82\82³\82ð\8fk\82ß\82é"
- {
- MENUITEM "\83\81\83C\83\93\83E\83B\83\93\83h\83E", 270
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 1", 271
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 2", 272
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 3", 273
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 4", 274
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 5", 275
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 6", 276
- MENUITEM "\83T\83u\83E\83B\83\93\83h\83E 7", 277
- }
- }
-
- POPUP "\83I\83v\83V\83\87\83\93(&O)"
- {
- POPUP "\83O\83\89\83t\83B\83N\83X(&G)"
- {
- MENUITEM "\82È\82µ(&N)", 400
- MENUITEM "\8b\8c\83^\83C\83\8b(&O)", 401
- MENUITEM "&Adam Bolt\82³\82ñ\83^\83C\83\8b", 402
- MENUITEM "\90V\83^\83C\83\8b", 403
- MENUITEM "\83^\83C\83\8b\82ð2\94{\95\9d\82Å\95\\8e¦", 409
- }
- MENUITEM "BGM(&M)", 411
- MENUITEM "\8cø\89Ê\89¹(&S)", 410
- MENUITEM "\95Ç\8e\86\82ð\8eg\82¤(&B)", 440
- MENUITEM "\95Ç\8e\86\82ð\91I\91ð(&O)...", 441
- MENUITEM "\89æ\96Ê\82ðHTML\82Å\95Û\91¶(&H)...", 450
- /* MENUITEM "\92n\90}(&M)", 430 */
- /* MENUITEM SEPARATOR
- MENUITEM "\96¢\8eg\97p", 410
- MENUITEM "\96¢\8eg\97p", 411*/
- }
-
- /*
- POPUP "\83w\83\8b\83v(&H)"
- {
- MENUITEM "\88ê\94Ê(&G)", 901
- MENUITEM "\83X\83|\83C\83\89\81[(&S)", 902
- }
- */
-}
-
-ANGBAND ICON "angband.ico"
-
-ANGBAND BITMAP "wall.bmp"
+#ifdef JP
+#include "ang_jp.rc"
+#else
+#include "ang_eng.rc"
+#endif
static concptr get_random_art_filename(const bool armour, const int power)
{
concptr filename;
- switch (armour) {
- case 1:
+ if (armour) {
switch (power) {
case 0:
filename = _("a_cursed_j.txt", "a_cursed.txt");
default:
filename = _("a_high_j.txt", "a_high.txt");
}
- break;
- default:
+ } else {
switch (power) {
case 0:
filename = _("w_cursed_j.txt", "w_cursed.txt");
o_ptr->artifact_bias = BIAS_MAGE;
else
o_ptr->artifact_bias = BIAS_ROGUE;
-
+ break;
+ case CLASS_ELEMENTALIST:
+ o_ptr->artifact_bias = one_in_(2) ? BIAS_MAGE : BIAS_INT;
+ break;
+
+ case MAX_CLASS:
break;
}
}
-#include "autopick/autopick-editor-util.h"
+#include <cstdlib>
+
+#include "autopick/autopick-editor-util.h"
#include "autopick/autopick-flags-table.h"
#include "autopick/autopick-methods-table.h"
#include "autopick/autopick-dirty-flags.h"
static chain_str_type *new_chain_str(concptr str)
{
- chain_str_type *chain;
size_t len = strlen(str);
- chain = (chain_str_type *)ralloc(sizeof(chain_str_type) + len * sizeof(char));
+ auto *chain = static_cast<chain_str_type *>(std::malloc(sizeof(chain_str_type) + len * sizeof(char)));
strcpy(chain->s, str);
chain->next = NULL;
return chain;
while (chain)
{
chain_str_type *next = chain->next;
- size_t len = strlen(chain->s);
- rnfree(chain, sizeof(chain_str_type) + len * sizeof(char));
+ std::free(chain);
chain = next;
}
}
/* free list of pointers */
- C_FREE((vptr)lines_list, MAX_LINES, concptr);
+ C_FREE(lines_list, MAX_LINES, concptr);
}
_("スナイパーは一撃必殺を狙う恐るべき射手です。精神を高めることにより、射撃の威力と精度を高めます。また、魔法を使うことはできませんが、研ぎ澄まされた精神から繰り出される射撃術はさらなる威力をもたらすことでしょう。テクニックが必要とされる職業です。",
"Snipers are good at shooting, and they can kill targets by a few shots. After they concentrate deeply, they can demonstrate their shooting talents. You can see the incredible firepower of their shots."),
+
+ _("元素使いはエレメンタルの力を駆使して戦う魔法使いです。扱える属性は限られますが、その力を十二分に引き出すことができます。魔法に必要な能力は賢さです。",
+ "An Elementalist is a spell caster that specializes in tapping elemental forces. They have a limited, but powerful, repertoire of spells. Wisdom determines an Elementalist's spell casting ability.")
};
/*! 性格の解説メッセージテーブル */
#include "birth/birth-util.h"
#include "core/asking-player.h"
#include "io/input-key-acceptor.h"
+#include "mind/mind-elementalist.h"
#include "player/player-realm.h"
#include "term/screen-processor.h"
#include "term/term-color-types.h"
/* Select the first realm */
creature_ptr->realm1 = REALM_NONE;
creature_ptr->realm2 = REALM_SELECT_CANCEL;
- while (TRUE) {
- char temp[80 * 10];
- int count = 0;
- creature_ptr->realm1 = select_realm(creature_ptr, realm_choices1[creature_ptr->pclass], &count);
+ if (creature_ptr->pclass == CLASS_ELEMENTALIST) {
+ creature_ptr->realm1 = select_element_realm(creature_ptr);
if (creature_ptr->realm1 == REALM_SELECT_CANCEL)
return FALSE;
- if (!creature_ptr->realm1)
- break;
-
- cleanup_realm_selection_window();
- shape_buffer(realm_explanations[technic2magic(creature_ptr->realm1) - 1], 74, temp, sizeof(temp));
- concptr t = temp;
- for (int i = 0; i < 10; i++) {
- if (t[0] == 0)
+ }
+ else
+ while (TRUE) {
+ char temp[80 * 10];
+ int count = 0;
+ creature_ptr->realm1 = select_realm(creature_ptr, realm_choices1[creature_ptr->pclass], &count);
+ if (creature_ptr->realm1 == REALM_SELECT_CANCEL)
+ return FALSE;
+ if (!creature_ptr->realm1)
break;
- else {
- prt(t, 12 + i, 3);
- t += strlen(t) + 1;
+
+ cleanup_realm_selection_window();
+ shape_buffer(realm_explanations[technic2magic(creature_ptr->realm1) - 1], 74, temp, sizeof(temp));
+ concptr t = temp;
+ for (int i = 0; i < 10; i++) {
+ if (t[0] == 0)
+ break;
+ else {
+ prt(t, 12 + i, 3);
+ t += strlen(t) + 1;
+ }
}
- }
- if (check_realm_selection(creature_ptr, count))
- break;
- }
+ if (check_realm_selection(creature_ptr, count))
+ break;
+ }
/* Select the second realm */
creature_ptr->realm2 = REALM_NONE;
/* Print the realm */
put_str(_("魔法 :", "Magic :"), 6, 1);
- c_put_str(TERM_L_BLUE, realm_names[creature_ptr->realm1], 6, 15);
+ if (creature_ptr->pclass == CLASS_ELEMENTALIST)
+ c_put_str(TERM_L_BLUE, get_element_title(creature_ptr->realm1), 6, 15);
+ else
+ c_put_str(TERM_L_BLUE, realm_names[creature_ptr->realm1], 6, 15);
/* Select the second realm */
while (TRUE) {
}
/*!
+ * @brief 経験値修正の合計値を計算
+ * @return なし
+ */
+u16b get_expfact(player_type *creature_ptr)
+{
+ u16b expfact = rp_ptr->r_exp;
+
+ if (creature_ptr->prace != RACE_ANDROID)
+ expfact += cp_ptr->c_exp;
+ if (((creature_ptr->pclass == CLASS_MONK) || (creature_ptr->pclass == CLASS_FORCETRAINER) || (creature_ptr->pclass == CLASS_NINJA))
+ && ((creature_ptr->prace == RACE_KLACKON) || (creature_ptr->prace == RACE_SPRITE)))
+ expfact -= 15;
+
+ return expfact;
+}
+
+/*!
* @brief その他「オートローラ中は算出の対象にしない」副次ステータスを処理する / Roll for some info that the auto-roller ignores
* @return なし
*/
void get_extra(player_type* creature_ptr, bool roll_hitdie)
{
- if (creature_ptr->prace == RACE_ANDROID)
- creature_ptr->expfact = rp_ptr->r_exp;
- else
- creature_ptr->expfact = rp_ptr->r_exp + cp_ptr->c_exp;
-
- if (((creature_ptr->pclass == CLASS_MONK) || (creature_ptr->pclass == CLASS_FORCETRAINER) || (creature_ptr->pclass == CLASS_NINJA)) && ((creature_ptr->prace == RACE_KLACKON) || (creature_ptr->prace == RACE_SPRITE)))
- creature_ptr->expfact -= 15;
+ creature_ptr->expfact = get_expfact(creature_ptr);
/* Reset record of race/realm changes */
creature_ptr->start_race = creature_ptr->prace;
int adjust_stat(int value, int amount);
void get_stats(player_type* creature_ptr);
-void get_extra(player_type* creature_ptr, bool roll_hitdie);
+u16b get_expfact(player_type *creature_ptr);
+void get_extra(player_type *creature_ptr, bool roll_hitdie);
void get_max_stats(player_type* creature_ptr);
static void display_initial_options(player_type *creature_ptr)
{
+ u16b expfact = get_expfact(creature_ptr) - 100;
s16b adj[A_MAX];
for (int i = 0; i < A_MAX; i++) {
adj[i] = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
put_str(" ", 3, 40);
put_str(_("修正の合計値", "Your total modification"), 3, 40);
put_str(_("腕力 知能 賢さ 器用 耐久 魅力 経験 ", "Str Int Wis Dex Con Chr EXP "), 4, 40);
- sprintf(buf, "%+3d %+3d %+3d %+3d %+3d %+3d %+4d%% ", adj[0], adj[1], adj[2], adj[3], adj[4], adj[5], cp_ptr->c_exp);
+ sprintf(buf, "%+3d %+3d %+3d %+3d %+3d %+3d %+4d%% ", adj[0], adj[1], adj[2], adj[3], adj[4], adj[5], expfact);
c_put_str(TERM_L_BLUE, buf, 5, 40);
put_str("HD ", 6, 40);
string_free(creature_ptr->last_message);
if (creature_ptr->inventory_list != NULL)
- C_WIPE(creature_ptr->inventory_list, INVEN_TOTAL, object_type);
+ C_KILL(creature_ptr->inventory_list, INVEN_TOTAL, object_type);
(void)WIPE(creature_ptr, player_type);
* @param creature_ptr プレーヤーへの参照ポインタ
* @return なし
* @details アンデッド系種族は開始時刻を夜からにする / Undead start just sunset
- * @details
+ * @details
*/
void init_turn(player_type *creature_ptr)
{
{ TV_SOFT_ARMOR, SV_SOFT_LEATHER_ARMOR },
{ TV_SWORD, SV_DAGGER }
},
+
+ { /* Elementalist */
+ { TV_POTION, SV_POTION_SPEED },
+ { TV_RING, SV_RING_SUSTAIN_WIS },
+ { TV_SWORD, SV_DAGGER }
+ },
};
object_prep(creature_ptr, q_ptr, lookup_kind(TV_ARROW, SV_AMMO_NORMAL));
q_ptr->number = (ITEM_NUMBER)rand_range(15, 20);
add_outfit(creature_ptr, q_ptr);
- } else if (creature_ptr->pclass == CLASS_HIGH_MAGE) {
+ } else if (creature_ptr->pclass == CLASS_HIGH_MAGE || creature_ptr->pclass == CLASS_ELEMENTALIST) {
object_prep(creature_ptr, q_ptr, lookup_kind(TV_WAND, SV_WAND_MAGIC_MISSILE));
q_ptr->number = 1;
q_ptr->pval = (PARAMETER_VALUE)rand_range(25, 30);
#include "view/display-messages.h"
/*!
- * @brief モンスター特技がラーニング可能かどうかを返す
- * @param ms_type モンスター特技ID
- */
-bool monster_spell_is_learnable(const int monspell)
-{
- switch (monspell) {
- case MS_DISPEL:
- case MS_ROCKET:
- case MS_SHOOT:
- case MS_BR_ACID:
- case MS_BR_ELEC:
- case MS_BR_FIRE:
- case MS_BR_COLD:
- case MS_BR_POIS:
- case MS_BR_NETHER:
- case MS_BR_LITE:
- case MS_BR_DARK:
- case MS_BR_CONF:
- case MS_BR_SOUND:
- case MS_BR_CHAOS:
- case MS_BR_DISEN:
- case MS_BR_NEXUS:
- case MS_BR_TIME:
- case MS_BR_INERTIA:
- case MS_BR_GRAVITY:
- case MS_BR_SHARDS:
- case MS_BR_PLASMA:
- case MS_BR_FORCE:
- case MS_BR_MANA:
- case MS_BALL_NUKE:
- case MS_BR_NUKE:
- case MS_BALL_CHAOS:
- case MS_BR_DISI:
- case MS_BALL_ACID:
- case MS_BALL_ELEC:
- case MS_BALL_FIRE:
- case MS_BALL_COLD:
- case MS_BALL_POIS:
- case MS_BALL_NETHER:
- case MS_BALL_WATER:
- case MS_BALL_MANA:
- case MS_BALL_DARK:
- case MS_DRAIN_MANA:
- case MS_MIND_BLAST:
- case MS_BRAIN_SMASH:
- case MS_CAUSE_1:
- case MS_CAUSE_2:
- case MS_CAUSE_3:
- case MS_CAUSE_4:
- case MS_BOLT_ACID:
- case MS_BOLT_ELEC:
- case MS_BOLT_FIRE:
- case MS_BOLT_COLD:
- case MS_STARBURST:
- case MS_BOLT_NETHER:
- case MS_BOLT_WATER:
- case MS_BOLT_MANA:
- case MS_BOLT_PLASMA:
- case MS_BOLT_ICE:
- case MS_MAGIC_MISSILE:
- case MS_SCARE:
- case MS_BLIND:
- case MS_CONF:
- case MS_SLOW:
- case MS_SLEEP:
- case MS_HAND_DOOM:
- case MS_TELE_TO:
- case MS_TELE_AWAY:
- case MS_PSY_SPEAR:
- case MS_DARKNESS:
- case MS_MAKE_TRAP:
- case MS_FORGET:
- case MS_S_KIN:
- case MS_S_CYBER:
- case MS_S_MONSTER:
- case MS_S_MONSTERS:
- case MS_S_ANT:
- case MS_S_SPIDER:
- case MS_S_HOUND:
- case MS_S_HYDRA:
- case MS_S_ANGEL:
- case MS_S_DEMON:
- case MS_S_UNDEAD:
- case MS_S_DRAGON:
- case MS_S_HI_UNDEAD:
- case MS_S_HI_DRAGON:
- case MS_S_AMBERITE:
- case MS_S_UNIQUE:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-/*!
* @brief 青魔法のラーニング判定と成功した場合のラーニング処理
* @param monspell ラーニングを試みるモンスター攻撃のID
* @return なし
enum blue_magic_type : int;
-bool monster_spell_is_learnable(int monspell);
void learn_spell(player_type *learner_ptr, int monspell);
void set_rf_masks(BIT_FLAGS *f4, BIT_FLAGS *f5, BIT_FLAGS *f6, blue_magic_type mode);
creature_ptr->is_dead = TRUE;
creature_ptr->leaving = TRUE;
if (!current_world_ptr->total_winner) {
+ play_music(TERM_XTRA_MUSIC_BASIC, MUSIC_BASIC_GAMEOVER);
exe_write_diary(creature_ptr, DIARY_DESCRIPTION, 0, _("ダンジョンの探索に絶望して自殺した。", "gave up all hope to commit suicide."));
exe_write_diary(creature_ptr, DIARY_GAMESTART, 1, _("-------- ゲームオーバー --------", "-------- Game Over --------"));
exe_write_diary(creature_ptr, DIARY_DESCRIPTION, 1, "\n\n\n\n");
powers[num++] = PET_TWO_HANDS;
}
break;
+
+ default:
+ break;
}
}
}
int sel_monster;
bool reinit_wilderness = FALSE;
-MONSTER_IDX today_mon;
/*!
* @brief 町に関するヘルプを表示する / Display town history
#pragma once
-#include "system/angband.h"
#include "object/tval-types.h"
+#include "system/angband.h"
+// clang-format off
#define BUILDING_NON_MEMBER 0 /*!< 不明(現在未使用) */
#define BUILDING_MEMBER 1 /*!< 不明(現在未使用) */
#define BUILDING_OWNER 2 /*!< 施設の種族/職業条件が一致している状態値 */
+// clang-format on
/*
* Arena constants
#define ARENA_DEFEATED_OLD_VER (-(MAX_SHORT)) /*<! 旧バージョンの闘技場敗北定義 */
extern bool reinit_wilderness;
-extern MONRACE_IDX today_mon;
extern u32b mon_odds[4];
extern int battle_odds;
}
+#ifdef JP
static bool is_player_undead(player_type *customer_ptr)
{
bool is_player_undead = is_specific_player_race(customer_ptr, RACE_SKELETON) ||
is_specific_player_race(customer_ptr, RACE_SPECTRE);
return is_player_undead;
}
+#endif
/*!
temp[0] = 0;
return;
}
- sprintf(buf, _("名前:%sにマッチ", "Monsters with a name \"%s\""), temp);
+ sprintf(buf, _("名前:%sにマッチ", "Monsters' names with \"%s\""), temp);
} else if (ident_info[i]) {
sprintf(buf, "%c - %s.", sym, ident_info[i] + 2);
} else {
{
if (!pat || !act)
return -1;
+ if (strlen(pat) == 0 || strlen(act) == 0)
+ return -1;
int n = macro_find_exact(pat);
if (n >= 0) {
#include "view/object-describer.h"
/*!
- * @brief 食料を食べるコマンドのサブルーチン
- * @param item 食べるオブジェクトの所持品ID
- * @return なし
+ * @brief 食料タイプの食料を食べたときの効果を発動
+ * @param creature_ptr プレイヤー情報への参照ポインタ
+ * @param o_ptr 食べるオブジェクト
+ * @return 鑑定されるならTRUE、されないならFALSE
*/
-void exe_eat_food(player_type *creature_ptr, INVENTORY_IDX item)
+bool exe_eat_food_type_object(player_type *creature_ptr, object_type *o_ptr)
{
- int ident, lev;
- object_type *o_ptr;
-
- if (music_singing_any(creature_ptr))
- stop_singing(creature_ptr);
- if (hex_spelling_any(creature_ptr))
- stop_hex_spell_all(creature_ptr);
- o_ptr = ref_item(creature_ptr, item);
-
- sound(SOUND_EAT);
-
- take_turn(creature_ptr, 100);
-
- /* Identity not known yet */
- ident = FALSE;
-
- /* Object level */
- lev = k_info[o_ptr->k_idx].level;
-
- if (o_ptr->tval == TV_FOOD) {
- /* Analyze the food */
- switch (o_ptr->sval) {
- case SV_FOOD_POISON: {
- if (!(has_resist_pois(creature_ptr) || is_oppose_pois(creature_ptr))) {
- if (set_poisoned(creature_ptr, creature_ptr->poisoned + randint0(10) + 10)) {
- ident = TRUE;
- }
- }
- break;
- }
-
- case SV_FOOD_BLINDNESS: {
- if (!has_resist_blind(creature_ptr)) {
- if (set_blind(creature_ptr, creature_ptr->blind + randint0(200) + 200)) {
- ident = TRUE;
- }
- }
- break;
- }
-
- case SV_FOOD_PARANOIA: {
- if (!has_resist_fear(creature_ptr)) {
- if (set_afraid(creature_ptr, creature_ptr->afraid + randint0(10) + 10)) {
- ident = TRUE;
- }
- }
- break;
- }
-
- case SV_FOOD_CONFUSION: {
- if (!has_resist_conf(creature_ptr)) {
- if (set_confused(creature_ptr, creature_ptr->confused + randint0(10) + 10)) {
- ident = TRUE;
- }
- }
- break;
- }
+ if (o_ptr->tval != TV_FOOD)
+ return FALSE;
+
+ switch (o_ptr->sval) {
+ case SV_FOOD_POISON:
+ if (!(has_resist_pois(creature_ptr) || is_oppose_pois(creature_ptr)))
+ if (set_poisoned(creature_ptr, creature_ptr->poisoned + randint0(10) + 10))
+ return TRUE;
+ break;
+ case SV_FOOD_BLINDNESS:
+ if (!has_resist_blind(creature_ptr))
+ if (set_blind(creature_ptr, creature_ptr->blind + randint0(200) + 200))
+ return TRUE;
+ break;
+ case SV_FOOD_PARANOIA:
+ if (!has_resist_fear(creature_ptr))
+ if (set_afraid(creature_ptr, creature_ptr->afraid + randint0(10) + 10))
+ return TRUE;
+ break;
+ case SV_FOOD_CONFUSION:
+ if (!has_resist_conf(creature_ptr))
+ if (set_confused(creature_ptr, creature_ptr->confused + randint0(10) + 10))
+ return TRUE;
+ break;
+ case SV_FOOD_HALLUCINATION:
+ if (!has_resist_chaos(creature_ptr))
+ if (set_image(creature_ptr, creature_ptr->image + randint0(250) + 250))
+ return TRUE;
+ break;
+ case SV_FOOD_PARALYSIS:
+ if (!creature_ptr->free_act)
+ if (set_paralyzed(creature_ptr, creature_ptr->paralyzed + randint0(10) + 10))
+ return TRUE;
+ break;
+ case SV_FOOD_WEAKNESS:
+ take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1);
+ (void)do_dec_stat(creature_ptr, A_STR);
+ return TRUE;
+ case SV_FOOD_SICKNESS:
+ take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1);
+ (void)do_dec_stat(creature_ptr, A_CON);
+ return TRUE;
+ case SV_FOOD_STUPIDITY:
+ take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1);
+ (void)do_dec_stat(creature_ptr, A_INT);
+ return TRUE;
+ case SV_FOOD_NAIVETY:
+ take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1);
+ (void)do_dec_stat(creature_ptr, A_WIS);
+ return TRUE;
+ case SV_FOOD_UNHEALTH:
+ take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1);
+ (void)do_dec_stat(creature_ptr, A_CON);
+ return TRUE;
+ case SV_FOOD_DISEASE:
+ take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1);
+ (void)do_dec_stat(creature_ptr, A_STR);
+ return TRUE;
+ case SV_FOOD_CURE_POISON:
+ if (set_poisoned(creature_ptr, 0))
+ return TRUE;
+ break;
+ case SV_FOOD_CURE_BLINDNESS:
+ if (set_blind(creature_ptr, 0))
+ return TRUE;
+ break;
+ case SV_FOOD_CURE_PARANOIA:
+ if (set_afraid(creature_ptr, 0))
+ return TRUE;
+ break;
+ case SV_FOOD_CURE_CONFUSION:
+ if (set_confused(creature_ptr, 0))
+ return TRUE;
+ break;
+ case SV_FOOD_CURE_SERIOUS:
+ return cure_serious_wounds(creature_ptr, 4, 8);
+ case SV_FOOD_RESTORE_STR:
+ if (do_res_stat(creature_ptr, A_STR))
+ return TRUE;
+ break;
+ case SV_FOOD_RESTORE_CON:
+ if (do_res_stat(creature_ptr, A_CON))
+ return TRUE;
+ break;
+ case SV_FOOD_RESTORING:
+ return restore_all_status(creature_ptr);
+#ifdef JP
+ /* それぞれの食べ物の感想をオリジナルより細かく表現 */
+ case SV_FOOD_BISCUIT:
+ msg_print("甘くてサクサクしてとてもおいしい。");
+ return TRUE;
+ case SV_FOOD_JERKY:
+ msg_print("歯ごたえがあっておいしい。");
+ return TRUE;
+ case SV_FOOD_SLIME_MOLD:
+ msg_print("これはなんとも形容しがたい味だ。");
+ return TRUE;
+ case SV_FOOD_RATION:
+ msg_print("これはおいしい。");
+ return TRUE;
+#else
+ case SV_FOOD_RATION:
+ case SV_FOOD_BISCUIT:
+ case SV_FOOD_JERKY:
+ case SV_FOOD_SLIME_MOLD:
+ msg_print("That tastes good.");
+ return TRUE;
+#endif
+ case SV_FOOD_WAYBREAD:
+ msg_print(_("これはひじょうに美味だ。", "That tastes good."));
+ (void)set_poisoned(creature_ptr, 0);
+ (void)hp_player(creature_ptr, damroll(4, 8));
+ return TRUE;
+ case SV_FOOD_PINT_OF_ALE:
+ case SV_FOOD_PINT_OF_WINE:
+ msg_print(_("のどごし爽やかだ。", "That tastes good."));
+ return TRUE;
+ }
- case SV_FOOD_HALLUCINATION: {
- if (!has_resist_chaos(creature_ptr)) {
- if (set_image(creature_ptr, creature_ptr->image + randint0(250) + 250)) {
- ident = TRUE;
- }
- }
- break;
- }
+ return FALSE;
+}
- case SV_FOOD_PARALYSIS: {
- if (!creature_ptr->free_act) {
- if (set_paralyzed(creature_ptr, creature_ptr->paralyzed + randint0(10) + 10)) {
- ident = TRUE;
- }
- }
- break;
- }
+/*!
+ * @brief 魔法道具のチャージをの食料として食べたときの効果を発動
+ * @param creature_ptr プレイヤー情報への参照ポインタ
+ * @param o_ptr 食べるオブジェクト
+ * @param item オブジェクトのインベントリ番号
+ * @return 食べようとしたらTRUE、しなかったらFALSE
+ */
+bool exe_eat_charge_of_magic_device(player_type *creature_ptr, object_type *o_ptr, INVENTORY_IDX item)
+{
+ if (o_ptr->tval != TV_STAFF && o_ptr->tval != TV_WAND)
+ return FALSE;
- case SV_FOOD_WEAKNESS: {
- take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1);
- (void)do_dec_stat(creature_ptr, A_STR);
- ident = TRUE;
- break;
- }
+ if (is_specific_player_race(creature_ptr, RACE_SKELETON) || is_specific_player_race(creature_ptr, RACE_GOLEM)
+ || is_specific_player_race(creature_ptr, RACE_ZOMBIE) || is_specific_player_race(creature_ptr, RACE_SPECTRE)) {
+ concptr staff;
- case SV_FOOD_SICKNESS: {
- take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1);
- (void)do_dec_stat(creature_ptr, A_CON);
- ident = TRUE;
- break;
+ if (o_ptr->tval == TV_STAFF && (item < 0) && (o_ptr->number > 1)) {
+ msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));
+ return TRUE;
}
- case SV_FOOD_STUPIDITY: {
- take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1);
- (void)do_dec_stat(creature_ptr, A_INT);
- ident = TRUE;
- break;
- }
+ staff = (o_ptr->tval == TV_STAFF) ? _("杖", "staff") : _("魔法棒", "wand");
- case SV_FOOD_NAIVETY: {
- take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1);
- (void)do_dec_stat(creature_ptr, A_WIS);
- ident = TRUE;
- break;
+ /* "Eat" charges */
+ if (o_ptr->pval == 0) {
+ msg_format(_("この%sにはもう魔力が残っていない。", "The %s has no charges left."), staff);
+ o_ptr->ident |= (IDENT_EMPTY);
+ creature_ptr->window_flags |= (PW_INVEN);
+ return TRUE;
}
- case SV_FOOD_UNHEALTH: {
- take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1);
- (void)do_dec_stat(creature_ptr, A_CON);
- ident = TRUE;
- break;
- }
+ msg_format(_("あなたは%sの魔力をエネルギー源として吸収した。", "You absorb mana of the %s as your energy."), staff);
- case SV_FOOD_DISEASE: {
- take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1);
- (void)do_dec_stat(creature_ptr, A_STR);
- ident = TRUE;
- break;
- }
+ /* Use a single charge */
+ o_ptr->pval--;
- case SV_FOOD_CURE_POISON: {
- if (set_poisoned(creature_ptr, 0))
- ident = TRUE;
- break;
- }
+ /* Eat a charge */
+ set_food(creature_ptr, creature_ptr->food + 5000);
- case SV_FOOD_CURE_BLINDNESS: {
- if (set_blind(creature_ptr, 0))
- ident = TRUE;
- break;
- }
+ /* XXX Hack -- unstack if necessary */
+ if (o_ptr->tval == TV_STAFF && (item >= 0) && (o_ptr->number > 1)) {
+ object_type forge;
+ object_type *q_ptr;
+ q_ptr = &forge;
+ object_copy(q_ptr, o_ptr);
- case SV_FOOD_CURE_PARANOIA: {
- if (set_afraid(creature_ptr, 0))
- ident = TRUE;
- break;
- }
+ /* Modify quantity */
+ q_ptr->number = 1;
- case SV_FOOD_CURE_CONFUSION: {
- if (set_confused(creature_ptr, 0))
- ident = TRUE;
- break;
- }
+ /* Restore the charges */
+ o_ptr->pval++;
- case SV_FOOD_CURE_SERIOUS: {
- ident = cure_serious_wounds(creature_ptr, 4, 8);
- break;
- }
+ /* Unstack the used item */
+ o_ptr->number--;
+ item = store_item_to_inventory(creature_ptr, q_ptr);
- case SV_FOOD_RESTORE_STR: {
- if (do_res_stat(creature_ptr, A_STR))
- ident = TRUE;
- break;
+ msg_format(_("杖をまとめなおした。", "You unstack your staff."));
}
- case SV_FOOD_RESTORE_CON: {
- if (do_res_stat(creature_ptr, A_CON))
- ident = TRUE;
- break;
+ if (item >= 0) {
+ inven_item_charges(creature_ptr, item);
+ } else {
+ floor_item_charges(creature_ptr->current_floor_ptr, 0 - item);
}
- case SV_FOOD_RESTORING: {
- ident = restore_all_status(creature_ptr);
- break;
- }
+ creature_ptr->window_flags |= (PW_INVEN | PW_EQUIP);
+ return TRUE;
+ }
-#ifdef JP
- /* それぞれの食べ物の感想をオリジナルより細かく表現 */
- case SV_FOOD_BISCUIT: {
- msg_print("甘くてサクサクしてとてもおいしい。");
- ident = TRUE;
- break;
- }
+ return FALSE;
+}
- case SV_FOOD_JERKY: {
- msg_print("歯ごたえがあっておいしい。");
- ident = TRUE;
- break;
- }
+/*!
+ * @brief 食料を食べるコマンドのサブルーチン
+ * @param item 食べるオブジェクトの所持品ID
+ * @return なし
+ */
+void exe_eat_food(player_type *creature_ptr, INVENTORY_IDX item)
+{
+ if (music_singing_any(creature_ptr))
+ stop_singing(creature_ptr);
+ if (hex_spelling_any(creature_ptr))
+ stop_hex_spell_all(creature_ptr);
- case SV_FOOD_SLIME_MOLD: {
- msg_print("これはなんとも形容しがたい味だ。");
- ident = TRUE;
- break;
- }
+ object_type *o_ptr = ref_item(creature_ptr, item);
- case SV_FOOD_RATION: {
- msg_print("これはおいしい。");
- ident = TRUE;
- break;
- }
-#else
- case SV_FOOD_RATION:
- case SV_FOOD_BISCUIT:
- case SV_FOOD_JERKY:
- case SV_FOOD_SLIME_MOLD: {
- msg_print("That tastes good.");
- ident = TRUE;
- break;
- }
-#endif
+ sound(SOUND_EAT);
- case SV_FOOD_WAYBREAD: {
- msg_print(_("これはひじょうに美味だ。", "That tastes good."));
- (void)set_poisoned(creature_ptr, 0);
- (void)hp_player(creature_ptr, damroll(4, 8));
- ident = TRUE;
- break;
- }
+ take_turn(creature_ptr, 100);
- case SV_FOOD_PINT_OF_ALE: {
- msg_print(_("のどごし爽やかだ。", "That tastes good."));
- ident = TRUE;
- break;
- }
+ /* Object level */
+ int lev = k_info[o_ptr->k_idx].level;
- case SV_FOOD_PINT_OF_WINE: {
- msg_print(_("のどごし爽やかだ。", "That tastes good."));
- ident = TRUE;
- break;
- }
- }
- }
+ /* Identity not known yet */
+ int ident = exe_eat_food_type_object(creature_ptr, o_ptr);
/*
* Store what may have to be updated for the inventory (including
creature_ptr->window_flags |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
- /* Food can feed the player */
+ /* Vampires are filled only by bloods */
if (is_specific_player_race(creature_ptr, RACE_VAMPIRE) || (creature_ptr->mimic_form == MIMIC_VAMPIRE)) {
/* Reduced nutritional benefit */
(void)set_food(creature_ptr, creature_ptr->food + (o_ptr->pval / 10));
if (creature_ptr->food < PY_FOOD_ALERT) /* Hungry */
msg_print(_("あなたの飢えは新鮮な血によってのみ満たされる!", "Your hunger can only be satisfied with fresh blood!"));
- } else if ((is_specific_player_race(creature_ptr, RACE_SKELETON) || is_specific_player_race(creature_ptr, RACE_GOLEM)
- || is_specific_player_race(creature_ptr, RACE_ZOMBIE) || is_specific_player_race(creature_ptr, RACE_SPECTRE))
- && (o_ptr->tval == TV_STAFF || o_ptr->tval == TV_WAND)) {
- concptr staff;
-
- if (o_ptr->tval == TV_STAFF && (item < 0) && (o_ptr->number > 1)) {
- creature_ptr->update |= inventory_flags;
- msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));
- return;
- }
- staff = (o_ptr->tval == TV_STAFF) ? _("杖", "staff") : _("魔法棒", "wand");
-
- /* "Eat" charges */
- if (o_ptr->pval == 0) {
- msg_format(_("この%sにはもう魔力が残っていない。", "The %s has no charges left."), staff);
- o_ptr->ident |= (IDENT_EMPTY);
- creature_ptr->update |= inventory_flags;
- creature_ptr->window_flags |= (PW_INVEN);
-
- return;
- }
- msg_format(_("あなたは%sの魔力をエネルギー源として吸収した。", "You absorb mana of the %s as your energy."), staff);
-
- /* Use a single charge */
- o_ptr->pval--;
-
- /* Eat a charge */
- set_food(creature_ptr, creature_ptr->food + 5000);
- /* XXX Hack -- unstack if necessary */
- if (o_ptr->tval == TV_STAFF && (item >= 0) && (o_ptr->number > 1)) {
- object_type forge;
- object_type *q_ptr;
- q_ptr = &forge;
- object_copy(q_ptr, o_ptr);
-
- /* Modify quantity */
- q_ptr->number = 1;
-
- /* Restore the charges */
- o_ptr->pval++;
-
- /* Unstack the used item */
- o_ptr->number--;
- item = store_item_to_inventory(creature_ptr, q_ptr);
-
- msg_format(_("杖をまとめなおした。", "You unstack your staff."));
- }
-
- /* Describe charges in the pack */
- if (item >= 0) {
- inven_item_charges(creature_ptr, item);
- }
-
- /* Describe charges on the floor */
- else {
- floor_item_charges(creature_ptr->current_floor_ptr, 0 - item);
- }
+ return;
+ }
- creature_ptr->window_flags |= (PW_INVEN | PW_EQUIP);
+ /* Undeads drain recharge of magic device */
+ if (exe_eat_charge_of_magic_device(creature_ptr, o_ptr, item)) {
creature_ptr->update |= inventory_flags;
-
- /* Don't eat a staff/wand itself */
return;
}
+ /* Balrogs change humanoid corpses to energy */
if ((is_specific_player_race(creature_ptr, RACE_BALROG) || (mimic_info[creature_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_DEMON))
&& (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_CORPSE && angband_strchr("pht", r_info[o_ptr->pval].d_char))) {
- /* Drain vitality of humanoids */
GAME_TEXT o_name[MAX_NLEN];
describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
msg_format(_("%sは燃え上り灰になった。精力を吸収した気がする。", "%^s is burnt to ashes. You absorb its vitality!"), o_name);
(void)set_food(creature_ptr, PY_FOOD_MAX - 1);
- } else if (is_specific_player_race(creature_ptr, RACE_SKELETON)) {
+
+ creature_ptr->update |= inventory_flags;
+ vary_item(creature_ptr, item, -1);
+ return;
+ }
+
+ if (is_specific_player_race(creature_ptr, RACE_SKELETON)) {
if (!((o_ptr->sval == SV_FOOD_WAYBREAD) || (o_ptr->sval < SV_FOOD_BISCUIT))) {
object_type forge;
object_type *q_ptr = &forge;
|| (mimic_info[creature_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_NONLIVING)) {
msg_print(_("生者の食物はあなたにとってほとんど栄養にならない。", "The food of mortals is poor sustenance for you."));
set_food(creature_ptr, creature_ptr->food + ((o_ptr->pval) / 20));
- } else if (o_ptr->tval == TV_FOOD && o_ptr->sval == SV_FOOD_WAYBREAD) {
- /* Waybread is always fully satisfying. */
- set_food(creature_ptr, MAX(creature_ptr->food, PY_FOOD_MAX - 1));
} else {
- /* Food can feed the player */
- (void)set_food(creature_ptr, creature_ptr->food + o_ptr->pval);
+ if (o_ptr->tval == TV_FOOD && o_ptr->sval == SV_FOOD_WAYBREAD) {
+ /* Waybread is always fully satisfying. */
+ set_food(creature_ptr, MAX(creature_ptr->food, PY_FOOD_MAX - 1));
+ } else {
+ /* Food can feed the player */
+ (void)set_food(creature_ptr, creature_ptr->food + o_ptr->pval);
+ }
}
creature_ptr->update |= inventory_flags;
creature_ptr->select_ring_slot = FALSE;
break;
+
+ default:
+ break;
}
if (object_is_cursed(&creature_ptr->inventory_list[slot])) {
}
break;
}
+
+ default:
+ break;
}
/* Sniper */
mult = 150;
break;
}
+
+ default:
+ break;
}
if (mult > 150)
bool get_check_strict(player_type *player_ptr, concptr prompt, BIT_FLAGS mode)
{
char buf[80];
- if (auto_more) {
- player_ptr->window_flags |= PW_MESSAGE;
- handle_stuff(player_ptr);
- num_more = 0;
- }
-
- msg_print(NULL);
if (!rogue_like_commands)
mode &= ~CHECK_OKAY_CANCEL;
strcat(buf, "[y/n]");
}
+ if (auto_more) {
+ player_ptr->window_flags |= PW_MESSAGE;
+ handle_stuff(player_ptr);
+ num_more = 0;
+ }
+
+ msg_print(NULL);
+
prt(buf, 0, 0);
if (!(mode & CHECK_NO_HISTORY) && player_ptr->playing) {
message_add(buf);
}
if (damage) {
- damage = calc_pois_damage_rate(creature_ptr) / 100;
+ damage *= (calc_pois_damage_rate(creature_ptr) / 100);
if (creature_ptr->levitation)
damage = damage / 5;
f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name),
-1);
if (!has_resist_pois(creature_ptr))
- (void)set_poisoned(creature_ptr, creature_ptr->poisoned + 1);
+ (void)set_poisoned(creature_ptr, creature_ptr->poisoned + damage);
} else {
concptr name = f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name;
msg_format(_("%sに毒された!", "The %s poisons you!"), name);
take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, name, -1);
if (!has_resist_pois(creature_ptr))
- (void)set_poisoned(creature_ptr, creature_ptr->poisoned + 3);
+ (void)set_poisoned(creature_ptr, creature_ptr->poisoned + damage);
}
cave_no_regen = TRUE;
#include "effect/effect-monster-resist-hurt.h"
#include "effect/effect-monster-spirit.h"
#include "effect/effect-monster-util.h"
+#include "mind/mind-elementalist.h"
#include "monster-floor/monster-death.h"
#include "monster-race/monster-race-hook.h"
#include "monster-race/monster-race.h"
case GF_OLD_CONF:
case GF_OLD_POLY:
case GF_GENOCIDE:
+ case GF_E_GENOCIDE:
return PROCESS_CONTINUE;
default:
break;
#include "effect/effect-characteristics.h"
#include "effect/effect-player-switcher.h"
#include "effect/effect-player-util.h"
+#include "effect/effect-processor.h"
#include "effect/spells-effect-util.h"
#include "floor/cave.h"
#include "main/sound-definitions-table.h"
#include "system/angband.h"
-typedef bool (*project_func)(
+struct ProjectResult;
+
+using project_func = ProjectResult (*)(
player_type *caster_ptr, MONSTER_IDX who, POSITION rad, POSITION y, POSITION x, HIT_POINT dam, EFFECT_ID typ, BIT_FLAGS flag, int monspell);
bool affect_player(MONSTER_IDX who, player_type *target_ptr, concptr who_name, int r, POSITION y, POSITION x, HIT_POINT dam, EFFECT_ID typ, BIT_FLAGS flag,
* @param typ 効果属性 / Type of damage to apply to monsters (and objects)
* @param flag 効果フラグ / Extra bit flags (see PROJECT_xxxx)
* @param monspell 効果元のモンスター魔法ID
- * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the
- * projection were observed, else FALSE
*/
-bool project(player_type *caster_ptr, const MONSTER_IDX who, POSITION rad, POSITION y, POSITION x, const HIT_POINT dam, const EFFECT_ID typ, BIT_FLAGS flag,
- const int monspell)
+ProjectResult project(player_type *caster_ptr, const MONSTER_IDX who, POSITION rad, POSITION y, POSITION x, const HIT_POINT dam, const EFFECT_ID typ,
+ BIT_FLAGS flag, const int monspell)
{
int dist;
POSITION y1;
POSITION y_saver;
POSITION x_saver;
int msec = delay_factor * delay_factor * delay_factor;
- bool notice = FALSE;
bool visual = FALSE;
bool drawn = FALSE;
bool breath = FALSE;
monster_target_y = caster_ptr->y;
monster_target_x = caster_ptr->x;
+ ProjectResult res;
+
if (flag & (PROJECT_JUMP)) {
x1 = x;
y1 = y;
}
if (affect_item(caster_ptr, 0, 0, y, x, dam, GF_SEEKER))
- notice = TRUE;
+ res.notice = TRUE;
if (!is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]))
continue;
y = get_grid_y(path_g[j]);
x = get_grid_x(path_g[j]);
if (affect_monster(caster_ptr, 0, 0, y, x, dam, GF_SEEKER, flag, TRUE))
- notice = TRUE;
+ res.notice = TRUE;
if (!who && (project_m_n == 1) && !jump && (caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx > 0)) {
monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx];
if (m_ptr->ml) {
py = get_grid_y(path_g[i]);
px = get_grid_x(path_g[i]);
if (affect_monster(caster_ptr, 0, 0, py, px, dam, GF_SEEKER, flag, TRUE))
- notice = TRUE;
+ res.notice = TRUE;
if (!who && (project_m_n == 1) && !jump) {
if (caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx > 0) {
monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx];
(void)affect_feature(caster_ptr, 0, 0, py, px, dam, GF_SEEKER);
}
- return notice;
+ return res;
} else if (typ == GF_SUPER_RAY) {
int j;
int second_step = 0;
}
if (affect_item(caster_ptr, 0, 0, y, x, dam, GF_SUPER_RAY))
- notice = TRUE;
+ res.notice = TRUE;
if (!cave_has_flag_bold(caster_ptr->current_floor_ptr, y, x, FF_PROJECT)) {
if (second_step)
continue;
(void)affect_feature(caster_ptr, 0, 0, py, px, dam, GF_SUPER_RAY);
}
- return notice;
+ return res;
}
int k;
}
if (!grids)
- return FALSE;
+ return res;
if (!blind && !(flag & (PROJECT_HIDE)) && (msec > 0)) {
for (int t = 0; t <= gm_rad; t++) {
if (breath) {
int d = dist_to_line(y, x, y1, x1, by, bx);
if (affect_feature(caster_ptr, who, d, y, x, dam, typ))
- notice = TRUE;
+ res.notice = TRUE;
} else {
if (affect_feature(caster_ptr, who, dist, y, x, dam, typ))
- notice = TRUE;
+ res.notice = TRUE;
}
}
}
if (breath) {
int d = dist_to_line(y, x, y1, x1, by, bx);
if (affect_item(caster_ptr, who, d, y, x, dam, typ))
- notice = TRUE;
+ res.notice = TRUE;
} else {
if (affect_item(caster_ptr, who, dist, y, x, dam, typ))
- notice = TRUE;
+ res.notice = TRUE;
}
}
}
}
if (affect_monster(caster_ptr, who, effective_dist, y, x, dam, typ, flag, see_s_msg))
- notice = TRUE;
+ res.notice = TRUE;
}
/* Player affected one monster (without "jumping") */
}
}
- if (affect_player(who, caster_ptr, who_name, effective_dist, y, x, dam, typ, flag, monspell, project))
- notice = TRUE;
+ if (affect_player(who, caster_ptr, who_name, effective_dist, y, x, dam, typ, flag, monspell, project)) {
+ res.notice = TRUE;
+ res.affected_player = TRUE;
+ }
}
}
}
}
- return (notice);
+ return res;
}
#include "system/angband.h"
-bool project(player_type *caster_ptr, const MONSTER_IDX who, POSITION rad, POSITION y, POSITION x, const HIT_POINT dam, const EFFECT_ID typ, BIT_FLAGS flag,
- const int monspell);
+//! project() の結果。
+struct ProjectResult {
+ bool notice{ false }; //!< プレイヤー/モンスター/アイテム/地形などに何らかの効果を及ぼしたか
+ bool affected_player{ false }; //!< プレイヤーに何らかの効果を及ぼしたか(ラーニング判定用)
+
+ ProjectResult() = default;
+};
+
+ProjectResult project(player_type *caster_ptr, const MONSTER_IDX who, POSITION rad, POSITION y, POSITION x, const HIT_POINT dam, const EFFECT_ID typ,
+ BIT_FLAGS flag, const int monspell);
case TV_BOW:
describe_bow(player_ptr, flavor_ptr);
break;
+
+ default:
+ break;
}
}
case TV_SCROLL:
case TV_ROD:
return TRUE;
+
+ default:
+ break;
}
return FALSE;
}
*t = '\0';
-}
\ No newline at end of file
+}
* 2014 Deskull rearranged comment for Doxygen. \n
*/
-#include <assert.h>
+#include <algorithm>
+#include <array>
+#include <stack>
#include "dungeon/dungeon-flag-types.h"
#include "dungeon/dungeon.h"
#include "wizard/wizard-messages.h"
#include "world/world.h"
-//--------------------------------------------------------------------
-// 動的可変長配列
-//--------------------------------------------------------------------
-
-typedef struct Vec {
- size_t len;
- size_t cap;
- int *data;
-} Vec;
-
-// 容量 cap の空 Vec を返す。
-static Vec vec_with_capacity(const size_t cap)
-{
- assert(cap > 0);
-
- Vec vec = { .len = 0, .cap = cap, .data = NULL };
- vec.data = static_cast<int*>(malloc(sizeof(int) * cap));
- if (!vec.data)
- rpanic(cap);
-
- return vec;
-}
-
-// サイズ len で、全要素が init で初期化された Vec を返す。
-static Vec vec_new(const size_t len, const int init)
-{
- assert(len > 0);
-
- const size_t cap = 2 * len;
- Vec vec = vec_with_capacity(cap);
-
- vec.len = len;
- for (size_t i = 0; i < len; ++i)
- vec.data[i] = init;
-
- return vec;
-}
-
-static void vec_delete(Vec *const vec)
-{
- free(vec->data);
-
- vec->len = 0;
- vec->cap = 0;
- vec->data = NULL;
-}
-
-static size_t vec_size(const Vec *const vec) { return vec->len; }
-
-static bool vec_is_empty(const Vec *const vec) { return vec_size(vec) == 0; }
-
-static void vec_push_back(Vec *const vec, const int e)
-{
- // 容量不足になったら容量を拡張する。
- if (vec->len == vec->cap) {
- vec->cap = vec->cap > 0 ? 2 * vec->cap : 1;
- vec->data = static_cast<int*>(realloc(vec->data, sizeof(int) * vec->cap));
- if (!vec->data)
- rpanic(vec->cap);
- }
-
- vec->data[vec->len++] = e;
-}
-
-static int vec_pop_back(Vec *const vec)
-{
- assert(!vec_is_empty(vec));
-
- return vec->data[vec->len-- - 1];
-}
-
-//--------------------------------------------------------------------
-
/*!
* @brief 闘技場用のアリーナ地形を作成する / Builds the on_defeat_arena_monster after it is entered -KMW-
* @param player_ptr プレーヤーへの参照ポインタ
return has_flag(flags, FF_PERMANENT) && !has_flag(flags, FF_MOVE);
}
-static void floor_is_connected_dfs(
- const floor_type *const floor_ptr, const IsWallFunc is_wall, const int y_start, const int x_start, Vec *const stk, const Vec *const visited)
+static void floor_is_connected_dfs(const floor_type *const floor_ptr, const IsWallFunc is_wall, const int y_start, const int x_start, bool *const visited)
{
// clang-format off
static const int DY[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
const int w = floor_ptr->width;
const int start = w * y_start + x_start;
- vec_push_back(stk, start);
- visited->data[start] = 1;
+ // 深さ優先探索用のスタック。
+ // 最大フロアサイズが h=66, w=198 なので、スタックオーバーフロー防止のため再帰は使わない。
+ std::stack<int> stk;
- while (!vec_is_empty(stk)) {
- const int cur = vec_pop_back(stk);
+ stk.emplace(start);
+ visited[start] = TRUE;
+
+ while (!stk.empty()) {
+ const int cur = stk.top();
+ stk.pop();
const int y = cur / w;
const int x = cur % w;
if (y_nxt < 0 || h <= y_nxt || x_nxt < 0 || w <= x_nxt)
continue;
const int nxt = w * y_nxt + x_nxt;
- if (visited->data[nxt])
+ if (visited[nxt])
continue;
if (is_wall(floor_ptr, y_nxt, x_nxt))
continue;
- vec_push_back(stk, nxt);
- visited->data[nxt] = 1;
+ stk.emplace(nxt);
+ visited[nxt] = TRUE;
}
}
}
// 連結成分数が 0 の場合、偽を返す。
static bool floor_is_connected(const floor_type *const floor_ptr, const IsWallFunc is_wall)
{
+ static std::array<bool, MAX_HGT * MAX_WID> visited;
+
const int h = floor_ptr->height;
const int w = floor_ptr->width;
- // ヒープ上に確保したスタックを用いてDFSする。
- // 最大フロアサイズが h=66, w=198 なので、単純に再帰DFSするとスタックオーバーフローが不安。
- Vec stk = vec_with_capacity(1024);
- Vec visited = vec_new((size_t)h * (size_t)w, 0);
+ std::fill(begin(visited), end(visited), false);
+
int n_component = 0; // 連結成分数
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
const int idx = w * y + x;
- if (visited.data[idx])
+ if (visited[idx])
continue;
if (is_wall(floor_ptr, y, x))
continue;
if (++n_component >= 2)
- goto finish;
- floor_is_connected_dfs(floor_ptr, is_wall, y, x, &stk, &visited);
+ break;
+ floor_is_connected_dfs(floor_ptr, is_wall, y, x, visited.data());
}
}
-finish:
- vec_delete(&visited);
- vec_delete(&stk);
-
return n_component == 1;
}
if (!j_ptr->name1)
j_ptr->number = (byte)damroll(6, 7);
}
+
+ default:
+ break;
}
if (cheat_peek)
* 2013 Deskull Doxygen向けのコメント整理\n
*/
-#include "grid/grid.h"
+#include <queue>
+
#include "core/window-redrawer.h"
#include "dungeon/dungeon-flag-types.h"
#include "dungeon/dungeon.h"
#include "game-option/map-screen-options.h"
#include "game-option/special-options.h"
#include "grid/feature.h"
+#include "grid/grid.h"
#include "grid/object-placer.h"
#include "grid/trap.h"
#include "io/screen-util.h"
#define FAF_NO_DROP 0x02
#define FAF_CRASH_GLASS 0x04
-pos_list tmp_pos;
-
/*!
* @brief 地形状態フラグテーブル /
* The table of features' actions
*/
void update_flow(player_type *subject_ptr)
{
+ struct Point {
+ int y;
+ int x;
+ Point(const int y, const int x)
+ : y(y)
+ , x(x)
+ {
+ }
+ };
+
POSITION x, y;
DIRECTION d;
- int flow_head_grid = 1;
- int flow_tail_grid = 0;
-
- /* Paranoia -- make sure the array is empty */
- if (tmp_pos.n)
- return;
/* The last way-point is on the map */
if (subject_ptr->running && in_bounds(subject_ptr->current_floor_ptr, flow_y, flow_x)) {
flow_y = subject_ptr->y;
flow_x = subject_ptr->x;
- /* Add the player's grid to the queue */
- tmp_pos.y[0] = subject_ptr->y;
- tmp_pos.x[0] = subject_ptr->x;
+ // 幅優先探索用のキュー。
+ std::queue<Point> que;
+ que.emplace(subject_ptr->y, subject_ptr->x);
/* Now process the queue */
- while (flow_head_grid != flow_tail_grid) {
- int ty, tx;
-
+ while (!que.empty()) {
/* Extract the next entry */
- ty = tmp_pos.y[flow_tail_grid];
- tx = tmp_pos.x[flow_tail_grid];
-
- /* Forget that entry */
- if (++flow_tail_grid == TEMP_MAX)
- flow_tail_grid = 0;
+ const auto [ty, tx] = que.front();
+ que.pop();
/* Add the "children" */
for (d = 0; d < 8; d++) {
- int old_head = flow_head_grid;
byte m = subject_ptr->current_floor_ptr->grid_array[ty][tx].cost + 1;
byte n = subject_ptr->current_floor_ptr->grid_array[ty][tx].dist + 1;
- grid_type *g_ptr;
/* Child location */
y = ty + ddy_ddd[d];
if (player_bold(subject_ptr, y, x))
continue;
- g_ptr = &subject_ptr->current_floor_ptr->grid_array[y][x];
+ grid_type *g_ptr = &subject_ptr->current_floor_ptr->grid_array[y][x];
if (is_closed_door(subject_ptr, g_ptr->feat))
m += 3;
continue;
/* Enqueue that entry */
- tmp_pos.y[flow_head_grid] = y;
- tmp_pos.x[flow_head_grid] = x;
-
- /* Advance the queue */
- if (++flow_head_grid == TEMP_MAX)
- flow_head_grid = 0;
-
- /* Hack -- notice overflow by forgetting new entry */
- if (flow_head_grid == flow_tail_grid)
- flow_head_grid = old_head;
+ que.emplace(y, x);
}
}
}
* included in all such copies.
*/
-#include "system/angband.h"
#include "floor/geometry.h"
#include "spell/spells-util.h"
+#include "system/angband.h"
- /*
- * A single "grid" in a Cave
- *
- * Note that several aspects of the code restrict the actual grid
- * to a max size of 256 by 256. In partcular, locations are often
- * saved as bytes, limiting each coordinate to the 0-255 range.
- *
- * The "o_idx" and "m_idx" fields are very interesting. There are
- * many places in the code where we need quick access to the actual
- * monster or object(s) in a given grid. The easiest way to
- * do this is to simply keep the index of the monster and object
- * (if any) with the grid, but this takes 198*66*4 bytes of memory.
- * Several other methods come to mind, which require only half this
- * amound of memory, but they all seem rather complicated, and would
- * probably add enough code that the savings would be lost. So for
- * these reasons, we simply store an index into the "o_list" and
- * ">m_list" arrays, using "zero" when no monster/object is present.
- *
- * Note that "o_idx" is the index of the top object in a stack of
- * objects, using the "next_o_idx" field of objects (see below) to
- * create the singly linked list of objects. If "o_idx" is zero
- * then there are no objects in the grid.
- *
- * Note the special fields for the "MONSTER_FLOW" code.
- */
+/*
+ * A single "grid" in a Cave
+ *
+ * Note that several aspects of the code restrict the actual grid
+ * to a max size of 256 by 256. In partcular, locations are often
+ * saved as bytes, limiting each coordinate to the 0-255 range.
+ *
+ * The "o_idx" and "m_idx" fields are very interesting. There are
+ * many places in the code where we need quick access to the actual
+ * monster or object(s) in a given grid. The easiest way to
+ * do this is to simply keep the index of the monster and object
+ * (if any) with the grid, but this takes 198*66*4 bytes of memory.
+ * Several other methods come to mind, which require only half this
+ * amound of memory, but they all seem rather complicated, and would
+ * probably add enough code that the savings would be lost. So for
+ * these reasons, we simply store an index into the "o_list" and
+ * ">m_list" arrays, using "zero" when no monster/object is present.
+ *
+ * Note that "o_idx" is the index of the top object in a stack of
+ * objects, using the "next_o_idx" field of objects (see below) to
+ * create the singly linked list of objects. If "o_idx" is zero
+ * then there are no objects in the grid.
+ *
+ * Note the special fields for the "MONSTER_FLOW" code.
+ */
typedef struct grid_type {
- BIT_FLAGS info; /* Hack -- grid flags */
+ BIT_FLAGS info; /* Hack -- grid flags */
- FEAT_IDX feat; /* Hack -- feature type */
- OBJECT_IDX o_idx; /* Object in this grid */
- MONSTER_IDX m_idx; /* Monster in this grid */
+ FEAT_IDX feat; /* Hack -- feature type */
+ OBJECT_IDX o_idx; /* Object in this grid */
+ MONSTER_IDX m_idx; /* Monster in this grid */
- /*! 地形の特別な情報を保存する / Special grid info
- * 具体的な使用一覧はクエスト行き階段の移行先クエストID、
- * 各ダンジョン入口の移行先ダンジョンID、
- *
- */
- s16b special;
+ /*! 地形の特別な情報を保存する / Special grid info
+ * 具体的な使用一覧はクエスト行き階段の移行先クエストID、
+ * 各ダンジョン入口の移行先ダンジョンID、
+ *
+ */
+ s16b special;
- FEAT_IDX mimic; /* Feature to mimic */
+ FEAT_IDX mimic; /* Feature to mimic */
- byte cost; /* Hack -- cost of flowing */
- byte dist; /* Hack -- distance from player */
- byte when; /* Hack -- when cost was computed */
+ byte cost; /* Hack -- cost of flowing */
+ byte dist; /* Hack -- distance from player */
+ byte when; /* Hack -- when cost was computed */
} grid_type;
/* A structure type for terrain template of saving dungeon floor */
typedef struct grid_template_type {
- BIT_FLAGS info;
- FEAT_IDX feat;
- FEAT_IDX mimic;
- s16b special;
- u16b occurrence;
+ BIT_FLAGS info;
+ FEAT_IDX feat;
+ FEAT_IDX mimic;
+ s16b special;
+ u16b occurrence;
} grid_template_type;
/*!
* @param Y 指定Y座標
* @param X 指定X座標
*/
-#define place_rubble(F,Y,X) set_cave_feat(F,Y,X,feat_rubble)
+#define place_rubble(F, Y, X) set_cave_feat(F, Y, X, feat_rubble)
/*!
* @brief 指定座標がFLOOR属性を持ったマスかどうかを返す
* @param X 指定X座標
* @return FLOOR属性を持っているならばTRUE
*/
-#define is_floor_bold(F,Y,X) (F->grid_array[Y][X].info & CAVE_FLOOR)
-#define is_extra_bold(F,Y,X) (F->grid_array[Y][X].info & CAVE_EXTRA)
+#define is_floor_bold(F, Y, X) (F->grid_array[Y][X].info & CAVE_FLOOR)
+#define is_extra_bold(F, Y, X) (F->grid_array[Y][X].info & CAVE_EXTRA)
-#define is_inner_bold(F,Y,X) (F->grid_array[Y][X].info & CAVE_INNER)
-#define is_outer_bold(F,Y,X) (F->grid_array[Y][X].info & CAVE_OUTER)
-#define is_solid_bold(F,Y,X) (F->grid_array[Y][X].info & CAVE_SOLID)
+#define is_inner_bold(F, Y, X) (F->grid_array[Y][X].info & CAVE_INNER)
+#define is_outer_bold(F, Y, X) (F->grid_array[Y][X].info & CAVE_OUTER)
+#define is_solid_bold(F, Y, X) (F->grid_array[Y][X].info & CAVE_SOLID)
#define is_floor_grid(C) ((C)->info & CAVE_FLOOR)
#define is_extra_grid(C) ((C)->info & CAVE_EXTRA)
#define is_outer_grid(C) ((C)->info & CAVE_OUTER)
#define is_solid_grid(C) ((C)->info & CAVE_SOLID)
+// clang-format off
+
/*
* 特殊なマス状態フラグ / Special grid flags
*/
#define CAVE_MNDK 0x8000 /*!< モンスターの暗源によって暗闇になっている / Darken by monster */
/* Used only while floor generation */
-#define CAVE_FLOOR 0x0200 /*!< フロア属性のあるマス */
+#define CAVE_FLOOR 0x0200 /*!< フロア属性のあるマス */
#define CAVE_EXTRA 0x0400
#define CAVE_INNER 0x0800
#define CAVE_OUTER 0x1000
#define DOOR_GLASS_DOOR 1
#define DOOR_CURTAIN 2
+// clang-format on
+
extern bool new_player_spot(player_type *creature_ptr);
-extern pos_list tmp_pos;
extern void place_bound_perm_wall(player_type *player_ptr, grid_type *g_ptr);
extern bool is_known_trap(player_type *player_ptr, grid_type *g_ptr);
*/
bool feat_uses_special(FEAT_IDX f_idx);
-extern POSITION distance(POSITION y1, POSITION x1, POSITION y2, POSITION x2);
extern void update_local_illumination(player_type *creature_ptr, POSITION y, POSITION x);
extern bool no_lite(player_type *creature_ptr);
extern void print_rel(player_type *subject_ptr, SYMBOL_CODE c, TERM_COLOR a, POSITION y, POSITION x);
extern bool cave_monster_teleportable_bold(player_type *player_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, teleport_flags mode);
extern bool cave_player_teleportable_bold(player_type *player_ptr, POSITION y, POSITION x, teleport_flags mode);
-enum grid_bold_type
-{
- GB_FLOOR,
- GB_EXTRA,
- GB_EXTRA_PERM,
- GB_INNER,
- GB_INNER_PERM,
- GB_OUTER,
- GB_OUTER_NOPERM,
- GB_SOLID,
- GB_SOLID_PERM,
- GB_SOLID_NOPERM
+// clang-format off
+enum grid_bold_type {
+ GB_FLOOR,
+ GB_EXTRA,
+ GB_EXTRA_PERM,
+ GB_INNER,
+ GB_INNER_PERM,
+ GB_OUTER,
+ GB_OUTER_NOPERM,
+ GB_SOLID,
+ GB_SOLID_PERM,
+ GB_SOLID_NOPERM
};
+// clang-format on
void place_grid(player_type *player_ptr, grid_type *g_ptr, grid_bold_type pg_type);
bool darkened_grid(player_type *player_ptr, grid_type *g_ptr);
void add_cave_info(floor_type *floor_ptr, POSITION y, POSITION x, int cave_mask);
FEAT_IDX get_feat_mimic(grid_type *g_ptr);
+// clang-format off
+
/*
* This macro allows us to efficiently add a grid to the "lite" array,
* note that we are never called for illegal grids, or for grids which
*/
#define cave_lite_hack(F,Y,X) \
{\
- if (!((F)->grid_array[Y][X].info & (CAVE_LITE))) \
- { \
- (F)->grid_array[Y][X].info |= (CAVE_LITE); \
- (F)->lite_y[(F)->lite_n] = (Y); \
- (F)->lite_x[(F)->lite_n++] = (X); \
- } \
+ if (!((F)->grid_array[Y][X].info & (CAVE_LITE))) \
+ { \
+ (F)->grid_array[Y][X].info |= (CAVE_LITE); \
+ (F)->lite_y[(F)->lite_n] = (Y); \
+ (F)->lite_x[(F)->lite_n++] = (X); \
+ } \
}
/*
*/
#define cave_note_and_redraw_later(F,C,Y,X) \
{\
- (C)->info |= CAVE_NOTE; \
- cave_redraw_later((F), (C), (Y), (X)); \
+ (C)->info |= CAVE_NOTE; \
+ cave_redraw_later((F), (C), (Y), (X)); \
}
/*
*/
#define cave_redraw_later(F,G,Y,X) \
{\
- if (!((G)->info & CAVE_REDRAW)) \
- { \
- (G)->info |= CAVE_REDRAW; \
- (F)->redraw_y[(F)->redraw_n] = (Y); \
- (F)->redraw_x[(F)->redraw_n++] = (X); \
- } \
+ if (!((G)->info & CAVE_REDRAW)) \
+ { \
+ (G)->info |= CAVE_REDRAW; \
+ (F)->redraw_y[(F)->redraw_n] = (Y); \
+ (F)->redraw_x[(F)->redraw_n++] = (X); \
+ } \
}
/*
(F)->view_n++;}\
}
+// clang-format on
+
int count_dt(player_type *creature_ptr, POSITION *y, POSITION *x, bool (*test)(player_type *, FEAT_IDX), bool under);
if (buf[0] != 'N' && buf[0] != 'D') {
int i;
for (i = 0; buf[i]; i++) {
- head->v_extra += (byte)buf[i];
- head->v_extra ^= (1U << (i % 8));
+ head->checksum += (byte)buf[i];
+ head->checksum ^= (1U << (i % 8));
}
}
*/
static concptr get_check_sum(void)
{
- return format("%02x%02x%02x%02x%02x%02x%02x%02x%02x", f_head.v_extra, k_head.v_extra, a_head.v_extra, e_head.v_extra, r_head.v_extra, d_head.v_extra,
- m_head.v_extra, s_head.v_extra, v_head.v_extra);
+ return format("%02x%02x%02x%02x%02x%02x%02x%02x%02x", f_head.checksum, k_head.checksum, a_head.checksum, e_head.checksum, r_head.checksum, d_head.checksum,
+ m_head.checksum, s_head.checksum, v_head.checksum);
}
/*!
#include "main/sound-definitions-table.h"
#include "main/sound-of-music.h"
#include "mind/mind-blue-mage.h"
+#include "mind/mind-elementalist.h"
#include "mind/mind-magic-eater.h"
#include "mind/mind-sniper.h"
#include "mind/snipe-types.h"
if ((creature_ptr->pclass == CLASS_MINDCRAFTER) || (creature_ptr->pclass == CLASS_BERSERKER) || (creature_ptr->pclass == CLASS_NINJA)
|| (creature_ptr->pclass == CLASS_MIRROR_MASTER))
do_cmd_mind_browse(creature_ptr);
+ else if (creature_ptr->pclass == CLASS_ELEMENTALIST)
+ do_cmd_element_browse(creature_ptr);
else if (creature_ptr->pclass == CLASS_SMITH)
do_cmd_kaji(creature_ptr, TRUE);
else if (creature_ptr->pclass == CLASS_MAGIC_EATER)
msg_print(NULL);
} else if (creature_ptr->anti_magic && (creature_ptr->pclass != CLASS_BERSERKER) && (creature_ptr->pclass != CLASS_SMITH)) {
concptr which_power = _("魔法", "magic");
- if (creature_ptr->pclass == CLASS_MINDCRAFTER)
+ switch (creature_ptr->pclass) {
+ case CLASS_MINDCRAFTER:
which_power = _("超能力", "psionic powers");
- else if (creature_ptr->pclass == CLASS_IMITATOR)
+ break;
+ case CLASS_IMITATOR:
which_power = _("ものまね", "imitation");
- else if (creature_ptr->pclass == CLASS_SAMURAI)
+ break;
+ case CLASS_SAMURAI:
which_power = _("必殺剣", "hissatsu");
- else if (creature_ptr->pclass == CLASS_MIRROR_MASTER)
+ break;
+ case CLASS_MIRROR_MASTER:
which_power = _("鏡魔法", "mirror magic");
- else if (creature_ptr->pclass == CLASS_NINJA)
+ break;
+ case CLASS_NINJA:
which_power = _("忍術", "ninjutsu");
- else if (mp_ptr->spell_book == TV_LIFE_BOOK)
- which_power = _("祈り", "prayer");
+ break;
+ case CLASS_ELEMENTALIST:
+ which_power = _("元素魔法", "magic");
+ break;
+ default:
+ if (mp_ptr->spell_book == TV_LIFE_BOOK)
+ which_power = _("祈り", "prayer");
+ break;
+ }
msg_format(_("反魔法バリアが%sを邪魔した!", "An anti-magic shell disrupts your %s!"), which_power);
free_turn(creature_ptr);
if ((creature_ptr->pclass == CLASS_MINDCRAFTER) || (creature_ptr->pclass == CLASS_BERSERKER) || (creature_ptr->pclass == CLASS_NINJA)
|| (creature_ptr->pclass == CLASS_MIRROR_MASTER))
do_cmd_mind(creature_ptr);
+ else if (creature_ptr->pclass == CLASS_ELEMENTALIST)
+ do_cmd_element(creature_ptr);
else if (creature_ptr->pclass == CLASS_IMITATOR)
do_cmd_mane(creature_ptr, FALSE);
else if (creature_ptr->pclass == CLASS_MAGIC_EATER)
{
char tmp[1024];
text_to_ascii(tmp, buf + 2);
- macro_add(tmp, macro__buf);
- return 0;
+ return macro_add(tmp, macro__buf);
}
process_pref_file(player_ptr, buf, process_autopick_file_command);
sprintf(buf, "%s.prf", player_ptr->base_name);
process_pref_file(player_ptr, buf, process_autopick_file_command);
- if (player_ptr->realm1 != REALM_NONE) {
+ if (player_ptr->realm1 != REALM_NONE && player_ptr->pclass != CLASS_ELEMENTALIST) {
sprintf(buf, "%s.prf", realm_names[player_ptr->realm1]);
process_pref_file(player_ptr, buf, process_autopick_file_command);
}
histpref_buf = NULL;
return TRUE;
-}
\ No newline at end of file
+}
#include "io-dump/character-dump.h"
#include "io/inet.h"
#include "io/input-key-acceptor.h"
+#include "mind/mind-elementalist.h"
#include "player/player-class.h"
#include "player/player-personality.h"
#include "player/player-race.h"
BUF *score;
score = buf_new();
+ concptr realm1_name;
char seikakutmp[128];
char title[128];
put_version(title);
sprintf(seikakutmp, "%s ", ap_ptr->title);
#endif
+ if (creature_ptr->pclass == CLASS_ELEMENTALIST)
+ realm1_name = get_element_title(creature_ptr->realm1);
+ else
+ realm1_name = realm_names[creature_ptr->realm1];
+
buf_sprintf(score, "name: %s\n", creature_ptr->name);
buf_sprintf(score, "version: %s\n", title);
buf_sprintf(score, "score: %d\n", calc_score(creature_ptr));
buf_sprintf(score, "race: %s\n", rp_ptr->title);
buf_sprintf(score, "class: %s\n", cp_ptr->title);
buf_sprintf(score, "seikaku: %s\n", seikakutmp);
- buf_sprintf(score, "realm1: %s\n", realm_names[creature_ptr->realm1]);
+ buf_sprintf(score, "realm1: %s\n", realm1_name);
buf_sprintf(score, "realm2: %s\n", realm_names[creature_ptr->realm2]);
buf_sprintf(score, "killer: %s\n", creature_ptr->died_from);
buf_sprintf(score, "-----charcter dump-----\n");
#include "game-option/input-options.h"
#include "io/command-repeater.h"
#include "io/input-key-requester.h"
+#include "mind/mind-elementalist.h"
#include "mind/mind-sniper.h"
#include "store/home.h"
#include "store/museum.h"
if ((client_ptr->pclass == CLASS_MINDCRAFTER) || (client_ptr->pclass == CLASS_BERSERKER) || (client_ptr->pclass == CLASS_NINJA)
|| (client_ptr->pclass == CLASS_MIRROR_MASTER))
do_cmd_mind_browse(client_ptr);
+ else if (client_ptr->pclass == CLASS_ELEMENTALIST)
+ do_cmd_element_browse(client_ptr);
else if (client_ptr->pclass == CLASS_SMITH)
do_cmd_kaji(client_ptr, TRUE);
else if (client_ptr->pclass == CLASS_MAGIC_EATER)
quit(_("setgid(): 正しく許可が取れません!", "setgid(): cannot set permissions correctly!"));
}
#else
+ (void)player_ptr;
+
if (setreuid(geteuid(), getuid()) != 0) {
quit(_("setreuid(): 正しく許可が取れません!", "setreuid(): cannot set permissions correctly!"));
}
if (!open_temporary_file(&fff, file_name))
return;
- if (creature_ptr->realm1 != REALM_NONE) {
+ if (creature_ptr->realm1 != REALM_NONE && creature_ptr->pclass != CLASS_ELEMENTALIST) {
fprintf(fff, _("%sの魔法書\n", "%s Spellbook\n"), realm_names[creature_ptr->realm1]);
for (SPELL_IDX i = 0; i < 32; i++) {
const magic_type *s_ptr;
}
fprintf(fff, "\n");
- if (creature_ptr->realm1) {
+ if (creature_ptr->realm1 && creature_ptr->pclass != CLASS_ELEMENTALIST) {
shape_buffer(realm_explanations[technic2magic(creature_ptr->realm1) - 1], 78, temp, sizeof(temp));
fprintf(fff, _("魔法: %s\n", "Realm: %s\n"), realm_names[creature_ptr->realm1]);
player_ptr->equip_cnt = 0;
if (player_ptr->inventory_list != NULL)
- C_WIPE(player_ptr->inventory_list, INVEN_TOTAL, object_type);
+ C_KILL(player_ptr->inventory_list, INVEN_TOTAL, object_type);
C_MAKE(player_ptr->inventory_list, INVEN_TOTAL, object_type);
int slot = 0;
if (z_older_than(10, 0, 3))
determine_daily_bounty(creature_ptr, TRUE);
else {
- rd_s16b(&today_mon);
+ rd_s16b(¤t_world_ptr->today_mon);
rd_s16b(&creature_ptr->today_mon);
}
}
lore_ptr->p = _("歌う", "sing");
lore_ptr->pc = TERM_SLATE;
break;
+
+ case RBM_NONE:
+ case RBM_SHOOT:
+ case NB_RBM_TYPE:
+ break;
}
}
case RBE_FLAVOR:
// フレーバー打撃には何の効果もないので付加説明もない。
break;
+
+ case RBE_NONE:
+ case NB_RBE_TYPE:
+ break;
}
}
#include "term/screen-processor.h"
#include "term/term-color-types.h"
-concptr wd_he[3] = { _("それ", "it"), _("彼", "he"), _("彼女", "she") };
-concptr wd_his[3] = { _("それの", "its"), _("彼の", "his"), _("彼女の", "her") };
+const who_word_definition Who::words = {
+ { WHO_WORD_TYPE::WHO,
+ {
+ { false, { { MSEX_NONE, _("それ", "it") }, { MSEX_MALE, _("彼", "he") }, { MSEX_FEMALE, _("彼女", "she") } } },
+ { true, { { MSEX_NONE, _("それら", "they") }, { MSEX_MALE, _("彼ら", "they") }, { MSEX_FEMALE, _("彼女ら", "they") } } },
+ } },
+ { WHO_WORD_TYPE::WHOSE,
+ {
+ { false, { { MSEX_NONE, _("それの", "its") }, { MSEX_MALE, _("彼の", "his") }, { MSEX_FEMALE, _("彼女の", "her") } } },
+ { true, { { MSEX_NONE, _("それらの", "their") }, { MSEX_MALE, _("彼らの", "their") }, { MSEX_FEMALE, _("彼女らの", "their") } } },
+ } },
+ { WHO_WORD_TYPE::WHOM,
+ {
+ { false, { { MSEX_NONE, _("それ", "it") }, { MSEX_MALE, _("彼", "him") }, { MSEX_FEMALE, _("彼女", "her") } } },
+ { true, { { MSEX_NONE, _("それら", "them") }, { MSEX_MALE, _("彼ら", "them") }, { MSEX_FEMALE, _("彼女ら", "them") } } },
+ } },
+};
/*
* Prepare hook for c_roff(). It will be changed for spoiler generation in wizard1.c.
#include "system/angband.h"
#include "system/monster-race-definition.h"
+#include <string>
+#include <unordered_map>
enum monster_sex {
MSEX_NONE = 0,
typedef void (*hook_c_roff_pf)(TERM_COLOR attr, concptr str);
extern hook_c_roff_pf hook_c_roff;
-extern concptr wd_he[3];
-extern concptr wd_his[3];
-
lore_type *initialize_lore_type(lore_type *lore_ptr, MONRACE_IDX r_idx, monster_lore_mode mode);
void hooked_roff(concptr str);
+
+enum WHO_WORD_TYPE { WHO = 0, WHOSE = 1, WHOM = 2 };
+using who_word_definition = std::unordered_map<WHO_WORD_TYPE, const std::unordered_map<bool, const std::unordered_map<monster_sex, std::string>>>;
+
+class Who {
+public:
+ static const who_word_definition words;
+
+ /*!
+ * @brief 三人称主格を取得(単数のみ)
+ * @param msex モンスターの性別
+ * @return 主語
+ */
+ static concptr who(monster_sex msex)
+ {
+ return who(msex, false);
+ }
+
+ /*!
+ * @brief 三人称主格を取得
+ * @param msex モンスターの性別
+ * @param multi 複数かどうか
+ * @return 主語
+ */
+ static concptr who(monster_sex msex, bool multi)
+ {
+ return words.at(WHO_WORD_TYPE::WHO).at(multi).at(msex).data();
+ }
+
+ /*!
+ * @brief 三人称所有格を取得(単数のみ)
+ * @param msex モンスターの性別
+ * @return 所有格
+ */
+ static concptr whose(monster_sex msex)
+ {
+ return whose(msex, false);
+ }
+
+ /*!
+ * @brief 三人称所有格を取得
+ * @param msex モンスターの性別
+ * @param multi 複数かどうか
+ * @return 所有格
+ */
+ static concptr whose(monster_sex msex, bool multi)
+ {
+ return words.at(WHO_WORD_TYPE::WHOSE).at(multi).at(msex).data();
+ }
+
+ /*!
+ * @brief 三人称目的格を取得(単数のみ)
+ * @param msex モンスターの性別
+ * @return 目的語
+ */
+ static concptr whom(monster_sex msex)
+ {
+ return whom(msex, false);
+ }
+
+ /*!
+ * @brief 三人称目的格を取得
+ * @param msex モンスターの性別
+ * @param multi 複数かどうか
+ * @return 目的語
+ */
+ static concptr whom(monster_sex msex, bool multi)
+ {
+ return words.at(WHO_WORD_TYPE::WHOM).at(multi).at(msex).data();
+ }
+};
display_lore_this(player_ptr, lore_ptr);
display_monster_aura(lore_ptr);
if (lore_ptr->flags2 & RF2_REFLECTING)
- hooked_roff(format(_("%^sは矢の呪文を跳ね返す。", "%^s reflects bolt spells. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは矢の呪文を跳ね返す。", "%^s reflects bolt spells. "), Who::who(lore_ptr->msex)));
display_monster_collective(lore_ptr);
lore_ptr->vn = 0;
return (NULL);
}
- for (y = 0; y < infoheader.biHeight; y++)
+ for (y = 0; y < static_cast<int>(infoheader.biHeight); y++)
{
int y2 = infoheader.biHeight - y - 1;
- for (x = 0; x < infoheader.biWidth; x++)
+ for (x = 0; x < static_cast<int>(infoheader.biWidth); x++)
{
int ch = getc(f);
Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
int width1, height1, width2, height2;
- int x1, x2, y1, y2, Tx, Ty;
- int *px1, *px2, *dx1, *dx2;
- int *py1, *py2, *dy1, *dy2;
+ volatile int x1, x2, y1, y2, Tx, Ty;
+ volatile int *px1, *px2, *dx1, *dx2;
+ volatile int *py1, *py2, *dy1, *dy2;
XImage *Tmp;
/*!
* todo main関数を含むファイルの割に長過ぎる。main-win-utils.cなどといった形で分割したい
- * @file main-win.c
+ * @file main-win.cpp
* @brief Windows版固有実装(メインエントリポイント含む)
* @date 2018/03/16
* @author Hengband Team
* </p>
*/
+#ifdef WINDOWS
+
+#include <cstdlib>
+
#include "autopick/autopick-pref-processor.h"
#include "cmd-io/cmd-process-screen.h"
#include "cmd-io/cmd-save.h"
#include "dungeon/quest.h"
#include "floor/floor-base-definitions.h"
#include "floor/floor-events.h"
-#include "game-option/game-play-options.h"
#include "game-option/runtime-arguments.h"
#include "game-option/special-options.h"
#include "io/files-util.h"
-#include "io/inet.h"
#include "io/input-key-acceptor.h"
#include "io/record-play-movie.h"
#include "io/signal-handlers.h"
#include "io/write-diary.h"
+#include "main-win/main-win-bg.h"
+#include "main-win/main-win-file-utils.h"
+#include "main-win/main-win-mci.h"
+#include "main-win/main-win-music.h"
+#include "main-win/main-win-sound.h"
#include "main/angband-initializer.h"
-#include "main/music-definitions-table.h"
-#include "main/sound-definitions-table.h"
#include "main/sound-of-music.h"
#include "monster-floor/monster-lite.h"
+#include "save/save.h"
#include "system/angband-version.h"
#include "system/angband.h"
#include "system/floor-type-definition.h"
#include "wizard/wizard-spoiler.h"
#include "world/world.h"
-#ifdef WINDOWS
-#include "dungeon/dungeon.h"
-#include "save/save.h"
+#include <commdlg.h>
#include <direct.h>
#include <locale.h>
-#include <windows.h>
+
+/*
+ * Include the support for loading bitmaps
+ */
+#include "term/readdib.h"
+
+#define MOUSE_SENS 40
/*
* Available graphic modes
#define IDM_HELP_CONTENTS 901
/*
- * Exclude parts of WINDOWS.H that are not needed (Win32)
- */
-#define WIN32_LEAN_AND_MEAN
-#define NONLS /* All NLS defines and routines */
-#define NOSERVICE /* All Service Controller routines, SERVICE_ equates, etc. */
-#define NOMCX /* Modem Configuration Extensions */
-
-/*
- * Include the "windows" support file
- */
-#include <windows.h>
-
-/*
- * Exclude parts of MMSYSTEM.H that are not needed
- */
-#define MMNODRV /* Installable driver support */
-#define MMNOWAVE /* Waveform support */
-#define MMNOMIDI /* MIDI support */
-#define MMNOAUX /* Auxiliary audio support */
-#define MMNOTIMER /* Timer support */
-#define MMNOJOY /* Joystick support */
-#define MMNOMCI /* MCI support */
-#define MMNOMMIO /* Multimedia file I/O support */
-
-#define INVALID_FILE_NAME (DWORD)0xFFFFFFFF
-#define MOUSE_SENS 40
-
-/*
- * Include some more files. Note: the Cygnus Cygwin compiler
- * doesn't use mmsystem.h instead it includes the winmm library
- * which performs a similar function.
- */
-#include <commdlg.h>
-#include <mmsystem.h>
-
-/*
- * Include the support for loading bitmaps
- */
-#include "term/readdib.h"
-
-#define MoveTo(H, X, Y) MoveToEx(H, X, Y, NULL)
-
-/*
* Foreground color bits
*/
#define VID_BLACK 0x00
static HPALETTE hPal;
/* bg */
-static HBITMAP hBG = NULL;
-static int use_bg = 0; //!< 背景使用フラグ、1なら私用。
-static char bg_bitmap_file[1024] = "bg.bmp"; //!< 現在の背景ビットマップファイル名。
+static int use_bg = 0; //!< 背景使用フラグ、1なら使用。
+#define DEFAULT_BG_FILENAME "bg.bmp"
/*
* The screen saver window
*/
static bool keep_subwindows = TRUE;
-#define SAMPLE_SOUND_MAX 16
/*
- * An array of sound file names
+ * Flag set once "music" has been initialized
*/
-static concptr sound_file[SOUND_MAX][SAMPLE_SOUND_MAX];
-
-#define SAMPLE_MUSIC_MAX 16
-static concptr music_file[MUSIC_BASIC_MAX][SAMPLE_MUSIC_MAX];
-static concptr dungeon_music_file[1000][SAMPLE_MUSIC_MAX];
-static concptr town_music_file[1000][SAMPLE_MUSIC_MAX];
-static concptr quest_music_file[1000][SAMPLE_MUSIC_MAX];
static bool can_use_music = FALSE;
-static MCI_OPEN_PARMS mop;
-static char mci_device_type[256];
-
-static int current_music_type = TERM_XTRA_MUSIC_MUTE;
-static int current_music_id = 0;
-static char current_music_path[1024];
-
/*
* Full path to ANGBAND.INI
*/
* Directory names
*/
static concptr ANGBAND_DIR_XTRA_GRAF;
-static concptr ANGBAND_DIR_XTRA_SOUND;
static concptr ANGBAND_DIR_XTRA_HELP;
-static concptr ANGBAND_DIR_XTRA_MUSIC;
/*
* The "complex" color values
VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, VK_RWIN, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU, VK_RMENU, 0 /* End of List */
};
-/* Function prototype */
-
-static bool is_already_running(void);
-
-/* bg */
-static void delete_bg(void)
-{
- if (hBG != NULL) {
- DeleteObject(hBG);
- hBG = NULL;
- }
-}
-
-static int init_bg(void)
-{
- char *bmfile = bg_bitmap_file;
- delete_bg();
- if (use_bg == 0)
- return 0;
-
- hBG = static_cast<HBITMAP>(LoadImage(NULL, bmfile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));
- if (!hBG) {
- plog_fmt(_("壁紙用ビットマップ '%s' を読み込めません。", "Can't load the bitmap file '%s'."), bmfile);
- use_bg = 0;
- return 0;
- }
-
- use_bg = 1;
- return 1;
-}
-
-static void DrawBG(HDC hdc, RECT *r)
-{
- if (!use_bg || !hBG)
- return;
-
- int x = r->left, y = r->top;
- int nx = x;
- int ny = y;
- BITMAP bm;
- GetObject(hBG, sizeof(bm), &bm);
- int swid = bm.bmWidth;
- int shgt = bm.bmHeight;
-
- HDC hdcSrc = CreateCompatibleDC(hdc);
- HBITMAP hOld = static_cast<HBITMAP>(SelectObject(hdcSrc, hBG));
-
- do {
- int sx = nx % swid;
- int cwid = MIN(swid - sx, r->right - nx);
- do {
- int sy = ny % shgt;
- int chgt = MIN(shgt - sy, r->bottom - ny);
- BitBlt(hdc, nx, ny, cwid, chgt, hdcSrc, sx, sy, SRCCOPY);
- ny += chgt;
- } while (ny < r->bottom);
-
- ny = y;
- nx += cwid;
- } while (nx < r->right);
-
- SelectObject(hdcSrc, hOld);
- DeleteDC(hdcSrc);
-}
-
-/*
- * Check for existance of a file
- */
-static bool check_file(concptr s)
-{
- char path[1024];
- strcpy(path, s);
- DWORD attrib = GetFileAttributes(path);
- if (attrib == INVALID_FILE_NAME)
- return FALSE;
- if (attrib & FILE_ATTRIBUTE_DIRECTORY)
- return FALSE;
-
- return TRUE;
-}
-
-/*
- * Check for existance of a directory
- */
-static bool check_dir(concptr s)
-{
- char path[1024];
- strcpy(path, s);
- int i = strlen(path);
- if (i && (path[i - 1] == '\\'))
- path[--i] = '\0';
-
- DWORD attrib = GetFileAttributes(path);
- if (attrib == INVALID_FILE_NAME)
- return FALSE;
- if (!(attrib & FILE_ATTRIBUTE_DIRECTORY))
- return FALSE;
-
- return TRUE;
-}
-
/*
* Validate a file
*/
strcpy(buf, use_bg ? "1" : "0");
WritePrivateProfileString("Angband", "BackGround", buf, ini_file);
- WritePrivateProfileString("Angband", "BackGroundBitmap", bg_bitmap_file[0] != '\0' ? bg_bitmap_file : "bg.bmp", ini_file);
+ WritePrivateProfileString("Angband", "BackGroundBitmap", bg_bitmap_file[0] != '\0' ? bg_bitmap_file : DEFAULT_BG_FILENAME, ini_file);
int path_length = strlen(ANGBAND_DIR) - 4; /* \libの4文字分を削除 */
char tmp[1024] = "";
arg_sound = (GetPrivateProfileInt("Angband", "Sound", 0, ini_file) != 0);
arg_music = (GetPrivateProfileInt("Angband", "Music", 0, ini_file) != 0);
use_bg = GetPrivateProfileInt("Angband", "BackGround", 0, ini_file);
- GetPrivateProfileString("Angband", "BackGroundBitmap", "bg.bmp", bg_bitmap_file, 1023, ini_file);
+ GetPrivateProfileString("Angband", "BackGroundBitmap", DEFAULT_BG_FILENAME, bg_bitmap_file, 1023, ini_file);
GetPrivateProfileString("Angband", "SaveFile", "", savefile, 1023, ini_file);
int n = strncmp(".\\", savefile, 2);
}
/*
- * - Taken from files.c.
- *
- * Extract "tokens" from a buffer
- *
- * This function uses "whitespace" as delimiters, and treats any amount of
- * whitespace as a single delimiter. We will never return any empty tokens.
- * When given an empty buffer, or a buffer containing only "whitespace", we
- * will return no tokens. We will never extract more than "num" tokens.
- *
- * By running a token through the "text_to_ascii()" function, you can allow
- * that token to include (encoded) whitespace, using "\s" to encode spaces.
- *
- * We save pointers to the tokens in "tokens", and return the number found.
- */
-static s16b tokenize_whitespace(char *buf, s16b num, char **tokens)
-{
- s16b k = 0;
- char *s = buf;
-
- while (k < num) {
- char *t;
- for (; *s && iswspace(*s); ++s) /* loop */
- ;
-
- if (!*s)
- break;
-
- for (t = s; *t && !iswspace(*t); ++t) /* loop */
- ;
-
- if (*t)
- *t++ = '\0';
-
- tokens[k++] = s;
- s = t;
- }
-
- return k;
-}
-
-static void load_sound_prefs(void)
-{
- char tmp[1024];
- char ini_path[1024];
- char wav_path[1024];
- char *zz[SAMPLE_SOUND_MAX];
-
- path_build(ini_path, 1024, ANGBAND_DIR_XTRA_SOUND, "sound_debug.cfg");
- if (GetPrivateProfileString("Device", "type", "", mci_device_type, 256, ini_path) == 0) {
- path_build(ini_path, 1024, ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
- GetPrivateProfileString("Device", "type", "", mci_device_type, 256, ini_path);
- }
-
- for (int i = 0; i < SOUND_MAX; i++) {
- GetPrivateProfileString("Sound", angband_sound_name[i], "", tmp, 1024, ini_path);
- int num = tokenize_whitespace(tmp, SAMPLE_SOUND_MAX, zz);
- for (int j = 0; j < num; j++) {
- path_build(wav_path, 1024, ANGBAND_DIR_XTRA_SOUND, zz[j]);
- if (check_file(wav_path))
- sound_file[i][j] = string_make(zz[j]);
- }
- }
-}
-
-static void load_music_prefs(void)
-{
- char tmp[1024];
- char ini_path[1024];
- char wav_path[1024];
- char *zz[SAMPLE_MUSIC_MAX];
- char key[80];
-
- path_build(ini_path, 1024, ANGBAND_DIR_XTRA_MUSIC, "music_debug.cfg");
- if (GetPrivateProfileString("Device", "type", "", mci_device_type, 256, ini_path) == 0) {
- path_build(ini_path, 1024, ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
- GetPrivateProfileString("Device", "type", "", mci_device_type, 256, ini_path);
- }
-
- for (int i = 0; i < MUSIC_BASIC_MAX; i++) {
- GetPrivateProfileString("Basic", angband_music_basic_name[i], "", tmp, 1024, ini_path);
- int num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz);
- for (int j = 0; j < num; j++) {
- path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]);
- if (check_file(wav_path))
- music_file[i][j] = string_make(zz[j]);
- }
- }
-
- for (int i = 0; i < current_world_ptr->max_d_idx; i++) {
- sprintf(key, "dungeon%03d", i);
- GetPrivateProfileString("Dungeon", key, "", tmp, 1024, ini_path);
- int num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz);
- for (int j = 0; j < num; j++) {
- path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]);
- if (check_file(wav_path))
- dungeon_music_file[i][j] = string_make(zz[j]);
- }
- }
-
- for (int i = 0; i < max_q_idx; i++) {
- sprintf(key, "quest%03d", i);
- GetPrivateProfileString("Quest", key, "", tmp, 1024, ini_path);
- int num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz);
- for (int j = 0; j < num; j++) {
- path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]);
- if (check_file(wav_path))
- quest_music_file[i][j] = string_make(zz[j]);
- }
- }
-
- for (int i = 0; i < 1000; i++) /*!< @todo 町最大数指定 */
- {
- sprintf(key, "town%03d", i);
- GetPrivateProfileString("Town", key, "", tmp, 1024, ini_path);
- int num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz);
- for (int j = 0; j < num; j++) {
- path_build(wav_path, 1024, ANGBAND_DIR_XTRA_MUSIC, zz[j]);
- if (check_file(wav_path))
- town_music_file[i][j] = string_make(zz[j]);
- }
- }
-}
-
-/*
* Create the new global palette based on the bitmap palette
* (if any), and the standard 16 entry palette derived from
* "win_clr[]" which is used for the basic 16 Angband colors.
HPALETTE hBmPal = static_cast<HPALETTE>(infGraph.hPalette);
if (hBmPal) {
lppeSize = 256 * sizeof(PALETTEENTRY);
- lppe = (LPPALETTEENTRY)ralloc(lppeSize);
+ lppe = (LPPALETTEENTRY)std::malloc(lppeSize);
nEntries = GetPaletteEntries(hBmPal, 0, 255, lppe);
if ((nEntries == 0) || (nEntries > 220)) {
plog(_("画面を16ビットか24ビットカラーモードにして下さい。", "Please switch to high- or true-color mode."));
- rnfree(lppe, lppeSize);
+ std::free(lppe);
return FALSE;
}
}
pLogPalSize = sizeof(LOGPALETTE) + (nEntries + 16) * sizeof(PALETTEENTRY);
- pLogPal = (LPLOGPALETTE)ralloc(pLogPalSize);
+ pLogPal = (LPLOGPALETTE)std::malloc(pLogPalSize);
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = nEntries + 16;
for (i = 0; i < nEntries; i++) {
}
if (lppe)
- rnfree(lppe, lppeSize);
+ std::free(lppe);
HPALETTE hNewPal = CreatePalette(pLogPal);
if (!hNewPal)
quit(_("パレットを作成できません!", "Cannot create palette!"));
- rnfree(pLogPal, pLogPalSize);
+ std::free(pLogPal);
td = &data[0];
HDC hdc = GetDC(td->w);
SelectPalette(hdc, hNewPal, 0);
static void init_music(void)
{
if (!can_use_music) {
- load_music_prefs();
+ main_win_music::load_music_prefs(current_world_ptr->max_d_idx, max_q_idx);
can_use_music = TRUE;
}
}
/*
- * Hack -- Stop a music
- */
-static void stop_music(void)
-{
- mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0);
- mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0);
- current_music_type = TERM_XTRA_MUSIC_MUTE;
- current_music_id = 0;
- strcpy(current_music_path, "\0");
-}
-
-/*
* Initialize sound
*/
static void init_sound(void)
/*
* Allow the user to lock this window.
*/
-static void term_window_pos(term_data *td, HWND hWnd) { SetWindowPos(td->w, hWnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); }
+static void term_window_pos(term_data *td, HWND hWnd)
+{
+ SetWindowPos(td->w, hWnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+}
static void windows_map(player_type *player_ptr);
init_music();
use_music = arg_music;
if (!arg_music)
- stop_music();
+ main_win_music::stop_music();
else
select_floor_music(player_ptr);
}
if (use_bg) {
rc.left = 0;
rc.top = 0;
- DrawBG(hdc, &rc);
+ draw_bg(hdc, &rc);
}
ReleaseDC(td->w, hdc);
*/
static errr term_xtra_win_sound(int v)
{
- char buf[1024];
if (!use_sound)
return 1;
- if ((v < 0) || (v >= SOUND_MAX))
- return 1;
-
- int i;
- for (i = 0; i < SAMPLE_SOUND_MAX; i++) {
- if (!sound_file[v][i])
- break;
- }
-
- if (i == 0)
- return 1;
-
- path_build(buf, 1024, ANGBAND_DIR_XTRA_SOUND, sound_file[v][Rand_external(i)]);
- return (PlaySound(buf, 0, SND_FILENAME | SND_ASYNC));
+ return play_sound(v);
}
/*
*/
static errr term_xtra_win_music(int n, int v)
{
- int i = 0;
- char buf[1024];
-
+ // FIXME use_musicの値に関わらずミュートを実行している
if (n == TERM_XTRA_MUSIC_MUTE)
- stop_music();
+ main_win_music::stop_music();
if (!use_music) {
return 1;
}
- if (n == TERM_XTRA_MUSIC_BASIC && ((v < 0) || (v >= MUSIC_BASIC_MAX)))
- return 1;
- else if (v < 0 || v >= 1000)
- return (1); /*!< TODO */
-
- switch (n) {
- case TERM_XTRA_MUSIC_BASIC:
- for (i = 0; i < SAMPLE_MUSIC_MAX; i++)
- if (!music_file[v][i])
- break;
- break;
- case TERM_XTRA_MUSIC_DUNGEON:
- for (i = 0; i < SAMPLE_MUSIC_MAX; i++)
- if (!dungeon_music_file[v][i])
- break;
- break;
- case TERM_XTRA_MUSIC_QUEST:
- for (i = 0; i < SAMPLE_MUSIC_MAX; i++)
- if (!quest_music_file[v][i])
- break;
- break;
- case TERM_XTRA_MUSIC_TOWN:
- for (i = 0; i < SAMPLE_MUSIC_MAX; i++)
- if (!town_music_file[v][i])
- break;
- break;
- }
-
- if (i == 0) {
- return 1;
- }
-
- switch (n) {
- case TERM_XTRA_MUSIC_BASIC:
- path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, music_file[v][Rand_external(i)]);
- break;
- case TERM_XTRA_MUSIC_DUNGEON:
- path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, dungeon_music_file[v][Rand_external(i)]);
- break;
- case TERM_XTRA_MUSIC_QUEST:
- path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, quest_music_file[v][Rand_external(i)]);
- break;
- case TERM_XTRA_MUSIC_TOWN:
- path_build(buf, 1024, ANGBAND_DIR_XTRA_MUSIC, town_music_file[v][Rand_external(i)]);
- break;
- }
-
- if (current_music_type == n && current_music_id == v)
- return 0;
-
- if (current_music_type != TERM_XTRA_MUSIC_MUTE && n != TERM_XTRA_MUSIC_MUTE)
- if (0 == strcmp(current_music_path, buf))
- return 0;
-
- current_music_type = n;
- current_music_id = v;
- strcpy(current_music_path, buf);
-
- mop.lpstrDeviceType = mci_device_type;
- mop.lpstrElementName = buf;
- mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0);
- mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0);
- mciSendCommand(mop.wDeviceID, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)&mop);
- mciSendCommand(mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0);
- mciSendCommand(mop.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mop);
- return 0;
+ return main_win_music::play_music(n, v);
}
/*
SetBkColor(hdc, RGB(0, 0, 0));
SelectObject(hdc, td->font_id);
if (use_bg)
- DrawBG(hdc, &rc);
+ draw_bg(hdc, &rc);
else
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
if (td->bizarre || (td->tile_hgt != td->font_hgt) || (td->tile_wid != td->font_wid)) {
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
if (use_bg)
- DrawBG(hdc, &rc);
+ draw_bg(hdc, &rc);
rc.left += ((td->tile_wid - td->font_wid) / 2);
rc.right = rc.left + td->font_wid;
}
use_bg = !use_bg;
- init_bg();
+ if (use_bg) {
+ use_bg = init_bg();
+ } else {
+ delete_bg();
+ }
+
term_xtra_win_react(player_ptr);
term_key_push(KTRL('R'));
break;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
if (GetOpenFileName(&ofn)) {
- use_bg = 1;
- init_bg();
+ use_bg = init_bg();
}
term_xtra_win_react(player_ptr);
switch (wParam) {
case VK_DIVIDE:
term_no_press = TRUE;
+ [[fallthrough]]; /* Fall through */
case VK_RETURN:
numpad = ext_key;
break;
case VK_SEPARATOR:
case VK_DECIMAL:
term_no_press = TRUE;
+ [[fallthrough]]; /* Fall through */
case VK_CLEAR:
case VK_HOME:
case VK_END:
if ((HWND)wParam == hWnd)
return 0;
}
+ [[fallthrough]]; /* Fall through */
case WM_QUERYNEWPALETTE: {
if (!paletted)
return 0;
}
}
}
+ [[fallthrough]]; /* Fall through */
case WM_ENABLE: {
if (wParam == FALSE && keep_subwindows) {
for (int i = 0; i < MAX_TERM_DATA; i++) {
if ((HWND)wParam == hWnd)
return FALSE;
}
+ [[fallthrough]]; /* Fall through */
case WM_QUERYNEWPALETTE: {
if (!paletted)
return 0;
/*!
* @brief (Windows固有)Windowsアプリケーションとしてのエントリポイント
*/
-int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
+int WINAPI WinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInst, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
WNDCLASS wc;
HDC hdc;
}
init_windows();
- init_bg();
+ if (use_bg) {
+ use_bg = init_bg();
+ }
plog_aux = hook_plog;
quit_aux = hook_quit;
--- /dev/null
+/*!
+ * @file main-win-bg.cpp
+ * @brief Windows版固有実装(壁紙)
+ */
+
+#include "locale/language-switcher.h"
+#include "main-win/main-win-bg.h"
+#include "system/h-define.h"
+#include "term/z-form.h"
+
+static HBITMAP hBG = NULL;
+char bg_bitmap_file[MAIN_WIN_MAX_PATH] = ""; //!< 現在の背景ビットマップファイル名。
+
+void delete_bg(void)
+{
+ if (hBG != NULL) {
+ DeleteObject(hBG);
+ hBG = NULL;
+ }
+}
+
+static BOOL init_bg_impl(void)
+{
+ char *bmfile = bg_bitmap_file;
+ delete_bg();
+
+ hBG = static_cast<HBITMAP>(LoadImage(NULL, bmfile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));
+ if (!hBG) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL init_bg(void)
+{
+ BOOL result = init_bg_impl();
+ if (!result) {
+ plog_fmt(_("壁紙用ビットマップ '%s' を読み込めません。", "Can't load the bitmap file '%s'."), bg_bitmap_file);
+ }
+
+ return result;
+}
+
+void draw_bg(HDC hdc, RECT *r)
+{
+ if (!hBG)
+ return;
+
+ int x = r->left, y = r->top;
+ int nx = x;
+ int ny = y;
+ BITMAP bm;
+ GetObject(hBG, sizeof(bm), &bm);
+ int swid = bm.bmWidth;
+ int shgt = bm.bmHeight;
+
+ HDC hdcSrc = CreateCompatibleDC(hdc);
+ HBITMAP hOld = static_cast<HBITMAP>(SelectObject(hdcSrc, hBG));
+
+ do {
+ int sx = nx % swid;
+ int cwid = MIN(swid - sx, r->right - nx);
+ do {
+ int sy = ny % shgt;
+ int chgt = MIN(shgt - sy, r->bottom - ny);
+ BitBlt(hdc, nx, ny, cwid, chgt, hdcSrc, sx, sy, SRCCOPY);
+ ny += chgt;
+ } while (ny < r->bottom);
+
+ ny = y;
+ nx += cwid;
+ } while (nx < r->right);
+
+ SelectObject(hdcSrc, hOld);
+ DeleteDC(hdcSrc);
+}
--- /dev/null
+#pragma once
+
+#include "main-win/main-win-windows.h"
+#include "main-win/main-win-define.h"
+
+extern char bg_bitmap_file[MAIN_WIN_MAX_PATH]; //!< 現在の背景ビットマップファイル名。
+
+void delete_bg(void);
+BOOL init_bg(void);
+void draw_bg(HDC hdc, RECT *r);
--- /dev/null
+#pragma once
+
+// max. length of full pathname
+#define MAIN_WIN_MAX_PATH 1024
+
+#define INVALID_FILE_NAME (DWORD)0xFFFFFFFF
--- /dev/null
+/*!
+ * @file main-win-file-utils.cpp
+ * @brief Windows版固有実装(ファイル関連処理)
+ */
+
+#include "main-win/main-win-file-utils.h"
+#include "main-win/main-win-define.h"
+#include "main-win/main-win-windows.h"
+
+/*
+ * Check for existance of a file
+ */
+bool check_file(concptr s)
+{
+ char path[MAIN_WIN_MAX_PATH];
+ strcpy(path, s);
+ DWORD attrib = GetFileAttributes(path);
+ if (attrib == INVALID_FILE_NAME)
+ return FALSE;
+ if (attrib & FILE_ATTRIBUTE_DIRECTORY)
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Check for existance of a directory
+ */
+bool check_dir(concptr s)
+{
+ char path[MAIN_WIN_MAX_PATH];
+ strcpy(path, s);
+ int i = strlen(path);
+ if (i && (path[i - 1] == '\\'))
+ path[--i] = '\0';
+
+ DWORD attrib = GetFileAttributes(path);
+ if (attrib == INVALID_FILE_NAME)
+ return FALSE;
+ if (!(attrib & FILE_ATTRIBUTE_DIRECTORY))
+ return FALSE;
+
+ return TRUE;
+}
--- /dev/null
+#pragma once
+
+#include "system/h-type.h"
+
+bool check_file(concptr s);
+bool check_dir(concptr s);
--- /dev/null
+/*!
+ * @file main-win-mci.cpp
+ * @brief Windows版固有実装(BGM再生用のMCI)
+ */
+
+#include "main-win/main-win-mci.h"
+
+MCI_OPEN_PARMS mop;
+char mci_device_type[MCI_DEVICE_TYPE_MAX_LENGTH];
--- /dev/null
+#pragma once
+
+#include "main-win/main-win-windows.h"
+
+#include <mciapi.h>
+
+extern MCI_OPEN_PARMS mop;
+#define MCI_DEVICE_TYPE_MAX_LENGTH 256
+extern char mci_device_type[MCI_DEVICE_TYPE_MAX_LENGTH];
--- /dev/null
+#pragma once
+
+#include "main-win/main-win-windows.h"
+
+/*
+ * Exclude parts of MMSYSTEM.H that are not needed
+ */
+#define MMNODRV /* Installable driver support */
+#define MMNOWAVE /* Waveform support */
+#define MMNOMIDI /* MIDI support */
+#define MMNOAUX /* Auxiliary audio support */
+#define MMNOTIMER /* Timer support */
+#define MMNOJOY /* Joystick support */
+#define MMNOMCI /* MCI support */
+#define MMNOMMIO /* Multimedia file I/O support */
+
+/*
+ * Include some more files. Note: the Cygnus Cygwin compiler
+ * doesn't use mmsystem.h instead it includes the winmm library
+ * which performs a similar function.
+ */
+#include <mmsystem.h>
--- /dev/null
+/*!
+ * @file main-win-music.cpp
+ * @brief Windows版固有実装(BGM)
+ */
+
+#include "main-win/main-win-music.h"
+#include "main-win/main-win-define.h"
+#include "main-win/main-win-file-utils.h"
+#include "main-win/main-win-mci.h"
+#include "main-win/main-win-mmsystem.h"
+#include "main-win/main-win-tokenizer.h"
+#include "term/z-term.h"
+#include "util/angband-files.h"
+
+concptr music_file[MUSIC_BASIC_MAX][SAMPLE_MUSIC_MAX];
+// TODO マジックナンバー除去
+concptr dungeon_music_file[1000][SAMPLE_MUSIC_MAX];
+concptr town_music_file[1000][SAMPLE_MUSIC_MAX];
+concptr quest_music_file[1000][SAMPLE_MUSIC_MAX];
+
+static int current_music_type = TERM_XTRA_MUSIC_MUTE;
+static int current_music_id = 0;
+static char current_music_path[MAIN_WIN_MAX_PATH];
+
+/*
+ * Directory name
+ */
+concptr ANGBAND_DIR_XTRA_MUSIC;
+
+namespace main_win_music {
+void load_music_prefs(DUNGEON_IDX max_d_idx, QUEST_IDX max_q_idx)
+{
+ char tmp[MAIN_WIN_MAX_PATH];
+ char ini_path[MAIN_WIN_MAX_PATH];
+ char wav_path[MAIN_WIN_MAX_PATH];
+ char *zz[SAMPLE_MUSIC_MAX];
+ // TODO マジックナンバー除去
+ char key[80];
+
+ path_build(ini_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, "music_debug.cfg");
+ if (GetPrivateProfileString("Device", "type", "", mci_device_type, _countof(mci_device_type), ini_path) == 0) {
+ path_build(ini_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, "music.cfg");
+ GetPrivateProfileString("Device", "type", "", mci_device_type, _countof(mci_device_type), ini_path);
+ }
+
+ for (int i = 0; i < MUSIC_BASIC_MAX; i++) {
+ GetPrivateProfileString("Basic", angband_music_basic_name[i], "", tmp, MAIN_WIN_MAX_PATH, ini_path);
+ int num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz);
+ for (int j = 0; j < num; j++) {
+ path_build(wav_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, zz[j]);
+ if (check_file(wav_path))
+ music_file[i][j] = string_make(zz[j]);
+ }
+ }
+
+ for (int i = 0; i < max_d_idx; i++) {
+ sprintf(key, "dungeon%03d", i);
+ GetPrivateProfileString("Dungeon", key, "", tmp, MAIN_WIN_MAX_PATH, ini_path);
+ int num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz);
+ for (int j = 0; j < num; j++) {
+ path_build(wav_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, zz[j]);
+ if (check_file(wav_path))
+ dungeon_music_file[i][j] = string_make(zz[j]);
+ }
+ }
+
+ for (int i = 0; i < max_q_idx; i++) {
+ sprintf(key, "quest%03d", i);
+ GetPrivateProfileString("Quest", key, "", tmp, MAIN_WIN_MAX_PATH, ini_path);
+ int num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz);
+ for (int j = 0; j < num; j++) {
+ path_build(wav_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, zz[j]);
+ if (check_file(wav_path))
+ quest_music_file[i][j] = string_make(zz[j]);
+ }
+ }
+
+ for (int i = 0; i < 1000; i++) /*!< @todo 町最大数指定 */
+ {
+ sprintf(key, "town%03d", i);
+ GetPrivateProfileString("Town", key, "", tmp, MAIN_WIN_MAX_PATH, ini_path);
+ int num = tokenize_whitespace(tmp, SAMPLE_MUSIC_MAX, zz);
+ for (int j = 0; j < num; j++) {
+ path_build(wav_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, zz[j]);
+ if (check_file(wav_path))
+ town_music_file[i][j] = string_make(zz[j]);
+ }
+ }
+}
+
+/*
+ * Stop a music
+ */
+void stop_music(void)
+{
+ mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0);
+ mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0);
+ current_music_type = TERM_XTRA_MUSIC_MUTE;
+ current_music_id = 0;
+ strcpy(current_music_path, "\0");
+}
+
+/*
+ * Play a music
+ */
+errr play_music(int type, int val)
+{
+ int i = 0;
+ char buf[MAIN_WIN_MAX_PATH];
+
+ if (type == TERM_XTRA_MUSIC_MUTE)
+ stop_music();
+
+ if (type == TERM_XTRA_MUSIC_BASIC && ((val < 0) || (val >= MUSIC_BASIC_MAX)))
+ return 1;
+ else if (val < 0 || val >= 1000)
+ return (1); /*!< TODO */
+
+ switch (type) {
+ case TERM_XTRA_MUSIC_BASIC:
+ for (i = 0; i < SAMPLE_MUSIC_MAX; i++)
+ if (!music_file[val][i])
+ break;
+ break;
+ case TERM_XTRA_MUSIC_DUNGEON:
+ for (i = 0; i < SAMPLE_MUSIC_MAX; i++)
+ if (!dungeon_music_file[val][i])
+ break;
+ break;
+ case TERM_XTRA_MUSIC_QUEST:
+ for (i = 0; i < SAMPLE_MUSIC_MAX; i++)
+ if (!quest_music_file[val][i])
+ break;
+ break;
+ case TERM_XTRA_MUSIC_TOWN:
+ for (i = 0; i < SAMPLE_MUSIC_MAX; i++)
+ if (!town_music_file[val][i])
+ break;
+ break;
+ }
+
+ if (i == 0) {
+ return 1;
+ }
+
+ switch (type) {
+ case TERM_XTRA_MUSIC_BASIC:
+ path_build(buf, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, music_file[val][Rand_external(i)]);
+ break;
+ case TERM_XTRA_MUSIC_DUNGEON:
+ path_build(buf, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, dungeon_music_file[val][Rand_external(i)]);
+ break;
+ case TERM_XTRA_MUSIC_QUEST:
+ path_build(buf, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, quest_music_file[val][Rand_external(i)]);
+ break;
+ case TERM_XTRA_MUSIC_TOWN:
+ path_build(buf, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_MUSIC, town_music_file[val][Rand_external(i)]);
+ break;
+ }
+
+ if (current_music_type == type && current_music_id == val)
+ return 0;
+
+ if (current_music_type != TERM_XTRA_MUSIC_MUTE && type != TERM_XTRA_MUSIC_MUTE)
+ if (0 == strcmp(current_music_path, buf))
+ return 0;
+
+ current_music_type = type;
+ current_music_id = val;
+ strcpy(current_music_path, buf);
+
+ mop.lpstrDeviceType = mci_device_type;
+ mop.lpstrElementName = buf;
+ mciSendCommand(mop.wDeviceID, MCI_STOP, 0, 0);
+ mciSendCommand(mop.wDeviceID, MCI_CLOSE, 0, 0);
+ mciSendCommand(mop.wDeviceID, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)&mop);
+ mciSendCommand(mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0);
+ mciSendCommand(mop.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mop);
+ return 0;
+}
+}
--- /dev/null
+#pragma once
+
+#include "system/h-type.h"
+
+#include "main/music-definitions-table.h"
+
+#define SAMPLE_MUSIC_MAX 16
+extern concptr music_file[MUSIC_BASIC_MAX][SAMPLE_MUSIC_MAX];
+// TODO マジックナンバー除去
+extern concptr dungeon_music_file[1000][SAMPLE_MUSIC_MAX];
+extern concptr town_music_file[1000][SAMPLE_MUSIC_MAX];
+extern concptr quest_music_file[1000][SAMPLE_MUSIC_MAX];
+extern concptr ANGBAND_DIR_XTRA_MUSIC;
+
+namespace main_win_music {
+void load_music_prefs(DUNGEON_IDX max_d_idx, QUEST_IDX max_q_idx);
+void stop_music(void);
+errr play_music(int type, int val);
+}
--- /dev/null
+/*!
+ * @file main-win-sound.cpp
+ * @brief Windows版固有実装(効果音)
+ */
+
+#include "main-win/main-win-define.h"
+#include "main-win/main-win-file-utils.h"
+#include "main-win/main-win-mci.h"
+#include "main-win/main-win-mmsystem.h"
+#include "main-win/main-win-sound.h"
+#include "main-win/main-win-tokenizer.h"
+#include "util/angband-files.h"
+
+/*
+ * An array of sound file names
+ */
+concptr sound_file[SOUND_MAX][SAMPLE_SOUND_MAX];
+
+/*
+ * Directory name
+ */
+concptr ANGBAND_DIR_XTRA_SOUND;
+
+void load_sound_prefs(void)
+{
+ char tmp[MAIN_WIN_MAX_PATH];
+ char ini_path[MAIN_WIN_MAX_PATH];
+ char wav_path[MAIN_WIN_MAX_PATH];
+ char *zz[SAMPLE_SOUND_MAX];
+
+ // FIXME sound.cfgとmusic.cfgに共通する「[Device]tyepe=~」項目の読込先変数が同じため競合する
+ // FIXME 効果音再生のPlaySound APIはMCIとは別のため、現在の所は効果音用のデバイスタイプ設定は不要
+ path_build(ini_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_SOUND, "sound_debug.cfg");
+ if (GetPrivateProfileString("Device", "type", "", mci_device_type, _countof(mci_device_type), ini_path) == 0) {
+ path_build(ini_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
+ GetPrivateProfileString("Device", "type", "", mci_device_type, _countof(mci_device_type), ini_path);
+ }
+
+ for (int i = 0; i < SOUND_MAX; i++) {
+ GetPrivateProfileString("Sound", angband_sound_name[i], "", tmp, MAIN_WIN_MAX_PATH, ini_path);
+ int num = tokenize_whitespace(tmp, SAMPLE_SOUND_MAX, zz);
+ for (int j = 0; j < num; j++) {
+ path_build(wav_path, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_SOUND, zz[j]);
+ if (check_file(wav_path))
+ sound_file[i][j] = string_make(zz[j]);
+ }
+ }
+}
+
+errr play_sound(int val)
+{
+ char buf[MAIN_WIN_MAX_PATH];
+ if ((val < 0) || (val >= SOUND_MAX))
+ return 1;
+
+ int i;
+ for (i = 0; i < SAMPLE_SOUND_MAX; i++) {
+ if (!sound_file[val][i])
+ break;
+ }
+
+ if (i == 0)
+ return 1;
+
+ path_build(buf, 1024, ANGBAND_DIR_XTRA_SOUND, sound_file[val][Rand_external(i)]);
+ return (PlaySound(buf, 0, SND_FILENAME | SND_ASYNC));
+}
--- /dev/null
+#pragma once
+
+#include "system/h-type.h"
+
+#include "main/sound-definitions-table.h"
+
+#define SAMPLE_SOUND_MAX 16
+extern concptr sound_file[SOUND_MAX][SAMPLE_SOUND_MAX];
+extern concptr ANGBAND_DIR_XTRA_SOUND;
+
+void load_sound_prefs(void);
+errr play_sound(int val);
--- /dev/null
+/*!
+ * @file main-win-tokenizer.cpp
+ * @brief Windows版固有実装(トークン分割)
+ */
+
+#include "main-win/main-win-tokenizer.h"
+
+#include <ctype.h>
+
+/*
+ * - Taken from files.c.
+ *
+ * Extract "tokens" from a buffer
+ *
+ * This function uses "whitespace" as delimiters, and treats any amount of
+ * whitespace as a single delimiter. We will never return any empty tokens.
+ * When given an empty buffer, or a buffer containing only "whitespace", we
+ * will return no tokens. We will never extract more than "num" tokens.
+ *
+ * By running a token through the "text_to_ascii()" function, you can allow
+ * that token to include (encoded) whitespace, using "\s" to encode spaces.
+ *
+ * We save pointers to the tokens in "tokens", and return the number found.
+ */
+s16b tokenize_whitespace(char *buf, s16b num, char **tokens)
+{
+ s16b k = 0;
+ char *s = buf;
+
+ while (k < num) {
+ char *t;
+ for (; *s && iswspace(*s); ++s) /* loop */
+ ;
+
+ if (!*s)
+ break;
+
+ for (t = s; *t && !iswspace(*t); ++t) /* loop */
+ ;
+
+ if (*t)
+ *t++ = '\0';
+
+ tokens[k++] = s;
+ s = t;
+ }
+
+ return k;
+}
--- /dev/null
+#pragma once
+
+#include "system/h-type.h"
+
+s16b tokenize_whitespace(char *buf, s16b num, char **tokens);
--- /dev/null
+#pragma once
+
+/*
+ * Exclude parts of WINDOWS.H that are not needed (Win32)
+ */
+#define WIN32_LEAN_AND_MEAN
+#define NONLS /* All NLS defines and routines */
+#define NOSERVICE /* All Service Controller routines, SERVICE_ equates, etc. */
+#define NOMCX /* Modem Configuration Extensions */
+
+/*
+ * Include the "windows" support file
+ */
+#include <windows.h>
typedef errr (*parse_info_txt_func)(char *buf, angband_header *head);
struct angband_header {
- byte v_major; /* Version -- major */
- byte v_minor; /* Version -- minor */
- byte v_patch; /* Version -- patch */
- byte v_extra; /* Version -- extra */
+ byte v_major; //!< Major version
+ byte v_minor; //!< Minor version
+ byte v_patch; //!< Patch version
+ byte checksum; //!< Checksum of "info" records
- u16b info_num; /* Number of "info" records */
- int info_len; /* Size of each "info" record */
- u16b head_size; /* Size of the "header" in bytes */
+ u16b info_num; //!< このinfoのデータ数
+ int info_len; //!< このinfoの総サイズ
+ u16b head_size; //!< このinfoのヘッダサイズ
- STR_OFFSET info_size; /* Size of the "info" array in bytes */
- STR_OFFSET name_size; /* Size of the "name" array in bytes */
- STR_OFFSET text_size; /* Size of the "text" array in bytes */
- STR_OFFSET tag_size; /* Size of the "tag" array in bytes */
+ STR_OFFSET info_size; //!< info配列サイズ
+ STR_OFFSET name_size; //!< 名前文字列群サイズ(総文字長)
+ STR_OFFSET text_size; //!< フレーバー文字列群サイズ(総文字長)
+ STR_OFFSET tag_size; //!< タグ文字列群サイズ(総文字長)
- void *info_ptr;
- char *name_ptr;
- char *text_ptr;
- char *tag_ptr;
+ void *info_ptr; //!< info配列へのポインタ
+ char *name_ptr; //!< 名前文字列群へのポインタ
+ char *text_ptr; //!< フレーバー文字列群へのポインタ
+ char *tag_ptr; //!< タグ文字列群へのポインタ
- parse_info_txt_func parse_info_txt;
+ parse_info_txt_func parse_info_txt; //!< Pointer to parser callback function
- void (*retouch)(angband_header *head);
+ void (*retouch)(angband_header *head); //!< 設定再読み込み用?
+
+ byte v_extra; ///< Extra version for Alpha, Beta
+ byte v_savefile; ///< Savefile version
};
extern angband_header f_head;
errr init_object_alloc(void)
{
s16b aux[MAX_DEPTH];
- (void)C_WIPE(&aux, MAX_DEPTH, s16b);
+ (void)C_WIPE(aux, MAX_DEPTH, s16b);
s16b num[MAX_DEPTH];
- (void)C_WIPE(&num, MAX_DEPTH, s16b);
+ (void)C_WIPE(num, MAX_DEPTH, s16b);
if (alloc_kind_table)
C_KILL(alloc_kind_table, alloc_kind_size, alloc_entry);
table[z].level = (DEPTH)x;
table[z].prob1 = (PROB)p;
table[z].prob2 = (PROB)p;
- table[z].prob3 = (PROB)p;
aux[x]++;
}
}
alloc_race_table[i].level = (DEPTH)x;
alloc_race_table[i].prob1 = (PROB)p;
alloc_race_table[i].prob2 = (PROB)p;
- alloc_race_table[i].prob3 = (PROB)p;
}
C_KILL(elements, max_r_idx, tag_type);
static errr init_info_raw(int fd, angband_header *head)
{
angband_header test;
- if (fd_read(fd, (char *)(&test), sizeof(angband_header)) || (test.v_major != head->v_major) || (test.v_minor != head->v_minor)
- || (test.v_patch != head->v_patch) || (test.info_num != head->info_num) || (test.info_len != head->info_len) || (test.head_size != head->head_size)
- || (test.info_size != head->info_size)) {
+ if (fd_read(fd, (char *)(&test), sizeof(angband_header))
+ || (test.v_major != head->v_major) || (test.v_minor != head->v_minor) || (test.v_patch != head->v_patch)
+ || (test.v_extra != head->v_extra) || (test.v_savefile != head->v_savefile)
+ || (test.head_size != head->head_size) || (test.info_size != head->info_size)
+ || (test.info_num != head->info_num) || (test.info_len != head->info_len))
return -1;
- }
*head = test;
C_MAKE(head->info_ptr, head->info_size, char);
head->v_major = FAKE_VER_MAJOR;
head->v_minor = FAKE_VER_MINOR;
head->v_patch = FAKE_VER_PATCH;
- head->v_extra = 0;
+ head->checksum = 0;
head->info_num = (IDX)num;
head->info_len = len;
head->head_size = sizeof(angband_header);
head->info_size = head->info_num * head->info_len;
+
+ head->v_extra = FAKE_VER_EXTRA;
+ head->v_savefile = SAVEFILE_VERSION;
}
/*!
(void)fd_close(fd);
}
- C_KILL(head->info_ptr, head->info_size, char);
+ C_FREE(static_cast<char *>(head->info_ptr), head->info_size, char);
+ head->info_ptr = nullptr;
if (name)
C_KILL(head->name_ptr, FAKE_NAME_SIZE, char);
for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
o_ptr = &player_ptr->inventory_list[i];
- if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_CORPSE) && (streq(r_name + r_info[o_ptr->pval].name, r_name + r_info[today_mon].name))) {
+ if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_CORPSE)
+ && (streq(r_name + r_info[o_ptr->pval].name, r_name + r_info[current_world_ptr->today_mon].name))) {
char buf[MAX_NLEN + 32];
describe_flavor(player_ptr, o_name, o_ptr, 0);
sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
if (get_check(buf)) {
- msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((r_info[today_mon].level * 50 + 100) * o_ptr->number));
- player_ptr->au += (r_info[today_mon].level * 50 + 100) * o_ptr->number;
+ msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((r_info[current_world_ptr->today_mon].level * 50 + 100) * o_ptr->number));
+ player_ptr->au += (r_info[current_world_ptr->today_mon].level * 50 + 100) * o_ptr->number;
player_ptr->redraw |= (PR_GOLD);
vary_item(player_ptr, i, -o_ptr->number);
}
for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
o_ptr = &player_ptr->inventory_list[i];
- if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_SKELETON) && (streq(r_name + r_info[o_ptr->pval].name, r_name + r_info[today_mon].name))) {
+ if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_SKELETON)
+ && (streq(r_name + r_info[o_ptr->pval].name, r_name + r_info[current_world_ptr->today_mon].name))) {
char buf[MAX_NLEN + 32];
describe_flavor(player_ptr, o_name, o_ptr, 0);
sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
if (get_check(buf)) {
- msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((r_info[today_mon].level * 30 + 60) * o_ptr->number));
- player_ptr->au += (r_info[today_mon].level * 30 + 60) * o_ptr->number;
+ msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((r_info[current_world_ptr->today_mon].level * 30 + 60) * o_ptr->number));
+ player_ptr->au += (r_info[current_world_ptr->today_mon].level * 30 + 60) * o_ptr->number;
player_ptr->redraw |= (PR_GOLD);
vary_item(player_ptr, i, -o_ptr->number);
}
void today_target(player_type *player_ptr)
{
char buf[160];
- monster_race *r_ptr = &r_info[today_mon];
+ monster_race *r_ptr = &r_info[current_world_ptr->today_mon];
clear_bldg(4, 18);
c_put_str(TERM_YELLOW, _("本日の賞金首", "Wanted monster that changes from day to day"), 5, 10);
prt(buf, 8, 10);
sprintf(buf, _("骨 ---- $%d", "skeleton ---- $%d"), (int)r_ptr->level * 30 + 60);
prt(buf, 9, 10);
- player_ptr->today_mon = today_mon;
+ player_ptr->today_mon = current_world_ptr->today_mon;
}
/*!
get_mon_num_prep_bounty(player_ptr);
while (TRUE) {
- today_mon = get_mon_num(player_ptr, MIN(max_dl / 2, 40), max_dl, GMN_ARENA);
+ current_world_ptr->today_mon = get_mon_num(player_ptr, MIN(max_dl / 2, 40), max_dl, GMN_ARENA);
monster_race *r_ptr;
- r_ptr = &r_info[today_mon];
+ r_ptr = &r_info[current_world_ptr->today_mon];
if (cheat_hear) {
msg_format("日替わり候補: %s ", r_ptr->name + r_name);
continue;
break;
}
+
+ // プレイヤーは日替わり賞金首に関する知識を失う。
+ player_ptr->today_mon = 0;
}
/*!
price = MAX(10, price);
price = (o_ptr->number * k_ptr->pval - o_ptr->pval) * price;
break;
+
+ default:
+ break;
}
if (price > 0)
o_ptr->ident &= ~(IDENT_EMPTY);
break;
+
+ default:
+ break;
}
}
#include "mspell/assign-monster-spell.h"
#include "mspell/mspell-checker.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "spell-realm/spells-hex.h"
#include "system/floor-type-definition.h"
#include "view/display-messages.h"
return;
}
-
+
if (ms_ptr->thrown_spell < RF5_SPELL_START + RF5_SPELL_SIZE) {
ms_ptr->r_ptr->r_flags5 |= (1UL << (ms_ptr->thrown_spell - RF5_SPELL_START));
if (ms_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
return;
}
-
+
if (ms_ptr->thrown_spell < RF6_SPELL_START + RF6_SPELL_SIZE) {
ms_ptr->r_ptr->r_flags6 |= (1UL << (ms_ptr->thrown_spell - RF6_SPELL_START));
if (ms_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
return TRUE;
ms_ptr->can_remember = is_original_ap_and_seen(target_ptr, ms_ptr->m_ptr);
- ms_ptr->dam = monspell_to_monster(target_ptr, ms_ptr->thrown_spell, ms_ptr->y, ms_ptr->x, m_idx, ms_ptr->target_idx, FALSE);
- if (ms_ptr->dam < 0)
+ const auto res = monspell_to_monster(target_ptr, ms_ptr->thrown_spell, ms_ptr->y, ms_ptr->x, m_idx, ms_ptr->target_idx, FALSE);
+ if (!res.valid)
return FALSE;
process_special_melee_spell(target_ptr, ms_ptr);
mam_ptr->touched = FALSE;
break;
}
+
+ case RBM_NONE:
+ case RBM_SHOOT:
+ case NB_RBM_TYPE:
+ break;
}
}
--- /dev/null
+/*!
+ * @brief 元素使いの魔法系統
+ */
+
+#include "mind-elementalist.h"
+#include "action/action-limited.h"
+#include "cmd-action/cmd-spell.h"
+#include "cmd-action/cmd-mind.h"
+#include "cmd-io/cmd-gameoption.h"
+#include "core/asking-player.h"
+#include "core/hp-mp-processor.h"
+#include "core/player-redraw-types.h"
+#include "core/stuff-handler.h"
+#include "core/window-redrawer.h"
+#include "effect/effect-characteristics.h"
+#include "effect/effect-monster-util.h"
+#include "effect/effect-processor.h"
+#include "effect/spells-effect-util.h"
+#include "floor/cave.h"
+#include "floor/floor-util.h"
+#include "game-option/disturbance-options.h"
+#include "game-option/input-options.h"
+#include "game-option/text-display-options.h"
+#include "io/command-repeater.h"
+#include "io/input-key-acceptor.h"
+#include "io/input-key-requester.h"
+#include "main/sound-definitions-table.h"
+#include "main/sound-of-music.h"
+#include "mind/mind-explanations-table.h"
+#include "monster/monster-describer.h"
+#include "monster-race/monster-race.h"
+#include "monster-race/race-flags3.h"
+#include "monster-race/race-flags-resistance.h"
+#include "mind/mind-mindcrafter.h"
+#include "player/player-status-table.h"
+#include "player-info/avatar.h"
+#include "player-status/player-status-base.h"
+#include "racial/racial-util.h"
+#include "spell-kind/earthquake.h"
+#include "spell-kind/spells-charm.h"
+#include "spell-kind/spells-detection.h"
+#include "spell-kind/spells-genocide.h"
+#include "spell-kind/spells-launcher.h"
+#include "spell-kind/spells-lite.h"
+#include "spell-kind/magic-item-recharger.h"
+#include "spell-kind/spells-beam.h"
+#include "spell-kind/spells-sight.h"
+#include "spell-kind/spells-world.h"
+#include "status/bad-status-setter.h"
+#include "status/base-status.h"
+#include "system/game-option-types.h"
+#include "util/bit-flags-calculator.h"
+#include "util/buffer-shaper.h"
+#include "util/int-char-converter.h"
+#include "target/target-getter.h"
+#include "term/screen-processor.h"
+#include "term/term-color-types.h"
+#include "view/display-messages.h"
+#include <string>
+#include <array>
+#include <unordered_map>
+
+/*!
+ * @brief 元素魔法呪文のID定義
+ */
+enum class ElementSpells {
+ BOLT_1ST = 0,
+ MON_DETECT = 1,
+ PERCEPT = 2,
+ CURE = 3,
+ BOLT_2ND = 4,
+ MAG_DETECT = 5,
+ BALL_3RD = 6,
+ BALL_1ST = 7,
+ BREATH_2ND = 8,
+ ANNIHILATE = 9,
+ BOLT_3RD = 10,
+ WAVE_1ST = 11,
+ BALL_2ND = 12,
+ BURST_1ST = 13,
+ STORM_2ND = 14,
+ BREATH_1ST = 15,
+ STORM_3ND = 16,
+ MAX
+};
+
+/*!
+ * @brief 元素魔法タイプ構造体
+ */
+struct element_type {
+ std::string_view title; //!< 領域名
+ std::array<spells_type, 3> type; //!< 属性タイプリスト
+ std::array<std::string_view, 3> name; //!< 属性名リスト
+ std::unordered_map<spells_type, spells_type> extra; //!< 追加属性タイプ
+};
+
+/*!
+ * @brief 元素魔法難易度構造体
+ */
+struct element_power {
+ int elem; //!< 使用属性番号
+ mind_type info; //!< 難易度構造体
+};
+
+using element_type_list = const std::unordered_map<ElementRealm, element_type>;
+using element_power_list = const std::unordered_map<ElementSpells, element_power>;
+using element_tip_list = const std::unordered_map<ElementSpells, std::string_view>;
+using element_text_list = const std::unordered_map<ElementRealm, std::string_view>;
+
+// clang-format off
+/*!
+ * @brief 元素魔法タイプ定義
+ */
+static element_type_list element_types = {
+ {
+ ElementRealm::FIRE, {
+ _("炎", "Fire"),
+ { GF_FIRE, GF_ROCKET, GF_PLASMA },
+ { _("火炎", "Fire"), _("爆発", "Explosion"), _("プラズマ", "Plasma") },
+ { },
+ }
+ },
+ {
+ ElementRealm::ICE, {
+ _("氷", "Ice"),
+ { GF_COLD, GF_INERTIAL, GF_TIME },
+ { _("冷気", "Ice"), _("遅鈍", "Inertia"), _("時間逆転", "Time Stream") },
+ { { GF_COLD, GF_ICE} },
+ }
+ },
+ {
+ ElementRealm::SKY, {
+ _("空", "Sky"),
+ { GF_ELEC, GF_LITE, GF_MANA },
+ { _("電撃", "Lightning"), _("光", "Light"), _("魔力", "Mana") },
+ { },
+ }
+ },
+ {
+ ElementRealm::SEA, {
+ _("海", "Sea"),
+ { GF_ACID, GF_WATER, GF_DISINTEGRATE },
+ { _("酸", "Acid"), _("水", "Water"), _("分解", "Disintegration") },
+ { },
+ }
+ },
+ {
+ ElementRealm::DARKNESS, {
+ _("闇", "Darkness"),
+ { GF_DARK, GF_NETHER, GF_HELL_FIRE },
+ { _("暗黒", "Darkness"), _("地獄", "Nether"), _("業火", "Hell Fire") },
+ { },
+ }
+ },
+ {
+ ElementRealm::CHAOS, {
+ _("混沌", "Chaos"),
+ { GF_CONFUSION, GF_CHAOS, GF_NEXUS },
+ { _("混乱", "Confusion"), _("カオス", "Chaos"), _("因果混乱", "Nexus") },
+ { },
+ }
+ },
+ {
+ ElementRealm::EARTH, {
+ _("地", "Earth"),
+ { GF_SHARDS, GF_FORCE, GF_METEOR },
+ { _("破片", "Shards"), _("フォース", "Force"), _("隕石", "Meteor") },
+ { },
+ }
+ },
+ {
+ ElementRealm::DEATH, {
+ _("瘴気", "Death"),
+ { GF_POIS, GF_HYPODYNAMIA, GF_DISENCHANT },
+ { _("毒", "Poison"), _("吸血", "Drain Life"), _("劣化", "Disenchantment") },
+ { },
+ }
+ },
+};
+
+/*!
+ * @brief 元素魔法呪文定義
+ */
+static 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") }}},
+ { ElementSpells::CURE, { 0, { 6, 5, 35, _("傷の治癒", "Cure Wounds") }}},
+ { ElementSpells::BOLT_2ND, { 1, { 8, 6, 35, _("%sの矢", "%s Bolt") }}},
+ { ElementSpells::MAG_DETECT, { 0, { 10, 8, 60, _("魔法感知", "Detect Magical Objs") }}},
+ { ElementSpells::BALL_3RD, { 2, { 15, 10, 55, _("%s放射", "%s Spout") }}},
+ { ElementSpells::BALL_1ST, { 0, { 18, 13, 65, _("%sの球", "%s Ball") }}},
+ { ElementSpells::BREATH_2ND, { 1, { 21, 20, 70, _("%sのブレス", "Breath of %s") }}},
+ { ElementSpells::ANNIHILATE, { 0, { 24, 20, 75, _("モンスター消滅", "Annihilation") }}},
+ { ElementSpells::BOLT_3RD, { 2, { 25, 15, 60, _("%sの矢", "%s Bolt") }}},
+ { ElementSpells::WAVE_1ST, { 0, { 28, 30, 75, _("元素の波動", "Elemental Wave") }}},
+ { ElementSpells::BALL_2ND, { 1, { 28, 22, 75, _("%sの球", "%s Ball") }}},
+ { ElementSpells::BURST_1ST, { 0, { 33, 35, 75, _("精気乱射", "%s Blast") }}},
+ { ElementSpells::STORM_2ND, { 1, { 35, 30, 75, _("%sの嵐", "%s Storm") }}},
+ { ElementSpells::BREATH_1ST, { 0, { 42, 48, 75, _("%sのブレス", "Breath of %s") }}},
+ { ElementSpells::STORM_3ND, { 2, { 45, 60, 80, _("%sの嵐", "%s Storm") }}},
+};
+
+/*!
+ * @brief 元素魔法呪文説明文定義
+ */
+static element_tip_list element_tips = {
+ { ElementSpells::BOLT_1ST,
+ _("弱い%sの矢を放つ。", "Fire a weak bolt of %s.") },
+ { ElementSpells::MON_DETECT,
+ _("近くの全てのモンスターを感知する。", "Detects monsters.") },
+ { ElementSpells::PERCEPT,
+ _("アイテムの雰囲気を知る。", "Gives feeling of an item.") },
+ { ElementSpells::CURE,
+ _("怪我と体力を少し回復させる。", "Heals HP and wounds a bit.") },
+ { ElementSpells::BOLT_2ND,
+ _("%sの矢を放つ。", "Fire a bolt of %s.") },
+ { ElementSpells::MAG_DETECT,
+ _("近くの魔法のアイテムを感知する。", "Detects magic devices.") },
+ { ElementSpells::BALL_3RD,
+ _("高威力で射程が短い%sの球を放つ。", "Fire a strong, short-range, ball of %s.") },
+ { ElementSpells::BALL_1ST,
+ _("%sの球を放つ。", "Fire a ball of %s.") },
+ { ElementSpells::BREATH_2ND,
+ _("%sのブレスを吐く。", "Fire a breath of %s.") },
+ { ElementSpells::ANNIHILATE,
+ _("%s耐性のないモンスターを1体抹殺する。", "Erase a monster unless it resists %s.") },
+ { ElementSpells::BOLT_3RD,
+ _("%sの矢を放つ。", "Fire a bolt of %s.") },
+ { ElementSpells::WAVE_1ST,
+ _("視界内の全ての敵に%sによるダメージを与える。", "Inflict %s damage on all monsters in sight.") },
+ { ElementSpells::BALL_2ND,
+ _("%sの球を放つ。", "Fire a ball of %s.") },
+ { ElementSpells::BURST_1ST,
+ _("ランダムな方向に%sの矢を放つ。", "Fire some bolts of %s in random direction.") },
+ { ElementSpells::STORM_2ND,
+ _("%sの巨大な球を放つ。", "Fire a large ball of %s.") },
+ { ElementSpells::BREATH_1ST,
+ _("%sのブレスを吐く。", "Fire a breath of %s.") },
+ { ElementSpells::STORM_3ND,
+ _("%sの巨大な球を放つ。", "Fire a large ball of %s.") },
+};
+
+/*!
+ * @brief 元素魔法選択時説明文定義
+ */
+static element_text_list element_texts = {
+ { ElementRealm::FIRE,
+ _("炎系統は巨大なエネルギーで灼熱を生み出し、全ての敵を燃やし尽くそうとします。",
+ "Great energy of Fire system will be able to burn out all of your enemies.")},
+ { ElementRealm::ICE,
+ _("氷系統の魔法はその冷たさで敵の動きを奪い尽くし、魂すらも止めてしまうでしょう。",
+ "Ice system will freeze your enemies, even their souls.")},
+ { ElementRealm::SKY,
+ _("空系統は大いなる天空のエネルギーを駆使して敵の全てを撃滅できます。",
+ "Sky system can terminate all of your enemies powerfully with the energy of the great sky.")},
+ { ElementRealm::SEA,
+ _("海系統はその敵の全てを溶かし、大いなる海へと返してしまいます。",
+ "Sea system melts all of your enemies and returns them to the great ocean.")},
+ { ElementRealm::DARKNESS,
+ _("闇系統は恐るべき力を常闇から引き出し、敵を地獄へと叩き落とすでしょう。",
+ "Dark system draws terrifying power from the darkness and knocks your enemies into hell.")},
+ { ElementRealm::CHAOS,
+ _("混沌系統は敵の意識も条理も捻じ曲げ、その存在をあの世に送ってしまいます。",
+ "Chaos system twists and wraps your enemies, even their souls, and scatters them as dust in the wind.")},
+ { ElementRealm::EARTH,
+ _("地系統は偉大なる大地の力を呼び出して、数多の敵のことごとくを粉砕しようとします。",
+ "Earth system smashes all of your enemies massively using its huge powers.")},
+ { ElementRealm::DEATH,
+ _("瘴気系統は全ての生ける者にとって途轍もない毒です。",
+ "Death system is a tremendous poison for all living enemies.")},
+};
+
+// clang-format on
+
+/*!
+ * @brief 元素魔法の領域名を返す
+ * @param realm_idx 領域番号
+ * @return 領域名
+ */
+concptr get_element_title(int realm_idx)
+{
+ auto realm = static_cast<ElementRealm>(realm_idx);
+ return element_types.at(realm).title.data();
+}
+
+/*!
+ * @brief 元素魔法領域の属性リストを返す
+ * @param realm_idx 領域番号
+ * @return 領域で使用できる属性リスト
+ */
+static std::array<spells_type, 3> get_element_types(int realm_idx)
+{
+ auto realm = static_cast<ElementRealm>(realm_idx);
+ return element_types.at(realm).type;
+}
+
+/*!
+ * @brief 元素魔法領域のn番目の属性を返す
+ * @param realm_idx 領域番号
+ * @param n 属性の何番目か
+ * @return 属性タイプ
+ */
+spells_type get_element_type(int realm_idx, int n)
+{
+ return get_element_types(realm_idx)[n];
+}
+
+/*!
+ * @brief 元素魔法領域のn番目の呪文用の属性を返す
+ * @param realm_idx 領域番号
+ * @param n 属性の何番目か
+ * @return 属性タイプ
+ */
+static spells_type get_element_spells_type(player_type *caster_ptr, int n) {
+ auto realm = element_types.at(static_cast<ElementRealm>(caster_ptr->realm1));
+ auto t = realm.type.at(n);
+ if (realm.extra.find(t) != realm.extra.end()) {
+ if (randint0(100) < caster_ptr->lev * 2)
+ return realm.extra.at(t);
+ }
+ return t;
+}
+
+/*!
+ * @brief 元素魔法領域の属性名リストを返す
+ * @param realm_idx 領域番号
+ * @return 領域で使用できる属性の名称リスト
+ */
+static std::array<std::string_view, 3> get_element_names(int realm_idx)
+{
+ auto realm = static_cast<ElementRealm>(realm_idx);
+ return element_types.at(realm).name;
+}
+
+/*!
+ * @brief 元素魔法領域のn番目の属性名を返す
+ * @param realm_idx 領域番号
+ * @param n 属性の何番目か
+ * @return 属性名
+ */
+concptr get_element_name(int realm_idx, int n)
+{
+ return get_element_names(realm_idx)[n].data();
+}
+
+/*!
+ * @brief 元素魔法の説明文を取得
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param spell_idx 呪文番号
+ * @return 説明文
+ */
+static concptr get_element_tip(player_type *caster_ptr, int spell_idx)
+{
+ auto realm = static_cast<ElementRealm>(caster_ptr->realm1);
+ auto spell = static_cast<ElementSpells>(spell_idx);
+ auto elem = element_powers.at(spell).elem;
+ return format(element_tips.at(spell).data(), element_types.at(realm).name[elem].data());
+}
+
+/*!
+ * @brief 元素魔法の説明文を取得
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param spell_idx 呪文番号
+ * @return 説明文
+ */
+static int get_elemental_elem(player_type *caster_ptr, int spell_idx)
+{
+ (void)caster_ptr;
+ auto spell = static_cast<ElementSpells>(spell_idx);
+ return element_powers.at(spell).elem;
+}
+
+/*!
+ * @brief 元素魔法呪文の難易度データを取得
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param spell_idx 呪文番号
+ * @return 説明文
+ */
+static mind_type get_elemental_info(player_type *caster_ptr, int spell_idx)
+{
+ (void)caster_ptr;
+ auto spell = static_cast<ElementSpells>(spell_idx);
+ return element_powers.at(spell).info;
+}
+
+/*!
+ * @brief 元素魔法呪文の効果表示文字列を取得
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param spell_idx 呪文番号
+ * @param p バッファ
+ * @return なし(pを更新)
+ */
+void get_element_effect_info(player_type *caster_ptr, int spell_idx, char *p)
+{
+ PLAYER_LEVEL plev = caster_ptr->lev;
+ auto spell = static_cast<ElementSpells>(spell_idx);
+ int dam = 0;
+
+ switch (spell) {
+ case ElementSpells::BOLT_1ST:
+ sprintf(p, " %s%dd%d", KWD_DAM, 3 + ((plev - 1) / 5), 4);
+ break;
+ case ElementSpells::CURE:
+ sprintf(p, " %s%dd%d", KWD_HEAL, 2, 8);
+ break;
+ case ElementSpells::BOLT_2ND:
+ sprintf(p, " %s%dd%d", KWD_DAM, 8 + ((plev - 5) / 4), 8);
+ break;
+ case ElementSpells::BALL_3RD:
+ sprintf(p, " %s%d", KWD_DAM, (50 + plev * 2));
+ break;
+ case ElementSpells::BALL_1ST:
+ sprintf(p, " %s%d", KWD_DAM, 55 + plev);
+ break;
+ case ElementSpells::BREATH_2ND:
+ dam = p_ptr->chp / 2;
+ sprintf(p, " %s%d", KWD_DAM, (dam > 150) ? 150 : dam);
+ break;
+ case ElementSpells::ANNIHILATE:
+ sprintf(p, " %s%d", _("効力:", "pow "), 50 + plev);
+ break;
+ case ElementSpells::BOLT_3RD:
+ sprintf(p, " %s%dd%d", KWD_DAM, 12 + ((plev - 5) / 4), 8);
+ break;
+ case ElementSpells::WAVE_1ST:
+ sprintf(p, " %sd%d", KWD_DAM, plev * 4);
+ break;
+ case ElementSpells::BALL_2ND:
+ sprintf(p, " %s%d", KWD_DAM, 75 + plev);
+ break;
+ case ElementSpells::BURST_1ST:
+ sprintf(p, " %s%dd%d", KWD_DAM, 6 + plev / 8, 8);
+ break;
+ case ElementSpells::STORM_2ND:
+ sprintf(p, " %s%d", KWD_DAM, 120 + plev * 2);
+ break;
+ case ElementSpells::BREATH_1ST:
+ sprintf(p, " %s%d", KWD_DAM, p_ptr->chp * 2 / 3);
+ break;
+ case ElementSpells::STORM_3ND:
+ sprintf(p, " %s%d", KWD_DAM, 300 + plev * 5);
+ break;
+ default:
+ p[0] = '\0';
+ break;
+ }
+}
+
+/*!
+ * @brief 元素魔法呪文を実行する
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param spell_idx 呪文番号
+ * @return 実行したらTRUE、キャンセルならFALSE
+ */
+static bool cast_element_spell(player_type *caster_ptr, SPELL_IDX spell_idx)
+{
+ auto spell = static_cast<ElementSpells>(spell_idx);
+ auto power = element_powers.at(spell);
+ spells_type typ;
+ DIRECTION dir;
+ PLAYER_LEVEL plev = caster_ptr->lev;
+ HIT_POINT dam;
+ POSITION y, x;
+ int num;
+
+ switch (spell) {
+ case ElementSpells::BOLT_1ST:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = damroll(3 + ((plev - 1) / 5), 4);
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ (void)fire_bolt(caster_ptr, typ, dir, dam);
+ break;
+ case ElementSpells::MON_DETECT:
+ (void)detect_monsters_normal(caster_ptr, DETECT_RAD_DEFAULT);
+ (void)detect_monsters_invis(caster_ptr, DETECT_RAD_DEFAULT);
+ break;
+ case ElementSpells::PERCEPT:
+ return psychometry(caster_ptr);
+ case ElementSpells::CURE:
+ (void)hp_player(caster_ptr, damroll(2, 8));
+ (void)set_cut(caster_ptr, caster_ptr->cut - 10);
+ break;
+ case ElementSpells::BOLT_2ND:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = damroll(8 + ((plev - 5) / 4), 8);
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ if (fire_bolt_or_beam(caster_ptr, plev, typ, dir, dam)) {
+ if (typ == GF_HYPODYNAMIA) {
+ (void)hp_player(caster_ptr, dam / 2);
+ }
+ }
+ break;
+ case ElementSpells::MAG_DETECT:
+ (void)detect_objects_magic(caster_ptr, DETECT_RAD_DEFAULT);
+ break;
+ case ElementSpells::BALL_3RD:
+ project_length = 4;
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ dam = 50 + plev * 2;
+ (void)fire_ball(caster_ptr, typ, dir, dam, 1);
+ project_length = 0;
+ break;
+ case ElementSpells::BALL_1ST:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = 55 + plev;
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ (void)fire_ball(caster_ptr, typ, dir, dam, 2);
+ break;
+ case ElementSpells::BREATH_2ND:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = MIN(150, caster_ptr->chp / 2);
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ if (fire_breath(caster_ptr, typ, dir, dam, 3)) {
+ if (typ == GF_HYPODYNAMIA) {
+ (void)hp_player(caster_ptr, dam / 2);
+ }
+ }
+ break;
+ case ElementSpells::ANNIHILATE:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ fire_ball_hide(caster_ptr, GF_E_GENOCIDE, dir, plev + 50, 0);
+ break;
+ case ElementSpells::BOLT_3RD:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = damroll(12 + ((plev - 5) / 4), 8);
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ fire_bolt_or_beam(caster_ptr, plev, typ, dir, dam);
+ break;
+ case ElementSpells::WAVE_1ST:
+ dam = randint1(plev * 4);
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ project_all_los(caster_ptr, typ, dam);
+ break;
+ case ElementSpells::BALL_2ND:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = 75 + plev;
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ if (fire_ball(caster_ptr, typ, dir, dam, 2)) {
+ if (typ == GF_HYPODYNAMIA) {
+ (void)hp_player(caster_ptr, dam / 2);
+ }
+ }
+ break;
+ case ElementSpells::BURST_1ST:
+ y = caster_ptr->y;
+ x = caster_ptr->x;
+ num = damroll(5, 3);
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ for (int k = 0; k < num; k++) {
+ int attempts = 1000;
+ while (attempts--) {
+ scatter(caster_ptr, &y, &x, caster_ptr->y, caster_ptr->x, 4, PROJECT_NONE);
+ if (!player_bold(caster_ptr, y, x))
+ break;
+ }
+ project(caster_ptr, 0, 0, y, x, damroll(6 + plev / 8, 10), typ, (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_KILL), -1);
+ }
+ break;
+ case ElementSpells::STORM_2ND:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = 125 + plev * 2;
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ if (fire_ball(caster_ptr, typ, dir, dam, 4)) {
+ if (typ == GF_HYPODYNAMIA) {
+ (void)hp_player(caster_ptr, dam / 2);
+ }
+ }
+ break;
+ case ElementSpells::BREATH_1ST:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = caster_ptr->chp * 2 / 3;
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ (void)fire_breath(caster_ptr, typ, dir, dam, 3);
+ break;
+ case ElementSpells::STORM_3ND:
+ if (!get_aim_dir(caster_ptr, &dir))
+ return FALSE;
+ dam = 300 + plev * 5;
+ typ = get_element_spells_type(caster_ptr, power.elem);
+ (void)fire_ball(caster_ptr, typ, dir, dam, 5);
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*!
+ * @brief 元素魔法呪文の失敗率を計算
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param spell_idx 呪文番号
+ * @return 失敗率
+ */
+static PERCENTAGE decide_element_chance(player_type *caster_ptr, mind_type spell)
+{
+ PERCENTAGE chance = spell.fail;
+
+ chance -= 3 * (caster_ptr->lev - spell.min_lev);
+ chance += caster_ptr->to_m_chance;
+ chance -= 3 * (adj_mag_stat[caster_ptr->stat_index[A_WIS]] - 1);
+
+ PERCENTAGE minfail = adj_mag_fail[caster_ptr->stat_index[A_WIS]];
+ if (chance < minfail)
+ chance = minfail;
+
+ if (caster_ptr->stun > 50)
+ chance += 25;
+ else if (caster_ptr->stun)
+ chance += 15;
+
+ if (heavy_armor(caster_ptr))
+ chance += 5;
+
+ if (caster_ptr->icky_wield[0])
+ chance += 5;
+
+ if (caster_ptr->icky_wield[1])
+ chance += 5;
+
+ if (chance > 95)
+ chance = 95;
+
+ return chance;
+}
+
+/*!
+ * @brief 元素魔法呪文の消費MPを計算
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param spell_idx 呪文番号
+ * @return 消費MP
+ */
+static MANA_POINT decide_element_mana_cost(player_type *caster_ptr, mind_type spell)
+{
+ (void)caster_ptr;
+ return spell.mana_cost;
+}
+
+/*!
+ * @brief 元素魔法呪文を選択して取得
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param sn 呪文番号
+ * @param only_browse 閲覧モードかどうか
+ * @return 選んだらTRUE、選ばなかったらFALSE
+ */
+bool get_element_power(player_type *caster_ptr, SPELL_IDX *sn, bool only_browse)
+{
+ SPELL_IDX i;
+ int num = 0;
+ TERM_LEN y = 1;
+ TERM_LEN x = 10;
+ PLAYER_LEVEL plev = caster_ptr->lev;
+ int ask = TRUE;
+ char choice;
+ char out_val[160];
+ char comment[80];
+ COMMAND_CODE code;
+ bool flag, redraw;
+ int menu_line = (use_menu ? 1 : 0);
+
+ *sn = -1;
+ if (repeat_pull(&code)) {
+ *sn = (SPELL_IDX)code;
+ if (get_elemental_info(caster_ptr, *sn).min_lev <= plev)
+ return TRUE;
+ }
+
+ concptr p = _("元素魔法", "magic");
+ flag = FALSE;
+ redraw = FALSE;
+
+ for (i = 0; i < static_cast<SPELL_IDX>(ElementSpells::MAX); i++) {
+ if (get_elemental_info(caster_ptr, i).min_lev <= plev)
+ num++;
+ }
+
+ if (only_browse)
+ (void)strnfmt(out_val, 78,
+ _("(%^s %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
+ p, I2A(0), I2A(num - 1), p);
+ else
+ (void)strnfmt(out_val, 78,
+ _("(%^s %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
+ 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;
+ while (!flag) {
+ if (choice == ESCAPE)
+ choice = ' ';
+ else if (!get_com(out_val, &choice, TRUE))
+ break;
+
+ if (use_menu && choice != ' ') {
+ switch (choice) {
+ case '0':
+ if (!only_browse)
+ screen_load();
+ return FALSE;
+ case '8':
+ case 'k':
+ case 'K':
+ menu_line += (num - 1);
+ break;
+ case '2':
+ case 'j':
+ case 'J':
+ menu_line++;
+ break;
+ case 'x':
+ case 'X':
+ case '\r':
+ case '\n':
+ i = menu_line - 1;
+ ask = FALSE;
+ break;
+ }
+
+ if (menu_line > num)
+ menu_line -= num;
+ }
+
+ int spell_max = static_cast<int>(ElementSpells::MAX);
+ if ((choice == ' ') || (choice == '*') || (choice == '?') || (use_menu && ask)) {
+ if (!redraw || use_menu) {
+ char desc[80];
+ char name[80];
+ redraw = TRUE;
+ if (!only_browse && !use_menu)
+ screen_save();
+
+ prt("", y, x);
+ put_str(_("名前", "Name"), y, x + 5);
+ put_str(_("Lv MP 失率 効果", "Lv MP Fail Info"), y, x + 35);
+ for (i = 0; i < spell_max; i++) {
+ elem = get_elemental_elem(caster_ptr, i);
+ spell = get_elemental_info(caster_ptr, i);
+
+ if (spell.min_lev > plev)
+ break;
+
+ PERCENTAGE chance = decide_element_chance(caster_ptr, spell);
+ int mana_cost = decide_element_mana_cost(caster_ptr, spell);
+ get_element_effect_info(caster_ptr, i, comment);
+
+ if (use_menu) {
+ if (i == (menu_line - 1))
+ strcpy(desc, _(" 》 ", " > "));
+ else
+ strcpy(desc, " ");
+ } else
+ sprintf(desc, " %c) ", I2A(i));
+
+ concptr s = get_element_name(caster_ptr->realm1, elem);
+ sprintf(name, spell.name, s);
+ strcat(desc,
+ format("%-30s%2d %4d %3d%%%s", name, spell.min_lev, mana_cost, chance, comment));
+ prt(desc, y + i + 1, x);
+ }
+
+ prt("", y + i + 1, x);
+ } else if (!only_browse) {
+ redraw = FALSE;
+ screen_load();
+ }
+
+ continue;
+ }
+
+ if (!use_menu) {
+ ask = isupper(choice);
+ if (ask)
+ choice = (char)tolower(choice);
+
+ i = (islower(choice) ? A2I(choice) : -1);
+ }
+
+ if ((i < 0) || (i >= num)) {
+ bell();
+ continue;
+ }
+
+ spell = get_elemental_info(caster_ptr, i);
+ if (ask) {
+ char tmp_val[160];
+ (void)strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), spell.name);
+ if (!get_check(tmp_val))
+ continue;
+ }
+
+ flag = TRUE;
+ }
+
+ if (redraw && !only_browse)
+ screen_load();
+
+ set_bits(caster_ptr->window_flags, PW_SPELL);
+ handle_stuff(caster_ptr);
+ if (!flag)
+ return FALSE;
+
+ *sn = i;
+ repeat_push((COMMAND_CODE)i);
+ return TRUE;
+}
+
+/*!
+ * @brief 元素魔法呪文をMPがなくても挑戦するか確認する
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param mana_cost 消費MP
+ * @return 詠唱するならTRUE、しないならFALSE
+ */
+static bool check_element_mp_sufficiency(player_type *caster_ptr, int mana_cost)
+{
+ if (mana_cost <= caster_ptr->csp)
+ return TRUE;
+
+ msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
+ if (!over_exert)
+ return FALSE;
+
+ return get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
+}
+
+/*!
+ * @brief 元素魔法呪文の詠唱を試み、成功なら詠唱し、失敗ならファンブルする
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param spell_idx 呪文番号
+ * @param chance 失敗率
+ * @return 詠唱して実行したらTRUE、されなかったらFALSE
+ */
+static bool try_cast_element_spell(player_type *caster_ptr, SPELL_IDX spell_idx, PERCENTAGE chance)
+{
+ if (randint0(100) >= chance) {
+ sound(SOUND_ZAP);
+ return cast_element_spell(caster_ptr, spell_idx);
+ }
+
+ if (flush_failure)
+ flush();
+
+ msg_format(_("魔力の集中に失敗した!", "You failed to concentrate hard enough for Mana!"));
+ sound(SOUND_FAIL);
+
+ if (randint1(100) < chance / 2) {
+ int plev = caster_ptr->lev;
+ msg_print(_("元素の力が制御できない氾流となって解放された!",
+ "Elemental power unleashes its power in an uncontrollable storm!"));
+ project(caster_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + plev / 10, caster_ptr->y, caster_ptr->x, plev * 2,
+ get_element_types(caster_ptr->realm1)[0],
+ PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM, -1);
+ caster_ptr->csp = MAX(0, caster_ptr->csp - plev * MAX(1, plev / 10));
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*!
+ * @brief 元素魔法コマンドのメインルーチン
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @return なし
+ */
+void do_cmd_element(player_type *caster_ptr)
+{
+ SPELL_IDX i;
+ if (cmd_limit_confused(caster_ptr) || !get_element_power(caster_ptr, &i, FALSE))
+ return;
+
+ mind_type spell = get_elemental_info(caster_ptr, i);
+ PERCENTAGE chance = decide_element_chance(caster_ptr, spell);
+ int mana_cost = decide_element_mana_cost(caster_ptr, spell);
+
+ if (!check_element_mp_sufficiency(caster_ptr, mana_cost))
+ return;
+
+ if (!try_cast_element_spell(caster_ptr, i, chance))
+ return;
+
+ if (mana_cost <= caster_ptr->csp) {
+ caster_ptr->csp -= mana_cost;
+ } else {
+ int oops = mana_cost;
+ caster_ptr->csp = 0;
+ caster_ptr->csp_frac = 0;
+ msg_print(_("精神を集中しすぎて気を失ってしまった!", "You faint from the effort!"));
+ (void)set_paralyzed(caster_ptr, caster_ptr->paralyzed + randint1(5 * oops + 1));
+ chg_virtue(caster_ptr, V_KNOWLEDGE, -10);
+ if (randint0(100) < 50) {
+ bool perm = (randint0(100) < 25);
+ msg_print(_("体を悪くしてしまった!", "You have damaged your health!"));
+ (void)dec_stat(caster_ptr, A_CON, 15 + randint1(10), perm);
+ }
+ }
+
+ take_turn(caster_ptr, 100);
+ set_bits(caster_ptr->redraw, PR_MANA);
+ set_bits(caster_ptr->window_flags, PW_PLAYER | PW_SPELL);
+}
+
+/*!
+ * @brief 現在プレイヤーが使用可能な元素魔法の一覧表示
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @return なし
+ */
+void do_cmd_element_browse(player_type *caster_ptr)
+{
+ SPELL_IDX n = 0;
+ char temp[62 * 5];
+
+ screen_save();
+ while (TRUE) {
+ if (!get_element_power(caster_ptr, &n, TRUE)) {
+ screen_load();
+ 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);
+ shape_buffer(get_element_tip(caster_ptr, n), 62, temp, sizeof(temp));
+ for (int j = 0, line = 17; temp[j]; j += (1 + strlen(&temp[j]))) {
+ prt(&temp[j], line, 15);
+ line++;
+ }
+
+ prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);
+ (void)inkey();
+ }
+}
+
+
+/*!
+ * @brief 元素魔法の単体抹殺の効果を発動する
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param em_ptr 魔法効果情報への参照ポインタ
+ * @return 効果処理を続けるかどうか
+ */
+process_result effect_monster_elemental_genocide(player_type *caster_ptr, effect_monster_type *em_ptr)
+{
+ auto types = get_element_types(caster_ptr->realm1);
+ char m_name[160];
+
+ monster_desc(caster_ptr, m_name, em_ptr->m_ptr, 0);
+ msg_format(_("%sが%sを包み込んだ。", "The %s surrounds %s."), types[0], m_name);
+
+ auto realm = static_cast<ElementRealm>(caster_ptr->realm1);
+ switch (realm) {
+ case ElementRealm::FIRE:
+ if (any_bits(em_ptr->r_ptr->r_flagsr, RFR_IM_FIRE))
+ return PROCESS_CONTINUE;
+ break;
+ case ElementRealm::ICE:
+ if (any_bits(em_ptr->r_ptr->r_flagsr, RFR_IM_COLD))
+ return PROCESS_CONTINUE;
+ break;
+ case ElementRealm::SKY:
+ if (any_bits(em_ptr->r_ptr->r_flagsr, RFR_IM_ELEC))
+ return PROCESS_CONTINUE;
+ break;
+ case ElementRealm::SEA:
+ if (any_bits(em_ptr->r_ptr->r_flagsr, RFR_IM_ACID))
+ return PROCESS_CONTINUE;
+ break;
+ case ElementRealm::DARKNESS:
+ if (any_bits(em_ptr->r_ptr->r_flagsr, RFR_RES_DARK) || any_bits(em_ptr->r_ptr->r_flags3, RF3_HURT_LITE))
+ return PROCESS_CONTINUE;
+ break;
+ case ElementRealm::CHAOS:
+ if (any_bits(em_ptr->r_ptr->r_flags3, RF3_NO_CONF))
+ return PROCESS_CONTINUE;
+ break;
+ case ElementRealm::EARTH:
+ if (any_bits(em_ptr->r_ptr->r_flagsr, RFR_RES_SHAR))
+ return PROCESS_CONTINUE;
+ break;
+ case ElementRealm::DEATH:
+ if (any_bits(em_ptr->r_ptr->r_flagsr, RFR_IM_POIS))
+ return PROCESS_CONTINUE;
+ break;
+ default:
+ return PROCESS_CONTINUE;
+ }
+
+ if (em_ptr->seen)
+ em_ptr->obvious = TRUE;
+
+ if (genocide_aux(caster_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam, !em_ptr->who, (em_ptr->r_ptr->level + 1) / 2, _("モンスター消滅", "Genocide One"))) {
+ if (em_ptr->seen_msg)
+ msg_format(_("%sは消滅した!", "%^s disappeared!"), em_ptr->m_name);
+ chg_virtue(caster_ptr, V_VITALITY, -1);
+ return PROCESS_TRUE;
+ }
+
+ em_ptr->skipped = TRUE;
+ return PROCESS_CONTINUE;
+}
+
+/*!
+ * @brief 元素領域とレベルの条件に見合うかチェックする
+ * @param caster_ptr プレイヤー情報への参照ポインタ
+ * @param realm 領域
+ * @param lev プレイヤーレベル
+ * @return 見合うならTRUE、そうでなければFALSE
+ * @detail
+ * レベルに応じて取得する耐性などの判定に使用する
+ */
+bool has_element_resist(player_type *creature_ptr, ElementRealm realm, PLAYER_LEVEL lev)
+{
+ if (creature_ptr->pclass != CLASS_ELEMENTALIST)
+ return FALSE;
+
+ auto prealm = static_cast<ElementRealm>(creature_ptr->realm1);
+ return (prealm == realm && creature_ptr->lev >= lev);
+}
+
+/*!
+ * @brief 領域選択時のカーソル表示(シンボル+領域名)
+ * @param i 位置
+ * @param n 最後尾の位置
+ * @param color 表示色
+ * @return なし
+ */
+static void display_realm_cursor(int i, int n, term_color_type color)
+{
+ char cur[80];
+ char sym;
+ concptr name;
+ if (i == n) {
+ sym = '*';
+ name = _("ランダム", "Random");
+ } else {
+ sym = I2A(i);
+ name = element_types.at(static_cast<ElementRealm>(i + 1)).title.data();
+ }
+ sprintf(cur, "%c) %s", sym, name);
+
+ c_put_str(color, cur, 12 + (i / 5), 2 + 15 * (i % 5));
+}
+
+/*!
+ * @brief 領域選択時の移動キー処理
+ * @param cs 現在位置
+ * @param n 最後尾の位置
+ * @param c 入力キー
+ * @return 新しい位置
+ */
+static int interpret_realm_select_key(int cs, int n, char c)
+{
+ if (c == 'Q')
+ quit(NULL);
+
+ if (c == '8')
+ if (cs >= 5)
+ return cs - 5;
+
+ if (c == '4')
+ if (cs > 0)
+ return cs - 1;
+
+ if (c == '6')
+ if (cs < n)
+ return cs + 1;
+
+ if (c == '2')
+ if (cs + 5 <= n)
+ return cs + 5;
+
+ return cs;
+}
+
+/*!
+ * @brief 領域選択ループ処理
+ * @param creature_ptr プレイヤー情報への参照ポインタ
+ * @param n 最後尾の位置
+ * @return 領域番号
+ */
+static int get_element_realm(player_type *creature_ptr, int is, int n)
+{
+ int cs = MAX(0, is);
+ int os = cs;
+ int k;
+
+ char buf[80];
+ sprintf(buf, _("領域を選んで下さい(%c-%c) ('='初期オプション設定): ", "Choose a realm (%c-%c) ('=' for options): "), I2A(0), I2A(n - 1));
+
+ while (TRUE) {
+ display_realm_cursor(os, n, TERM_WHITE);
+ display_realm_cursor(cs, n, TERM_YELLOW);
+ put_str(buf, 10, 10);
+ os = cs;
+
+ char c = inkey();
+ cs = interpret_realm_select_key(cs, n, c);
+
+ if (c == 'S')
+ return 255;
+
+ if (c == ' ' || c == '\r' || c == '\n') {
+ if (cs == n) {
+ display_realm_cursor(cs, n, TERM_WHITE);
+ cs = randint0(n - 1);
+ }
+ break;
+ }
+
+ if (c == '*') {
+ display_realm_cursor(cs, n, TERM_WHITE);
+ cs = randint0(n - 1);
+ break;
+ }
+
+ k = islower(c) ? A2I(c) : -1;
+ if (k >= 0 && k < n) {
+ display_realm_cursor(cs, n, TERM_WHITE);
+ cs = k;
+ break;
+ }
+
+ k = isupper(c) ? (26 + c - 'A') : -1;
+ if (k >= 26 && k < n) {
+ display_realm_cursor(cs, n, TERM_WHITE);
+ cs = k;
+ break;
+ }
+
+ if (c == '=') {
+ screen_save();
+ do_cmd_options_aux(creature_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
+ screen_load();
+ } else if (c != '2' && c != '4' && c != '6' && c != '8')
+ bell();
+ }
+
+ display_realm_cursor(cs, n, TERM_YELLOW);
+ return (cs + 1);
+}
+
+/*!
+ * @brief 領域選択
+ * @param creature_ptr プレイヤー情報への参照ポインタ
+ * @return 領域番号
+ */
+byte select_element_realm(player_type *creature_ptr)
+{
+ clear_from(10);
+
+ int realm_max = static_cast<int>(ElementRealm::MAX);
+ int realm_idx = 1;
+ int row = 16;
+ while (1) {
+ put_str(
+ _("注意:元素系統の選択によりあなたが習得する呪文のタイプが決まります。", "Note: The system of element will determine which spells you can learn."),
+ 23, 5);
+
+ for (int i = 0; i < realm_max; i++) {
+ display_realm_cursor(i, realm_max - 1, TERM_WHITE);
+ }
+
+ realm_idx = get_element_realm(creature_ptr, realm_idx - 1, realm_max - 1);
+ if (realm_idx == 255)
+ break;
+
+ auto realm = static_cast<ElementRealm>(realm_idx);
+ char temp[80 * 5];
+ shape_buffer(element_texts.at(realm).data(), 74, temp, sizeof(temp));
+ concptr t = temp;
+ for (int i = 0; i < 5; i++) {
+ if (t[0] == 0)
+ break;
+ prt(t, row + i, 3);
+ t += strlen(t) + 1;
+ }
+
+ if (get_check_strict(creature_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
+ break;
+
+ clear_from(row);
+ }
+
+ clear_from(10);
+ return (byte)realm_idx;
+}
+
+/*!
+ * @brief クラスパワー情報を追加
+ * @param creature_ptr プレイヤー情報への参照ポインタ
+ * @param rc_ptr レイシャルパワー情報への参照ポインタ
+ * @return なし
+ */
+void switch_element_racial(player_type *creature_ptr, rc_type *rc_ptr)
+{
+ auto realm = static_cast<ElementRealm>(creature_ptr->realm1);
+ switch (realm) {
+ case ElementRealm::FIRE:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("ライト・エリア", "Light area"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 3;
+ rc_ptr->power_desc[rc_ptr->num].cost = 5;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 10;
+ rc_ptr->power_desc[rc_ptr->num++].number = -4;
+ break;
+ case ElementRealm::ICE:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("フリーズ・モンスター", "Sleep monster"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 10;
+ rc_ptr->power_desc[rc_ptr->num].cost = 10;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 15;
+ rc_ptr->power_desc[rc_ptr->num++].number = -4;
+ break;
+ case ElementRealm::SKY:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("魔力充填", "Recharging"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 20;
+ rc_ptr->power_desc[rc_ptr->num].cost = 15;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 25;
+ rc_ptr->power_desc[rc_ptr->num++].number = -4;
+ break;
+ case ElementRealm::SEA:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("岩石溶解", "Stone to mud"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 5;
+ rc_ptr->power_desc[rc_ptr->num].cost = 5;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 10;
+ rc_ptr->power_desc[rc_ptr->num++].number = -4;
+ break;
+ case ElementRealm::DARKNESS:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("アンデッド従属", "Enslave undead"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 10;
+ rc_ptr->power_desc[rc_ptr->num].cost = 10;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 20;
+ rc_ptr->power_desc[rc_ptr->num++].number = -4;
+ break;
+ case ElementRealm::CHAOS:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("現実変容", "Alter reality"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 35;
+ rc_ptr->power_desc[rc_ptr->num].cost = 30;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 40;
+ rc_ptr->power_desc[rc_ptr->num++].number = -4;
+ break;
+ case ElementRealm::EARTH:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("地震", "Earthquake"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 25;
+ rc_ptr->power_desc[rc_ptr->num].cost = 15;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 20;
+ rc_ptr->power_desc[rc_ptr->num++].number = -4;
+ break;
+ case ElementRealm::DEATH:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("害虫駆除", "Pesticide"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 5;
+ rc_ptr->power_desc[rc_ptr->num].cost = 3;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 20;
+ rc_ptr->power_desc[rc_ptr->num++].number = -4;
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ * @brief クラスパワーを実行
+ * @param creature_ptr プレイヤー情報への参照ポインタ
+ * @return 実行したらTRUE、しなかったらFALSE
+ */
+bool switch_element_execution(player_type *creature_ptr)
+{
+ auto realm = static_cast<ElementRealm>(creature_ptr->realm1);
+ PLAYER_LEVEL plev = creature_ptr->lev;
+ DIRECTION dir;
+
+ switch (realm) {
+ case ElementRealm::FIRE:
+ (void)lite_area(creature_ptr, damroll(2, plev / 2), plev / 10);
+ break;
+ case ElementRealm::ICE:
+ if (!get_aim_dir(creature_ptr, &dir))
+ return FALSE;
+ (void)project_hook(creature_ptr, GF_OLD_SLEEP, dir, (plev * 2), PROJECT_STOP | PROJECT_KILL | PROJECT_REFLECTABLE);
+ break;
+ case ElementRealm::SKY:
+ (void)recharge(creature_ptr, 120);
+ break;
+ case ElementRealm::SEA:
+ if (!get_aim_dir(creature_ptr, &dir))
+ return FALSE;
+ (void)wall_to_mud(creature_ptr, dir, plev * 3 / 2);
+ break;
+ case ElementRealm::DARKNESS:
+ if (!get_aim_dir(creature_ptr, &dir))
+ return FALSE;
+ (void)control_one_undead(creature_ptr, dir, plev * 3 / 2);
+ break;
+ case ElementRealm::CHAOS:
+ reserve_alter_reality(creature_ptr, randint0(21) + 15);
+ break;
+ case ElementRealm::EARTH:
+ (void)earthquake(creature_ptr, creature_ptr->y, creature_ptr->x, 10, 0);
+ break;
+ case ElementRealm::DEATH:
+ (void)dispel_monsters(creature_ptr, plev / 2);
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
--- /dev/null
+#pragma once
+
+#include "system/angband.h"
+#include "spell/spell-types.h"
+
+enum class ElementRealm {
+ FIRE = 1,
+ ICE = 2,
+ SKY = 3,
+ SEA = 4,
+ DARKNESS = 5,
+ CHAOS = 6,
+ EARTH = 7,
+ DEATH = 8,
+ MAX
+};
+
+typedef struct player_type player_type;
+typedef struct effect_monster_type effect_monster_type;
+typedef struct rc_type rc_type;
+
+concptr get_element_title(int realm_idx);
+spells_type get_element_type(int realm_idx, int n);
+concptr get_element_name(int realm_idx, int n);
+void do_cmd_element(player_type *caster_ptr);
+void do_cmd_element_browse(player_type *caster_ptr);
+process_result effect_monster_elemental_genocide(player_type *caster_ptr, effect_monster_type *em_ptr);
+bool has_element_resist(player_type *creature_ptr, ElementRealm realm, PLAYER_LEVEL lev);
+byte select_element_realm(player_type *creature_ptr);
+void switch_element_racial(player_type *creature_ptr, rc_type *rc_ptr);
+bool switch_element_execution(player_type *creature_ptr);
case TV_FIGURINE:
okay = TRUE;
break;
+
+ default:
+ break;
}
autopick_alter_item(caster_ptr, item, (bool)(okay && destroy_feeling));
MIND_BERSERKER = 2, /*!< 特殊能力: 怒り */
MIND_MIRROR_MASTER = 3, /*!< 特殊能力: 鏡魔法 */
MIND_NINJUTSU = 4, /*!< 特殊能力: 忍術 */
+ MIND_ELEMENTAL = 5, //!< 特殊能力: 元素魔法 */
};
if (o_ptr->sval != SV_POISON_NEEDLE)
return TRUE;
}
+
+ default:
+ break;
}
return FALSE;
monster_attack_show(monap_ptr);
break;
}
+
+ case RBM_NONE:
+ case RBM_SHOOT:
+ case NB_RBM_TYPE:
+ break;
}
}
monap_ptr->obvious = TRUE;
monap_ptr->damage = 0;
break;
+
+ case NB_RBE_TYPE:
+ break;
}
}
floor_type *floor_ptr = player_ptr->current_floor_ptr;
bool is_drop_corpse = one_in_(md_ptr->r_ptr->flags1 & RF1_UNIQUE ? 1 : 4);
is_drop_corpse &= (md_ptr->r_ptr->flags9 & (RF9_DROP_CORPSE | RF9_DROP_SKELETON)) != 0;
- is_drop_corpse &= !(floor_ptr->inside_arena || player_ptr->phase_out || md_ptr->cloned || ((md_ptr->m_ptr->r_idx == today_mon) && is_pet(md_ptr->m_ptr)));
+ is_drop_corpse &= !(floor_ptr->inside_arena || player_ptr->phase_out || md_ptr->cloned
+ || ((md_ptr->m_ptr->r_idx == current_world_ptr->today_mon) && is_pet(md_ptr->m_ptr)));
if (!is_drop_corpse)
return;
return _("は爆発して粉々になった。", " explodes into tiny shreds.");
return _("を倒した。", " is destroyed.");
-}
\ No newline at end of file
+}
-#include "monster-floor/monster-lite.h"
+#include <vector>
+
#include "core/player-update-types.h"
#include "dungeon/dungeon-flag-types.h"
#include "dungeon/dungeon.h"
#include "grid/feature-flag-types.h"
#include "grid/grid.h"
#include "monster-floor/monster-lite-util.h"
+#include "monster-floor/monster-lite.h"
#include "monster-race/monster-race.h"
#include "monster-race/race-flags7.h"
#include "monster/monster-status.h"
#include "view/display-messages.h"
#include "world/world.h"
+struct Point {
+ int y;
+ int x;
+ Point(const int y, const int x)
+ : y(y)
+ , x(x)
+ {
+ }
+};
+
/*!
* @brief モンスターによる光量状態更新 / Add a square to the changes array
* @param subject_ptr 主観となるクリーチャーの参照ポインタ
+ * @param points 座標たちを記録する配列
* @param y Y座標
* @param x X座標
*/
-static void update_monster_lite(player_type *subject_ptr, const POSITION y, const POSITION x, monster_lite_type *ml_ptr)
+static void update_monster_lite(
+ player_type *const subject_ptr, std::vector<Point> &points, const POSITION y, const POSITION x, const monster_lite_type *const ml_ptr)
{
grid_type *g_ptr;
int dpf, d;
}
if (!(g_ptr->info & CAVE_MNDK)) {
- tmp_pos.x[tmp_pos.n] = x;
- tmp_pos.y[tmp_pos.n] = y;
- tmp_pos.n++;
+ points.emplace_back(y, x);
} else {
g_ptr->info &= ~(CAVE_MNDK);
}
/*
* Add a square to the changes array
*/
-static void update_monster_dark(player_type *subject_ptr, const POSITION y, const POSITION x, monster_lite_type *ml_ptr)
+static void update_monster_dark(
+ player_type *const subject_ptr, std::vector<Point> &points, const POSITION y, const POSITION x, const monster_lite_type *const ml_ptr)
{
grid_type *g_ptr;
int midpoint, dpf, d;
}
}
- tmp_pos.x[tmp_pos.n] = x;
- tmp_pos.y[tmp_pos.n] = y;
- tmp_pos.n++;
+ points.emplace_back(y, x);
g_ptr->info |= CAVE_MNDK;
}
*/
void update_mon_lite(player_type *subject_ptr)
{
- void (*add_mon_lite)(player_type *, const POSITION, const POSITION, monster_lite_type *);
+ // 座標たちを記録する配列。
+ std::vector<Point> points;
+
+ void (*add_mon_lite)(player_type *, std::vector<Point> &, const POSITION, const POSITION, const monster_lite_type *);
int dis_lim = ((d_info[subject_ptr->dungeon_idx].flags1 & DF1_DARKNESS) && !subject_ptr->see_nocto) ? (MAX_SIGHT / 2 + 1) : (MAX_SIGHT + 3);
floor_type *floor_ptr = subject_ptr->current_floor_ptr;
for (int i = 0; i < floor_ptr->mon_lite_n; i++) {
g_ptr->info &= ~(CAVE_MNLT | CAVE_MNDK);
}
- tmp_pos.n = 0;
if (!current_world_ptr->timewalk_m_idx) {
monster_type *m_ptr;
monster_race *r_ptr;
monster_lite_type tmp_ml;
monster_lite_type *ml_ptr = initialize_monster_lite_type(floor_ptr, &tmp_ml, m_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx + 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx - 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx + 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx - 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 1, ml_ptr);
if (rad < 2)
continue;
grid_type *g_ptr;
if (cave_has_flag_bold(subject_ptr->current_floor_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx, f_flag)) {
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 2, ml_ptr->mon_fx + 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 2, ml_ptr->mon_fx, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 2, ml_ptr->mon_fx - 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx + 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx - 1, ml_ptr);
g_ptr = &floor_ptr->grid_array[ml_ptr->mon_fy + 2][ml_ptr->mon_fx];
if ((rad == 3) && cave_has_flag_grid(g_ptr, f_flag)) {
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 3, ml_ptr->mon_fx + 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 3, ml_ptr->mon_fx, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 3, ml_ptr->mon_fx - 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 3, ml_ptr->mon_fx + 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 3, ml_ptr->mon_fx, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 3, ml_ptr->mon_fx - 1, ml_ptr);
}
}
if (cave_has_flag_bold(subject_ptr->current_floor_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx, f_flag)) {
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 2, ml_ptr->mon_fx + 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 2, ml_ptr->mon_fx, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 2, ml_ptr->mon_fx - 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx + 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx - 1, ml_ptr);
g_ptr = &floor_ptr->grid_array[ml_ptr->mon_fy - 2][ml_ptr->mon_fx];
if ((rad == 3) && cave_has_flag_grid(g_ptr, f_flag)) {
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 3, ml_ptr->mon_fx + 1, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 3, ml_ptr->mon_fx, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 3, ml_ptr->mon_fx - 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 3, ml_ptr->mon_fx + 1, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 3, ml_ptr->mon_fx, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 3, ml_ptr->mon_fx - 1, ml_ptr);
}
}
if (cave_has_flag_bold(subject_ptr->current_floor_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx + 1, f_flag)) {
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 2, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx + 2, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx + 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 2, ml_ptr);
g_ptr = &floor_ptr->grid_array[ml_ptr->mon_fy][ml_ptr->mon_fx + 2];
if ((rad == 3) && cave_has_flag_grid(g_ptr, f_flag)) {
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 3, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx + 3, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 3, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 3, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx + 3, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 3, ml_ptr);
}
}
if (cave_has_flag_bold(subject_ptr->current_floor_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx - 1, f_flag)) {
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 2, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx - 2, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx - 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 2, ml_ptr);
g_ptr = &floor_ptr->grid_array[ml_ptr->mon_fy][ml_ptr->mon_fx - 2];
if ((rad == 3) && cave_has_flag_grid(g_ptr, f_flag)) {
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 3, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy, ml_ptr->mon_fx - 3, ml_ptr);
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 3, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 3, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy, ml_ptr->mon_fx - 3, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 3, ml_ptr);
}
}
continue;
if (cave_has_flag_bold(subject_ptr->current_floor_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx + 1, f_flag))
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 2, ml_ptr->mon_fx + 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx + 2, ml_ptr);
if (cave_has_flag_bold(subject_ptr->current_floor_ptr, ml_ptr->mon_fy + 1, ml_ptr->mon_fx - 1, f_flag))
- add_mon_lite(subject_ptr, ml_ptr->mon_fy + 2, ml_ptr->mon_fx - 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy + 2, ml_ptr->mon_fx - 2, ml_ptr);
if (cave_has_flag_bold(subject_ptr->current_floor_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx + 1, f_flag))
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 2, ml_ptr->mon_fx + 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx + 2, ml_ptr);
if (cave_has_flag_bold(subject_ptr->current_floor_ptr, ml_ptr->mon_fy - 1, ml_ptr->mon_fx - 1, f_flag))
- add_mon_lite(subject_ptr, ml_ptr->mon_fy - 2, ml_ptr->mon_fx - 2, ml_ptr);
+ add_mon_lite(subject_ptr, points, ml_ptr->mon_fy - 2, ml_ptr->mon_fx - 2, ml_ptr);
}
}
- s16b end_temp = tmp_pos.n;
+ const auto end_temp = size(points);
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];
} else if ((g_ptr->info & (CAVE_VIEW | CAVE_MNDK)) == CAVE_VIEW)
cave_note_and_redraw_later(floor_ptr, g_ptr, fy, fx);
- tmp_pos.x[tmp_pos.n] = fx;
- tmp_pos.y[tmp_pos.n] = fy;
- tmp_pos.n++;
+ points.emplace_back(fy, fx);
}
floor_ptr->mon_lite_n = 0;
- for (int i = 0; i < end_temp; i++) {
- POSITION fx = tmp_pos.x[i];
- POSITION fy = tmp_pos.y[i];
- grid_type *g_ptr;
- g_ptr = &floor_ptr->grid_array[fy][fx];
+ for (size_t i = 0; i < end_temp; i++) {
+ const auto [fy, fx] = points[i];
+
+ grid_type *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, g_ptr, fy, fx);
floor_ptr->mon_lite_n++;
}
- for (int i = end_temp; i < tmp_pos.n; i++)
- floor_ptr->grid_array[tmp_pos.y[i]][tmp_pos.x[i]].info &= ~(CAVE_TEMP | CAVE_XTRA);
+ for (size_t i = end_temp; i < size(points); i++) {
+ const auto [y, x] = points[i];
+ floor_ptr->grid_array[y][x].info &= ~(CAVE_TEMP | CAVE_XTRA);
+ }
- tmp_pos.n = 0;
subject_ptr->update |= PU_DELAY_VIS;
subject_ptr->monlite = (floor_ptr->grid_array[subject_ptr->y][subject_ptr->x].info & CAVE_MNLT) != 0;
if (!(subject_ptr->special_defense & NINJA_S_STEALTH)) {
#include "monster/monster-info.h"
#include "monster/smart-learn-types.h"
#include "mspell/assign-monster-spell.h"
+#include "mspell/mspell.h"
#include "spell-kind/spells-teleport.h"
#include "system/floor-type-definition.h"
#include "view/display-messages.h"
if (none_bits(r_ptr->flags3, RF3_DRAGON))
return FALSE;
- if (none_bits(r_ptr->flags4, vault_aux_dragon_mask4))
+ if (any_bits(r_ptr->flags3, RF3_UNDEAD))
return FALSE;
- if (any_bits(r_ptr->flags3, RF3_UNDEAD))
+ BIT_FLAGS flags = RF4_BREATH_MASK;
+ reset_bits(flags, vault_aux_dragon_mask4);
+
+ if (any_bits(r_ptr->flags4, flags) || !all_bits(r_ptr->flags4, vault_aux_dragon_mask4))
return FALSE;
return TRUE;
#include "pet/pet-fall-off.h"
#include "system/alloc-entries.h"
#include "system/floor-type-definition.h"
+#include "util/probability-table.h"
#include "view/display-messages.h"
#include "world/world.h"
+#include <iterator>
#define HORDE_NOGOOD 0x01 /*!< (未実装フラグ)HORDE生成でGOODなモンスターの生成を禁止する? */
#define HORDE_NOEVIL 0x02 /*!< (未実装フラグ)HORDE生成でEVILなモンスターの生成を禁止する? */
*/
MONRACE_IDX get_mon_num(player_type *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS option)
{
- int i, j, p;
int r_idx;
- long value, total_prob3;
- int mon_num = 0;
monster_race *r_ptr;
alloc_entry *table = alloc_race_table;
}
}
- total_prob3 = 0L;
+ ProbabilityTable<int> prob_table;
/* Process probabilities */
- for (i = 0; i < alloc_race_size; i++) {
- table[i].prob3 = 0;
+ for (int i = 0; i < alloc_race_size; i++) {
if (table[i].level < min_level)
continue;
if (max_level < table[i].level)
}
}
- table[i].prob3 = table[i].prob2;
-
- if (table[i].prob3 > 0) {
- mon_num++;
- total_prob3 += table[i].prob3;
- }
+ prob_table.entry_item(i, table[i].prob2);
}
if (cheat_hear) {
- msg_format(_("モンスター第3次候補数:%d(%d-%dF)%d ", "monster third selection:%d(%d-%dF)%d "), mon_num, min_level, max_level, total_prob3);
+ msg_format(_("モンスター第3次候補数:%d(%d-%dF)%d ", "monster third selection:%d(%d-%dF)%d "), prob_table.item_count(), min_level, max_level,
+ prob_table.total_prob());
}
- if (total_prob3 <= 0)
+ if (prob_table.empty())
return 0;
- value = randint0(total_prob3);
- int found_count = 0;
- for (i = 0; i < alloc_race_size; i++) {
- if (value < table[i].prob3)
- break;
- value = value - table[i].prob3;
- found_count++;
- }
-
- p = randint0(100);
+ // 40%で1回、50%で2回、10%で3回抽選し、その中で一番レベルが高いモンスターを選択する
+ int n = 1;
- /* Try for a "harder" monster once (50%) or twice (10%) */
- if (p < 60) {
- j = found_count;
- value = randint0(total_prob3);
- for (found_count = 0; found_count < alloc_race_size; found_count++) {
- if (value < table[found_count].prob3)
- break;
+ const int p = randint0(100);
+ if (p < 60)
+ n++;
+ if (p < 10)
+ n++;
- value = value - table[found_count].prob3;
- }
+ std::vector<int> result;
+ ProbabilityTable<int>::lottery(std::back_inserter(result), prob_table, n);
- if (table[found_count].level < table[j].level)
- found_count = j;
- }
-
- /* Try for a "harder" monster twice (10%) */
- if (p < 10) {
- j = found_count;
- value = randint0(total_prob3);
- for (found_count = 0; found_count < alloc_race_size; found_count++) {
- if (value < table[found_count].prob3)
- break;
-
- value = value - table[found_count].prob3;
- }
-
- if (table[found_count].level < table[j].level)
- found_count = j;
- }
+ auto it = std::max_element(result.begin(), result.end(), [table](int a, int b) { return table[a].level < table[b].level; });
- return (table[found_count].index);
+ return (table[*it].index);
}
/*!
*/
#include "mspell/assign-monster-spell.h"
+#include "blue-magic/blue-magic-checker.h"
#include "mspell/mspell-ball.h"
#include "mspell/mspell-bolt.h"
#include "mspell/mspell-breath.h"
#include "mspell/mspell-curse.h"
#include "mspell/mspell-dispel.h"
#include "mspell/mspell-floor.h"
+#include "mspell/mspell-learn-checker.h"
#include "mspell/mspell-particularity.h"
#include "mspell/mspell-special.h"
#include "mspell/mspell-status.h"
#include "mspell/mspell-summon.h"
#include "mspell/mspell-type.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "spell/spell-types.h"
/*!
- * @brief モンスターからプレイヤーへの呪文の振り分け関数。 /
- * @param SPELL_NUM モンスター魔法ID (monster_spell_typeのenum値とは異なる)
+ * @brief SPELL_IDX を monster_spell_type に変換する。
+ */
+static int spell_idx_to_monster_spell_type(const SPELL_IDX idx)
+{
+ return idx - RF4_SPELL_START;
+}
+
+static MonsterSpellResult monspell_to_player_impl(player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx)
+{
+ // clang-format off
+ switch (ms_type) {
+ case RF4_SPELL_START + 0: return spell_RF4_SHRIEK(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); /* RF4_SHRIEK */
+ case RF4_SPELL_START + 1: break; /* RF4_XXX1 */
+ case RF4_SPELL_START + 2: return spell_RF4_DISPEL(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); /* RF4_DISPEL */
+ case RF4_SPELL_START + 3: return spell_RF4_ROCKET(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_ROCKET */
+ case RF4_SPELL_START + 4: return spell_RF4_SHOOT(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_SHOOT */
+ case RF4_SPELL_START + 5: break; /* RF4_XXX2 */
+ case RF4_SPELL_START + 6: break; /* RF4_XXX3 */
+ case RF4_SPELL_START + 7: break; /* RF4_XXX4 */
+ case RF4_SPELL_START + 8: return spell_RF4_BREATH(target_ptr, GF_ACID, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_ACID */
+ case RF4_SPELL_START + 9: return spell_RF4_BREATH(target_ptr, GF_ELEC, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_ELEC */
+ case RF4_SPELL_START + 10: return spell_RF4_BREATH(target_ptr, GF_FIRE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_FIRE */
+ case RF4_SPELL_START + 11: return spell_RF4_BREATH(target_ptr, GF_COLD, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_COLD */
+ case RF4_SPELL_START + 12: return spell_RF4_BREATH(target_ptr, GF_POIS, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_POIS */
+ case RF4_SPELL_START + 13: return spell_RF4_BREATH(target_ptr, GF_NETHER, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_NETH */
+ case RF4_SPELL_START + 14: return spell_RF4_BREATH(target_ptr, GF_LITE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_LITE */
+ case RF4_SPELL_START + 15: return spell_RF4_BREATH(target_ptr, GF_DARK, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_DARK */
+ case RF4_SPELL_START + 16: return spell_RF4_BREATH(target_ptr, GF_CONFUSION, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_CONF */
+ case RF4_SPELL_START + 17: return spell_RF4_BREATH(target_ptr, GF_SOUND, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_SOUN */
+ case RF4_SPELL_START + 18: return spell_RF4_BREATH(target_ptr, GF_CHAOS, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_CHAO */
+ case RF4_SPELL_START + 19: return spell_RF4_BREATH(target_ptr, GF_DISENCHANT, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_DISE */
+ case RF4_SPELL_START + 20: return spell_RF4_BREATH(target_ptr, GF_NEXUS, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_NEXU */
+ case RF4_SPELL_START + 21: return spell_RF4_BREATH(target_ptr, GF_TIME, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_TIME */
+ case RF4_SPELL_START + 22: return spell_RF4_BREATH(target_ptr, GF_INERTIAL, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_INER */
+ case RF4_SPELL_START + 23: return spell_RF4_BREATH(target_ptr, GF_GRAVITY, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_GRAV */
+ case RF4_SPELL_START + 24: return spell_RF4_BREATH(target_ptr, GF_SHARDS, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_SHAR */
+ case RF4_SPELL_START + 25: return spell_RF4_BREATH(target_ptr, GF_PLASMA, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_PLAS */
+ case RF4_SPELL_START + 26: return spell_RF4_BREATH(target_ptr, GF_FORCE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_WALL */
+ case RF4_SPELL_START + 27: return spell_RF4_BREATH(target_ptr, GF_MANA, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_MANA */
+ case RF4_SPELL_START + 28: return spell_RF4_BA_NUKE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BA_NUKE */
+ case RF4_SPELL_START + 29: return spell_RF4_BREATH(target_ptr, GF_NUKE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_NUKE */
+ case RF4_SPELL_START + 30: return spell_RF4_BA_CHAO(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BA_CHAO */
+ case RF4_SPELL_START + 31: return spell_RF4_BREATH(target_ptr, GF_DISINTEGRATE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_DISI */
+ case RF5_SPELL_START + 0: return spell_RF5_BA_ACID(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_ACID */
+ case RF5_SPELL_START + 1: return spell_RF5_BA_ELEC(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_ELEC */
+ case RF5_SPELL_START + 2: return spell_RF5_BA_FIRE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_FIRE */
+ case RF5_SPELL_START + 3: return spell_RF5_BA_COLD(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_COLD */
+ case RF5_SPELL_START + 4: return spell_RF5_BA_POIS(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_POIS */
+ case RF5_SPELL_START + 5: return spell_RF5_BA_NETH(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_NETH */
+ case RF5_SPELL_START + 6: return spell_RF5_BA_WATE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_WATE */
+ case RF5_SPELL_START + 7: return spell_RF5_BA_MANA(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_MANA */
+ case RF5_SPELL_START + 8: return spell_RF5_BA_DARK(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_DARK */
+ case RF5_SPELL_START + 9: return spell_RF5_DRAIN_MANA(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_DRAIN_MANA */
+ case RF5_SPELL_START + 10: return spell_RF5_MIND_BLAST(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_MIND_BLAST */
+ case RF5_SPELL_START + 11: return spell_RF5_BRAIN_SMASH(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_MIND_BLAST */
+ case RF5_SPELL_START + 12: return spell_RF5_CAUSE_1(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_CAUSE_1 */
+ case RF5_SPELL_START + 13: return spell_RF5_CAUSE_2(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_CAUSE_2 */
+ case RF5_SPELL_START + 14: return spell_RF5_CAUSE_3(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_CAUSE_3 */
+ case RF5_SPELL_START + 15: return spell_RF5_CAUSE_4(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_CAUSE_4 */
+ case RF5_SPELL_START + 16: return spell_RF5_BO_ACID(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_ACID */
+ case RF5_SPELL_START + 17: return spell_RF5_BO_ELEC(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_ELEC */
+ case RF5_SPELL_START + 18: return spell_RF5_BO_FIRE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_FIRE */
+ case RF5_SPELL_START + 19: return spell_RF5_BO_COLD(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_COLD */
+ case RF5_SPELL_START + 20: return spell_RF5_BA_LITE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_LITE */
+ case RF5_SPELL_START + 21: return spell_RF5_BO_NETH(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_NETH */
+ case RF5_SPELL_START + 22: return spell_RF5_BO_WATE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_WATE */
+ case RF5_SPELL_START + 23: return spell_RF5_BO_MANA(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_MANA */
+ case RF5_SPELL_START + 24: return spell_RF5_BO_PLAS(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_PLAS */
+ case RF5_SPELL_START + 25: return spell_RF5_BO_ICEE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_ICEE */
+ case RF5_SPELL_START + 26: return spell_RF5_MISSILE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_MISSILE */
+ case RF5_SPELL_START + 27: return spell_RF5_SCARE(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); /* RF5_SCARE */
+ case RF5_SPELL_START + 28: return spell_RF5_BLIND(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); /* RF5_BLIND */
+ case RF5_SPELL_START + 29: return spell_RF5_CONF(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); /* RF5_CONF */
+ case RF5_SPELL_START + 30: return spell_RF5_SLOW(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); /* RF5_SLOW */
+ case RF5_SPELL_START + 31: return spell_RF5_HOLD(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); /* RF5_HOLD */
+ case RF6_SPELL_START + 0: return spell_RF6_HASTE(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_HASTE */
+ case RF6_SPELL_START + 1: return spell_RF6_HAND_DOOM(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_HAND_DOOM */
+ case RF6_SPELL_START + 2: return spell_RF6_HEAL(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_HEAL */
+ case RF6_SPELL_START + 3: return spell_RF6_INVULNER(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_INVULNER */
+ case RF6_SPELL_START + 4: return spell_RF6_BLINK(target_ptr, m_idx, MONSTER_TO_PLAYER, FALSE); /* RF6_BLINK */
+ case RF6_SPELL_START + 5: return spell_RF6_TPORT(target_ptr, m_idx, MONSTER_TO_PLAYER); /* RF6_TPORT */
+ case RF6_SPELL_START + 6: return spell_RF6_WORLD(target_ptr, m_idx); /* RF6_WORLD */
+ case RF6_SPELL_START + 7: return spell_RF6_SPECIAL(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_SPECIAL */
+ case RF6_SPELL_START + 8: return spell_RF6_TELE_TO(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_TELE_TO */
+ case RF6_SPELL_START + 9: return spell_RF6_TELE_AWAY(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_TELE_AWAY */
+ case RF6_SPELL_START + 10: return spell_RF6_TELE_LEVEL(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_TELE_LEVEL */
+ case RF6_SPELL_START + 11: return spell_RF6_PSY_SPEAR(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_PSY_SPEAR */
+ case RF6_SPELL_START + 12: return spell_RF6_DARKNESS(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_DARKNESS */
+ case RF6_SPELL_START + 13: return spell_RF6_TRAPS(target_ptr, y, x, m_idx); /* RF6_TRAPS */
+ case RF6_SPELL_START + 14: return spell_RF6_FORGET(target_ptr, m_idx); /* RF6_FORGET */
+ case RF6_SPELL_START + 15: return spell_RF6_RAISE_DEAD(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_RAISE_DEAD */
+ case RF6_SPELL_START + 16: return spell_RF6_S_KIN(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_KIN */
+ case RF6_SPELL_START + 17: return spell_RF6_S_CYBER(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_CYBER */
+ case RF6_SPELL_START + 18: return spell_RF6_S_MONSTER(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_MONSTER */
+ case RF6_SPELL_START + 19: return spell_RF6_S_MONSTERS(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_MONSTER */
+ case RF6_SPELL_START + 20: return spell_RF6_S_ANT(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_ANT */
+ case RF6_SPELL_START + 21: return spell_RF6_S_SPIDER(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_SPIDER */
+ case RF6_SPELL_START + 22: return spell_RF6_S_HOUND(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_HOUND */
+ case RF6_SPELL_START + 23: return spell_RF6_S_HYDRA(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_HYDRA */
+ case RF6_SPELL_START + 24: return spell_RF6_S_ANGEL(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_ANGEL */
+ case RF6_SPELL_START + 25: return spell_RF6_S_DEMON(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_DEMON */
+ case RF6_SPELL_START + 26: return spell_RF6_S_UNDEAD(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_UNDEAD */
+ case RF6_SPELL_START + 27: return spell_RF6_S_DRAGON(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_DRAGON */
+ case RF6_SPELL_START + 28: return spell_RF6_S_HI_UNDEAD(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_HI_UNDEAD */
+ case RF6_SPELL_START + 29: return spell_RF6_S_HI_DRAGON(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_HI_DRAGON */
+ case RF6_SPELL_START + 30: return spell_RF6_S_AMBERITES(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_AMBERITES */
+ case RF6_SPELL_START + 31: return spell_RF6_S_UNIQUE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_UNIQUE */
+ default: break;
+ }
+ // clang-format on
+
+ return MonsterSpellResult::make_invalid();
+}
+
+static MonsterSpellResult monspell_to_monster_impl(
+ player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, bool is_special_spell)
+{
+ // clang-format off
+ switch (ms_type) {
+ case RF4_SPELL_START + 0: return spell_RF4_SHRIEK(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); /* RF4_SHRIEK */
+ case RF4_SPELL_START + 1: break; /* RF4_XXX1 */
+ case RF4_SPELL_START + 2: return spell_RF4_DISPEL(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); /* RF4_DISPEL */
+ case RF4_SPELL_START + 3: return spell_RF4_ROCKET(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_ROCKET */
+ case RF4_SPELL_START + 4: return spell_RF4_SHOOT(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_SHOOT */
+ case RF4_SPELL_START + 5: break; /* RF4_XXX2 */
+ case RF4_SPELL_START + 6: break; /* RF4_XXX3 */
+ case RF4_SPELL_START + 7: break; /* RF4_XXX4 */
+ case RF4_SPELL_START + 8: return spell_RF4_BREATH(target_ptr, GF_ACID, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_ACID */
+ case RF4_SPELL_START + 9: return spell_RF4_BREATH(target_ptr, GF_ELEC, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_ELEC */
+ case RF4_SPELL_START + 10: return spell_RF4_BREATH(target_ptr, GF_FIRE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_FIRE */
+ case RF4_SPELL_START + 11: return spell_RF4_BREATH(target_ptr, GF_COLD, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_COLD */
+ case RF4_SPELL_START + 12: return spell_RF4_BREATH(target_ptr, GF_POIS, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_POIS */
+ case RF4_SPELL_START + 13: return spell_RF4_BREATH(target_ptr, GF_NETHER, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_NETH */
+ case RF4_SPELL_START + 14: return spell_RF4_BREATH(target_ptr, GF_LITE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_LITE */
+ case RF4_SPELL_START + 15: return spell_RF4_BREATH(target_ptr, GF_DARK, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_DARK */
+ case RF4_SPELL_START + 16: return spell_RF4_BREATH(target_ptr, GF_CONFUSION, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_CONF */
+ case RF4_SPELL_START + 17: return spell_RF4_BREATH(target_ptr, GF_SOUND, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_SOUN */
+ case RF4_SPELL_START + 18: return spell_RF4_BREATH(target_ptr, GF_CHAOS, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_CHAO */
+ case RF4_SPELL_START + 19: return spell_RF4_BREATH(target_ptr, GF_DISENCHANT, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_DISE */
+ case RF4_SPELL_START + 20: return spell_RF4_BREATH(target_ptr, GF_NEXUS, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_NEXU */
+ case RF4_SPELL_START + 21: return spell_RF4_BREATH(target_ptr, GF_TIME, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_TIME */
+ case RF4_SPELL_START + 22: return spell_RF4_BREATH(target_ptr, GF_INERTIAL, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_INER */
+ case RF4_SPELL_START + 23: return spell_RF4_BREATH(target_ptr, GF_GRAVITY, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_GRAV */
+ case RF4_SPELL_START + 24: return spell_RF4_BREATH(target_ptr, GF_SHARDS, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_SHAR */
+ case RF4_SPELL_START + 25: return spell_RF4_BREATH(target_ptr, GF_PLASMA, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_PLAS */
+ case RF4_SPELL_START + 26: return spell_RF4_BREATH(target_ptr, GF_FORCE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_WALL */
+ case RF4_SPELL_START + 27: return spell_RF4_BREATH(target_ptr, GF_MANA, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_MANA */
+ case RF4_SPELL_START + 28: return spell_RF4_BA_NUKE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BA_NUKE */
+ case RF4_SPELL_START + 29: return spell_RF4_BREATH(target_ptr, GF_NUKE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_NUKE */
+ case RF4_SPELL_START + 30: return spell_RF4_BA_CHAO(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BA_CHAO */
+ case RF4_SPELL_START + 31: return spell_RF4_BREATH(target_ptr, GF_DISINTEGRATE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_DISI */
+ case RF5_SPELL_START + 0: return spell_RF5_BA_ACID(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_ACID */
+ case RF5_SPELL_START + 1: return spell_RF5_BA_ELEC(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_ELEC */
+ case RF5_SPELL_START + 2: return spell_RF5_BA_FIRE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_FIRE */
+ case RF5_SPELL_START + 3: return spell_RF5_BA_COLD(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_COLD */
+ case RF5_SPELL_START + 4: return spell_RF5_BA_POIS(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_POIS */
+ case RF5_SPELL_START + 5: return spell_RF5_BA_NETH(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_NETH */
+ case RF5_SPELL_START + 6: return spell_RF5_BA_WATE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_WATE */
+ case RF5_SPELL_START + 7: return spell_RF5_BA_MANA(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_MANA */
+ case RF5_SPELL_START + 8: return spell_RF5_BA_DARK(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_DARK */
+ case RF5_SPELL_START + 9: return spell_RF5_DRAIN_MANA(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_DRAIN_MANA */
+ case RF5_SPELL_START + 10: return spell_RF5_MIND_BLAST(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_MIND_BLAST */
+ case RF5_SPELL_START + 11: return spell_RF5_BRAIN_SMASH(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BRAIN_SMASH */
+ case RF5_SPELL_START + 12: return spell_RF5_CAUSE_1(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_CAUSE_1 */
+ case RF5_SPELL_START + 13: return spell_RF5_CAUSE_2(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_CAUSE_2 */
+ case RF5_SPELL_START + 14: return spell_RF5_CAUSE_3(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_CAUSE_3 */
+ case RF5_SPELL_START + 15: return spell_RF5_CAUSE_4(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_CAUSE_4 */
+ case RF5_SPELL_START + 16: return spell_RF5_BO_ACID(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_ACID */
+ case RF5_SPELL_START + 17: return spell_RF5_BO_ELEC(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_ELEC */
+ case RF5_SPELL_START + 18: return spell_RF5_BO_FIRE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_FIRE */
+ case RF5_SPELL_START + 19: return spell_RF5_BO_COLD(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_COLD */
+ case RF5_SPELL_START + 20: return spell_RF5_BA_LITE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_LITE */
+ case RF5_SPELL_START + 21: return spell_RF5_BO_NETH(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_NETH */
+ case RF5_SPELL_START + 22: return spell_RF5_BO_WATE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_WATE */
+ case RF5_SPELL_START + 23: return spell_RF5_BO_MANA(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_MANA */
+ case RF5_SPELL_START + 24: return spell_RF5_BO_PLAS(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_PLAS */
+ case RF5_SPELL_START + 25: return spell_RF5_BO_ICEE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_ICEE */
+ case RF5_SPELL_START + 26: return spell_RF5_MISSILE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_MISSILE */
+ case RF5_SPELL_START + 27: return spell_RF5_SCARE(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); /* RF5_SCARE */
+ case RF5_SPELL_START + 28: return spell_RF5_BLIND(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); /* RF5_BLIND */
+ case RF5_SPELL_START + 29: return spell_RF5_CONF(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); /* RF5_CONF */
+ case RF5_SPELL_START + 30: return spell_RF5_SLOW(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); /* RF5_SLOW */
+ case RF5_SPELL_START + 31: return spell_RF5_HOLD(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); /* RF5_HOLD */
+ case RF6_SPELL_START + 0: return spell_RF6_HASTE(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_HASTE */
+ case RF6_SPELL_START + 1: return spell_RF6_HAND_DOOM(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_HAND_DOOM */
+ case RF6_SPELL_START + 2: return spell_RF6_HEAL(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_HEAL */
+ case RF6_SPELL_START + 3: return spell_RF6_INVULNER(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_INVULNER */
+ case RF6_SPELL_START + 4: return spell_RF6_BLINK(target_ptr, m_idx, MONSTER_TO_MONSTER, is_special_spell); /* RF6_BLINK */
+ case RF6_SPELL_START + 5: return spell_RF6_TPORT(target_ptr, m_idx, MONSTER_TO_MONSTER); /* RF6_TPORT */
+ case RF6_SPELL_START + 6: break; /* RF6_WORLD */
+ case RF6_SPELL_START + 7: return spell_RF6_SPECIAL(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_SPECIAL */
+ case RF6_SPELL_START + 8: return spell_RF6_TELE_TO(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_TELE_TO */
+ case RF6_SPELL_START + 9: return spell_RF6_TELE_AWAY(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_TELE_AWAY */
+ case RF6_SPELL_START + 10: return spell_RF6_TELE_LEVEL(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_TELE_LEVEL */
+ case RF6_SPELL_START + 11: return spell_RF6_PSY_SPEAR(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_PSY_SPEAR */
+ case RF6_SPELL_START + 12: return spell_RF6_DARKNESS(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_DARKNESS */
+ case RF6_SPELL_START + 13: break; /* RF6_TRAPS */
+ case RF6_SPELL_START + 14: break; /* RF6_FORGET */
+ case RF6_SPELL_START + 15: return spell_RF6_RAISE_DEAD(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_RAISE_DEAD */
+ case RF6_SPELL_START + 16: return spell_RF6_S_KIN(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_KIN */
+ case RF6_SPELL_START + 17: return spell_RF6_S_CYBER(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_CYBER */
+ case RF6_SPELL_START + 18: return spell_RF6_S_MONSTER(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_MONSTER */
+ case RF6_SPELL_START + 19: return spell_RF6_S_MONSTERS(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_MONSTER */
+ case RF6_SPELL_START + 20: return spell_RF6_S_ANT(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_ANT */
+ case RF6_SPELL_START + 21: return spell_RF6_S_SPIDER(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_SPIDER */
+ case RF6_SPELL_START + 22: return spell_RF6_S_HOUND(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_HOUND */
+ case RF6_SPELL_START + 23: return spell_RF6_S_HYDRA(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_HYDRA */
+ case RF6_SPELL_START + 24: return spell_RF6_S_ANGEL(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_ANGEL */
+ case RF6_SPELL_START + 25: return spell_RF6_S_DEMON(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_DEMON */
+ case RF6_SPELL_START + 26: return spell_RF6_S_UNDEAD(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_UNDEAD */
+ case RF6_SPELL_START + 27: return spell_RF6_S_DRAGON(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_DRAGON */
+ case RF6_SPELL_START + 28: return spell_RF6_S_HI_UNDEAD(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_HI_UNDEAD */
+ case RF6_SPELL_START + 29: return spell_RF6_S_HI_DRAGON(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_HI_DRAGON */
+ case RF6_SPELL_START + 30: return spell_RF6_S_AMBERITES(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_AMBERITES */
+ case RF6_SPELL_START + 31: return spell_RF6_S_UNIQUE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_UNIQUE */
+ default: break;
+ }
+ // clang-format on
+
+ return MonsterSpellResult::make_invalid();
+}
+
+/*!
+ * @brief モンスターからプレイヤーへの魔法使用。ラーニング処理も行う。
+ * @param ms_type モンスター魔法ID (monster_spell_typeのenum値とは異なる)
* @param y 対象の地点のy座標
* @param x 対象の地点のx座標
* @param m_idx 呪文を唱えるモンスターID
- * @return 攻撃呪文のダメージ、または召喚したモンスターの数を返す。その他の場合0。以降の処理を中断するなら-1を返す。
*/
-HIT_POINT monspell_to_player(player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx)
+MonsterSpellResult monspell_to_player(player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx)
{
- switch (ms_type)
- {
- case RF4_SPELL_START + 0: spell_RF4_SHRIEK(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); break; /* RF4_SHRIEK */
- case RF4_SPELL_START + 1: break; /* RF4_XXX1 */
- case RF4_SPELL_START + 2: spell_RF4_DISPEL(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); break; /* RF4_DISPEL */
- case RF4_SPELL_START + 3: return spell_RF4_ROCKET(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_ROCKET */
- case RF4_SPELL_START + 4: return spell_RF4_SHOOT(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_SHOOT */
- case RF4_SPELL_START + 5: break; /* RF4_XXX2 */
- case RF4_SPELL_START + 6: break; /* RF4_XXX3 */
- case RF4_SPELL_START + 7: break; /* RF4_XXX4 */
- case RF4_SPELL_START + 8: return spell_RF4_BREATH(target_ptr, GF_ACID, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_ACID */
- case RF4_SPELL_START + 9: return spell_RF4_BREATH(target_ptr, GF_ELEC, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_ELEC */
- case RF4_SPELL_START + 10: return spell_RF4_BREATH(target_ptr, GF_FIRE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_FIRE */
- case RF4_SPELL_START + 11: return spell_RF4_BREATH(target_ptr, GF_COLD, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_COLD */
- case RF4_SPELL_START + 12: return spell_RF4_BREATH(target_ptr, GF_POIS, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_POIS */
- case RF4_SPELL_START + 13: return spell_RF4_BREATH(target_ptr, GF_NETHER, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_NETH */
- case RF4_SPELL_START + 14: return spell_RF4_BREATH(target_ptr, GF_LITE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_LITE */
- case RF4_SPELL_START + 15: return spell_RF4_BREATH(target_ptr, GF_DARK, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_DARK */
- case RF4_SPELL_START + 16: return spell_RF4_BREATH(target_ptr, GF_CONFUSION, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_CONF */
- case RF4_SPELL_START + 17: return spell_RF4_BREATH(target_ptr, GF_SOUND, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_SOUN */
- case RF4_SPELL_START + 18: return spell_RF4_BREATH(target_ptr, GF_CHAOS, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_CHAO */
- case RF4_SPELL_START + 19: return spell_RF4_BREATH(target_ptr, GF_DISENCHANT, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_DISE */
- case RF4_SPELL_START + 20: return spell_RF4_BREATH(target_ptr, GF_NEXUS, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_NEXU */
- case RF4_SPELL_START + 21: return spell_RF4_BREATH(target_ptr, GF_TIME, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_TIME */
- case RF4_SPELL_START + 22: return spell_RF4_BREATH(target_ptr, GF_INERTIAL, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_INER */
- case RF4_SPELL_START + 23: return spell_RF4_BREATH(target_ptr, GF_GRAVITY, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_GRAV */
- case RF4_SPELL_START + 24: return spell_RF4_BREATH(target_ptr, GF_SHARDS, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_SHAR */
- case RF4_SPELL_START + 25: return spell_RF4_BREATH(target_ptr, GF_PLASMA, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_PLAS */
- case RF4_SPELL_START + 26: return spell_RF4_BREATH(target_ptr, GF_FORCE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_WALL */
- case RF4_SPELL_START + 27: return spell_RF4_BREATH(target_ptr, GF_MANA, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_MANA */
- case RF4_SPELL_START + 28: return spell_RF4_BA_NUKE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BA_NUKE */
- case RF4_SPELL_START + 29: return spell_RF4_BREATH(target_ptr, GF_NUKE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_NUKE */
- case RF4_SPELL_START + 30: return spell_RF4_BA_CHAO(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BA_CHAO */
- case RF4_SPELL_START + 31: return spell_RF4_BREATH(target_ptr, GF_DISINTEGRATE, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF4_BR_DISI */
- case RF5_SPELL_START + 0: return spell_RF5_BA_ACID(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_ACID */
- case RF5_SPELL_START + 1: return spell_RF5_BA_ELEC(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_ELEC */
- case RF5_SPELL_START + 2: return spell_RF5_BA_FIRE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_FIRE */
- case RF5_SPELL_START + 3: return spell_RF5_BA_COLD(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_COLD */
- case RF5_SPELL_START + 4: return spell_RF5_BA_POIS(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_POIS */
- case RF5_SPELL_START + 5: return spell_RF5_BA_NETH(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_NETH */
- case RF5_SPELL_START + 6: return spell_RF5_BA_WATE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_WATE */
- case RF5_SPELL_START + 7: return spell_RF5_BA_MANA(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_MANA */
- case RF5_SPELL_START + 8: return spell_RF5_BA_DARK(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_DARK */
- case RF5_SPELL_START + 9: return spell_RF5_DRAIN_MANA(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_DRAIN_MANA */
- case RF5_SPELL_START + 10: return spell_RF5_MIND_BLAST(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_MIND_BLAST */
- case RF5_SPELL_START + 11: return spell_RF5_BRAIN_SMASH(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_MIND_BLAST */
- case RF5_SPELL_START + 12: return spell_RF5_CAUSE_1(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_CAUSE_1 */
- case RF5_SPELL_START + 13: return spell_RF5_CAUSE_2(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_CAUSE_2 */
- case RF5_SPELL_START + 14: return spell_RF5_CAUSE_3(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_CAUSE_3 */
- case RF5_SPELL_START + 15: return spell_RF5_CAUSE_4(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_CAUSE_4 */
- case RF5_SPELL_START + 16: return spell_RF5_BO_ACID(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_ACID */
- case RF5_SPELL_START + 17: return spell_RF5_BO_ELEC(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_ELEC */
- case RF5_SPELL_START + 18: return spell_RF5_BO_FIRE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_FIRE */
- case RF5_SPELL_START + 19: return spell_RF5_BO_COLD(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_COLD */
- case RF5_SPELL_START + 20: return spell_RF5_BA_LITE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BA_LITE */
- case RF5_SPELL_START + 21: return spell_RF5_BO_NETH(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_NETH */
- case RF5_SPELL_START + 22: return spell_RF5_BO_WATE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_WATE */
- case RF5_SPELL_START + 23: return spell_RF5_BO_MANA(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_MANA */
- case RF5_SPELL_START + 24: return spell_RF5_BO_PLAS(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_PLAS */
- case RF5_SPELL_START + 25: return spell_RF5_BO_ICEE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_BO_ICEE */
- case RF5_SPELL_START + 26: return spell_RF5_MISSILE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF5_MISSILE */
- case RF5_SPELL_START + 27: spell_RF5_SCARE(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); break; /* RF5_SCARE */
- case RF5_SPELL_START + 28: spell_RF5_BLIND(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); break; /* RF5_BLIND */
- case RF5_SPELL_START + 29: spell_RF5_CONF(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); break; /* RF5_CONF */
- case RF5_SPELL_START + 30: spell_RF5_SLOW(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); break; /* RF5_SLOW */
- case RF5_SPELL_START + 31: spell_RF5_HOLD(m_idx, target_ptr, 0, MONSTER_TO_PLAYER); break; /* RF5_HOLD */
- case RF6_SPELL_START + 0: spell_RF6_HASTE(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_HASTE */
- case RF6_SPELL_START + 1: return spell_RF6_HAND_DOOM(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_HAND_DOOM */
- case RF6_SPELL_START + 2: spell_RF6_HEAL(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_HEAL */
- case RF6_SPELL_START + 3: spell_RF6_INVULNER(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_INVULNER */
- case RF6_SPELL_START + 4: spell_RF6_BLINK(target_ptr, m_idx, MONSTER_TO_PLAYER, FALSE); break; /* RF6_BLINK */
- case RF6_SPELL_START + 5: spell_RF6_TPORT(target_ptr, m_idx, MONSTER_TO_PLAYER); break; /* RF6_TPORT */
- case RF6_SPELL_START + 6: return spell_RF6_WORLD(target_ptr, m_idx); break; /* RF6_WORLD */
- case RF6_SPELL_START + 7: return spell_RF6_SPECIAL(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_SPECIAL */
- case RF6_SPELL_START + 8: spell_RF6_TELE_TO(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_TELE_TO */
- case RF6_SPELL_START + 9: spell_RF6_TELE_AWAY(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_TELE_AWAY */
- case RF6_SPELL_START + 10: spell_RF6_TELE_LEVEL(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_TELE_LEVEL */
- case RF6_SPELL_START + 11: return spell_RF6_PSY_SPEAR(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_PSY_SPEAR */
- case RF6_SPELL_START + 12: spell_RF6_DARKNESS(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_DARKNESS */
- case RF6_SPELL_START + 13: spell_RF6_TRAPS(target_ptr, y, x, m_idx); break; /* RF6_TRAPS */
- case RF6_SPELL_START + 14: spell_RF6_FORGET(target_ptr, m_idx); break; /* RF6_FORGET */
- case RF6_SPELL_START + 15: spell_RF6_RAISE_DEAD(target_ptr, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_RAISE_DEAD */
- case RF6_SPELL_START + 16: spell_RF6_S_KIN(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_KIN */
- case RF6_SPELL_START + 17: spell_RF6_S_CYBER(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_CYBER */
- case RF6_SPELL_START + 18: spell_RF6_S_MONSTER(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_MONSTER */
- case RF6_SPELL_START + 19: spell_RF6_S_MONSTERS(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_MONSTER */
- case RF6_SPELL_START + 20: spell_RF6_S_ANT(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_ANT */
- case RF6_SPELL_START + 21: spell_RF6_S_SPIDER(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_SPIDER */
- case RF6_SPELL_START + 22: spell_RF6_S_HOUND(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_HOUND */
- case RF6_SPELL_START + 23: spell_RF6_S_HYDRA(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_HYDRA */
- case RF6_SPELL_START + 24: spell_RF6_S_ANGEL(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_ANGEL */
- case RF6_SPELL_START + 25: spell_RF6_S_DEMON(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_DEMON */
- case RF6_SPELL_START + 26: spell_RF6_S_UNDEAD(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_UNDEAD */
- case RF6_SPELL_START + 27: spell_RF6_S_DRAGON(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_DRAGON */
- case RF6_SPELL_START + 28: spell_RF6_S_HI_UNDEAD(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_HI_UNDEAD */
- case RF6_SPELL_START + 29: spell_RF6_S_HI_DRAGON(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_HI_DRAGON */
- case RF6_SPELL_START + 30: spell_RF6_S_AMBERITES(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_AMBERITES */
- case RF6_SPELL_START + 31: spell_RF6_S_UNIQUE(target_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); break; /* RF6_S_UNIQUE */
- }
+ // 特技使用前の時点でプレイヤーがモンスターを視認できているかチェック(ラーニングの必要条件)。
+ const bool player_could_see_monster = spell_learnable(target_ptr, m_idx);
- return 0;
-}
+ auto res = monspell_to_player_impl(target_ptr, ms_type, y, x, m_idx);
+ if (!player_could_see_monster)
+ res.learnable = false;
+ // 条件を満たしていればラーニングを試みる。
+ if (res.valid && res.learnable) {
+ const auto monspell = spell_idx_to_monster_spell_type(ms_type);
+ learn_spell(target_ptr, monspell);
+ }
+
+ return res;
+}
/*!
* todo モンスターからモンスターへの呪文なのにplayer_typeが引数になり得るのは間違っている……
- * @brief モンスターからモンスターへの呪文の振り分け関数。 /
+ * @brief モンスターからモンスターへの魔法使用。ラーニング処理も行う。
* @param target_ptr プレーヤーへの参照ポインタ (monster_spell_typeのenum値とは異なる)
- * @param SPELL_NUM モンスター魔法ID
+ * @param ms_type モンスター魔法ID
* @param y 対象の地点のy座標
* @param x 対象の地点のx座標
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param is_special_spell 特殊な行動である時TRUE
- * @return 攻撃呪文のダメージ、または召喚したモンスターの数を返す。その他の場合0。以降の処理を中断するなら-1を返す。
*/
-HIT_POINT monspell_to_monster(player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, bool is_special_spell)
+MonsterSpellResult monspell_to_monster(
+ player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, bool is_special_spell)
{
- switch (ms_type)
- {
- case RF4_SPELL_START + 0: spell_RF4_SHRIEK(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); break; /* RF4_SHRIEK */
- case RF4_SPELL_START + 1: return -1; /* RF4_XXX1 */
- case RF4_SPELL_START + 2: spell_RF4_DISPEL(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); break; /* RF4_DISPEL */
- case RF4_SPELL_START + 3: return spell_RF4_ROCKET(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_ROCKET */
- case RF4_SPELL_START + 4: return spell_RF4_SHOOT(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_SHOOT */
- case RF4_SPELL_START + 5: return -1; /* RF4_XXX2 */
- case RF4_SPELL_START + 6: return -1; /* RF4_XXX3 */
- case RF4_SPELL_START + 7: return -1; /* RF4_XXX4 */
- case RF4_SPELL_START + 8: return spell_RF4_BREATH(target_ptr, GF_ACID, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_ACID */
- case RF4_SPELL_START + 9: return spell_RF4_BREATH(target_ptr, GF_ELEC, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_ELEC */
- case RF4_SPELL_START + 10: return spell_RF4_BREATH(target_ptr, GF_FIRE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_FIRE */
- case RF4_SPELL_START + 11: return spell_RF4_BREATH(target_ptr, GF_COLD, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_COLD */
- case RF4_SPELL_START + 12: return spell_RF4_BREATH(target_ptr, GF_POIS, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_POIS */
- case RF4_SPELL_START + 13: return spell_RF4_BREATH(target_ptr, GF_NETHER, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_NETH */
- case RF4_SPELL_START + 14: return spell_RF4_BREATH(target_ptr, GF_LITE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_LITE */
- case RF4_SPELL_START + 15: return spell_RF4_BREATH(target_ptr, GF_DARK, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_DARK */
- case RF4_SPELL_START + 16: return spell_RF4_BREATH(target_ptr, GF_CONFUSION, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_CONF */
- case RF4_SPELL_START + 17: return spell_RF4_BREATH(target_ptr, GF_SOUND, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_SOUN */
- case RF4_SPELL_START + 18: return spell_RF4_BREATH(target_ptr, GF_CHAOS, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_CHAO */
- case RF4_SPELL_START + 19: return spell_RF4_BREATH(target_ptr, GF_DISENCHANT, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_DISE */
- case RF4_SPELL_START + 20: return spell_RF4_BREATH(target_ptr, GF_NEXUS, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_NEXU */
- case RF4_SPELL_START + 21: return spell_RF4_BREATH(target_ptr, GF_TIME, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_TIME */
- case RF4_SPELL_START + 22: return spell_RF4_BREATH(target_ptr, GF_INERTIAL, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_INER */
- case RF4_SPELL_START + 23: return spell_RF4_BREATH(target_ptr, GF_GRAVITY, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_GRAV */
- case RF4_SPELL_START + 24: return spell_RF4_BREATH(target_ptr, GF_SHARDS, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_SHAR */
- case RF4_SPELL_START + 25: return spell_RF4_BREATH(target_ptr, GF_PLASMA, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_PLAS */
- case RF4_SPELL_START + 26: return spell_RF4_BREATH(target_ptr, GF_FORCE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_WALL */
- case RF4_SPELL_START + 27: return spell_RF4_BREATH(target_ptr, GF_MANA, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_MANA */
- case RF4_SPELL_START + 28: return spell_RF4_BA_NUKE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BA_NUKE */
- case RF4_SPELL_START + 29: return spell_RF4_BREATH(target_ptr, GF_NUKE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_NUKE */
- case RF4_SPELL_START + 30: return spell_RF4_BA_CHAO(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BA_CHAO */
- case RF4_SPELL_START + 31: return spell_RF4_BREATH(target_ptr, GF_DISINTEGRATE, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF4_BR_DISI */
- case RF5_SPELL_START + 0: return spell_RF5_BA_ACID(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_ACID */
- case RF5_SPELL_START + 1: return spell_RF5_BA_ELEC(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_ELEC */
- case RF5_SPELL_START + 2: return spell_RF5_BA_FIRE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_FIRE */
- case RF5_SPELL_START + 3: return spell_RF5_BA_COLD(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_COLD */
- case RF5_SPELL_START + 4: return spell_RF5_BA_POIS(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_POIS */
- case RF5_SPELL_START + 5: return spell_RF5_BA_NETH(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_NETH */
- case RF5_SPELL_START + 6: return spell_RF5_BA_WATE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_WATE */
- case RF5_SPELL_START + 7: return spell_RF5_BA_MANA(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_MANA */
- case RF5_SPELL_START + 8: return spell_RF5_BA_DARK(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_DARK */
- case RF5_SPELL_START + 9: return spell_RF5_DRAIN_MANA(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_DRAIN_MANA */
- case RF5_SPELL_START + 10: return spell_RF5_MIND_BLAST(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_MIND_BLAST */
- case RF5_SPELL_START + 11: return spell_RF5_BRAIN_SMASH(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BRAIN_SMASH */
- case RF5_SPELL_START + 12: return spell_RF5_CAUSE_1(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_CAUSE_1 */
- case RF5_SPELL_START + 13: return spell_RF5_CAUSE_2(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_CAUSE_2 */
- case RF5_SPELL_START + 14: return spell_RF5_CAUSE_3(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_CAUSE_3 */
- case RF5_SPELL_START + 15: return spell_RF5_CAUSE_4(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_CAUSE_4 */
- case RF5_SPELL_START + 16: return spell_RF5_BO_ACID(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_ACID */
- case RF5_SPELL_START + 17: return spell_RF5_BO_ELEC(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_ELEC */
- case RF5_SPELL_START + 18: return spell_RF5_BO_FIRE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_FIRE */
- case RF5_SPELL_START + 19: return spell_RF5_BO_COLD(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_COLD */
- case RF5_SPELL_START + 20: return spell_RF5_BA_LITE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BA_LITE */
- case RF5_SPELL_START + 21: return spell_RF5_BO_NETH(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_NETH */
- case RF5_SPELL_START + 22: return spell_RF5_BO_WATE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_WATE */
- case RF5_SPELL_START + 23: return spell_RF5_BO_MANA(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_MANA */
- case RF5_SPELL_START + 24: return spell_RF5_BO_PLAS(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_PLAS */
- case RF5_SPELL_START + 25: return spell_RF5_BO_ICEE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_BO_ICEE */
- case RF5_SPELL_START + 26: return spell_RF5_MISSILE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF5_MISSILE */
- case RF5_SPELL_START + 27: spell_RF5_SCARE(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); break; /* RF5_SCARE */
- case RF5_SPELL_START + 28: spell_RF5_BLIND(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); break; /* RF5_BLIND */
- case RF5_SPELL_START + 29: spell_RF5_CONF(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); break; /* RF5_CONF */
- case RF5_SPELL_START + 30: spell_RF5_SLOW(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); break; /* RF5_SLOW */
- case RF5_SPELL_START + 31: spell_RF5_HOLD(m_idx, target_ptr, t_idx, MONSTER_TO_MONSTER); break; /* RF5_HOLD */
- case RF6_SPELL_START + 0: spell_RF6_HASTE(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_HASTE */
- case RF6_SPELL_START + 1: return spell_RF6_HAND_DOOM(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_HAND_DOOM */
- case RF6_SPELL_START + 2: spell_RF6_HEAL(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_HEAL */
- case RF6_SPELL_START + 3: spell_RF6_INVULNER(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_INVULNER */
- case RF6_SPELL_START + 4: spell_RF6_BLINK(target_ptr, m_idx, MONSTER_TO_MONSTER, is_special_spell); break; /* RF6_BLINK */
- case RF6_SPELL_START + 5: spell_RF6_TPORT(target_ptr, m_idx, MONSTER_TO_MONSTER); break; /* RF6_TPORT */
- case RF6_SPELL_START + 6: return -1; break; /* RF6_WORLD */
- case RF6_SPELL_START + 7: return spell_RF6_SPECIAL(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_SPECIAL */
- case RF6_SPELL_START + 8: spell_RF6_TELE_TO(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_TELE_TO */
- case RF6_SPELL_START + 9: spell_RF6_TELE_AWAY(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_TELE_AWAY */
- case RF6_SPELL_START + 10: spell_RF6_TELE_LEVEL(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_TELE_LEVEL */
- case RF6_SPELL_START + 11: return spell_RF6_PSY_SPEAR(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_PSY_SPEAR */
- case RF6_SPELL_START + 12: spell_RF6_DARKNESS(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_DARKNESS */
- case RF6_SPELL_START + 13: return -1; /* RF6_TRAPS */
- case RF6_SPELL_START + 14: return -1; /* RF6_FORGET */
- case RF6_SPELL_START + 15: spell_RF6_RAISE_DEAD(target_ptr, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_RAISE_DEAD */
- case RF6_SPELL_START + 16: spell_RF6_S_KIN(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_KIN */
- case RF6_SPELL_START + 17: spell_RF6_S_CYBER(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_CYBER */
- case RF6_SPELL_START + 18: spell_RF6_S_MONSTER(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_MONSTER */
- case RF6_SPELL_START + 19: spell_RF6_S_MONSTERS(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_MONSTER */
- case RF6_SPELL_START + 20: spell_RF6_S_ANT(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_ANT */
- case RF6_SPELL_START + 21: spell_RF6_S_SPIDER(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_SPIDER */
- case RF6_SPELL_START + 22: spell_RF6_S_HOUND(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_HOUND */
- case RF6_SPELL_START + 23: spell_RF6_S_HYDRA(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_HYDRA */
- case RF6_SPELL_START + 24: spell_RF6_S_ANGEL(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_ANGEL */
- case RF6_SPELL_START + 25: spell_RF6_S_DEMON(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_DEMON */
- case RF6_SPELL_START + 26: spell_RF6_S_UNDEAD(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_UNDEAD */
- case RF6_SPELL_START + 27: spell_RF6_S_DRAGON(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_DRAGON */
- case RF6_SPELL_START + 28: spell_RF6_S_HI_UNDEAD(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_HI_UNDEAD */
- case RF6_SPELL_START + 29: spell_RF6_S_HI_DRAGON(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_HI_DRAGON */
- case RF6_SPELL_START + 30: spell_RF6_S_AMBERITES(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_AMBERITES */
- case RF6_SPELL_START + 31: spell_RF6_S_UNIQUE(target_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); break; /* RF6_S_UNIQUE */
- }
+ // 特技使用前の時点でプレイヤーがモンスターを視認できているかチェック(ラーニングの必要条件)。
+ const bool player_could_see_monster = spell_learnable(target_ptr, m_idx);
+
+ auto res = monspell_to_monster_impl(target_ptr, ms_type, y, x, m_idx, t_idx, is_special_spell);
+ if (!player_could_see_monster)
+ res.learnable = false;
+
+ // 条件を満たしていればラーニングを試みる。
+ if (res.valid && res.learnable) {
+ const auto monspell = spell_idx_to_monster_spell_type(ms_type);
+ learn_spell(target_ptr, monspell);
+ }
- return 0;
+ return res;
}
#include "system/angband.h"
-HIT_POINT monspell_to_player(player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx);
-HIT_POINT monspell_to_monster(player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, bool is_special_spell);
+struct MonsterSpellResult;
+
+MonsterSpellResult monspell_to_player(player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx);
+MonsterSpellResult monspell_to_monster(
+ player_type *target_ptr, SPELL_IDX ms_type, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, bool is_special_spell);
#include "mspell/mspell-selector.h"
#include "mspell/mspell-type.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "player/attack-defense-types.h"
#include "spell-kind/spells-world.h"
#include "spell-realm/spells-hex.h"
if (!check_thrown_mspell(target_ptr, msa_ptr))
return FALSE;
- // 特技使用前の時点でプレイヤーがモンスターを視認できているかチェック(ラーニングの必要条件)。
- const bool player_could_see_monster = spell_learnable(target_ptr, m_idx);
-
// 特技を使う。
- msa_ptr->dam = monspell_to_player(target_ptr, msa_ptr->thrown_spell, msa_ptr->y, msa_ptr->x, m_idx);
- if (msa_ptr->dam < 0)
+ const auto monspell_res = monspell_to_player(target_ptr, msa_ptr->thrown_spell, msa_ptr->y, msa_ptr->x, m_idx);
+ if (!monspell_res.valid)
return FALSE;
- // 条件を満たしていればラーニングを試みる。
- if (player_could_see_monster) {
- const int monspell = msa_ptr->thrown_spell - RF4_SPELL_START;
- // XXX: 「暗闇」は特定条件下でライトエリアになる関係上、やむを得ずラー
- // ニング処理を特技処理に含めた。よって二重ラーニングを行わないようここ
- // では除外する。
- const bool try_learn = monster_spell_is_learnable(monspell) && monspell != MS_DARKNESS;
- if (try_learn)
- learn_spell(target_ptr, monspell);
- }
-
check_mspell_imitation(target_ptr, msa_ptr);
remember_mspell(msa_ptr);
if (target_ptr->is_dead && (msa_ptr->r_ptr->r_deaths < MAX_SHORT) && !target_ptr->current_floor_ptr->inside_arena)
#include "mspell/mspell-ball.h"
+#include "effect/effect-processor.h"
#include "main/sound-of-music.h"
#include "mind/drs-types.h"
#include "monster-race/race-indice-types.h"
#include "mspell/mspell-damage-calculator.h"
#include "mspell/mspell-type.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "spell/spell-types.h"
#include "system/floor-type-definition.h"
#include "view/display-messages.h"
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF4_BA_NUKE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF4_BA_NUKE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが放射能球を放った。", "%^s casts a ball of radiation."),
_("%^sが%sに放射能球を放った。", "%^s casts a ball of radiation at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BALL_NUKE), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_NUKE, dam, 2, FALSE, MS_BALL_NUKE, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_NUKE), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_NUKE, dam, 2, FALSE, MS_BALL_NUKE, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_POIS);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF4_BA_CHAO(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF4_BA_CHAO(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが恐ろしげにつぶやいた。", "%^s mumbles frighteningly."),
_("%^sが純ログルスを放った。", "%^s invokes a raw Logrus."), _("%^sが%sに純ログルスを放った。", "%^s invokes raw Logrus upon %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BALL_CHAOS), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_CHAOS, dam, 4, FALSE, MS_BALL_CHAOS, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_CHAOS), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_CHAOS, dam, 4, FALSE, MS_BALL_CHAOS, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_CHAOS);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_ACID(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_ACID(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam, rad;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがアシッド・ボールの呪文を唱えた。", "%^s casts an acid ball."),
_("%^sが%sに向かってアシッド・ボールの呪文を唱えた。", "%^s casts an acid ball at %s."), TARGET_TYPE);
- rad = monster_is_powerful(target_ptr->current_floor_ptr, m_idx) ? 4 : 2;
- dam = monspell_damage(target_ptr, (MS_BALL_ACID), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_ACID, dam, rad, FALSE, MS_BALL_ACID, TARGET_TYPE);
+ const auto rad = monster_is_powerful(target_ptr->current_floor_ptr, m_idx) ? 4 : 2;
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_ACID), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_ACID, dam, rad, FALSE, MS_BALL_ACID, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_ACID);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_ELEC(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_ELEC(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam, rad;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
- _("%^sã\81\8cã\82µã\83³ã\83\80ã\83¼ã\83»ã\83»ã\83\9cã\83¼ã\83«ã\81®å\91ªæ\96\87ã\82\92å\94±ã\81\88ã\81\9fã\80\82", "%^s casts a lightning ball."),
+ _("%^sがサンダー・ボールの呪文を唱えた。", "%^s casts a lightning ball."),
_("%^sが%sに向かってサンダー・ボールの呪文を唱えた。", "%^s casts a lightning ball at %s."), TARGET_TYPE);
- rad = monster_is_powerful(target_ptr->current_floor_ptr, m_idx) ? 4 : 2;
- dam = monspell_damage(target_ptr, (MS_BALL_ELEC), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_ELEC, dam, rad, FALSE, MS_BALL_ELEC, TARGET_TYPE);
+ const auto rad = monster_is_powerful(target_ptr->current_floor_ptr, m_idx) ? 4 : 2;
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_ELEC), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_ELEC, dam, rad, FALSE, MS_BALL_ELEC, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_ELEC);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_FIRE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_FIRE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam, rad;
monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
if (m_ptr->r_idx == MON_ROLENTO) {
_("%^sがファイア・ボールの呪文を唱えた。", "%^s casts a fire ball."),
_("%^sが%sに向かってファイア・ボールの呪文を唱えた。", "%^s casts a fire ball at %s."), TARGET_TYPE);
}
- rad = monster_is_powerful(target_ptr->current_floor_ptr, m_idx) ? 4 : 2;
- dam = monspell_damage(target_ptr, (MS_BALL_FIRE), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_FIRE, dam, rad, FALSE, MS_BALL_FIRE, TARGET_TYPE);
+
+ const auto rad = monster_is_powerful(target_ptr->current_floor_ptr, m_idx) ? 4 : 2;
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_FIRE), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_FIRE, dam, rad, FALSE, MS_BALL_FIRE, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_FIRE);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_COLD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_COLD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam, rad;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがアイス・ボールの呪文を唱えた。", "%^s casts a frost ball."),
_("%^sが%sに向かってアイス・ボールの呪文を唱えた。", "%^s casts a frost ball at %s."), TARGET_TYPE);
- rad = monster_is_powerful(target_ptr->current_floor_ptr, m_idx) ? 4 : 2;
- dam = monspell_damage(target_ptr, (MS_BALL_COLD), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_COLD, dam, rad, FALSE, MS_BALL_COLD, TARGET_TYPE);
+ const auto rad = monster_is_powerful(target_ptr->current_floor_ptr, m_idx) ? 4 : 2;
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_COLD), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_COLD, dam, rad, FALSE, MS_BALL_COLD, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_COLD);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_POIS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_POIS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが悪臭雲の呪文を唱えた。", "%^s casts a stinking cloud."),
_("%^sが%sに向かって悪臭雲の呪文を唱えた。", "%^s casts a stinking cloud at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BALL_POIS), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_POIS, dam, 2, FALSE, MS_BALL_POIS, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_POIS), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_POIS, dam, 2, FALSE, MS_BALL_POIS, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_POIS);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_NETH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_NETH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが地獄球の呪文を唱えた。", "%^s casts a nether ball."),
_("%^sが%sに向かって地獄球の呪文を唱えた。", "%^s casts a nether ball at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BALL_NETHER), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_NETHER, dam, 2, FALSE, MS_BALL_NETHER, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_NETHER), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_NETHER, dam, 2, FALSE, MS_BALL_NETHER, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_NETH);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_WATE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_WATE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
bool known = monster_near_player(target_ptr->current_floor_ptr, m_idx, t_idx);
bool see_either = see_monster(target_ptr, m_idx) || see_monster(target_ptr, t_idx);
bool mon_to_mon = (TARGET_TYPE == MONSTER_TO_MONSTER);
msg_format(_("%^sは渦巻に飲み込まれた。", "%^s is engulfed in a whirlpool."), t_name);
}
- dam = monspell_damage(target_ptr, (MS_BALL_WATER), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_WATER, dam, 4, FALSE, MS_BALL_WATER, TARGET_TYPE);
- return dam;
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_WATER), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_WATER, dam, 4, FALSE, MS_BALL_WATER, TARGET_TYPE);
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かを力強くつぶやいた。", "%^s mumbles powerfully."),
_("%^sが魔力の嵐の呪文を念じた。", "%^s invokes a mana storm."), _("%^sが%sに対して魔力の嵐の呪文を念じた。", "%^s invokes a mana storm upon %s."),
TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BALL_MANA), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_MANA, dam, 4, FALSE, MS_BALL_MANA, TARGET_TYPE);
- return dam;
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_MANA), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_MANA, dam, 4, FALSE, MS_BALL_MANA, TARGET_TYPE);
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_DARK(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_DARK(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かを力強くつぶやいた。", "%^s mumbles powerfully."),
_("%^sが暗黒の嵐の呪文を念じた。", "%^s invokes a darkness storm."),
_("%^sが%sに対して暗黒の嵐の呪文を念じた。", "%^s invokes a darkness storm upon %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BALL_DARK), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_DARK, dam, 4, FALSE, MS_BALL_DARK, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BALL_DARK), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_DARK, dam, 4, FALSE, MS_BALL_DARK, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_DARK);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BA_LITE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BA_LITE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かを力強くつぶやいた。", "%^s mumbles powerfully."),
_("%^sがスターバーストの呪文を念じた。", "%^s invokes a starburst."),
_("%^sが%sに対してスターバーストの呪文を念じた。", "%^s invokes a starburst upon %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_STARBURST), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_LITE, dam, 4, FALSE, MS_STARBURST, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_STARBURST), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_LITE, dam, 4, FALSE, MS_STARBURST, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_LITE);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
#include "system/angband.h"
-HIT_POINT spell_RF4_BA_NUKE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF4_BA_CHAO(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_ACID(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_ELEC(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_FIRE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_COLD(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_POIS(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_NETH(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_WATE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_MANA(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_DARK(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BA_LITE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF4_BA_NUKE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF4_BA_CHAO(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_ACID(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_ELEC(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_FIRE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_COLD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_POIS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_NETH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_WATE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_DARK(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BA_LITE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
#include "mspell/mspell-bolt.h"
+#include "effect/effect-processor.h"
#include "main/sound-definitions-table.h"
#include "main/sound-of-music.h"
#include "mind/drs-types.h"
#include "mspell/mspell-damage-calculator.h"
#include "mspell/mspell-type.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "spell/spell-types.h"
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF4_SHOOT(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF4_SHOOT(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが奇妙な音を発した。", "%^s makes a strange noise."), _("%^sが矢を放った。", "%^s fires an arrow."),
_("%^sが%sに矢を放った。", "%^s fires an arrow at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_SHOOT), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_ARROW, dam, MS_SHOOT, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_SHOOT), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_ARROW, dam, MS_SHOOT, TARGET_TYPE);
sound(SOUND_SHOOT);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_ACID(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_ACID(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがアシッド・ボルトの呪文を唱えた。", "%^s casts an acid bolt."),
_("%sが%sに向かってアシッド・ボルトの呪文を唱えた。", "%^s casts an acid bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_ACID), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_ACID, dam, MS_BOLT_ACID, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_ACID), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_ACID, dam, MS_BOLT_ACID, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_ACID);
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_ELEC(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_ELEC(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがサンダー・ボルトの呪文を唱えた。", "%^s casts a lightning bolt."),
_("%^sが%sに向かってサンダー・ボルトの呪文を唱えた。", "%^s casts a lightning bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_ELEC), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_ELEC, dam, MS_BOLT_ELEC, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_ELEC), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_ELEC, dam, MS_BOLT_ELEC, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_ELEC);
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_FIRE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_FIRE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがファイア・ボルトの呪文を唱えた。", "%^s casts a fire bolt."),
_("%^sが%sに向かってファイア・ボルトの呪文を唱えた。", "%^s casts a fire bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_FIRE), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_FIRE, dam, MS_BOLT_FIRE, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_FIRE), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_FIRE, dam, MS_BOLT_FIRE, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_FIRE);
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_COLD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_COLD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがアイス・ボルトの呪文を唱えた。", "%^s casts a frost bolt."),
_("%^sが%sに向かってアイス・ボルトの呪文を唱えた。", "%^s casts a frost bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_COLD), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_COLD, dam, MS_BOLT_COLD, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_COLD), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_COLD, dam, MS_BOLT_COLD, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_COLD);
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_NETH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_NETH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが地獄の矢の呪文を唱えた。", "%^s casts a nether bolt."),
_("%^sが%sに向かって地獄の矢の呪文を唱えた。", "%^s casts a nether bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_NETHER), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_NETHER, dam, MS_BOLT_NETHER, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_NETHER), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_NETHER, dam, MS_BOLT_NETHER, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_NETH);
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_WATE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_WATE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがウォーター・ボルトの呪文を唱えた。", "%^s casts a water bolt."),
_("%^sが%sに向かってウォーター・ボルトの呪文を唱えた。", "%^s casts a water bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_WATER), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_WATER, dam, MS_BOLT_WATER, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_WATER), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_WATER, dam, MS_BOLT_WATER, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが魔力の矢の呪文を唱えた。", "%^s casts a mana bolt."),
_("%^sが%sに向かって魔力の矢の呪文を唱えた。", "%^s casts a mana bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_MANA), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_MANA, dam, MS_BOLT_MANA, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_MANA), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_MANA, dam, MS_BOLT_MANA, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_PLAS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_PLAS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがプラズマ・ボルトの呪文を唱えた。", "%^s casts a plasma bolt."),
_("%^sが%sに向かってプラズマ・ボルトの呪文を唱えた。", "%^s casts a plasma bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_PLASMA), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_PLASMA, dam, MS_BOLT_PLASMA, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_PLASMA), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_PLASMA, dam, MS_BOLT_PLASMA, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BO_ICEE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BO_ICEE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが極寒の矢の呪文を唱えた。", "%^s casts an ice bolt."),
_("%^sが%sに向かって極寒の矢の呪文を唱えた。", "%^s casts an ice bolt at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_BOLT_ICE), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_ICE, dam, MS_BOLT_ICE, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_BOLT_ICE), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_ICE, dam, MS_BOLT_ICE, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_COLD);
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_MISSILE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_MISSILE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがマジック・ミサイルの呪文を唱えた。", "%^s casts a magic missile."),
_("%^sが%sに向かってマジック・ミサイルの呪文を唱えた。", "%^s casts a magic missile at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_MAGIC_MISSILE), m_idx, DAM_ROLL);
- bolt(target_ptr, m_idx, y, x, GF_MISSILE, dam, MS_MAGIC_MISSILE, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_MAGIC_MISSILE), m_idx, DAM_ROLL);
+ const auto proj_res = bolt(target_ptr, m_idx, y, x, GF_MISSILE, dam, MS_MAGIC_MISSILE, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
update_smart_learn(target_ptr, m_idx, DRS_REFLECT);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
#include "system/angband.h"
-HIT_POINT spell_RF4_SHOOT(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_ACID(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_ELEC(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_FIRE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_COLD(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_NETH(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_WATE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_MANA(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_PLAS(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BO_ICEE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_MISSILE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF4_SHOOT(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_ACID(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_ELEC(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_FIRE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_COLD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_NETH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_WATE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_PLAS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BO_ICEE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_MISSILE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
#include "mspell/mspell-breath.h"
#include "core/disturbance.h"
+#include "effect/effect-processor.h"
#include "main/sound-definitions-table.h"
#include "main/sound-of-music.h"
#include "mind/drs-types.h"
#include "mspell/mspell-checker.h"
#include "mspell/mspell-damage-calculator.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "spell/spell-types.h"
#include "system/floor-type-definition.h"
#include "view/display-messages.h"
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF4_BREATH(player_type *target_ptr, int GF_TYPE, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF4_BREATH(player_type *target_ptr, int GF_TYPE, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
HIT_POINT dam, ms_type, drs_type = 0;
concptr type_s;
floor_ptr->monster_noise = TRUE;
sound(SOUND_BREATH);
- breath(target_ptr, y, x, m_idx, GF_TYPE, dam, 0, TRUE, ms_type, TARGET_TYPE);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_TYPE, dam, 0, TRUE, ms_type, TARGET_TYPE);
if (smart_learn_aux && mon_to_player)
update_smart_learn(target_ptr, m_idx, drs_type);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
#include "system/angband.h"
-HIT_POINT spell_RF4_BREATH(player_type* target_ptr, int GF_TYPE, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF4_BREATH(player_type *target_ptr, int GF_TYPE, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
* @param dam_hp 威力
* @param monspell モンスター魔法のID
* @param target_type モンスターからモンスターへ撃つならMONSTER_TO_MONSTER、モンスターからプレイヤーならMONSTER_TO_PLAYER
- * @return なし
*/
-void bolt(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type)
+ProjectResult bolt(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type)
{
BIT_FLAGS flg = 0;
switch (target_type) {
if (typ != GF_ARROW)
flg |= PROJECT_REFLECTABLE;
- (void)project(target_ptr, m_idx, 0, y, x, dam_hp, typ, flg, monspell);
+ return project(target_ptr, m_idx, 0, y, x, dam_hp, typ, flg, monspell);
}
/*!
* @param dam_hp 威力
* @param monspell モンスター魔法のID
* @param target_type モンスターからモンスターへ撃つならMONSTER_TO_MONSTER、モンスターからプレイヤーならMONSTER_TO_PLAYER
- * @return なし
*/
-void beam(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type)
+ProjectResult beam(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type)
{
BIT_FLAGS flg = 0;
switch (target_type) {
break;
}
- (void)project(target_ptr, m_idx, 0, y, x, dam_hp, typ, flg, monspell);
+ return project(target_ptr, m_idx, 0, y, x, dam_hp, typ, flg, monspell);
}
/*!
* @param breath
* @param monspell モンスター魔法のID
* @param target_type モンスターからモンスターへ撃つならMONSTER_TO_MONSTER、モンスターからプレイヤーならMONSTER_TO_PLAYER
- * @return なし
*/
-void breath(
+ProjectResult breath(
player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, EFFECT_ID typ, int dam_hp, POSITION rad, bool breath, int monspell, int target_type)
{
monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
break;
}
- (void)project(target_ptr, m_idx, rad, y, x, dam_hp, typ, flg, monspell);
+ return project(target_ptr, m_idx, rad, y, x, dam_hp, typ, flg, monspell);
}
/*!
#include "system/angband.h"
#include "system/monster-type-definition.h"
+struct ProjectResult;
+
bool clean_shot(player_type *target_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, bool is_friend);
bool summon_possible(player_type *target_ptr, POSITION y1, POSITION x1);
bool raise_possible(player_type *target_ptr, monster_type *m_ptr);
bool spell_is_inate(SPELL_IDX spell);
-void beam(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type);
-void bolt(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type);
-void breath(
+ProjectResult beam(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type);
+ProjectResult bolt(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type);
+ProjectResult breath(
player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, EFFECT_ID typ, int dam_hp, POSITION rad, bool breath, int monspell, int target_type);
#include "mspell/mspell-curse.h"
#include "core/disturbance.h"
+#include "effect/effect-processor.h"
#include "monster/monster-info.h"
#include "monster/monster-list.h"
#include "mspell/mspell-checker.h"
#include "mspell/mspell-damage-calculator.h"
#include "mspell/mspell-type.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "spell/spell-types.h"
#include "system/floor-type-definition.h"
#include "view/display-messages.h"
/*!
- * @brief RF5_CAUSE_*のメッセージ処理関数 /
+ * @brief RF5_CAUSE_* の処理関数
* @param target_ptr プレーヤーへの参照ポインタ
* @param GF_TYPE 攻撃に使用する属性
* @param dam 攻撃に使用するダメージ量
* @param msg3 対モンスターのメッセージ
* @param MS_TYPE 呪文の番号
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
*/
-void spell_RF5_CAUSE(player_type *target_ptr, int GF_TYPE, HIT_POINT dam, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, concptr msg1,
- concptr msg2, concptr msg3, int MS_TYPE, int TARGET_TYPE)
+static MonsterSpellResult spell_RF5_CAUSE(player_type *target_ptr, int GF_TYPE, HIT_POINT dam, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx,
+ concptr msg1, concptr msg2, concptr msg3, int MS_TYPE, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
monster_name(target_ptr, t_idx, t_name);
else
msg_format(msg2, m_name);
breath(target_ptr, y, x, m_idx, GF_TYPE, dam, 0, FALSE, MS_TYPE, TARGET_TYPE);
- return;
+ return res;
}
if (TARGET_TYPE == MONSTER_TO_MONSTER) {
}
breath(target_ptr, y, x, m_idx, GF_TYPE, dam, 0, FALSE, MS_TYPE, TARGET_TYPE);
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-HIT_POINT spell_RF5_CAUSE_1(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_CAUSE_1(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- concptr msg1, msg2, msg3;
- HIT_POINT dam;
- dam = monspell_damage(target_ptr, (MS_CAUSE_1), m_idx, DAM_ROLL);
+ concptr msg1 = _("%^sが何かをつぶやいた。", "%^s mumbles.");
+ concptr msg2 = _("%^sがあなたを指さして呪った。", "%^s points at you and curses.");
+ concptr msg3 = _("%^sは%sを指さして呪いをかけた。", "%^s points at %s and curses.");
- msg1 = _("%^sが何かをつぶやいた。", "%^s mumbles.");
- msg2 = _("%^sがあなたを指さして呪った。", "%^s points at you and curses.");
- msg3 = _("%^sは%sを指さして呪いをかけた。", "%^s points at %s and curses.");
+ const auto dam = monspell_damage(target_ptr, (MS_CAUSE_1), m_idx, DAM_ROLL);
- spell_RF5_CAUSE(target_ptr, GF_CAUSE_1, dam, y, x, m_idx, t_idx, msg1, msg2, msg3, MS_CAUSE_1, TARGET_TYPE);
- return dam;
+ return spell_RF5_CAUSE(target_ptr, GF_CAUSE_1, dam, y, x, m_idx, t_idx, msg1, msg2, msg3, MS_CAUSE_1, TARGET_TYPE);
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-HIT_POINT spell_RF5_CAUSE_2(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_CAUSE_2(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- concptr msg1, msg2, msg3;
- HIT_POINT dam;
- dam = monspell_damage(target_ptr, (MS_CAUSE_2), m_idx, DAM_ROLL);
+ concptr msg1 = _("%^sが何かをつぶやいた。", "%^s mumbles.");
+ concptr msg2 = _("%^sがあなたを指さして恐ろしげに呪った。", "%^s points at you and curses horribly.");
+ concptr msg3 = _("%^sは%sを指さして恐ろしげに呪いをかけた。", "%^s points at %s and curses horribly.");
- msg1 = _("%^sが何かをつぶやいた。", "%^s mumbles.");
- msg2 = _("%^sがあなたを指さして恐ろしげに呪った。", "%^s points at you and curses horribly.");
- msg3 = _("%^sは%sを指さして恐ろしげに呪いをかけた。", "%^s points at %s and curses horribly.");
+ const auto dam = monspell_damage(target_ptr, (MS_CAUSE_2), m_idx, DAM_ROLL);
- spell_RF5_CAUSE(target_ptr, GF_CAUSE_2, dam, y, x, m_idx, t_idx, msg1, msg2, msg3, MS_CAUSE_2, TARGET_TYPE);
- return dam;
+ return spell_RF5_CAUSE(target_ptr, GF_CAUSE_2, dam, y, x, m_idx, t_idx, msg1, msg2, msg3, MS_CAUSE_2, TARGET_TYPE);
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-HIT_POINT spell_RF5_CAUSE_3(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_CAUSE_3(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- concptr msg1, msg2, msg3;
- HIT_POINT dam;
- dam = monspell_damage(target_ptr, (MS_CAUSE_3), m_idx, DAM_ROLL);
+ concptr msg1 = _("%^sが何かを大声で叫んだ。", "%^s mumbles loudly.");
+ concptr msg2 = _("%^sがあなたを指さして恐ろしげに呪文を唱えた!", "%^s points at you, incanting terribly!");
+ concptr msg3 = _("%^sは%sを指さし、恐ろしげに呪文を唱えた!", "%^s points at %s, incanting terribly!");
- msg1 = _("%^sが何かを大声で叫んだ。", "%^s mumbles loudly.");
- msg2 = _("%^sがあなたを指さして恐ろしげに呪文を唱えた!", "%^s points at you, incanting terribly!");
- msg3 = _("%^sは%sを指さし、恐ろしげに呪文を唱えた!", "%^s points at %s, incanting terribly!");
+ const auto dam = monspell_damage(target_ptr, (MS_CAUSE_3), m_idx, DAM_ROLL);
- spell_RF5_CAUSE(target_ptr, GF_CAUSE_3, dam, y, x, m_idx, t_idx, msg1, msg2, msg3, MS_CAUSE_3, TARGET_TYPE);
- return dam;
+ return spell_RF5_CAUSE(target_ptr, GF_CAUSE_3, dam, y, x, m_idx, t_idx, msg1, msg2, msg3, MS_CAUSE_3, TARGET_TYPE);
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-HIT_POINT spell_RF5_CAUSE_4(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_CAUSE_4(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- concptr msg1, msg2, msg3;
- HIT_POINT dam;
- dam = monspell_damage(target_ptr, (MS_CAUSE_4), m_idx, DAM_ROLL);
+ concptr msg1 = _("%^sが「お前は既に死んでいる」と叫んだ。", "%^s screams the word 'DIE!'");
+ concptr msg2 = _("%^sがあなたの秘孔を突いて「お前は既に死んでいる」と叫んだ。", "%^s points at you, screaming the word DIE!");
+ concptr msg3 = _("%^sが%sの秘孔を突いて、「お前は既に死んでいる」と叫んだ。", "%^s points at %s, screaming the word, 'DIE!'");
- msg1 = _("%^sが「お前は既に死んでいる」と叫んだ。", "%^s screams the word 'DIE!'");
- msg2 = _("%^sがあなたの秘孔を突いて「お前は既に死んでいる」と叫んだ。", "%^s points at you, screaming the word DIE!");
- msg3 = _("%^sが%sの秘孔を突いて、「お前は既に死んでいる」と叫んだ。", "%^s points at %s, screaming the word, 'DIE!'");
+ const auto dam = monspell_damage(target_ptr, (MS_CAUSE_4), m_idx, DAM_ROLL);
- spell_RF5_CAUSE(target_ptr, GF_CAUSE_4, dam, y, x, m_idx, t_idx, msg1, msg2, msg3, MS_CAUSE_4, TARGET_TYPE);
- return dam;
+ return spell_RF5_CAUSE(target_ptr, GF_CAUSE_4, dam, y, x, m_idx, t_idx, msg1, msg2, msg3, MS_CAUSE_4, TARGET_TYPE);
}
#include "system/angband.h"
-void spell_RF5_CAUSE(player_type* target_ptr, int GF_TYPE, HIT_POINT dam, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, concptr msg1, concptr msg2, concptr msg3, int MS_TYPE, int TARGET_TYPE);
-HIT_POINT spell_RF5_CAUSE_1(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_CAUSE_2(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_CAUSE_3(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_CAUSE_4(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF5_CAUSE_1(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_CAUSE_2(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_CAUSE_3(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_CAUSE_4(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
#include "monster/monster-status.h"
#include "mspell/mspell-type.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "player/attack-defense-types.h"
#include "realm/realm-song-numbers.h"
#include "spell-realm/spells-craft.h"
* @param target_ptr プレーヤーへの参照ポインタ
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF4_DISPEL(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF4_DISPEL(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
monster_name(target_ptr, t_idx, t_name);
msg_print(_("弱い者いじめは止めるんだ!", ""));
}
- return;
+ return res;
}
if (TARGET_TYPE == MONSTER_TO_MONSTER) {
dispel_monster_status(target_ptr, t_idx);
}
+
+ return res;
}
#include "system/angband.h"
-void spell_RF4_DISPEL(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF4_DISPEL(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
#include "mspell/mspell-status.h"
#include "mspell/mspell-type.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "player/player-personalities-types.h"
#include "player/player-status-flags.h"
#include "spell-kind/spells-lite.h"
* @param target_ptr プレーヤーへの参照ポインタ
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * ラーニング不可。
*/
-void spell_RF4_SHRIEK(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF4_SHRIEK(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
{
simple_monspell_message(target_ptr, m_idx, t_idx, _("%^sがかん高い金切り声をあげた。", "%^s makes a high pitched shriek."),
_("%^sが%sに向かって叫んだ。", "%^s shrieks at %s."), TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
aggravate_monsters(target_ptr, m_idx);
- return;
- }
-
- if (TARGET_TYPE == MONSTER_TO_MONSTER) {
+ } else if (TARGET_TYPE == MONSTER_TO_MONSTER) {
set_monster_csleep(target_ptr, t_idx, 0);
}
+
+ return MonsterSpellResult::make_valid();
}
/*!
* @brief RF6_WORLDの処理。時を止める。 /
* @param target_ptr プレーヤーへの参照ポインタ
* @param m_idx 呪文を唱えるモンスターID
+ *
+ * ラーニング不可。
*/
-HIT_POINT spell_RF6_WORLD(player_type *target_ptr, MONSTER_IDX m_idx)
+MonsterSpellResult spell_RF6_WORLD(player_type *target_ptr, MONSTER_IDX m_idx)
{
monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
MONSTER_IDX who = 0;
who = 1;
else if (m_ptr->r_idx == MON_WONG)
who = 3;
- if (!set_monster_timewalk(target_ptr, randint1(2) + 2, who, TRUE))
- return FALSE;
- return who;
+
+ (void)set_monster_timewalk(target_ptr, randint1(2) + 2, who, TRUE);
+
+ return MonsterSpellResult::make_valid();
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param is_quantum_effect 量子的効果によるショート・テレポートの場合時TRUE
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * ラーニング不可。
*/
-void spell_RF6_BLINK(player_type *target_ptr, MONSTER_IDX m_idx, int TARGET_TYPE, bool is_quantum_effect)
+MonsterSpellResult spell_RF6_BLINK(player_type *target_ptr, MONSTER_IDX m_idx, int TARGET_TYPE, bool is_quantum_effect)
{
+ const auto res = MonsterSpellResult::make_valid();
+
GAME_TEXT m_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
if (!is_quantum_effect && teleport_barrier(target_ptr, m_idx)) {
if (see_monster(target_ptr, m_idx))
msg_format(_("魔法のバリアが%^sのテレポートを邪魔した。", "Magic barrier obstructs teleporting of %^s."), m_name);
- return;
+ return res;
}
if (see_monster(target_ptr, m_idx))
if (TARGET_TYPE == MONSTER_TO_PLAYER)
target_ptr->update |= (PU_MONSTERS);
+
+ return res;
}
/*!
* @param target_ptr プレーヤーへの参照ポインタ
* @param m_idx 呪文を唱えるモンスターID
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * ラーニング不可。
*/
-void spell_RF6_TPORT(player_type *target_ptr, MONSTER_IDX m_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_TPORT(player_type *target_ptr, MONSTER_IDX m_idx, int TARGET_TYPE)
{
+ const auto res = MonsterSpellResult::make_valid();
+
GAME_TEXT m_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
if (teleport_barrier(target_ptr, m_idx)) {
if (see_monster(target_ptr, m_idx))
msg_format(_("魔法のバリアが%^sのテレポートを邪魔した。", "Magic barrier obstructs teleporting of %^s."), m_name);
- return;
+ return res;
}
if (see_monster(target_ptr, m_idx))
msg_format(_("%^sがテレポートした。", "%^s teleports away."), m_name);
teleport_away_followable(target_ptr, m_idx);
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_TELE_TO(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_TELE_TO(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *m_ptr = &floor_ptr->m_list[m_idx];
monster_type *t_ptr = &floor_ptr->m_list[t_idx];
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
teleport_player_to(target_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
- return;
+ return res;
}
if (TARGET_TYPE != MONSTER_TO_MONSTER)
- return;
+ return res;
bool resists_tele = FALSE;
GAME_TEXT t_name[MAX_NLEN];
if (resists_tele) {
set_monster_csleep(target_ptr, t_idx, 0);
- return;
+ return res;
}
if (t_idx == target_ptr->riding)
else
teleport_monster_to(target_ptr, t_idx, m_ptr->fy, m_ptr->fx, 100, TELEPORT_PASSIVE);
set_monster_csleep(target_ptr, t_idx, 0);
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_TELE_AWAY(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_TELE_AWAY(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *t_ptr = &floor_ptr->m_list[t_idx];
monster_race *tr_ptr = &r_info[t_ptr->r_idx];
}
teleport_player_away(m_idx, target_ptr, 100, FALSE);
- return;
+ return res;
}
if (TARGET_TYPE != MONSTER_TO_MONSTER)
- return;
+ return res;
bool resists_tele = FALSE;
GAME_TEXT t_name[MAX_NLEN];
if (resists_tele) {
set_monster_csleep(target_ptr, t_idx, 0);
- return;
+ return res;
}
if (t_idx == target_ptr->riding)
else
teleport_away(target_ptr, t_idx, MAX_SIGHT * 2 + 5, TELEPORT_PASSIVE);
set_monster_csleep(target_ptr, t_idx, 0);
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * ラーニング不可。
*/
-void spell_RF6_TELE_LEVEL(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_TELE_LEVEL(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ const auto res = MonsterSpellResult::make_valid();
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *t_ptr = &floor_ptr->m_list[t_idx];
monster_race *tr_ptr = &r_info[t_ptr->r_idx];
}
update_smart_learn(target_ptr, m_idx, DRS_NEXUS);
- return;
+ return res;
}
if (TARGET_TYPE != MONSTER_TO_MONSTER)
- return;
+ return res;
resist = tr_ptr->flagsr & (RFR_EFF_RES_NEXU_MASK | RFR_RES_TELE);
saving_throw = (tr_ptr->flags1 & RF1_QUESTOR) || (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
if (!resist && !saving_throw) {
teleport_level(target_ptr, (t_idx == target_ptr->riding) ? 0 : t_idx);
}
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象かつ暗闇ならラーニング可。
*/
-void spell_RF6_DARKNESS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_DARKNESS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *m_ptr = &floor_ptr->m_list[m_idx];
if (monster_to_monster && !is_hostile(t_ptr))
can_use_lite_area = FALSE;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = monster_to_player && !can_use_lite_area;
+
if (can_use_lite_area) {
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが辺りを明るく照らした。", "%^s cast a spell to light up."), _("%^sが辺りを明るく照らした。", "%^s cast a spell to light up."), TARGET_TYPE);
if (can_use_lite_area) {
(void)lite_area(target_ptr, 0, 3);
} else {
- // XXX: ラーニング条件が特技IDのみから決まらないため、やむを得ずここでラーニング処理を行う。
- learn_spell(target_ptr, MS_DARKNESS);
(void)unlite_area(target_ptr, 0, 3);
}
- return;
+ return res;
}
if (!monster_to_monster)
- return;
+ return res;
int lite_area = can_use_lite_area ? -1 : MS_DARKNESS;
(void)project(target_ptr, m_idx, 3, y, x, 0, GF_LITE_WEAK, PROJECT_GRID | PROJECT_KILL, lite_area);
lite_room(target_ptr, y, x);
+
+ return res;
}
/*!
* @param y 対象の地点のy座標
* @param x 対象の地点のx座標
* @param m_idx 呪文を唱えるモンスターID
- * @param なし
+ *
+ * ラーニング可。
*/
-void spell_RF6_TRAPS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx)
+MonsterSpellResult spell_RF6_TRAPS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx)
{
GAME_TEXT m_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
msg_format(_("%^sが呪文を唱えて邪悪に微笑んだ。", "%^s casts a spell and cackles evilly."), m_name);
(void)trap_creation(target_ptr, y, x);
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = true;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * ラーニング不可。
*/
-void spell_RF6_RAISE_DEAD(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_RAISE_DEAD(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
TARGET_TYPE);
animate_dead(target_ptr, m_idx, m_ptr->fy, m_ptr->fx);
+
+ return MonsterSpellResult::make_valid();
}
#include "system/angband.h"
-void spell_RF4_SHRIEK(MONSTER_IDX m_idx, player_type* target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF6_WORLD(player_type* target_ptr, MONSTER_IDX m_idx);
-void spell_RF6_BLINK(player_type* target_ptr, MONSTER_IDX m_idx, int TARGET_TYPE, bool is_quantum_effect);
-void spell_RF6_TPORT(player_type* target_ptr, MONSTER_IDX m_idx, int TARGET_TYPE);
-void spell_RF6_TELE_TO(player_type* target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_TELE_AWAY(player_type* target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_TELE_LEVEL(player_type* target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_DARKNESS(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_TRAPS(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx);
-void spell_RF6_RAISE_DEAD(player_type* target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF4_SHRIEK(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_WORLD(player_type *target_ptr, MONSTER_IDX m_idx);
+MonsterSpellResult spell_RF6_BLINK(player_type *target_ptr, MONSTER_IDX m_idx, int TARGET_TYPE, bool is_quantum_effect);
+MonsterSpellResult spell_RF6_TPORT(player_type *target_ptr, MONSTER_IDX m_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_TELE_TO(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_TELE_AWAY(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_TELE_LEVEL(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_DARKNESS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_TRAPS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx);
+MonsterSpellResult spell_RF6_RAISE_DEAD(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
*/
#include "mspell/mspell-particularity.h"
+#include "effect/effect-processor.h"
#include "mind/drs-types.h"
#include "monster/monster-update.h"
#include "mspell/mspell-checker.h"
#include "mspell/mspell-damage-calculator.h"
#include "mspell/mspell-type.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "spell/spell-types.h"
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF4_ROCKET(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF4_ROCKET(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
-
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かを射った。", "%^s shoots something."), _("%^sがロケットを発射した。", "%^s fires a rocket."),
_("%^sが%sにロケットを発射した。", "%^s fires a rocket at %s."), TARGET_TYPE);
- dam = monspell_damage(target_ptr, (MS_ROCKET), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_ROCKET, dam, 2, FALSE, MS_ROCKET, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_ROCKET), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_ROCKET, dam, 2, FALSE, MS_ROCKET, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_SHARD);
- return dam;
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF6_HAND_DOOM(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_HAND_DOOM(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
simple_monspell_message(target_ptr, m_idx, t_idx, _("%^sが<破滅の手>を放った!", "%^s invokes the Hand of Doom!"),
_("%^sが%sに<破滅の手>を放った!", "%^s invokes the Hand of Doom upon %s!"), TARGET_TYPE);
- HIT_POINT dam = 0;
+ ProjectResult proj_res;
if (TARGET_TYPE == MONSTER_TO_PLAYER) {
- dam = monspell_damage(target_ptr, (MS_HAND_DOOM), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_HAND_DOOM, dam, 0, FALSE, MS_HAND_DOOM, MONSTER_TO_PLAYER);
+ const auto dam = monspell_damage(target_ptr, (MS_HAND_DOOM), m_idx, DAM_ROLL);
+ proj_res = breath(target_ptr, y, x, m_idx, GF_HAND_DOOM, dam, 0, FALSE, MS_HAND_DOOM, MONSTER_TO_PLAYER);
} else if (TARGET_TYPE == MONSTER_TO_MONSTER) {
- dam = 20; /* Dummy power */
- breath(target_ptr, y, x, m_idx, GF_HAND_DOOM, dam, 0, FALSE, MS_HAND_DOOM, MONSTER_TO_MONSTER);
+ const auto dam = 20; /* Dummy power */
+ proj_res = breath(target_ptr, y, x, m_idx, GF_HAND_DOOM, dam, 0, FALSE, MS_HAND_DOOM, MONSTER_TO_MONSTER);
}
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF6_PSY_SPEAR(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_PSY_SPEAR(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが光の剣を放った。", "%^s throw a Psycho-Spear."),
_("%^sが%sに向かって光の剣を放った。", "%^s throw a Psycho-spear at %s."), TARGET_TYPE);
- HIT_POINT dam = monspell_damage(target_ptr, (MS_PSY_SPEAR), m_idx, DAM_ROLL);
- beam(target_ptr, m_idx, y, x, GF_PSY_SPEAR, dam, MS_PSY_SPEAR, MONSTER_TO_PLAYER);
- return dam;
+ const auto dam = monspell_damage(target_ptr, (MS_PSY_SPEAR), m_idx, DAM_ROLL);
+ const auto proj_res = beam(target_ptr, m_idx, y, x, GF_PSY_SPEAR, dam, MS_PSY_SPEAR, MONSTER_TO_PLAYER);
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
#include "system/angband.h"
-HIT_POINT spell_RF4_ROCKET(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF6_HAND_DOOM(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF6_PSY_SPEAR(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF4_ROCKET(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_HAND_DOOM(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_PSY_SPEAR(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
#include "monster/monster-util.h"
#include "mspell/mspell-checker.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "player/player-damage.h"
#include "spell-kind/spells-teleport.h"
#include "spell-realm/spells-crusade.h"
* @param player_ptr プレーヤーへの参照ポインタ
* @param m_idx 呪文を唱えるモンスターID
*/
-HIT_POINT spell_RF6_SPECIAL_BANORLUPART(player_type *target_ptr, MONSTER_IDX m_idx)
+static MonsterSpellResult spell_RF6_SPECIAL_BANORLUPART(player_type *target_ptr, MONSTER_IDX m_idx)
{
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *m_ptr = &floor_ptr->m_list[m_idx];
dummy_maxhp = m_ptr->maxhp / 2;
if (floor_ptr->inside_arena || target_ptr->phase_out || !summon_possible(target_ptr, m_ptr->fy, m_ptr->fx))
- return -1;
+ return MonsterSpellResult::make_invalid();
delete_monster_idx(target_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].m_idx);
summon_named_creature(target_ptr, 0, dummy_y, dummy_x, MON_BANOR, mode);
dummy_maxhp = 0;
if (!r_info[MON_BANOR].cur_num || !r_info[MON_LUPART].cur_num)
- return -1;
+ return MonsterSpellResult::make_invalid();
for (MONSTER_IDX k = 1; k < floor_ptr->m_max; k++) {
if (floor_ptr->m_list[k].r_idx == MON_BANOR || floor_ptr->m_list[k].r_idx == MON_LUPART) {
break;
}
- return 0;
+ return MonsterSpellResult::make_valid();
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
*/
-HIT_POINT spell_RF6_SPECIAL_ROLENTO(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+static MonsterSpellResult spell_RF6_SPECIAL_ROLENTO(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
int count = 0, k;
int num = 1 + randint1(3);
if (target_ptr->blind && count) {
msg_print(_("多くのものが間近にばらまかれる音がする。", "You hear many things scattered nearby."));
}
- return 0;
+
+ return MonsterSpellResult::make_valid();
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
*/
-HIT_POINT spell_RF6_SPECIAL_B(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+static MonsterSpellResult spell_RF6_SPECIAL_B(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *m_ptr = &floor_ptr->m_list[m_idx];
teleport_away(target_ptr, m_idx, 10, TELEPORT_NONMAGICAL);
target_ptr->update |= (PU_MONSTERS);
- return 0;
+ return MonsterSpellResult::make_valid();
}
-
simple_monspell_message(target_ptr, m_idx, t_idx, _("%^sがあなたを掴んで空中から投げ落とした。", "%^s snatches you, soars into the sky, and drops you."),
_("%^sが%sを掴んで空中から投げ落とした。", "%^s snatches %s, soars into the sky, and releases its grip."), TARGET_TYPE);
if (monster_to_monster)
mon_take_hit_mon(target_ptr, t_idx, dam, &dead, &fear, extract_note_dies(real_r_idx(t_ptr)), m_idx);
- return dam;
+
+ return MonsterSpellResult::make_valid();
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * ラーニング不可。
*/
-HIT_POINT spell_RF6_SPECIAL(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_SPECIAL(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *m_ptr = &floor_ptr->m_list[m_idx];
disturb(target_ptr, TRUE, TRUE);
switch (m_ptr->r_idx) {
case MON_OHMU:
- return -1;
+ return MonsterSpellResult::make_invalid();
case MON_BANORLUPART:
case MON_BANOR:
if (r_ptr->d_char == 'B') {
return spell_RF6_SPECIAL_B(target_ptr, y, x, m_idx, t_idx, TARGET_TYPE);
break;
+ } else {
+ return MonsterSpellResult::make_invalid();
}
-
- else
- return -1;
}
}
#include "system/angband.h"
-HIT_POINT spell_RF6_SPECIAL(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF6_SPECIAL(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
#include "blue-magic/blue-magic-checker.h"
#include "core/disturbance.h"
#include "core/player-redraw-types.h"
+#include "effect/effect-processor.h"
#include "mind/drs-types.h"
#include "monster-race/monster-race.h"
#include "monster-race/race-flags1.h"
#include "mspell/mspell-checker.h"
#include "mspell/mspell-damage-calculator.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "player/player-personalities-types.h"
#include "player/player-status-flags.h"
#include "spell/spell-types.h"
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_DRAIN_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_DRAIN_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
- HIT_POINT dam;
GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
monster_name(target_ptr, t_idx, t_name);
msg_format(_("%^sは精神エネルギーを%sから吸いとった。", "%^s draws psychic energy from %s."), m_name, t_name);
}
- dam = monspell_damage(target_ptr, (MS_DRAIN_MANA), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_DRAIN_MANA, dam, 0, FALSE, MS_DRAIN_MANA, TARGET_TYPE);
+ const auto dam = monspell_damage(target_ptr, (MS_DRAIN_MANA), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_DRAIN_MANA, dam, 0, FALSE, MS_DRAIN_MANA, TARGET_TYPE);
if (TARGET_TYPE == MONSTER_TO_PLAYER)
update_smart_learn(target_ptr, m_idx, DRS_MANA);
- return dam;
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_MIND_BLAST(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_MIND_BLAST(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
bool seen = (!target_ptr->blind && m_ptr->ml);
- HIT_POINT dam;
GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
monster_name(target_ptr, t_idx, t_name);
msg_format(_("%^sは%sをじっと睨んだ。", "%^s gazes intently at %s."), m_name, t_name);
}
- dam = monspell_damage(target_ptr, (MS_MIND_BLAST), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_MIND_BLAST, dam, 0, FALSE, MS_MIND_BLAST, TARGET_TYPE);
- return dam;
+ const auto dam = monspell_damage(target_ptr, (MS_MIND_BLAST), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_MIND_BLAST, dam, 0, FALSE, MS_MIND_BLAST, TARGET_TYPE);
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return ダメージ量を返す。
+ *
+ * プレイヤーに当たったらラーニング可。
*/
-HIT_POINT spell_RF5_BRAIN_SMASH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BRAIN_SMASH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
bool seen = (!target_ptr->blind && m_ptr->ml);
- HIT_POINT dam;
GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
monster_name(target_ptr, t_idx, t_name);
msg_format(_("%^sは%sをじっと睨んだ。", "%^s gazes intently at %s."), m_name, t_name);
}
- dam = monspell_damage(target_ptr, (MS_BRAIN_SMASH), m_idx, DAM_ROLL);
- breath(target_ptr, y, x, m_idx, GF_BRAIN_SMASH, dam, 0, FALSE, MS_BRAIN_SMASH, TARGET_TYPE);
- return dam;
+ const auto dam = monspell_damage(target_ptr, (MS_BRAIN_SMASH), m_idx, DAM_ROLL);
+ const auto proj_res = breath(target_ptr, y, x, m_idx, GF_BRAIN_SMASH, dam, 0, FALSE, MS_BRAIN_SMASH, TARGET_TYPE);
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = proj_res.affected_player;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF5_SCARE(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_SCARE(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *t_ptr = &floor_ptr->m_list[t_idx];
monster_race *tr_ptr = &r_info[t_ptr->r_idx];
}
update_smart_learn(target_ptr, m_idx, DRS_FEAR);
- return;
+ return res;
}
if (TARGET_TYPE != MONSTER_TO_MONSTER)
- return;
+ return res;
resist = ((tr_ptr->flags3 & RF3_NO_FEAR) != 0);
saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
if (!resist && !saving_throw) {
set_monster_monfear(target_ptr, t_idx, monster_fear_remaining(t_ptr) + randint0(4) + 4);
}
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF5_BLIND(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_BLIND(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *t_ptr = &floor_ptr->m_list[t_idx];
monster_race *tr_ptr = &r_info[t_ptr->r_idx];
}
update_smart_learn(target_ptr, m_idx, DRS_BLIND);
- return;
+ return res;
}
if (TARGET_TYPE != MONSTER_TO_MONSTER)
- return;
+ return res;
concptr msg1;
GAME_TEXT t_name[MAX_NLEN];
if (!resist && !saving_throw) {
(void)set_monster_confused(target_ptr, t_idx, monster_confused_remaining(t_ptr) + 12 + randint0(4));
}
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF5_CONF(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_CONF(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *t_ptr = &floor_ptr->m_list[t_idx];
monster_race *tr_ptr = &r_info[t_ptr->r_idx];
}
update_smart_learn(target_ptr, m_idx, DRS_CONF);
- return;
+ return res;
}
if (TARGET_TYPE != MONSTER_TO_MONSTER)
- return;
+ return res;
resist = ((tr_ptr->flags3 & RF3_NO_CONF) != 0);
saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
if (!resist && !saving_throw) {
(void)set_monster_confused(target_ptr, t_idx, monster_confused_remaining(t_ptr) + 12 + randint0(4));
}
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF5_HOLD(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_HOLD(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *t_ptr = &floor_ptr->m_list[t_idx];
monster_race *tr_ptr = &r_info[t_ptr->r_idx];
}
update_smart_learn(target_ptr, m_idx, DRS_FREE);
- return;
+ return res;
}
if (TARGET_TYPE != MONSTER_TO_MONSTER)
- return;
+ return res;
resist = ((tr_ptr->flags1 & RF1_UNIQUE) != 0 || (tr_ptr->flags3 & RF3_NO_STUN) != 0);
saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
if (!resist && !saving_throw) {
(void)set_monster_stunned(target_ptr, t_idx, monster_stunned_remaining(t_ptr) + randint1(4) + 4);
}
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * ラーニング不可。
*/
-void spell_RF6_HASTE(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_HASTE(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
bool see_m = see_monster(target_ptr, m_idx);
monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
if (TARGET_TYPE == MONSTER_TO_PLAYER || (TARGET_TYPE == MONSTER_TO_MONSTER && see_m))
msg_format(_("%^sの動きが速くなった。", "%^s starts moving faster."), m_name);
}
+
+ return MonsterSpellResult::make_valid();
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF5_SLOW(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF5_SLOW(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *t_ptr = &floor_ptr->m_list[t_idx];
monster_race *tr_ptr = &r_info[t_ptr->r_idx];
}
update_smart_learn(target_ptr, m_idx, DRS_FREE);
- return;
+ return res;
}
if (TARGET_TYPE != MONSTER_TO_MONSTER)
- return;
+ return res;
concptr msg1;
GAME_TEXT t_name[MAX_NLEN];
if (!resist && !saving_throw) {
set_monster_slow(target_ptr, t_idx, monster_slow_remaining(t_ptr) + 50);
}
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * ラーニング不可。
*/
-void spell_RF6_HEAL(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_HEAL(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
+ const auto res = MonsterSpellResult::make_valid();
+
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *m_ptr = &floor_ptr->m_list[m_idx];
DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
target_ptr->redraw |= (PR_UHEALTH);
if (!monster_fear_remaining(m_ptr))
- return;
+ return res;
(void)set_monster_monfear(target_ptr, m_idx, 0);
if (see_monster(target_ptr, m_idx))
msg_format(_("%^sは勇気を取り戻した。", format("%%^s recovers %s courage.", m_poss)), m_name);
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * ラーニング不可。
*/
-void spell_RF6_INVULNER(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_INVULNER(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
bool seen = (!target_ptr->blind && m_ptr->ml);
if (!monster_invulner_remaining(m_ptr))
(void)set_monster_invulner(target_ptr, m_idx, randint1(4) + 4, FALSE);
+
+ return MonsterSpellResult::make_valid();
}
/*!
* @brief RF6_FORGETの処理。記憶消去。 /
* @param target_ptr プレーヤーへの参照ポインタ
* @param m_idx 呪文を唱えるモンスターID
- * @param なし
+ *
+ * ラーニング可。
*/
-void spell_RF6_FORGET(player_type *target_ptr, MONSTER_IDX m_idx)
+MonsterSpellResult spell_RF6_FORGET(player_type *target_ptr, MONSTER_IDX m_idx)
{
DEPTH rlev = monster_level_idx(target_ptr->current_floor_ptr, m_idx);
GAME_TEXT m_name[MAX_NLEN];
} else if (lose_all_info(target_ptr)) {
msg_print(_("記憶が薄れてしまった。", "Your memories fade away."));
}
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = true;
+
+ return res;
}
#include "system/angband.h"
-void spell_badstatus_message(player_type* target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, concptr msg1, concptr msg2, concptr msg3, concptr msg4, bool resist, bool saving_throw, int TARGET_TYPE);
-HIT_POINT spell_RF5_DRAIN_MANA(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_MIND_BLAST(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-HIT_POINT spell_RF5_BRAIN_SMASH(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF5_SCARE(MONSTER_IDX m_idx, player_type* target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF5_BLIND(MONSTER_IDX m_idx, player_type* target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF5_CONF(MONSTER_IDX m_idx, player_type* target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF5_HOLD(MONSTER_IDX m_idx, player_type* target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_HASTE(player_type* target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF5_SLOW(MONSTER_IDX m_idx, player_type* target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_HEAL(player_type* target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_INVULNER(player_type* target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_FORGET(player_type* target_ptr, MONSTER_IDX m_idx);
+struct MonsterSpellResult;
+
+void spell_badstatus_message(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, concptr msg1, concptr msg2, concptr msg3, concptr msg4, bool resist,
+ bool saving_throw, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_DRAIN_MANA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_MIND_BLAST(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BRAIN_SMASH(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_SCARE(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_BLIND(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_CONF(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_HOLD(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_HASTE(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF5_SLOW(MONSTER_IDX m_idx, player_type *target_ptr, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_HEAL(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_INVULNER(player_type *target_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_FORGET(player_type *target_ptr, MONSTER_IDX m_idx);
#include "monster/monster-info.h"
#include "monster/monster-status.h"
#include "mspell/mspell-util.h"
+#include "mspell/mspell.h"
#include "mspell/specified-summon.h"
#include "spell-kind/spells-launcher.h"
#include "spell/spell-types.h"
* @param m_idx 呪文を唱えるモンスターID
* @return 召喚したモンスターの数を返す。
*/
-MONSTER_NUMBER summon_Kin(player_type *target_ptr, POSITION y, POSITION x, int rlev, MONSTER_IDX m_idx)
+static MONSTER_NUMBER summon_Kin(player_type *target_ptr, POSITION y, POSITION x, int rlev, MONSTER_IDX m_idx)
{
int count = 0;
for (int k = 0; k < 4; k++) {
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_KIN(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
+MonsterSpellResult spell_RF6_S_KIN(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
{
floor_type *floor_ptr = target_ptr->current_floor_ptr;
monster_type *m_ptr = &floor_ptr->m_list[m_idx];
if (known && !see_monster(target_ptr, t_idx) && count && (target_type == MONSTER_TO_MONSTER))
floor_ptr->monster_noise = TRUE;
+
+ auto res = MonsterSpellResult::make_valid();
+ res.learnable = target_type == MONSTER_TO_PLAYER;
+
+ return res;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_CYBER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_CYBER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
int count = 0;
floor_type *floor_ptr = target_ptr->current_floor_ptr;
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_MONSTER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_MONSTER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが魔法で仲間を召喚した!", "%^s magically summons help!"),
_("%^sが魔法で仲間を召喚した!", "%^s magically summons help!"), TARGET_TYPE);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_MONSTERS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_MONSTERS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが魔法でモンスターを召喚した!", "%^s magically summons monsters!"), _("%^sが魔法でモンスターを召喚した!", "%^s magically summons monsters!"),
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_ANT(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_ANT(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが魔法でアリを召喚した。", "%^s magically summons ants."),
_("%^sが魔法でアリを召喚した。", "%^s magically summons ants."), TARGET_TYPE);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_SPIDER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_SPIDER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."), _("%^sが魔法でクモを召喚した。", "%^s magically summons spiders."),
_("%^sが魔法でクモを召喚した。", "%^s magically summons spiders."), TARGET_TYPE);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_HOUND(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_HOUND(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが魔法でハウンドを召喚した。", "%^s magically summons hounds."), _("%^sが魔法でハウンドを召喚した。", "%^s magically summons hounds."),
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_HYDRA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_HYDRA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが魔法でヒドラを召喚した。", "%^s magically summons hydras."), _("%^sが魔法でヒドラを召喚した。", "%^s magically summons hydras."), TARGET_TYPE);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_ANGEL(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_ANGEL(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが魔法で天使を召喚した!", "%^s magically summons an angel!"), _("%^sが魔法で天使を召喚した!", "%^s magically summons an angel!"), TARGET_TYPE);
bool mon_to_mon = (TARGET_TYPE == MONSTER_TO_MONSTER);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_DEMON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_DEMON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sは魔法で混沌の宮廷から悪魔を召喚した!", "%^s magically summons a demon from the Courts of Chaos!"),
bool mon_to_mon = (TARGET_TYPE == MONSTER_TO_MONSTER);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_UNDEAD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_UNDEAD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが魔法でアンデッドの強敵を召喚した!", "%^s magically summons an undead adversary!"),
bool mon_to_mon = (TARGET_TYPE == MONSTER_TO_MONSTER);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_DRAGON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_DRAGON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが魔法でドラゴンを召喚した!", "%^s magically summons a dragon!"), _("%^sが魔法でドラゴンを召喚した!", "%^s magically summons a dragon!"),
bool mon_to_mon = (TARGET_TYPE == MONSTER_TO_MONSTER);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_HI_UNDEAD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_HI_UNDEAD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
GAME_TEXT m_name[MAX_NLEN];
monster_name(target_ptr, m_idx, m_name);
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_HI_DRAGON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_HI_DRAGON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが魔法で古代ドラゴンを召喚した!", "%^s magically summons ancient dragons!"),
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_AMBERITES(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_AMBERITES(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sがアンバーの王族を召喚した!", "%^s magically summons Lords of Amber!"),
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
/*!
* @param m_idx 呪文を唱えるモンスターID
* @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
* @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
- * @return 召喚したモンスターの数を返す。
+ *
+ * プレイヤーが対象ならラーニング可。
*/
-void spell_RF6_S_UNIQUE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
+MonsterSpellResult spell_RF6_S_UNIQUE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
{
monspell_message(target_ptr, m_idx, t_idx, _("%^sが何かをつぶやいた。", "%^s mumbles."),
_("%^sが魔法で特別な強敵を召喚した!", "%^s magically summons special opponents!"),
if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(target_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;
}
-#pragma once
+#pragma once
#include "system/angband.h"
-MONSTER_NUMBER summon_Kin(player_type* target_ptr, POSITION y, POSITION x, int rlev, MONSTER_IDX m_idx);
-void spell_RF6_S_KIN(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_CYBER(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_MONSTER(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_MONSTERS(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_ANT(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_SPIDER(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_HOUND(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_HYDRA(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_ANGEL(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_DEMON(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_UNDEAD(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_DRAGON(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_HI_UNDEAD(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_HI_DRAGON(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_AMBERITES(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
-void spell_RF6_S_UNIQUE(player_type* target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+struct MonsterSpellResult;
+
+MonsterSpellResult spell_RF6_S_KIN(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_CYBER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_MONSTER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_MONSTERS(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_ANT(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_SPIDER(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_HOUND(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_HYDRA(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_ANGEL(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_DEMON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_UNDEAD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_DRAGON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_HI_UNDEAD(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_HI_DRAGON(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_AMBERITES(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
+MonsterSpellResult spell_RF6_S_UNIQUE(player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE);
--- /dev/null
+#pragma once
+
+//! モンスターが魔法を使った際の結果。
+struct MonsterSpellResult {
+private:
+ explicit MonsterSpellResult(const bool valid)
+ : valid(valid)
+ {
+ }
+
+public:
+ bool valid; //!< 通常は true。何か変なこと(無効な魔法IDなど)が起こったら false
+ bool learnable{ false }; //!< ラーニングを試みるか
+
+ MonsterSpellResult() = delete;
+
+ static MonsterSpellResult make_valid()
+ {
+ return MonsterSpellResult(true);
+ }
+
+ static MonsterSpellResult make_invalid()
+ {
+ return MonsterSpellResult(false);
+ }
+};
#include "system/floor-type-definition.h"
#include "view/display-messages.h"
-bool switch_activation(player_type *user_ptr, object_type *o_ptr, const activation_type *const act_ptr, concptr name)
+bool switch_activation(player_type *user_ptr, object_type **o_ptr_ptr, const activation_type *const act_ptr, concptr name)
{
+ object_type *o_ptr = (*o_ptr_ptr);
+
switch (act_ptr->index) {
case ACT_SUNLIGHT:
return activate_sunlight(user_ptr);
true_healing(user_ptr, 0);
return TRUE;
case ACT_CURE_MANA_FULL:
- msg_format(_("%sが青白く光った...", "The %s glows pale..."), name);
+ msg_format(_("%sが青白く光った...", "The %s glows palely..."), name);
restore_mana(user_ptr, TRUE);
return TRUE;
case ACT_ESP:
case ACT_ULTIMATE_RESIST:
return activate_ultimate_resistance(user_ptr);
case ACT_CAST_OFF:
- (void)cosmic_cast_off(user_ptr, o_ptr);
+ (void)cosmic_cast_off(user_ptr, o_ptr_ptr);
return TRUE;
case ACT_FALLING_STAR:
return activate_toragoroshi(user_ptr);
msg_format(_("Unknown activation effect: %d.", "Unknown activation effect: %d."), act_ptr->index);
return FALSE;
}
-}
\ No newline at end of file
+}
#include "system/angband.h"
typedef struct activation_type activation_type;
-bool switch_activation(player_type *user_ptr, object_type *o_ptr, const activation_type *const act_ptr, concptr name);
+bool switch_activation(player_type *user_ptr, object_type **o_ptr_ptr, const activation_type *const act_ptr, concptr name);
break;
}
+
+ default:
+ break;
}
}
#include "sv-definition/sv-armor-types.h"
#include "sv-definition/sv-protector-types.h"
#include "util/bit-flags-calculator.h"
+#include "view/display-messages.h"
/*!
* @brief 防具系オブジェクトに生成ランクごとの強化を与えるサブルーチン
add_flag(o_ptr->art_flags, TR_NO_TELE);
break;
default:
- okay_flag = false;
+ msg_print(_("エラー:適した呪い鎧エゴがみつかりませんでした.", "Error:Suitable cursed armor ego not found."));
+ okay_flag = true;
break;
}
break;
}
+
+ default:
+ break;
}
}
break;
}
+
+ default:
+ break;
}
-}
\ No newline at end of file
+}
break;
}
+
+ default:
+ break;
}
}
#include "object-enchant/object-ego.h"
#include "object-enchant/trg-types.h"
#include "util/bit-flags-calculator.h"
+#include "util/probability-table.h"
#include <vector>
/*
*/
EGO_IDX max_e_idx;
-struct random_ego_weight
-{
- EGO_IDX idx;
- long weight;
-};
-
/*!
* @brief アイテムのエゴをレア度の重みに合わせてランダムに選択する
* Choose random ego type
*/
byte get_random_ego(byte slot, bool good)
{
- std::vector<random_ego_weight> list;
- long total = 0L;
+ ProbabilityTable<EGO_IDX> prob_table;
for (EGO_IDX i = 1; i < max_e_idx; i++) {
ego_item_type *e_ptr = &e_info[i];
if (e_ptr->slot != slot || e_ptr->rarity <= 0)
bool worthless = e_ptr->rating == 0 || e_ptr->gen_flags.has_any_of({ TRG::CURSED, TRG::HEAVY_CURSE, TRG::PERMA_CURSE });
if (good != worthless) {
- random_ego_weight ew = { i, (255 / e_ptr->rarity) };
- list.push_back(ew);
- total += ew.weight;
+ prob_table.entry_item(i, (255 / e_ptr->rarity));
}
}
- int value = randint1(total);
- for (random_ego_weight &ew : list) {
- value -= ew.weight;
- if (value <= 0L)
- return ew.idx;
+ if (!prob_table.empty()) {
+ return prob_table.pick_one_at_random();
}
return (EGO_IDX)0;
// clang-format off
enum class TRG {
- INSTA_ART = 1, /* Item must be an artifact */
- QUESTITEM = 2, /* quest level item -KMW- */
- XTRA_POWER = 3, /* Extra power */
- ONE_SUSTAIN = 4, /* One sustain */
- XTRA_RES_OR_POWER = 5, /* Extra resistance or power */
- XTRA_H_RES = 6, /* Extra high resistance */
- XTRA_E_RES = 7, /* Extra element resistance */
- XTRA_L_RES = 8, /* Extra lordly resistance */
- XTRA_D_RES = 9, /* Extra dragon resistance */
- XTRA_RES = 10, /* Extra resistance */
- CURSED = 11, /* Item is Cursed */
- HEAVY_CURSE = 12, /* Item is Heavily Cursed */
- PERMA_CURSE = 13, /* Item is Perma Cursed */
- RANDOM_CURSE0 = 14, /* Item is Random Cursed */
- RANDOM_CURSE1 = 15, /* Item is Random Cursed */
- RANDOM_CURSE2 = 16, /* Item is Random Cursed */
- XTRA_DICE = 17, /* Extra dice */
- POWERFUL = 18, /* Item has good value even if Cursed */
+ INSTA_ART = 0, /* Item must be an artifact */
+ QUESTITEM = 1, /* quest level item -KMW- */
+ XTRA_POWER = 2, /* Extra power */
+ ONE_SUSTAIN = 3, /* One sustain */
+ XTRA_RES_OR_POWER = 4, /* Extra resistance or power */
+ XTRA_H_RES = 5, /* Extra high resistance */
+ XTRA_E_RES = 6, /* Extra element resistance */
+ XTRA_L_RES = 7, /* Extra lordly resistance */
+ XTRA_D_RES = 8, /* Extra dragon resistance */
+ XTRA_RES = 9, /* Extra resistance */
+ CURSED = 10, /* Item is Cursed */
+ HEAVY_CURSE = 11, /* Item is Heavily Cursed */
+ PERMA_CURSE = 12, /* Item is Perma Cursed */
+ RANDOM_CURSE0 = 13, /* Item is Random Cursed */
+ RANDOM_CURSE1 = 14, /* Item is Random Cursed */
+ RANDOM_CURSE2 = 15, /* Item is Random Cursed */
+ XTRA_DICE = 16, /* Extra dice */
+ POWERFUL = 17, /* Item has good value even if Cursed */
MAX,
};
// clang-format on
case TV_BOLT: {
return TRUE;
}
+
+ default:
+ break;
}
return FALSE;
*/
bool item_tester_learn_spell(player_type *player_ptr, object_type *o_ptr)
{
+ if (player_ptr->pclass == CLASS_ELEMENTALIST)
+ return FALSE;
+
s32b choices = realm_choices2[player_ptr->pclass];
if (player_ptr->pclass == CLASS_PRIEST) {
if (is_good_realm(player_ptr->realm1)) {
if (vanilla_town)
return FALSE;
- if (player_ptr->today_mon > 0 && (streq(r_name + r_info[o_ptr->pval].name, r_name + r_info[today_mon].name)))
+ if (player_ptr->today_mon > 0 && (streq(r_name + r_info[o_ptr->pval].name, r_name + r_info[current_world_ptr->today_mon].name)))
return TRUE;
if (o_ptr->pval == MON_TSUCHINOKO)
if (o_ptr->sval != SV_POISON_NEEDLE)
return TRUE;
}
+
+ default:
+ break;
}
return FALSE;
{
return TRUE;
}
+
+ default:
+ break;
}
return FALSE;
{
return TRUE;
}
+
+ default:
+ break;
}
return FALSE;
{
return TRUE;
}
+
+ default:
+ break;
}
return FALSE;
{
return TRUE;
}
+
+ default:
+ break;
}
return FALSE;
case TV_BOOTS: {
return (INVEN_FEET);
}
+
+ default:
+ break;
}
return -1;
return 1000L;
else
return ((r_info[o_ptr->pval].level) * 50L + 1000);
+
+ default:
+ break;
}
return (0L);
if (has_flag(flgs, TR_SPEED))
value += (o_ptr->pval * 10000L);
break;
+
+ default:
+ break;
}
switch (o_ptr->tval) {
value = 0L;
break;
}
+
+ default:
+ break;
}
if (value < 0)
dam = 0;
check_wraith_form = FALSE;
break;
+
+ default:
+ break;
}
if (check_wraith_form && target_ptr->wraith_form) {
}
break;
+
+ default:
+ break;
}
}
feel = FEEL_TERRIBLE;
break;
}
+
+ default:
+ break;
}
}
case CLASS_MAGE:
case CLASS_HIGH_MAGE:
case CLASS_SORCERER:
- case CLASS_MAGIC_EATER: {
+ case CLASS_MAGIC_EATER:
+ case CLASS_ELEMENTALIST: {
if (0 != randint0(240000L / (plev + 5)))
return;
heavy = TRUE;
break;
}
+
+ case MAX_CLASS:
+ break;
}
if (compare_virtue(creature_ptr, V_KNOWLEDGE, 100, VIRTUE_LARGE))
okay = TRUE;
break;
}
+
+ default:
+ break;
}
if (!okay)
case CLASS_SORCERER:
case CLASS_MAGIC_EATER:
case CLASS_MIRROR_MASTER:
- case CLASS_BLUE_MAGE: {
+ case CLASS_BLUE_MAGE:
+ case CLASS_ELEMENTALIST: {
if (0 != randint0(9000L / (plev * plev + 40)))
return;
break;
}
+
+ case MAX_CLASS:
+ break;
}
for (INVENTORY_IDX i = 0; i < INVEN_TOTAL; i++) {
okay = TRUE;
break;
}
+
+ default:
+ break;
}
if (!okay)
creature_ptr->vir_types[i++] = V_FAITH;
creature_ptr->vir_types[i++] = V_UNLIFE;
break;
+ case CLASS_ELEMENTALIST:
+ creature_ptr->vir_types[i++] = V_NATURE;
+ break;
+ case MAX_CLASS:
+ break;
};
/* Get one virtue based on race */
case RACE_ELF:
case RACE_SPRITE:
case RACE_ENT:
+ case RACE_MERFOLK:
creature_ptr->vir_types[i++] = V_NATURE;
break;
case RACE_HOBBIT:
case RACE_BEASTMAN:
creature_ptr->vir_types[i++] = V_CHANCE;
break;
+ case MAX_RACES:
+ break;
}
/* Get a virtue for realms */
break;
case CLASS_MINDCRAFTER:
case CLASS_FORCETRAINER:
+ case CLASS_ELEMENTALIST:
if (creature_ptr->lev > 14)
self_ptr->info[self_ptr->line++]
= _("あなたは精神を集中してMPを回復させることができる。(消費なし)", "You can concentrate to regenerate your mana (cost 0).");
self_ptr->info[self_ptr->line++] = _("あなたは素早く移動することができる。(消費なし)", "You can walk extremely fast (cost 0).");
break;
+
+ case CLASS_ARCHER:
+ case CLASS_BARD:
+ case CLASS_SNIPER:
+ case MAX_CLASS:
+ break;
}
}
* @details
* * 各要素によるステータス修正値の合計
*/
-s16b PlayerBasicStatistics::ModificationValue()
+s16b PlayerBasicStatistics::modification_value()
{
- return PlayerStatusBase::getValue();
+ return PlayerStatusBase::get_value();
}
/*!
* @brief 基礎ステータスの実値
* @return status_typeに対応するステータスの実値を返す
*/
-s16b PlayerBasicStatistics::getValue()
+s16b PlayerBasicStatistics::get_value()
{
this->set_locals();
return this->owner_ptr->stat_index[(int)this->status_type];
* @details
* * owner_ptrのステータスを更新する
*/
-void PlayerBasicStatistics::updateValue()
+void PlayerBasicStatistics::update_value()
{
this->set_locals();
this->update_top_status();
using PlayerStatusBase::PlayerStatusBase;
PlayerBasicStatistics() = delete;
- void updateValue();
- s16b ModificationValue();
- s16b getValue() override;
+ void update_value();
+ s16b modification_value();
+ s16b get_value() override;
protected:
base_status_type status_type;
return result;
}
-BIT_FLAGS PlayerCharisma::getAllFlags()
+BIT_FLAGS PlayerCharisma::get_all_flags()
{
- BIT_FLAGS flags = PlayerStatusBase::getAllFlags();
+ BIT_FLAGS flags = PlayerStatusBase::get_all_flags();
if (any_bits(this->owner_ptr->muta3, MUT3_ILL_NORM)) {
set_bits(flags, FLAG_CAUSE_MUTATION);
return flags;
}
-BIT_FLAGS PlayerCharisma::getBadFlags()
+BIT_FLAGS PlayerCharisma::get_bad_flags()
{
- BIT_FLAGS flags = PlayerStatusBase::getBadFlags();
+ BIT_FLAGS flags = PlayerStatusBase::get_bad_flags();
if (any_bits(this->owner_ptr->muta3, MUT3_ILL_NORM)) {
set_bits(flags, FLAG_CAUSE_MUTATION);
using PlayerBasicStatistics::PlayerBasicStatistics;
PlayerCharisma() = delete;
- BIT_FLAGS getAllFlags() override;
- BIT_FLAGS getBadFlags() override;
+ BIT_FLAGS get_all_flags() override;
+ BIT_FLAGS get_bad_flags() override;
protected:
void set_locals() override;
value = this->default_value;
value += this->riding_value();
value += this->inventory_weight_value();
+ value += this->action_value();
}
return value;
}
* * 派生クラスからset_locals()をコールして初期値、上限、下限をセット。
* * 各要素毎に計算した値を初期値に単純に加算し、上限と下限で丸める。
*/
-s16b PlayerStatusBase::getValue()
+s16b PlayerStatusBase::get_value()
{
this->set_locals(); /* 計算前に値のセット。派生クラスの値がセットされる。*/
s16b pow = this->default_value;
* @brief 修正値が0でないところにビットを立てて返す。
* @return 判定結果のBIT_FLAGS
*/
-BIT_FLAGS PlayerStatusBase::getAllFlags()
+BIT_FLAGS PlayerStatusBase::get_all_flags()
{
this->set_locals(); /* 計算前に値のセット。派生クラスの値がセットされる。*/
BIT_FLAGS result = equipments_flags(this->tr_flag);
* @brief 修正値が1以上のところにビットを立てて返す。
* @return 判定結果のBIT_FLAGS
*/
-BIT_FLAGS PlayerStatusBase::getGoodFlags()
+BIT_FLAGS PlayerStatusBase::get_good_flags()
{
this->set_locals(); /* 計算前に値のセット。派生クラスの値がセットされる。*/
BIT_FLAGS result = equipments_flags(this->tr_flag);
* @brief 修正値が-1以下のところにビットを立てて返す。
* @return 判定結果のBIT_FLAGS
*/
-BIT_FLAGS PlayerStatusBase::getBadFlags()
+BIT_FLAGS PlayerStatusBase::get_bad_flags()
{
this->set_locals(); /* 計算前に値のセット。派生クラスの値がセットされる。*/
BIT_FLAGS result = equipments_bad_flags(this->tr_bad_flag);
PlayerStatusBase(player_type *owner_ptr);
PlayerStatusBase() = delete;
virtual ~PlayerStatusBase() = default;
- virtual s16b getValue();
- virtual BIT_FLAGS getAllFlags();
- virtual BIT_FLAGS getGoodFlags();
- virtual BIT_FLAGS getBadFlags();
+ virtual s16b get_value();
+ virtual BIT_FLAGS get_all_flags();
+ virtual BIT_FLAGS get_good_flags();
+ virtual BIT_FLAGS get_bad_flags();
protected:
s16b default_value;
* @details
* * TR_STELATHがマイナスの要素に加え、種族影フェアリーかつ反感のとき種族にマイナスフラグを与える
*/
-BIT_FLAGS PlayerStealth::getBadFlags()
+BIT_FLAGS PlayerStealth::get_bad_flags()
{
- BIT_FLAGS result = PlayerStatusBase::getBadFlags();
+ BIT_FLAGS result = PlayerStatusBase::get_bad_flags();
if (this->is_aggravated_s_fairy())
set_bits(result, FLAG_CAUSE_RACE);
using PlayerStatusBase::PlayerStatusBase;
PlayerStealth() = delete;
- BIT_FLAGS getBadFlags() override;
+ BIT_FLAGS get_bad_flags() override;
protected:
void set_locals() override;
if (saving_throw(10 + creature_ptr->lev))
return;
break;
+
+ default:
+ break;
}
} else {
if (mimic_info[creature_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_DEMON) {
creature_ptr->update |= PU_BONUS;
handle_stuff(creature_ptr);
-}
\ No newline at end of file
+}
#include "permanent-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 "player/player-personalities-types.h"
break;
}
+ case CLASS_ELEMENTALIST:
+ if (has_element_resist(creature_ptr, ElementRealm::FIRE, 1))
+ add_flag(flags, TR_RES_FIRE);
+ if (has_element_resist(creature_ptr, ElementRealm::ICE, 1))
+ add_flag(flags, TR_RES_COLD);
+ if (has_element_resist(creature_ptr, ElementRealm::SKY, 1))
+ add_flag(flags, TR_RES_ELEC);
+ if (has_element_resist(creature_ptr, ElementRealm::SEA, 1))
+ add_flag(flags, TR_RES_ACID);
+ if (has_element_resist(creature_ptr, ElementRealm::DARKNESS, 1))
+ add_flag(flags, TR_RES_DARK);
+ if (has_element_resist(creature_ptr, ElementRealm::DARKNESS, 30))
+ add_flag(flags, TR_RES_NETHER);
+ if (has_element_resist(creature_ptr, ElementRealm::CHAOS, 1))
+ add_flag(flags, TR_RES_CONF);
+ if (has_element_resist(creature_ptr, ElementRealm::CHAOS, 30))
+ add_flag(flags, TR_RES_CHAOS);
+ if (has_element_resist(creature_ptr, ElementRealm::EARTH, 1))
+ add_flag(flags, TR_RES_SHARDS);
+ if (has_element_resist(creature_ptr, ElementRealm::EARTH, 30))
+ add_flag(flags, TR_REFLECT);
+ if (has_element_resist(creature_ptr, ElementRealm::DEATH, 1))
+ add_flag(flags, TR_RES_POIS);
+ if (has_element_resist(creature_ptr, ElementRealm::DEATH, 30))
+ add_flag(flags, TR_RES_DISEN);
+ break;
default:
break;
}
2, 20, 40,
4, 70, 2
},
+
+ {
+#ifdef JP
+ "元素使い",
+#endif
+ "Elementalist",
+
+ {-3, 1, 3, 0, -1, 0},
+ 30, 40, 38, 3, 16, 20, 34, 20,
+ 7, 15, 11, 0, 0, 0, 6, 7,
+ 0, 30, 25,
+ 3, 100, 2
+ },
};
/*!
"伯爵",
"領主",
},
+
+ /* Elementalist */
+ {
+ "練習生",
+ "奇術師",
+ "幻術師",
+ "呪術師",
+ "召霊師",
+ "召魔師",
+ "魔術師",
+ "魔道師",
+ "イプシシマス",
+ "大魔道師",
+ },
};
#else
"Duke",
"Lord",
},
+
+ /* Elementalist */
+ {
+ "Apprentice",
+ "Trickster",
+ "Illusionist",
+ "Spellbinder",
+ "Evoker",
+ "Conjurer",
+ "Warlock",
+ "Sorcerer",
+ "Ipsissimus",
+ "Archmage",
+ },
};
-#endif
\ No newline at end of file
+#endif
CLASS_MIRROR_MASTER = 25,
CLASS_NINJA = 26,
CLASS_SNIPER = 27,
- MAX_CLASS = 28, /*!< 職業の最大定義数 Maximum number of player "class" types (see "table.c", etc) */
+ CLASS_ELEMENTALIST = 28,
+ MAX_CLASS = 29, /*!< 職業の最大定義数 Maximum number of player "class" types (see "table.c", etc) */
};
(CH_NONE), /* Mirror-master */
(CH_NONE), /* Ninja */
(CH_NONE), /* Sniper */
+ (CH_NONE), /* Elementalist */
};
/*!
(CH_NONE), /* Mirror-master */
(CH_NONE), /* Ninja */
(CH_NONE), /* Sniper */
+ (CH_NONE), /* Elementalist */
};
REALM_IDX get_realm1_book(player_type *player_ptr) { return player_ptr->realm1 + TV_LIFE_BOOK - 1; }
bool is_wizard_class(player_type *player_ptr)
{
return (player_ptr->pclass == CLASS_MAGE || player_ptr->pclass == CLASS_HIGH_MAGE || player_ptr->pclass == CLASS_SORCERER || player_ptr->pclass == CLASS_MAGIC_EATER
- || player_ptr->pclass == CLASS_BLUE_MAGE);
+ || player_ptr->pclass == CLASS_BLUE_MAGE || player_ptr->pclass == CLASS_ELEMENTALIST);
}
#include "artifact/fixed-art-types.h"
#include "grid/grid.h"
#include "inventory/inventory-slot-types.h"
+#include "mind/mind-elementalist.h"
#include "monster-race/monster-race.h"
#include "monster-race/race-flags2.h"
#include "monster-race/race-flags7.h"
{
switch (tr_flag) {
case TR_STR:
- return PlayerStrength(creature_ptr).getAllFlags();
+ return PlayerStrength(creature_ptr).get_all_flags();
case TR_INT:
- return PlayerIntelligence(creature_ptr).getAllFlags();
+ return PlayerIntelligence(creature_ptr).get_all_flags();
case TR_WIS:
- return PlayerWisdom(creature_ptr).getAllFlags();
+ return PlayerWisdom(creature_ptr).get_all_flags();
case TR_DEX:
- return PlayerDextarity(creature_ptr).getAllFlags();
+ return PlayerDextarity(creature_ptr).get_all_flags();
case TR_CON:
- return PlayerConstitution(creature_ptr).getAllFlags();
+ return PlayerConstitution(creature_ptr).get_all_flags();
case TR_CHR:
- return PlayerCharisma(creature_ptr).getAllFlags();
+ return PlayerCharisma(creature_ptr).get_all_flags();
case TR_MAGIC_MASTERY:
return has_magic_mastery(creature_ptr);
case TR_FORCE_WEAPON:
return check_equipment_flags(creature_ptr, tr_flag);
case TR_STEALTH:
- return PlayerStealth(creature_ptr).getAllFlags();
+ return PlayerStealth(creature_ptr).get_all_flags();
case TR_SEARCH:
return 0;
case TR_INFRA:
case TR_TUNNEL:
return 0;
case TR_SPEED:
- return PlayerSpeed(creature_ptr).getAllFlags();
+ return PlayerSpeed(creature_ptr).get_all_flags();
case TR_BLOWS:
return 0;
case TR_CHAOTIC:
case TR_DARK_SOURCE:
case TR_SUPPORTIVE:
return check_equipment_flags(creature_ptr, tr_flag);
+
+ case TR_FLAG_MAX:
+ break;
}
return 0;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::EARTH, 30))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_REFLECT);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::SEA, 1))
+ result |= FLAG_CAUSE_CLASS;
+
result |= has_immune_acid(creature_ptr);
result |= check_equipment_flags(creature_ptr, TR_RES_ACID);
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::SKY, 1))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_ELEC);
result |= has_immune_elec(creature_ptr);
return result;
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::FIRE, 1))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_FIRE);
result |= has_immune_fire(creature_ptr);
return result;
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::ICE, 1))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_COLD);
result |= has_immune_cold(creature_ptr);
return result;
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::DEATH, 1))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_POIS);
return result;
}
result |= FLAG_CAUSE_BATTLE_FORM;
}
+ if (has_element_resist(creature_ptr, ElementRealm::CHAOS, 1))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_CONF);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::DARKNESS, 1))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_DARK);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::CHAOS, 30))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_CHAOS);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::DEATH, 30))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_DISEN);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::EARTH, 1))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_SHARDS);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::DARKNESS, 30))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_RES_NETHER);
return result;
}
case CLASS_NINJA:
result |= FLAG_CAUSE_CLASS;
break;
+
+ default:
+ break;
}
if (creature_ptr->mimic_form == MIMIC_DEMON_LORD) {
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::SEA, 30))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_IM_ACID);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::SKY, 30))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_IM_ELEC);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::FIRE, 30))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_IM_FIRE);
return result;
}
result |= FLAG_CAUSE_MAGIC_TIME_EFFECT;
}
+ if (has_element_resist(creature_ptr, ElementRealm::ICE, 30))
+ result |= FLAG_CAUSE_CLASS;
+
result |= check_equipment_flags(creature_ptr, TR_IM_COLD);
return result;
}
case RACE_SPECTRE:
return 0;
break;
+
+ default:
+ break;
}
return 100;
}
}
- creature_ptr->stat_add[A_STR] = PlayerStrength(creature_ptr).ModificationValue();
- creature_ptr->stat_add[A_INT] = PlayerIntelligence(creature_ptr).ModificationValue();
- creature_ptr->stat_add[A_WIS] = PlayerWisdom(creature_ptr).ModificationValue();
- creature_ptr->stat_add[A_DEX] = PlayerDextarity(creature_ptr).ModificationValue();
- creature_ptr->stat_add[A_CON] = PlayerConstitution(creature_ptr).ModificationValue();
- creature_ptr->stat_add[A_CHR] = PlayerCharisma(creature_ptr).ModificationValue();
-
- PlayerStrength(creature_ptr).updateValue();
- PlayerIntelligence(creature_ptr).updateValue();
- PlayerWisdom(creature_ptr).updateValue();
- PlayerDextarity(creature_ptr).updateValue();
- PlayerConstitution(creature_ptr).updateValue();
- PlayerCharisma(creature_ptr).updateValue();
+ creature_ptr->stat_add[A_STR] = PlayerStrength(creature_ptr).modification_value();
+ creature_ptr->stat_add[A_INT] = PlayerIntelligence(creature_ptr).modification_value();
+ creature_ptr->stat_add[A_WIS] = PlayerWisdom(creature_ptr).modification_value();
+ creature_ptr->stat_add[A_DEX] = PlayerDextarity(creature_ptr).modification_value();
+ creature_ptr->stat_add[A_CON] = PlayerConstitution(creature_ptr).modification_value();
+ creature_ptr->stat_add[A_CHR] = PlayerCharisma(creature_ptr).modification_value();
+
+ PlayerStrength(creature_ptr).update_value();
+ PlayerIntelligence(creature_ptr).update_value();
+ PlayerWisdom(creature_ptr).update_value();
+ PlayerDextarity(creature_ptr).update_value();
+ PlayerConstitution(creature_ptr).update_value();
+ PlayerCharisma(creature_ptr).update_value();
o_ptr = &creature_ptr->inventory_list[INVEN_BOW];
if (o_ptr->k_idx) {
creature_ptr->to_ds[i] = calc_to_weapon_dice_side(creature_ptr, INVEN_MAIN_HAND + i);
}
- creature_ptr->pspeed = PlayerSpeed(creature_ptr).getValue();
+ creature_ptr->pspeed = PlayerSpeed(creature_ptr).get_value();
creature_ptr->see_infra = calc_intra_vision(creature_ptr);
- creature_ptr->skill_stl = PlayerStealth(creature_ptr).getValue();
+ creature_ptr->skill_stl = PlayerStealth(creature_ptr).get_value();
creature_ptr->skill_dis = calc_disarming(creature_ptr);
creature_ptr->skill_dev = calc_device_ability(creature_ptr);
creature_ptr->skill_sav = calc_saving_throw(creature_ptr);
case RACE_BALROG:
creature_ptr->align -= 200;
break;
+
+ default:
+ break;
}
}
return;
int levels;
- if ((creature_ptr->pclass == CLASS_MINDCRAFTER) || (creature_ptr->pclass == CLASS_MIRROR_MASTER) || (creature_ptr->pclass == CLASS_BLUE_MAGE)) {
+ if ((creature_ptr->pclass == CLASS_MINDCRAFTER) || (creature_ptr->pclass == CLASS_MIRROR_MASTER) || (creature_ptr->pclass == CLASS_BLUE_MAGE)
+ || creature_ptr->pclass == CLASS_ELEMENTALIST) {
levels = creature_ptr->lev;
} else {
if (mp_ptr->spell_first > creature_ptr->lev) {
case CLASS_BLUE_MAGE:
case CLASS_MONK:
case CLASS_FORCETRAINER:
- case CLASS_SORCERER: {
+ case CLASS_SORCERER:
+ case CLASS_ELEMENTALIST: {
if (creature_ptr->inventory_list[INVEN_MAIN_HAND].tval <= TV_SWORD)
cur_wgt += creature_ptr->inventory_list[INVEN_MAIN_HAND].weight;
if (creature_ptr->inventory_list[INVEN_SUB_HAND].tval <= TV_SWORD)
switch (creature_ptr->pclass) {
case CLASS_MAGE:
case CLASS_HIGH_MAGE:
- case CLASS_BLUE_MAGE: {
+ case CLASS_BLUE_MAGE:
+ case CLASS_ELEMENTALIST: {
msp -= msp * (cur_wgt - max_wgt) / 600;
break;
}
penalty = penalty / 2 - 5;
}
- for (int i = FLAG_CAUSE_INVEN_MAIN_HAND; i < FLAG_CAUSE_MAX; i <<= 1)
+ for (unsigned int i = FLAG_CAUSE_INVEN_MAIN_HAND; i < FLAG_CAUSE_MAX; i <<= 1)
if (penalty > 0 && any_bits(creature_ptr->easy_2weapon, i))
penalty /= 2;
if ((empty_hands(creature_ptr, FALSE) != EMPTY_HAND_NONE) && !has_melee_weapon(creature_ptr, INVEN_MAIN_HAND)
&& !has_melee_weapon(creature_ptr, INVEN_SUB_HAND))
return TRUE;
+
+ default:
+ break;
}
}
/* fall through */
case MELEE_TYPE_BAREHAND_TWO:
hit += (creature_ptr->skill_exp[GINOU_SUDE] - WEAPON_EXP_BEGINNER) / 200;
+ break;
+
+ default:
+ break;
}
if ((is_martial_arts_mode(creature_ptr) && empty_hands(creature_ptr, FALSE) == (EMPTY_HAND_MAIN | EMPTY_HAND_SUB))
s16b pet_follow_distance; /* Length of the imaginary "leash" for pets */
s16b pet_extra_flags; /* Various flags for controling pets */
- s16b today_mon; /* Wanted monster */
+ MONSTER_IDX today_mon; //!< 日替わり賞金首を知っていればそのモンスターID、知らなければ 0
bool dtrap; /* Whether you are on trap-safe grids */
FLOOR_IDX floor_id; /* Current floor location */
-#include "player/player-view.h"
+#include <vector>
+
#include "core/player-update-types.h"
#include "floor/cave.h"
#include "floor/line-of-sight.h"
#include "game-option/map-screen-options.h"
#include "grid/grid.h"
+#include "player/player-view.h"
#include "system/floor-type-definition.h"
/*
*/
void update_view(player_type *subject_ptr)
{
+ struct Point {
+ int y;
+ int x;
+ Point(const int y, const int x)
+ : y(y)
+ , x(x)
+ {
+ }
+ };
+
+ // 前回プレイヤーから見えていた座標たちを格納する配列。
+ std::vector<Point> points;
+
int n, m, d, k, z;
POSITION y, x;
g_ptr = &floor_ptr->grid_array[y][x];
g_ptr->info &= ~(CAVE_VIEW);
g_ptr->info |= CAVE_TEMP;
- tmp_pos.y[tmp_pos.n] = y;
- tmp_pos.x[tmp_pos.n] = x;
- tmp_pos.n++;
+
+ points.emplace_back(y, x);
}
floor_ptr->view_n = 0;
cave_note_and_redraw_later(floor_ptr, g_ptr, y, x);
}
- for (n = 0; n < tmp_pos.n; n++) {
- y = tmp_pos.y[n];
- x = tmp_pos.x[n];
+ for (const auto &[y, x] : points) {
g_ptr = &floor_ptr->grid_array[y][x];
g_ptr->info &= ~(CAVE_TEMP);
if (g_ptr->info & CAVE_VIEW)
cave_redraw_later(floor_ptr, g_ptr, y, x);
}
- tmp_pos.n = 0;
subject_ptr->update |= PU_DELAY_VIS;
}
72, 6, 180, 25,
66, 4, 150, 20,
0,
- 0xFFFFFFF,
+ 0x1FFFFFFF,
},
{
#ifdef JP
66, 6, 130, 15,
62, 6, 100, 10,
2,
- 0xE77E7FF,
+ 0x1E77E7FF,
},
{
#ifdef JP
60, 4, 100, 6,
54, 4, 80, 6,
3,
- 0xE77E75B,
+ 0x1E77E75B,
},
{
36, 3, 60, 3,
33, 3, 50, 3,
4,
- 0xF6FFC0B,
+ 0x1F6FFC0B,
},
{
#ifdef JP
42, 3, 90, 6,
39, 3, 75, 3,
4,
- 0xF67D60F,
+ 0x1F67D60F,
},
{
#ifdef JP
48, 3, 150, 10,
46, 3, 120, 10,
5,
- 0x1890005,
+ 0x01890005,
},
{
#ifdef JP
66, 1, 150, 5,
62, 1, 120, 5,
3,
- 0xDD8818D,
+ 0x0DD8818D,
},
{
#ifdef JP
96, 10, 250, 50,
84, 8, 225, 40,
3,
- 0x0880005,
+ 0x00880005,
},
{
#ifdef JP
82, 5, 190, 20,
78, 6, 180, 15,
0,
- 0xFFFF7FF,
+ 0x1FFFF7FF,
},
{
#ifdef JP
90, 10, 190, 20,
82, 10, 180, 15,
4,
- 0xF77E75B,
+ 0x1F77E75B,
},
{
#ifdef JP
82, 5, 200, 20,
78, 6, 190, 15,
0,
- 0x5C0A09D,
+ 0x05C0A09D,
},
{
#ifdef JP
92, 10, 255, 60,
80, 8, 235, 60,
3,
- 0x0A80407,
+ 0x00A80407,
},
{
#ifdef JP
100,10, 255, 65,
80, 10, 240, 64,
3,
- 0x8880011,
+ 0x08880011,
},
{
#ifdef JP
111, 11, 255, 86,
99, 11, 250, 86,
0,
- 0x23D4727,
+ 0x123D4727,
},
{
#ifdef JP
92, 10, 255, 60,
80, 8, 235, 60,
1,
- 0x0888005,
+ 0x00888005,
},
{
#ifdef JP
50, 3, 90, 6,
50, 3, 75, 3,
2,
- 0x667360F,
+ 0x1667360F,
},
{
#ifdef JP
60, 3, 80, 4,
54, 3, 70, 4,
2,
- 0x04D8011,
+ 0x004D8011,
},
{
#ifdef JP
60, 1, 130, 5,
55, 1, 100, 5,
3,
- 0x444A009,
+ 0x0444A009,
},
{
#ifdef JP
43, 3, 92, 6,
40, 3, 78, 3,
5,
- 0x569040F,
+ 0x0569040F,
},
{
#ifdef JP
60, 4, 100, 6,
54, 4, 80, 6,
5,
- 0xE77C7DF,
+ 0x1E77C7DF,
},
{
#ifdef JP
76, 1, 160, 5,
72, 1, 130, 5,
2,
- 0x7FFE757,
+ 0x07FFE757,
},
{
#ifdef JP
68, 6, 142, 15,
63, 6, 112, 10,
4,
- 0x2334746,
+ 0x12334746,
},
{
#ifdef JP
68, 1, 150, 5,
64, 1, 120, 5,
3,
- 0xDB537CB,
+ 0x1DB537CB,
},
{
#ifdef JP
66, 1, 200, 6,
62, 1, 180, 6,
4,
- 0x0800001,
+ 0x00800001,
},
{
#ifdef JP
72, 6, 50, 5,
66, 4, 50, 5,
2,
- 0x234070F,
+ 0x1234070F,
},
{
#ifdef JP
72, 6, 100, 25,
66, 4, 100, 20,
2,
- 0x0800001,
+ 0x00800001,
},
{
#ifdef JP
72, 6, 180, 25,
66, 4, 150, 20,
5,
- 0x67DC7FF,
+ 0x167DC7FF,
},
{
#ifdef JP
72, 6, 100, 25,
66, 4, 100, 20,
5,
- 0x631474A,
+ 0x1631474A,
},
{
#ifdef JP
32, 2, 75, 2,
29, 2, 65, 2,
4,
- 0x623F65E,
+ 0x1623F65E,
},
{
#ifdef JP
65, 6, 150, 20,
61, 6, 120, 15,
0,
- 0x57887CF,
+ 0x057887CF,
},
{
#ifdef JP
111, 11, 255, 50,
99, 11, 250, 45,
0,
- 0x0010005,
+ 0x00010005,
},
{
#ifdef JP
82, 5, 190, 20,
78, 6, 180, 15,
3,
- 0x779F777,
+ 0x0779F777,
},
{
#ifdef JP
100,10, 255, 65,
80, 10, 240, 64,
5,
- 0x7EDC4DB,
+ 0x17EDC4DB,
},
{
#ifdef JP
82, 5, 190, 20,
78, 6, 180, 15,
0,
- 0xFFFF7FF,
+ 0x1FFFF7FF,
},
{
#ifdef JP
80, 8, 90, 20,
73, 8, 80, 15,
4,
- 0xE33C7DF,
+ 0x1E33C7DF,
},
{
#ifdef JP
48, 6, 150, 25,
44, 4, 130, 20,
0,
- 0xC18B7AD,
+ 0x0C18B7AD,
},
{
#ifdef JP
72, 12, 240, 64,
66, 12, 220, 64,
0,
- 0x0800001,
+ 0x00800001,
},
{
#ifdef JP
66, 6, 130, 15,
62, 6, 100, 10,
2,
- 0xE77E7FF,
+ 0x1E77E7FF,
},
};
#include "object-enchant/tr-types.h"
#include "player/player-race.h"
#include "player/special-defense-types.h"
+#include "mind/mind-elementalist.h"
#include "util/bit-flags-calculator.h"
/*!
- * @brief プレイヤーの種族による免疫フラグを返す
+ * @brief プレイヤーの職業/種族による免疫フラグを返す
* @param creature_ptr プレーヤーへの参照ポインタ
* @param flags フラグを保管する配列
* @return なし
*/
void player_immunity(player_type *creature_ptr, BIT_FLAGS *flags)
{
- for (int i = 0; i < TR_FLAG_SIZE; i++)
- flags[i] = 0L;
+ for (int i = 0; i < TR_FLAG_SIZE; i++)
+ flags[i] = 0L;
- if (is_specific_player_race(creature_ptr, RACE_SPECTRE))
- add_flag(flags, TR_RES_NETHER);
- if (creature_ptr->mimic_form == MIMIC_VAMPIRE || is_specific_player_race(creature_ptr, RACE_VAMPIRE))
- add_flag(flags, TR_RES_DARK);
- if (creature_ptr->mimic_form == MIMIC_DEMON_LORD)
- add_flag(flags, TR_RES_FIRE);
- else if (is_specific_player_race(creature_ptr, RACE_YEEK) && creature_ptr->lev > 19)
- add_flag(flags, TR_RES_ACID);
+ if (is_specific_player_race(creature_ptr, RACE_SPECTRE))
+ add_flag(flags, TR_RES_NETHER);
+ if (creature_ptr->mimic_form == MIMIC_VAMPIRE || is_specific_player_race(creature_ptr, RACE_VAMPIRE))
+ add_flag(flags, TR_RES_DARK);
+ if (creature_ptr->mimic_form == MIMIC_DEMON_LORD)
+ add_flag(flags, TR_RES_FIRE);
+ else if (is_specific_player_race(creature_ptr, RACE_YEEK) && creature_ptr->lev > 19)
+ add_flag(flags, TR_RES_ACID);
+
+ if (creature_ptr->pclass == CLASS_ELEMENTALIST) {
+ if (has_element_resist(creature_ptr, ElementRealm::FIRE, 30))
+ add_flag(flags, TR_RES_FIRE);
+ if (has_element_resist(creature_ptr, ElementRealm::SKY, 30))
+ add_flag(flags, TR_RES_ELEC);
+ if (has_element_resist(creature_ptr, ElementRealm::SEA, 30))
+ add_flag(flags, TR_RES_ACID);
+ if (has_element_resist(creature_ptr, ElementRealm::ICE, 30))
+ add_flag(flags, TR_RES_COLD);
+ }
}
#include "racial/class-racial-switcher.h"
+#include "mind/mind-elementalist.h"
#include "racial/racial-util.h"
#include "realm/realm-names-table.h"
#include "realm/realm-types.h"
rc_ptr->power_desc[rc_ptr->num].fail = 0;
rc_ptr->power_desc[rc_ptr->num++].number = -3;
break;
+ case CLASS_ELEMENTALIST:
+ strcpy(rc_ptr->power_desc[rc_ptr->num].racial_name, _("明鏡止水", "Clear Mind"));
+ rc_ptr->power_desc[rc_ptr->num].min_level = 15;
+ rc_ptr->power_desc[rc_ptr->num].cost = 0;
+ rc_ptr->power_desc[rc_ptr->num].stat = A_WIS;
+ rc_ptr->power_desc[rc_ptr->num].fail = 10;
+ rc_ptr->power_desc[rc_ptr->num++].number = -3;
+
+ switch_element_racial(creature_ptr, rc_ptr);
+ break;
default:
strcpy(rc_ptr->power_desc[0].racial_name, _("(なし)", "(none)"));
break;
#include "racial/racial-draconian.h"
+#include "mind/mind-elementalist.h"
#include "spell-kind/spells-launcher.h"
#include "spell/spell-types.h"
#include "target/target-getter.h"
}
break;
+ case CLASS_ELEMENTALIST:
+ *breath_type = get_element_type(creature_ptr->realm1, 0);
+ *breath_type_description = get_element_name(creature_ptr->realm1, 0);
+ break;
+ default:
+ break;
}
}
#include "melee/melee-postprocess.h"
#include "mind/mind-archer.h"
#include "mind/mind-cavalry.h"
+#include "mind/mind-elementalist.h"
#include "mind/mind-force-trainer.h"
#include "mind/mind-hobbit.h"
#include "mind/mind-mage.h"
return TRUE;
case CLASS_NINJA:
return hayagake(creature_ptr);
+ case CLASS_ELEMENTALIST:
+ if (command == -3)
+ return clear_mind(creature_ptr);
+ if (command == -4)
+ return switch_element_execution(creature_ptr);
+ return TRUE;
default:
return TRUE;
}
case TV_DIGGING: {
return TRUE;
}
+
+ default:
+ break;
}
return FALSE;
* @author Hourier
*/
-#include "room/cave-filler.h"
+#include <queue>
+
#include "dungeon/dungeon-flag-types.h"
#include "dungeon/dungeon.h"
#include "floor/cave.h"
#include "grid/feature.h"
#include "grid/grid.h"
+#include "room/cave-filler.h"
#include "room/lake-types.h"
#include "system/floor-type-definition.h"
* Quick and nasty fill routine used to find the connected region
* of floor in the middle of the grids
*/
-static void cave_fill(player_type *player_ptr, POSITION y, POSITION x)
+static void cave_fill(player_type *player_ptr, const POSITION y, const POSITION x)
{
- int flow_tail_room = 1;
- int flow_head_room = 0;
- tmp_pos.y[0] = y;
- tmp_pos.x[0] = x;
+ struct Point {
+ int y;
+ int x;
+ Point(const int y, const int x)
+ : y(y)
+ , x(x)
+ {
+ }
+ };
+
floor_type *floor_ptr = player_ptr->current_floor_ptr;
- while (flow_head_room != flow_tail_room) {
- POSITION ty = tmp_pos.y[flow_head_room];
- POSITION tx = tmp_pos.x[flow_head_room];
- if (++flow_head_room == TEMP_MAX)
- flow_head_room = 0;
+
+ // 幅優先探索用のキュー。
+ std::queue<Point> que;
+ que.emplace(y, x);
+
+ while (!que.empty()) {
+ const auto [y_cur, x_cur] = que.front();
+ que.pop();
for (int d = 0; d < 8; d++) {
- int old_head = flow_tail_room;
- int j = ty + ddy_ddd[d];
- int i = tx + ddx_ddd[d];
- if (!in_bounds(floor_ptr, j, i)) {
- floor_ptr->grid_array[j][i].info |= CAVE_ICKY;
+ int y_to = y_cur + ddy_ddd[d];
+ int x_to = x_cur + ddx_ddd[d];
+ if (!in_bounds(floor_ptr, y_to, x_to)) {
+ floor_ptr->grid_array[y_to][x_to].info |= CAVE_ICKY;
continue;
}
- if ((i <= fill_data.xmin) || (i >= fill_data.xmax) || (j <= fill_data.ymin) || (j >= fill_data.ymax)) {
- floor_ptr->grid_array[j][i].info |= CAVE_ICKY;
+ if ((x_to <= fill_data.xmin) || (x_to >= fill_data.xmax) || (y_to <= fill_data.ymin) || (y_to >= fill_data.ymax)) {
+ floor_ptr->grid_array[y_to][x_to].info |= CAVE_ICKY;
continue;
}
- if (!hack_isnt_wall(player_ptr, j, i, fill_data.c1, fill_data.c2, fill_data.c3, fill_data.feat1, fill_data.feat2, fill_data.feat3, fill_data.info1,
- fill_data.info2, fill_data.info3))
+ if (!hack_isnt_wall(player_ptr, y_to, x_to, fill_data.c1, fill_data.c2, fill_data.c3, fill_data.feat1, fill_data.feat2, fill_data.feat3,
+ fill_data.info1, fill_data.info2, fill_data.info3))
continue;
- tmp_pos.y[flow_tail_room] = (byte)j;
- tmp_pos.x[flow_tail_room] = (byte)i;
- if (++flow_tail_room == TEMP_MAX)
- flow_tail_room = 0;
-
- if (flow_tail_room == flow_head_room) {
- flow_tail_room = old_head;
- continue;
- }
+ que.emplace(y_to, x_to);
(fill_data.amount)++;
}
+++ /dev/null
-#include "room/pit-nest-kinds-table.h"
-#include "monster-race/monster-race-hook.h"
-
-/*!nest情報テーブル*/
-vault_aux_type nest_types[MAX_PIT_NEST_KINDS] =
-{
- { _("クローン", "clone"), vault_aux_clone, vault_prep_clone, 5, 3 },
- { _("ゼリー", "jelly"), vault_aux_jelly, NULL, 5, 6 },
- { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 25, 2 },
- { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 25, 2 },
- { _("ミミック", "mimic"), vault_aux_mimic, NULL, 30, 4 },
- { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 70, 2 },
- { _("犬小屋", "kennel"), vault_aux_kennel, NULL, 45, 4 },
- { _("動物園", "animal"), vault_aux_animal, NULL, 35, 5 },
- { _("教会", "chapel"), vault_aux_chapel_g, NULL, 75, 4 },
- { _("アンデッド", "undead"), vault_aux_undead, NULL, 75, 5 },
- { NULL, NULL, NULL, 0, 0 },
-};
-
-/*!pit情報テーブル*/
-vault_aux_type pit_types[MAX_PIT_NEST_KINDS] =
-{
- { _("オーク", "orc"), vault_aux_orc, NULL, 5, 6 },
- { _("トロル", "troll"), vault_aux_troll, NULL, 20, 6 },
- { _("巨人", "giant"), vault_aux_giant, NULL, 50, 6 },
- { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 80, 2 },
- { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 70, 1 },
- { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 70, 1 },
- { _("教会", "chapel"), vault_aux_chapel_g, NULL, 65, 2 },
- { _("ドラゴン", "dragon"), vault_aux_dragon, vault_prep_dragon, 70, 6 },
- { _("デーモン", "demon"), vault_aux_demon, NULL, 80, 6 },
- { _("ダークエルフ", "dark elf"), vault_aux_dark_elf, NULL, 45, 4 },
- { NULL, NULL, NULL, 0, 0 },
-};
-
-const int placing[MAX_MONSTER_PLACE][3] = {
- { -2, -9, 0 },{ -2, -8, 0 },{ -3, -7, 0 },{ -3, -6, 0 },
- { +2, -9, 0 },{ +2, -8, 0 },{ +3, -7, 0 },{ +3, -6, 0 },
- { -2, +9, 0 },{ -2, +8, 0 },{ -3, +7, 0 },{ -3, +6, 0 },
- { +2, +9, 0 },{ +2, +8, 0 },{ +3, +7, 0 },{ +3, +6, 0 },
- { -2, -7, 1 },{ -3, -5, 1 },{ -3, -4, 1 },
- { +2, -7, 1 },{ +3, -5, 1 },{ +3, -4, 1 },
- { -2, +7, 1 },{ -3, +5, 1 },{ -3, +4, 1 },
- { +2, +7, 1 },{ +3, +5, 1 },{ +3, +4, 1 },
- { -2, -6, 2 },{ -2, -5, 2 },{ -3, -3, 2 },
- { +2, -6, 2 },{ +2, -5, 2 },{ +3, -3, 2 },
- { -2, +6, 2 },{ -2, +5, 2 },{ -3, +3, 2 },
- { +2, +6, 2 },{ +2, +5, 2 },{ +3, +3, 2 },
- { -2, -4, 3 },{ -3, -2, 3 },
- { +2, -4, 3 },{ +3, -2, 3 },
- { -2, +4, 3 },{ -3, +2, 3 },
- { +2, +4, 3 },{ +3, +2, 3 },
- { -2, -3, 4 },{ -3, -1, 4 },
- { +2, -3, 4 },{ +3, -1, 4 },
- { -2, +3, 4 },{ -3, +1, 4 },
- { +2, +3, 4 },{ +3, +1, 4 },
- { -2, -2, 5 },{ -3, 0, 5 },{ -2, +2, 5 },
- { +2, -2, 5 },{ +3, 0, 5 },{ +2, +2, 5 },
- { -2, -1, 6 },{ -2, +1, 6 },
- { +2, -1, 6 },{ +2, +1, 6 },
- { -2, 0, 7 },{ +2, 0, 7 },
- { 0, 0, -1 }
-};
+++ /dev/null
-#pragma once
-
-#include "system/angband.h"
-
-#define NUM_NEST_MON_TYPE 64 /*!<nestの種別数 */
-
-/*! nestのID定義 / Nest types code */
-#define NEST_TYPE_CLONE 0
-#define NEST_TYPE_JELLY 1
-#define NEST_TYPE_SYMBOL_GOOD 2
-#define NEST_TYPE_SYMBOL_EVIL 3
-#define NEST_TYPE_MIMIC 4
-#define NEST_TYPE_LOVECRAFTIAN 5
-#define NEST_TYPE_KENNEL 6
-#define NEST_TYPE_ANIMAL 7
-#define NEST_TYPE_CHAPEL 8
-#define NEST_TYPE_UNDEAD 9
-
-/*! pitのID定義 / Pit types code */
-#define PIT_TYPE_ORC 0
-#define PIT_TYPE_TROLL 1
-#define PIT_TYPE_GIANT 2
-#define PIT_TYPE_LOVECRAFTIAN 3
-#define PIT_TYPE_SYMBOL_GOOD 4
-#define PIT_TYPE_SYMBOL_EVIL 5
-#define PIT_TYPE_CHAPEL 6
-#define PIT_TYPE_DRAGON 7
-#define PIT_TYPE_DEMON 8
-#define PIT_TYPE_DARK_ELF 9
-
-#define MAX_PIT_NEST_KINDS 11
-#define MAX_MONSTER_PLACE 69
-
-/*! pit/nest型情報の構造体定義 */
-typedef struct vault_aux_type
-{
- concptr name;
- bool (*hook_func)(player_type *player_ptr, MONRACE_IDX r_idx);
- void (*prep_func)(player_type *player_ptr);
- DEPTH level;
- int chance;
-} vault_aux_type;
-
-extern vault_aux_type nest_types[MAX_PIT_NEST_KINDS];
-extern vault_aux_type pit_types[MAX_PIT_NEST_KINDS];
-
-extern const int placing[MAX_MONSTER_PLACE][3];
#include "room/rooms-vault.h"
#include "system/dungeon-data-definition.h"
#include "system/floor-type-definition.h"
+#include "util/probability-table.h"
#include "wizard/wizard-messages.h"
/*!
if (!(d_info[floor_ptr->dungeon_idx].flags1 & DF1_ARCADE))
prob_list[ROOM_T_ARCADE] = 0;
- int total_prob = 0;
+ ProbabilityTable<int> prob_table;
for (int i = 0; i < ROOM_T_MAX; i++) {
room_num[i] = 0;
- total_prob += prob_list[i];
+ prob_table.entry_item(i, prob_list[i]);
}
for (int i = dun_rooms; i > 0; i--) {
int room_type;
- int rand = randint0(total_prob);
- for (room_type = 0; room_type < ROOM_T_MAX; room_type++) {
- if (rand < prob_list[room_type])
- break;
- else
- rand -= prob_list[room_type];
- }
-
- if (room_type >= ROOM_T_MAX)
+ if (prob_table.empty())
room_type = ROOM_T_NORMAL;
+ else
+ room_type = prob_table.pick_one_at_random();
room_num[room_type]++;
switch (room_type) {
#include "monster/monster-info.h"
#include "monster/monster-list.h"
#include "monster/monster-util.h"
-#include "room/pit-nest-kinds-table.h"
#include "room/space-finder.h"
#include "system/floor-type-definition.h"
+#include "util/probability-table.h"
#include "util/sort.h"
#include "view/display-messages.h"
#include "wizard/wizard-messages.h"
+#include <vector>
/*!
* @brief ダンジョン毎に指定されたピット配列を基準にランダムなpit/nestタイプを決める
* @param allow_flag_mask 生成が許されるpit/nestのビット配列
* @return 選択されたpit/nestのID、選択失敗した場合-1を返す。
*/
-static int pick_vault_type(floor_type *floor_ptr, vault_aux_type *l_ptr, BIT_FLAGS16 allow_flag_mask)
+static int pick_vault_type(floor_type *floor_ptr, std::vector<nest_pit_type>& l_ptr, BIT_FLAGS16 allow_flag_mask)
{
- int total;
- int count;
- vault_aux_type *n_ptr;
- for (n_ptr = l_ptr, total = 0, count = 0; TRUE; n_ptr++, count++) {
- if (!n_ptr->name)
- break;
+ ProbabilityTable<int> table;
+ for (size_t i = 0; i < l_ptr.size(); i++) {
+ nest_pit_type *n_ptr = &l_ptr.at(i);
if (n_ptr->level > floor_ptr->dun_level)
continue;
- if (!(allow_flag_mask & (1UL << count)))
+ if (!(allow_flag_mask & (1UL << i)))
continue;
- total += n_ptr->chance * MAX_DEPTH / (MIN(floor_ptr->dun_level, MAX_DEPTH - 1) - n_ptr->level + 5);
- }
-
- int random_type = randint0(total);
- for (n_ptr = l_ptr, total = 0, count = 0; TRUE; n_ptr++, count++) {
- if (!n_ptr->name)
- break;
-
- if (n_ptr->level > floor_ptr->dun_level)
- continue;
-
- if (!(allow_flag_mask & (1UL << count)))
- continue;
-
- total += n_ptr->chance * MAX_DEPTH / (MIN(floor_ptr->dun_level, MAX_DEPTH - 1) - n_ptr->level + 5);
- if (random_type < total)
- break;
+ table.entry_item(i, n_ptr->chance * MAX_DEPTH / (MIN(floor_ptr->dun_level, MAX_DEPTH - 1) - n_ptr->level + 5));
}
- return n_ptr->name ? count : -1;
+ return !table.empty() ? table.pick_one_at_random() : -1;
}
/*!
}
/*!
+ * @brief 生成するNestの情報テーブル
+ */
+std::vector<nest_pit_type> nest_types = {
+ { _("クローン", "clone"), vault_aux_clone, vault_prep_clone, 5, 3 },
+ { _("ゼリー", "jelly"), vault_aux_jelly, NULL, 5, 6 },
+ { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 25, 2 },
+ { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 25, 2 },
+ { _("ミミック", "mimic"), vault_aux_mimic, NULL, 30, 4 },
+ { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 70, 2 },
+ { _("犬小屋", "kennel"), vault_aux_kennel, NULL, 45, 4 },
+ { _("動物園", "animal"), vault_aux_animal, NULL, 35, 5 },
+ { _("教会", "chapel"), vault_aux_chapel_g, NULL, 75, 4 },
+ { _("アンデッド", "undead"), vault_aux_undead, NULL, 75, 5 },
+};
+
+/*!
* @brief タイプ5の部屋…nestを生成する / Type 5 -- Monster nests
* @param player_ptr プレーヤーへの参照ポインタ
* @return なし
floor_type *floor_ptr = player_ptr->current_floor_ptr;
int cur_nest_type = pick_vault_type(floor_ptr, nest_types, d_info[floor_ptr->dungeon_idx].nest);
- vault_aux_type *n_ptr;
+ nest_pit_type *n_ptr;
/* No type available */
if (cur_nest_type < 0)
}
/*!
+ * @brief 生成するPitの情報テーブル
+ */
+std::vector<nest_pit_type> pit_types = {
+ { _("オーク", "orc"), vault_aux_orc, NULL, 5, 6 },
+ { _("トロル", "troll"), vault_aux_troll, NULL, 20, 6 },
+ { _("巨人", "giant"), vault_aux_giant, NULL, 50, 6 },
+ { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 80, 2 },
+ { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 70, 1 },
+ { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 70, 1 },
+ { _("教会", "chapel"), vault_aux_chapel_g, NULL, 65, 2 },
+ { _("ドラゴン", "dragon"), vault_aux_dragon, vault_prep_dragon, 70, 6 },
+ { _("デーモン", "demon"), vault_aux_demon, NULL, 80, 6 },
+ { _("ダークエルフ", "dark elf"), vault_aux_dark_elf, NULL, 45, 4 },
+};
+
+/*!
* @brief タイプ6の部屋…pitを生成する / Type 6 -- Monster pits
* @return なし
* @details
floor_type *floor_ptr = player_ptr->current_floor_ptr;
int cur_pit_type = pick_vault_type(floor_ptr, pit_types, d_info[floor_ptr->dungeon_idx].pit);
- vault_aux_type *n_ptr;
+ nest_pit_type *n_ptr;
/* No type available */
if (cur_pit_type < 0)
return TRUE;
}
-/*
- * Helper function for "trapped monster pit"
+// clang-format off
+/*!
+ * @brief 開門トラップのモンスター配置テーブル
+ * @detail
+ * 中央からの相対座標(X,Y)、モンスターの強さ
+ */
+const int place_table_trapped_pit[TRAPPED_PIT_MONSTER_PLACE_MAX][3] = {
+ { -2, -9, 0 }, { -2, -8, 0 }, { -3, -7, 0 }, { -3, -6, 0 }, { +2, -9, 0 }, { +2, -8, 0 }, { +3, -7, 0 }, { +3, -6, 0 },
+ { -2, +9, 0 }, { -2, +8, 0 }, { -3, +7, 0 }, { -3, +6, 0 }, { +2, +9, 0 }, { +2, +8, 0 }, { +3, +7, 0 }, { +3, +6, 0 },
+ { -2, -7, 1 }, { -3, -5, 1 }, { -3, -4, 1 }, { -2, +7, 1 }, { -3, +5, 1 }, { -3, +4, 1 },
+ { +2, -7, 1 }, { +3, -5, 1 }, { +3, -4, 1 }, { +2, +7, 1 }, { +3, +5, 1 }, { +3, +4, 1 },
+ { -2, -6, 2 }, { -2, -5, 2 }, { -3, -3, 2 }, { -2, +6, 2 }, { -2, +5, 2 }, { -3, +3, 2 },
+ { +2, -6, 2 }, { +2, -5, 2 }, { +3, -3, 2 }, { +2, +6, 2 }, { +2, +5, 2 }, { +3, +3, 2 },
+ { -2, -4, 3 }, { -3, -2, 3 }, { -2, +4, 3 }, { -3, +2, 3 },
+ { +2, -4, 3 }, { +3, -2, 3 }, { +2, +4, 3 }, { +3, +2, 3 },
+ { -2, -3, 4 }, { -3, -1, 4 }, { +2, -3, 4 }, { +3, -1, 4 },
+ { -2, +3, 4 }, { -3, +1, 4 }, { +2, +3, 4 }, { +3, +1, 4 },
+ { -2, -2, 5 }, { -3, 0, 5 }, { -2, +2, 5 }, { +2, -2, 5 }, { +3, 0, 5 }, { +2, +2, 5 },
+ { -2, -1, 6 }, { -2, +1, 6 }, { +2, -1, 6 }, { +2, +1, 6 },
+ { -2, 0, 7 }, { +2, 0, 7 },
+ { 0, 0, -1 } };
+// clang-format on
+
+/*!
+ * @brief 開門トラップに配置するモンスターの条件フィルタ
+ * @detai;
+ * 穴を掘るモンスター、壁を抜けるモンスターは却下
*/
static bool vault_aux_trapped_pit(player_type *player_ptr, MONRACE_IDX r_idx)
{
}
/*!
- * @brief タイプ13の部屋…トラップpitの生成 / Type 13 -- Trapped monster pits
+ * @brief タイプ13の部屋…開門トラップpitの生成 / Type 13 -- Trapped monster pits
* @return なし
* @details
* A trapped monster pit is a "big" room with a straight corridor in\n
floor_type *floor_ptr = player_ptr->current_floor_ptr;
int cur_pit_type = pick_vault_type(floor_ptr, pit_types, d_info[floor_ptr->dungeon_idx].pit);
- vault_aux_type *n_ptr;
+ nest_pit_type *n_ptr;
/* Only in Angband */
if (floor_ptr->dungeon_idx != DUNGEON_ANGBAND)
}
}
- for (i = 0; placing[i][2] >= 0; i++) {
- y = yval + placing[i][0];
- x = xval + placing[i][1];
- place_monster_aux(player_ptr, 0, y, x, what[placing[i][2]], PM_NO_KAGE);
+ 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);
}
return TRUE;
#include "system/angband.h"
+#define NUM_NEST_MON_TYPE 64 /*!<nestの種別数 */
+#define TRAPPED_PIT_MONSTER_PLACE_MAX 69
+
+/*! nestのID定義 / Nest types code */
+enum nest_type : int {
+ NEST_TYPE_CLONE = 0,
+ NEST_TYPE_JELLY = 1,
+ NEST_TYPE_SYMBOL_GOOD = 2,
+ NEST_TYPE_SYMBOL_EVIL = 3,
+ NEST_TYPE_MIMIC = 4,
+ NEST_TYPE_LOVECRAFTIAN = 5,
+ NEST_TYPE_KENNEL = 6,
+ NEST_TYPE_ANIMAL = 7,
+ NEST_TYPE_CHAPEL = 8,
+ NEST_TYPE_UNDEAD = 9,
+};
+
+/*! pitのID定義 / Pit types code */
+enum pit_type : int {
+ PIT_TYPE_ORC = 0,
+ PIT_TYPE_TROLL = 1,
+ PIT_TYPE_GIANT = 2,
+ PIT_TYPE_LOVECRAFTIAN = 3,
+ PIT_TYPE_SYMBOL_GOOD = 4,
+ PIT_TYPE_SYMBOL_EVIL = 5,
+ PIT_TYPE_CHAPEL = 6,
+ PIT_TYPE_DRAGON = 7,
+ PIT_TYPE_DEMON = 8,
+ PIT_TYPE_DARK_ELF = 9,
+};
+
+/*! pit/nest型情報の構造体定義 */
+struct nest_pit_type {
+ concptr name; //<! 部屋名
+ bool (*hook_func)(player_type *player_ptr, MONRACE_IDX r_idx); //<! モンスターフィルタ関数
+ void (*prep_func)(player_type *player_ptr); //<! 能力フィルタ関数
+ DEPTH level; //<! 相当階
+ int chance; //!< 生成確率
+};
+
/*! デバッグ時にnestのモンスター情報を確認するための構造体 / A struct for nest monster information with cheat_hear */
-typedef struct nest_mon_info_type {
- MONRACE_IDX r_idx;
- bool used;
-} nest_mon_info_type;
+struct nest_mon_info_type {
+ MONRACE_IDX r_idx; //!< モンスター種族ID
+ bool used; //!< 既に選んだかどうか
+};
typedef struct dun_data_type dun_data_type;
bool build_type5(player_type *player_ptr, dun_data_type *dd_ptr);
wr_s32b(current_world_ptr->game_turn);
wr_s32b(current_world_ptr->dungeon_turn);
wr_s32b(current_world_ptr->arena_start_turn);
- wr_s16b(today_mon);
+ wr_s16b(current_world_ptr->today_mon);
wr_s16b(creature_ptr->today_mon);
wr_s16b(creature_ptr->riding);
wr_s16b(creature_ptr->floor_id);
-#include "specific-object/torch.h"
+#include <vector>
+
#include "core/player-update-types.h"
#include "dungeon/dungeon-flag-types.h"
#include "dungeon/dungeon.h"
#include "object-enchant/tr-types.h"
#include "object/object-flags.h"
#include "player/special-defense-types.h"
-#include "system/floor-type-definition.h"
+#include "specific-object/torch.h"
#include "sv-definition/sv-lite-types.h"
+#include "system/floor-type-definition.h"
#include "util/bit-flags-calculator.h"
/*!
}
}
-
POSITION rad = 0;
if (has_flag(flgs, TR_LITE_1) && !has_flag(flgs, TR_DARK_SOURCE))
rad += 1;
*/
void update_lite(player_type *subject_ptr)
{
+ struct Point {
+ int y;
+ int x;
+ Point(const int y, const int x)
+ : y(y)
+ , x(x)
+ {
+ }
+ };
+
+ // 前回照らされていた座標たちを格納する配列。
+ std::vector<Point> points;
+
POSITION p = subject_ptr->cur_lite;
- grid_type *g_ptr;
- floor_type *floor_ptr = subject_ptr->current_floor_ptr;
+ floor_type *const floor_ptr = subject_ptr->current_floor_ptr;
+
+ // 前回照らされていた座標たちを記録。
for (int i = 0; i < floor_ptr->lite_n; i++) {
- POSITION y = floor_ptr->lite_y[i];
- POSITION x = floor_ptr->lite_x[i];
+ const POSITION y = floor_ptr->lite_y[i];
+ const POSITION x = floor_ptr->lite_x[i];
+
floor_ptr->grid_array[y][x].info &= ~(CAVE_LITE);
floor_ptr->grid_array[y][x].info |= CAVE_TEMP;
- tmp_pos.y[tmp_pos.n] = y;
- tmp_pos.x[tmp_pos.n] = x;
- tmp_pos.n++;
+
+ points.emplace_back(y, x);
}
floor_ptr->lite_n = 0;
for (int i = 0; i < floor_ptr->lite_n; i++) {
POSITION y = floor_ptr->lite_y[i];
POSITION x = floor_ptr->lite_x[i];
- g_ptr = &floor_ptr->grid_array[y][x];
+ grid_type *g_ptr = &floor_ptr->grid_array[y][x];
if (g_ptr->info & CAVE_TEMP)
continue;
cave_note_and_redraw_later(floor_ptr, g_ptr, y, x);
}
- for (int i = 0; i < tmp_pos.n; i++) {
- POSITION y = tmp_pos.y[i];
- POSITION x = tmp_pos.x[i];
- g_ptr = &floor_ptr->grid_array[y][x];
+ // 前回照らされていた座標たちのうち、状態が変わったものについて再描画フラグを立てる。
+ for (const auto &[y, x] : points) {
+ grid_type *g_ptr = &floor_ptr->grid_array[y][x];
g_ptr->info &= ~(CAVE_TEMP);
if (g_ptr->info & CAVE_LITE)
continue;
cave_redraw_later(floor_ptr, g_ptr, y, x);
}
- tmp_pos.n = 0;
subject_ptr->update |= PU_DELAY_VIS;
}
ty = target_row;
}
- return project(caster_ptr, 0, rad, ty, tx, dam, typ, flg, -1);
+ return project(caster_ptr, 0, rad, ty, tx, dam, typ, flg, -1).notice;
}
/*!
* Affect grids, objects, and monsters
* </pre>
*/
-bool fire_breath(player_type *caster_ptr, EFFECT_ID typ, DIRECTION dir, HIT_POINT dam, POSITION rad) { return fire_ball(caster_ptr, typ, dir, dam, -rad); }
+bool fire_breath(player_type *caster_ptr, EFFECT_ID typ, DIRECTION dir, HIT_POINT dam, POSITION rad)
+{
+ return fire_ball(caster_ptr, typ, dir, dam, -rad);
+}
/*!
* @brief ロケット系スペルの発動(詳細な差は確認中) / Cast a ball spell
}
BIT_FLAGS flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
- return (project(caster_ptr, 0, rad, ty, tx, dam, typ, flg, -1));
+ return project(caster_ptr, 0, rad, ty, tx, dam, typ, flg, -1).notice;
}
/*!
ty = target_row;
}
- return (project(caster_ptr, 0, rad, ty, tx, dam, typ, flg, -1));
+ return project(caster_ptr, 0, rad, ty, tx, dam, typ, flg, -1).notice;
}
/*!
bool fire_meteor(player_type *caster_ptr, MONSTER_IDX who, EFFECT_ID typ, POSITION y, POSITION x, HIT_POINT dam, POSITION rad)
{
BIT_FLAGS flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
- return (project(caster_ptr, who, rad, y, x, dam, typ, flg, -1));
+ return project(caster_ptr, who, rad, y, x, dam, typ, flg, -1).notice;
}
/*!
}
/* Analyze the "dir" and the "target". */
- if (!project(caster_ptr, 0, 0, y, x, damroll(dd, ds), typ, flg, -1)) {
+ const auto proj_res = project(caster_ptr, 0, 0, y, x, damroll(dd, ds), typ, flg, -1);
+ if (!proj_res.notice)
result = FALSE;
- }
}
return result;
ty = target_row;
}
- return (project(caster_ptr, 0, 0, ty, tx, dam, typ, flg, -1));
+ return project(caster_ptr, 0, 0, ty, tx, dam, typ, flg, -1).notice;
}
-#include "spell-kind/spells-lite.h"
+#include <vector>
+
#include "dungeon/dungeon-flag-types.h"
#include "dungeon/dungeon.h"
#include "effect/effect-characteristics.h"
#include "monster/monster-update.h"
#include "player/special-defense-types.h"
#include "spell-kind/spells-launcher.h"
+#include "spell-kind/spells-lite.h"
#include "spell/spell-types.h"
#include "system/floor-type-definition.h"
#include "target/projection-path-calculator.h"
#include "view/display-messages.h"
#include "world/world.h"
+struct Point {
+ int y;
+ int x;
+ Point(const int y, const int x)
+ : y(y)
+ , x(x)
+ {
+ }
+};
+
+using PassBoldFunc = bool (*)(floor_type *, POSITION, POSITION);
+
/*!
* todo この辺、xとyが引数になっているが、caster_ptr->xとcaster_ptr->yで全て置き換えが効くはず……
- * @brief 部屋全体を照らすサブルーチン
+ * @brief 指定した座標全てを照らす。
* @param caster_ptr プレーヤーへの参照ポインタ
- * @return なし
+ * @param points 明るくすべき座標たち
* @details
* <pre>
* This routine clears the entire "temp" set.
* STUPID monsters wake up 1/10 the time when illuminated
* </pre>
*/
-static void cave_temp_room_lite(player_type *caster_ptr)
+static void cave_temp_room_lite(player_type *caster_ptr, const std::vector<Point> &points)
{
- for (int i = 0; i < tmp_pos.n; i++) {
- POSITION y = tmp_pos.y[i];
- POSITION x = tmp_pos.x[i];
+ for (const auto &point : points) {
+ const POSITION y = point.y;
+ const POSITION x = point.x;
+
grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
g_ptr->info &= ~(CAVE_TEMP);
g_ptr->info |= (CAVE_GLOW);
lite_spot(caster_ptr, y, x);
update_local_illumination(caster_ptr, y, x);
}
-
- tmp_pos.n = 0;
}
/*!
* todo この辺、xとyが引数になっているが、caster_ptr->xとcaster_ptr->yで全て置き換えが効くはず……
- * @brief 部屋全体を暗くするサブルーチン
+ * @brief 指定した座標全てを暗くする。
* @param caster_ptr プレーヤーへの参照ポインタ
- * @return なし
+ * @param points 暗くすべき座標たち
* @details
* <pre>
* This routine clears the entire "temp" set.
* Also, process all affected monsters
* </pre>
*/
-static void cave_temp_room_unlite(player_type *caster_ptr)
+static void cave_temp_room_unlite(player_type *caster_ptr, const std::vector<Point> &points)
{
- for (int i = 0; i < tmp_pos.n; i++) {
- POSITION y = tmp_pos.y[i];
- POSITION x = tmp_pos.x[i];
+ for (const auto &point : points) {
+ const POSITION y = point.y;
+ const POSITION x = point.x;
+
grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
bool do_dark = !is_mirror_grid(g_ptr);
g_ptr->info &= ~(CAVE_TEMP);
lite_spot(caster_ptr, y, x);
update_local_illumination(caster_ptr, y, x);
}
-
- tmp_pos.n = 0;
}
/*!
* @param pass_bold 地形条件を返す関数ポインタ
* @return 該当地形の数
*/
-static int next_to_open(floor_type *floor_ptr, POSITION cy, POSITION cx, bool (*pass_bold)(floor_type *, POSITION, POSITION))
+static int next_to_open(floor_type *floor_ptr, const POSITION cy, const POSITION cx, const PassBoldFunc pass_bold)
{
int len = 0;
int blen = 0;
* @param pass_bold 地形条件を返す関数ポインタ
* @return 該当地形の数
*/
-static int next_to_walls_adj(floor_type *floor_ptr, POSITION cy, POSITION cx, bool (*pass_bold)(floor_type *, POSITION, POSITION))
+static int next_to_walls_adj(floor_type *floor_ptr, const POSITION cy, const POSITION cx, const PassBoldFunc pass_bold)
{
POSITION y, x;
int c = 0;
}
/*!
- * @brief 部屋内にある一点の周囲に該当する地形数かいくつあるかをグローバル変数tmp_pos.nに返す / Aux function -- see below
+ * @brief (y,x) が指定条件を満たすなら points に加える
* @param caster_ptr プレーヤーへの参照ポインタ
+ * @param points 座標記録用配列
* @param y 部屋内のy座標1点
* @param x 部屋内のx座標1点
* @param only_room 部屋内地形のみをチェック対象にするならば TRUE
* @param pass_bold 地形条件を返す関数ポインタ
- * @return 該当地形の数
*/
-static void cave_temp_room_aux(player_type *caster_ptr, POSITION y, POSITION x, bool only_room, bool (*pass_bold)(floor_type *, POSITION, POSITION))
+static void cave_temp_room_aux(
+ player_type *caster_ptr, std::vector<Point> &points, const POSITION y, const POSITION x, const bool only_room, const PassBoldFunc pass_bold)
{
- grid_type *g_ptr;
floor_type *floor_ptr = caster_ptr->current_floor_ptr;
- g_ptr = &floor_ptr->grid_array[y][x];
+ grid_type *g_ptr = &floor_ptr->grid_array[y][x];
+
+ // 既に points に追加済みなら何もしない。
if (g_ptr->info & (CAVE_TEMP))
return;
return;
}
- if (tmp_pos.n == TEMP_MAX)
- return;
-
+ // (y,x) を points に追加し、追加済みフラグを立てる。
+ points.emplace_back(y, x);
g_ptr->info |= (CAVE_TEMP);
- tmp_pos.y[tmp_pos.n] = y;
- tmp_pos.x[tmp_pos.n] = x;
- tmp_pos.n++;
}
/*!
- * @brief 部屋内にある一点の周囲がいくつ光を通すかをグローバル変数tmp_pos.nに返す / Aux function -- see below
+ * @brief (y,x) が明るくすべきマスなら points に加える
* @param caster_ptr プレーヤーへの参照ポインタ
+ * @param points 座標記録用配列
* @param y 指定Y座標
* @param x 指定X座標
- * @return なし
*/
-static void cave_temp_lite_room_aux(player_type *caster_ptr, POSITION y, POSITION x) { cave_temp_room_aux(caster_ptr, y, x, FALSE, cave_los_bold); }
+static void cave_temp_lite_room_aux(player_type *caster_ptr, std::vector<Point> &points, const POSITION y, const POSITION x)
+{
+ cave_temp_room_aux(caster_ptr, points, y, x, FALSE, cave_los_bold);
+}
/*!
* @brief 指定のマスが光を通さず射線のみを通すかを返す。 / Aux function -- see below
static bool cave_pass_dark_bold(floor_type *floor_ptr, POSITION y, POSITION x) { return cave_has_flag_bold(floor_ptr, y, x, FF_PROJECT); }
/*!
- * @brief 部屋内にある一点の周囲がいくつ射線を通すかをグローバル変数tmp_pos.nに返す / Aux function -- see below
+ * @brief (y,x) が暗くすべきマスなら points に加える
* @param caster_ptr プレーヤーへの参照ポインタ
* @param y 指定Y座標
* @param x 指定X座標
- * @return なし
*/
-static void cave_temp_unlite_room_aux(player_type *caster_ptr, POSITION y, POSITION x) { cave_temp_room_aux(caster_ptr, y, x, TRUE, cave_pass_dark_bold); }
+static void cave_temp_unlite_room_aux(player_type *caster_ptr, std::vector<Point> &points, const POSITION y, const POSITION x)
+{
+ cave_temp_room_aux(caster_ptr, points, y, x, TRUE, cave_pass_dark_bold);
+}
/*!
- * @brief 指定された部屋内を照らす / Illuminate any room containing the given location.
+ * @brief (y1,x1) を含む全ての部屋を照らす。 / Illuminate any room containing the given location.
* @param caster_ptr プレーヤーへの参照ポインタ
* @param y1 指定Y座標
* @param x1 指定X座標
- * @return なし
+ *
+ * NOTE: 部屋に限らないかも?
*/
-void lite_room(player_type *caster_ptr, POSITION y1, POSITION x1)
+void lite_room(player_type *caster_ptr, const POSITION y1, const POSITION x1)
{
- cave_temp_lite_room_aux(caster_ptr, y1, x1);
+ // 明るくするマスを記録する配列。
+ std::vector<Point> points;
+
floor_type *floor_ptr = caster_ptr->current_floor_ptr;
- for (int i = 0; i < tmp_pos.n; i++) {
- POSITION x = tmp_pos.x[i];
- POSITION y = tmp_pos.y[i];
+
+ // (y1,x1) を起点として明るくするマスを記録していく。
+ // 実質幅優先探索。
+ cave_temp_lite_room_aux(caster_ptr, points, y1, x1);
+ for (size_t i = 0; i < size(points); i++) {
+ const auto &point = points[i];
+ const POSITION y = point.y;
+ const POSITION x = point.x;
if (!cave_los_bold(floor_ptr, y, x))
continue;
- cave_temp_lite_room_aux(caster_ptr, y + 1, x);
- cave_temp_lite_room_aux(caster_ptr, y - 1, x);
- cave_temp_lite_room_aux(caster_ptr, y, x + 1);
- cave_temp_lite_room_aux(caster_ptr, y, x - 1);
+ cave_temp_lite_room_aux(caster_ptr, points, y + 1, x);
+ cave_temp_lite_room_aux(caster_ptr, points, y - 1, x);
+ cave_temp_lite_room_aux(caster_ptr, points, y, x + 1);
+ cave_temp_lite_room_aux(caster_ptr, points, y, x - 1);
- cave_temp_lite_room_aux(caster_ptr, y + 1, x + 1);
- cave_temp_lite_room_aux(caster_ptr, y - 1, x - 1);
- cave_temp_lite_room_aux(caster_ptr, y - 1, x + 1);
- cave_temp_lite_room_aux(caster_ptr, y + 1, x - 1);
+ cave_temp_lite_room_aux(caster_ptr, points, y + 1, x + 1);
+ cave_temp_lite_room_aux(caster_ptr, points, y - 1, x - 1);
+ cave_temp_lite_room_aux(caster_ptr, points, y - 1, x + 1);
+ cave_temp_lite_room_aux(caster_ptr, points, y + 1, x - 1);
}
- cave_temp_room_lite(caster_ptr);
+ // 記録したマスを実際に明るくする。
+ cave_temp_room_lite(caster_ptr, points);
+
+ // 超隠密状態の更新。
if (caster_ptr->special_defense & NINJA_S_STEALTH) {
if (floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info & CAVE_GLOW)
set_superstealth(caster_ptr, FALSE);
}
/*!
- * @brief 指定された部屋内を暗くする / Darken all rooms containing the given location
+ * @brief (y1,x1) を含む全ての部屋を暗くする。 / Darken all rooms containing the given location
* @param caster_ptr プレーヤーへの参照ポインタ
* @param y1 指定Y座標
* @param x1 指定X座標
- * @return なし
*/
-void unlite_room(player_type *caster_ptr, POSITION y1, POSITION x1)
+void unlite_room(player_type *caster_ptr, const POSITION y1, const POSITION x1)
{
- cave_temp_unlite_room_aux(caster_ptr, y1, x1);
- for (int i = 0; i < tmp_pos.n; i++) {
- POSITION x = tmp_pos.x[i];
- POSITION y = tmp_pos.y[i];
- if (!cave_pass_dark_bold(caster_ptr->current_floor_ptr, y, x))
+ // 暗くするマスを記録する配列。
+ std::vector<Point> points;
+
+ floor_type *floor_ptr = caster_ptr->current_floor_ptr;
+
+ // (y1,x1) を起点として暗くするマスを記録していく。
+ // 実質幅優先探索。
+ cave_temp_unlite_room_aux(caster_ptr, points, y1, x1);
+ for (size_t i = 0; i < size(points); i++) {
+ const auto &point = points[i];
+ const POSITION y = point.y;
+ const POSITION x = point.x;
+
+ if (!cave_pass_dark_bold(floor_ptr, y, x))
continue;
- cave_temp_unlite_room_aux(caster_ptr, y + 1, x);
- cave_temp_unlite_room_aux(caster_ptr, y - 1, x);
- cave_temp_unlite_room_aux(caster_ptr, y, x + 1);
- cave_temp_unlite_room_aux(caster_ptr, y, x - 1);
+ cave_temp_unlite_room_aux(caster_ptr, points, y + 1, x);
+ cave_temp_unlite_room_aux(caster_ptr, points, y - 1, x);
+ cave_temp_unlite_room_aux(caster_ptr, points, y, x + 1);
+ cave_temp_unlite_room_aux(caster_ptr, points, y, x - 1);
- cave_temp_unlite_room_aux(caster_ptr, y + 1, x + 1);
- cave_temp_unlite_room_aux(caster_ptr, y - 1, x - 1);
- cave_temp_unlite_room_aux(caster_ptr, y - 1, x + 1);
- cave_temp_unlite_room_aux(caster_ptr, y + 1, x - 1);
+ cave_temp_unlite_room_aux(caster_ptr, points, y + 1, x + 1);
+ cave_temp_unlite_room_aux(caster_ptr, points, y - 1, x - 1);
+ cave_temp_unlite_room_aux(caster_ptr, points, y - 1, x + 1);
+ cave_temp_unlite_room_aux(caster_ptr, points, y + 1, x - 1);
}
- cave_temp_room_unlite(caster_ptr);
+ // 記録したマスを実際に暗くする。
+ cave_temp_room_unlite(caster_ptr, points);
}
/*!
bool door_creation(player_type *caster_ptr, POSITION y, POSITION x)
{
BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
- return (project(caster_ptr, 0, 1, y, x, 0, GF_MAKE_DOOR, flg, -1));
+ return project(caster_ptr, 0, 1, y, x, 0, GF_MAKE_DOOR, flg, -1).notice;
}
/*!
bool trap_creation(player_type *caster_ptr, POSITION y, POSITION x)
{
BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
- return (project(caster_ptr, 0, 1, y, x, 0, GF_MAKE_TRAP, flg, -1));
+ return project(caster_ptr, 0, 1, y, x, 0, GF_MAKE_TRAP, flg, -1).notice;
}
/*!
bool tree_creation(player_type *caster_ptr, POSITION y, POSITION x)
{
BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
- return (project(caster_ptr, 0, 1, y, x, 0, GF_MAKE_TREE, flg, -1));
+ return project(caster_ptr, 0, 1, y, x, 0, GF_MAKE_TREE, flg, -1).notice;
}
/*!
bool create_rune_protection_area(player_type *caster_ptr, POSITION y, POSITION x)
{
BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM;
- return (project(caster_ptr, 0, 1, y, x, 0, GF_MAKE_RUNE_PROTECTION, flg, -1));
+ return project(caster_ptr, 0, 1, y, x, 0, GF_MAKE_RUNE_PROTECTION, flg, -1).notice;
}
/*!
bool wall_stone(player_type *caster_ptr)
{
BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
- bool dummy = (project(caster_ptr, 0, 1, caster_ptr->y, caster_ptr->x, 0, GF_STONE_WALL, flg, -1));
+ bool dummy = project(caster_ptr, 0, 1, caster_ptr->y, caster_ptr->x, 0, GF_STONE_WALL, flg, -1).notice;
caster_ptr->update |= (PU_FLOW);
caster_ptr->redraw |= (PR_MAP);
return dummy;
bool destroy_doors_touch(player_type *caster_ptr)
{
BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
- return (project(caster_ptr, 0, 1, caster_ptr->y, caster_ptr->x, 0, GF_KILL_DOOR, flg, -1));
+ return project(caster_ptr, 0, 1, caster_ptr->y, caster_ptr->x, 0, GF_KILL_DOOR, flg, -1).notice;
}
/*!
bool disarm_traps_touch(player_type *caster_ptr)
{
BIT_FLAGS flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE;
- return (project(caster_ptr, 0, 1, caster_ptr->y, caster_ptr->x, 0, GF_KILL_TRAP, flg, -1));
+ return project(caster_ptr, 0, 1, caster_ptr->y, caster_ptr->x, 0, GF_KILL_TRAP, flg, -1).notice;
}
/*!
bool sleep_monsters_touch(player_type *caster_ptr)
{
BIT_FLAGS flg = PROJECT_KILL | PROJECT_HIDE;
- return (project(caster_ptr, 0, 1, caster_ptr->y, caster_ptr->x, caster_ptr->lev, GF_OLD_SLEEP, flg, -1));
+ return project(caster_ptr, 0, 1, caster_ptr->y, caster_ptr->x, caster_ptr->lev, GF_OLD_SLEEP, flg, -1).notice;
}
/*!
bool animate_dead(player_type *caster_ptr, MONSTER_IDX who, POSITION y, POSITION x)
{
BIT_FLAGS flg = PROJECT_ITEM | PROJECT_HIDE;
- return (project(caster_ptr, who, 5, y, x, 0, GF_ANIM_DEAD, flg, -1));
+ return project(caster_ptr, who, 5, y, x, 0, GF_ANIM_DEAD, flg, -1).notice;
}
/*!
* @brief 周辺破壊効果(プレイヤー中心)
* @param caster_ptr プレーヤーへの参照ポインタ
- * @return 作用が実際にあった場合TRUEを返す
*/
void wall_breaker(player_type *caster_ptr)
{
POSITION y = m_ptr->fy;
POSITION x = m_ptr->fx;
- if (project(caster_ptr, 0, 0, y, x, dam, typ, flg, -1))
+ if (project(caster_ptr, 0, 0, y, x, dam, typ, flg, -1).notice)
obvious = TRUE;
}
GF_CRUSADE = 114, /*!< 魔法効果: 聖戦*/
GF_STASIS_EVIL = 115, /*!< 魔法効果: 邪悪拘束*/
GF_WOUNDS = 116, /*!< 魔法効果: 創傷*/
- MAX_GF = 117, /*!< 欠番を無視した最大サイズ (直上の値+1) */
+ GF_E_GENOCIDE = 117, /*!< 魔法効果: 元素抹殺 */
+ MAX_GF = 118, /*!< 欠番を無視した最大サイズ (直上の値+1) */
};
is_special_class &= creature_ptr->pclass != CLASS_SORCERER;
is_special_class &= creature_ptr->pclass != CLASS_MAGIC_EATER;
is_special_class &= creature_ptr->pclass != CLASS_BLUE_MAGE;
+ is_special_class &= creature_ptr->pclass != CLASS_ELEMENTALIST;
if (is_special_class)
(void)take_hit(creature_ptr, DAMAGE_NOESCAPE, 50, _("コントロールし難い強力な魔力の解放", "unleashing magics too mighty to control"), -1);
return TRUE;
}
-bool cosmic_cast_off(player_type *creature_ptr, object_type *o_ptr)
+/*!
+ * @brief 装備を脱ぎ捨てて小宇宙を燃やす
+ * @param creature_ptr プレイヤー情報への参照ポインタ
+ * @param o_ptr_ptr 脱ぐ装備品への参照ポインタのポインタ
+ * @return 脱いだらTRUE、脱がなかったらFALSE
+ * @detail
+ * 脱いで落とした装備にtimeoutを設定するために装備品のアドレスを返す。
+ */
+bool cosmic_cast_off(player_type *creature_ptr, object_type **o_ptr_ptr)
{
+ object_type *o_ptr = (*o_ptr_ptr);
+
/* Cast off activated item */
- INVENTORY_IDX inv;
- for (inv = INVEN_MAIN_HAND; inv <= INVEN_FEET; inv++) {
- if (o_ptr == &creature_ptr->inventory_list[inv])
+ INVENTORY_IDX slot;
+ for (slot = INVEN_MAIN_HAND; slot <= INVEN_FEET; slot++) {
+ if (o_ptr == &creature_ptr->inventory_list[slot])
break;
}
- if (inv > INVEN_FEET)
+ if (slot > INVEN_FEET)
return FALSE;
object_type forge;
object_copy(&forge, o_ptr);
- inven_item_increase(creature_ptr, inv, (0 - o_ptr->number));
- inven_item_optimize(creature_ptr, inv);
- OBJECT_IDX o_idx = drop_near(creature_ptr, &forge, 0, creature_ptr->y, creature_ptr->x);
- o_ptr = &creature_ptr->current_floor_ptr->o_list[o_idx];
+ inven_item_increase(creature_ptr, slot, (0 - o_ptr->number));
+ inven_item_optimize(creature_ptr, slot);
+
+ OBJECT_IDX old_o_idx = drop_near(creature_ptr, &forge, 0, creature_ptr->y, creature_ptr->x);
+ *o_ptr_ptr = &creature_ptr->current_floor_ptr->o_list[old_o_idx];
GAME_TEXT o_name[MAX_NLEN];
- describe_flavor(creature_ptr, o_name, o_ptr, OD_NAME_ONLY);
+ describe_flavor(creature_ptr, o_name, &forge, OD_NAME_ONLY);
msg_format(_("%sを脱ぎ捨てた。", "You cast off %s."), o_name);
/* Get effects */
bool restore_all_status(player_type *creature_ptr);
bool fishing(player_type *creature_ptr);
-bool cosmic_cast_off(player_type *creature_ptr, object_type *o_ptr);
+bool cosmic_cast_off(player_type *creature_ptr, object_type **o_ptr_ptr);
void apply_nexus(monster_type *m_ptr, player_type *target_ptr);
void status_shuffle(player_type *creature_ptr);
if (creature_ptr->is_dead)
return FALSE;
- if (creature_ptr->pclass == CLASS_BERSERKER)
+ if (creature_ptr->pclass == CLASS_BERSERKER) {
v = 1;
+ return FALSE;
+ }
+
if (v) {
if (creature_ptr->shero && !do_dec) {
if (creature_ptr->shero > v)
IDX t_idx;
while (TRUE) {
t_idx = rumor_num(zz[1], NO_TOWN);
- if (town_info[t_idx].name)
+ if (town_info[t_idx].name[0] != '\0')
break;
}
/*
- * @brief
+ * @brief
* @author
* Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
* 2002/01/12 mogami
*
* Pass 1 is determined from allocation information
* Pass 2 is determined from allocation restriction
- * Pass 3 is determined from allocation calculation
*/
typedef struct alloc_entry {
KIND_OBJECT_IDX index; /* The actual index */
DEPTH level; /* Base dungeon level */
PROB prob1; /* Probability, pass 1 */
PROB prob2; /* Probability, pass 2 */
- PROB prob3; /* Probability, pass 3 */
u16b total; /* Unused for now */
} alloc_entry;
#define FAKE_VER_MAJOR 13 /*!< ゲームのバージョン番号定義(メジャー番号 + 10) */
#define FAKE_VER_MINOR 0 /*!< ゲームのバージョン番号定義(マイナー番号) */
#define FAKE_VER_PATCH 0 /*!< ゲームのバージョン番号定義(パッチ番号) */
-#define FAKE_VER_EXTRA 12 /*!< ゲームのバージョン番号定義(エクストラ番号) */
+#define FAKE_VER_EXTRA 13 /*!< ゲームのバージョン番号定義(エクストラ番号) */
/*!
* @brief バージョンが開発版が安定版かを返す
* todo どこからも呼ばれていない。main関数辺りに移設するか、そもそもコメントでいいと思われる
* コピーライト情報 / Link a copyright message into the executable
*/
+/*
const concptr copyright[5] =
{
"Copyright (c) 1989 James E. Wilson, Robert A. Keoneke",
"and not for profit purposes provided that this copyright and statement",
"are included in all such copies."
};
+*/
concptr ANGBAND_SYS = "xxx";
concptr ANGBAND_KEYBOARD = _("JAPAN", "0");
-#include "target/grid-selector.h"
+#include <vector>
+
#include "core/player-redraw-types.h"
#include "core/player-update-types.h"
-#include "core/window-redrawer.h"
#include "core/stuff-handler.h"
+#include "core/window-redrawer.h"
#include "floor/cave.h"
#include "game-option/game-play-options.h"
#include "game-option/keymap-directory-getter.h"
#include "io/input-key-acceptor.h"
#include "io/screen-util.h"
#include "system/floor-type-definition.h"
+#include "target/grid-selector.h"
#include "target/target-checker.h"
#include "term/screen-processor.h"
#include "util/int-char-converter.h"
* XAngband: Prepare the "temp" array for "tget_pt"
* based on target_set_prepare funciton.
*/
-static void tgt_pt_prepare(player_type *creature_ptr)
+static void tgt_pt_prepare(player_type *creature_ptr, std::vector<POSITION> &ys, std::vector<POSITION> &xs)
{
- tmp_pos.n = 0;
if (!expand_list)
return;
if (!tgt_pt_accept(creature_ptr, y, x))
continue;
- tmp_pos.x[tmp_pos.n] = x;
- tmp_pos.y[tmp_pos.n] = y;
- tmp_pos.n++;
+ ys.emplace_back(y);
+ xs.emplace_back(x);
}
}
- ang_sort(creature_ptr, tmp_pos.x, tmp_pos.y, tmp_pos.n, ang_sort_comp_distance, ang_sort_swap_position);
+ ang_sort(creature_ptr, xs.data(), ys.data(), size(ys), ang_sort_comp_distance, ang_sort_swap_position);
}
/*
*/
bool tgt_pt(player_type *creature_ptr, POSITION *x_ptr, POSITION *y_ptr)
{
+ // "interesting" な座標たちを記録する配列。
+ // ang_sort() を利用する関係上、y/x 座標それぞれについて配列を作る。
+ std::vector<POSITION> ys;
+ std::vector<POSITION> xs;
+
TERM_LEN wid, hgt;
get_screen_size(&wid, &hgt);
POSITION x = creature_ptr->x;
POSITION y = creature_ptr->y;
if (expand_list)
- tgt_pt_prepare(creature_ptr);
+ tgt_pt_prepare(creature_ptr, ys, xs);
msg_print(_("場所を選んでスペースキーを押して下さい。", "Select a point and press space."));
msg_flag = FALSE;
char ch = 0;
- int n = 0;
+ size_t n = 0;
bool success = FALSE;
while ((ch != ESCAPE) && !success) {
bool move_fast = FALSE;
break;
case '>':
case '<': {
- if (!expand_list || !tmp_pos.n)
+ if (!expand_list || ys.empty())
break;
int dx, dy;
int cx = (panel_col_min + panel_col_max) / 2;
int cy = (panel_row_min + panel_row_max) / 2;
n++;
- for (; n < tmp_pos.n; ++n) {
- grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[tmp_pos.y[n]][tmp_pos.x[n]];
+ for (; n < size(ys); ++n) {
+ const POSITION y_cur = ys[n];
+ const POSITION x_cur = xs[n];
+ grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[y_cur][x_cur];
if (cave_has_flag_grid(g_ptr, FF_STAIRS) && cave_has_flag_grid(g_ptr, ch == '>' ? FF_MORE : FF_LESS))
break;
}
- if (n == tmp_pos.n) {
+ if (n == size(ys)) {
n = 0;
y = creature_ptr->y;
x = creature_ptr->x;
creature_ptr->window_flags |= PW_OVERHEAD;
handle_stuff(creature_ptr);
} else {
- y = tmp_pos.y[n];
- x = tmp_pos.x[n];
+ y = ys[n];
+ x = xs[n];
dy = 2 * (y - cy) / hgt;
dx = 2 * (x - cx) / wid;
if (dy || dx)
-#include "target/target-preparation.h"
+#include <utility>
+#include <vector>
+
#include "floor/cave.h"
#include "game-option/input-options.h"
#include "grid/feature.h"
#include "system/floor-type-definition.h"
#include "system/object-type-definition.h"
#include "target/projection-path-calculator.h"
+#include "target/target-preparation.h"
#include "target/target-types.h"
#include "util/bit-flags-calculator.h"
#include "util/sort.h"
return FALSE;
}
-/*
- * Prepare the "temp" array for "target_set"
+/*!
+ * @brief "interesting" な座標たちを ys, xs に返す。
+ * @param creature_ptr
+ * @param ys y座標たちを格納する配列 (POSITION 型)
+ * @param xs x座標たちを格納する配列 (POSITION 型)
+ * @param mode
*
- * Return the number of target_able monsters in the set.
+ * ys, xs は処理開始時にクリアされる。
*/
-void target_set_prepare(player_type *creature_ptr, BIT_FLAGS mode)
+void target_set_prepare(player_type *creature_ptr, std::vector<POSITION> &ys, std::vector<POSITION> &xs, const BIT_FLAGS mode)
{
POSITION min_hgt, max_hgt, min_wid, max_wid;
if (mode & TARGET_KILL) {
max_wid = panel_col_max;
}
- tmp_pos.n = 0;
+ ys.clear();
+ xs.clear();
+
for (POSITION y = min_hgt; y <= max_hgt; y++) {
for (POSITION x = min_wid; x <= max_wid; x++) {
grid_type *g_ptr;
if ((mode & (TARGET_KILL)) && !target_pet && is_pet(&creature_ptr->current_floor_ptr->m_list[g_ptr->m_idx]))
continue;
- tmp_pos.x[tmp_pos.n] = x;
- tmp_pos.y[tmp_pos.n] = y;
- tmp_pos.n++;
+ ys.emplace_back(y);
+ xs.emplace_back(x);
}
}
if (mode & (TARGET_KILL)) {
- ang_sort(creature_ptr, tmp_pos.x, tmp_pos.y, tmp_pos.n, ang_sort_comp_distance, ang_sort_swap_position);
+ ang_sort(creature_ptr, xs.data(), ys.data(), size(ys), ang_sort_comp_distance, ang_sort_swap_position);
} else {
- ang_sort(creature_ptr, tmp_pos.x, tmp_pos.y, tmp_pos.n, ang_sort_comp_importance, ang_sort_swap_position);
+ ang_sort(creature_ptr, xs.data(), ys.data(), size(ys), ang_sort_comp_importance, ang_sort_swap_position);
}
- if (creature_ptr->riding == 0 || !target_pet || (tmp_pos.n <= 1) || !(mode & (TARGET_KILL)))
+ // 乗っているモンスターがターゲットリストの先頭にならないようにする調整。
+
+ if (creature_ptr->riding == 0 || !target_pet || (size(ys) <= 1) || !(mode & (TARGET_KILL)))
return;
- POSITION tmp = tmp_pos.y[0];
- tmp_pos.y[0] = tmp_pos.y[1];
- tmp_pos.y[1] = tmp;
- tmp = tmp_pos.x[0];
- tmp_pos.x[0] = tmp_pos.x[1];
- tmp_pos.x[1] = tmp;
+ // 0 番目と 1 番目を入れ替える。
+ std::swap(ys[0], ys[1]);
+ std::swap(xs[0], xs[1]);
}
void target_sensing_monsters_prepare(player_type *creature_ptr, std::vector<MONSTER_IDX> &monster_list)
-#pragma once
-
-#include "system/angband.h"
+#pragma once
#include <vector>
+#include "system/angband.h"
+
bool target_able(player_type *creature_ptr, MONSTER_IDX m_idx);
-void target_set_prepare(player_type *creature_ptr, BIT_FLAGS mode);
+void target_set_prepare(player_type *creature_ptr, std::vector<POSITION> &ys, std::vector<POSITION> &xs, BIT_FLAGS mode);
void target_sensing_monsters_prepare(player_type *creature_ptr, std::vector<MONSTER_IDX> &monster_list);
-#include "target/target-setter.h"
+#include <vector>
+
#include "core/player-redraw-types.h"
#include "core/player-update-types.h"
#include "core/stuff-handler.h"
#include "target/target-checker.h"
#include "target/target-describer.h"
#include "target/target-preparation.h"
+#include "target/target-setter.h"
#include "target/target-types.h"
#include "term/screen-processor.h"
#include "util/bit-flags-calculator.h"
#include "window/display-sub-windows.h"
#include "window/main-window-util.h"
+// "interesting" な座標たちを記録する配列。
+// ang_sort() を利用する関係上、y/x座標それぞれについて配列を作る。
+static std::vector<POSITION> ys_interest;
+static std::vector<POSITION> xs_interest;
+
// Target Setter.
typedef struct ts_type {
target_type mode;
POSITION y;
POSITION x;
- POSITION y2;
- POSITION x2;
+ POSITION y2; // panel_row_min 退避用
+ POSITION x2; // panel_col_min 退避用
bool done;
- bool flag;
+ bool flag; // 移動コマンド入力時、"interesting" な座標へ飛ぶかどうか
char query;
char info[80];
grid_type *g_ptr;
TERM_LEN wid, hgt;
- int m;
- int distance;
- int target_num;
- bool move_fast;
+ int m; // "interesting" な座標たちのうち現在ターゲットしているもののインデックス
+ int distance; // カーソルの移動方向 (1,2,3,4,6,7,8,9)
+ int target_num; // target_pick() の結果
+ bool move_fast; // カーソル移動を粗くする(1マスずつ移動しない)
} ts_type;
static ts_type *initialize_target_set_type(player_type *creature_ptr, ts_type *ts_ptr, target_type mode)
return change_panel(creature_ptr, dy, dx);
}
-/*
- * Help "select" a location (see below)
+/*!
+ * @brief "interesting" な座標たちのうち、(y1,x1) から (dy,dx) 方向にある最も近いもののインデックスを得る。
+ * @param y1 現在地座標y
+ * @param x1 現在地座標x
+ * @param dy 現在地からの向きy [-1,1]
+ * @param dx 現在地からの向きx [-1,1]
+ * @return 最も近い座標のインデックス。適切なものがない場合 -1
*/
-static POSITION_IDX target_pick(POSITION y1, POSITION x1, POSITION dy, POSITION dx)
+static POSITION_IDX target_pick(const POSITION y1, const POSITION x1, const POSITION dy, const POSITION dx)
{
+ // 最も近いもののインデックスとその距離。
POSITION_IDX b_i = -1, b_v = 9999;
- for (POSITION_IDX i = 0; i < tmp_pos.n; i++) {
- POSITION x2 = tmp_pos.x[i];
- POSITION y2 = tmp_pos.y[i];
- POSITION x3 = (x2 - x1);
- POSITION y3 = (y2 - y1);
+
+ for (POSITION_IDX i = 0; i < (POSITION_IDX)size(ys_interest); i++) {
+ const POSITION x2 = xs_interest[i];
+ const POSITION y2 = ys_interest[i];
+
+ // (y1,x1) から (y2,x2) へ向かうベクトル。
+ const POSITION x3 = (x2 - x1);
+ const POSITION y3 = (y2 - y1);
+
+ // (dy,dx) 方向にないものを除外する。
+
+ // dx > 0 のとき、x3 <= 0 なるものは除外。
+ // dx < 0 のとき、x3 >= 0 なるものは除外。
if (dx && (x3 * dx <= 0))
continue;
+ // dy > 0 のとき、y3 <= 0 なるものは除外。
+ // dy < 0 のとき、y3 >= 0 なるものは除外。
if (dy && (y3 * dy <= 0))
continue;
- POSITION x4 = ABS(x3);
- POSITION y4 = ABS(y3);
+ const POSITION x4 = ABS(x3);
+ const POSITION y4 = ABS(y3);
+
+ // (dy,dx) が (-1,0) or (1,0) のとき、|x3| > |y3| なるものは除外。
if (dy && !dx && (x4 > y4))
continue;
+ // (dy,dx) が (0,-1) or (0,1) のとき、|y3| > |x3| なるものは除外。
if (dx && !dy && (y4 > x4))
continue;
- POSITION_IDX v = ((x4 > y4) ? (x4 + x4 + y4) : (y4 + y4 + x4));
+ // (y1,x1), (y2,x2) 間の距離を求め、最も近いものを更新する。
+ // 距離の定義は v の式を参照。
+ const POSITION_IDX v = ((x4 > y4) ? (x4 + x4 + y4) : (y4 + y4 + x4));
if ((b_i >= 0) && (v >= b_v))
continue;
static void describe_projectablity(player_type *creature_ptr, ts_type *ts_ptr)
{
- ts_ptr->y = tmp_pos.y[ts_ptr->m];
- ts_ptr->x = tmp_pos.x[ts_ptr->m];
+ ts_ptr->y = ys_interest[ts_ptr->m];
+ ts_ptr->x = xs_interest[ts_ptr->m];
change_panel_xy(creature_ptr, ts_ptr->y, ts_ptr->x);
if ((ts_ptr->mode & TARGET_LOOK) == 0)
print_path(creature_ptr, ts_ptr->y, ts_ptr->x);
case ' ':
case '*':
case '+':
- if (++ts_ptr->m != tmp_pos.n)
+ if (++ts_ptr->m != (int)size(ys_interest))
return;
ts_ptr->m = 0;
if (ts_ptr->m-- != 0)
return;
- ts_ptr->m = tmp_pos.n - 1;
+ ts_ptr->m = (int)size(ys_interest) - 1;
if (!expand_list)
ts_ptr->done = TRUE;
creature_ptr->redraw |= PR_MAP;
creature_ptr->window_flags |= PW_OVERHEAD;
handle_stuff(creature_ptr);
- target_set_prepare(creature_ptr, ts_ptr->mode);
+ target_set_prepare(creature_ptr, ys_interest, xs_interest, ts_ptr->mode);
ts_ptr->y = creature_ptr->y;
ts_ptr->x = creature_ptr->x;
}
return;
}
- if (++ts_ptr->m != tmp_pos.n)
+ if (++ts_ptr->m != (int)size(ys_interest))
return;
ts_ptr->m = 0;
}
}
+/*!
+ * @brief カーソル移動に伴い、描画範囲、"interesting" 座標リスト、現在のターゲットを更新する。
+ * @return カーソル移動によって描画範囲が変化したかどうか
+ */
static bool check_panel_changed(player_type *creature_ptr, ts_type *ts_ptr)
{
+ // カーソル移動によって描画範囲が変化しないなら何もせずその旨を返す。
if (!change_panel(creature_ptr, ddy[ts_ptr->distance], ddx[ts_ptr->distance]))
return FALSE;
- int v = tmp_pos.y[ts_ptr->m];
- int u = tmp_pos.x[ts_ptr->m];
- target_set_prepare(creature_ptr, ts_ptr->mode);
+ // 描画範囲が変化した場合、"interesting" 座標リストおよび現在のターゲットを更新する必要がある。
+
+ // "interesting" 座標を探す起点。
+ // ts_ptr->m が有効な座標を指していればそれを使う。
+ // さもなくば (ts_ptr->y, ts_ptr->x) を使う。
+ int v, u;
+ if (ts_ptr->m < (int)size(ys_interest)) {
+ v = ys_interest[ts_ptr->m];
+ u = xs_interest[ts_ptr->m];
+ } else {
+ v = ts_ptr->y;
+ u = ts_ptr->x;
+ }
+
+ // 新たな描画範囲を用いて "interesting" 座標リストを更新。
+ target_set_prepare(creature_ptr, ys_interest, xs_interest, ts_ptr->mode);
+
+ // 新たな "interesting" 座標リストからターゲットを探す。
ts_ptr->flag = TRUE;
ts_ptr->target_num = target_pick(v, u, ddy[ts_ptr->distance], ddx[ts_ptr->distance]);
if (ts_ptr->target_num >= 0)
return TRUE;
}
+/*!
+ * @brief カーソル移動方向に "interesting" な座標がなかったとき、画面外まで探す。
+ *
+ * 既に "interesting" な座標を発見している場合、この関数は何もしない。
+ */
static void sweep_targets(player_type *creature_ptr, ts_type *ts_ptr)
{
floor_type *floor_ptr = creature_ptr->current_floor_ptr;
while (ts_ptr->flag && (ts_ptr->target_num < 0)) {
+ // カーソル移動に伴い、必要なだけ描画範囲を更新。
+ // "interesting" 座標リストおよび現在のターゲットも更新。
if (check_panel_changed(creature_ptr, ts_ptr))
continue;
creature_ptr->redraw |= PR_MAP;
creature_ptr->window_flags |= PW_OVERHEAD;
handle_stuff(creature_ptr);
- target_set_prepare(creature_ptr, ts_ptr->mode);
+ target_set_prepare(creature_ptr, ys_interest, xs_interest, ts_ptr->mode);
ts_ptr->flag = FALSE;
ts_ptr->x += dx;
ts_ptr->y += dy;
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(creature_ptr, dy, dx))
- target_set_prepare(creature_ptr, ts_ptr->mode);
+ target_set_prepare(creature_ptr, ys_interest, xs_interest, ts_ptr->mode);
}
if (ts_ptr->x >= floor_ptr->width - 1)
static bool set_target_grid(player_type *creature_ptr, ts_type *ts_ptr)
{
- if (!ts_ptr->flag || (tmp_pos.n == 0))
+ if (!ts_ptr->flag || ys_interest.empty())
return FALSE;
describe_projectablity(creature_ptr, ts_ptr);
ts_ptr->y2 = panel_row_min;
ts_ptr->x2 = panel_col_min;
- ts_ptr->target_num = target_pick(tmp_pos.y[ts_ptr->m], tmp_pos.x[ts_ptr->m], ddy[ts_ptr->distance], ddx[ts_ptr->distance]);
+ {
+ const POSITION y = ys_interest[ts_ptr->m];
+ const POSITION x = xs_interest[ts_ptr->m];
+ ts_ptr->target_num = target_pick(y, x, ddy[ts_ptr->distance], ddx[ts_ptr->distance]);
+ }
sweep_targets(creature_ptr, ts_ptr);
ts_ptr->m = ts_ptr->target_num;
return TRUE;
creature_ptr->redraw |= PR_MAP;
creature_ptr->window_flags |= PW_OVERHEAD;
handle_stuff(creature_ptr);
- target_set_prepare(creature_ptr, ts_ptr->mode);
+ target_set_prepare(creature_ptr, ys_interest, xs_interest, ts_ptr->mode);
ts_ptr->y = creature_ptr->y;
ts_ptr->x = creature_ptr->x;
case 'o':
ts_ptr->flag = TRUE;
ts_ptr->m = 0;
int bd = 999;
- for (int i = 0; i < tmp_pos.n; i++) {
- int t = distance(ts_ptr->y, ts_ptr->x, tmp_pos.y[i], tmp_pos.x[i]);
+ for (size_t i = 0; i < size(ys_interest); i++) {
+ const POSITION y = ys_interest[i];
+ const POSITION x = xs_interest[i];
+ int t = distance(ts_ptr->y, ts_ptr->x, y, x);
if (t < bd) {
ts_ptr->m = i;
bd = t;
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(creature_ptr, dy, dx))
- target_set_prepare(creature_ptr, ts_ptr->mode);
+ target_set_prepare(creature_ptr, ys_interest, xs_interest, ts_ptr->mode);
}
floor_type *floor_ptr = creature_ptr->current_floor_ptr;
ts_type tmp_ts;
ts_type *ts_ptr = initialize_target_set_type(creature_ptr, &tmp_ts, mode);
target_who = 0;
- target_set_prepare(creature_ptr, mode);
+ target_set_prepare(creature_ptr, ys_interest, xs_interest, mode);
sweep_target_grids(creature_ptr, ts_ptr);
- tmp_pos.n = 0;
prt("", 0, 0);
verify_panel(creature_ptr);
set_bits(creature_ptr->update, PU_MONSTERS);
/* Purpose: Memory management routines -BEN- */
-#include "term/z-virt.h"
-#include "term/z-util.h"
-
-/*
- * Optional auxiliary "rnfree" function
- */
-vptr (*rnfree_aux)(vptr, huge) = NULL;
-
-/*
- * Free some memory (allocated by ralloc), return NULL
- */
-vptr rnfree(vptr p, huge len)
-{
- /* Easy to free zero bytes */
- if (len == 0) return (NULL);
-
- /* Use the "aux" function */
- if (rnfree_aux) return ((*rnfree_aux)(p, len));
-
- /* Use "free" */
- free ((char*)(p));
-
- return (NULL);
-}
-
-
-/*
- * Optional auxiliary "rpanic" function
- */
-vptr (*rpanic_aux)(huge) = NULL;
-
-/*
- * The system is out of memory, so panic. If "rpanic_aux" is set,
- * it can be used to free up some memory and do a new "ralloc()",
- * or if not, it can be used to save things, clean up, and exit.
- * By default, this function simply crashes the computer.
- */
-vptr rpanic(huge len)
-{
- /* Hopefully, we have a real "panic" function */
- if (rpanic_aux) return ((*rpanic_aux)(len));
-
- /* Attempt to crash before icky things happen */
- core("Out of Memory!");
- return ((vptr)(NULL));
-}
-
-
-/*
- * Optional auxiliary "ralloc" function
- */
-vptr (*ralloc_aux)(huge) = NULL;
-
-
-/*
- * Allocate some memory
- */
-vptr ralloc(huge len)
-{
- vptr mem;
-
- /* Allow allocation of "zero bytes" */
- if (len == 0) return ((vptr)(NULL));
-
-#ifdef VERBOSE_RALLOC
-
- /* Count allocated memory */
- virt_make += len;
-
- /* Log important allocations */
- if (len > virt_size)
- {
- char buf[80];
- sprintf(buf, "Make (%ld): %ld - %ld = %ld.",
- len, virt_make, virt_kill, virt_make - virt_kill);
- plog(buf);
- }
-
-#endif
-
- /* Use the aux function if set */
- if (ralloc_aux) mem = (*ralloc_aux)(len);
-
- /* Use malloc() to allocate some memory */
- else mem = ((vptr)(malloc((size_t)(len))));
-
- /* We were able to acquire memory */
- if (!mem) mem = rpanic(len);
-
- /* Return the memory, if any */
- return (mem);
-}
-
-
+#include <cstring>
+#include "term/z-virt.h"
-/*
- * Allocate a constant string, containing the same thing as 'str'
+/*!
+ * @brief str の複製を返す。戻り値は使用後に string_free() で解放すること。
+ *
+ * nullptr が渡された場合、nullptr を返す。
*/
-concptr string_make(concptr str)
+concptr string_make(const concptr str)
{
- huge len = 0;
- concptr t = str;
- char *s, *res;
-
- /* Simple sillyness */
- if (!str) return (str);
-
- /* Get the number of chars in the string, including terminator */
- while (str[len++]) /* loop */;
+ if (!str)
+ return nullptr;
- /* Allocate space for the string */
- s = res = (char*)(ralloc(len));
+ const auto bufsize = std::strlen(str) + 1;
+ auto *const buf = new char[bufsize];
+ std::strcpy(buf, str);
- /* Copy the string (with terminator) */
- while ((*s++ = *t++) != 0) /* loop */;
-
- /* Return the allocated, initialized, string */
- return (res);
+ return buf;
}
-
-/*
- * Un-allocate a string allocated above.
- * Depends on no changes being made to the string.
+/*!
+ * @brief string_make() で割り当てたバッファを解放する。
+ * @return 常に 0
+ *
+ * nullptr が渡された場合、何もせず 0 を返す。
*/
-errr string_free(concptr str)
+errr string_free(const concptr str)
{
- huge len = 0;
-
- /* Succeed on non-strings */
- if (!str) return 0;
-
- /* Count the number of chars in 'str' plus the terminator */
- while (str[len++]) /* loop */;
+ if (!str)
+ return 0;
- /* Kill the buffer of chars we must have allocated above */
- (void)rnfree((vptr)(str), len);
+ delete[] str;
- /* Success */
- return 0;
+ return 0;
}
#include "system/h-basic.h"
+#include <type_traits>
+
/*
* Memory management routines.
*
- * Set ralloc_aux to modify the memory allocation routine.
- * Set rnfree_aux to modify the memory de-allocation routine.
- * Set rpanic_aux to let the program react to memory failures.
- *
* These routines work best as a *replacement* for malloc/free.
*
* The string_make() and string_free() routines handle dynamic strings.
* in particular, that it returns its first argument.
*/
-
+//
+// データクリアマクロ WIPE/C_WIPE の実装
+//
+
+// トリビアル型は memset でゼロクリアする
+template <typename T, std::enable_if_t<std::is_trivial_v<T>, std::nullptr_t> = nullptr>
+inline T *c_wipe_impl(T *p, size_t n)
+{
+ return static_cast<T *>(memset(p, 0, sizeof(T) * n));
+}
+template <typename T, std::enable_if_t<std::is_trivial_v<T>, std::nullptr_t> = nullptr>
+inline T *wipe_impl(T *p)
+{
+ return static_cast<T *>(memset(p, 0, sizeof(T)));
+}
+
+// 非トリビアル型はデフォルトコンストラクタで生成したオブジェクトをコピーする
+template <typename T, std::enable_if_t<!std::is_trivial_v<T>, std::nullptr_t> = nullptr>
+inline T *c_wipe_impl(T *p, size_t n)
+{
+ T obj{};
+ for (size_t i = 0; i < n; i++) {
+ *p = obj;
+ }
+ return p;
+}
+template <typename T, std::enable_if_t<!std::is_trivial_v<T>, std::nullptr_t> = nullptr>
+inline T *wipe_impl(T *p)
+{
+ *p = T{};
+ return p;
+}
+
+//
+// データコピーマクロ COPY/C_COPY の実装
+//
+
+// トリビアルコピーが可能な型は memcpy でコピーする
+template <typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, std::nullptr_t> = nullptr>
+inline T *c_copy_impl(T *p1, T *p2, size_t n)
+{
+ return static_cast<T *>(memcpy(p1, p2, sizeof(T) * n));
+}
+
+// トリビアルコピーが不可能な型は要素を1つずつコピー代入する
+template <typename T, std::enable_if_t<!std::is_trivially_copyable_v<T>, std::nullptr_t> = nullptr>
+inline T *c_copy_impl(T *p1, T *p2, size_t n)
+{
+ for (size_t i = 0; i < n; i++) {
+ *(p1 + i) = *(p2 + i);
+ }
+ return p1;
+}
+
+// 単要素の場合はトリビアルコピーの可/不可に関わらずコピー代入する
+template <typename T>
+inline T *copy_impl(T *p1, T *p2)
+{
+ *p1 = *p2;
+ return p1;
+}
+
+//
+// メモリ領域確保マクロ RNEW/C_RNEW の実装
+// MAKE/C_MAKE から最終的に呼ばれる
+//
+
+template <typename T>
+inline T *c_rnew_impl(size_t count)
+{
+ return new T[count];
+}
+
+template <typename T>
+inline T *rnew_impl()
+{
+ return new T;
+}
+
+//
+// メモリ領域解放マクロ FREE/C_FREE の実装
+// KILL/C_KILL からも FREE/C_FREE を介して呼ばれる
+//
+
+template <typename T>
+inline T *c_free_impl(T *p, size_t count)
+{
+ (void)count; // unused;
+
+ delete[] p;
+ return nullptr;
+}
+
+template <typename T>
+inline T *free_impl(T *p)
+{
+ delete p;
+ return nullptr;
+}
/**** Available macros ****/
-
/* Size of 'N' things of type 'T' */
-#define C_SIZE(N,T) \
- ((huge)((N)*(sizeof(T))))
+#define C_SIZE(N, T) ((huge)((N) * (sizeof(T))))
/* Size of one thing of type 'T' */
-#define SIZE(T) \
- ((huge)(sizeof(T)))
-
+#define SIZE(T) ((huge)(sizeof(T)))
+#if 0
/* Compare two arrays of type T[N], at locations P1 and P2 */
-#define C_DIFF(P1,P2,N,T) \
- (memcmp((char*)(P1),(char*)(P2),C_SIZE(N,T)))
+#define C_DIFF(P1, P2, N, T) (memcmp((char *)(P1), (char *)(P2), C_SIZE(N, T)))
/* Compare two things of type T, at locations P1 and P2 */
-#define DIFF(P1,P2,T) \
- (memcmp((char*)(P1),(char*)(P2),SIZE(T)))
-
+#define DIFF(P1, P2, T) (memcmp((char *)(P1), (char *)(P2), SIZE(T)))
/* Set every byte in an array of type T[N], at location P, to V, and return P */
-#define C_BSET(P,V,N,T) \
- (T*)(memset((char*)(P),(V),C_SIZE(N,T)))
+#define C_BSET(P, V, N, T) (T *)(memset((char *)(P), (V), C_SIZE(N, T)))
/* Set every byte in a thing of type T, at location P, to V, and return P */
-#define BSET(P,V,T) \
- (T*)(memset((char*)(P),(V),SIZE(T)))
-
+#define BSET(P, V, T) (T *)(memset((char *)(P), (V), SIZE(T)))
+#endif
/* Wipe an array of type T[N], at location P, and return P */
-#define C_WIPE(P,N,T) \
- (T*)(memset((char*)(P),0,C_SIZE(N,T)))
+#define C_WIPE(P, N, T) (c_wipe_impl<T>(P, N))
/* Wipe a thing of type T, at location P, and return P */
-#define WIPE(P,T) \
- (T*)(memset((char*)(P),0,SIZE(T)))
-
+#define WIPE(P, T) (wipe_impl<T>(P))
/* Load an array of type T[N], at location P1, from another, at location P2 */
-#define C_COPY(P1,P2,N,T) \
- (T*)(memcpy((char*)(P1),(char*)(P2),C_SIZE(N,T)))
+#define C_COPY(P1, P2, N, T) (c_copy_impl<T>(P1, P2, N))
/* Load a thing of type T, at location P1, from another, at location P2 */
-#define COPY(P1,P2,T) \
- (T*)(memcpy((char*)(P1),(char*)(P2),SIZE(T)))
-
+#define COPY(P1, P2, T) (copy_impl<T>(P1, P2))
/* Free an array of N things of type T at P, return NULL */
-#define C_FREE(P,N,T) \
- (T*)(rnfree(P,C_SIZE(N,T)))
+#define C_FREE(P, N, T) (c_free_impl<T>(P, N))
/* Free one thing of type T at P, return NULL */
-#define FREE(P,T) \
- (T*)(rnfree(P,SIZE(T)))
-
+#define FREE(P, T) (free_impl<T>(P))
/* Allocate, and return, an array of type T[N] */
-#define C_RNEW(N,T) \
- ((T*)(ralloc(C_SIZE(N,T))))
+#define C_RNEW(N, T) (c_rnew_impl<T>(N))
/* Allocate, and return, a thing of type T */
-#define RNEW(T) \
- ((T*)(ralloc(SIZE(T))))
-
+#define RNEW(T) (rnew_impl<T>())
/* Allocate, wipe, and return an array of type T[N] */
-#define C_ZNEW(N,T) \
- ((T*)(C_WIPE(C_RNEW(N,T),N,T)))
+#define C_ZNEW(N, T) ((T *)(C_WIPE(C_RNEW(N, T), N, T)))
/* Allocate, wipe, and return a thing of type T */
-#define ZNEW(T) \
- ((T*)(WIPE(RNEW(T),T)))
-
+#define ZNEW(T) ((T *)(WIPE(RNEW(T), T)))
/* Allocate a wiped array of type T[N], assign to pointer P */
-#define C_MAKE(P,N,T) \
- ((P)=C_ZNEW(N,T))
+#define C_MAKE(P, N, T) ((P) = C_ZNEW(N, T))
/* Allocate a wiped thing of type T, assign to pointer P */
-#define MAKE(P,T) \
- ((P)=ZNEW(T))
-
+#define MAKE(P, T) ((P) = ZNEW(T))
/* Free an array of type T[N], at location P, and set P to NULL */
-#define C_KILL(P,N,T) \
- ((P)=C_FREE(P,N,T))
+#define C_KILL(P, N, T) ((P) = C_FREE(P, N, T))
/* Free a thing of type T, at location P, and set P to NULL */
-#define KILL(P,T) \
- ((P)=FREE(P,T))
-
-
-
-/**** Available variables ****/
-
-/* Replacement hook for "rnfree()" */
-extern vptr (*rnfree_aux)(vptr, huge);
-
-/* Replacement hook for "rpanic()" */
-extern vptr (*rpanic_aux)(huge);
-
-/* Replacement hook for "ralloc()" */
-extern vptr (*ralloc_aux)(huge);
-
+#define KILL(P, T) ((P) = FREE(P, T))
/**** Available functions ****/
-/* De-allocate a given amount of memory */
-extern vptr rnfree(vptr p, huge len);
-
-/* Panic, attempt to Allocate 'len' bytes */
-extern vptr rpanic(huge len);
-
-/* Allocate (and return) 'len', or dump core */
-extern vptr ralloc(huge len);
-
/* Create a "dynamic string" */
extern concptr string_make(concptr str);
/* Free a string allocated with "string_make()" */
extern errr string_free(concptr str);
-
-
-
#endif
-
-
-
if (o_ptr->pval > j_ptr->pval)
return FALSE;
break;
+
+ default:
+ break;
}
return o_value > object_value(player_ptr, j_ptr);
--- /dev/null
+#pragma once
+
+#include "term/z-rand.h"
+
+#include <algorithm>
+#include <exception>
+#include <stdexcept>
+#include <tuple>
+#include <vector>
+
+/**
+ * @brief 確率テーブルクラス
+ *
+ * 確率テーブルを作成し、確率に従った抽選を行うクラス
+ *
+ * @tparam IdType 確率テーブルに登録するIDの型
+ */
+template <typename IdType>
+class ProbabilityTable {
+public:
+ /**
+ * @brief コンストラクタ
+ *
+ * 空の確率テーブルを生成する
+ */
+ ProbabilityTable() = default;
+
+ /**
+ * @brief 確率テーブルを空にする
+ */
+ void clear()
+ {
+ return item_list_.clear();
+ }
+
+ /**
+ * @brief 確率テーブルに項目を登録する
+ *
+ * 確率テーブルに項目のIDと選択確率のセットを登録する。
+ * 追加した項目が選択される確率は、
+ * 追加した項目の確率(引数prob) / すべての項目のprobの合計
+ * となる。
+ * probが0もしくは負数の場合はなにも登録しない。
+ *
+ * @param id 項目のID
+ * @param prob 項目の選択確率
+ */
+ void entry_item(IdType id, int prob)
+ {
+ if (prob > 0) {
+ // 二分探索を行うため、probは累積値を格納する
+ auto cumulative_prob = item_list_.empty() ? 0 : std::get<1>(item_list_.back());
+ item_list_.emplace_back(id, cumulative_prob + prob);
+ }
+ }
+
+ /**
+ * @brief 現在の確率テーブルのすべての項目の選択確率の合計を取得する
+ *
+ * 確率テーブルに登録されているすべての項目の確率(登録時の引数prob)の合計を取得する。
+ *
+ * @return int 現在の確率テーブルのすべての項目の選択確率の合計
+ */
+ int total_prob() const
+ {
+ if (item_list_.empty())
+ return 0;
+
+ return std::get<1>(item_list_.back());
+ }
+
+ /**
+ * @brief 確率テーブルに登録されている項目の数を取得する
+ *
+ * 確率テーブルに登録されている項目の数を取得する。
+ * 登録されている項目のIDに被りがある場合は別の項目として加算した数となる。
+ *
+ * @return size_t 確率テーブルに登録されている項目の数
+ */
+ size_t item_count() const
+ {
+ return item_list_.size();
+ }
+
+ /**
+ * @brief 確率テーブルの項目が空かどうかを調べる
+ *
+ * @return bool 確率テーブルに項目が一つも登録されておらず空であれば true
+ * 項目が一つ以上登録されており空でなければ false
+ */
+ bool empty() const
+ {
+ return item_list_.empty();
+ }
+
+ /**
+ * @brief 確率テーブルから項目をランダムに1つ選択する
+ *
+ * 確率テーブルに登録されているすべての項目から、確率に従って項目を1つ選択する
+ * それぞれの項目が選択される確率は、確率設定probに対して
+ * 該当項目のprob / すべての項目のprobの合計
+ * となる。
+ * 抽選は独立試行で行われ、選択された項目がテーブルから取り除かれる事はない。
+ * 確率テーブルになにも登録されていない場合、std::runtime_error例外を送出する。
+ *
+ * @return int 選択された項目のID
+ */
+ IdType pick_one_at_random() const
+ {
+ if (empty()) {
+ throw std::runtime_error("There is no entry in the probability table.");
+ }
+
+ // probの合計の範囲からランダムでkeyを取得し、二分探索で選択する項目を決定する
+ const int key = randint0(total_prob());
+ auto it = std::partition_point(item_list_.begin(), item_list_.end(), [key](const auto &i) { return std::get<1>(i) <= key; });
+
+ return std::get<0>(*it);
+ }
+
+ /**
+ * @brief 確率テーブルから複数回抽選する
+ *
+ * 確率テーブルから引数 n で指定した回数抽選し、抽選の結果選択された項目のIDを
+ * 出力イテレータに n 個書き込む。
+ * 抽選は独立試行で行われ、選択された項目がテーブルから取り除かれる事はない。
+ *
+ * @tparam OutputIter 出力イテレータの型
+ * @param first 結果を書き込む出力イテレータ
+ * @param table 抽選を行う確率テーブル
+ * @param n 抽選を行う回数
+ */
+ template <typename OutputIter>
+ static void lottery(OutputIter first, const ProbabilityTable &table, size_t n)
+ {
+ std::generate_n(first, n, [&table] { return table.pick_one_at_random(); });
+ }
+
+private:
+ /** 項目のIDと確率のセットを格納する配列 */
+ std::vector<std::tuple<IdType, int>> item_list_;
+};
return NULL;
}
+
+/*!
+ * @brief 左側の空白を除去
+ * @param p char型のポインタ
+ * @return 除去後のポインタ
+ */
+char *ltrim(char *p)
+{
+ while (p[0] == ' ')
+ p++;
+ return p;
+}
+
+/*!
+ * @brief 右側の空白を除去
+ * @param p char型のポインタ
+ * @return 除去後のポインタ
+ */
+char *rtrim(char *p)
+{
+ int i = strlen(p) - 1;
+ while (p[i] == ' ')
+ p[i--] = '\0';
+ return p;
+}
+
+/*!
+ * @brief 文字列の後方から一致するかどうか比較する
+ * @param s1 比較元文字列ポインタ
+ * @param s2 比較先文字列ポインタ
+ * @param len 比較する長さ
+ * @return 等しい場合は0、p1が大きい場合は-1、p2が大きい場合は1
+ * @detail
+ * strncmpの後方から比較する版
+ */
+int strrncmp(const char *s1, const char *s2, int len)
+{
+ int i;
+ int l1 = strlen(s1);
+ int l2 = strlen(s2);
+
+ for (i = 1; i <= len; i++) {
+ int p1 = l1 - i;
+ int p2 = l2 - i;
+
+ if (l1 != l2) {
+ if (p1 < 0)
+ return (-1);
+ if (p2 < 0)
+ return (1);
+ } else {
+ if (p1 < 0)
+ return (0);
+ }
+
+ if (s1[p1] < s2[p2])
+ return (-1);
+ if (s1[p1] > s2[p2])
+ return (-1);
+ }
+
+ return (0);
+}
size_t angband_strcat(char *buf, concptr src, size_t bufsize);
char *angband_strstr(concptr haystack, concptr 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);
static void display_monster_blow_jp(lore_type *lore_ptr, int attack_numbers, int d1, int d2, int m)
{
if (attack_numbers == 0) {
- hooked_roff(format("%^sは", wd_he[lore_ptr->msex]));
+ hooked_roff(format("%^sは", Who::who(lore_ptr->msex)));
}
if (d1 && d2 && (lore_ptr->know_everything || know_damage(lore_ptr->r_idx, m))) {
static void display_monster_blow_en(lore_type *lore_ptr, int attack_numbers, int d1, int d2, int m)
{
if (attack_numbers == 0) {
- hooked_roff(format("%^s can ", wd_he[lore_ptr->msex]));
+ hooked_roff(format("%^s can ", Who::who(lore_ptr->msex)));
} else if (attack_numbers < lore_ptr->count - 1) {
hooked_roff(", ");
} else {
if (attack_numbers > 0) {
hooked_roff(_("。", ". "));
} else if (lore_ptr->flags1 & RF1_NEVER_BLOW) {
- hooked_roff(format(_("%^sは物理的な攻撃方法を持たない。", "%^s has no physical attacks. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは物理的な攻撃方法を持たない。", "%^s has no physical attacks. "), Who::who(lore_ptr->msex)));
} else {
- hooked_roff(format(_("%s攻撃については何も知らない。", "Nothing is known about %s attack. "), wd_his[lore_ptr->msex]));
+ hooked_roff(format(_("%s攻撃については何も知らない。", "Nothing is known about %s attack. "), Who::whose(lore_ptr->msex)));
}
}
if ((lore_ptr->drop_gold == 0) && (lore_ptr->drop_item == 0))
return;
- hooked_roff(format(_("%^sは", "%^s may carry"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s may carry"), Who::who(lore_ptr->msex)));
#ifdef JP
#else
lore_ptr->sin = FALSE;
return;
lore_ptr->breath = TRUE;
- hooked_roff(format(_("%^sは", "%^s"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s"), Who::who(lore_ptr->msex)));
for (int n = 0; n < lore_ptr->vn; n++) {
#ifdef JP
if (n != 0)
if (lore_ptr->breath) {
hooked_roff(_("、なおかつ", ", and is also"));
} else {
- hooked_roff(format(_("%^sは", "%^s is"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s is"), Who::who(lore_ptr->msex)));
}
#ifdef JP
if (!know_armour(lore_ptr->r_idx, lore_ptr->know_everything))
return;
- hooked_roff(format(_("%^sは AC%d の防御力と", "%^s has an armor rating of %d"), wd_he[lore_ptr->msex], lore_ptr->r_ptr->ac));
+ hooked_roff(format(_("%^sは AC%d の防御力と", "%^s has an armor rating of %d"), Who::who(lore_ptr->msex), lore_ptr->r_ptr->ac));
if ((lore_ptr->flags1 & RF1_FORCE_MAXHP) || (lore_ptr->r_ptr->hside == 1)) {
u32b hp = lore_ptr->r_ptr->hdice * (lore_ptr->nightmare ? 2 : 1) * lore_ptr->r_ptr->hside;
hooked_roff(format(_(" %d の体力がある。", " and a life rating of %d. "), (s16b)MIN(30000, hp)));
if (lore_ptr->vn <= 0)
return;
- hooked_roff(format(_("%^sは", "%^s"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s"), Who::who(lore_ptr->msex)));
for (int n = 0; n < lore_ptr->vn; n++) {
#ifdef JP
if (n != lore_ptr->vn - 1) {
void display_monster_constitutions(lore_type *lore_ptr)
{
if (lore_ptr->flags7 & RF7_AQUATIC)
- hooked_roff(format(_("%^sは水中に棲んでいる。", "%^s lives in water. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは水中に棲んでいる。", "%^s lives in water. "), Who::who(lore_ptr->msex)));
if (lore_ptr->flags7 & (RF7_SELF_LITE_1 | RF7_SELF_LITE_2))
- hooked_roff(format(_("%^sは光っている。", "%^s is shining. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは光っている。", "%^s is shining. "), Who::who(lore_ptr->msex)));
if (lore_ptr->flags7 & (RF7_SELF_DARK_1 | RF7_SELF_DARK_2))
- hook_c_roff(TERM_L_DARK, format(_("%^sは暗黒に包まれている。", "%^s is surrounded by darkness. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_L_DARK, format(_("%^sは暗黒に包まれている。", "%^s is surrounded by darkness. "), Who::who(lore_ptr->msex)));
if (lore_ptr->flags2 & RF2_INVISIBLE)
- hooked_roff(format(_("%^sは透明で目に見えない。", "%^s is invisible. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは透明で目に見えない。", "%^s is invisible. "), Who::who(lore_ptr->msex)));
if (lore_ptr->flags2 & RF2_COLD_BLOOD)
- hooked_roff(format(_("%^sは冷血動物である。", "%^s is cold blooded. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは冷血動物である。", "%^s is cold blooded. "), Who::who(lore_ptr->msex)));
if (lore_ptr->flags2 & RF2_EMPTY_MIND)
- hooked_roff(format(_("%^sはテレパシーでは感知できない。", "%^s is not detected by telepathy. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sはテレパシーでは感知できない。", "%^s is not detected by telepathy. "), Who::who(lore_ptr->msex)));
else if (lore_ptr->flags2 & RF2_WEIRD_MIND)
- hooked_roff(format(_("%^sはまれにテレパシーで感知できる。", "%^s is rarely detected by telepathy. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sはまれにテレパシーで感知できる。", "%^s is rarely detected by telepathy. "), Who::who(lore_ptr->msex)));
if (lore_ptr->flags2 & RF2_MULTIPLY)
- hook_c_roff(TERM_L_UMBER, format(_("%^sは爆発的に増殖する。", "%^s breeds explosively. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_L_UMBER, format(_("%^sは爆発的に増殖する。", "%^s breeds explosively. "), Who::who(lore_ptr->msex)));
if (lore_ptr->flags2 & RF2_REGENERATE)
- hook_c_roff(TERM_L_WHITE, format(_("%^sは素早く体力を回復する。", "%^s regenerates quickly. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_L_WHITE, format(_("%^sは素早く体力を回復する。", "%^s regenerates quickly. "), Who::who(lore_ptr->msex)));
if (lore_ptr->flags7 & RF7_RIDING)
- hook_c_roff(TERM_SLATE, format(_("%^sに乗ることができる。", "%^s is suitable for riding. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_SLATE, format(_("%^sに乗ることができる。", "%^s is suitable for riding. "), Who::who(lore_ptr->msex)));
}
void display_monster_concrete_weakness(lore_type *lore_ptr)
if (lore_ptr->vn <= 0)
return;
- hooked_roff(format(_("%^sには", "%^s"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sには", "%^s"), Who::who(lore_ptr->msex)));
for (int n = 0; n < lore_ptr->vn; n++) {
#ifdef JP
if (n != 0)
if (lore_ptr->vn <= 0)
return;
- hooked_roff(format(_("%^sは", "%^s"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s"), Who::who(lore_ptr->msex)));
for (int n = 0; n < lore_ptr->vn; n++) {
#ifdef JP
if (n != 0)
return;
if (lore_ptr->r_ptr->next_r_idx) {
- hooked_roff(format(_("%^sは経験を積むと、", "%^s will evolve into "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは経験を積むと、", "%^s will evolve into "), Who::who(lore_ptr->msex)));
hook_c_roff(TERM_YELLOW, format("%s", r_name + r_info[lore_ptr->r_ptr->next_r_idx].name));
- hooked_roff(_(format("に進化する。"), format(" when %s gets enough experience. ", wd_he[lore_ptr->msex])));
+ hooked_roff(_(format("に進化する。"), format(" when %s gets enough experience. ", Who::who(lore_ptr->msex))));
} else if (!(lore_ptr->r_ptr->flags1 & RF1_UNIQUE)) {
- hooked_roff(format(_("%sは進化しない。", "%s won't evolve. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%sは進化しない。", "%s won't evolve. "), Who::who(lore_ptr->msex)));
}
}
if (lore_ptr->vn <= 0)
return;
- hooked_roff(format(_("%^sは", "%^s"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s"), Who::who(lore_ptr->msex)));
for (int n = 0; n < lore_ptr->vn; n++) {
#ifdef JP
if (n != 0)
act = _("をかなり警戒しており", "is ever vigilant for");
}
- hooked_roff(_(format("%^sは侵入者%s、 %d フィート先から侵入者に気付くことがある。", wd_he[lore_ptr->msex], act, 10 * lore_ptr->r_ptr->aaf),
- format("%^s %s intruders, which %s may notice from %d feet. ", wd_he[lore_ptr->msex], act, wd_he[lore_ptr->msex], 10 * lore_ptr->r_ptr->aaf)));
+ hooked_roff(_(format("%^sは侵入者%s、 %d フィート先から侵入者に気付くことがある。", Who::who(lore_ptr->msex), act, 10 * lore_ptr->r_ptr->aaf),
+ format("%^s %s intruders, which %s may notice from %d feet. ", Who::who(lore_ptr->msex), act, Who::who(lore_ptr->msex), 10 * lore_ptr->r_ptr->aaf)));
}
bool dead = (lore_ptr->r_ptr->max_num == 0);
if (lore_ptr->r_ptr->r_deaths) {
- hooked_roff(format(_("%^sはあなたの先祖を %d 人葬っている", "%^s has slain %d of your ancestors"), wd_he[lore_ptr->msex], lore_ptr->r_ptr->r_deaths));
+ hooked_roff(format(_("%^sはあなたの先祖を %d 人葬っている", "%^s has slain %d of your ancestors"), Who::who(lore_ptr->msex), lore_ptr->r_ptr->r_deaths));
if (dead) {
hooked_roff(
}
hooked_roff("\n");
- } else if (dead) {
- hooked_roff(_("あなたはこの仇敵をすでに葬り去っている。", "You have slain this foe. "));
+ } else {
+ if (dead)
+ hooked_roff(_("あなたはこの仇敵をすでに葬り去っている。", "You have slain this foe. "));
+ else
+ hooked_roff(_("この仇敵はまだ生きている!", "This foe is still alive! "));
+
hooked_roff("\n");
}
return TRUE;
}
-static bool display_killed(lore_type *lore_ptr)
+static void display_killed(lore_type *lore_ptr)
{
- if (lore_ptr->r_ptr->r_deaths == 0)
- return FALSE;
-
hooked_roff(_(format("このモンスターはあなたの先祖を %d 人葬っている", lore_ptr->r_ptr->r_deaths),
format("%d of your ancestors %s been killed by this creature, ", lore_ptr->r_ptr->r_deaths, plural(lore_ptr->r_ptr->r_deaths, "has", "have"))));
_("が、あなたの先祖はこのモンスターを少なくとも %d 体は倒している。", "and your ancestors have exterminated at least %d of the creatures. "),
lore_ptr->r_ptr->r_tkills));
} else {
- hooked_roff(format(_("が、まだ%sを倒したことはない。", "and %s is not ever known to have been defeated. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("が、まだ%sを倒したことはない。", "and %s is not ever known to have been defeated. "), Who::who(lore_ptr->msex)));
}
-
- hooked_roff("\n");
- return TRUE;
}
-void display_kill_numbers(lore_type *lore_ptr)
+static void display_no_killed(lore_type *lore_ptr)
{
- if ((lore_ptr->mode & 0x02) != 0)
- return;
-
- if (display_kill_unique(lore_ptr))
- return;
-
- if (display_killed(lore_ptr))
- return;
-
if (lore_ptr->r_ptr->r_pkills) {
hooked_roff(format(
_("あなたはこのモンスターを少なくとも %d 体は殺している。", "You have killed at least %d of these creatures. "), lore_ptr->r_ptr->r_pkills));
} else {
hooked_roff(_("このモンスターを倒したことはない。", "No battles to the death are recalled. "));
}
+}
+
+/*!
+ * @brief 生存数制限のあるモンスターの最大生存数を表示する
+ * @param lore_ptr モンスターの思い出構造体への参照ポインタ
+ * @return なし
+ * @detail
+ * 一度も倒したことのないモンスターの情報は不明。
+ */
+static void display_number_of_nazguls(lore_type *lore_ptr)
+{
+ if (lore_ptr->mode != MONSTER_LORE_DEBUG && lore_ptr->r_ptr->r_tkills == 0)
+ return;
+
+ int remain = lore_ptr->r_ptr->max_num;
+ int killed = lore_ptr->r_ptr->r_akills;
+ if (remain == 0) {
+#ifdef JP
+ hooked_roff(format("%sはかつて %ld 体存在した。", Who::who(lore_ptr->msex, (killed > 1)), killed));
+#else
+ hooked_roff(format("You already killed all %ld of %s. ", killed, Who::whom(lore_ptr->msex, (killed > 1))));
+#endif
+ } else {
+#ifdef JP
+ hooked_roff(format("%sはまだ %ld 体生きている。", Who::who(lore_ptr->msex, (remain + killed > 1)), remain));
+#else
+ concptr be = (remain > 1) ? "are" : "is";
+ hooked_roff(format("%ld of %s %s still alive. ", remain, Who::whom(lore_ptr->msex, (remain + killed > 1)), be));
+#endif
+ }
+}
+
+void display_kill_numbers(lore_type *lore_ptr)
+{
+ if ((lore_ptr->mode & 0x02) != 0)
+ return;
+
+ if (display_kill_unique(lore_ptr))
+ return;
+
+ if (lore_ptr->r_ptr->r_deaths == 0)
+ display_no_killed(lore_ptr);
+ else
+ display_killed(lore_ptr);
+
+ display_number_of_nazguls(lore_ptr);
hooked_roff("\n");
}
{
lore_ptr->old = FALSE;
if (lore_ptr->r_ptr->level == 0) {
- hooked_roff(format(_("%^sは町に住み", "%^s lives in the town"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは町に住み", "%^s lives in the town"), Who::who(lore_ptr->msex)));
lore_ptr->old = TRUE;
} else if (lore_ptr->r_ptr->r_tkills || lore_ptr->know_everything) {
if (depth_in_feet) {
hooked_roff(format(
- _("%^sは通常地下 %d フィートで出現し", "%^s is normally found at depths of %d feet"), wd_he[lore_ptr->msex], lore_ptr->r_ptr->level * 50));
+ _("%^sは通常地下 %d フィートで出現し", "%^s is normally found at depths of %d feet"), Who::who(lore_ptr->msex), lore_ptr->r_ptr->level * 50));
} else {
- hooked_roff(format(_("%^sは通常地下 %d 階で出現し", "%^s is normally found on dungeon level %d"), wd_he[lore_ptr->msex], lore_ptr->r_ptr->level));
+ hooked_roff(format(_("%^sは通常地下 %d 階で出現し", "%^s is normally found on dungeon level %d"), Who::who(lore_ptr->msex), lore_ptr->r_ptr->level));
}
lore_ptr->old = TRUE;
if (lore_ptr->old) {
hooked_roff(_("、", ", and "));
} else {
- hooked_roff(format(_("%^sは", "%^s "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s "), Who::who(lore_ptr->msex)));
lore_ptr->old = TRUE;
}
if (lore_ptr->old) {
hooked_roff(_("、しかし", ", but "));
} else {
- hooked_roff(format(_("%^sは", "%^s "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s "), Who::who(lore_ptr->msex)));
lore_ptr->old = TRUE;
}
{
if ((lore_ptr->flags2 & RF2_AURA_FIRE) && (lore_ptr->flags2 & RF2_AURA_ELEC) && (lore_ptr->flags3 & RF3_AURA_COLD))
hook_c_roff(
- TERM_VIOLET, format(_("%^sは炎と氷とスパークに包まれている。", "%^s is surrounded by flames, ice and electricity. "), wd_he[lore_ptr->msex]));
+ TERM_VIOLET, format(_("%^sは炎と氷とスパークに包まれている。", "%^s is surrounded by flames, ice and electricity. "), Who::who(lore_ptr->msex)));
else if ((lore_ptr->flags2 & RF2_AURA_FIRE) && (lore_ptr->flags2 & RF2_AURA_ELEC))
- hook_c_roff(TERM_L_RED, format(_("%^sは炎とスパークに包まれている。", "%^s is surrounded by flames and electricity. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_L_RED, format(_("%^sは炎とスパークに包まれている。", "%^s is surrounded by flames and electricity. "), Who::who(lore_ptr->msex)));
else if ((lore_ptr->flags2 & RF2_AURA_FIRE) && (lore_ptr->flags3 & RF3_AURA_COLD))
- hook_c_roff(TERM_BLUE, format(_("%^sは炎と氷に包まれている。", "%^s is surrounded by flames and ice. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_BLUE, format(_("%^sは炎と氷に包まれている。", "%^s is surrounded by flames and ice. "), Who::who(lore_ptr->msex)));
else if ((lore_ptr->flags3 & RF3_AURA_COLD) && (lore_ptr->flags2 & RF2_AURA_ELEC))
- hook_c_roff(TERM_L_GREEN, format(_("%^sは氷とスパークに包まれている。", "%^s is surrounded by ice and electricity. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_L_GREEN, format(_("%^sは氷とスパークに包まれている。", "%^s is surrounded by ice and electricity. "), Who::who(lore_ptr->msex)));
else if (lore_ptr->flags2 & RF2_AURA_FIRE)
- hook_c_roff(TERM_RED, format(_("%^sは炎に包まれている。", "%^s is surrounded by flames. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_RED, format(_("%^sは炎に包まれている。", "%^s is surrounded by flames. "), Who::who(lore_ptr->msex)));
else if (lore_ptr->flags3 & RF3_AURA_COLD)
- hook_c_roff(TERM_BLUE, format(_("%^sは氷に包まれている。", "%^s is surrounded by ice. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_BLUE, format(_("%^sは氷に包まれている。", "%^s is surrounded by ice. "), Who::who(lore_ptr->msex)));
else if (lore_ptr->flags2 & RF2_AURA_ELEC)
- hook_c_roff(TERM_L_BLUE, format(_("%^sはスパークに包まれている。", "%^s is surrounded by electricity. "), wd_he[lore_ptr->msex]));
+ hook_c_roff(TERM_L_BLUE, format(_("%^sはスパークに包まれている。", "%^s is surrounded by electricity. "), Who::who(lore_ptr->msex)));
}
void display_lore_this(player_type *player_ptr, lore_type *lore_ptr)
void display_monster_collective(lore_type *lore_ptr)
{
if ((lore_ptr->flags1 & RF1_ESCORT) || (lore_ptr->flags1 & RF1_ESCORTS) || lore_ptr->reinforce) {
- hooked_roff(format(_("%^sは通常護衛を伴って現れる。", "%^s usually appears with escorts. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは通常護衛を伴って現れる。", "%^s usually appears with escorts. "), Who::who(lore_ptr->msex)));
display_monster_escort_contents(lore_ptr);
} else if (lore_ptr->flags1 & RF1_FRIENDS) {
- hooked_roff(format(_("%^sは通常集団で現れる。", "%^s usually appears in groups. "), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは通常集団で現れる。", "%^s usually appears in groups. "), Who::who(lore_ptr->msex)));
}
}
if (lore_ptr->vn <= 0)
return;
- hooked_roff(format(_("%^sは", "%^s"), wd_he[lore_ptr->msex]));
+ hooked_roff(format(_("%^sは", "%^s"), Who::who(lore_ptr->msex)));
for (int n = 0; n < lore_ptr->vn; n++) {
#ifdef JP
if (n != lore_ptr->vn - 1) {
#include "info-reader/fixed-map-parser.h"
#include "inventory/inventory-slot-types.h"
#include "knowledge/knowledge-mutations.h"
+#include "mind/mind-elementalist.h"
#include "mutation/mutation-flag-types.h"
#include "object/object-info.h"
#include "object/object-kind.h"
*/
static void display_magic_realms(player_type *creature_ptr)
{
- if (creature_ptr->realm1 == 0) return;
+ if (creature_ptr->realm1 == 0)
+ return;
- char tmp[64];
- if (creature_ptr->realm2)
+ char tmp[64];
+ if (creature_ptr->pclass == CLASS_ELEMENTALIST)
+ sprintf(tmp, "%s", get_element_title(creature_ptr->realm1));
+ else if (creature_ptr->realm2)
sprintf(tmp, "%s, %s", realm_names[creature_ptr->realm1], realm_names[creature_ptr->realm2]);
else
strcpy(tmp, realm_names[creature_ptr->realm1]);
}
if ((caster_ptr->pclass == CLASS_MINDCRAFTER) || (caster_ptr->pclass == CLASS_BERSERKER) || (caster_ptr->pclass == CLASS_NINJA)
- || (caster_ptr->pclass == CLASS_MIRROR_MASTER) || (caster_ptr->pclass == CLASS_FORCETRAINER)) {
+ || (caster_ptr->pclass == CLASS_MIRROR_MASTER) || (caster_ptr->pclass == CLASS_FORCETRAINER) || caster_ptr->pclass == CLASS_ELEMENTALIST) {
PERCENTAGE minfail = 0;
PLAYER_LEVEL plev = caster_ptr->lev;
PERCENTAGE chance = 0;
use_mind = MIND_NINJUTSU;
use_hp = TRUE;
break;
+ case CLASS_ELEMENTALIST:
+ use_mind = MIND_ELEMENTAL;
+ break;
default:
use_mind = 0;
break;
TERM_LEN line = y;
monster_type *last_mons = NULL;
int n_same = 0;
- int i;
+ size_t i;
for (i = 0; i < monster_list.size(); i++) {
auto m_ptr = &floor_ptr->m_list[monster_list[i]];
if (is_pet(m_ptr))
m_ptr = &creature_ptr->current_floor_ptr->m_list[health_who];
if (current_world_ptr->wizard && creature_ptr->phase_out) {
- row = ROW_INFO - 2;
+ row = ROW_INFO - 1;
col = COL_INFO + 2;
term_putstr(col - 2, row, 12, TERM_WHITE, " / ");
}
/*!
- * @brief プレイヤーの行動速度を表示する / Prints the speed of a character. -CJS-
+ * @brief プレイヤーの行動速度を表示する / Prints the speed_value of a character. -CJS-
* @param player_ptr プレーヤーへの参照ポインタ
* @return なし
*/
TERM_LEN col_speed = wid + COL_SPEED;
TERM_LEN row_speed = hgt + ROW_SPEED;
- int i = player_ptr->pspeed;
- if (player_ptr->action == ACTION_SEARCH && !player_ptr->lightspeed)
- i += 10;
+ int speed_value = player_ptr->pspeed - 110;
floor_type *floor_ptr = player_ptr->current_floor_ptr;
bool is_player_fast = is_fast(player_ptr);
char buf[32] = "";
TERM_COLOR attr = TERM_WHITE;
- if (i > 110) {
+ if (speed_value > 0) {
if (player_ptr->riding) {
monster_type *m_ptr = &floor_ptr->m_list[player_ptr->riding];
if (monster_fast_remaining(m_ptr) && !monster_slow_remaining(m_ptr))
attr = TERM_VIOLET;
else
attr = TERM_L_GREEN;
- sprintf(buf, "%s(+%d)", (player_ptr->riding ? _("乗馬", "Ride") : _("加速", "Fast")), (i - 110));
- } else if (i < 110) {
+ sprintf(buf, "%s(+%d)", (player_ptr->riding ? _("乗馬", "Ride") : _("加速", "Fast")), speed_value);
+ } else if (speed_value < 0) {
if (player_ptr->riding) {
monster_type *m_ptr = &floor_ptr->m_list[player_ptr->riding];
if (monster_fast_remaining(m_ptr) && !monster_slow_remaining(m_ptr))
attr = TERM_VIOLET;
else
attr = TERM_L_UMBER;
- sprintf(buf, "%s(-%d)", (player_ptr->riding ? _("乗馬", "Ride") : _("減速", "Slow")), (110 - i));
+ sprintf(buf, "%s(%d)", (player_ptr->riding ? _("乗馬", "Ride") : _("減速", "Slow")), speed_value);
} else if (player_ptr->riding) {
attr = TERM_GREEN;
strcpy(buf, _("乗馬中", "Riding"));
{ "u", _("啓蒙(忍者以外)", "Wiz-lite all floor except Ninja") },
{ "v", _("特別品獲得ドロップ", "Drop special object") },
{ "w", _("啓蒙(忍者配慮)", "Wiz-lite all floor") },
+ { "W", _("願い", "Wishing") },
{ "x", _("経験値を得る(指定可)", "Get experience") },
{ "X", _("所持品を初期状態に戻す", "Return inventory to initial") },
{ "z", _("近隣のモンスター消去", "Terminate near monsters") },
case 'w':
wiz_lite(creature_ptr, (bool)(creature_ptr->pclass == CLASS_NINJA));
break;
+ case 'W':
+ do_cmd_wishing(creature_ptr, -1, TRUE, TRUE, TRUE);
+ break;
case 'x':
gain_exp(creature_ptr, command_arg ? command_arg : (creature_ptr->exp + 1));
break;
return _("変な色の", "Icky");
}
-spoiler_output_status spoil_mon_desc(concptr fname, bool show_all, race_flags8 RF8_flags)
+spoiler_output_status spoil_mon_desc(concptr fname, std::function<bool(const monster_race *)> filter_monster)
{
player_type dummy;
u16b why = 2;
for (int i = 0; i < n; i++) {
monster_race *r_ptr = &r_info[who[i]];
concptr name = (r_name + r_ptr->name);
- if (!show_all && none_bits(r_ptr->flags8, RF8_flags))
+ if (filter_monster && !filter_monster(r_ptr))
continue;
char name_buf[41];
}
/*!
- * @brief モンスター簡易情報のスポイラー出力を行うメインルーチン /
- * Create a spoiler file for monsters -BEN-
- * @param fname 生成ファイル名
- */
-spoiler_output_status spoil_mon_desc_all(concptr fname) { return spoil_mon_desc(fname, TRUE, RF8_WILD_ALL); }
-
-/*!
* @brief 関数ポインタ用の出力関数 /
* Hook function used in spoil_mon_info()
* @param attr 未使用
#include "system/angband.h"
#include "wizard/spoiler-util.h"
-enum race_flags8 : uint32_t;
+#include <functional>
+
+struct monster_race;
+
spoiler_output_status spoil_mon_desc_all(concptr fname);
-spoiler_output_status spoil_mon_desc(concptr fname, bool show_all, race_flags8 RF8_flags);
+spoiler_output_status spoil_mon_desc(concptr fname, std::function<bool(const monster_race *)> filter_monster = nullptr);
spoiler_output_status spoil_mon_info(concptr fname);
#include "wizard/wizard-item-modifier.h"
+#include "artifact/fixed-art-generator.h"
#include "artifact/random-art-generator.h"
#include "core/asking-player.h"
+#include "core/show-file.h"
#include "core/player-update-types.h"
#include "core/window-redrawer.h"
#include "flavor/flavor-describer.h"
#include "flavor/object-flavor-types.h"
#include "floor/floor-object.h"
+#include "game-option/cheat-options.h"
+#include "inventory/inventory-slot-types.h"
#include "io/input-key-acceptor.h"
#include "object-enchant/apply-magic.h"
#include "object-enchant/item-apply-magic.h"
+#include "object-enchant/object-ego.h"
+#include "object-enchant/tr-types.h"
#include "object-hook/hook-enchant.h"
+#include "object-hook/hook-checker.h"
#include "object/item-use-flags.h"
#include "object/object-flags.h"
#include "object/object-generator.h"
+#include "object/object-info.h"
#include "object/object-kind.h"
+#include "object/object-kind-hook.h"
#include "object/object-value.h"
+#include "util/string-processor.h"
#include "system/alloc-entries.h"
#include "system/artifact-type-definition.h"
#include "system/floor-type-definition.h"
#include "term/term-color-types.h"
#include "view/display-messages.h"
#include "util/bit-flags-calculator.h"
+#include "world/world.h"
+#include <vector>
#define K_MAX_DEPTH 110 /*!< アイテムの階層毎生成率を表示する最大階 */
msg_print("Changes ignored.");
}
}
+
+/*!
+ * @brief オブジェクトの装備スロットがエゴが有効なスロットかどうか判定
+ */
+static int is_slot_able_to_be_ego(player_type *caster_ptr, object_type *o_ptr)
+{
+ int slot = wield_slot(caster_ptr, o_ptr);
+
+ if (slot > -1)
+ return slot;
+
+ if ((o_ptr->tval == TV_SHOT) || (o_ptr->tval == TV_ARROW) || (o_ptr->tval == TV_BOLT))
+ return (INVEN_AMMO);
+
+ return (-1);
+}
+
+/*!
+ * @brief 願ったが消えてしまった場合のメッセージ
+ */
+static void wishing_puff_of_smoke(void)
+{
+ msg_print(_("何かが足下に転がってきたが、煙のように消えてしまった。",
+ "You feel something roll beneath your feet, but it disappears in a puff of smoke!"));
+}
+
+/*!
+ * @brief 願ったが消えてしまった場合のメッセージ
+ * @param caster_ptr 願ったプレイヤー情報への参照ポインタ
+ * @param prob ★などを願った場合の生成確率
+ * @param art_ok アーティファクトの生成を許すならTRUE
+ * @param ego_ok エゴの生成を許すならTRUE
+ * @param confirm 願わない場合に確認するかどうか
+ * @return 願った結果
+ */
+WishResult do_cmd_wishing(player_type *caster_ptr, int prob, bool allow_art, bool allow_ego, bool confirm)
+{
+ concptr fixed_str[] = {
+#ifdef JP
+ "燃えない",
+ "錆びない",
+ "腐食しない",
+ "安定した",
+#else
+ "rotproof",
+ "fireproof",
+ "rustproof",
+ "erodeproof",
+ "corrodeproof",
+ "fixed",
+#endif
+ NULL,
+ };
+
+ char buf[MAX_NLEN] = "\0";
+ char *str = buf;
+ object_type forge;
+ object_type *o_ptr = &forge;
+ char o_name[MAX_NLEN];
+
+ bool wish_art = FALSE;
+ bool wish_randart = FALSE;
+ bool wish_ego = FALSE;
+ bool exam_base = TRUE;
+ bool ok_art = (randint0(100) < prob) ? TRUE : FALSE;
+ bool ok_ego = (randint0(100) < 50 + prob) ? TRUE : FALSE;
+ bool must = (prob < 0) ? TRUE : FALSE;
+ bool blessed = FALSE;
+ bool fixed = TRUE;
+
+ while (1) {
+ if (get_string(_("何をお望み? ", "For what do you wish?"), buf, (MAX_NLEN - 1)))
+ break;
+ if (confirm) {
+ if (!get_check(_("何も願いません。本当によろしいですか?", "Do you wish nothing, really?")))
+ continue;
+ }
+ return WishResult::NOTHING;
+ }
+
+#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);
+#endif // !JP
+
+ str = rtrim(str);
+
+ if (!strncmp(str, _("祝福された", "blessed"), _(10, 7))) {
+ str = ltrim(str + _(10, 7));
+ blessed = TRUE;
+ }
+
+ for (int i = 0; fixed_str[i] != NULL; i++) {
+ int len = strlen(fixed_str[i]);
+ if (!strncmp(str, fixed_str[i], len)) {
+ str = ltrim(str + len);
+ fixed = TRUE;
+ break;
+ }
+ }
+
+#ifdef JP
+ if (!strncmp(str, "★", 2)) {
+ str = ltrim(str + 2);
+ wish_art = TRUE;
+ exam_base = FALSE;
+ } else
+#endif
+
+ if (!strncmp(str, _("☆", "The "), _(2, 4))) {
+ str = ltrim(str + _(2, 4));
+ wish_art = TRUE;
+ wish_randart = TRUE;
+ }
+
+ /* wishing random ego ? */
+ else if (!strncmp(str, _("高級な", "excellent "), _(6, 9))) {
+ str = ltrim(str + _(6, 9));
+ wish_ego = TRUE;
+ }
+
+ if (strlen(str) < 1) {
+ msg_print(_("名前がない!", "What?"));
+ return WishResult::NOTHING;
+ }
+
+ if (!allow_art && wish_art) {
+ msg_print(_("アーティファクトは願えない!", "You can not wish artifacts!"));
+ return WishResult::NOTHING;
+ }
+
+ if (cheat_xtra)
+ msg_format("Wishing %s....", buf);
+
+ std::vector<KIND_OBJECT_IDX> k_ids;
+ std::vector<EGO_IDX> e_ids;
+ if (exam_base) {
+ int len;
+ int max_len = 0;
+ for (KIND_OBJECT_IDX k = 1; k < max_k_idx; k++) {
+ object_kind *k_ptr = &k_info[k];
+ if (!k_ptr->name)
+ continue;
+
+ object_prep(caster_ptr, o_ptr, k);
+ describe_flavor(caster_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY | OD_STORE));
+#ifndef JP
+ str_tolower(o_name);
+#endif
+ if (cheat_xtra)
+ msg_format("Matching object No.%d %s", k, o_name);
+
+ len = strlen(o_name);
+
+ if (_(!strrncmp(str, o_name, len), !strncmp(str, o_name, len))) {
+ if (len > max_len) {
+ k_ids.push_back(k);
+ max_len = len;
+ }
+ }
+ }
+
+ if (allow_ego && k_ids.size() == 1) {
+ KIND_OBJECT_IDX k_idx = k_ids.back();
+ object_prep(caster_ptr, o_ptr, k_idx);
+
+ for (EGO_IDX k = 1; k < max_e_idx; k++) {
+ ego_item_type *e_ptr = &e_info[k];
+ if (!e_ptr->name)
+ continue;
+
+ strcpy(o_name, (e_name + e_ptr->name));
+#ifndef JP
+ str_tolower(o_name);
+#endif
+ if (cheat_xtra)
+ msg_format("Mathcing ego No.%d %s...", k, o_name);
+
+ if (_(!strncmp(str, o_name, strlen(o_name)), !strrncmp(str, o_name, strlen(o_name)))) {
+ if (is_slot_able_to_be_ego(caster_ptr, o_ptr) != e_ptr->slot)
+ continue;
+
+ e_ids.push_back(k);
+ }
+ }
+ }
+ }
+
+ std::vector<ARTIFACT_IDX> a_ids;
+
+ if (allow_art) {
+ char a_desc[MAX_NLEN] = "\0";
+ char *a_str = a_desc;
+
+ int len;
+ int mlen = 0;
+ for (ARTIFACT_IDX i = 1; i < max_a_idx; i++) {
+ artifact_type *a_ptr = &a_info[i];
+ if (!a_ptr->name)
+ continue;
+
+ KIND_OBJECT_IDX k_idx = lookup_kind(a_ptr->tval, a_ptr->sval);
+ if (!k_idx)
+ continue;
+
+ object_prep(caster_ptr, o_ptr, k_idx);
+ o_ptr->name1 = i;
+
+ describe_flavor(caster_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY | OD_STORE));
+#ifndef JP
+ str_tolower(o_name);
+#endif
+ a_str = a_desc;
+ strcpy(a_desc, a_name + a_ptr->name);
+
+ if (*a_str == '$')
+ a_str++;
+#ifdef JP
+ /* remove quotes */
+ if (!strncmp(a_str, "『", 2)) {
+ a_str += 2;
+ char *s = strstr(a_str, "』");
+ *s = '\0';
+ }
+ /* remove 'of' */
+ else {
+ int l = strlen(a_str);
+ if (!strrncmp(a_str, "の", 2)) {
+ a_str[l - 2] = '\0';
+ }
+ }
+#else
+ /* remove quotes */
+ if (a_str[0] == '\'') {
+ a_str += 1;
+ char *s = strchr(a_desc, '\'');
+ *s = '\0';
+ }
+ /* remove 'of ' */
+ else if (!strncmp(a_str, (const char *)"of ", 3)) {
+ a_str += 3;
+ }
+
+ str_tolower(a_str);
+#endif
+
+ if (cheat_xtra)
+ msg_format("Matching artifact No.%d %s(%s)", i, a_desc, _(&o_name[2], o_name));
+
+ std::vector<char *> l = { a_str, a_name + a_ptr->name, _(&o_name[2], o_name) };
+ for (size_t c = 0; c < l.size(); c++) {
+ if (!strcmp(str, l.at(c))) {
+ len = strlen(l.at(c));
+ if (len > mlen) {
+ a_ids.push_back(i);
+ mlen = len;
+ }
+ }
+ }
+ }
+ }
+
+ if (current_world_ptr->wizard && (a_ids.size() > 1 || e_ids.size() > 1)) {
+ msg_print(_("候補が多すぎる!", "Too many matches!"));
+ return WishResult::FAIL;
+ }
+
+ if (a_ids.size() == 1) {
+ ARTIFACT_IDX a_idx = a_ids.back();
+ if (must || (ok_art && !a_info[a_idx].cur_num)) {
+ create_named_art(caster_ptr, a_idx, caster_ptr->y, caster_ptr->x);
+ if (!current_world_ptr->wizard)
+ a_info[a_idx].cur_num = 1;
+ }
+ else
+ wishing_puff_of_smoke();
+ return WishResult::ARTIFACT;
+ }
+
+ if (!allow_ego && (wish_ego || e_ids.size() > 0)) {
+ msg_print(_("エゴアイテムは願えない!", "Can not wish ego item."));
+ return WishResult::NOTHING;
+ }
+
+ if (k_ids.size() == 1) {
+ KIND_OBJECT_IDX k_idx = k_ids.back();
+ object_kind *k_ptr = &k_info[k_idx];
+
+ artifact_type *a_ptr;
+ ARTIFACT_IDX a_idx = 0;
+ if (k_ptr->gen_flags.has(TRG::INSTA_ART)) {
+ for (ARTIFACT_IDX i = 1; i < max_a_idx; i++) {
+ a_ptr = &a_info[i];
+ if (a_ptr->tval != k_ptr->tval || a_ptr->sval != k_ptr->sval)
+ continue;
+ a_idx = i;
+ break;
+ }
+ }
+
+ if (a_idx > 0) {
+ a_ptr = &a_info[a_idx];
+ if (must || (ok_art && !a_ptr->cur_num)) {
+ create_named_art(caster_ptr, a_idx, caster_ptr->y, caster_ptr->x);
+ if (!current_world_ptr->wizard)
+ a_info[a_idx].cur_num = 1;
+ }
+ else
+ wishing_puff_of_smoke();
+ return WishResult::ARTIFACT;
+ }
+
+ if (wish_randart) {
+ if (must || ok_art) {
+ do {
+ object_prep(caster_ptr, o_ptr, k_idx);
+ apply_magic(caster_ptr, o_ptr, k_ptr->level, (AM_SPECIAL | AM_NO_FIXED_ART));
+ } while (!o_ptr->art_name || o_ptr->name1 || o_ptr->name2 || object_is_cursed(o_ptr));
+
+ if (o_ptr->art_name)
+ drop_near(caster_ptr, o_ptr, -1, caster_ptr->y, caster_ptr->x);
+ } else {
+ wishing_puff_of_smoke();
+ }
+ return WishResult::ARTIFACT;
+ }
+
+ WishResult res = WishResult::NOTHING;
+ if (allow_ego && (wish_ego || e_ids.size() > 0)) {
+ if (must || ok_ego) {
+ int max_roll = 1000;
+ int i = 0;
+ for (i = 0; i < max_roll; i++) {
+ object_prep(caster_ptr, o_ptr, k_idx);
+ (void)apply_magic(caster_ptr, o_ptr, k_ptr->level, (AM_GREAT | AM_NO_FIXED_ART));
+
+ if (o_ptr->name1 || o_ptr->art_name)
+ continue;
+
+ if (wish_ego)
+ break;
+
+ EGO_IDX e_idx = 0;
+ for (auto e : e_ids) {
+ if (o_ptr->name2 == e) {
+ e_idx = e;
+ break;
+ }
+ }
+
+ if (e_idx != 0)
+ break;
+ }
+
+ if (i == max_roll) {
+ msg_print(_("失敗!もう一度願ってみてください。", "Failed! Try again."));
+ return WishResult::FAIL;
+ }
+ } else {
+ wishing_puff_of_smoke();
+ }
+
+ res = WishResult::EGO;
+ } else {
+ for (int i = 0; i < 100; i++) {
+ object_prep(caster_ptr, o_ptr, k_idx);
+ apply_magic(caster_ptr, o_ptr, 0, (AM_NO_FIXED_ART));
+ if (!object_is_cursed(o_ptr))
+ break;
+ }
+ res = WishResult::NORMAL;
+ }
+
+ if (blessed && wield_slot(caster_ptr, o_ptr) != -1)
+ add_flag(o_ptr->art_flags, TR_BLESSED);
+
+ if (fixed && wield_slot(caster_ptr, o_ptr) != -1) {
+ add_flag(o_ptr->art_flags, TR_IGNORE_ACID);
+ add_flag(o_ptr->art_flags, TR_IGNORE_FIRE);
+ }
+
+ (void)drop_near(caster_ptr, o_ptr, -1, caster_ptr->y, caster_ptr->x);
+
+ return res;
+ }
+
+ msg_print(_("うーん、そんなものは存在しないようだ。", "Ummmm, that is not existing..."));
+ return WishResult::FAIL;
+}
#include "system/angband.h"
+enum class WishResult { FAIL = -1, NOTHING = 0, NORMAL = 1, EGO = 2, ARTIFACT = 3, MAX };
+
void wiz_modify_item(player_type *creature_ptr);
+WishResult do_cmd_wishing(player_type *caster_ptr, int prob, bool art_ok, bool ego_ok, bool confirm);
#include "io/input-key-acceptor.h"
#include "main/sound-of-music.h"
#include "monster-race/monster-race.h"
+#include "monster-race/race-flags7.h"
#include "monster-race/race-flags8.h"
#include "system/angband-version.h"
#include "term/screen-processor.h"
#include "util/angband-files.h"
+#include "util/bit-flags-calculator.h"
#include "util/int-char-converter.h"
#include "util/sort.h"
#include "view/display-messages.h"
return SPOILER_OUTPUT_SUCCESS;
}
+spoiler_output_status spoil_categorized_mon_desc()
+{
+ spoiler_output_status status = spoil_mon_desc("mon-desc-ridable.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags7, RF7_RIDING); });
+
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-wildonly.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_ONLY); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-town.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_TOWN); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-shore.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_SHORE); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-ocean.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_OCEAN); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-waste.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_WASTE); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-wood.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_WOOD); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-volcano.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_VOLCANO); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-mountain.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_MOUNTAIN); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-grass.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_GRASS); });
+ if (status == SPOILER_OUTPUT_SUCCESS)
+ status = spoil_mon_desc("mon-desc-wildall.txt", [](const monster_race *r_ptr) { return any_bits(r_ptr->flags8, RF8_WILD_ALL); });
+
+ return status;
+}
+
/*!
* @brief スポイラー出力を行うコマンドのメインルーチン /
* Create Spoiler files -BEN-
prt("(1) Brief Object Info (obj-desc.txt)", 5, 5);
prt("(2) Brief Artifact Info (artifact.txt)", 6, 5);
prt("(3) Brief Monster Info (mon-desc.txt)", 7, 5);
- prt("(4) Full Monster Info (mon-info.txt)", 8, 5);
- prt("(5) Monster Evolution Info (mon-evol.txt)", 9, 5);
+ prt("(4) Brief Categorized Monster Info (mon-desc-*.txt)", 8, 5);
+ prt("(5) Full Monster Info (mon-info.txt)", 9, 5);
+ prt("(6) Monster Evolution Info (mon-evol.txt)", 10, 5);
prt(_("コマンド:", "Command: "), _(18, 12), 0);
switch (inkey()) {
case ESCAPE:
status = spoil_fixed_artifact("artifact.txt");
break;
case '3':
- status = spoil_mon_desc_all("mon-desc.txt");
+ status = spoil_mon_desc("mon-desc.txt");
break;
case '4':
- status = spoil_mon_info("mon-info.txt");
+ status = spoil_categorized_mon_desc();
break;
case '5':
+ status = spoil_mon_info("mon-info.txt");
+ break;
+ case '6':
status = spoil_mon_evol("mon-evol.txt");
break;
default:
case SPOILER_OUTPUT_SUCCESS:
msg_print("Successfully created a spoiler file.");
break;
+ case SPOILER_OUTPUT_CANCEL:
+ break;
}
msg_erase();
}
if (status != SPOILER_OUTPUT_SUCCESS)
return status;
- status = spoil_mon_desc_all("mon-desc.txt");
+ status = spoil_mon_desc("mon-desc.txt");
if (status != SPOILER_OUTPUT_SUCCESS)
return status;
- status = spoil_mon_desc("mon-desc-wildonly.txt", FALSE, RF8_WILD_ONLY);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-town.txt", FALSE, RF8_WILD_TOWN);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-shore.txt", FALSE, RF8_WILD_SHORE);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-ocean.txt", FALSE, RF8_WILD_OCEAN);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-waste.txt", FALSE, RF8_WILD_WASTE);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-wood.txt", FALSE, RF8_WILD_WOOD);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-volcano.txt", FALSE, RF8_WILD_VOLCANO);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-mountain.txt", FALSE, RF8_WILD_MOUNTAIN);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-grass.txt", FALSE, RF8_WILD_GRASS);
- if (status != SPOILER_OUTPUT_SUCCESS)
- return status;
- status = spoil_mon_desc("mon-desc-wildall.txt", FALSE, RF8_WILD_ALL);
+ status = spoil_categorized_mon_desc();
if (status != SPOILER_OUTPUT_SUCCESS)
return status;
#include "object/object-kind.h"
#include "system/alloc-entries.h"
#include "system/floor-type-definition.h"
+#include "util/probability-table.h"
#include "view/display-messages.h"
#include "world/world.h"
+#include <iterator>
/*!
* @brief グローバルオブジェクト配列から空きを取得する /
*/
OBJECT_IDX get_obj_num(player_type *owner_ptr, DEPTH level, BIT_FLAGS mode)
{
- int i, j, p;
- KIND_OBJECT_IDX k_idx;
- long value, total;
- object_kind *k_ptr;
alloc_entry *table = alloc_kind_table;
if (level > MAX_DEPTH - 1)
}
}
- total = 0L;
- for (i = 0; i < alloc_kind_size; i++) {
+ // 候補の確率テーブル生成
+ ProbabilityTable<int> prob_table;
+ for (int i = 0; i < alloc_kind_size; i++) {
if (table[i].level > level)
break;
- table[i].prob3 = 0;
- k_idx = table[i].index;
- k_ptr = &k_info[k_idx];
+ KIND_OBJECT_IDX k_idx = table[i].index;
+ object_kind *k_ptr = &k_info[k_idx];
if ((mode & AM_FORBID_CHEST) && (k_ptr->tval == TV_CHEST))
continue;
- table[i].prob3 = table[i].prob2;
- total += table[i].prob3;
+ prob_table.entry_item(i, table[i].prob2);
}
- if (total <= 0)
+ // 候補なし
+ if (prob_table.empty())
return 0;
- value = randint0(total);
- for (i = 0; i < alloc_kind_size; i++) {
- if (value < table[i].prob3)
- break;
-
- value = value - table[i].prob3;
- }
-
- p = randint0(100);
- if (p < 60) {
- j = i;
- value = randint0(total);
- for (i = 0; i < alloc_kind_size; i++) {
- if (value < table[i].prob3)
- break;
-
- value = value - table[i].prob3;
- }
+ // 40%で1回、50%で2回、10%で3回抽選し、その中で一番レベルが高いアイテムを選択する
+ int n = 1;
- if (table[i].level < table[j].level)
- i = j;
- }
+ const int p = randint0(100);
+ if (p < 60)
+ n++;
+ if (p < 10)
+ n++;
- if (p >= 10)
- return (table[i].index);
+ std::vector<int> result;
+ ProbabilityTable<int>::lottery(std::back_inserter(result), prob_table, n);
- j = i;
- value = randint0(total);
- for (i = 0; i < alloc_kind_size; i++) {
- if (value < table[i].prob3)
- break;
-
- value = value - table[i].prob3;
- }
+ auto it = std::max_element(result.begin(), result.end(), [table](int a, int b) { return table[a].level < table[b].level; });
- if (table[i].level < table[j].level)
- i = j;
- return (table[i].index);
+ return table[*it].index;
}
typedef struct world_type {
- POSITION max_wild_x; /*!< Maximum size of the wilderness */
- POSITION max_wild_y; /*!< Maximum size of the wilderness */
- GAME_TURN game_turn; /*!< 画面表示上のゲーム時間基準となるターン / Current game turn */
- GAME_TURN game_turn_limit; /*!< game_turnの最大値 / Limit of game_turn */
- GAME_TURN dungeon_turn; /*!< NASTY生成の計算に関わる内部ターン値 / Game turn in dungeon */
- GAME_TURN dungeon_turn_limit; /*!< dungeon_turnの最大値 / Limit of game_turn in dungeon */
- GAME_TURN arena_start_turn; /*!< 闘技場賭博の開始ターン値 */
- u32b start_time;
- u16b noscore; /* Cheating flags */
- u16b total_winner; /* Total winner */
+ POSITION max_wild_x; /*!< Maximum size of the wilderness */
+ POSITION max_wild_y; /*!< Maximum size of the wilderness */
+ GAME_TURN game_turn; /*!< 画面表示上のゲーム時間基準となるターン / Current game turn */
+ GAME_TURN game_turn_limit; /*!< game_turnの最大値 / Limit of game_turn */
+ GAME_TURN dungeon_turn; /*!< NASTY生成の計算に関わる内部ターン値 / Game turn in dungeon */
+ GAME_TURN dungeon_turn_limit; /*!< dungeon_turnの最大値 / Limit of game_turn in dungeon */
+ GAME_TURN arena_start_turn; /*!< 闘技場賭博の開始ターン値 */
+ u32b start_time;
+ u16b noscore; /* Cheating flags */
+ u16b total_winner; /* Total winner */
- MONSTER_IDX timewalk_m_idx; /*!< 現在時間停止を行っているモンスターのID */
+ MONSTER_IDX timewalk_m_idx; /*!< 現在時間停止を行っているモンスターのID */
- MONRACE_IDX bounty_r_idx[MAX_BOUNTY];
+ MONRACE_IDX bounty_r_idx[MAX_BOUNTY];
+ MONSTER_IDX today_mon; //!< 実際の日替わり賞金首
- u32b play_time; /*!< 実プレイ時間 */
+ u32b play_time; /*!< 実プレイ時間 */
- u32b seed_flavor; /* Hack -- consistent object colors */
- u32b seed_town; /* Hack -- consistent town layout */
+ u32b seed_flavor; /* Hack -- consistent object colors */
+ u32b seed_town; /* Hack -- consistent town layout */
- bool is_loading_now; /*!< ロード処理中フラグ...ロード直後にcalc_bonus()時の徳変化、及びsanity_blast()による異常を抑止する */
+ bool is_loading_now; /*!< ロード処理中フラグ...ロード直後にcalc_bonus()時の徳変化、及びsanity_blast()による異常を抑止する */
- /*
- * Savefile version
- */
- byte h_ver_major; /* Savefile version for Hengband 1.1.1 and later */
- byte h_ver_minor;
- byte h_ver_patch;
- byte h_ver_extra;
+ /*
+ * Savefile version
+ */
+ byte h_ver_major; /* Savefile version for Hengband 1.1.1 and later */
+ byte h_ver_minor;
+ byte h_ver_patch;
+ byte h_ver_extra;
- byte sf_extra; /* Savefile's encoding key */
+ byte sf_extra; /* Savefile's encoding key */
- byte z_major; /* Savefile version for Hengband */
- byte z_minor;
- byte z_patch;
+ byte z_major; /* Savefile version for Hengband */
+ byte z_minor;
+ byte z_patch;
- /*
- * Savefile information
- */
- u32b sf_system; /* Operating system info */
- u32b sf_when; /* Time when savefile created */
- u16b sf_lives; /* Number of past "lives" with this file */
- u16b sf_saves; /* Number of "saves" during this life */
+ /*
+ * Savefile information
+ */
+ u32b sf_system; /* Operating system info */
+ u32b sf_when; /* Time when savefile created */
+ u16b sf_lives; /* Number of past "lives" with this file */
+ u16b sf_saves; /* Number of "saves" during this life */
- bool character_generated; /* The character exists */
- bool character_dungeon; /* The character has a dungeon */
- bool character_loaded; /* The character was loaded from a savefile */
- bool character_saved; /* The character was just saved to a savefile */
+ bool character_generated; /* The character exists */
+ bool character_dungeon; /* The character has a dungeon */
+ bool character_loaded; /* The character was loaded from a savefile */
+ bool character_saved; /* The character was just saved to a savefile */
- byte character_icky_depth; /* The game is in an icky full screen mode */
- bool character_xtra; /* The game is in an icky startup mode */
+ byte character_icky_depth; /* The game is in an icky full screen mode */
+ bool character_xtra; /* The game is in an icky startup mode */
- bool creating_savefile; /* New savefile is currently created */
+ bool creating_savefile; /* New savefile is currently created */
- bool wizard; /* This world under wizard mode */
+ bool wizard; /* This world under wizard mode */
- OBJECT_IDX max_o_idx; /*!< Maximum number of objects in the level */
- MONSTER_IDX max_m_idx; /*!< Maximum number of monsters in the level */
+ OBJECT_IDX max_o_idx; /*!< Maximum number of objects in the level */
+ MONSTER_IDX max_m_idx; /*!< Maximum number of monsters in the level */
- DUNGEON_IDX max_d_idx;
+ DUNGEON_IDX max_d_idx;
} world_type;