- added NBlood source.

This commit is contained in:
Christoph Oelckers 2019-09-20 00:42:45 +02:00
parent 23bc385393
commit 0254bf82d3
207 changed files with 74689 additions and 407 deletions

3
.gitignore vendored
View file

@ -53,3 +53,6 @@ project.xcworkspace/
*.dSYM/
.DS_Store
Platform/Windows/Build
Platform/Windows/Win32
Platform/Windows/x64

View file

@ -29,6 +29,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glad", "glad.vcxproj", "{6A
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rednukem", "rednukem.vcxproj", "{44C4B4F0-B489-4612-B9C7-A38503B7FB67}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsmackerdec", "libsmackerdec.vcxproj", "{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nblood", "nblood.vcxproj", "{5407CB5A-4B15-41FA-B79B-8B386A14D275}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -101,6 +105,22 @@ Global
{44C4B4F0-B489-4612-B9C7-A38503B7FB67}.Release|Win32.Build.0 = Release|Win32
{44C4B4F0-B489-4612-B9C7-A38503B7FB67}.Release|x64.ActiveCfg = Release|x64
{44C4B4F0-B489-4612-B9C7-A38503B7FB67}.Release|x64.Build.0 = Release|x64
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}.Debug|Win32.ActiveCfg = Debug|Win32
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}.Debug|Win32.Build.0 = Debug|Win32
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}.Debug|x64.ActiveCfg = Debug|x64
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}.Debug|x64.Build.0 = Debug|x64
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}.Release|Win32.ActiveCfg = Release|Win32
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}.Release|Win32.Build.0 = Release|Win32
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}.Release|x64.ActiveCfg = Release|x64
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}.Release|x64.Build.0 = Release|x64
{5407CB5A-4B15-41FA-B79B-8B386A14D275}.Debug|Win32.ActiveCfg = Debug|Win32
{5407CB5A-4B15-41FA-B79B-8B386A14D275}.Debug|Win32.Build.0 = Debug|Win32
{5407CB5A-4B15-41FA-B79B-8B386A14D275}.Debug|x64.ActiveCfg = Debug|x64
{5407CB5A-4B15-41FA-B79B-8B386A14D275}.Debug|x64.Build.0 = Debug|x64
{5407CB5A-4B15-41FA-B79B-8B386A14D275}.Release|Win32.ActiveCfg = Release|Win32
{5407CB5A-4B15-41FA-B79B-8B386A14D275}.Release|Win32.Build.0 = Release|Win32
{5407CB5A-4B15-41FA-B79B-8B386A14D275}.Release|x64.ActiveCfg = Release|x64
{5407CB5A-4B15-41FA-B79B-8B386A14D275}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -114,6 +134,8 @@ Global
{32D4CF70-A3D6-4CEA-81D7-64C743980276} = {8BD117A0-7FA2-44B0-88A5-29D6C220601E}
{6AC1D997-8DAE-4343-8DD8-DA2A1CA63212} = {8BD117A0-7FA2-44B0-88A5-29D6C220601E}
{44C4B4F0-B489-4612-B9C7-A38503B7FB67} = {18C3CB5F-1DE6-4CFE-B7F7-ABE824222E1C}
{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45} = {8BD117A0-7FA2-44B0-88A5-29D6C220601E}
{5407CB5A-4B15-41FA-B79B-8B386A14D275} = {18C3CB5F-1DE6-4CFE-B7F7-ABE824222E1C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0346D2C0-3EB9-4AFB-973F-2904758D6C02}

View file

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\source\libsmackerdec\include\BitReader.h" />
<ClInclude Include="..\..\source\libsmackerdec\include\FileStream.h" />
<ClInclude Include="..\..\source\libsmackerdec\include\HuffmanVLC.h" />
<ClInclude Include="..\..\source\libsmackerdec\include\LogError.h" />
<ClInclude Include="..\..\source\libsmackerdec\include\SmackerDecoder.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\source\libsmackerdec\src\BitReader.cpp" />
<ClCompile Include="..\..\source\libsmackerdec\src\FileStream.cpp" />
<ClCompile Include="..\..\source\libsmackerdec\src\HuffmanVLC.cpp" />
<ClCompile Include="..\..\source\libsmackerdec\src\LogError.cpp" />
<ClCompile Include="..\..\source\libsmackerdec\src\SmackerDecoder.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{598F0D83-2C1B-4F7C-B04D-7FDD471C8C45}</ProjectGuid>
<RootNamespace>libsmackerdec</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="props\build_x64.props" />
<Import Project="props\build_common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="props\build_x64.props" />
<Import Project="props\build_common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="props\build_x86.props" />
<Import Project="props\build_common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="props\build_x86.props" />
<Import Project="props\build_common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)Build\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\Build\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)Build\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\Build\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)Build\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\Build\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)Build\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\Build\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<LanguageStandard>stdcpp14</LanguageStandard>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<DebugInformationFormat>None</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<LanguageStandard>stdcpp14</LanguageStandard>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<OmitFramePointers>false</OmitFramePointers>
<FunctionLevelLinking>true</FunctionLevelLinking>
<LanguageStandard>stdcpp14</LanguageStandard>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<LanguageStandard>stdcpp14</LanguageStandard>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<DebugInformationFormat>None</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files" />
<Filter Include="Source Files" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\source\libsmackerdec\include\BitReader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\libsmackerdec\include\FileStream.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\libsmackerdec\include\HuffmanVLC.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\libsmackerdec\include\LogError.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\libsmackerdec\include\SmackerDecoder.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\source\libsmackerdec\src\BitReader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\libsmackerdec\src\FileStream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\libsmackerdec\src\HuffmanVLC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\libsmackerdec\src\LogError.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\libsmackerdec\src\SmackerDecoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,365 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{5407CB5A-4B15-41FA-B79B-8B386A14D275}</ProjectGuid>
<RootNamespace>nblood</RootNamespace>
<Keyword>MakeFileProj</Keyword>
<PlatformToolset>v142</PlatformToolset>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<ProjectName>nblood</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="props\build_x64.props" />
<Import Project="props\build_common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="props\build_x64.props" />
<Import Project="props\build_common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="props\build_x86.props" />
<Import Project="props\build_common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="props\build_x86.props" />
<Import Project="props\build_common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
<OutDir>$(SolutionDir)..\..\</OutDir>
<IntDir>$(Platform)\Build\$(ProjectName)\$(Configuration)\</IntDir>
<NMakeIncludeSearchPath>$(NMakeIncludeSearchPath);..\..\source\build\include;..\..\source\mact\include;..\..\source\audiolib\include;..\..\source\enet\include;..\..\platform\windows\include</NMakeIncludeSearchPath>
<NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f msvc.mak DEBUG=1 WINBITS=32 RENDERTYPE=SDL</NMakeBuildCommandLine>
<NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f msvc.mak veryclean all DEBUG=1 WINBITS=32 RENDERTYPE=SDL</NMakeReBuildCommandLine>
<NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f msvc.mak veryclean DEBUG=1 WINBITS=32 RENDERTYPE=SDL</NMakeCleanCommandLine>
<NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">USE_OPENGL;POLYMER;SDL_USEFOLDER;SDL_TARGET=2</NMakePreprocessorDefinitions>
<NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f msvc.mak WINBITS=32 RENDERTYPE=SDL</NMakeBuildCommandLine>
<NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f msvc.mak veryclean all WINBITS=32 RENDERTYPE=SDL</NMakeReBuildCommandLine>
<NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f msvc.mak veryclean WINBITS=32 RENDERTYPE=SDL</NMakeCleanCommandLine>
<NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">USE_OPENGL;POLYMER;SDL_USEFOLDER;SDL_TARGET=2</NMakePreprocessorDefinitions>
<NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f msvc.mak DEBUG=1 WINBITS=64 RENDERTYPE=SDL</NMakeBuildCommandLine>
<NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f msvc.mak veryclean all DEBUG=1 WINBITS=64 RENDERTYPE=SDL</NMakeReBuildCommandLine>
<NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f msvc.mak veryclean DEBUG=1 WINBITS=64 RENDERTYPE=SDL</NMakeCleanCommandLine>
<NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">USE_OPENGL;POLYMER;NOASM;SDL_USEFOLDER;SDL_TARGET=2</NMakePreprocessorDefinitions>
<NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f msvc.mak WINBITS=64 RENDERTYPE=SDL</NMakeBuildCommandLine>
<NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f msvc.mak veryclean all WINBITS=64 RENDERTYPE=SDL</NMakeReBuildCommandLine>
<NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f msvc.mak veryclean WINBITS=64 RENDERTYPE=SDL</NMakeCleanCommandLine>
<NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">USE_OPENGL;POLYMER;NOASM;SDL_USEFOLDER;SDL_TARGET=2</NMakePreprocessorDefinitions>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<GenerateManifest>false</GenerateManifest>
<EmbedManifest>false</EmbedManifest>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
<EmbedManifest>false</EmbedManifest>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<EmbedManifest>false</EmbedManifest>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<EmbedManifest>false</EmbedManifest>
<LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Link>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<SupportJustMyCode>true</SupportJustMyCode>
<FunctionLevelLinking>true</FunctionLevelLinking>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp14</LanguageStandard>
<Optimization>Disabled</Optimization>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;RENDERTYPESDL=1;MIXERTYPEWIN=1;SDL_USEFOLDER;SDL_TARGET=2;USE_OPENGL=1;POLYMER=1;STARTUP_WINDOW;USE_LIBVPX;HAVE_VORBIS;HAVE_XMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp14</LanguageStandard>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<DebugInformationFormat>None</DebugInformationFormat>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<OmitFramePointers>false</OmitFramePointers>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<SupportJustMyCode>true</SupportJustMyCode>
<FunctionLevelLinking>true</FunctionLevelLinking>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp14</LanguageStandard>
<Optimization>Disabled</Optimization>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp14</LanguageStandard>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
<DebugInformationFormat>None</DebugInformationFormat>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\source\blood\rsrc\eduke32_icon.c" />
<ClCompile Include="..\..\source\blood\src\actor.cpp" />
<ClCompile Include="..\..\source\blood\src\ai.cpp" />
<ClCompile Include="..\..\source\blood\src\aibat.cpp" />
<ClCompile Include="..\..\source\blood\src\aibeast.cpp" />
<ClCompile Include="..\..\source\blood\src\aiboneel.cpp" />
<ClCompile Include="..\..\source\blood\src\aiburn.cpp" />
<ClCompile Include="..\..\source\blood\src\aicaleb.cpp" />
<ClCompile Include="..\..\source\blood\src\aicerber.cpp" />
<ClCompile Include="..\..\source\blood\src\aicult.cpp" />
<ClCompile Include="..\..\source\blood\src\aigarg.cpp" />
<ClCompile Include="..\..\source\blood\src\aighost.cpp" />
<ClCompile Include="..\..\source\blood\src\aigilbst.cpp" />
<ClCompile Include="..\..\source\blood\src\aihand.cpp" />
<ClCompile Include="..\..\source\blood\src\aihound.cpp" />
<ClCompile Include="..\..\source\blood\src\aiinnoc.cpp" />
<ClCompile Include="..\..\source\blood\src\aipod.cpp" />
<ClCompile Include="..\..\source\blood\src\airat.cpp" />
<ClCompile Include="..\..\source\blood\src\aispid.cpp" />
<ClCompile Include="..\..\source\blood\src\aitchern.cpp" />
<ClCompile Include="..\..\source\blood\src\aiunicult.cpp" />
<ClCompile Include="..\..\source\blood\src\aizomba.cpp" />
<ClCompile Include="..\..\source\blood\src\aizombf.cpp" />
<ClCompile Include="..\..\source\blood\src\asound.cpp" />
<ClCompile Include="..\..\source\blood\src\blood.cpp" />
<ClCompile Include="..\..\source\blood\src\callback.cpp" />
<ClCompile Include="..\..\source\blood\src\choke.cpp" />
<ClCompile Include="..\..\source\blood\src\common.cpp" />
<ClCompile Include="..\..\source\blood\src\config.cpp" />
<ClCompile Include="..\..\source\blood\src\controls.cpp" />
<ClCompile Include="..\..\source\blood\src\credits.cpp" />
<ClCompile Include="..\..\source\blood\src\db.cpp" />
<ClCompile Include="..\..\source\blood\src\demo.cpp" />
<ClCompile Include="..\..\source\blood\src\dude.cpp" />
<ClCompile Include="..\..\source\blood\src\endgame.cpp" />
<ClCompile Include="..\..\source\blood\src\eventq.cpp" />
<ClCompile Include="..\..\source\blood\src\fire.cpp" />
<ClCompile Include="..\..\source\blood\src\fx.cpp" />
<ClCompile Include="..\..\source\blood\src\gamemenu.cpp" />
<ClCompile Include="..\..\source\blood\src\gameutil.cpp" />
<ClCompile Include="..\..\source\blood\src\getopt.cpp" />
<ClCompile Include="..\..\source\blood\src\gib.cpp" />
<ClCompile Include="..\..\source\blood\src\globals.cpp" />
<ClCompile Include="..\..\source\blood\src\gmtimbre.cpp" />
<ClCompile Include="..\..\source\blood\src\inifile.cpp" />
<ClCompile Include="..\..\source\blood\src\iob.cpp" />
<ClCompile Include="..\..\source\blood\src\levels.cpp" />
<ClCompile Include="..\..\source\blood\src\loadsave.cpp" />
<ClCompile Include="..\..\source\blood\src\map2d.cpp" />
<ClCompile Include="..\..\source\blood\src\menu.cpp" />
<ClCompile Include="..\..\source\blood\src\messages.cpp" />
<ClCompile Include="..\..\source\blood\src\midi.cpp" />
<ClCompile Include="..\..\source\blood\src\mirrors.cpp" />
<ClCompile Include="..\..\source\blood\src\misc.cpp" />
<ClCompile Include="..\..\source\blood\src\mpu401.cpp" />
<ClCompile Include="..\..\source\blood\src\music.cpp" />
<ClCompile Include="..\..\source\blood\src\network.cpp" />
<ClCompile Include="..\..\source\blood\src\osdcmd.cpp" />
<ClCompile Include="..\..\source\blood\src\player.cpp" />
<ClCompile Include="..\..\source\blood\src\pqueue.cpp" />
<ClCompile Include="..\..\source\blood\src\qav.cpp" />
<ClCompile Include="..\..\source\blood\src\qheap.cpp" />
<ClCompile Include="..\..\source\blood\src\replace.cpp" />
<ClCompile Include="..\..\source\blood\src\resource.cpp" />
<ClCompile Include="..\..\source\blood\src\screen.cpp" />
<ClCompile Include="..\..\source\blood\src\sectorfx.cpp" />
<ClCompile Include="..\..\source\blood\src\seq.cpp" />
<ClCompile Include="..\..\source\blood\src\sfx.cpp" />
<ClCompile Include="..\..\source\blood\src\sound.cpp" />
<ClCompile Include="..\..\source\blood\src\startwin.game.cpp" />
<ClCompile Include="..\..\source\blood\src\tile.cpp" />
<ClCompile Include="..\..\source\blood\src\trig.cpp" />
<ClCompile Include="..\..\source\blood\src\triggers.cpp" />
<ClCompile Include="..\..\source\blood\src\view.cpp" />
<ClCompile Include="..\..\source\blood\src\warp.cpp" />
<ClCompile Include="..\..\source\blood\src\weapon.cpp" />
<ClCompile Include="..\..\source\blood\src\winbits.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="audiolib.vcxproj">
<Project>{0029c61b-b63d-4e61-99f2-f4e49aabfc47}</Project>
</ProjectReference>
<ProjectReference Include="build.vcxproj">
<Project>{dbecb851-5624-4fa8-9a9d-7169d0f12ff1}</Project>
</ProjectReference>
<ProjectReference Include="enet.vcxproj">
<Project>{a68cc5e4-567a-44c8-94fe-c1de09aeeb40}</Project>
</ProjectReference>
<ProjectReference Include="glad.vcxproj">
<Project>{6ac1d997-8dae-4343-8dd8-da2a1ca63212}</Project>
</ProjectReference>
<ProjectReference Include="libsmackerdec.vcxproj">
<Project>{598f0d83-2c1b-4f7c-b04d-7fdd471c8c45}</Project>
</ProjectReference>
<ProjectReference Include="libxmp-lite.vcxproj">
<Project>{32d4cf70-a3d6-4cea-81d7-64c743980276}</Project>
</ProjectReference>
<ProjectReference Include="mact.vcxproj">
<Project>{bcde1852-e2c6-4abb-84fb-5cd431764a9a}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\source\blood\rsrc\gameres.rc">
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\source\blood\src\actor.h" />
<ClInclude Include="..\..\source\blood\src\ai.h" />
<ClInclude Include="..\..\source\blood\src\aibat.h" />
<ClInclude Include="..\..\source\blood\src\aibeast.h" />
<ClInclude Include="..\..\source\blood\src\aiboneel.h" />
<ClInclude Include="..\..\source\blood\src\aiburn.h" />
<ClInclude Include="..\..\source\blood\src\aicaleb.h" />
<ClInclude Include="..\..\source\blood\src\aicerber.h" />
<ClInclude Include="..\..\source\blood\src\aicult.h" />
<ClInclude Include="..\..\source\blood\src\aigarg.h" />
<ClInclude Include="..\..\source\blood\src\aighost.h" />
<ClInclude Include="..\..\source\blood\src\aigilbst.h" />
<ClInclude Include="..\..\source\blood\src\aihand.h" />
<ClInclude Include="..\..\source\blood\src\aihound.h" />
<ClInclude Include="..\..\source\blood\src\aiinnoc.h" />
<ClInclude Include="..\..\source\blood\src\aipod.h" />
<ClInclude Include="..\..\source\blood\src\airat.h" />
<ClInclude Include="..\..\source\blood\src\aispid.h" />
<ClInclude Include="..\..\source\blood\src\aitchern.h" />
<ClInclude Include="..\..\source\blood\src\aiunicult.h" />
<ClInclude Include="..\..\source\blood\src\aizomba.h" />
<ClInclude Include="..\..\source\blood\src\aizombf.h" />
<ClInclude Include="..\..\source\blood\src\asound.h" />
<ClInclude Include="..\..\source\blood\src\blood.h" />
<ClInclude Include="..\..\source\blood\src\callback.h" />
<ClInclude Include="..\..\source\blood\src\choke.h" />
<ClInclude Include="..\..\source\blood\src\common_game.h" />
<ClInclude Include="..\..\source\blood\src\config.h" />
<ClInclude Include="..\..\source\blood\src\controls.h" />
<ClInclude Include="..\..\source\blood\src\credits.h" />
<ClInclude Include="..\..\source\blood\src\db.h" />
<ClInclude Include="..\..\source\blood\src\demo.h" />
<ClInclude Include="..\..\source\blood\src\dude.h" />
<ClInclude Include="..\..\source\blood\src\endgame.h" />
<ClInclude Include="..\..\source\blood\src\eventq.h" />
<ClInclude Include="..\..\source\blood\src\fire.h" />
<ClInclude Include="..\..\source\blood\src\function.h" />
<ClInclude Include="..\..\source\blood\src\fx.h" />
<ClInclude Include="..\..\source\blood\src\gamedefs.h" />
<ClInclude Include="..\..\source\blood\src\gamemenu.h" />
<ClInclude Include="..\..\source\blood\src\gameutil.h" />
<ClInclude Include="..\..\source\blood\src\getopt.h" />
<ClInclude Include="..\..\source\blood\src\gib.h" />
<ClInclude Include="..\..\source\blood\src\globals.h" />
<ClInclude Include="..\..\source\blood\src\map2d.h" />
<ClInclude Include="..\..\source\blood\src\menu.h" />
<ClInclude Include="..\..\source\blood\src\messages.h" />
<ClInclude Include="..\..\source\blood\src\mirrors.h" />
<ClInclude Include="..\..\source\blood\src\warp.h" />
<ClInclude Include="..\..\source\blood\src\inifile.h" />
<ClInclude Include="..\..\source\blood\src\iob.h" />
<ClInclude Include="..\..\source\blood\src\levels.h" />
<ClInclude Include="..\..\source\blood\src\loadsave.h" />
<ClInclude Include="..\..\source\blood\src\midi.h" />
<ClInclude Include="..\..\source\blood\src\misc.h" />
<ClInclude Include="..\..\source\blood\src\mpu401.h" />
<ClInclude Include="..\..\source\blood\src\network.h" />
<ClInclude Include="..\..\source\blood\src\osdcmds.h" />
<ClInclude Include="..\..\source\blood\src\player.h" />
<ClInclude Include="..\..\source\blood\src\pqueue.h" />
<ClInclude Include="..\..\source\blood\src\qav.h" />
<ClInclude Include="..\..\source\blood\src\qheap.h" />
<ClInclude Include="..\..\source\blood\src\replace.h" />
<ClInclude Include="..\..\source\blood\src\resource.h" />
<ClInclude Include="..\..\source\blood\src\screen.h" />
<ClInclude Include="..\..\source\blood\src\sectorfx.h" />
<ClInclude Include="..\..\source\blood\src\seq.h" />
<ClInclude Include="..\..\source\blood\src\sfx.h" />
<ClInclude Include="..\..\source\blood\src\sound.h" />
<ClInclude Include="..\..\source\blood\src\startwin.game.h" />
<ClInclude Include="..\..\source\blood\src\tile.h" />
<ClInclude Include="..\..\source\blood\src\trig.h" />
<ClInclude Include="..\..\source\blood\src\triggers.h" />
<ClInclude Include="..\..\source\blood\src\view.h" />
<ClInclude Include="..\..\source\blood\src\weapon.h" />
<ClInclude Include="..\..\source\blood\src\_functio.h" />
<ClInclude Include="..\..\source\blood\src\_midi.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,485 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\source\blood\rsrc\eduke32_icon.c">
<Filter>Resource Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\blood.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\levels.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\winbits.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\startwin.game.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\osdcmd.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\config.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\getopt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\controls.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\demo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\screen.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\qheap.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\resource.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\misc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\inifile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\tile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\trig.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\replace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\globals.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\db.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\iob.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\seq.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\sfx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\dude.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\player.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\sound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\mpu401.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\music.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\midi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\gameutil.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\pqueue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\eventq.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\callback.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\fx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\actor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\endgame.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\qav.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\triggers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\view.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\sectorfx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\gib.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\weapon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\warp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\mirrors.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\ai.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\gamemenu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\menu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\messages.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\map2d.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\asound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\credits.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\choke.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\fire.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aibat.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aibeast.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aiboneel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aiburn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aicaleb.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aicerber.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aicult.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aigarg.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aighost.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aigilbst.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aihand.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aihound.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aiinnoc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aipod.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\airat.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aispid.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aitchern.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aizomba.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aizombf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\loadsave.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\gmtimbre.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\common.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\blood\src\aiunicult.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\source\blood\rsrc\gameres.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\source\blood\src\levels.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\common_game.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\startwin.game.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\network.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\blood.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\_functio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\function.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\gamedefs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\getopt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\controls.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\demo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\db.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\actor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\trig.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\screen.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\qheap.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\misc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\inifile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\tile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\globals.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\replace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\iob.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\seq.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\sfx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\player.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\dude.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\sound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\midi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\mpu401.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\_midi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\loadsave.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\gameutil.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\pqueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\eventq.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\callback.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\fx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\endgame.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\ai.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\qav.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\triggers.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\view.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\sectorfx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\gib.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\weapon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\warp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\mirrors.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\gamemenu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\menu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\messages.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\map2d.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\asound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\credits.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\choke.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\fire.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aibat.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aibeast.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aiboneel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aiburn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aicaleb.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aicerber.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aicult.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aigarg.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aighost.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aigilbst.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aihand.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aihound.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aiinnoc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aipod.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\airat.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aispid.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aitchern.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aizomba.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aizombf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\osdcmds.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\source\blood\src\aiunicult.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -6,7 +6,7 @@
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;RENDERTYPESDL=1;MIXERTYPEWIN=1;SDL_USEFOLDER;SDL_TARGET=2;USE_OPENGL=1;STARTUP_WINDOW;USE_LIBVPX;HAVE_VORBIS;HAVE_XMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./include;./include/vpx/;./include/sdl2/;../../source/build/include;../../source/mact/include;../../source/audiolib/include;../../source/enet/include;../../source/glad/include;../../source/libxmp-lite/include;../../source/libxmp-lite/include/libxmp-lite</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>./include;./include/vpx/;./include/sdl2/;../../source/build/include;../../source/mact/include;../../source/audiolib/include;../../source/enet/include;../../source/glad/include;../../source/libxmp-lite/include;../../source/libxmp-lite/include/libxmp-lite;../../source/libsmackerdec/include</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996;4244;4018;4267</DisableSpecificWarnings>
<AdditionalOptions>/J %(AdditionalOptions)</AdditionalOptions>
</ClCompile>

View file

@ -225,7 +225,6 @@
<ClCompile Include="..\..\source\rr\src\config.cpp" />
<ClCompile Include="..\..\source\rr\src\common.cpp" />
<ClCompile Include="..\..\source\rr\src\demo.cpp" />
<ClCompile Include="..\..\source\rr\src\file_lib.cpp" />
<ClCompile Include="..\..\source\rr\src\game.cpp" />
<ClCompile Include="..\..\source\rr\src\gamedef.cpp" />
<ClCompile Include="..\..\source\rr\src\gameexec.cpp" />

View file

@ -272,9 +272,6 @@
<ClCompile Include="..\..\source\rr\rsrc\eduke32_icon.c">
<Filter>Resource Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\rr\src\file_lib.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\source\rr\rsrc\gameres.rc">

View file

@ -67,6 +67,9 @@ enum MV_Errors
MV_InvalidFile,
};
void DisableInterrupts(void);
void RestoreInterrupts(void);
extern void (*MV_Printf)(const char *fmt, ...);
const char *MV_ErrorString(int32_t ErrorNumber);
int32_t MV_VoicePlaying(int32_t handle);

View file

@ -53,12 +53,6 @@ typedef struct
uint32_t tick;
} songposition;
enum MIDI_Device
{
MIDIDEVICE_NONE = -1,
MIDIDEVICE_MPU = 0,
MIDIDEVICE_OPL
};
#define MUSIC_LoopSong ( 1 == 1 )
#define MUSIC_PlayOnce ( !MUSIC_LoopSong )

View file

@ -96,13 +96,13 @@ float MV_GlobalVolume = 1.f;
static int32_t lockdepth = 0;
static FORCE_INLINE void DisableInterrupts(void)
void DisableInterrupts(void)
{
if (!lockdepth++)
SoundDriver_Lock();
}
static FORCE_INLINE void RestoreInterrupts(void)
void RestoreInterrupts(void)
{
if (!--lockdepth)
SoundDriver_Unlock();

View file

@ -0,0 +1,191 @@
ai_h=\
$(blood_src)/aibat.h \
$(blood_src)/aibeast.h \
$(blood_src)/aiboneel.h \
$(blood_src)/aiburn.h \
$(blood_src)/aicaleb.h \
$(blood_src)/aicerber.h \
$(blood_src)/aicult.h \
$(blood_src)/aigarg.h \
$(blood_src)/aighost.h \
$(blood_src)/aigilbst.h \
$(blood_src)/aihand.h \
$(blood_src)/aihound.h \
$(blood_src)/aiinnoc.h \
$(blood_src)/aipod.h \
$(blood_src)/airat.h \
$(blood_src)/aispid.h \
$(blood_src)/aitchern.h \
$(blood_src)/aiunicult.h \
$(blood_src)/aizomba.h \
$(blood_src)/aizombf.h
common_h=\
$(engine_inc)/compat.h \
$(engine_inc)/common.h \
$(engine_inc)/pragmas.h \
$(engine_inc)/build.h \
$(engine_inc)/baselayer.h \
$(engine_inc)/palette.h \
$(engine_inc)/polymer.h \
$(engine_inc)/polymost.h \
$(engine_inc)/texcache.h \
$(engine_inc)/cache1d.h \
$(mact_inc)/file_lib.h \
$(mact_inc)/keyboard.h \
$(mact_inc)/mouse.h \
$(mact_inc)/joystick.h \
$(mact_inc)/control.h \
$(audiolib_inc)/fx_man.h \
$(audiolib_inc)/music.h \
$(blood_src)/common_game.h \
$(blood_src)/blood.h \
$(blood_src)/actor.h \
$(blood_src)/ai.h \
$(blood_src)/al_midi.h \
$(blood_src)/asound.h \
$(blood_src)/callback.h \
$(blood_src)/choke.h \
$(blood_src)/config.h \
$(blood_src)/controls.h \
$(blood_src)/credits.h \
$(blood_src)/db.h \
$(blood_src)/demo.h \
$(blood_src)/dude.h \
$(blood_src)/endgame.h \
$(blood_src)/eventq.h \
$(blood_src)/fire.h \
$(blood_src)/function.h \
$(blood_src)/fx.h \
$(blood_src)/gamedefs.h \
$(blood_src)/gamemenu.h \
$(blood_src)/getopt.h \
$(blood_src)/gib.h \
$(blood_src)/globals.h \
$(blood_src)/inifile.h \
$(blood_src)/iob.h \
$(blood_src)/levels.h \
$(blood_src)/loadsave.h \
$(blood_src)/map2d.h \
$(blood_src)/menu.h \
$(blood_src)/messages.h \
$(blood_src)/midi.h \
$(blood_src)/mirrors.h \
$(blood_src)/misc.h \
$(blood_src)/mpu401.h \
$(blood_src)/network.h \
$(blood_src)/opl3.h \
$(blood_src)/osdcmds.h \
$(blood_src)/player.h \
$(blood_src)/pqueue.h \
$(blood_src)/qav.h \
$(blood_src)/qheap.h \
$(blood_src)/replace.h \
$(blood_src)/resource.h \
$(blood_src)/screen.h \
$(blood_src)/sectorfx.h \
$(blood_src)/seq.h \
$(blood_src)/sfx.h \
$(blood_src)/sound.h \
$(blood_src)/tile.h \
$(blood_src)/trig.h \
$(blood_src)/triggers.h \
$(blood_src)/view.h \
$(blood_src)/warp.h \
$(blood_src)/tile.h
$(blood_obj)/blood.$o: $(blood_src)/blood.cpp $(common_h)
$(blood_obj)/actor.$o: $(blood_src)/actor.cpp $(common_h) $(ai_h)
$(blood_obj)/ai.$o: $(blood_src)/ai.cpp $(common_h) $(ai_h)
$(blood_obj)/aibat.$o: $(blood_src)/aibat.cpp $(common_h) $(ai_h)
$(blood_obj)/aibeast.$o: $(blood_src)/aibeast.cpp $(common_h) $(ai_h)
$(blood_obj)/aiboneel.$o: $(blood_src)/aiboneel.cpp $(common_h) $(ai_h)
$(blood_obj)/aiburn.$o: $(blood_src)/aiburn.cpp $(common_h) $(ai_h)
$(blood_obj)/aicaleb.$o: $(blood_src)/aicaleb.cpp $(common_h) $(ai_h)
$(blood_obj)/aicerber.$o: $(blood_src)/aicerber.cpp $(common_h) $(ai_h)
$(blood_obj)/aicult.$o: $(blood_src)/aicult.cpp $(common_h) $(ai_h)
$(blood_obj)/aigarg.$o: $(blood_src)/aigarg.cpp $(common_h) $(ai_h)
$(blood_obj)/aighost.$o: $(blood_src)/aighost.cpp $(common_h) $(ai_h)
$(blood_obj)/aigilbst.$o: $(blood_src)/aigilbst.cpp $(common_h) $(ai_h)
$(blood_obj)/aihand.$o: $(blood_src)/aihand.cpp $(common_h) $(ai_h)
$(blood_obj)/aihound.$o: $(blood_src)/aihound.cpp $(common_h) $(ai_h)
$(blood_obj)/aiinnoc.$o: $(blood_src)/aiinnoc.cpp $(common_h) $(ai_h)
$(blood_obj)/aipod.$o: $(blood_src)/aipod.cpp $(common_h) $(ai_h)
$(blood_obj)/airat.$o: $(blood_src)/airat.cpp $(common_h) $(ai_h)
$(blood_obj)/aispid.$o: $(blood_src)/aispid.cpp $(common_h) $(ai_h)
$(blood_obj)/aitchern.$o: $(blood_src)/aitchern.cpp $(common_h) $(ai_h)
$(blood_obj)/aiunicult.$o: $(blood_src)/aiunicult.cpp $(common_h) $(ai_h)
$(blood_obj)/aizomba.$o: $(blood_src)/aizomba.cpp $(common_h) $(ai_h)
$(blood_obj)/aizombf.$o: $(blood_src)/aizombf.cpp $(common_h) $(ai_h)
$(blood_obj)/asound.$o: $(blood_src)/asound.cpp $(common_h)
$(blood_obj)/callback.$o: $(blood_src)/callback.cpp $(common_h)
$(blood_obj)/choke.$o: $(blood_src)/choke.cpp $(common_h)
$(blood_obj)/common.$o: $(blood_src)/common.cpp $(common_h)
$(blood_obj)/config.$o: $(blood_src)/config.cpp $(common_h)
$(blood_obj)/controls.$o: $(blood_src)/controls.cpp $(common_h)
$(blood_obj)/credits.$o: $(blood_src)/credits.cpp $(common_h)
$(blood_obj)/db.$o: $(blood_src)/db.cpp $(common_h)
$(blood_obj)/demo.$o: $(blood_src)/demo.cpp $(common_h)
$(blood_obj)/dude.$o: $(blood_src)/dude.cpp $(common_h)
$(blood_obj)/endgame.$o: $(blood_src)/endgame.cpp $(common_h)
$(blood_obj)/eventq.$o: $(blood_src)/eventq.cpp $(common_h)
$(blood_obj)/fire.$o: $(blood_src)/fire.cpp $(common_h)
$(blood_obj)/fx.$o: $(blood_src)/fx.cpp $(common_h)
$(blood_obj)/gamemenu.$o: $(blood_src)/gamemenu.cpp $(common_h)
$(blood_obj)/gameutil.$o: $(blood_src)/gameutil.cpp $(common_h)
$(blood_obj)/getopt.$o: $(blood_src)/getopt.cpp $(common_h)
$(blood_obj)/gib.$o: $(blood_src)/gib.cpp $(common_h)
$(blood_obj)/globals.$o: $(blood_src)/globals.cpp $(common_h)
$(blood_obj)/inifile.$o: $(blood_src)/inifile.cpp $(common_h)
$(blood_obj)/iob.$o: $(blood_src)/iob.cpp $(common_h)
$(blood_obj)/levels.$o: $(blood_src)/levels.cpp $(common_h)
$(blood_obj)/loadsave.$o: $(blood_src)/loadsave.cpp $(common_h)
$(blood_obj)/map2d.$o: $(blood_src)/map2d.cpp $(common_h)
$(blood_obj)/menu.$o: $(blood_src)/menu.cpp $(common_h)
$(blood_obj)/messages.$o: $(blood_src)/messages.cpp $(common_h)
$(blood_obj)/mirrors.$o: $(blood_src)/mirrors.cpp $(common_h)
$(blood_obj)/misc.$o: $(blood_src)/misc.cpp $(common_h)
$(blood_obj)/network.$o: $(blood_src)/network.cpp $(common_h)
$(blood_obj)/osdcmd.$o: $(blood_src)/osdcmd.cpp $(common_h)
$(blood_obj)/player.$o: $(blood_src)/player.cpp $(common_h)
$(blood_obj)/pqueue.$o: $(blood_src)/pqueue.cpp $(common_h)
$(blood_obj)/qav.$o: $(blood_src)/qav.cpp $(common_h)
$(blood_obj)/qheap.$o: $(blood_src)/qheap.cpp $(common_h)
$(blood_obj)/replace.$o: $(blood_src)/replace.cpp $(common_h)
$(blood_obj)/resource.$o: $(blood_src)/resource.cpp $(common_h)
$(blood_obj)/screen.$o: $(blood_src)/screen.cpp $(common_h)
$(blood_obj)/sectorfx.$o: $(blood_src)/sectorfx.cpp $(common_h)
$(blood_obj)/seq.$o: $(blood_src)/seq.cpp $(common_h)
$(blood_obj)/sfx.$o: $(blood_src)/sfx.cpp $(common_h)
$(blood_obj)/sound.$o: $(blood_src)/sound.cpp $(common_h)
$(blood_obj)/tile.$o: $(blood_src)/tile.cpp $(common_h)
$(blood_obj)/trig.$o: $(blood_src)/trig.cpp $(common_h)
$(blood_obj)/triggers.$o: $(blood_src)/triggers.cpp $(common_h)
$(blood_obj)/view.$o: $(blood_src)/view.cpp $(common_h) $(ai_h)
$(blood_obj)/warp.$o: $(blood_src)/warp.cpp $(common_h)
$(blood_obj)/weapon.$o: $(blood_src)/weapon.cpp $(common_h)
$(blood_obj)/winbits.$o: $(blood_src)/winbits.cpp
# misc objects
$(blood_obj)/game_icon.$o: $(blood_rsrc)/game_icon.c $(blood_rsrc)/game_icon.ico
$(blood_obj)/gameres.$o: $(blood_rsrc)/gameres.rc $(blood_src)/startwin.game.h $(blood_rsrc)/game.bmp
$(blood_obj)/buildres.$o: $(blood_rsrc)/buildres.rc $(engine_inc)/startwin.editor.h $(blood_rsrc)/build.bmp
$(blood_obj)/startwin.game.$o: $(blood_src)/startwin.game.cpp $(blood_h) $(engine_inc)/build.h $(engine_inc)/winlayer.h $(engine_inc)/compat.h
$(blood_obj)/startgtk.game.$o: $(blood_src)/startgtk.game.cpp $(blood_h) $(engine_inc)/dynamicgtk.h $(engine_inc)/build.h $(engine_inc)/baselayer.h $(engine_inc)/compat.h
# mact objects
$(mact_obj)/animlib.$o: $(mact_src)/animlib.cpp $(mact_inc)/animlib.h $(engine_inc)/compat.h
$(mact_obj)/file_lib.$o: $(mact_src)/file_lib.cpp $(mact_inc)/file_lib.h
$(mact_obj)/control.$o: $(mact_src)/control.cpp $(mact_inc)/control.h $(mact_inc)/keyboard.h $(mact_inc)/mouse.h $(mact_inc)/joystick.h $(engine_inc)/baselayer.h
$(mact_obj)/keyboard.$o: $(mact_src)/keyboard.cpp $(mact_inc)/keyboard.h $(engine_inc)/compat.h $(engine_inc)/baselayer.h
$(mact_obj)/joystick.$o: $(mact_src)/joystick.cpp $(mact_inc)/joystick.h $(engine_inc)/baselayer.h
$(mact_obj)/scriplib.$o: $(mact_src)/scriplib.cpp $(mact_inc)/scriplib.h $(mact_src)/_scrplib.h $(engine_inc)/compat.h
$(blood_obj)/al_midi.$o: $(blood_src)/al_midi.cpp $(engine_inc)/compat.h $(blood_src)/al_midi.h $(blood_src)/_al_midi.h $(blood_src)/opl3.h
$(blood_obj)/gmtimbre.$o: $(blood_src)/gmtimbre.cpp
$(blood_obj)/opl3.$o: $(blood_src)/opl3.cpp
$(blood_obj)/midi.$o: $(blood_src)/midi.cpp $(blood_src)/_midi.h $(blood_src)/midi.h $(blood_src)/al_midi.h $(audiolib_inc)/music.h
$(blood_obj)/oplmidi.$o: $(blood_src)/oplmidi.cpp $(blood_src)/_oplmidi.h $(blood_src)/oplmidi.h $(blood_src)/al_midi.h $(audiolib_inc)/music.h
$(blood_obj)/mpu401.$o: $(blood_src)/mpu401.cpp $(blood_src)/mpu401.h $(audiolib_inc)/music.h
$(blood_obj)/music.$o: $(blood_src)/music.cpp $(blood_src)/midi.h $(blood_src)/mpu401.h $(blood_src)/al_midi.h $(audiolib_inc)/music.h

339
source/blood/gpl-2.0.txt Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

BIN
source/blood/rsrc/build.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

View file

@ -0,0 +1 @@
#include "eduke32_icon.c"

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View file

@ -0,0 +1,72 @@
#define NEED_COMMCTRL_H
#include "../../build/include/windows_inc.h"
#include "../../build/include/startwin.editor.h"
RSRC_ICON ICON "build_icon.ico"
RSRC_BMP BITMAP "build.bmp"
WIN_STARTWIN DIALOGEX DISCARDABLE 20, 40, 260, 200
STYLE DS_MODALFRAME | DS_CENTER | DS_SETFONT | DS_FIXEDSYS | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU
CAPTION "Startup"
FONT 8, "MS Shell Dlg"
BEGIN
CONTROL "", WIN_STARTWIN_BITMAP, "STATIC", SS_BITMAP | SS_CENTERIMAGE | WS_CHILD | WS_VISIBLE, 0, 0, 66, 172
CONTROL "", WIN_STARTWIN_TABCTL, WC_TABCONTROL, WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 5, 250, 170
CONTROL "&Start", WIN_STARTWIN_START, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 180, 48, 14
CONTROL "&Cancel", WIN_STARTWIN_CANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 207, 180, 48, 14
CONTROL "", WIN_STARTWIN_MESSAGES, "EDIT", ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VSCROLL, 0, 0, 32, 32
END
WIN_STARTWINPAGE_CONFIG DIALOGEX DISCARDABLE 20, 40, 279, 168
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
CAPTION "Dialog"
FONT 8, "MS Shell Dlg"
BEGIN
CONTROL "&2D Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 8, 50, 8
CONTROL "", IDC2DVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 6, 80, 56
CONTROL "&Fullscreen", IDCFULLSCREEN, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 148, 8, 49, 10
CONTROL "&3D Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 24, 50, 8
CONTROL "", IDC3DVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 22, 80, 56
CONTROL "&Always show this window at startup", IDCALWAYSSHOW, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 118, 116, 140, 8
END
#define FILEVER 1,9,9,9
#define PRODUCTVER 1,9,9,9
#define STRFILEVER "2.0.0devel\0"
#define STRPRODUCTVER "2.0.0devel\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION FILEVER
PRODUCTVERSION PRODUCTVER
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x3L
#else
FILEFLAGS 0x2L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "Mapster32 for EDuke32"
VALUE "FileVersion", STRFILEVER
VALUE "InternalName", "Mapster32"
VALUE "LegalCopyright", "Copyright © 2018 EDuke32 Developers, 1996, 2003 3D Realms Entertainment"
VALUE "LegalTrademarks", "Duke Nukem® is a Registered Trademark of Gearbox Software, LLC."
VALUE "OriginalFilename", "mapster32.exe"
VALUE "ProductName", "Mapster32"
VALUE "ProductVersion", STRPRODUCTVER
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
1 24 "manifest.build.xml"

View file

@ -0,0 +1,20 @@
#include "sdl_inc.h"
#include "sdlappicon.h"
static Uint8 sdlappicon_pixels[] = {
#if defined _WIN32 && SDL_MAJOR_VERSION==1
# include "eduke32_icon_32px.c"
#else
# include "eduke32_icon_48px.c"
#endif
};
struct sdlappicon sdlappicon = {
#if defined _WIN32 && SDL_MAJOR_VERSION==1
32,32,
#else
48,48,
#endif
sdlappicon_pixels
};

View file

@ -0,0 +1,196 @@
/* GIMP RGBA C-Source image dump (eduke32_icon_32px.c) */
#if 0
static const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[32 * 32 * 4 + 1];
} sdlappicon = {
32, 32, 4,
#endif
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\313\035\035\033\303\034\034]\311\034\034\225\340''\301\343<<\330\345JJ"
"\346\345JJ\346\342\065\065\330\337\040\040\301\314\035\035\225\303\034\034]\275\032"
"\032\033\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\302\033\033\062\320\035\035\240\345JJ\351\360\231\231\377\366\305\305\377"
"\372\341\341\377\375\364\364\377\375\360\360\377\373\343\343\377\365\272"
"\272\377\361\236\236\377\356\213\213\377\352mm\377\342\071\071\351\320\035\035"
"\240\302\033\033\062\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\257\030\030\007\311"
"\034\034\214\343AA\371\363\253\253\377\374\357\357\377\376\375\375\377\376"
"\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\371\371"
"\377\373\346\346\377\370\323\323\377\365\270\270\377\363\254\254\377\363"
"\262\262\377\360\231\231\377\344EE\371\302\033\033\214\257\030\030\007\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\313\035\035\062\322\036\036\320\353rr\377\366\301\301\377\371\330\330"
"\377\376\371\371\377\376\375\375\377\374\355\355\377\366\305\305\377\361"
"\236\236\377\356\207\207\377\355\202\202\377\356\215\215\377\363\256\256"
"\377\370\315\315\377\370\315\315\377\370\323\323\377\370\325\325\377\372"
"\341\341\377\361\236\236\377\325\036\036\320\302\033\033\062\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\307\034\034/\331\037"
"\037\350\353rr\377\360\235\235\377\363\262\262\377\374\353\353\377\367\307"
"\307\377\354{{\377\345JJ\377\341\064\064\377\340++\377\332\037\037\377\314\035"
"\035\377\303\034\034\377\313\035\035\377\340%%\377\351ff\377\366\277\277\377\374"
"\357\357\377\374\351\351\377\376\375\375\377\366\277\277\377\340''\350\302"
"\033\033/\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\314\035\035"
",\327\036\036\360\351ll\377\354{{\377\365\272\272\377\370\317\317\377\347\\"
"\\\377\314\035\035\377\322\036\036\377\340++\377\341\064\064\377\342\065\065\377"
"\341\062\062\377\336\037\037\377\313\035\035\377\302\033\033\377\275\032\032\377\302"
"\033\033\377\314\035\035\377\351jj\377\374\353\353\377\376\375\375\377\376\375"
"\375\377\370\321\321\377\340%%\360\302\033\033,\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\237\026\026\005\320\035\035\322\351ff\377\353tt\377\363\253\253\377"
"\366\277\277\377\342\065\065\377\322\036\036\377\303\034\034\377\332\037\037\377"
"\342\065\065\377\343<<\377\343<<\377\342\065\065\377\337\040\040\377\320\035\035"
"\377\305\034\034\377\302\033\033\377\313\035\035\377\302\033\033\377\311\034\034\377"
"\346OO\377\371\334\334\377\375\366\366\377\371\330\330\377\361\236\236\377"
"\325\036\036\322\237\026\026\005\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\303\034\034\213"
"\350ee\377\360\225\225\377\365\270\270\377\365\272\272\377\307\034\034\377"
"\303\034\034\377\307\034\034\377\347WW\377\347WW\377\337\040\040\377\342\065\065"
"\377\342\067\067\377\340--\377\336\037\037\377\313\035\035\377\305\034\034\377\302"
"\033\033\377\340--\377\347XX\377\337\040\040\377\322\036\036\377\340''\377\367"
"\312\312\377\372\341\341\377\367\310\310\377\354yy\377\302\033\033\213\000\000"
"\000\000\000\000\000\000\000\000\000\000\302\033\033+\342\065\065\372\363\256\256\377\363\253\253"
"\377\370\321\321\377\331\037\037\377\276\033\033\377\271\032\032\377\350ee\377"
"\374\357\357\377\367\307\307\377\320\035\035\377\262\031\031\377\242\027\027\377"
"\223\025\025\377\217\024\024\377\235\026\026\377\251\030\030\377\302\033\033\377\360"
"\225\225\377\376\373\373\377\355\204\204\377\320\035\035\377\275\032\032\377"
"\341..\377\371\330\330\377\365\270\270\377\363\253\253\377\342\067\067\372"
"\307\034\034+\000\000\000\000\000\000\000\000\314\035\035\242\357\224\224\377\367\307\307\377"
"\372\341\341\377\347WW\377\322\036\036\377\303\034\034\377\350__\377\373\346"
"\346\377\355\204\204\377\361\244\244\377\342\071\071\377z\021\021\377w\020\020"
"\377w\020\020\377w\020\020\377z\021\021\377w\020\020\377\244\027\027\377\364\263\263"
"\377\374\351\351\377\376\373\373\377\353tt\377\275\032\032\377\313\035\035\377"
"\346SS\377\370\323\323\377\360\231\231\377\353xx\377\320\035\035\242\000\000\000"
"\000\307\034\034\026\343<<\361\367\310\310\377\372\337\337\377\366\277\277\377"
"\302\033\033\377\311\034\034\377\343@@\377\373\346\346\377\356\211\211\377\340"
"--\377\366\277\277\377\370\323\323\377\223\025\025\377|\021\021\377|\021\021\377"
"|\021\021\377w\020\020\377z\021\021\377\354}}\377\367\310\310\377\347WW\377\370"
"\323\323\377\374\357\357\377\343@@\377\322\036\036\377\302\033\033\377\364\263"
"\263\377\364\263\263\377\360\227\227\377\341\062\062\361\307\034\034\026\302\033"
"\033\\\353xx\377\367\312\312\377\373\344\344\377\351ll\377\275\032\032\377\313"
"\035\035\377\365\272\272\377\371\334\334\377\345HH\377\363\262\262\377\376"
"\373\373\377\376\373\373\377\353rr\377z\021\021\377|\021\021\377|\021\021\377z"
"\021\021\377\244\027\027\377\375\366\366\377\376\373\373\377\364\267\267\377"
"\345JJ\377\370\325\325\377\363\260\260\377\302\033\033\377\322\036\036\377\350"
"]]\377\370\315\315\377\361\236\236\377\351ff\377\303\034\034\\\313\035\035\227"
"\357\220\220\377\367\310\310\377\370\323\323\377\340))\377\302\033\033\377"
"\347WW\377\376\373\373\377\360\233\233\377\353vv\377\376\373\373\377\376"
"\373\373\377\376\373\373\377\375\362\362\377\244\027\027\377\214\023\023\377"
"\235\026\026\377\217\024\024\377\353rr\377\376\373\373\377\376\373\373\377\376"
"\373\373\377\353tt\377\353vv\377\373\346\346\377\343AA\377\311\034\034\377"
"\331\037\037\377\367\312\312\377\363\256\256\377\355\202\202\377\313\035\035"
"\227\337\040\040\303\361\236\236\377\370\323\323\377\362\245\245\377\311\034"
"\034\377\275\032\032\377\357\220\220\377\374\353\353\377\347ZZ\377\371\330\330"
"\377\376\373\373\377\376\373\373\377\376\373\373\377\376\373\373\377\372"
"\337\337\377\373\346\346\377\376\373\373\377\367\307\307\377\376\373\373"
"\377\376\373\373\377\376\373\373\377\376\373\373\377\371\330\330\377\345"
"HH\377\370\325\325\377\356\213\213\377\311\034\034\377\276\033\033\377\362\247"
"\247\377\367\307\307\377\360\225\225\377\340%%\303\342\067\067\330\363\262"
"\262\377\372\335\335\377\356\215\215\377\275\032\032\377\313\035\035\377\364"
"\265\265\377\366\277\277\377\343AA\377\376\373\373\377\376\373\373\377\376"
"\373\373\377\376\373\373\377\376\373\373\377\376\373\373\377\372\341\341"
"\377\366\305\305\377\376\373\373\377\376\373\373\377\376\373\373\377\376"
"\373\373\377\376\373\373\377\376\373\373\377\343AA\377\364\265\265\377\363"
"\262\262\377\305\034\034\377\303\034\034\377\356\213\213\377\370\323\323\377"
"\363\253\253\377\342\071\071\330\344GG\346\367\314\314\377\373\346\346\377"
"\355\202\202\377\275\032\032\377\336\037\037\377\371\330\330\377\370\321\321"
"\377\357\224\224\377\376\373\373\377\376\373\373\377\376\373\373\377\376"
"\373\373\377\376\373\373\377\366\277\277\377\217\024\024\377z\021\021\377\337"
"\"\"\377\375\366\366\377\376\373\373\377\376\373\373\377\376\373\373\377"
"\376\373\373\377\357\220\220\377\367\310\310\377\370\325\325\377\325\036\036"
"\377\303\034\034\377\354}}\377\372\335\335\377\364\267\267\377\343AA\346\345"
"JJ\346\371\332\332\377\375\360\360\377\355\206\206\377\307\034\034\377\337"
"\040\040\377\355\206\206\377\360\235\235\377\353vv\377\352qq\377\353rr\377"
"\353rr\377\354}}\377\376\373\373\377\353vv\377w\020\020\377w\020\020\377\214"
"\023\023\377\376\367\367\377\371\330\330\377\353rr\377\353rr\377\352qq\377"
"\353vv\377\357\220\220\377\353vv\377\311\034\034\377\303\034\034\377\354}}\377"
"\371\332\332\377\364\267\267\377\344EE\346\343AA\330\371\330\330\377\376"
"\367\367\377\360\225\225\377\331\037\037\377\337\040\040\377\325\036\036\377\313"
"\035\035\377\230\025\025\377w\020\020\377z\021\021\377p\020\020\377\217\024\024\377\373"
"\350\350\377\375\362\362\377\235\026\026\377|\021\021\377\346UU\377\376\373\373"
"\377\342\071\071\377z\021\021\377z\021\021\377w\020\020\377\217\024\024\377\302\033"
"\033\377\275\032\032\377\302\033\033\377\275\032\032\377\356\213\213\377\370\325"
"\325\377\363\254\254\377\342\071\071\330\340))\303\367\312\312\377\376\367"
"\367\377\364\263\263\377\337$$\377\337\040\040\377\337\"\"\377\336\037\037\377"
"\260\031\031\377w\020\020\377|\021\021\377z\021\021\377z\021\021\377\345JJ\377\376"
"\373\373\377\375\366\366\377\374\351\351\377\376\373\373\377\371\332\332"
"\377\235\026\026\377|\021\021\377|\021\021\377w\020\020\377\251\030\030\377\307\034"
"\034\377\311\034\034\377\302\033\033\377\311\034\034\377\362\247\247\377\370\323"
"\323\377\361\236\236\377\340%%\303\313\035\035\227\363\262\262\377\375\362"
"\362\377\372\335\335\377\341\064\064\377\320\035\035\377\331\037\037\377\325\036"
"\036\377\302\033\033\377~\021\021\377w\020\020\377|\021\021\377w\020\020\377\212\023"
"\023\377\362\245\245\377\376\373\373\377\376\373\373\377\376\373\373\377\337"
"\"\"\377z\021\021\377|\021\021\377w\020\020\377~\021\021\377\275\032\032\377\305\034"
"\034\377\311\034\034\377\276\033\033\377\337$$\377\370\321\321\377\366\305\305"
"\377\357\220\220\377\313\035\035\227\275\032\032\\\355\202\202\377\372\341\341"
"\377\374\351\351\377\351jj\377\275\032\032\377\314\035\035\377\302\033\033\377"
"\276\033\033\377\250\030\030\377w\020\020\377z\021\021\377z\021\021\377\244\027\027\377"
"\375\362\362\377\376\373\373\377\376\373\373\377\376\373\373\377\362\245"
"\245\377z\021\021\377w\020\020\377w\020\020\377\244\027\027\377\276\033\033\377\276"
"\033\033\377\302\033\033\377\303\034\034\377\350__\377\371\330\330\377\365\270"
"\270\377\353tt\377\302\033\033\\\307\034\034\026\343<<\361\366\305\305\377\371"
"\332\332\377\365\272\272\377\275\032\032\377\302\033\033\377\275\032\032\377\276"
"\033\033\377\276\033\033\377\237\026\026\377z\021\021\377\217\024\024\377\375\362\362"
"\377\376\373\373\377\376\373\373\377\376\373\373\377\376\373\373\377\376"
"\373\373\377\346OO\377z\021\021\377\237\026\026\377\276\033\033\377\275\032\032\377"
"\275\032\032\377\302\033\033\377\303\034\034\377\365\270\270\377\366\305\305\377"
"\363\253\253\377\342\067\067\361\307\034\034\026\000\000\000\000\313\035\035\242\355\206"
"\206\377\363\262\262\377\371\326\326\377\346QQ\377\311\034\034\377\275\032\032"
"\377\275\032\032\377\276\033\033\377\276\033\033\377\232\026\026\377\346OO\377\372"
"\341\341\377\376\373\373\377\376\373\373\377\376\373\373\377\376\373\373"
"\377\372\335\335\377\366\277\277\377\260\031\031\377\302\033\033\377\276\033\033"
"\377\276\033\033\377\275\032\032\377\320\035\035\377\345NN\377\370\325\325\377"
"\361\244\244\377\355\202\202\377\320\035\035\242\000\000\000\000\000\000\000\000\302\033\033"
"+\340--\372\361\236\236\377\362\251\251\377\371\330\330\377\337\040\040\377"
"\311\034\034\377\275\032\032\377\276\033\033\377\275\032\032\377\347ZZ\377\371\334"
"\334\377\347\\\\\377\347WW\377\351ff\377\351ff\377\350__\377\343AA\377\365"
"\272\272\377\370\315\315\377\307\034\034\377\275\032\032\377\275\032\032\377\313"
"\035\035\377\337\040\040\377\370\323\323\377\360\235\235\377\360\235\235\377"
"\342\067\067\372\307\034\034+\000\000\000\000\000\000\000\000\000\000\000\000\302\033\033\213\350aa\377"
"\362\247\247\377\367\310\310\377\366\305\305\377\322\036\036\377\311\034\034"
"\377\276\033\033\377\275\032\032\377\357\217\217\377\376\373\373\377\373\350"
"\350\377\370\317\317\377\370\315\315\377\370\315\315\377\370\315\315\377"
"\374\351\351\377\376\367\367\377\363\262\262\377\325\036\036\377\275\032\032"
"\377\313\035\035\377\322\036\036\377\367\307\307\377\367\307\307\377\360\231"
"\231\377\351jj\377\311\034\034\213\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\237\026\026"
"\005\320\035\035\322\353xx\377\360\227\227\377\366\277\277\377\367\310\310\377"
"\341\062\062\377\311\034\034\377\276\033\033\377\325\036\036\377\345JJ\377\357\217"
"\217\377\364\265\265\377\370\315\315\377\370\315\315\377\364\265\265\377"
"\357\217\217\377\345JJ\377\302\033\033\377\275\032\032\377\313\035\035\377\343"
"<<\377\367\310\310\377\366\305\305\377\360\235\235\377\355\202\202\377\327"
"\036\036\322\237\026\026\005\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\307\034\034"
",\332\037\037\360\356\207\207\377\360\235\235\377\370\315\315\377\371\326\326"
"\377\347\\\\\377\302\033\033\377\275\032\032\377\302\033\033\377\275\032\032\377"
"\320\035\035\377\337\040\040\377\337\"\"\377\320\035\035\377\275\032\032\377\311"
"\034\034\377\303\034\034\377\275\032\032\377\347\\\\\377\371\334\334\377\370\315"
"\315\377\361\236\236\377\360\225\225\377\340%%\360\307\034\034,\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\307\034\034/\336\037\037\350\355"
"\202\202\377\363\262\262\377\365\274\274\377\373\344\344\377\366\277\277"
"\377\352oo\377\341\062\062\377\320\035\035\377\307\034\034\377\302\033\033\377\302"
"\033\033\377\307\034\034\377\314\035\035\377\340--\377\351ll\377\364\267\267\377"
"\371\334\334\377\365\270\270\377\364\267\267\377\356\215\215\377\337$$\350"
"\307\034\034/\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\307\034\034\062\322\036\036\320\353tt\377\366\301\301\377\367\312\312"
"\377\372\341\341\377\373\346\346\377\370\325\325\377\363\256\256\377\360"
"\231\231\377\356\207\207\377\356\207\207\377\360\235\235\377\363\262\262"
"\377\370\325\325\377\372\341\341\377\370\323\323\377\364\263\263\377\365"
"\270\270\377\354}}\377\327\036\036\320\307\034\034\062\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\257\030\030"
"\007\303\034\034\214\343<<\371\360\225\225\377\366\305\305\377\370\315\315\377"
"\370\315\315\377\371\332\332\377\373\344\344\377\375\360\360\377\375\364"
"\364\377\373\346\346\377\371\330\330\377\367\312\312\377\367\310\310\377"
"\365\272\272\377\357\220\220\377\343<<\371\307\034\034\214\257\030\030\007\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\302\033\033\062\314\035\035\240\342\071\071"
"\351\354yy\377\360\225\225\377\363\254\254\377\366\305\305\377\371\330\330"
"\377\371\330\330\377\367\307\307\377\363\254\254\377\357\224\224\377\353"
"xx\377\343<<\351\320\035\035\240\302\033\033\062\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\275\032\032\033\276\033\033]\311\034"
"\034\225\337$$\301\343<<\330\344GG\346\344GG\346\343<<\330\340''\301\313\035"
"\035\225\276\033\033]\275\032\032\033\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
#if 0
};
#endif

View file

@ -0,0 +1,423 @@
/* GIMP RGBA C-Source image dump (test.c) */
#if 0
static const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
unsigned char pixel_data[48 * 48 * 4 + 1];
} sdlappicon = {
48, 48, 4,
#endif
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\037\004\004\001\325\036"
"\036(\325\036\036_\325\036\036\222\325\036\036\270\325\036\036\321\325\036\036\343\325"
"\036\036\355\325\036\036\355\325\036\036\343\325\036\036\321\325\036\036\270\325\036"
"\036\222\325\036\036_\325\036\036(\037\004\004\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036"
"\036\325\036\036s\325\036\036\304\325\036\036\365\343<<\377\350aa\377\355\202\202"
"\377\361\242\242\377\366\277\277\377\366\301\301\377\366\277\277\377\362"
"\251\251\377\355\202\202\377\350ee\377\345JJ\377\340--\377\325\036\036\365"
"\325\036\036\304\325\036\036s\325\036\036\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\334\037\037&\325\036\036\222\325\036\036\354\343"
"AA\377\360\227\227\377\371\334\334\377\375\364\364\377\376\371\371\377\376"
"\371\371\377\375\366\366\377\374\353\353\377\372\341\341\377\371\330\330"
"\377\370\315\315\377\365\274\274\377\364\267\267\377\364\267\267\377\363"
"\253\253\377\360\235\235\377\352oo\377\341\062\062\377\325\036\036\354\325\036"
"\036\222\334\037\037&\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\311\034\034\014\325\036\036"
"|\325\036\036\354\345NN\377\365\270\270\377\373\350\350\377\375\362\362\377"
"\375\362\362\377\375\366\366\377\375\360\360\377\375\362\362\377\375\362"
"\362\377\373\350\350\377\371\334\334\377\371\326\326\377\367\312\312\377"
"\365\270\270\377\363\262\262\377\363\254\254\377\361\244\244\377\361\242"
"\242\377\362\247\247\377\363\262\262\377\361\236\236\377\344GG\377\325\036"
"\036\354\325\036\036|\311\034\034\014\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036\064\325\036\036\305\341\062"
"\062\377\360\231\231\377\367\310\310\377\370\325\325\377\371\334\334\377\373"
"\350\350\377\374\357\357\377\375\364\364\377\375\366\366\377\375\366\366"
"\377\376\367\367\377\375\366\366\377\375\366\366\377\375\364\364\377\374"
"\353\353\377\372\341\341\377\370\323\323\377\365\270\270\377\361\236\236"
"\377\361\236\236\377\361\244\244\377\363\262\262\377\366\301\301\377\367"
"\310\310\377\363\254\254\377\342\067\067\377\325\036\036\305\325\036\036\064\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036Z\325"
"\036\036\356\344GG\377\361\236\236\377\363\262\262\377\365\272\272\377\367"
"\310\310\377\371\326\326\377\373\350\350\377\375\364\364\377\376\371\371"
"\377\371\330\330\377\362\251\251\377\355\206\206\377\351ll\377\347WW\377"
"\346OO\377\347XX\377\352oo\377\360\227\227\377\370\325\325\377\375\362\362"
"\377\370\325\325\377\365\270\270\377\365\274\274\377\366\301\301\377\367"
"\307\307\377\370\323\323\377\372\341\341\377\351ff\377\325\036\036\356\325"
"\036\036Z\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036q\325\036"
"\036\374\347XX\377\357\220\220\377\360\225\225\377\361\242\242\377\364\263"
"\263\377\370\325\325\377\375\360\360\377\370\323\323\377\356\213\213\377"
"\345NN\377\342\067\067\377\342\067\067\377\342\067\067\377\341\062\062\377\340++"
"\377\337$$\377\331\037\037\377\320\035\035\377\314\035\035\377\311\034\034\377\337"
"\040\040\377\353tt\377\370\315\315\377\374\353\353\377\371\326\326\377\370"
"\315\315\377\371\330\330\377\373\346\346\377\374\351\351\377\357\224\224"
"\377\325\036\036\374\325\036\036q\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036q\320"
"\035\035\377\347XX\377\355\206\206\377\355\206\206\377\356\215\215\377\361"
"\244\244\377\371\330\330\377\370\321\321\377\347\\\\\377\340''\377\340--"
"\377\342\065\065\377\342\067\067\377\342\067\067\377\342\067\067\377\342\065\065\377"
"\340++\377\340%%\377\327\036\036\377\320\035\035\377\314\035\035\377\303\034\034"
"\377\302\033\033\377\307\034\034\377\322\036\036\377\347XX\377\370\323\323\377"
"\374\353\353\377\373\343\343\377\373\350\350\377\373\346\346\377\374\351"
"\351\377\363\254\254\377\332\037\037\377\325\036\036q\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036"
"Z\325\036\036\374\347WW\377\354yy\377\353xx\377\354\177\177\377\363\254\254"
"\377\376\367\367\377\353tt\377\313\035\035\377\327\036\036\377\337\040\040\377"
"\340++\377\341\064\064\377\342\067\067\377\342\067\067\377\342\067\067\377\342\065"
"\065\377\340--\377\340%%\377\327\036\036\377\320\035\035\377\313\035\035\377\303"
"\034\034\377\302\033\033\377\313\035\035\377\325\036\036\377\331\037\037\377\336\037"
"\037\377\356\207\207\377\376\371\371\377\374\353\353\377\373\346\346\377\372"
"\341\341\377\371\334\334\377\361\236\236\377\325\036\036\374\325\036\036Z\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327"
"\036\036\061\325\036\036\355\345NN\377\354{{\377\352oo\377\353tt\377\364\263\263"
"\377\373\350\350\377\343<<\377\275\032\032\377\303\034\034\377\320\035\035\377"
"\336\037\037\377\340''\377\341..\377\342\065\065\377\342\067\067\377\342\067\067"
"\377\342\065\065\377\340--\377\337$$\377\327\036\036\377\320\035\035\377\311\034"
"\034\377\302\033\033\377\303\034\034\377\320\035\035\377\331\037\037\377\332\037\037"
"\377\340''\377\340--\377\351ff\377\374\357\357\377\374\353\353\377\371\330"
"\330\377\370\315\315\377\367\310\310\377\354}}\377\325\036\036\355\327\036\036"
"\061\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\331\037\037\013"
"\325\036\036\310\342\071\071\377\356\213\213\377\354\177\177\377\354yy\377\364"
"\263\263\377\371\326\326\377\320\035\035\377\262\031\031\377\266\031\031\377\275"
"\032\032\377\307\034\034\377\327\036\036\377\337$$\377\340--\377\342\065\065\377"
"\342\067\067\377\342\067\067\377\342\065\065\377\340--\377\337$$\377\327\036\036"
"\377\314\035\035\377\311\034\034\377\302\033\033\377\311\034\034\377\325\036\036\377"
"\331\037\037\377\337\040\040\377\340--\377\341..\377\341..\377\345JJ\377\371"
"\334\334\377\373\343\343\377\366\277\277\377\365\270\270\377\366\277\277"
"\377\346QQ\377\325\036\036\310\331\037\037\013\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\325\036\036|\336\037\037\377\360\225\225\377\357\220\220\377"
"\356\207\207\377\363\262\262\377\372\341\341\377\303\034\034\377\257\030\030"
"\377\260\031\031\377\262\031\031\377\271\032\032\377\340''\377\363\254\254\377"
"\340--\377\340))\377\341\062\062\377\342\067\067\377\342\067\067\377\342\067\067"
"\377\340--\377\337$$\377\322\036\036\377\314\035\035\377\307\034\034\377\303\034"
"\034\377\320\035\035\377\331\037\037\377\353tt\377\345JJ\377\341..\377\341..\377"
"\340++\377\340''\377\342\065\065\377\373\344\344\377\370\323\323\377\364\263"
"\263\377\364\263\263\377\363\254\254\377\337$$\377\325\036\036|\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\322\036\036\"\325\036\036\356\354\177\177\377\361"
"\244\244\377\360\227\227\377\361\242\242\377\375\366\366\377\340''\377\257"
"\030\030\377\253\030\030\377\253\030\030\377\260\031\031\377\343<<\377\375\360\360"
"\377\370\323\323\377\361\236\236\377\337$$\377\331\037\037\377\275\032\032\377"
"\246\027\027\377\223\025\025\377\203\022\022\377\203\022\022\377\214\023\023\377\232"
"\026\026\377\250\030\030\377\273\032\032\377\322\036\036\377\342\071\071\377\376\367"
"\367\377\375\362\362\377\351jj\377\340--\377\340''\377\336\037\037\377\325"
"\036\036\377\343AA\377\375\366\366\377\365\272\272\377\362\251\251\377\361"
"\236\236\377\355\202\202\377\325\036\036\356\322\036\036\"\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\325\036\036\222\342\067\067\377\364\267\267\377\362\251\251\377"
"\361\244\244\377\370\325\325\377\351ll\377\271\032\032\377\264\031\031\377\262"
"\031\031\377\253\030\030\377\346SS\377\376\367\367\377\362\251\251\377\360\225"
"\225\377\375\366\366\377\313\035\035\377\177\022\022\377~\021\021\377x\021\021\377"
"w\020\020\377u\020\020\377u\020\020\377w\020\020\377x\021\021\377~\021\021\377\177\022"
"\022\377\250\030\030\377\363\253\253\377\374\357\357\377\374\357\357\377\376"
"\371\371\377\354yy\377\336\037\037\377\327\036\036\377\322\036\036\377\314\035\035"
"\377\353tt\377\371\326\326\377\360\231\231\377\360\227\227\377\360\235\235"
"\377\342\065\065\377\325\036\036\222\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036\036\325"
"\036\036\355\360\227\227\377\366\277\277\377\363\262\262\377\367\310\310\377"
"\370\315\315\377\303\034\034\377\276\033\033\377\275\032\032\377\266\031\031\377"
"\343<<\377\376\367\367\377\357\220\220\377\354{{\377\351ff\377\356\213\213"
"\377\360\227\227\377w\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377"
"u\020\020\377u\020\020\377u\020\020\377u\020\020\377w\020\020\377\253\030\030\377\371"
"\330\330\377\363\253\253\377\373\344\344\377\371\334\334\377\376\371\371"
"\377\347XX\377\322\036\036\377\314\035\035\377\303\034\034\377\302\033\033\377\370"
"\315\315\377\364\267\267\377\357\220\220\377\357\220\220\377\354\177\177"
"\377\325\036\036\355\325\036\036\036\000\000\000\000\000\000\000\000\325\036\036q\341..\377\367"
"\312\312\377\366\301\301\377\365\274\274\377\374\351\351\377\346OO\377\313"
"\035\035\377\307\034\034\377\302\033\033\377\340''\377\374\353\353\377\361\244"
"\244\377\353tt\377\346QQ\377\346OO\377\365\270\270\377\376\375\375\377\302"
"\033\033\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020"
"\377u\020\020\377u\020\020\377u\020\020\377\360\231\231\377\370\323\323\377\346"
"OO\377\357\220\220\377\366\301\301\377\370\315\315\377\374\357\357\377\341"
"..\377\302\033\033\377\276\033\033\377\275\032\032\377\343AA\377\372\341\341\377"
"\357\220\220\377\357\224\224\377\360\235\235\377\340))\377\325\036\036q\000\000"
"\000\000\221\024\024\003\325\036\036\305\353tt\377\366\301\301\377\365\272\272\377"
"\367\312\312\377\370\315\315\377\325\036\036\377\322\036\036\377\320\035\035\377"
"\314\035\035\377\364\263\263\377\367\307\307\377\357\220\220\377\350aa\377"
"\346OO\377\367\310\310\377\376\375\375\377\376\375\375\377\367\312\312\377"
"|\021\021\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020"
"\377u\020\020\377\271\032\032\377\376\375\375\377\376\375\375\377\367\310\310"
"\377\346OO\377\356\207\207\377\363\262\262\377\370\315\315\377\364\263\263"
"\377\276\033\033\377\275\032\032\377\273\032\032\377\273\032\032\377\367\310\310"
"\377\363\253\253\377\360\225\225\377\360\231\231\377\350ee\377\325\036\036"
"\305\221\024\024\003\327\036\036'\325\036\036\366\363\253\253\377\364\267\267\377"
"\365\270\270\377\373\343\343\377\353rr\377\327\036\036\377\327\036\036\377\327"
"\036\036\377\345NN\377\374\351\351\377\363\256\256\377\357\220\220\377\341"
"\064\064\377\365\270\270\377\376\375\375\377\376\375\375\377\376\375\375\377"
"\376\375\375\377\343AA\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020"
"\020\377u\020\020\377u\020\020\377\364\267\267\377\376\375\375\377\376\375\375"
"\377\376\375\375\377\365\270\270\377\341\064\064\377\356\215\215\377\360\227"
"\227\377\373\343\343\377\343<<\377\275\032\032\377\275\032\032\377\276\033\033"
"\377\350ee\377\370\323\323\377\357\224\224\377\357\224\224\377\357\220\220"
"\377\325\036\036\366\327\036\036'\325\036\036_\341..\377\364\267\267\377\364\263"
"\263\377\364\263\263\377\376\371\371\377\337\040\040\377\322\036\036\377\322"
"\036\036\377\327\036\036\377\366\277\277\377\370\323\323\377\365\272\272\377"
"\351ff\377\356\207\207\377\376\375\375\377\376\375\375\377\376\375\375\377"
"\376\375\375\377\376\375\375\377\374\353\353\377\223\025\025\377u\020\020\377"
"u\020\020\377u\020\020\377u\020\020\377u\020\020\377\320\035\035\377\376\375\375\377"
"\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\356\207"
"\207\377\346SS\377\357\224\224\377\365\270\270\377\365\272\272\377\275\032"
"\032\377\275\032\032\377\275\032\032\377\314\035\035\377\376\367\367\377\360\231"
"\231\377\360\231\231\377\361\242\242\377\340++\377\325\036\036_\325\036\036\222"
"\344GG\377\364\267\267\377\363\262\262\377\366\277\277\377\367\307\307\377"
"\320\035\035\377\320\035\035\377\320\035\035\377\340--\377\376\371\371\377\365"
"\274\274\377\361\242\242\377\343<<\377\372\335\335\377\376\375\375\377\376"
"\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375"
"\377\354\177\177\377\241\027\027\377\346SS\377\352oo\377\340%%\377\212\023\023"
"\377\367\312\312\377\376\375\375\377\376\375\375\377\376\375\375\377\376"
"\375\375\377\376\375\375\377\372\335\335\377\343<<\377\355\202\202\377\360"
"\225\225\377\376\367\367\377\331\037\037\377\275\032\032\377\276\033\033\377\302"
"\033\033\377\366\305\305\377\364\263\263\377\361\236\236\377\363\253\253\377"
"\344CC\377\325\036\036\222\325\036\036\272\351ff\377\364\263\263\377\363\256"
"\256\377\370\323\323\377\357\220\220\377\320\035\035\377\320\035\035\377\320"
"\035\035\377\351ff\377\372\341\341\377\364\263\263\377\352oo\377\354yy\377"
"\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375"
"\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377"
"\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375"
"\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377"
"\376\375\375\377\376\375\375\377\354yy\377\350]]\377\360\231\231\377\371"
"\330\330\377\350aa\377\302\033\033\377\302\033\033\377\303\034\034\377\357\220"
"\220\377\367\312\312\377\361\242\242\377\362\247\247\377\351jj\377\325\036"
"\036\272\325\036\036\321\355\202\202\377\365\270\270\377\363\262\262\377\372"
"\341\341\377\352mm\377\320\035\035\377\314\035\035\377\314\035\035\377\360\227"
"\227\377\370\321\321\377\363\256\256\377\345JJ\377\363\256\256\377\376\375"
"\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377"
"\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375"
"\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377"
"\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375"
"\375\377\376\375\375\377\363\256\256\377\344EE\377\361\236\236\377\367\310"
"\310\377\357\224\224\377\303\034\034\377\303\034\034\377\303\034\034\377\351jj"
"\377\371\330\330\377\362\247\247\377\363\253\253\377\356\207\207\377\325"
"\036\036\321\325\036\036\343\361\242\242\377\365\270\270\377\364\263\263\377"
"\373\350\350\377\347WW\377\320\035\035\377\320\035\035\377\320\035\035\377\365"
"\272\272\377\367\307\307\377\363\262\262\377\341..\377\371\326\326\377\376"
"\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375"
"\377\376\375\375\377\376\375\375\377\376\375\375\377\363\256\256\377\244"
"\027\027\377u\020\020\377\276\033\033\377\370\323\323\377\376\375\375\377\376\375"
"\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377"
"\376\375\375\377\371\326\326\377\340--\377\362\247\247\377\365\274\274\377"
"\366\277\277\377\311\034\034\377\311\034\034\377\311\034\034\377\346QQ\377\373"
"\344\344\377\363\253\253\377\363\254\254\377\357\224\224\377\325\036\036\343"
"\325\036\036\355\364\263\263\377\366\305\305\377\366\277\277\377\374\357\357"
"\377\345NN\377\327\036\036\377\327\036\036\377\327\036\036\377\370\315\315\377"
"\367\312\312\377\367\310\310\377\345JJ\377\375\364\364\377\376\375\375\377"
"\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375"
"\375\377\376\375\375\377\376\367\367\377\223\025\025\377u\020\020\377u\020\020"
"\377u\020\020\377\275\032\032\377\376\375\375\377\376\375\375\377\376\375\375"
"\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\375"
"\364\364\377\344GG\377\365\274\274\377\365\274\274\377\367\312\312\377\313"
"\035\035\377\313\035\035\377\313\035\035\377\344CC\377\374\351\351\377\363\254"
"\254\377\363\256\256\377\361\244\244\377\325\036\036\355\325\036\036\355\365"
"\270\270\377\367\312\312\377\367\310\310\377\375\360\360\377\346QQ\377\336"
"\037\037\377\336\037\037\377\336\037\037\377\363\254\254\377\370\321\321\377\370"
"\321\321\377\365\272\272\377\364\267\267\377\364\267\267\377\364\267\267"
"\377\364\267\267\377\364\267\267\377\364\267\267\377\372\341\341\377\376"
"\375\375\377\367\307\307\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377"
"\201\022\022\377\376\375\375\377\376\375\375\377\370\323\323\377\364\267\267"
"\377\364\267\267\377\364\267\267\377\364\267\267\377\364\267\267\377\365"
"\272\272\377\370\315\315\377\370\315\315\377\361\244\244\377\311\034\034\377"
"\311\034\034\377\311\034\034\377\343AA\377\373\350\350\377\363\253\253\377\363"
"\254\254\377\361\244\244\377\325\036\036\355\325\036\036\343\365\270\270\377"
"\370\323\323\377\370\315\315\377\374\357\357\377\350aa\377\337\040\040\377"
"\337$$\377\337$$\377\337$$\377\337$$\377\337$$\377\221\024\024\377w\020\020\377"
"u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377\346OO\377\376\375"
"\375\377\375\360\360\377\210\023\023\377u\020\020\377u\020\020\377u\020\020\377\253"
"\030\030\377\376\375\375\377\376\375\375\377\320\035\035\377u\020\020\377u\020\020"
"\377u\020\020\377u\020\020\377w\020\020\377\214\023\023\377\311\034\034\377\311\034"
"\034\377\311\034\034\377\311\034\034\377\311\034\034\377\311\034\034\377\346QQ\377"
"\373\344\344\377\363\253\253\377\363\253\253\377\360\235\235\377\325\036\036"
"\343\325\036\036\321\361\242\242\377\371\330\330\377\370\325\325\377\374\353"
"\353\377\354yy\377\337$$\377\340''\377\340''\377\340''\377\340''\377\340"
"%%\377\241\027\027\377x\021\021\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377"
"u\020\020\377\331\037\037\377\376\375\375\377\376\375\375\377\360\225\225\377"
"\210\023\023\377u\020\020\377\233\026\026\377\366\301\301\377\376\375\375\377\376"
"\375\375\377\233\026\026\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377x\021"
"\021\377\232\026\026\377\313\035\035\377\313\035\035\377\311\034\034\377\311\034\034"
"\377\311\034\034\377\311\034\034\377\351jj\377\371\334\334\377\363\253\253\377"
"\363\256\256\377\356\207\207\377\325\036\036\321\325\036\036\272\354\177\177"
"\377\371\334\334\377\371\330\330\377\373\346\346\377\360\235\235\377\340"
"%%\377\340''\377\340%%\377\340%%\377\337\040\040\377\337\040\040\377\262\031\031"
"\377~\021\021\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377~\021"
"\021\377\367\312\312\377\376\375\375\377\376\375\375\377\376\375\375\377\373"
"\344\344\377\376\375\375\377\376\375\375\377\376\375\375\377\360\231\231"
"\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377~\021\021\377\251"
"\030\030\377\311\034\034\377\311\034\034\377\311\034\034\377\311\034\034\377\311\034"
"\034\377\313\035\035\377\357\220\220\377\370\321\321\377\363\254\254\377\363"
"\262\262\377\352mm\377\325\036\036\272\325\036\036\222\347XX\377\371\334\334"
"\377\371\330\330\377\371\334\334\377\367\312\312\377\337$$\377\337\040\040"
"\377\337\040\040\377\336\037\037\377\332\037\037\377\331\037\037\377\303\034\034\377"
"\177\022\022\377w\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020"
"\020\377\235\026\026\377\367\307\307\377\376\375\375\377\376\375\375\377\376"
"\375\375\377\376\375\375\377\376\375\375\377\361\236\236\377\212\023\023\377"
"u\020\020\377u\020\020\377u\020\020\377u\020\020\377w\020\020\377\177\022\022\377\271"
"\032\032\377\307\034\034\377\307\034\034\377\311\034\034\377\311\034\034\377\311\034"
"\034\377\311\034\034\377\366\305\305\377\366\277\277\377\363\256\256\377\363"
"\262\262\377\345JJ\377\325\036\036\222\325\036\036_\342\065\065\377\371\330\330"
"\377\370\325\325\377\370\321\321\377\376\371\371\377\341..\377\336\037\037"
"\377\331\037\037\377\327\036\036\377\327\036\036\377\320\035\035\377\313\035\035\377"
"\241\027\027\377|\021\021\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020"
"\020\377u\020\020\377\351ll\377\376\375\375\377\376\375\375\377\376\375\375"
"\377\376\375\375\377\376\375\375\377\340%%\377u\020\020\377u\020\020\377u\020"
"\020\377u\020\020\377u\020\020\377|\021\021\377\241\027\027\377\302\033\033\377\302"
"\033\033\377\303\034\034\377\311\034\034\377\311\034\034\377\311\034\034\377\332\037"
"\037\377\376\371\371\377\363\254\254\377\363\254\254\377\363\262\262\377\340"
"--\377\325\036\036_\327\036\036'\325\036\036\366\366\277\277\377\367\312\312\377"
"\367\307\307\377\373\346\346\377\353rr\377\327\036\036\377\322\036\036\377\320"
"\035\035\377\313\035\035\377\302\033\033\377\276\033\033\377\266\031\031\377\177\022"
"\022\377w\020\020\377u\020\020\377u\020\020\377u\020\020\377u\020\020\377\253\030\030"
"\377\376\367\367\377\376\375\375\377\376\375\375\377\376\375\375\377\376"
"\375\375\377\376\375\375\377\373\344\344\377\210\023\023\377u\020\020\377u\020"
"\020\377u\020\020\377w\020\020\377\177\022\022\377\262\031\031\377\275\032\032\377\276"
"\033\033\377\302\033\033\377\302\033\033\377\303\034\034\377\303\034\034\377\351ff"
"\377\371\334\334\377\362\251\251\377\363\253\253\377\362\247\247\377\325"
"\036\036\366\327\036\036'\221\024\024\003\325\036\036\305\354}}\377\367\310\310\377"
"\366\301\301\377\370\315\315\377\367\312\312\377\320\035\035\377\311\034\034"
"\377\303\034\034\377\302\033\033\377\275\032\032\377\275\032\032\377\276\033\033\377"
"\253\030\030\377~\021\021\377w\020\020\377u\020\020\377u\020\020\377w\020\020\377\365"
"\272\272\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375"
"\377\376\375\375\377\376\375\375\377\376\375\375\377\354\177\177\377u\020"
"\020\377u\020\020\377w\020\020\377~\021\021\377\253\030\030\377\271\032\032\377\271"
"\032\032\377\273\032\032\377\275\032\032\377\276\033\033\377\302\033\033\377\303\034"
"\034\377\367\310\310\377\364\267\267\377\361\244\244\377\363\253\253\377\352"
"oo\377\325\036\036\305\221\024\024\003\000\000\000\000\325\036\036q\340--\377\367\307\307"
"\377\365\270\270\377\363\262\262\377\373\346\346\377\344GG\377\302\033\033"
"\377\275\032\032\377\275\032\032\377\275\032\032\377\275\032\032\377\275\032\032\377"
"\275\032\032\377\250\030\030\377~\021\021\377w\020\020\377u\020\020\377\343AA\377\376"
"\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375"
"\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\271"
"\032\032\377w\020\020\377~\021\021\377\250\030\030\377\275\032\032\377\275\032\032\377"
"\273\032\032\377\273\032\032\377\271\032\032\377\275\032\032\377\275\032\032\377\343"
"AA\377\373\344\344\377\361\236\236\377\361\244\244\377\363\254\254\377\340"
"++\377\325\036\036q\000\000\000\000\000\000\000\000\325\036\036\036\325\036\036\355\356\215\215"
"\377\363\262\262\377\362\247\247\377\365\272\272\377\370\315\315\377\276"
"\033\033\377\275\032\032\377\275\032\032\377\275\032\032\377\275\032\032\377\275\032"
"\032\377\273\032\032\377\275\032\032\377\257\030\030\377\177\022\022\377\237\026\026"
"\377\374\353\353\377\376\375\375\377\376\375\375\377\376\375\375\377\376"
"\375\375\377\376\375\375\377\376\375\375\377\376\375\375\377\376\375\375"
"\377\373\346\346\377\370\315\315\377\206\023\023\377\260\031\031\377\276\033\033"
"\377\275\032\032\377\276\033\033\377\275\032\032\377\273\032\032\377\271\032\032\377"
"\271\032\032\377\275\032\032\377\370\315\315\377\365\270\270\377\360\227\227"
"\377\361\242\242\377\356\213\213\377\325\036\036\355\325\036\036\036\000\000\000\000\000"
"\000\000\000\000\000\000\000\325\036\036\222\340--\377\362\247\247\377\360\227\227\377\360"
"\225\225\377\370\323\323\377\352mm\377\275\032\032\377\275\032\032\377\275\032"
"\032\377\273\032\032\377\273\032\032\377\275\032\032\377\302\033\033\377\303\034\034"
"\377\276\033\033\377\363\254\254\377\357\224\224\377\354yy\377\363\256\256"
"\377\371\326\326\377\375\362\362\377\375\362\362\377\371\326\326\377\363"
"\256\256\377\354yy\377\343<<\377\365\270\270\377\355\202\202\377\311\034\034"
"\377\303\034\034\377\276\033\033\377\275\032\032\377\275\032\032\377\275\032\032\377"
"\275\032\032\377\273\032\032\377\351jj\377\370\315\315\377\356\215\215\377\357"
"\224\224\377\361\236\236\377\343<<\377\325\036\036\222\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\322\036\036\"\325\036\036\356\353tt\377\360\227\227\377\360\225"
"\225\377\362\251\251\377\375\366\366\377\340--\377\275\032\032\377\273\032\032"
"\377\273\032\032\377\275\032\032\377\302\033\033\377\303\034\034\377\311\034\034\377"
"\350aa\377\373\346\346\377\361\242\242\377\353tt\377\345NN\377\341\062\062"
"\377\336\037\037\377\336\037\037\377\341\062\062\377\345JJ\377\352oo\377\360\231"
"\231\377\363\262\262\377\375\366\366\377\341\062\062\377\311\034\034\377\302"
"\033\033\377\275\032\032\377\275\032\032\377\275\032\032\377\275\032\032\377\340--"
"\377\375\366\366\377\361\236\236\377\356\213\213\377\357\220\220\377\354"
"}}\377\325\036\036\356\322\036\036\"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\325\036\036|\331\037\037\377\360\227\227\377\360\231\231\377\360\227\227\377"
"\366\277\277\377\372\341\341\377\327\036\036\377\273\032\032\377\275\032\032\377"
"\276\033\033\377\302\033\033\377\307\034\034\377\332\037\037\377\373\350\350\377"
"\370\323\323\377\366\277\277\377\365\270\270\377\365\270\270\377\366\277"
"\277\377\367\310\310\377\367\312\312\377\366\277\277\377\364\267\267\377"
"\364\263\263\377\364\263\263\377\367\312\312\377\373\346\346\377\356\207"
"\207\377\311\034\034\377\303\034\034\377\302\033\033\377\275\032\032\377\275\032\032"
"\377\327\036\036\377\373\343\343\377\366\277\277\377\357\220\220\377\357\220"
"\220\377\357\224\224\377\340''\377\325\036\036|\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\331\037\037\013\325\036\036\310\342\067\067\377\361\236\236"
"\377\357\224\224\377\357\220\220\377\366\305\305\377\371\330\330\377\336"
"\037\037\377\276\033\033\377\302\033\033\377\303\034\034\377\311\034\034\377\320\035"
"\035\377\346QQ\377\366\277\277\377\376\367\367\377\373\344\344\377\370\325"
"\325\377\371\330\330\377\370\325\325\377\371\326\326\377\371\330\330\377"
"\370\325\325\377\373\343\343\377\375\366\366\377\365\274\274\377\345JJ\377"
"\303\034\034\377\307\034\034\377\311\034\034\377\307\034\034\377\302\033\033\377\336"
"\037\037\377\371\330\330\377\367\310\310\377\360\225\225\377\357\224\224\377"
"\360\225\225\377\345JJ\377\325\036\036\310\331\037\037\013\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327\036\036\061\325\036\036\355\347XX\377"
"\360\225\225\377\357\220\220\377\357\220\220\377\366\301\301\377\374\351"
"\351\377\343AA\377\302\033\033\377\311\034\034\377\314\035\035\377\322\036\036\377"
"\327\036\036\377\327\036\036\377\337$$\377\350ee\377\361\236\236\377\363\253"
"\253\377\370\321\321\377\370\321\321\377\363\253\253\377\361\236\236\377"
"\350ee\377\336\037\037\377\320\035\035\377\314\035\035\377\311\034\034\377\307\034"
"\034\377\311\034\034\377\311\034\034\377\343AA\377\374\351\351\377\366\301\301"
"\377\360\225\225\377\360\225\225\377\360\231\231\377\352mm\377\325\036\036"
"\355\327\036\036\061\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\325\036\036Z\325\036\036\374\352mm\377\360\227\227\377\357\224"
"\224\377\360\227\227\377\366\277\277\377\376\371\371\377\354yy\377\313\035"
"\035\377\320\035\035\377\322\036\036\377\325\036\036\377\325\036\036\377\322\036\036"
"\377\320\035\035\377\325\036\036\377\331\037\037\377\336\037\037\377\336\037\037\377"
"\331\037\037\377\322\036\036\377\320\035\035\377\320\035\035\377\320\035\035\377\320"
"\035\035\377\313\035\035\377\307\034\034\377\307\034\034\377\354yy\377\376\371\371"
"\377\366\277\277\377\360\231\231\377\360\225\225\377\360\231\231\377\354"
"\177\177\377\325\036\036\374\325\036\036Z\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036q\322\036\036"
"\377\353rr\377\360\235\235\377\361\236\236\377\361\236\236\377\363\262\262"
"\377\371\334\334\377\370\321\321\377\345JJ\377\327\036\036\377\327\036\036\377"
"\322\036\036\377\322\036\036\377\320\035\035\377\327\036\036\377\331\037\037\377\336"
"\037\037\377\336\037\037\377\332\037\037\377\325\036\036\377\320\035\035\377\320\035"
"\035\377\320\035\035\377\320\035\035\377\313\035\035\377\344CC\377\370\315\315\377"
"\371\330\330\377\363\262\262\377\361\244\244\377\362\247\247\377\361\236"
"\236\377\355\202\202\377\336\037\037\377\325\036\036q\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\325\036\036q\325\036\036\374\351ff\377\361\236\236\377\362\251\251\377"
"\362\251\251\377\363\256\256\377\370\315\315\377\374\353\353\377\367\312"
"\312\377\354}}\377\341..\377\320\035\035\377\322\036\036\377\327\036\036\377\332"
"\037\037\377\336\037\037\377\336\037\037\377\332\037\037\377\327\036\036\377\322\036"
"\036\377\320\035\035\377\340++\377\354yy\377\367\312\312\377\373\350\350\377"
"\366\305\305\377\362\247\247\377\363\253\253\377\363\253\253\377\362\251"
"\251\377\353tt\377\325\036\036\374\325\036\036q\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\325\036\036Z\325\036\036\356\345JJ\377\363\254\254\377\364"
"\263\263\377\364\263\263\377\365\270\270\377\365\274\274\377\370\315\315"
"\377\372\341\341\377\375\364\364\377\370\323\323\377\361\236\236\377\354"
"{{\377\353tt\377\346QQ\377\346QQ\377\353tt\377\354{{\377\361\236\236\377"
"\370\323\323\377\375\364\364\377\371\334\334\377\366\305\305\377\363\254"
"\254\377\362\251\251\377\362\247\247\377\363\262\262\377\363\256\256\377"
"\346SS\377\325\036\036\356\325\036\036Z\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036\064\325\036\036\305\340))\377\357\220\220"
"\377\365\274\274\377\366\277\277\377\366\277\277\377\365\274\274\377\365"
"\272\272\377\364\263\263\377\366\301\301\377\370\325\325\377\373\343\343"
"\377\373\344\344\377\375\360\360\377\375\360\360\377\373\346\346\377\373"
"\343\343\377\370\325\325\377\366\301\301\377\364\267\267\377\364\267\267"
"\377\363\262\262\377\364\263\263\377\363\262\262\377\363\254\254\377\357"
"\220\220\377\341..\377\325\036\036\305\325\036\036\064\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\311\034\034\014\325"
"\036\036|\325\036\036\354\343<<\377\361\236\236\377\367\307\307\377\366\277\277"
"\377\365\272\272\377\364\267\267\377\364\267\267\377\365\272\272\377\366"
"\277\277\377\366\301\301\377\367\312\312\377\370\315\315\377\367\310\310"
"\377\366\277\277\377\365\270\270\377\364\267\267\377\364\263\263\377\364"
"\263\263\377\365\272\272\377\364\267\267\377\361\236\236\377\344EE\377\325"
"\036\036\354\325\036\036|\311\034\034\014\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\334\037"
"\037&\325\036\036\222\325\036\036\354\340))\377\353tt\377\363\256\256\377\366"
"\277\277\377\366\301\301\377\366\277\277\377\366\305\305\377\367\307\307"
"\377\370\315\315\377\370\321\321\377\370\315\315\377\367\307\307\377\366"
"\277\277\377\366\277\277\377\365\270\270\377\363\254\254\377\354{{\377\341"
"\064\064\377\325\036\036\354\325\036\036\222\334\037\037&\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\036\036\036\325\036\036s\325\036\036"
"\304\325\036\036\365\340++\377\345JJ\377\352mm\377\357\220\220\377\363\254"
"\254\377\364\267\267\377\364\267\267\377\363\256\256\377\357\220\220\377"
"\353rr\377\346OO\377\340--\377\325\036\036\365\325\036\036\304\325\036\036s\325"
"\036\036\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\037\004\004\001\325\036\036(\325\036\036_\325\036\036"
"\222\325\036\036\270\325\036\036\321\325\036\036\343\325\036\036\355\325\036\036\355"
"\325\036\036\343\325\036\036\321\325\036\036\270\325\036\036\222\325\036\036_\325\036"
"\036(\037\004\004\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
#if 0
};
#endif

BIN
source/blood/rsrc/game.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

View file

@ -0,0 +1 @@
#include "eduke32_icon.c"

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

View file

@ -0,0 +1,80 @@
#define NEED_COMMCTRL_H
#include "../../build/include/windows_inc.h"
#include "../src/startwin.game.h"
RSRC_ICON ICON "game_icon.ico"
RSRC_BMP BITMAP "game.bmp"
WIN_STARTWIN DIALOGEX DISCARDABLE 20, 40, 260, 200
STYLE DS_MODALFRAME | DS_CENTER | DS_SETFONT | DS_FIXEDSYS | WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE | WS_SYSMENU
CAPTION "Startup"
FONT 8, "MS Shell Dlg"
BEGIN
CONTROL "", WIN_STARTWIN_BITMAP, "STATIC", SS_BITMAP | SS_CENTERIMAGE | WS_CHILD | WS_VISIBLE, 0, 0, 66, 172
CONTROL "", WIN_STARTWIN_TABCTL, WC_TABCONTROL, WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 5, 250, 170
CONTROL "&Start", WIN_STARTWIN_START, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 180, 48, 14
CONTROL "&Cancel", WIN_STARTWIN_CANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 207, 180, 48, 14
CONTROL "", WIN_STARTWIN_MESSAGES, "EDIT", ES_MULTILINE | ES_READONLY | WS_CHILD | WS_VSCROLL, 0, 0, 32, 32
END
WIN_STARTWINPAGE_CONFIG DIALOGEX DISCARDABLE 20, 40, 279, 168
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
CAPTION "Dialog"
FONT 8, "MS Shell Dlg"
BEGIN
CONTROL "&Video mode:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 6, 50, 8
CONTROL "", IDCVMODE, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 4, 86, 56
CONTROL "&Fullscreen", IDCFULLSCREEN, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 154, 6, 46, 10
//#if defined POLYMER && POLYMER != 0
// CONTROL "&Polymer", IDCPOLYMER, "BUTTON", BS_CHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 203, 6, 40, 10
//#endif
CONTROL "Input devices:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 20, 50, 8
CONTROL "", IDCINPUT, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 60, 19, 86, 56
CONTROL "&Game:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 35, 100, 8
CONTROL "", IDCDATA, "LISTBOX", LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS | LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 10, 45, 226, 43
CONTROL "Custom game content &directory:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 90, 160, 8
CONTROL "", IDCGAMEDIR, "COMBOBOX", CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 10, 99, 226, 156
CONTROL "&Enable ""autoload"" folder", IDCAUTOLOAD, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 5, 116, 100, 8
CONTROL "&Always show this window at startup", IDCALWAYSSHOW, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 118, 116, 140, 8
END
#define FILEVER 1,9,9,9
#define PRODUCTVER 1,9,9,9
#define STRFILEVER "2.0.0devel\0"
#define STRPRODUCTVER "2.0.0devel\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION FILEVER
PRODUCTVERSION PRODUCTVER
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x3L
#else
FILEFLAGS 0x2L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "NBlood"
VALUE "FileVersion", STRFILEVER
VALUE "InternalName", "NBlood"
VALUE "LegalCopyright", "Copyright © 2018 EDuke32 Developers, 1996, 2003 3D Realms Entertainment"
VALUE "LegalTrademarks", "Duke Nukem® is a Registered Trademark of Gearbox Software, LLC."
VALUE "OriginalFilename", "nblood.exe"
VALUE "ProductName", "NBlood"
VALUE "ProductVersion", STRPRODUCTVER
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
1 24 "manifest.game.xml"

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="EDuke32.Mapster32"
type="win32"
/>
<description>Mapster32 for EDuke32</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="NBlood"
type="win32"
/>
<description>NBlood</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

376
source/blood/src/_functio.h Normal file
View file

@ -0,0 +1,376 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
// _functio.h
// file created by makehead.exe
// these headers contain default key assignments, as well as
// default button assignments and game function names
// axis defaults are also included
#include "_control.h"
#include "control.h"
#ifndef function_private_h_
#define function_private_h_
#ifdef __cplusplus
extern "C" {
#endif
// KEEPINSYNC lunatic/con_lang.lua
char gamefunctions[NUMGAMEFUNCTIONS][MAXGAMEFUNCLEN] =
{
"Move_Forward",
"Move_Backward",
"Turn_Left",
"Turn_Right",
"Turn_Around",
"Strafe",
"Strafe_Left",
"Strafe_Right",
"Jump",
"Crouch",
"Run",
"AutoRun",
"Open",
"Weapon_Fire",
"Weapon_Special_Fire",
"Aim_Up",
"Aim_Down",
"Aim_Center",
"Look_Up",
"Look_Down",
"Tilt_Left",
"Tilt_Right",
"Weapon_1",
"Weapon_2",
"Weapon_3",
"Weapon_4",
"Weapon_5",
"Weapon_6",
"Weapon_7",
"Weapon_8",
"Weapon_9",
"Weapon_10",
"Inventory_Use",
"Inventory_Left",
"Inventory_Right",
"Map_Toggle",
"Map_Follow_Mode",
"Shrink_Screen",
"Enlarge_Screen",
"Send_Message",
"See_Coop_View",
"See_Chase_View",
"Mouse_Aiming",
"Toggle_Crosshair",
"Next_Weapon",
"Previous_Weapon",
"Holster_Weapon",
"Show_Opponents_Weapon",
"BeastVision",
"CrystalBall",
"JumpBoots",
"MedKit",
"ProximityBombs",
"RemoteBombs",
"Show_Console",
};
#ifdef __SETUP__
const char keydefaults[NUMGAMEFUNCTIONS*2][MAXGAMEFUNCLEN] =
{
"W", "Kpad8",
"S", "Kpad2",
"Left", "Kpad4",
"Right", "KPad6",
"BakSpc", "",
"LAlt", "RAlt",
"A", "",
"D", "",
"Space", "/",
"LCtrl", "",
"LShift", "RShift",
"CapLck", "",
"E", "",
"RCtrl", "",
"X", "",
"Home", "KPad7",
"End", "Kpad1",
"KPad5", "",
"PgUp", "Kpad9",
"PgDn", "Kpad3",
"Insert", "Kpad0",
"Delete", "Kpad.",
"1", "",
"2", "",
"3", "",
"4", "",
"5", "",
"6", "",
"7", "",
"8", "",
"9", "",
"0", "",
"Enter", "KpdEnt",
"[", "",
"]", "",
"Tab", "",
"F", "",
"-", "Kpad-",
"=", "Kpad+",
"T", "",
"K", "",
"F7", "",
"U", "",
"I", "",
"'", "",
";", "",
"ScrLck", "",
"Y", "",
"B", "",
"C", "",
"J", "",
"M", "",
"P", "",
"R", "",
"`", "",
};
const char oldkeydefaults[NUMGAMEFUNCTIONS*2][MAXGAMEFUNCLEN] =
{
"Up", "Kpad8",
"Down", "Kpad2",
"Left", "Kpad4",
"Right", "KPad6",
"BakSpc", "",
"LAlt", "RAlt",
",", "",
".", "",
"A", "/",
"Z", "",
"LShift", "RShift",
"CapLck", "",
"Space", "",
"LCtrl", "RCtrl",
"X", "",
"Home", "KPad7",
"End", "Kpad1",
"KPad5", "",
"PgUp", "Kpad9",
"PgDn", "Kpad3",
"Insert", "Kpad0",
"Delete", "Kpad.",
"1", "",
"2", "",
"3", "",
"4", "",
"5", "",
"6", "",
"7", "",
"8", "",
"9", "",
"0", "",
"Enter", "KpdEnt",
"[", "",
"]", "",
"Tab", "",
"F", "",
"-", "Kpad-",
"=", "Kpad+",
"T", "",
"K", "",
"F7", "",
"U", "",
"I", "",
"'", "",
";", "",
"ScrLck", "",
"W", "",
"B", "",
"C", "",
"J", "",
"M", "",
"P", "",
"R", "",
"`", "",
};
static const char * mousedefaults[MAXMOUSEBUTTONS] =
{
"Weapon_Fire",
"Weapon_Special_Fire",
"",
"",
"Previous_Weapon",
"Next_Weapon",
};
static const char * mouseclickeddefaults[MAXMOUSEBUTTONS] =
{
};
static const char * mouseanalogdefaults[MAXMOUSEAXES] =
{
"analog_turning",
"analog_moving",
};
static const char * mousedigitaldefaults[MAXMOUSEDIGITAL] =
{
};
#if defined(GEKKO)
static const char * joystickdefaults[MAXJOYBUTTONSANDHATS] =
{
"Open", // A
"Fire", // B
"Run", // 1
"Map", // 2
"Previous_Weapon", // -
"Next_Weapon", // +
"", // Home
"Jump", // Z
"Crouch", // C
"Map", // X
"Run", // Y
"Jump", // L
"Quick_Kick", // R
"Crouch", // ZL
"Fire", // ZR
"Quick_Kick", // D-Pad Up
"Inventory_Right", // D-Pad Right
"Inventory", // D-Pad Down
"Inventory_Left", // D-Pad Left
};
static const char * joystickclickeddefaults[MAXJOYBUTTONSANDHATS] =
{
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"Inventory",
};
static const char * joystickanalogdefaults[MAXJOYAXES] =
{
"analog_strafing",
"analog_moving",
"analog_turning",
"analog_lookingupanddown",
};
static const char * joystickdigitaldefaults[MAXJOYDIGITAL] =
{
};
#else
static const char * joystickdefaults[MAXJOYBUTTONSANDHATS] =
{
"Fire",
"Strafe",
"Run",
"Open",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"Aim_Down",
"Look_Right",
"Aim_Up",
"Look_Left",
};
static const char * joystickclickeddefaults[MAXJOYBUTTONSANDHATS] =
{
"",
"Inventory",
"Jump",
"Crouch",
};
static const char * joystickanalogdefaults[MAXJOYAXES] =
{
"analog_turning",
"analog_moving",
"analog_strafing",
};
static const char * joystickdigitaldefaults[MAXJOYDIGITAL] =
{
"",
"",
"",
"",
"",
"",
"Run",
};
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

149
source/blood/src/_midi.h Normal file
View file

@ -0,0 +1,149 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#ifndef ___MIDI_H
#define ___MIDI_H
#include "compat.h"
#define RELATIVE_BEAT( measure, beat, tick ) \
( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) )
//Bobby Prince thinks this may be 100
//#define GENMIDI_DefaultVolume 100
#define GENMIDI_DefaultVolume 90
#define MAX_FORMAT 1
#define NUM_MIDI_CHANNELS 16
#define TIME_PRECISION 16
#define MIDI_HEADER_SIGNATURE 0x6468544d // "MThd"
#define MIDI_TRACK_SIGNATURE 0x6b72544d // "MTrk"
#define MIDI_VOLUME 7
#define MIDI_PAN 10
#define MIDI_DETUNE 94
#define MIDI_RHYTHM_CHANNEL 9
#define MIDI_RPN_MSB 100
#define MIDI_RPN_LSB 101
#define MIDI_DATAENTRY_MSB 6
#define MIDI_DATAENTRY_LSB 38
#define MIDI_PITCHBEND_MSB 0
#define MIDI_PITCHBEND_LSB 0
#define MIDI_RUNNING_STATUS 0x80
#define MIDI_NOTE_OFF 0x8
#define MIDI_NOTE_ON 0x9
#define MIDI_POLY_AFTER_TCH 0xA
#define MIDI_CONTROL_CHANGE 0xB
#define MIDI_PROGRAM_CHANGE 0xC
#define MIDI_AFTER_TOUCH 0xD
#define MIDI_PITCH_BEND 0xE
#define MIDI_SPECIAL 0xF
#define MIDI_SYSEX 0xF0
#define MIDI_SYSEX_CONTINUE 0xF7
#define MIDI_META_EVENT 0xFF
#define MIDI_END_OF_TRACK 0x2F
#define MIDI_TEMPO_CHANGE 0x51
#define MIDI_TIME_SIGNATURE 0x58
#define MIDI_RESET_ALL_CONTROLLERS 0x79
#define MIDI_ALL_NOTES_OFF 0x7b
#define MIDI_MONO_MODE_ON 0x7E
#define MIDI_SYSTEM_RESET 0xFF
#define GET_NEXT_EVENT( track, data ) do { \
( data ) = *( track )->pos; \
( track )->pos += 1; \
} while (0)
#define GET_MIDI_CHANNEL( event ) ( ( event ) & 0xf )
#define GET_MIDI_COMMAND( event ) ( ( event ) >> 4 )
#define EMIDI_INFINITE -1
#define EMIDI_END_LOOP_VALUE 127
#define EMIDI_ALL_CARDS 127
#define EMIDI_INCLUDE_TRACK 110
#define EMIDI_EXCLUDE_TRACK 111
#define EMIDI_PROGRAM_CHANGE 112
#define EMIDI_VOLUME_CHANGE 113
#define EMIDI_CONTEXT_START 114
#define EMIDI_CONTEXT_END 115
#define EMIDI_LOOP_START 116
#define EMIDI_LOOP_END 117
#define EMIDI_SONG_LOOP_START 118
#define EMIDI_SONG_LOOP_END 119
#define EMIDI_GeneralMIDI 0
#define EMIDI_SoundBlaster 4
#define EMIDI_AffectsCurrentCard(c, type) (((c) == EMIDI_ALL_CARDS) || ((c) == (type)))
#define EMIDI_NUM_CONTEXTS 7
typedef struct
{
char *pos;
char *loopstart;
int16_t loopcount;
int16_t RunningStatus;
unsigned time;
int32_t FPSecondsPerTick;
int16_t tick;
int16_t beat;
int16_t measure;
int16_t BeatsPerMeasure;
int16_t TicksPerBeat;
int16_t TimeBase;
int32_t delay;
int16_t active;
} songcontext;
typedef struct
{
char *start;
char *pos;
int32_t delay;
int16_t active;
int16_t RunningStatus;
int16_t currentcontext;
songcontext context[EMIDI_NUM_CONTEXTS];
char EMIDI_IncludeTrack;
char EMIDI_ProgramChange;
char EMIDI_VolumeChange;
} track;
static int32_t _MIDI_ReadNumber(void *from, size_t size);
static int32_t _MIDI_ReadDelta(track *ptr);
static void _MIDI_ResetTracks(void);
static void _MIDI_AdvanceTick(void);
static void _MIDI_MetaEvent(track *Track);
static void _MIDI_SysEx(track *Track);
static int32_t _MIDI_InterpretControllerInfo(track *Track, int32_t TimeSet, int32_t channel, int32_t c1, int32_t c2);
static int32_t _MIDI_SendControlChange(int32_t channel, int32_t c1, int32_t c2);
static void _MIDI_SetChannelVolume(int32_t channel, int32_t volume);
static void _MIDI_SendChannelVolumes(void);
static void _MIDI_InitEMIDI(void);
#endif

7247
source/blood/src/actor.cpp Normal file

File diff suppressed because it is too large Load diff

280
source/blood/src/actor.h Normal file
View file

@ -0,0 +1,280 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "build.h"
#include "common_game.h"
#include "blood.h"
#include "db.h"
#include "fx.h"
#include "gameutil.h"
enum DAMAGE_TYPE {
DAMAGE_TYPE_0 = 0,
DAMAGE_TYPE_1, // Flame
DAMAGE_TYPE_2,
DAMAGE_TYPE_3,
DAMAGE_TYPE_4,
DAMAGE_TYPE_5,
DAMAGE_TYPE_6, // Tesla
};
enum VECTOR_TYPE {
VECTOR_TYPE_0 = 0,
VECTOR_TYPE_1,
VECTOR_TYPE_2,
VECTOR_TYPE_3,
VECTOR_TYPE_4,
VECTOR_TYPE_5,
VECTOR_TYPE_6,
VECTOR_TYPE_7,
VECTOR_TYPE_8,
VECTOR_TYPE_9,
VECTOR_TYPE_10,
VECTOR_TYPE_11,
VECTOR_TYPE_12,
VECTOR_TYPE_13,
VECTOR_TYPE_14,
VECTOR_TYPE_15,
VECTOR_TYPE_16,
VECTOR_TYPE_17,
VECTOR_TYPE_18,
VECTOR_TYPE_19,
VECTOR_TYPE_20,
VECTOR_TYPE_21,
VECTOR_TYPE_22,
kVectorMax,
};
struct THINGINFO
{
short at0; // health
short at2; // mass
unsigned char at4; // clipdist
short at5; // flags
int at7; // elasticity
int atb; // damage resistance
short atf; // cstat
short at11; // picnum
char at13; // shade
unsigned char at14; // pal
unsigned char at15; // xrepeat
unsigned char at16; // yrepeat
int at17[7]; // damage
int allowThrow; // By NoOne: indicates if kGDXCustomDude can throw it
};
struct AMMOITEMDATA
{
short at0;
short picnum; // startHealth
char shade; // mass
char at5;
unsigned char xrepeat; // at6
unsigned char yrepeat; // at7
short at8;
unsigned char ata;
unsigned char atb;
};
struct WEAPONITEMDATA
{
short at0;
short picnum; // startHealth
char shade; // mass
char at5;
unsigned char xrepeat; // at6
unsigned char yrepeat; // at7
short at8;
short ata;
short atc;
};
struct ITEMDATA
{
short at0; // unused?
short picnum; // startHealth
char shade; // mass
char at5; // unused?
unsigned char xrepeat; // at6
unsigned char yrepeat; // at7
short at8;
};
struct MissileType
{
short picnum;
int at2; // speed
int at6; // angle
unsigned char ata; // xrepeat
unsigned char atb; // yrepeat
char atc; // shade
unsigned char atd; // clipdist
int fireSound[2]; // By NoOne: predefined fire sounds. used by kGDXCustomDude, but can be used for something else.
};
struct EXPLOSION
{
unsigned char at0;
char at1; // dmg
char at2; // dmg rnd
int at3; // radius
int at7;
int atb;
int atf;
int at13;
int at17;
};
struct VECTORDATA_at1d {
FX_ID at0;
FX_ID at1;
FX_ID at2;
int at3;
};
struct VECTORDATA {
DAMAGE_TYPE at0;
int at1; // damage
int at5;
int maxDist; // range
int atd;
int at11; // burn
int at15; // blood splats
int at19; // blood splat chance
VECTORDATA_at1d at1d[15];
int fireSound[2]; // By NoOne: predefined fire sounds. used by kGDXCustomDude, but can be used for something else.
};
struct SPRITEHIT {
int hit, ceilhit, florhit;
};
extern AMMOITEMDATA gAmmoItemData[];
extern WEAPONITEMDATA gWeaponItemData[];
extern ITEMDATA gItemData[];
extern MissileType missileInfo[];
extern EXPLOSION explodeInfo[];
extern THINGINFO thingInfo[];
extern VECTORDATA gVectorData[];
extern SPRITEHIT gSpriteHit[];
extern int gDudeDrag;
extern short gAffectedSectors[kMaxSectors];
extern short gAffectedXWalls[kMaxXWalls];
inline void GetSpriteExtents(spritetype *pSprite, int *top, int *bottom)
{
*top = *bottom = pSprite->z;
if ((pSprite->cstat & 0x30) != 0x20)
{
int height = tilesiz[pSprite->picnum].y;
int center = height / 2 + picanm[pSprite->picnum].yofs;
*top -= (pSprite->yrepeat << 2)*center;
*bottom += (pSprite->yrepeat << 2)*(height - center);
}
}
inline bool IsPlayerSprite(spritetype *pSprite)
{
if (pSprite->type >= kDudePlayer1 && pSprite->type <= kDudePlayer8)
return 1;
return 0;
}
inline bool IsDudeSprite(spritetype *pSprite)
{
if (pSprite->type >= kDudeBase && pSprite->type < kDudeMax)
return 1;
return 0;
}
inline void actBurnSprite(int nSource, XSPRITE *pXSprite, int nTime)
{
pXSprite->burnTime = ClipHigh(pXSprite->burnTime + nTime, sprite[pXSprite->reference].statnum == 6 ? 2400 : 1200);
pXSprite->burnSource = nSource;
}
bool IsItemSprite(spritetype *pSprite);
bool IsWeaponSprite(spritetype *pSprite);
bool IsAmmoSprite(spritetype *pSprite);
bool IsUnderwaterSector(int nSector);
int actSpriteOwnerToSpriteId(spritetype *pSprite);
void actPropagateSpriteOwner(spritetype *pTarget, spritetype *pSource);
int actSpriteIdToOwnerId(int nSprite);
int actOwnerIdToSpriteId(int nSprite);
bool actTypeInSector(int nSector, int nType);
void actAllocateSpares(void);
void actInit(void);
void ConcussSprite(int a1, spritetype *pSprite, int x, int y, int z, int a6);
int actWallBounceVector(int *x, int *y, int nWall, int a4);
int actFloorBounceVector(int *x, int *y, int *z, int nSector, int a5);
void sub_2A620(int nSprite, int x, int y, int z, int nSector, int nDist, int a7, int a8, DAMAGE_TYPE a9, int a10, int a11, int a12, int a13);
void sub_2AA94(spritetype *pSprite, XSPRITE *pXSprite);
spritetype *actSpawnFloor(spritetype *pSprite);
spritetype *actDropAmmo(spritetype *pSprite, int nType);
spritetype *actDropWeapon(spritetype *pSprite, int nType);
spritetype *actDropItem(spritetype *pSprite, int nType);
spritetype *actDropKey(spritetype *pSprite, int nType);
spritetype *actDropFlag(spritetype *pSprite, int nType);
spritetype *actDropObject(spritetype *pSprite, int nType);
bool actHealDude(XSPRITE *pXDude, int a2, int a3);
void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4);
int actDamageSprite(int nSource, spritetype *pSprite, DAMAGE_TYPE a3, int a4);
void actHitcodeToData(int a1, HITINFO *pHitInfo, int *a3, spritetype **a4, XSPRITE **a5, int *a6, walltype **a7, XWALL **a8, int *a9, sectortype **a10, XSECTOR **a11);
void actImpactMissile(spritetype *pMissile, int a2);
void actKickObject(spritetype *pSprite1, spritetype *pSprite2);
void actTouchFloor(spritetype *pSprite, int nSector);
void ProcessTouchObjects(spritetype *pSprite, int nXSprite);
void actAirDrag(spritetype *pSprite, int a2);
int MoveThing(spritetype *pSprite);
void MoveDude(spritetype *pSprite);
int MoveMissile(spritetype *pSprite);
void actExplodeSprite(spritetype *pSprite);
void actActivateGibObject(spritetype *pSprite, XSPRITE *pXSprite);
bool IsUnderWater(spritetype *pSprite);
void actProcessSprites(void);
spritetype * actSpawnSprite(int nSector, int x, int y, int z, int nStat, char a6);
spritetype *actSpawnDude(spritetype *pSource, short nType, int a3, int a4);
spritetype * actSpawnSprite(spritetype *pSource, int nStat);
spritetype * actSpawnThing(int nSector, int x, int y, int z, int nThingType);
spritetype * actFireThing(spritetype *pSprite, int a2, int a3, int a4, int thingType, int a6);
spritetype* actFireMissile(spritetype *pSprite, int a2, int a3, int a4, int a5, int a6, int nType);
int actGetRespawnTime(spritetype *pSprite);
bool actCheckRespawn(spritetype *pSprite);
bool actCanSplatWall(int nWall);
void actFireVector(spritetype *pShooter, int a2, int a3, int a4, int a5, int a6, VECTOR_TYPE vectorType);
void actPostSprite(int nSprite, int nStatus);
void actPostProcess(void);
void MakeSplash(spritetype *pSprite, XSPRITE *pXSprite);
spritetype* DropRandomPickupObject(spritetype* pSprite, short prevItem);
spritetype* spawnRandomDude(spritetype* pSprite);
int GetDataVal(spritetype* pSprite, int data);
int my_random(int a, int b);
int GetRandDataVal(int *rData, spritetype* pSprite);
bool sfxPlayMissileSound(spritetype* pSprite, int missileId);
bool sfxPlayVectorSound(spritetype* pSprite, int vectorId);
spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist);
int getDudeMassBySpriteSize(spritetype* pSprite);
bool ceilIsTooLow(spritetype* pSprite);

1802
source/blood/src/ai.cpp Normal file

File diff suppressed because it is too large Load diff

105
source/blood/src/ai.h Normal file
View file

@ -0,0 +1,105 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "compat.h"
#include "common_game.h"
#include "actor.h"
#include "db.h"
struct AISTATE {
int stateType; // By NoOne: current type of state. Basically required for kGDXDudeTargetChanger, but can be used for something else.
int at0; // seq
int at4; // seq callback
int at8;
void(*atc)(spritetype *, XSPRITE *);
void(*at10)(spritetype *, XSPRITE *);
void(*at14)(spritetype *, XSPRITE *);
AISTATE *at18; // next state ?
};
extern AISTATE aiState[];
enum AI_SFX_PRIORITY {
AI_SFX_PRIORITY_0 = 0,
AI_SFX_PRIORITY_1,
AI_SFX_PRIORITY_2,
};
struct DUDEEXTRA_at6_u1
{
int at0;
int at4;
char at8;
};
struct DUDEEXTRA_at6_u2
{
int at0;
char at4;
};
struct DUDEEXTRA
{
int at0;
char at4;
AI_SFX_PRIORITY at5;
union
{
DUDEEXTRA_at6_u1 u1;
DUDEEXTRA_at6_u2 u2;
} at6;
//DUDEEXTRA_at6 at6;
};
struct TARGETTRACK {
int at0;
int at4;
int at8; // view angle
int atc;
int at10; // Move predict
};
extern int dword_138BB0[5];
extern DUDEEXTRA gDudeExtra[];
extern int gDudeSlope[];
bool sub_5BDA8(spritetype *pSprite, int nSeq);
void aiPlay3DSound(spritetype *pSprite, int a2, AI_SFX_PRIORITY a3, int a4);
void aiNewState(spritetype *pSprite, XSPRITE *pXSprite, AISTATE *pAIState);
void aiChooseDirection(spritetype *pSprite, XSPRITE *pXSprite, int a3);
void aiMoveForward(spritetype *pSprite, XSPRITE *pXSprite);
void aiMoveTurn(spritetype *pSprite, XSPRITE *pXSprite);
void aiMoveDodge(spritetype *pSprite, XSPRITE *pXSprite);
void aiActivateDude(spritetype *pSprite, XSPRITE *pXSprite);
void aiSetTarget(XSPRITE *pXSprite, int x, int y, int z);
void aiSetTarget(XSPRITE *pXSprite, int nTarget);
int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_TYPE nDmgType, int nDamage);
void aiThinkTarget(spritetype *pSprite, XSPRITE *pXSprite);
void sub_5F15C(spritetype *pSprite, XSPRITE *pXSprite);
void aiProcessDudes(void);
void aiInit(void);
void aiInitSprite(spritetype *pSprite);
// By NoOne: this function required for kGDXDudeTargetChanger
void aiSetGenIdleState(spritetype* pSprite, XSPRITE* pXSprite);

437
source/blood/src/aibat.cpp Normal file
View file

@ -0,0 +1,437 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aibat.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "player.h"
#include "seq.h"
#include "trig.h"
static void BiteSeqCallback(int, int);
static void thinkTarget(spritetype *, XSPRITE *);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkPonder(spritetype *, XSPRITE *);
static void MoveDodgeUp(spritetype *, XSPRITE *);
static void MoveDodgeDown(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static void MoveForward(spritetype *, XSPRITE *);
static void MoveSwoop(spritetype *, XSPRITE *);
static void MoveFly(spritetype *, XSPRITE *);
static void MoveToCeil(spritetype *, XSPRITE *);
static int nBiteClient = seqRegisterClient(BiteSeqCallback);
AISTATE batIdle = {kAiStateIdle, 0, -1, 0, NULL, NULL, thinkTarget, NULL };
AISTATE batFlyIdle = {kAiStateIdle, 6, -1, 0, NULL, NULL, thinkTarget, NULL };
AISTATE batChase = {kAiStateChase, 6, -1, 0, NULL, MoveForward, thinkChase, &batFlyIdle };
AISTATE batPonder = {kAiStateOther, 6, -1, 0, NULL, NULL, thinkPonder, NULL };
AISTATE batGoto = {kAiStateMove, 6, -1, 600, NULL, MoveForward, thinkGoto, &batFlyIdle };
AISTATE batBite = {kAiStateChase, 7, nBiteClient, 60, NULL, NULL, NULL, &batPonder };
AISTATE batRecoil = {kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &batChase };
AISTATE batSearch = {kAiStateSearch, 6, -1, 120, NULL, MoveForward, thinkSearch, &batFlyIdle };
AISTATE batSwoop = {kAiStateOther, 6, -1, 60, NULL, MoveSwoop, thinkChase, &batChase };
AISTATE batFly = { kAiStateMove, 6, -1, 0, NULL, MoveFly, thinkChase, &batChase };
AISTATE batTurn = {kAiStateMove, 6, -1, 60, NULL, aiMoveTurn, NULL, &batChase };
AISTATE batHide = {kAiStateOther, 6, -1, 0, NULL, MoveToCeil, MoveForward, NULL };
AISTATE batDodgeUp = {kAiStateMove, 6, -1, 120, NULL, MoveDodgeUp, 0, &batChase };
AISTATE batDodgeUpRight = {kAiStateMove, 6, -1, 90, NULL, MoveDodgeUp, 0, &batChase };
AISTATE batDodgeUpLeft = {kAiStateMove, 6, -1, 90, NULL, MoveDodgeUp, 0, &batChase };
AISTATE batDodgeDown = {kAiStateMove, 6, -1, 120, NULL, MoveDodgeDown, 0, &batChase };
AISTATE batDodgeDownRight = {kAiStateMove, 6, -1, 90, NULL, MoveDodgeDown, 0, &batChase };
AISTATE batDodgeDownLeft = {kAiStateMove, 6, -1, 90, NULL, MoveDodgeDown, 0, &batChase };
static void BiteSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
spritetype *pSprite = &sprite[pXSprite->reference];
spritetype *pTarget = &sprite[pXSprite->target];
int dx = Cos(pSprite->ang) >> 16;
int dy = Sin(pSprite->ang) >> 16;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEINFO *pDudeInfoT = &dudeInfo[pTarget->type-kDudeBase];
int height = (pSprite->yrepeat*pDudeInfo->eyeHeight)<<2;
int height2 = (pTarget->yrepeat*pDudeInfoT->eyeHeight)<<2;
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
actFireVector(pSprite, 0, 0, dx, dy, height2-height, VECTOR_TYPE_6);
}
static void thinkTarget(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
if (pDudeExtraE->at8 && pDudeExtraE->at4 < 10)
pDudeExtraE->at4++;
else if (pDudeExtraE->at4 >= 10 && pDudeExtraE->at8)
{
pDudeExtraE->at4 = 0;
pXSprite->goalAng += 256;
POINT3D *pTarget = &baseSprite[pSprite->index];
aiSetTarget(pXSprite, pTarget->x, pTarget->y, pTarget->z);
aiNewState(pSprite, pXSprite, &batTurn);
return;
}
if (Chance(pDudeInfo->alertChance))
{
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
PLAYER *pPlayer = &gPlayer[p];
if (pPlayer->pXSprite->health == 0 || powerupCheck(pPlayer, 13) > 0)
continue;
int x = pPlayer->pSprite->x;
int y = pPlayer->pSprite->y;
int z = pPlayer->pSprite->z;
int nSector = pPlayer->pSprite->sectnum;
int dx = x-pSprite->x;
int dy = y-pSprite->y;
int nDist = approxDist(dx, dy);
if (nDist > pDudeInfo->seeDist && nDist > pDudeInfo->hearDist)
continue;
if (!cansee(x, y, z, nSector, pSprite->x, pSprite->y, pSprite->z-((pDudeInfo->eyeHeight*pSprite->yrepeat)<<2), pSprite->sectnum))
continue;
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pPlayer->at5b);
aiActivateDude(pSprite, pXSprite);
}
else if (nDist < pDudeInfo->hearDist)
{
aiSetTarget(pXSprite, x, y, z);
aiActivateDude(pSprite, pXSprite);
}
else
continue;
break;
}
}
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
thinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &batSearch);
thinkTarget(pSprite, pXSprite);
}
static void thinkPonder(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &batSearch);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &batSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
int height2 = (dudeInfo[pTarget->type-kDudeBase].eyeHeight*pTarget->yrepeat)<<2;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
aiSetTarget(pXSprite, pXSprite->target);
if (height2-height < 0x3000 && nDist < 0x1800 && nDist > 0xc00 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &batDodgeUp);
else if (height2-height > 0x5000 && nDist < 0x1800 && nDist > 0xc00 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &batDodgeDown);
else if (height2-height < 0x2000 && nDist < 0x200 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &batDodgeUp);
else if (height2-height > 0x6000 && nDist < 0x1400 && nDist > 0x800 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &batDodgeDown);
else if (height2-height < 0x2000 && nDist < 0x1400 && nDist > 0x800 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &batDodgeUp);
else if (height2-height < 0x2000 && klabs(nDeltaAngle) < 85 && nDist > 0x1400)
aiNewState(pSprite, pXSprite, &batDodgeUp);
else if (height2-height > 0x4000)
aiNewState(pSprite, pXSprite, &batDodgeDown);
else
aiNewState(pSprite, pXSprite, &batDodgeUp);
return;
}
}
aiNewState(pSprite, pXSprite, &batGoto);
pXSprite->target = -1;
}
static void MoveDodgeUp(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int dx = xvel[nSprite];
int dy = yvel[nSprite];
int t1 = dmulscale30(dx, nCos, dy, nSin);
int t2 = dmulscale30(dx, nSin, -dy, nCos);
if (pXSprite->dodgeDir > 0)
t2 += pDudeInfo->sideSpeed;
else
t2 -= pDudeInfo->sideSpeed;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -0x52aaa;
}
static void MoveDodgeDown(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
if (pXSprite->dodgeDir == 0)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int dx = xvel[nSprite];
int dy = yvel[nSprite];
int t1 = dmulscale30(dx, nCos, dy, nSin);
int t2 = dmulscale30(dx, nSin, -dy, nCos);
if (pXSprite->dodgeDir > 0)
t2 += pDudeInfo->sideSpeed;
else
t2 -= pDudeInfo->sideSpeed;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = 0x44444;
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &batGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &batSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &batSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
// Should be dudeInfo[pTarget->type-kDudeBase]
int height2 = (pDudeInfo->eyeHeight*pTarget->yrepeat)<<2;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int floorZ = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
if (height2-height < 0x2000 && nDist < 0x200 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &batBite);
else if ((height2-height > 0x5000 || floorZ-bottom > 0x5000) && nDist < 0x1400 && nDist > 0x800 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &batSwoop);
else if ((height2-height < 0x3000 || floorZ-bottom < 0x3000) && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &batFly);
return;
}
}
else
{
aiNewState(pSprite, pXSprite, &batFly);
return;
}
}
pXSprite->target = -1;
aiNewState(pSprite, pXSprite, &batHide);
}
static void MoveForward(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
return;
if (pXSprite->target == -1)
pSprite->ang = (pSprite->ang+256)&2047;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if ((unsigned int)Random(64) < 32 && nDist <= 0x200)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
if (pXSprite->target == -1)
t1 += nAccel;
else
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
}
static void MoveSwoop(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pXSprite->goalAng = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x600) && nDist <= 0x200)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = 0x44444;
}
static void MoveFly(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pSprite->ang = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x4000) && nDist <= 0x200)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -0x2d555;
}
void MoveToCeil(spritetype *pSprite, XSPRITE *pXSprite)
{
int x = pSprite->x;
int y = pSprite->y;
int z = pSprite->z;
int nSector = pSprite->sectnum;
if (z - pXSprite->targetZ < 0x1000)
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
pDudeExtraE->at8 = 0;
pSprite->hitag = 0;
aiNewState(pSprite, pXSprite, &batIdle);
}
else
aiSetTarget(pXSprite, x, y, sector[nSector].ceilingz);
}

43
source/blood/src/aibat.h Normal file
View file

@ -0,0 +1,43 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE batIdle;
extern AISTATE batFlyIdle;
extern AISTATE batChase;
extern AISTATE batPonder;
extern AISTATE batGoto;
extern AISTATE batBite;
extern AISTATE batRecoil;
extern AISTATE batSearch;
extern AISTATE batSwoop;
extern AISTATE batFly;
extern AISTATE batTurn;
extern AISTATE batHide;
extern AISTATE batDodgeUp;
extern AISTATE batDodgeUpRight;
extern AISTATE batDodgeUpLeft;
extern AISTATE batDodgeDown;
extern AISTATE batDodgeDownRight;
extern AISTATE batDodgeDownLeft;

View file

@ -0,0 +1,581 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aibeast.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void SlashSeqCallback(int, int);
static void StompSeqCallback(int, int);
static void MorphToBeast(spritetype *, XSPRITE *);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static void thinkSwimGoto(spritetype *, XSPRITE *);
static void thinkSwimChase(spritetype *, XSPRITE *);
static void MoveForward(spritetype *, XSPRITE *);
static void sub_628A0(spritetype *, XSPRITE *);
static void sub_62AE0(spritetype *, XSPRITE *);
static void sub_62D7C(spritetype *, XSPRITE *);
static int nSlashClient = seqRegisterClient(SlashSeqCallback);
static int nStompClient = seqRegisterClient(StompSeqCallback);
AISTATE beastIdle = {kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE beastChase = {kAiStateChase, 8, -1, 0, NULL, MoveForward, thinkChase, NULL };
AISTATE beastDodge = { kAiStateMove, 8, -1, 60, NULL, aiMoveDodge, NULL, &beastChase };
AISTATE beastGoto = { kAiStateMove, 8, -1, 600, NULL, MoveForward, thinkGoto, &beastIdle };
AISTATE beastSlash = { kAiStateChase, 6, nSlashClient, 120, NULL, NULL, NULL, &beastChase };
AISTATE beastStomp = { kAiStateChase, 7, nStompClient, 120, NULL, NULL, NULL, &beastChase };
AISTATE beastSearch = { kAiStateSearch, 8, -1, 120, NULL, MoveForward, thinkSearch, &beastIdle };
AISTATE beastRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &beastDodge };
AISTATE beastTeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &beastDodge };
AISTATE beastSwimIdle = {kAiStateIdle, 9, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE beastSwimChase = { kAiStateChase, 9, -1, 0, NULL, sub_628A0, thinkSwimChase, NULL };
AISTATE beastSwimDodge = { kAiStateMove, 9, -1, 90, NULL, aiMoveDodge, NULL, &beastSwimChase };
AISTATE beastSwimGoto = { kAiStateMove, 9, -1, 600, NULL, MoveForward, thinkSwimGoto, &beastSwimIdle };
AISTATE beastSwimSearch = { kAiStateSearch, 9, -1, 120, NULL, MoveForward, thinkSearch, &beastSwimIdle };
AISTATE beastSwimSlash = { kAiStateChase, 9, nSlashClient, 0, NULL, NULL, thinkSwimChase, &beastSwimChase };
AISTATE beastSwimRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &beastSwimDodge };
AISTATE beastMorphToBeast = { kAiStateOther, -1, -1, 0, MorphToBeast, NULL, NULL, &beastIdle };
AISTATE beastMorphFromCultist = { kAiStateOther, 2576, -1, 0, NULL, NULL, NULL, &beastMorphToBeast };
AISTATE beast138FB4 = { kAiStateOther, 9, -1, 120, NULL, sub_62AE0, thinkSwimChase, &beastSwimChase };
AISTATE beast138FD0 = { kAiStateOther, 9, -1, 0, NULL, sub_62D7C, thinkSwimChase, &beastSwimChase };
AISTATE beast138FEC = { kAiStateOther, 9, -1, 120, NULL, aiMoveTurn, NULL, &beastSwimChase };
static void SlashSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
spritetype *pTarget = &sprite[pXSprite->target];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
// Correct ?
int dz = pSprite->z-pTarget->z;
dx += Random3(4000-700*gGameOptions.nDifficulty);
dy += Random3(4000-700*gGameOptions.nDifficulty);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_13);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_13);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_13);
sfxPlay3DSound(pSprite, 9012+Random(2), -1, 0);
}
static void StompSeqCallback(int, int nXSprite)
{
char vb8[(kMaxSectors+7)>>3];
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
int x = pSprite->x;
int y = pSprite->y;
int z = pSprite->z;
int vc = 400;
int nSector = pSprite->sectnum;
int v1c = 5+2*gGameOptions.nDifficulty;
int v10 = 25+30*gGameOptions.nDifficulty;
gAffectedSectors[0] = -1;
gAffectedXWalls[0] = -1;
GetClosestSpriteSectors(nSector, x, y, vc, gAffectedSectors, vb8, gAffectedXWalls);
char v4 = 0;
int v34 = -1;
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
actHitcodeToData(hit, &gHitInfo, &v34, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (hit == 3 && v34 >= 0)
{
if (sprite[v34].statnum == 6)
v4 = 0;
}
vc <<= 4;
for (int nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
{
if (nSprite != nSprite2 || v4)
{
spritetype *pSprite2 = &sprite[nSprite2];
if (pSprite2->extra > 0 && pSprite2->extra < kMaxXSprites)
{
if (pSprite2->type == 251)
continue;
if (pSprite2->hitag&32)
continue;
if (TestBitString(vb8, pSprite2->sectnum) && CheckProximity(pSprite2, x, y, z, nSector, vc))
{
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (klabs(bottom-sector[nSector].floorz) == 0)
{
int dx = klabs(pSprite->x-pSprite2->x);
int dy = klabs(pSprite->y-pSprite2->y);
int nDist2 = ksqrt(dx*dx + dy*dy);
if (nDist2 <= vc)
{
int nDamage;
if (!nDist2)
nDamage = v1c + v10;
else
nDamage = v1c + ((vc-nDist2)*v10)/vc;
if (IsPlayerSprite(pSprite2))
gPlayer[pSprite2->type-kDudePlayer1].at37f += nDamage*4;
actDamageSprite(nSprite, pSprite2, DAMAGE_TYPE_0, nDamage<<4);
}
}
}
}
}
}
for (int nSprite2 = headspritestat[4]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
{
spritetype *pSprite2 = &sprite[nSprite2];
if (pSprite2->hitag&32)
continue;
if (TestBitString(vb8, pSprite2->sectnum) && CheckProximity(pSprite2, x, y, z, nSector, vc))
{
XSPRITE *pXSprite = &xsprite[pSprite2->extra];
if (pXSprite->locked)
continue;
int dx = klabs(pSprite->x-pSprite2->x);
int dy = klabs(pSprite->y-pSprite2->y);
int nDist2 = ksqrt(dx*dx + dy*dy);
if (nDist2 <= vc)
{
int nDamage;
if (!nDist2)
nDamage = v1c + v10;
else
nDamage = v1c + ((vc-nDist2)*v10)/vc;
if (IsPlayerSprite(pSprite2))
gPlayer[pSprite2->type-kDudePlayer1].at37f += nDamage*4;
actDamageSprite(nSprite, pSprite2, DAMAGE_TYPE_0, nDamage<<4);
}
}
}
sfxPlay3DSound(pSprite, 9015+Random(2), -1, 0);
}
static void MorphToBeast(spritetype *pSprite, XSPRITE *pXSprite)
{
actHealDude(pXSprite, dudeInfo[51].startHealth, dudeInfo[51].startHealth);
pSprite->type = 251;
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimSearch);
else
aiNewState(pSprite, pXSprite, &beastSearch);
}
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimSearch);
else
aiNewState(pSprite, pXSprite, &beastSearch);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimSearch);
else
aiNewState(pSprite, pXSprite, &beastSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimSearch);
else
aiNewState(pSprite, pXSprite, &beastSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int nXSprite = sprite[pXSprite->reference].extra;
gDudeSlope[nXSprite] = divscale(pTarget->z-pSprite->z, nDist, 10);
if (nDist < 0x1400 && nDist > 0xa00 && klabs(nDeltaAngle) < 85 && (pTarget->hitag&2)
&& IsPlayerSprite(pTarget) && Chance(0x8000))
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
if (pXTarget->health > gPlayerTemplate[0].startHealth/2)
{
switch (hit)
{
case -1:
if (!pXSector || !pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastStomp);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type)
{
if (!pXSector || !pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastStomp);
}
else
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimDodge);
else
aiNewState(pSprite, pXSprite, &beastDodge);
}
break;
default:
if (!pXSector || !pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastStomp);
break;
}
}
}
if (nDist < 921 && klabs(nDeltaAngle) < 28)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimSlash);
else
aiNewState(pSprite, pXSprite, &beastSlash);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type)
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimSlash);
else
aiNewState(pSprite, pXSprite, &beastSlash);
}
else
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimDodge);
else
aiNewState(pSprite, pXSprite, &beastDodge);
}
break;
default:
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimSlash);
else
aiNewState(pSprite, pXSprite, &beastSlash);
break;
}
}
}
return;
}
}
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &beastSwimGoto);
else
aiNewState(pSprite, pXSprite, &beastGoto);
pXSprite->target = -1;
}
static void thinkSwimGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &beastSwimSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkSwimChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &beastSwimGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &beastSwimSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &beastSwimSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = pDudeInfo->eyeHeight+pSprite->z;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int UNUSED(floorZ) = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
if (nDist < 0x400 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &beastSwimSlash);
else
{
aiPlay3DSound(pSprite, 9009+Random(2), AI_SFX_PRIORITY_1, -1);
aiNewState(pSprite, pXSprite, &beast138FD0);
}
}
}
else
aiNewState(pSprite, pXSprite, &beast138FD0);
return;
}
aiNewState(pSprite, pXSprite, &beastSwimGoto);
pXSprite->target = -1;
}
static void MoveForward(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
if (klabs(nAng) > 341)
return;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (nDist <= 0x400 && Random(64) < 32)
return;
xvel[nSprite] += mulscale30(pDudeInfo->frontSpeed, Cos(pSprite->ang));
yvel[nSprite] += mulscale30(pDudeInfo->frontSpeed, Sin(pSprite->ang));
}
static void sub_628A0(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
return;
if (pXSprite->target == -1)
pSprite->ang = (pSprite->ang+256)&2047;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Random(64) < 32 && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
if (pXSprite->target == -1)
t1 += nAccel;
else
t1 += nAccel>>2;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
}
static void sub_62AE0(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
spritetype *pTarget = &sprite[pXSprite->target];
int z = pSprite->z + dudeInfo[pSprite->type - kDudeBase].eyeHeight;
int z2 = pTarget->z + dudeInfo[pTarget->type - kDudeBase].eyeHeight;
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pXSprite->goalAng = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int dz = z2 - z;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x600) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -dz;
}
static void sub_62D7C(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
spritetype *pTarget = &sprite[pXSprite->target];
int z = pSprite->z + dudeInfo[pSprite->type - kDudeBase].eyeHeight;
int z2 = pTarget->z + dudeInfo[pTarget->type - kDudeBase].eyeHeight;
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pSprite->ang = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int dz = (z2 - z)<<3;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x4000) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = dz;
}

View file

@ -0,0 +1,46 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE beastIdle;
extern AISTATE beastChase;
extern AISTATE beastDodge;
extern AISTATE beastGoto;
extern AISTATE beastSlash;
extern AISTATE beastStomp;
extern AISTATE beastSearch;
extern AISTATE beastRecoil;
extern AISTATE beastTeslaRecoil;
extern AISTATE beastSwimIdle;
extern AISTATE beastSwimChase;
extern AISTATE beastSwimDodge;
extern AISTATE beastSwimGoto;
extern AISTATE beastSwimSearch;
extern AISTATE beastSwimSlash;
extern AISTATE beastSwimRecoil;
extern AISTATE beastMorphToBeast;
extern AISTATE beastMorphFromCultist;
extern AISTATE beast138FB4;
extern AISTATE beast138FD0;
extern AISTATE beast138FEC;

View file

@ -0,0 +1,442 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aiboneel.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void BiteSeqCallback(int, int);
static void thinkTarget(spritetype *, XSPRITE *);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkPonder(spritetype *, XSPRITE *);
static void MoveDodgeUp(spritetype *, XSPRITE *);
static void MoveDodgeDown(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static void MoveForward(spritetype *, XSPRITE *);
static void MoveSwoop(spritetype *, XSPRITE *);
static void MoveAscend(spritetype *pSprite, XSPRITE *pXSprite);
static void MoveToCeil(spritetype *, XSPRITE *);
static int nBiteClient = seqRegisterClient(BiteSeqCallback);
AISTATE eelIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, thinkTarget, NULL };
AISTATE eelFlyIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, thinkTarget, NULL };
AISTATE eelChase = { kAiStateChase, 0, -1, 0, NULL, MoveForward, thinkChase, &eelIdle };
AISTATE eelPonder = { kAiStateOther, 0, -1, 0, NULL, NULL, thinkPonder, NULL };
AISTATE eelGoto = { kAiStateMove, 0, -1, 600, NULL, NULL, thinkGoto, &eelIdle };
AISTATE eelBite = { kAiStateChase, 7, nBiteClient, 60, NULL, NULL, NULL, &eelChase };
AISTATE eelRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &eelChase };
AISTATE eelSearch = { kAiStateSearch, 0, -1, 120, NULL, MoveForward, thinkSearch, &eelIdle };
AISTATE eelSwoop = { kAiStateOther, 0, -1, 60, NULL, MoveSwoop, thinkChase, &eelChase };
AISTATE eelFly = { kAiStateMove, 0, -1, 0, NULL, MoveAscend, thinkChase, &eelChase };
AISTATE eelTurn = { kAiStateMove, 0, -1, 60, NULL, aiMoveTurn, NULL, &eelChase };
AISTATE eelHide = { kAiStateOther, 0, -1, 0, NULL, MoveToCeil, MoveForward, NULL };
AISTATE eelDodgeUp = { kAiStateMove, 0, -1, 120, NULL, MoveDodgeUp, NULL, &eelChase };
AISTATE eelDodgeUpRight = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeUp, NULL, &eelChase };
AISTATE eelDodgeUpLeft = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeUp, NULL, &eelChase };
AISTATE eelDodgeDown = { kAiStateMove, 0, -1, 120, NULL, MoveDodgeDown, NULL, &eelChase };
AISTATE eelDodgeDownRight = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeDown, NULL, &eelChase };
AISTATE eelDodgeDownLeft = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeDown, NULL, &eelChase };
static void BiteSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
spritetype *pSprite = &sprite[pXSprite->reference];
spritetype *pTarget = &sprite[pXSprite->target];
int dx = Cos(pSprite->ang) >> 16;
int dy = Sin(pSprite->ang) >> 16;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEINFO *pDudeInfoT = &dudeInfo[pTarget->type-kDudeBase];
int height = (pSprite->yrepeat*pDudeInfo->eyeHeight)<<2;
int height2 = (pTarget->yrepeat*pDudeInfoT->eyeHeight)<<2;
/*
* workaround for
* pXSprite->target >= 0 && pXSprite->target < kMaxSprites in file NBlood/source/blood/src/aiboneel.cpp at line 86
* The value of pXSprite->target is -1.
* copied from lines 177:181
* resolves this case, but may cause other issues?
*/
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &eelSearch);
return;
}
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
actFireVector(pSprite, 0, 0, dx, dy, height2-height, VECTOR_TYPE_7);
}
static void thinkTarget(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
if (pDudeExtraE->at8 && pDudeExtraE->at4 < 10)
pDudeExtraE->at4++;
else if (pDudeExtraE->at4 >= 10 && pDudeExtraE->at8)
{
pDudeExtraE->at4 = 0;
pXSprite->goalAng += 256;
POINT3D *pTarget = &baseSprite[pSprite->index];
aiSetTarget(pXSprite, pTarget->x, pTarget->y, pTarget->z);
aiNewState(pSprite, pXSprite, &eelTurn);
return;
}
if (Chance(pDudeInfo->alertChance))
{
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
PLAYER *pPlayer = &gPlayer[p];
if (pPlayer->pXSprite->health == 0 || powerupCheck(pPlayer, 13) > 0)
continue;
int x = pPlayer->pSprite->x;
int y = pPlayer->pSprite->y;
int z = pPlayer->pSprite->z;
int nSector = pPlayer->pSprite->sectnum;
int dx = x-pSprite->x;
int dy = y-pSprite->y;
int nDist = approxDist(dx, dy);
if (nDist > pDudeInfo->seeDist && nDist > pDudeInfo->hearDist)
continue;
if (!cansee(x, y, z, nSector, pSprite->x, pSprite->y, pSprite->z-((pDudeInfo->eyeHeight*pSprite->yrepeat)<<2), pSprite->sectnum))
continue;
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
pDudeExtraE->at4 = 0;
aiSetTarget(pXSprite, pPlayer->at5b);
aiActivateDude(pSprite, pXSprite);
}
else if (nDist < pDudeInfo->hearDist)
{
pDudeExtraE->at4 = 0;
aiSetTarget(pXSprite, x, y, z);
aiActivateDude(pSprite, pXSprite);
}
else
continue;
break;
}
}
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
thinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &eelSearch);
thinkTarget(pSprite, pXSprite);
}
static void thinkPonder(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &eelSearch);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &eelSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
int height2 = (dudeInfo[pTarget->type-kDudeBase].eyeHeight*pTarget->yrepeat)<<2;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
aiSetTarget(pXSprite, pXSprite->target);
if (height2-height < -0x2000 && nDist < 0x1800 && nDist > 0xc00 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelDodgeUp);
else if (height2-height > 0xccc && nDist < 0x1800 && nDist > 0xc00 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelDodgeDown);
else if (height2-height < 0xccc && nDist < 0x399 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelDodgeUp);
else if (height2-height > 0xccc && nDist < 0x1400 && nDist > 0x800 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelDodgeDown);
else if (height2-height < -0x2000 && nDist < 0x1400 && nDist > 0x800 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelDodgeUp);
else if (height2-height < -0x2000 && klabs(nDeltaAngle) < 85 && nDist > 0x1400)
aiNewState(pSprite, pXSprite, &eelDodgeUp);
else if (height2-height > 0xccc)
aiNewState(pSprite, pXSprite, &eelDodgeDown);
else
aiNewState(pSprite, pXSprite, &eelDodgeUp);
return;
}
}
aiNewState(pSprite, pXSprite, &eelGoto);
pXSprite->target = -1;
}
static void MoveDodgeUp(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int dx = xvel[nSprite];
int dy = yvel[nSprite];
int t1 = dmulscale30(dx, nCos, dy, nSin);
int t2 = dmulscale30(dx, nSin, -dy, nCos);
if (pXSprite->dodgeDir > 0)
t2 += pDudeInfo->sideSpeed;
else
t2 -= pDudeInfo->sideSpeed;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -0x8000;
}
static void MoveDodgeDown(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
if (pXSprite->dodgeDir == 0)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int dx = xvel[nSprite];
int dy = yvel[nSprite];
int t1 = dmulscale30(dx, nCos, dy, nSin);
int t2 = dmulscale30(dx, nSin, -dy, nCos);
if (pXSprite->dodgeDir > 0)
t2 += pDudeInfo->sideSpeed;
else
t2 -= pDudeInfo->sideSpeed;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = 0x44444;
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &eelGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &eelSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &eelSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
int top2, bottom2;
GetSpriteExtents(pTarget, &top2, &bottom2);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x399 && top2 > top && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelSwoop);
else if (nDist <= 0x399 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelBite);
else if (bottom2 > top && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelSwoop);
else if (top2 < top && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &eelFly);
}
}
return;
}
pXSprite->target = -1;
aiNewState(pSprite, pXSprite, &eelSearch);
}
static void MoveForward(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = (pDudeInfo->frontSpeed-(((4-gGameOptions.nDifficulty)<<26)/120)/120)<<2;
if (klabs(nAng) > 341)
return;
if (pXSprite->target == -1)
pSprite->ang = (pSprite->ang+256)&2047;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (nDist <= 0x399)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
if (pXSprite->target == -1)
t1 += nAccel;
else
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
}
static void MoveSwoop(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = (pDudeInfo->frontSpeed-(((4-gGameOptions.nDifficulty)<<26)/120)/120)<<2;
if (klabs(nAng) > 341)
return;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x8000) && nDist <= 0x399)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = 0x22222;
}
static void MoveAscend(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = (pDudeInfo->frontSpeed-(((4-gGameOptions.nDifficulty)<<26)/120)/120)<<2;
if (klabs(nAng) > 341)
return;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x4000) && nDist <= 0x399)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -0x8000;
}
void MoveToCeil(spritetype *pSprite, XSPRITE *pXSprite)
{
int x = pSprite->x;
int y = pSprite->y;
int z = pSprite->z;
int nSector = pSprite->sectnum;
if (z - pXSprite->targetZ < 0x1000)
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
pDudeExtraE->at8 = 0;
pSprite->hitag = 0;
aiNewState(pSprite, pXSprite, &eelIdle);
}
else
aiSetTarget(pXSprite, x, y, sector[nSector].ceilingz);
}

View file

@ -0,0 +1,44 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE eelIdle;
extern AISTATE eelFlyIdle;
extern AISTATE eelChase;
extern AISTATE eelPonder;
extern AISTATE eelGoto;
extern AISTATE eelBite;
extern AISTATE eelRecoil;
extern AISTATE eelSearch;
extern AISTATE eelSwoop;
extern AISTATE eelFly;
extern AISTATE eelTurn;
extern AISTATE eelHide;
extern AISTATE eelDodgeUp;
extern AISTATE eelDodgeUpRight;
extern AISTATE eelDodgeUpLeft;
extern AISTATE eelDodgeDown;
extern AISTATE eelDodgeDownRight;
extern AISTATE eelDodgeDownLeft;

267
source/blood/src/aiburn.cpp Normal file
View file

@ -0,0 +1,267 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aiburn.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void BurnSeqCallback(int, int);
static void thinkSearch(spritetype*, XSPRITE*);
static void thinkGoto(spritetype*, XSPRITE*);
static void thinkChase(spritetype*, XSPRITE*);
static int nBurnClient = seqRegisterClient(BurnSeqCallback);
AISTATE cultistBurnIdle = { kAiStateIdle, 3, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE cultistBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE cultistBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &cultistBurnSearch };
AISTATE cultistBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &cultistBurnSearch };
AISTATE cultistBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &cultistBurnChase };
AISTATE zombieABurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE zombieABurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &zombieABurnSearch };
AISTATE zombieABurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, NULL };
AISTATE zombieABurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &zombieABurnChase };
AISTATE zombieFBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE zombieFBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &zombieFBurnSearch };
AISTATE zombieFBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, NULL };
AISTATE zombieFBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &zombieFBurnChase };
AISTATE innocentBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE innocentBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &zombieFBurnSearch };
AISTATE innocentBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, NULL };
AISTATE innocentBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &zombieFBurnChase };
AISTATE beastBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE beastBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &beastBurnSearch };
AISTATE beastBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &beastBurnSearch };
AISTATE beastBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &beastBurnChase };
AISTATE tinycalebBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE tinycalebBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &tinycalebBurnSearch };
AISTATE tinycalebBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &tinycalebBurnSearch };
AISTATE tinycalebBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &tinycalebBurnChase };
AISTATE GDXGenDudeBurnIdle = { kAiStateIdle, 3, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE GDXGenDudeBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE GDXGenDudeBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &GDXGenDudeBurnSearch };
AISTATE GDXGenDudeBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &GDXGenDudeBurnSearch };
AISTATE GDXGenDudeBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &GDXGenDudeBurnChase };
static void BurnSeqCallback(int, int)
{
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
{
switch (pSprite->type)
{
case 240:
aiNewState(pSprite, pXSprite, &cultistBurnSearch);
break;
case 241:
aiNewState(pSprite, pXSprite, &zombieABurnSearch);
break;
case 242:
aiNewState(pSprite, pXSprite, &zombieFBurnSearch);
break;
case 239:
aiNewState(pSprite, pXSprite, &innocentBurnSearch);
break;
case 253:
aiNewState(pSprite, pXSprite, &beastBurnSearch);
break;
case 252:
aiNewState(pSprite, pXSprite, &tinycalebBurnSearch);
break;
case kGDXGenDudeBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch);
break;
}
}
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
switch (pSprite->type)
{
case 240:
aiNewState(pSprite, pXSprite, &cultistBurnGoto);
break;
case 241:
aiNewState(pSprite, pXSprite, &zombieABurnGoto);
break;
case 242:
aiNewState(pSprite, pXSprite, &zombieFBurnGoto);
break;
case 239:
aiNewState(pSprite, pXSprite, &innocentBurnGoto);
break;
case 253:
aiNewState(pSprite, pXSprite, &beastBurnGoto);
break;
case 252:
aiNewState(pSprite, pXSprite, &tinycalebBurnGoto);
break;
case kGDXGenDudeBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto);
break;
}
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
switch (pSprite->type)
{
case 240:
aiNewState(pSprite, pXSprite, &cultistBurnSearch);
break;
case 241:
aiNewState(pSprite, pXSprite, &zombieABurnSearch);
break;
case 242:
aiNewState(pSprite, pXSprite, &zombieFBurnSearch);
break;
case 239:
aiNewState(pSprite, pXSprite, &innocentBurnSearch);
break;
case 253:
aiNewState(pSprite, pXSprite, &beastBurnSearch);
break;
case 252:
aiNewState(pSprite, pXSprite, &tinycalebBurnSearch);
break;
case kGDXGenDudeBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch);
break;
}
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x333 && klabs(nDeltaAngle) < 85)
{
switch (pSprite->type)
{
case 240:
aiNewState(pSprite, pXSprite, &cultistBurnAttack);
break;
case 241:
aiNewState(pSprite, pXSprite, &zombieABurnAttack);
break;
case 242:
aiNewState(pSprite, pXSprite, &zombieFBurnAttack);
break;
case 239:
aiNewState(pSprite, pXSprite, &innocentBurnAttack);
break;
case 253:
aiNewState(pSprite, pXSprite, &beastBurnAttack);
break;
case 252:
aiNewState(pSprite, pXSprite, &tinycalebBurnAttack);
break;
case kGDXGenDudeBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch);
break;
}
}
return;
}
}
}
switch (pSprite->type)
{
case 240:
aiNewState(pSprite, pXSprite, &cultistBurnGoto);
break;
case 241:
aiNewState(pSprite, pXSprite, &zombieABurnGoto);
break;
case 242:
aiNewState(pSprite, pXSprite, &zombieFBurnGoto);
break;
case 239:
aiNewState(pSprite, pXSprite, &innocentBurnGoto);
break;
case 253:
aiNewState(pSprite, pXSprite, &beastBurnGoto);
break;
case 252:
aiNewState(pSprite, pXSprite, &tinycalebBurnGoto);
break;
case kGDXGenDudeBurning:
aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch);
break;
}
pXSprite->target = -1;
}

56
source/blood/src/aiburn.h Normal file
View file

@ -0,0 +1,56 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE cultistBurnIdle;
extern AISTATE cultistBurnChase;
extern AISTATE cultistBurnGoto;
extern AISTATE cultistBurnSearch;
extern AISTATE cultistBurnAttack;
extern AISTATE zombieABurnChase;
extern AISTATE zombieABurnGoto;
extern AISTATE zombieABurnSearch;
extern AISTATE zombieABurnAttack;
extern AISTATE zombieFBurnChase;
extern AISTATE zombieFBurnGoto;
extern AISTATE zombieFBurnSearch;
extern AISTATE zombieFBurnAttack;
extern AISTATE innocentBurnChase;
extern AISTATE innocentBurnGoto;
extern AISTATE innocentBurnSearch;
extern AISTATE innocentBurnAttack;
extern AISTATE beastBurnChase;
extern AISTATE beastBurnGoto;
extern AISTATE beastBurnSearch;
extern AISTATE beastBurnAttack;
extern AISTATE tinycalebBurnChase;
extern AISTATE tinycalebBurnGoto;
extern AISTATE tinycalebBurnSearch;
extern AISTATE tinycalebBurnAttack;
extern AISTATE GDXGenDudeBurnIdle;
extern AISTATE GDXGenDudeBurnChase;
extern AISTATE GDXGenDudeBurnGoto;
extern AISTATE GDXGenDudeBurnSearch;
extern AISTATE GDXGenDudeBurnAttack;

View file

@ -0,0 +1,423 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aicaleb.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void SeqAttackCallback(int, int);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static void thinkSwimGoto(spritetype *, XSPRITE *);
static void thinkSwimChase(spritetype *, XSPRITE *);
static void sub_65D04(spritetype *, XSPRITE *);
static void sub_65F44(spritetype *, XSPRITE *);
static void sub_661E0(spritetype *, XSPRITE *);
static int nAttackClient = seqRegisterClient(SeqAttackCallback);
AISTATE tinycalebIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE tinycalebChase = { kAiStateChase, 6, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE tinycalebDodge = { kAiStateMove, 6, -1, 90, NULL, aiMoveDodge, NULL, &tinycalebChase };
AISTATE tinycalebGoto = { kAiStateMove, 6, -1, 600, NULL, aiMoveForward, thinkGoto, &tinycalebIdle };
AISTATE tinycalebAttack = { kAiStateChase, 0, nAttackClient, 120, NULL, NULL, NULL, &tinycalebChase };
AISTATE tinycalebSearch = { kAiStateSearch, 6, -1, 120, NULL, aiMoveForward, thinkSearch, &tinycalebIdle };
AISTATE tinycalebRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &tinycalebDodge };
AISTATE tinycalebTeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &tinycalebDodge };
AISTATE tinycalebSwimIdle = { kAiStateIdle, 10, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE tinycalebSwimChase = { kAiStateChase, 8, -1, 0, NULL, sub_65D04, thinkSwimChase, NULL };
AISTATE tinycalebSwimDodge = { kAiStateMove, 8, -1, 90, NULL, aiMoveDodge, NULL, &tinycalebSwimChase };
AISTATE tinycalebSwimGoto = { kAiStateMove, 8, -1, 600, NULL, aiMoveForward, thinkSwimGoto, &tinycalebSwimIdle };
AISTATE tinycalebSwimSearch = { kAiStateSearch, 8, -1, 120, NULL, aiMoveForward, thinkSearch, &tinycalebSwimIdle };
AISTATE tinycalebSwimAttack = { kAiStateChase, 10, nAttackClient, 0, NULL, NULL, NULL, &tinycalebSwimChase };
AISTATE tinycalebSwimRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &tinycalebSwimDodge };
AISTATE tinycaleb139660 = { kAiStateOther, 8, -1, 120, NULL, sub_65F44, thinkSwimChase, &tinycalebSwimChase };
AISTATE tinycaleb13967C = { kAiStateOther, 8, -1, 0, NULL, sub_661E0, thinkSwimChase, &tinycalebSwimChase };
AISTATE tinycaleb139698 = { kAiStateOther, 8, -1, 120, NULL, aiMoveTurn, NULL, &tinycalebSwimChase };
static void SeqAttackCallback(int, int nXSprite)
{
int nSprite = xsprite[nXSprite].reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
int dz = gDudeSlope[nXSprite];
dx += Random2(1500);
dy += Random2(1500);
dz += Random2(1500);
for (int i = 0; i < 2; i++)
{
int r1 = Random3(500);
int r2 = Random3(1000);
int r3 = Random3(1000);
actFireVector(pSprite, 0, 0, dx+r3, dy+r2, dz+r1, VECTOR_TYPE_1);
}
if (Chance(0x8000))
sfxPlay3DSound(pSprite, 10000+Random(5), -1, 0);
if (Chance(0x8000))
sfxPlay3DSound(pSprite, 1001, -1, 0);
else
sfxPlay3DSound(pSprite, 1002, -1, 0);
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimSearch);
else
aiNewState(pSprite, pXSprite, &tinycalebSearch);
}
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimSearch);
else
aiNewState(pSprite, pXSprite, &tinycalebSearch);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimSearch);
else
{
aiPlay3DSound(pSprite, 11000+Random(4), AI_SFX_PRIORITY_1, -1);
aiNewState(pSprite, pXSprite, &tinycalebSearch);
}
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimSearch);
else
aiNewState(pSprite, pXSprite, &tinycalebSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int nXSprite = sprite[pXSprite->reference].extra;
gDudeSlope[nXSprite] = divscale(pTarget->z-pSprite->z, nDist, 10);
if (nDist < 0x599 && klabs(nDeltaAngle) < 28)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimAttack);
else
aiNewState(pSprite, pXSprite, &tinycalebAttack);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type)
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimAttack);
else
aiNewState(pSprite, pXSprite, &tinycalebAttack);
}
else
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimDodge);
else
aiNewState(pSprite, pXSprite, &tinycalebDodge);
}
break;
default:
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimAttack);
else
aiNewState(pSprite, pXSprite, &tinycalebAttack);
break;
}
}
}
return;
}
}
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &tinycalebSwimGoto);
else
aiNewState(pSprite, pXSprite, &tinycalebGoto);
if (Chance(0x2000))
sfxPlay3DSound(pSprite, 10000 + Random(5), -1, 0);
pXSprite->target = -1;
}
static void thinkSwimGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &tinycalebSwimSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkSwimChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &tinycalebSwimGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &tinycalebSwimSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &tinycalebSwimSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = pDudeInfo->eyeHeight+pSprite->z;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int UNUSED(floorZ) = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
if (nDist < 0x400 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &tinycalebSwimAttack);
else
aiNewState(pSprite, pXSprite, &tinycaleb13967C);
}
}
return;
}
aiNewState(pSprite, pXSprite, &tinycalebSwimGoto);
pXSprite->target = -1;
}
static void sub_65D04(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
return;
if (pXSprite->target == -1)
pSprite->ang = (pSprite->ang+256)&2047;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Random(64) < 32 && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
if (pXSprite->target == -1)
t1 += nAccel;
else
t1 += nAccel>>2;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
}
static void sub_65F44(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
spritetype *pTarget = &sprite[pXSprite->target];
int z = pSprite->z + dudeInfo[pSprite->type - kDudeBase].eyeHeight;
int z2 = pTarget->z + dudeInfo[pTarget->type - kDudeBase].eyeHeight;
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pXSprite->goalAng = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int dz = z2 - z;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x600) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -dz;
}
static void sub_661E0(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
spritetype *pTarget = &sprite[pXSprite->target];
int z = pSprite->z + dudeInfo[pSprite->type - kDudeBase].eyeHeight;
int z2 = pTarget->z + dudeInfo[pTarget->type - kDudeBase].eyeHeight;
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pSprite->ang = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int dz = (z2 - z)<<3;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x4000) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = dz;
}

View file

@ -0,0 +1,43 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE tinycalebIdle;
extern AISTATE tinycalebChase;
extern AISTATE tinycalebDodge;
extern AISTATE tinycalebGoto;
extern AISTATE tinycalebAttack;
extern AISTATE tinycalebSearch;
extern AISTATE tinycalebRecoil;
extern AISTATE tinycalebTeslaRecoil;
extern AISTATE tinycalebSwimIdle;
extern AISTATE tinycalebSwimChase;
extern AISTATE tinycalebSwimDodge;
extern AISTATE tinycalebSwimGoto;
extern AISTATE tinycalebSwimSearch;
extern AISTATE tinycalebSwimAttack;
extern AISTATE tinycalebSwimRecoil;
extern AISTATE tinycaleb139660;
extern AISTATE tinycaleb13967C;
extern AISTATE tinycaleb139698;

View file

@ -0,0 +1,489 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aicerber.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void BiteSeqCallback(int, int);
static void BurnSeqCallback(int, int);
static void BurnSeqCallback2(int, int);
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite);
static void thinkTarget(spritetype *pSprite, XSPRITE *pXSprite);
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite);
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite);
static int nBiteClient = seqRegisterClient(BiteSeqCallback);
static int nBurnClient = seqRegisterClient(BurnSeqCallback);
static int nBurnClient2 = seqRegisterClient(BurnSeqCallback2);
AISTATE cerberusIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, thinkTarget, NULL };
AISTATE cerberusSearch = { kAiStateSearch, 7, -1, 1800, NULL, aiMoveForward, thinkSearch, &cerberusIdle };
AISTATE cerberusChase = { kAiStateChase, 7, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE cerberusRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &cerberusSearch };
AISTATE cerberusTeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &cerberusSearch };
AISTATE cerberusGoto = { kAiStateMove, 7, -1, 600, NULL, aiMoveForward, thinkGoto, &cerberusIdle };
AISTATE cerberusBite = { kAiStateChase, 6, nBiteClient, 60, NULL, NULL, NULL, &cerberusChase };
AISTATE cerberusBurn = { kAiStateChase, 6, nBurnClient, 60, NULL, NULL, NULL, &cerberusChase };
AISTATE cerberus3Burn = { kAiStateChase, 6, nBurnClient2, 60, NULL, NULL, NULL, &cerberusChase };
AISTATE cerberus2Idle = { kAiStateIdle, 0, -1, 0, NULL, NULL, thinkTarget, NULL };
AISTATE cerberus2Search = { kAiStateSearch, 7, -1, 1800, NULL, aiMoveForward, thinkSearch, &cerberus2Idle };
AISTATE cerberus2Chase = { kAiStateChase, 7, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE cerberus2Recoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &cerberus2Search };
AISTATE cerberus2Goto = { kAiStateMove, 7, -1, 600, NULL, aiMoveForward, thinkGoto, &cerberus2Idle };
AISTATE cerberus2Bite = { kAiStateChase, 6, nBiteClient, 60, NULL, NULL, NULL, &cerberus2Chase };
AISTATE cerberus2Burn = { kAiStateChase, 6, nBurnClient, 60, NULL, NULL, NULL, &cerberus2Chase };
AISTATE cerberus4Burn = { kAiStateChase, 6, nBurnClient2, 60, NULL, NULL, NULL, &cerberus2Chase };
AISTATE cerberus139890 = { kAiStateOther, 7, -1, 120, NULL, aiMoveTurn, NULL, &cerberusChase };
AISTATE cerberus1398AC = { kAiStateOther, 7, -1, 120, NULL, aiMoveTurn, NULL, &cerberusChase };
static void BiteSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
int dz = pTarget->z-pSprite->z;
actFireVector(pSprite, 350, -100, dx, dy, dz, VECTOR_TYPE_14);
actFireVector(pSprite, -350, 0, dx, dy, dz, VECTOR_TYPE_14);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_14);
}
static void BurnSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int height = pDudeInfo->eyeHeight*pSprite->yrepeat;
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
int x = pSprite->x;
int y = pSprite->y;
int z = height; // ???
TARGETTRACK tt1 = { 0x10000, 0x10000, 0x100, 0x55, 0x1aaaaa };
Aim aim;
aim.dx = Cos(pSprite->ang)>>16;
aim.dy = Sin(pSprite->ang)>>16;
aim.dz = gDudeSlope[nXSprite];
int nClosest = 0x7fffffff;
for (short nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
{
spritetype *pSprite2 = &sprite[nSprite2];
if (pSprite == pSprite2 || !(pSprite2->hitag&8))
continue;
int x2 = pSprite2->x;
int y2 = pSprite2->y;
int z2 = pSprite2->z;
int nDist = approxDist(x2-x, y2-y);
if (nDist == 0 || nDist > 0x2800)
continue;
if (tt1.at10)
{
int t = divscale(nDist, tt1.at10, 12);
x2 += (xvel[nSprite2]*t)>>12;
y2 += (yvel[nSprite2]*t)>>12;
z2 += (zvel[nSprite2]*t)>>8;
}
int tx = x+mulscale30(Cos(pSprite->ang), nDist);
int ty = y+mulscale30(Sin(pSprite->ang), nDist);
int tz = z+mulscale(gDudeSlope[nXSprite], nDist, 10);
int tsr = mulscale(9460, nDist, 10);
int top, bottom;
GetSpriteExtents(pSprite2, &top, &bottom);
if (tz-tsr > bottom || tz+tsr < top)
continue;
int dx = (tx-x2)>>4;
int dy = (ty-y2)>>4;
int dz = (tz-z2)>>8;
int nDist2 = ksqrt(dx*dx+dy*dy+dz*dz);
if (nDist2 < nClosest)
{
int nAngle = getangle(x2-x, y2-y);
int nDeltaAngle = ((nAngle-pSprite->ang+1024)&2047)-1024;
if (klabs(nDeltaAngle) <= tt1.at8)
{
int tz = pSprite2->z-pSprite->z;
if (cansee(x, y, z, pSprite->sectnum, x2, y2, z2, pSprite2->sectnum))
{
nClosest = nDist2;
aim.dx = Cos(nAngle)>>16;
aim.dy = Sin(nAngle)>>16;
aim.dz = divscale(tz, nDist, 10);
}
else
aim.dz = tz;
}
}
}
switch (pSprite->type)
{
case 227:
actFireMissile(pSprite, -350, 0, aim.dx, aim.dy, aim.dz, 313);
actFireMissile(pSprite, 350, -100, aim.dx, aim.dy, aim.dz, 313);
break;
case 228:
actFireMissile(pSprite, 350, -100, aim.dx, aim.dy, aim.dz, 313);
break;
}
}
static void BurnSeqCallback2(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int height = pDudeInfo->eyeHeight*pSprite->yrepeat;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
int x = pSprite->x;
int y = pSprite->y;
int z = height; // ???
TARGETTRACK tt1 = { 0x10000, 0x10000, 0x100, 0x55, 0x1aaaaa };
Aim aim;
int ax, ay, az;
aim.dx = ax = Cos(pSprite->ang)>>16;
aim.dy = ay = Sin(pSprite->ang)>>16;
aim.dz = gDudeSlope[nXSprite];
az = 0;
int nClosest = 0x7fffffff;
for (short nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
{
spritetype *pSprite2 = &sprite[nSprite2];
if (pSprite == pSprite2 || !(pSprite2->hitag&8))
continue;
int x2 = pSprite2->x;
int y2 = pSprite2->y;
int z2 = pSprite2->z;
int nDist = approxDist(x2-x, y2-y);
if (nDist == 0 || nDist > 0x2800)
continue;
if (tt1.at10)
{
int t = divscale(nDist, tt1.at10, 12);
x2 += (xvel[nSprite2]*t)>>12;
y2 += (yvel[nSprite2]*t)>>12;
z2 += (zvel[nSprite2]*t)>>8;
}
int tx = x+mulscale30(Cos(pSprite->ang), nDist);
int ty = y+mulscale30(Sin(pSprite->ang), nDist);
int tz = z+mulscale(gDudeSlope[nXSprite], nDist, 10);
int tsr = mulscale(9460, nDist, 10);
int top, bottom;
GetSpriteExtents(pSprite2, &top, &bottom);
if (tz-tsr > bottom || tz+tsr < top)
continue;
int dx = (tx-x2)>>4;
int dy = (ty-y2)>>4;
int dz = (tz-z2)>>8;
int nDist2 = ksqrt(dx*dx+dy*dy+dz*dz);
if (nDist2 < nClosest)
{
int nAngle = getangle(x2-x, y2-y);
int nDeltaAngle = ((nAngle-pSprite->ang+1024)&2047)-1024;
if (klabs(nDeltaAngle) <= tt1.at8)
{
DUDEINFO *pDudeInfo2 = &dudeInfo[pSprite2->type - kDudeBase];
int height = (pDudeInfo2->aimHeight*pSprite2->yrepeat)<<2;
int tz = (z2-height)-z;
if (cansee(x, y, z, pSprite->sectnum, x2, y2, z2, pSprite2->sectnum))
{
nClosest = nDist2;
aim.dx = Cos(nAngle)>>16;
aim.dy = Sin(nAngle)>>16;
aim.dz = divscale(tz, nDist, 10);
}
else
aim.dz = tz;
}
}
}
switch (pSprite->type)
{
case 227:
actFireMissile(pSprite, 350, -100, aim.dx, aim.dy, -aim.dz, 308);
actFireMissile(pSprite, -350, 0, ax, ay, az, 308);
break;
case 228:
actFireMissile(pSprite, 350, -100, aim.dx, aim.dy, -aim.dz, 308);
break;
}
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkTarget(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
if (pDudeExtraE->at8 && pDudeExtraE->at4 < 10)
pDudeExtraE->at4++;
else if (pDudeExtraE->at4 >= 10 && pDudeExtraE->at8)
{
pXSprite->goalAng += 256;
POINT3D *pTarget = &baseSprite[pSprite->index];
aiSetTarget(pXSprite, pTarget->x, pTarget->y, pTarget->z);
if (pSprite->type == 227)
aiNewState(pSprite, pXSprite, &cerberus139890);
else
aiNewState(pSprite, pXSprite, &cerberus1398AC);
return;
}
if (Chance(pDudeInfo->alertChance))
{
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
PLAYER *pPlayer = &gPlayer[p];
if (pPlayer->pXSprite->health == 0 || powerupCheck(pPlayer, 13) > 0)
continue;
int x = pPlayer->pSprite->x;
int y = pPlayer->pSprite->y;
int z = pPlayer->pSprite->z;
int nSector = pPlayer->pSprite->sectnum;
int dx = x-pSprite->x;
int dy = y-pSprite->y;
int nDist = approxDist(dx, dy);
if (nDist > pDudeInfo->seeDist && nDist > pDudeInfo->hearDist)
continue;
if (!cansee(x, y, z, nSector, pSprite->x, pSprite->y, pSprite->z-((pDudeInfo->eyeHeight*pSprite->yrepeat)<<2), pSprite->sectnum))
continue;
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
pDudeExtraE->at0 = 0;
aiSetTarget(pXSprite, pPlayer->at5b);
aiActivateDude(pSprite, pXSprite);
}
else if (nDist < pDudeInfo->hearDist)
{
pDudeExtraE->at0 = 0;
aiSetTarget(pXSprite, x, y, z);
aiActivateDude(pSprite, pXSprite);
}
else
continue;
break;
}
}
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
{
switch (pSprite->type)
{
case 227:
aiNewState(pSprite, pXSprite, &cerberusSearch);
break;
case 228:
aiNewState(pSprite, pXSprite, &cerberus2Search);
break;
}
}
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
switch (pSprite->type)
{
case 227:
aiNewState(pSprite, pXSprite, &cerberusGoto);
break;
case 228:
aiNewState(pSprite, pXSprite, &cerberus2Goto);
break;
}
return;
}
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
switch (pSprite->type)
{
case 227:
aiNewState(pSprite, pXSprite, &cerberusSearch);
break;
case 228:
aiNewState(pSprite, pXSprite, &cerberus2Search);
break;
}
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
switch (pSprite->type)
{
case 227:
aiNewState(pSprite, pXSprite, &cerberusSearch);
break;
case 228:
aiNewState(pSprite, pXSprite, &cerberus2Search);
break;
}
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x1b00 && nDist > 0xd00 && klabs(nDeltaAngle) < 85)
{
switch (pSprite->type)
{
case 227:
aiNewState(pSprite, pXSprite, &cerberusBurn);
break;
case 228:
aiNewState(pSprite, pXSprite, &cerberus2Burn);
break;
}
}
else if (nDist < 0xb00 && nDist > 0x500 && klabs(nDeltaAngle) < 85)
{
switch (pSprite->type)
{
case 227:
aiNewState(pSprite, pXSprite, &cerberus3Burn);
break;
case 228:
aiNewState(pSprite, pXSprite, &cerberus4Burn);
break;
}
}
else if (nDist < 0x200 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (pSprite->type)
{
case 227:
switch (hit)
{
case -1:
aiNewState(pSprite, pXSprite, &cerberusBite);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 211)
aiNewState(pSprite, pXSprite, &cerberusBite);
break;
case 0:
case 4:
break;
default:
aiNewState(pSprite, pXSprite, &cerberusBite);
break;
}
break;
case 228:
switch (hit)
{
case -1:
aiNewState(pSprite, pXSprite, &cerberus2Bite);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 211)
aiNewState(pSprite, pXSprite, &cerberus2Bite);
break;
case 0:
case 4:
break;
default:
aiNewState(pSprite, pXSprite, &cerberus2Bite);
break;
}
break;
}
}
return;
}
}
}
switch (pSprite->type)
{
case 227:
aiNewState(pSprite, pXSprite, &cerberusGoto);
break;
case 228:
aiNewState(pSprite, pXSprite, &cerberus2Goto);
break;
}
pXSprite->target = -1;
}

View file

@ -0,0 +1,44 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE cerberusIdle;
extern AISTATE cerberusSearch;
extern AISTATE cerberusChase;
extern AISTATE cerberusRecoil;
extern AISTATE cerberusTeslaRecoil;
extern AISTATE cerberusGoto;
extern AISTATE cerberusBite;
extern AISTATE cerberusBurn;
extern AISTATE cerberus3Burn;
extern AISTATE cerberus2Idle;
extern AISTATE cerberus2Search;
extern AISTATE cerberus2Chase;
extern AISTATE cerberus2Recoil;
extern AISTATE cerberus2Goto;
extern AISTATE cerberus2Bite;
extern AISTATE cerberus2Burn;
extern AISTATE cerberus4Burn;
extern AISTATE cerberus139890;
extern AISTATE cerberus1398AC;

659
source/blood/src/aicult.cpp Normal file
View file

@ -0,0 +1,659 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aicult.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void TommySeqCallback(int, int);
static void TeslaSeqCallback(int, int);
static void ShotSeqCallback(int, int);
static void ThrowSeqCallback(int, int);
static void sub_68170(int, int);
static void sub_68230(int, int);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static int nTommyClient = seqRegisterClient(TommySeqCallback);
static int nTeslaClient = seqRegisterClient(TeslaSeqCallback);
static int nShotClient = seqRegisterClient(ShotSeqCallback);
static int nThrowClient = seqRegisterClient(ThrowSeqCallback);
static int n68170Client = seqRegisterClient(sub_68170);
static int n68230Client = seqRegisterClient(sub_68230);
AISTATE cultistIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE cultistProneIdle = { kAiStateIdle, 17, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE fanaticProneIdle = { kAiStateIdle, 17, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE cultistProneIdle3 = { kAiStateIdle, 17, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE cultistChase = { kAiStateChase, 9, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE fanaticChase = { kAiStateChase, 0, -1, 0, NULL, aiMoveTurn, thinkChase, NULL };
AISTATE cultistDodge = { kAiStateMove, 9, -1, 90, NULL, aiMoveDodge, NULL, &cultistChase };
AISTATE cultistGoto = { kAiStateMove, 9, -1, 600, NULL, aiMoveForward, thinkGoto, &cultistIdle };
AISTATE cultistProneChase = { kAiStateChase, 14, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE cultistProneDodge = { kAiStateMove, 14, -1, 90, NULL, aiMoveDodge, NULL, &cultistProneChase };
AISTATE cultistTThrow = { kAiStateChase, 7, nThrowClient, 120, NULL, NULL, NULL, &cultistTFire };
AISTATE cultistSThrow = { kAiStateChase, 7, nThrowClient, 120, NULL, NULL, NULL, &cultistSFire };
AISTATE cultistTsThrow = { kAiStateChase, 7, nThrowClient, 120, NULL, NULL, NULL, &cultistTsFire };
AISTATE cultistDThrow = { kAiStateChase, 7, nThrowClient, 120, NULL, NULL, NULL, &cultistChase };
AISTATE cultist139A78 = { kAiStateChase, 7, n68170Client, 120, NULL, NULL, NULL, &cultistChase };
AISTATE cultist139A94 = { kAiStateChase, 7, n68230Client, 120, NULL, NULL, NULL, &cultistIdle };
AISTATE cultist139AB0 = { kAiStateChase, 7, n68230Client, 120, NULL, NULL, thinkSearch, &cultist139A94 };
AISTATE cultist139ACC = { kAiStateChase, 7, n68230Client, 120, NULL, NULL, thinkSearch, &cultist139AB0 };
AISTATE cultist139AE8 = { kAiStateChase, 7, n68230Client, 120, NULL, NULL, thinkSearch, &cultist139AE8 };
AISTATE cultistSearch = { kAiStateSearch, 9, -1, 1800, NULL, aiMoveForward, thinkSearch, &cultistIdle };
AISTATE cultistSFire = { kAiStateChase, 6, nShotClient, 60, NULL, NULL, NULL, &cultistChase };
AISTATE cultistTFire = { kAiStateChase, 6, nTommyClient, 0, NULL, aiMoveTurn, thinkChase, &cultistTFire };
AISTATE cultistTsFire = { kAiStateChase, 6, nTeslaClient, 0, NULL, aiMoveTurn, thinkChase, &cultistChase };
AISTATE cultistSProneFire = { kAiStateChase, 8, nShotClient, 60, NULL, NULL, NULL, &cultistProneChase };
AISTATE cultistTProneFire = { kAiStateChase, 8, nTommyClient, 0, NULL, aiMoveTurn, thinkChase, &cultistTProneFire };
AISTATE cultistTsProneFire = { kAiStateChase, 8, nTeslaClient, 0, NULL, aiMoveTurn, NULL, &cultistTsProneFire };
AISTATE cultistRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &cultistDodge };
AISTATE cultistProneRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &cultistProneDodge };
AISTATE cultistTeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &cultistDodge };
AISTATE cultistSwimIdle = { kAiStateIdle, 13, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE cultistSwimChase = { kAiStateChase, 13, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE cultistSwimDodge = { kAiStateMove, 13, -1, 90, NULL, aiMoveDodge, NULL, &cultistSwimChase };
AISTATE cultistSwimGoto = { kAiStateMove, 13, -1, 600, NULL, aiMoveForward, thinkGoto, &cultistSwimIdle };
AISTATE cultistSwimSearch = { kAiStateSearch, 13, -1, 1800, NULL, aiMoveForward, thinkSearch, &cultistSwimIdle };
AISTATE cultistSSwimFire = { kAiStateChase, 8, nShotClient, 60, NULL, NULL, NULL, &cultistSwimChase };
AISTATE cultistTSwimFire = { kAiStateChase, 8, nTommyClient, 0, NULL, aiMoveTurn, thinkChase, &cultistTSwimFire };
AISTATE cultistTsSwimFire = { kAiStateChase, 8, nTeslaClient, 0, NULL, aiMoveTurn, thinkChase, &cultistTsSwimFire };
AISTATE cultistSwimRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &cultistSwimDodge };
static void TommySeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang) >> 16;
int dy = Sin(pSprite->ang) >> 16;
int dz = gDudeSlope[nXSprite];
dx += Random3((5-gGameOptions.nDifficulty)*1000);
dy += Random3((5-gGameOptions.nDifficulty)*1000);
dz += Random3((5-gGameOptions.nDifficulty)*500);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_2);
sfxPlay3DSound(pSprite, 4001, -1, 0);
}
static void TeslaSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
if (Chance(dword_138BB0[gGameOptions.nDifficulty]))
{
int dx = Cos(pSprite->ang) >> 16;
int dy = Sin(pSprite->ang) >> 16;
int dz = gDudeSlope[nXSprite];
dx += Random3((5-gGameOptions.nDifficulty)*1000);
dy += Random3((5-gGameOptions.nDifficulty)*1000);
dz += Random3((5-gGameOptions.nDifficulty)*500);
actFireMissile(pSprite, 0, 0, dx, dy, dz, 306);
sfxPlay3DSound(pSprite, 470, -1, 0);
}
}
static void ShotSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang) >> 16;
int dy = Sin(pSprite->ang) >> 16;
int dz = gDudeSlope[nXSprite];
dx += Random2((5-gGameOptions.nDifficulty)*1000-500);
dy += Random2((5-gGameOptions.nDifficulty)*1000-500);
dz += Random2((5-gGameOptions.nDifficulty)*500);
for (int i = 0; i < 8; i++)
{
int r1 = Random3(500);
int r2 = Random3(1000);
int r3 = Random3(1000);
actFireVector(pSprite, 0, 0, dx+r3, dy+r2, dz+r1, VECTOR_TYPE_1);
}
if (Chance(0x8000))
sfxPlay3DSound(pSprite, 1001, -1, 0);
else
sfxPlay3DSound(pSprite, 1002, -1, 0);
}
static void ThrowSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int nMissile = 418;
if (gGameOptions.nDifficulty > 2)
nMissile = 419;
char v4 = Chance(0x6000);
sfxPlay3DSound(pSprite, 455, -1, 0);
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
int dx = pTarget->x - pSprite->x;
int dy = pTarget->y - pSprite->y;
int dz = pTarget->z - pSprite->z;
int nDist = approxDist(dx, dy);
int nDist2 = nDist / 540;
if (nDist > 0x1e00)
v4 = 0;
spritetype *pMissile = actFireThing(pSprite, 0, 0, dz/128-14500, nMissile, (nDist2<<23)/120);
if (v4)
xsprite[pMissile->extra].Impact = 1;
else
evPost(pMissile->index, 3, 120*(1+Random(2)), COMMAND_ID_1);
}
static void sub_68170(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int nMissile = 418;
if (gGameOptions.nDifficulty > 2)
nMissile = 419;
sfxPlay3DSound(pSprite, 455, -1, 0);
spritetype *pMissile = actFireThing(pSprite, 0, 0, gDudeSlope[nXSprite]-9460, nMissile, 0x133333);
evPost(pMissile->index, 3, 120*(2+Random(2)), COMMAND_ID_1);
}
static void sub_68230(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int nMissile = 418;
if (gGameOptions.nDifficulty > 2)
nMissile = 419;
sfxPlay3DSound(pSprite, 455, -1, 0);
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
int dx = pTarget->x - pSprite->x;
int dy = pTarget->y - pSprite->y;
int dz = pTarget->z - pSprite->z;
int nDist = approxDist(dx, dy);
int nDist2 = nDist / 540;
spritetype *pMissile = actFireThing(pSprite, 0, 0, dz/128-14500, nMissile, (nDist2<<17)/120);
xsprite[pMissile->extra].Impact = 1;
}
static char TargetNearExplosion(spritetype *pSprite)
{
for (short nSprite = headspritesect[pSprite->sectnum]; nSprite >= 0; nSprite = nextspritesect[nSprite])
{
if (sprite[nSprite].type == 418 || sprite[nSprite].statnum == 2)
return 1;
}
return 0;
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
sub_5F15C(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 5120 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
{
switch (pXSprite->medium)
{
case 0:
aiNewState(pSprite, pXSprite, &cultistSearch);
break;
case 1:
case 2:
aiNewState(pSprite, pXSprite, &cultistSwimSearch);
break;
}
}
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
switch (pXSprite->medium)
{
case 0:
aiNewState(pSprite, pXSprite, &cultistGoto);
break;
case 1:
case 2:
aiNewState(pSprite, pXSprite, &cultistSwimGoto);
break;
}
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
switch (pXSprite->medium)
{
case 0:
aiNewState(pSprite, pXSprite, &cultistSearch);
if (pSprite->type == 201)
aiPlay3DSound(pSprite, 4021+Random(4), AI_SFX_PRIORITY_1, -1);
else
aiPlay3DSound(pSprite, 1021+Random(4), AI_SFX_PRIORITY_1, -1);
break;
case 1:
case 2:
aiNewState(pSprite, pXSprite, &cultistSwimSearch);
break;
}
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
switch (pXSprite->medium)
{
case 0:
aiNewState(pSprite, pXSprite, &cultistSearch);
break;
case 1:
case 2:
aiNewState(pSprite, pXSprite, &cultistSwimSearch);
break;
}
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int nXSprite = sprite[pXSprite->reference].extra;
gDudeSlope[nXSprite] = divscale(pTarget->z-pSprite->z, nDist, 10);
switch (pSprite->type)
{
case 201:
if (nDist < 0x1e00 && nDist > 0xe00 && klabs(nDeltaAngle) < 85 && !TargetNearExplosion(pTarget)
&& (pTarget->hitag&2) && gGameOptions.nDifficulty > 2 && IsPlayerSprite(pTarget) && gPlayer[pTarget->type-kDudePlayer1].at2e
&& Chance(0x8000))
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistTThrow);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 202 && pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistTThrow);
break;
default:
aiNewState(pSprite, pXSprite, &cultistTThrow);
break;
}
}
else if (nDist < 0x4600 && klabs(nDeltaAngle) < 28)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTProneFire);
else if (sub_5BDA8(pSprite, 13) && (pXSprite->medium == 1 || pXSprite->medium == 2))
aiNewState(pSprite, pXSprite, &cultistTSwimFire);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 202)
{
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistTSwimFire);
}
else
{
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistDodge);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistProneDodge);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSwimDodge);
}
break;
default:
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistTSwimFire);
break;
}
}
break;
case 202:
if (nDist < 0x2c00 && nDist > 0x1400 && !TargetNearExplosion(pTarget)
&& (pTarget->hitag&2) && gGameOptions.nDifficulty >= 2 && IsPlayerSprite(pTarget) && !gPlayer[pTarget->type-kDudePlayer1].at2e
&& Chance(0x8000))
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistSThrow);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 202 && pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistSThrow);
break;
default:
aiNewState(pSprite, pXSprite, &cultistSThrow);
break;
}
}
else if (nDist < 0x3200 && klabs(nDeltaAngle) < 28)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSSwimFire);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 201)
{
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSSwimFire);
}
else
{
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistDodge);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistProneDodge);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSwimDodge);
}
break;
default:
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSSwimFire);
break;
}
}
break;
case 247:
if (nDist < 0x1e00 && nDist > 0xe00 && !TargetNearExplosion(pTarget)
&& (pTarget->hitag&2) && gGameOptions.nDifficulty > 2 && IsPlayerSprite(pTarget) && gPlayer[pTarget->type-kDudePlayer1].at2e
&& Chance(0x8000))
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistTsThrow);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 202 && pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistTsThrow);
break;
default:
aiNewState(pSprite, pXSprite, &cultistTsThrow);
break;
}
}
else if (nDist < 0x3200 && klabs(nDeltaAngle) < 28)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTsFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTsProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistTsSwimFire);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 201)
{
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTsFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTsProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistTsSwimFire);
}
else
{
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistDodge);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistProneDodge);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSwimDodge);
}
break;
default:
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTsFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistTsProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistTsSwimFire);
break;
}
}
break;
case 248:
if (nDist < 0x2c00 && nDist > 0x1400 && klabs(nDeltaAngle) < 85
&& (pTarget->hitag&2) && IsPlayerSprite(pTarget))
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistDThrow);
break;
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 202 && pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistDThrow);
break;
default:
aiNewState(pSprite, pXSprite, &cultistDThrow);
break;
}
}
else if (nDist < 0x1400 && klabs(nDeltaAngle) < 85
&& (pTarget->hitag&2) && IsPlayerSprite(pTarget))
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultist139A78);
break;
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 202 && pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultist139A78);
break;
default:
aiNewState(pSprite, pXSprite, &cultist139A78);
break;
}
}
break;
case 249:
if (nDist < 0x1e00 && nDist > 0xe00 && !TargetNearExplosion(pTarget)
&& (pTarget->hitag&2) && gGameOptions.nDifficulty > 2 && IsPlayerSprite(pTarget) && gPlayer[pTarget->type-kDudePlayer1].at2e
&& Chance(0x8000))
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistSThrow);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 202 && pXSprite->medium != 1 && pXSprite->medium != 2)
aiNewState(pSprite, pXSprite, &cultistSThrow);
break;
default:
aiNewState(pSprite, pXSprite, &cultistSThrow);
break;
}
}
else if (nDist < 0x3200 && klabs(nDeltaAngle) < 28)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSSwimFire);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 201)
{
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSSwimFire);
}
else
{
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistDodge);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistProneDodge);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSwimDodge);
}
break;
default:
if (!sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSFire);
else if (sub_5BDA8(pSprite, 14) && pXSprite->medium == 0)
aiNewState(pSprite, pXSprite, &cultistSProneFire);
else if (pXSprite->medium == 1 || pXSprite->medium == 2)
aiNewState(pSprite, pXSprite, &cultistSSwimFire);
break;
}
}
break;
}
return;
}
}
}
switch (pXSprite->medium)
{
case 0:
aiNewState(pSprite, pXSprite, &cultistGoto);
break;
case 1:
case 2:
aiNewState(pSprite, pXSprite, &cultistSwimGoto);
break;
}
pXSprite->target = -1;
}

63
source/blood/src/aicult.h Normal file
View file

@ -0,0 +1,63 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE cultistIdle;
extern AISTATE cultistProneIdle;
extern AISTATE fanaticProneIdle;
extern AISTATE cultistProneIdle3;
extern AISTATE cultistChase;
extern AISTATE fanaticChase;
extern AISTATE cultistDodge;
extern AISTATE cultistGoto;
extern AISTATE cultistProneChase;
extern AISTATE cultistProneDodge;
extern AISTATE cultistTThrow;
extern AISTATE cultistSThrow;
extern AISTATE cultistTsThrow;
extern AISTATE cultistDThrow;
extern AISTATE cultist139A78;
extern AISTATE cultist139A94;
extern AISTATE cultist139AB0;
extern AISTATE cultist139ACC;
extern AISTATE cultist139AE8;
extern AISTATE cultistSearch;
extern AISTATE cultistSFire;
extern AISTATE cultistTFire;
extern AISTATE cultistTsFire;
extern AISTATE cultistSProneFire;
extern AISTATE cultistTProneFir;
extern AISTATE cultistTsProneFire;
extern AISTATE cultistRecoil;
extern AISTATE cultistProneRecoil;
extern AISTATE cultistTeslaRecoil;
extern AISTATE cultistSwimIdle;
extern AISTATE cultistSwimChase;
extern AISTATE cultistSwimDodge;
extern AISTATE cultistSwimGoto;
extern AISTATE cultistSwimSearch;
extern AISTATE cultistSSwimFire;
extern AISTATE cultistTSwimFire;
extern AISTATE cultistTsSwimFire;
extern AISTATE cultistSwimRecoil;

704
source/blood/src/aigarg.cpp Normal file
View file

@ -0,0 +1,704 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aigarg.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void SlashFSeqCallback(int, int);
static void ThrowFSeqCallback(int, int);
static void BlastSSeqCallback(int, int);
static void ThrowSSeqCallback(int, int);
static void thinkTarget(spritetype *, XSPRITE *);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void MoveDodgeUp(spritetype *, XSPRITE *);
static void MoveDodgeDown(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static void entryFStatue(spritetype *, XSPRITE *);
static void entrySStatue(spritetype *, XSPRITE *);
static void MoveForward(spritetype *, XSPRITE *);
static void MoveSlow(spritetype *, XSPRITE *);
static void MoveSwoop(spritetype *, XSPRITE *);
static void MoveFly(spritetype *, XSPRITE *);
static void playStatueBreakSnd(spritetype*,XSPRITE*);
static int nSlashFClient = seqRegisterClient(SlashFSeqCallback);
static int nThrowFClient = seqRegisterClient(ThrowFSeqCallback);
static int nThrowSClient = seqRegisterClient(ThrowSSeqCallback);
static int nBlastSClient = seqRegisterClient(BlastSSeqCallback);
AISTATE gargoyleFIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, thinkTarget, NULL };
AISTATE gargoyleStatueIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, NULL, NULL };
AISTATE gargoyleFChase = { kAiStateChase, 0, -1, 0, NULL, MoveForward, thinkChase, &gargoyleFIdle };
AISTATE gargoyleFGoto = { kAiStateMove, 0, -1, 600, NULL, MoveForward, thinkGoto, &gargoyleFIdle };
AISTATE gargoyleFSlash = { kAiStateChase, 6, nSlashFClient, 120, NULL, NULL, NULL, &gargoyleFChase };
AISTATE gargoyleFThrow = { kAiStateChase, 6, nThrowFClient, 120, NULL, NULL, NULL, &gargoyleFChase };
AISTATE gargoyleSThrow = { kAiStateChase, 6, nThrowSClient, 120, NULL, MoveForward, NULL, &gargoyleFChase };
AISTATE gargoyleSBlast = { kAiStateChase, 7, nBlastSClient, 60, NULL, MoveSlow, NULL, &gargoyleFChase };
AISTATE gargoyleFRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &gargoyleFChase };
AISTATE gargoyleFSearch = { kAiStateSearch, 0, -1, 120, NULL, MoveForward, thinkSearch, &gargoyleFIdle };
AISTATE gargoyleFMorph2 = { kAiStateOther, -1, -1, 0, entryFStatue, NULL, NULL, &gargoyleFIdle };
AISTATE gargoyleFMorph = { kAiStateOther, 6, -1, 0, NULL, NULL, NULL, &gargoyleFMorph2 };
AISTATE gargoyleSMorph2 = { kAiStateOther, -1, -1, 0, entrySStatue, NULL, NULL, &gargoyleFIdle };
AISTATE gargoyleSMorph = { kAiStateOther, 6, -1, 0, NULL, NULL, NULL, &gargoyleSMorph2 };
AISTATE gargoyleSwoop = { kAiStateOther, 0, -1, 120, NULL, MoveSwoop, thinkChase, &gargoyleFChase };
AISTATE gargoyleFly = { kAiStateMove, 0, -1, 120, NULL, MoveFly, thinkChase, &gargoyleFChase };
AISTATE gargoyleTurn = { kAiStateMove, 0, -1, 120, NULL, aiMoveTurn, NULL, &gargoyleFChase };
AISTATE gargoyleDodgeUp = { kAiStateMove, 0, -1, 60, NULL, MoveDodgeUp, NULL, &gargoyleFChase };
AISTATE gargoyleFDodgeUpRight = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeUp, NULL, &gargoyleFChase };
AISTATE gargoyleFDodgeUpLeft = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeUp, NULL, &gargoyleFChase };
AISTATE gargoyleDodgeDown = { kAiStateMove, 0, -1, 120, NULL, MoveDodgeDown, NULL, &gargoyleFChase };
AISTATE gargoyleFDodgeDownRight = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeDown, NULL, &gargoyleFChase };
AISTATE gargoyleFDodgeDownLeft = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeDown, NULL, &gargoyleFChase };
AISTATE statueFBreakSEQ = { kAiStateOther, 5, -1, 0, entryFStatue, NULL, playStatueBreakSnd, &gargoyleFMorph2};
AISTATE statueSBreakSEQ = { kAiStateOther, 5, -1, 0, entrySStatue, NULL, playStatueBreakSnd, &gargoyleSMorph2};
static void playStatueBreakSnd(spritetype* pSprite, XSPRITE* pXSprite) {
UNREFERENCED_PARAMETER(pXSprite);
aiPlay3DSound(pSprite, 313, AI_SFX_PRIORITY_1, -1);
}
static void SlashFSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
spritetype *pTarget = &sprite[pXSprite->target];
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
DUDEINFO *pDudeInfoT = &dudeInfo[pTarget->type - kDudeBase];
int height = (pSprite->yrepeat*pDudeInfo->eyeHeight)<<2;
int height2 = (pTarget->yrepeat*pDudeInfoT->eyeHeight)<<2;
int dz = height-height2;
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_13);
int r1 = Random(50);
int r2 = Random(50);
actFireVector(pSprite, 0, 0, dx+r2, dy-r1, dz, VECTOR_TYPE_13);
r1 = Random(50);
r2 = Random(50);
actFireVector(pSprite, 0, 0, dx-r2, dy+r1, dz, VECTOR_TYPE_13);
}
static void ThrowFSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
actFireThing(&sprite[nSprite], 0, 0, gDudeSlope[nXSprite]-7500, 421, 0xeeeee);
}
static void BlastSSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
wrand(); // ???
spritetype *pTarget = &sprite[pXSprite->target];
int height = (pSprite->yrepeat*dudeInfo[pSprite->type-kDudeBase].eyeHeight) << 2;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nDist) = approxDist(dx, dy);
int UNUSED(nAngle) = getangle(dx, dy);
int x = pSprite->x;
int y = pSprite->y;
int z = height;
TARGETTRACK tt = { 0x10000, 0x10000, 0x100, 0x55, 0x1aaaaa };
Aim aim;
aim.dx = Cos(pSprite->ang)>>16;
aim.dy = Sin(pSprite->ang)>>16;
aim.dz = gDudeSlope[nXSprite];
int nClosest = 0x7fffffff;
for (short nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
{
spritetype *pSprite2 = &sprite[nSprite2];
if (pSprite == pSprite2 || !(pSprite2->hitag&8))
continue;
int x2 = pSprite2->x;
int y2 = pSprite2->y;
int z2 = pSprite2->z;
int nDist = approxDist(x2-x, y2-y);
if (nDist == 0 || nDist > 0x2800)
continue;
if (tt.at10)
{
int t = divscale(nDist, tt.at10, 12);
x2 += (xvel[nSprite2]*t)>>12;
y2 += (yvel[nSprite2]*t)>>12;
z2 += (zvel[nSprite2]*t)>>8;
}
int tx = x+mulscale30(Cos(pSprite->ang), nDist);
int ty = y+mulscale30(Sin(pSprite->ang), nDist);
int tz = z+mulscale(gDudeSlope[nXSprite], nDist, 10);
int tsr = mulscale(9460, nDist, 10);
int top, bottom;
GetSpriteExtents(pSprite2, &top, &bottom);
if (tz-tsr > bottom || tz+tsr < top)
continue;
int dx = (tx-x2)>>4;
int dy = (ty-y2)>>4;
int dz = (tz-z2)>>8;
int nDist2 = ksqrt(dx*dx+dy*dy+dz*dz);
if (nDist2 < nClosest)
{
int nAngle = getangle(x2-x, y2-y);
int nDeltaAngle = ((nAngle-pSprite->ang+1024)&2047)-1024;
if (klabs(nDeltaAngle) <= tt.at8)
{
int tz = pSprite2->z-pSprite->z;
if (cansee(x, y, z, pSprite->sectnum, x2, y2, z2, pSprite2->sectnum))
{
nClosest = nDist2;
aim.dx = Cos(nAngle)>>16;
aim.dy = Sin(nAngle)>>16;
aim.dz = divscale(tz, nDist, 10);
if (tz > -0x333)
aim.dz = divscale(tz, nDist, 10);
else if (tz < -0x333 && tz > -0xb33)
aim.dz = divscale(tz, nDist, 10)+9460;
else if (tz < -0xb33 && tz > -0x3000)
aim.dz = divscale(tz, nDist, 10)+9460;
else if (tz < -0x3000)
aim.dz = divscale(tz, nDist, 10)-7500;
else
aim.dz = divscale(tz, nDist, 10);
}
else
aim.dz = divscale(tz, nDist, 10);
}
}
}
if (IsPlayerSprite(pTarget) || !VanillaMode()) // By NoOne: allow to fire missile in non-player targets
{
actFireMissile(pSprite, -120, 0, aim.dx, aim.dy, aim.dz, 311);
actFireMissile(pSprite, 120, 0, aim.dx, aim.dy, aim.dz, 311);
}
}
static void ThrowSSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
actFireThing(pSprite, 0, 0, gDudeSlope[nXSprite]-7500, 421, Chance(0x6000) ? 0x133333 : 0x111111);
}
static void thinkTarget(spritetype *pSprite, XSPRITE *pXSprite)
{
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
if (pDudeExtraE->at8 && pDudeExtraE->at4 < 10)
pDudeExtraE->at4++;
else if (pDudeExtraE->at4 >= 10 && pDudeExtraE->at8)
{
pXSprite->goalAng += 256;
POINT3D *pTarget = &baseSprite[pSprite->index];
aiSetTarget(pXSprite, pTarget->x, pTarget->y, pTarget->z);
aiNewState(pSprite, pXSprite, &gargoyleTurn);
return;
}
if (Chance(pDudeInfo->alertChance))
{
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
PLAYER *pPlayer = &gPlayer[p];
if (pPlayer->pXSprite->health == 0 || powerupCheck(pPlayer, 13) > 0)
continue;
int x = pPlayer->pSprite->x;
int y = pPlayer->pSprite->y;
int z = pPlayer->pSprite->z;
int nSector = pPlayer->pSprite->sectnum;
int dx = x-pSprite->x;
int dy = y-pSprite->y;
int nDist = approxDist(dx, dy);
if (nDist > pDudeInfo->seeDist && nDist > pDudeInfo->hearDist)
continue;
if (!cansee(x, y, z, nSector, pSprite->x, pSprite->y, pSprite->z-((pDudeInfo->eyeHeight*pSprite->yrepeat)<<2), pSprite->sectnum))
continue;
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
pDudeExtraE->at4 = 0;
aiSetTarget(pXSprite, pPlayer->at5b);
aiActivateDude(pSprite, pXSprite);
}
else if (nDist < pDudeInfo->hearDist)
{
pDudeExtraE->at4 = 0;
aiSetTarget(pXSprite, x, y, z);
aiActivateDude(pSprite, pXSprite);
}
else
continue;
break;
}
}
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
sub_5F15C(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &gargoyleFSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void MoveDodgeUp(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int dx = xvel[nSprite];
int dy = yvel[nSprite];
int t1 = dmulscale30(dx, nCos, dy, nSin);
int t2 = dmulscale30(dx, nSin, -dy, nCos);
if (pXSprite->dodgeDir > 0)
t2 += pDudeInfo->sideSpeed;
else
t2 -= pDudeInfo->sideSpeed;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -0x1d555;
}
static void MoveDodgeDown(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
if (pXSprite->dodgeDir == 0)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int dx = xvel[nSprite];
int dy = yvel[nSprite];
int t1 = dmulscale30(dx, nCos, dy, nSin);
int t2 = dmulscale30(dx, nSin, -dy, nCos);
if (pXSprite->dodgeDir > 0)
t2 += pDudeInfo->sideSpeed;
else
t2 -= pDudeInfo->sideSpeed;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = 0x44444;
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &gargoyleFGoto);
return;
}
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &gargoyleFSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &gargoyleFSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
// Should be dudeInfo[pTarget->type-kDudeBase]
int height2 = (pDudeInfo->eyeHeight*pTarget->yrepeat)<<2;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int floorZ = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
switch (pSprite->type)
{
case 206:
if (nDist < 0x1800 && nDist > 0xc00 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
sfxPlay3DSound(pSprite, 1408, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleFThrow);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 207)
{
sfxPlay3DSound(pSprite, 1408, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleFThrow);
}
break;
default:
sfxPlay3DSound(pSprite, 1408, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleFThrow);
break;
}
}
else if (nDist < 0x400 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
sfxPlay3DSound(pSprite, 1406, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleFSlash);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 207)
{
sfxPlay3DSound(pSprite, 1406, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleFSlash);
}
break;
default:
sfxPlay3DSound(pSprite, 1406, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleFSlash);
break;
}
}
else if ((height2-height > 0x2000 || floorZ-bottom > 0x2000) && nDist < 0x1400 && nDist > 0xa00)
{
aiPlay3DSound(pSprite, 1400, AI_SFX_PRIORITY_1, -1);
aiNewState(pSprite, pXSprite, &gargoyleSwoop);
}
else if ((height2-height < 0x2000 || floorZ-bottom < 0x2000) && klabs(nDeltaAngle) < 85)
aiPlay3DSound(pSprite, 1400, AI_SFX_PRIORITY_1, -1);
break;
case 207:
if (nDist < 0x1800 && nDist > 0xc00 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
sfxPlay3DSound(pSprite, 1457, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleSBlast);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 206)
{
sfxPlay3DSound(pSprite, 1457, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleSBlast);
}
break;
default:
sfxPlay3DSound(pSprite, 1457, 0, 0);
aiNewState(pSprite, pXSprite, &gargoyleSBlast);
break;
}
}
else if (nDist < 0x400 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
aiNewState(pSprite, pXSprite, &gargoyleFSlash);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 206)
aiNewState(pSprite, pXSprite, &gargoyleFSlash);
break;
default:
aiNewState(pSprite, pXSprite, &gargoyleFSlash);
break;
}
}
else if ((height2-height > 0x2000 || floorZ-bottom > 0x2000) && nDist < 0x1400 && nDist > 0x800)
{
if (pSprite->type == 206)
aiPlay3DSound(pSprite, 1400, AI_SFX_PRIORITY_1, -1);
else
aiPlay3DSound(pSprite, 1450, AI_SFX_PRIORITY_1, -1);
aiNewState(pSprite, pXSprite, &gargoyleSwoop);
}
else if ((height2-height < 0x2000 || floorZ-bottom < 0x2000) && klabs(nDeltaAngle) < 85)
aiPlay3DSound(pSprite, 1450, AI_SFX_PRIORITY_1, -1);
break;
}
}
return;
}
else
{
aiNewState(pSprite, pXSprite, &gargoyleFly);
return;
}
}
aiNewState(pSprite, pXSprite, &gargoyleFGoto);
pXSprite->target = -1;
}
static void entryFStatue(spritetype *pSprite, XSPRITE *pXSprite)
{
DUDEINFO *pDudeInfo = &dudeInfo[6];
actHealDude(pXSprite, pDudeInfo->startHealth, pDudeInfo->startHealth);
pSprite->type = 206;
}
static void entrySStatue(spritetype *pSprite, XSPRITE *pXSprite)
{
DUDEINFO *pDudeInfo = &dudeInfo[7];
actHealDude(pXSprite, pDudeInfo->startHealth, pDudeInfo->startHealth);
pSprite->type = 207;
}
static void MoveForward(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
return;
if (pXSprite->target == -1)
pSprite->ang = (pSprite->ang+256)&2047;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if ((unsigned int)Random(64) < 32 && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
if (pXSprite->target == -1)
t1 += nAccel;
else
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
}
static void MoveSlow(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pXSprite->goalAng = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x600) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 = nAccel>>1;
t2 >>= 1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
switch (pSprite->type)
{
case 206:
zvel[nSprite] = 0x44444;
break;
case 207:
zvel[nSprite] = 0x35555;
break;
}
}
static void MoveSwoop(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pXSprite->goalAng = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x600) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
switch (pSprite->type)
{
case 206:
zvel[nSprite] = t1;
break;
case 207:
zvel[nSprite] = t1;
break;
}
}
static void MoveFly(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pSprite->ang = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x4000) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
switch (pSprite->type)
{
case 206:
zvel[nSprite] = -t1;
break;
case 207:
zvel[nSprite] = -t1;
break;
}
klabs(zvel[nSprite]);
}

50
source/blood/src/aigarg.h Normal file
View file

@ -0,0 +1,50 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE gargoyleFIdle;
extern AISTATE gargoyleStatueIdle;
extern AISTATE gargoyleFChase;
extern AISTATE gargoyleFGoto;
extern AISTATE gargoyleFSlash;
extern AISTATE gargoyleFThrow;
extern AISTATE gargoyleSThrow;
extern AISTATE gargoyleSBlast;
extern AISTATE gargoyleFRecoil;
extern AISTATE gargoyleFSearch;
extern AISTATE gargoyleFMorph2;
extern AISTATE gargoyleFMorph;
extern AISTATE gargoyleSMorph2;
extern AISTATE gargoyleSMorph;
extern AISTATE gargoyleSwoop;
extern AISTATE gargoyleFly;
extern AISTATE gargoyleTurn;
extern AISTATE gargoyleDodgeUp;
extern AISTATE gargoyleFDodgeUpRight;
extern AISTATE gargoyleFDodgeUpLeft;
extern AISTATE gargoyleDodgeDown;
extern AISTATE gargoyleFDodgeDownRight;
extern AISTATE gargoyleFDodgeDownLeft;
extern AISTATE statueFBreakSEQ;
extern AISTATE statueSBreakSEQ;

View file

@ -0,0 +1,587 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aighost.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void SlashSeqCallback(int, int);
static void ThrowSeqCallback(int, int);
static void BlastSeqCallback(int, int);
static void thinkTarget(spritetype *, XSPRITE *);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void MoveDodgeUp(spritetype *, XSPRITE *);
static void MoveDodgeDown(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static void MoveForward(spritetype *, XSPRITE *);
static void MoveSlow(spritetype *, XSPRITE *);
static void MoveSwoop(spritetype *, XSPRITE *);
static void MoveFly(spritetype *, XSPRITE *);
static int nSlashClient = seqRegisterClient(SlashSeqCallback);
static int nThrowClient = seqRegisterClient(ThrowSeqCallback);
static int nBlastClient = seqRegisterClient(BlastSeqCallback);
AISTATE ghostIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, thinkTarget, NULL };
AISTATE ghostChase = { kAiStateChase, 0, -1, 0, NULL, MoveForward, thinkChase, &ghostIdle };
AISTATE ghostGoto = { kAiStateMove, 0, -1, 600, NULL, MoveForward, thinkGoto, &ghostIdle };
AISTATE ghostSlash = { kAiStateChase, 6, nSlashClient, 120, NULL, NULL, NULL, &ghostChase };
AISTATE ghostThrow = { kAiStateChase, 6, nThrowClient, 120, NULL, NULL, NULL, &ghostChase };
AISTATE ghostBlast = { kAiStateChase, 6, nBlastClient, 120, NULL, MoveSlow, NULL, &ghostChase };
AISTATE ghostRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &ghostChase };
AISTATE ghostTeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &ghostChase };
AISTATE ghostSearch = { kAiStateSearch, 0, -1, 120, NULL, MoveForward, thinkSearch, &ghostIdle };
AISTATE ghostSwoop = { kAiStateOther, 0, -1, 120, NULL, MoveSwoop, thinkChase, &ghostChase };
AISTATE ghostFly = { kAiStateMove, 0, -1, 0, NULL, MoveFly, thinkChase, &ghostChase };
AISTATE ghostTurn = { kAiStateMove, 0, -1, 120, NULL, aiMoveTurn, NULL, &ghostChase };
AISTATE ghostDodgeUp = { kAiStateMove, 0, -1, 60, NULL, MoveDodgeUp, NULL, &ghostChase };
AISTATE ghostDodgeUpRight = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeUp, NULL, &ghostChase };
AISTATE ghostDodgeUpLeft = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeUp, NULL, &ghostChase };
AISTATE ghostDodgeDown = { kAiStateMove, 0, -1, 120, NULL, MoveDodgeDown, NULL, &ghostChase };
AISTATE ghostDodgeDownRight = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeDown, NULL, &ghostChase };
AISTATE ghostDodgeDownLeft = { kAiStateMove, 0, -1, 90, NULL, MoveDodgeDown, NULL, &ghostChase };
static void SlashSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
spritetype *pTarget = &sprite[pXSprite->target];
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEINFO *pDudeInfoT = &dudeInfo[pTarget->type-kDudeBase];
int height = (pSprite->yrepeat*pDudeInfo->eyeHeight)<<2;
int height2 = (pTarget->yrepeat*pDudeInfoT->eyeHeight)<<2;
int dz = height-height2;
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
sfxPlay3DSound(pSprite, 1406, 0, 0);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_12);
int r1 = Random(50);
int r2 = Random(50);
actFireVector(pSprite, 0, 0, dx+r2, dy-r1, dz, VECTOR_TYPE_12);
r1 = Random(50);
r2 = Random(50);
actFireVector(pSprite, 0, 0, dx-r2, dy+r1, dz, VECTOR_TYPE_12);
}
static void ThrowSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
actFireThing(&sprite[nSprite], 0, 0, gDudeSlope[nXSprite]-7500, 421, 0xeeeee);
}
static void BlastSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
wrand(); // ???
spritetype *pTarget = &sprite[pXSprite->target];
int height = (pSprite->yrepeat*dudeInfo[pSprite->type-kDudeBase].eyeHeight) << 2;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nDist) = approxDist(dx, dy);
int UNUSED(nAngle) = getangle(dx, dy);
int x = pSprite->x;
int y = pSprite->y;
int z = height;
TARGETTRACK tt = { 0x10000, 0x10000, 0x100, 0x55, 0x1aaaaa };
Aim aim;
aim.dx = Cos(pSprite->ang)>>16;
aim.dy = Sin(pSprite->ang)>>16;
aim.dz = gDudeSlope[nXSprite];
int nClosest = 0x7fffffff;
for (short nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
{
spritetype *pSprite2 = &sprite[nSprite2];
if (pSprite == pSprite2 || !(pSprite2->hitag&8))
continue;
int x2 = pSprite2->x;
int y2 = pSprite2->y;
int z2 = pSprite2->z;
int nDist = approxDist(x2-x, y2-y);
if (nDist == 0 || nDist > 0x2800)
continue;
if (tt.at10)
{
int t = divscale(nDist, tt.at10, 12);
x2 += (xvel[nSprite2]*t)>>12;
y2 += (yvel[nSprite2]*t)>>12;
z2 += (zvel[nSprite2]*t)>>8;
}
int tx = x+mulscale30(Cos(pSprite->ang), nDist);
int ty = y+mulscale30(Sin(pSprite->ang), nDist);
int tz = z+mulscale(gDudeSlope[nXSprite], nDist, 10);
int tsr = mulscale(9460, nDist, 10);
int top, bottom;
GetSpriteExtents(pSprite2, &top, &bottom);
if (tz-tsr > bottom || tz+tsr < top)
continue;
int dx = (tx-x2)>>4;
int dy = (ty-y2)>>4;
int dz = (tz-z2)>>8;
int nDist2 = ksqrt(dx*dx+dy*dy+dz*dz);
if (nDist2 < nClosest)
{
int nAngle = getangle(x2-x, y2-y);
int nDeltaAngle = ((nAngle-pSprite->ang+1024)&2047)-1024;
if (klabs(nDeltaAngle) <= tt.at8)
{
int tz = pSprite2->z-pSprite->z;
if (cansee(x, y, z, pSprite->sectnum, x2, y2, z2, pSprite2->sectnum))
{
nClosest = nDist2;
aim.dx = Cos(nAngle)>>16;
aim.dy = Sin(nAngle)>>16;
aim.dz = divscale(tz, nDist, 10);
if (tz > -0x333)
aim.dz = divscale(tz, nDist, 10);
else if (tz < -0x333 && tz > -0xb33)
aim.dz = divscale(tz, nDist, 10)+9460;
else if (tz < -0xb33 && tz > -0x3000)
aim.dz = divscale(tz, nDist, 10)+9460;
else if (tz < -0x3000)
aim.dz = divscale(tz, nDist, 10)-7500;
else
aim.dz = divscale(tz, nDist, 10);
}
else
aim.dz = divscale(tz, nDist, 10);
}
}
}
if (IsPlayerSprite(pTarget) || !VanillaMode()) // By NoOne: allow fire missile in non-player targets if not a demo
{
sfxPlay3DSound(pSprite, 489, 0, 0);
actFireMissile(pSprite, 0, 0, aim.dx, aim.dy, aim.dz, 307);
}
}
static void thinkTarget(spritetype *pSprite, XSPRITE *pXSprite)
{
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
if (pDudeExtraE->at8 && pDudeExtraE->at4 < 10)
pDudeExtraE->at4++;
else if (pDudeExtraE->at4 >= 10 && pDudeExtraE->at8)
{
pXSprite->goalAng += 256;
POINT3D *pTarget = &baseSprite[pSprite->index];
aiSetTarget(pXSprite, pTarget->x, pTarget->y, pTarget->z);
aiNewState(pSprite, pXSprite, &ghostTurn);
return;
}
if (Chance(pDudeInfo->alertChance))
{
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
PLAYER *pPlayer = &gPlayer[p];
if (pPlayer->pXSprite->health == 0 || powerupCheck(pPlayer, 13) > 0)
continue;
int x = pPlayer->pSprite->x;
int y = pPlayer->pSprite->y;
int z = pPlayer->pSprite->z;
int nSector = pPlayer->pSprite->sectnum;
int dx = x-pSprite->x;
int dy = y-pSprite->y;
int nDist = approxDist(dx, dy);
if (nDist > pDudeInfo->seeDist && nDist > pDudeInfo->hearDist)
continue;
if (!cansee(x, y, z, nSector, pSprite->x, pSprite->y, pSprite->z-((pDudeInfo->eyeHeight*pSprite->yrepeat)<<2), pSprite->sectnum))
continue;
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
pDudeExtraE->at4 = 0;
aiSetTarget(pXSprite, pPlayer->at5b);
aiActivateDude(pSprite, pXSprite);
return;
}
else if (nDist < pDudeInfo->hearDist)
{
pDudeExtraE->at4 = 0;
aiSetTarget(pXSprite, x, y, z);
aiActivateDude(pSprite, pXSprite);
return;
}
}
}
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &ghostSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void MoveDodgeUp(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int dx = xvel[nSprite];
int dy = yvel[nSprite];
int t1 = dmulscale30(dx, nCos, dy, nSin);
int t2 = dmulscale30(dx, nSin, -dy, nCos);
if (pXSprite->dodgeDir > 0)
t2 += pDudeInfo->sideSpeed;
else
t2 -= pDudeInfo->sideSpeed;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -0x1d555;
}
static void MoveDodgeDown(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
if (pXSprite->dodgeDir == 0)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int dx = xvel[nSprite];
int dy = yvel[nSprite];
int t1 = dmulscale30(dx, nCos, dy, nSin);
int t2 = dmulscale30(dx, nSin, -dy, nCos);
if (pXSprite->dodgeDir > 0)
t2 += pDudeInfo->sideSpeed;
else
t2 -= pDudeInfo->sideSpeed;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = 0x44444;
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &ghostGoto);
return;
}
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &ghostSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &ghostSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
// Should be dudeInfo[pTarget->type-kDudeBase]
int height2 = (pDudeInfo->eyeHeight*pTarget->yrepeat)<<2;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int floorZ = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
switch (pSprite->type)
{
case 210:
if (nDist < 0x2000 && nDist > 0x1000 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
aiNewState(pSprite, pXSprite, &ghostBlast);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 210)
aiNewState(pSprite, pXSprite, &ghostBlast);
break;
default:
aiNewState(pSprite, pXSprite, &ghostBlast);
break;
}
}
else if (nDist < 0x400 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
aiNewState(pSprite, pXSprite, &ghostSlash);
break;
case 0:
case 4:
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type && sprite[gHitInfo.hitsprite].type != 210)
aiNewState(pSprite, pXSprite, &ghostSlash);
break;
default:
aiNewState(pSprite, pXSprite, &ghostSlash);
break;
}
}
else if ((height2-height > 0x2000 || floorZ-bottom > 0x2000) && nDist < 0x1400 && nDist > 0x800)
{
aiPlay3DSound(pSprite, 1600, AI_SFX_PRIORITY_1, -1);
aiNewState(pSprite, pXSprite, &ghostSwoop);
}
else if ((height2-height < 0x2000 || floorZ-bottom < 0x2000) && klabs(nDeltaAngle) < 85)
aiPlay3DSound(pSprite, 1600, AI_SFX_PRIORITY_1, -1);
break;
}
}
return;
}
else
{
aiNewState(pSprite, pXSprite, &ghostFly);
return;
}
}
aiNewState(pSprite, pXSprite, &ghostGoto);
pXSprite->target = -1;
}
static void MoveForward(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
return;
if (pXSprite->target == -1)
pSprite->ang = (pSprite->ang+256)&2047;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if ((unsigned int)Random(64) < 32 && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
if (pXSprite->target == -1)
t1 += nAccel;
else
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
}
static void MoveSlow(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pXSprite->goalAng = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x600) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 = nAccel>>1;
t2 >>= 1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
switch (pSprite->type)
{
case 210:
zvel[nSprite] = 0x44444;
break;
}
}
static void MoveSwoop(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pXSprite->goalAng = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x600) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
switch (pSprite->type)
{
case 210:
zvel[nSprite] = t1;
break;
}
}
static void MoveFly(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = pDudeInfo->frontSpeed<<2;
if (klabs(nAng) > 341)
{
pSprite->ang = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x4000) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
switch (pSprite->type)
{
case 210:
zvel[nSprite] = -t1;
break;
}
}

View file

@ -0,0 +1,42 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
extern AISTATE ghostIdle;
extern AISTATE ghostChase;
extern AISTATE ghostGoto;
extern AISTATE ghostSlash;
extern AISTATE ghostThrow;
extern AISTATE ghostBlast;
extern AISTATE ghostRecoil;
extern AISTATE ghostTeslaRecoil;
extern AISTATE ghostSearch;
extern AISTATE ghostSwoop;
extern AISTATE ghostFly;
extern AISTATE ghostTurn;
extern AISTATE ghostDodgeUp;
extern AISTATE ghostDodgeUpRight;
extern AISTATE ghostDodgeUpLeft;
extern AISTATE ghostDodgeDown;
extern AISTATE ghostDodgeDownRight;
extern AISTATE ghostDodgeDownLeft;

View file

@ -0,0 +1,415 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aigilbst.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void GillBiteSeqCallback(int, int);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static void thinkSwimGoto(spritetype *, XSPRITE *);
static void thinkSwimChase(spritetype *, XSPRITE *);
static void sub_6CB00(spritetype *, XSPRITE *);
static void sub_6CD74(spritetype *, XSPRITE *);
static void sub_6D03C(spritetype *, XSPRITE *);
static int nGillBiteClient = seqRegisterClient(GillBiteSeqCallback);
AISTATE gillBeastIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE gillBeastChase = { kAiStateChase, 9, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE gillBeastDodge = { kAiStateMove, 9, -1, 90, NULL, aiMoveDodge, NULL, &gillBeastChase };
AISTATE gillBeastGoto = { kAiStateMove, 9, -1, 600, NULL, aiMoveForward, thinkGoto, &gillBeastIdle };
AISTATE gillBeastBite = { kAiStateChase, 6, nGillBiteClient, 120, NULL, NULL, NULL, &gillBeastChase };
AISTATE gillBeastSearch = { kAiStateMove, 9, -1, 120, NULL, aiMoveForward, thinkSearch, &gillBeastIdle };
AISTATE gillBeastRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &gillBeastDodge };
AISTATE gillBeastSwimIdle = { kAiStateIdle, 10, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE gillBeastSwimChase = { kAiStateChase, 10, -1, 0, NULL, sub_6CB00, thinkSwimChase, NULL };
AISTATE gillBeastSwimDodge = { kAiStateMove, 10, -1, 90, NULL, aiMoveDodge, NULL, &gillBeastSwimChase };
AISTATE gillBeastSwimGoto = { kAiStateMove, 10, -1, 600, NULL, aiMoveForward, thinkSwimGoto, &gillBeastSwimIdle };
AISTATE gillBeastSwimSearch = { kAiStateSearch, 10, -1, 120, NULL, aiMoveForward, thinkSearch, &gillBeastSwimIdle };
AISTATE gillBeastSwimBite = { kAiStateChase, 7, nGillBiteClient, 0, NULL, NULL, thinkSwimChase, &gillBeastSwimChase };
AISTATE gillBeastSwimRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &gillBeastSwimDodge };
AISTATE gillBeast13A138 = { kAiStateOther, 10, -1, 120, NULL, sub_6CD74, thinkSwimChase, &gillBeastSwimChase };
AISTATE gillBeast13A154 = { kAiStateOther, 10, -1, 0, NULL, sub_6D03C, thinkSwimChase, &gillBeastSwimChase };
AISTATE gillBeast13A170 = { kAiStateOther, 10, -1, 120, NULL, NULL, aiMoveTurn, &gillBeastSwimChase };
static void GillBiteSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
spritetype *pTarget = &sprite[pXSprite->target];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
int dz = pSprite->z-pTarget->z;
dx += Random3(2000);
dy += Random3(2000);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_8);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_8);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_8);
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimSearch);
else
aiNewState(pSprite, pXSprite, &gillBeastSearch);
}
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimSearch);
else
aiNewState(pSprite, pXSprite, &gillBeastSearch);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimSearch);
else
aiNewState(pSprite, pXSprite, &gillBeastSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimSearch);
else
aiNewState(pSprite, pXSprite, &gillBeastSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int nXSprite = sprite[pXSprite->reference].extra;
gDudeSlope[nXSprite] = divscale(pTarget->z-pSprite->z, nDist, 10);
if (nDist < 921 && klabs(nDeltaAngle) < 28)
{
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimBite);
else
aiNewState(pSprite, pXSprite, &gillBeastBite);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type)
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimBite);
else
aiNewState(pSprite, pXSprite, &gillBeastBite);
}
else
{
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimDodge);
else
aiNewState(pSprite, pXSprite, &gillBeastDodge);
}
break;
default:
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimBite);
else
aiNewState(pSprite, pXSprite, &gillBeastBite);
break;
}
}
}
return;
}
}
XSECTOR *pXSector;
int nXSector = sector[pSprite->sectnum].extra;
if (nXSector > 0)
pXSector = &xsector[nXSector];
else
pXSector = NULL;
if (pXSector && pXSector->Underwater)
aiNewState(pSprite, pXSprite, &gillBeastSwimGoto);
else
aiNewState(pSprite, pXSprite, &gillBeastGoto);
sfxPlay3DSound(pSprite, 1701, -1, 0);
pXSprite->target = -1;
}
static void thinkSwimGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &gillBeastSwimSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkSwimChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &gillBeastSwimSearch);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &gillBeastSwimSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &gillBeastSwimSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = pDudeInfo->eyeHeight+pSprite->z;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
int UNUSED(floorZ) = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y);
if (nDist < 0x400 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &gillBeastSwimBite);
else
{
aiPlay3DSound(pSprite, 1700, AI_SFX_PRIORITY_1, -1);
aiNewState(pSprite, pXSprite, &gillBeast13A154);
}
}
}
else
aiNewState(pSprite, pXSprite, &gillBeast13A154);
return;
}
aiNewState(pSprite, pXSprite, &gillBeastSwimGoto);
pXSprite->target = -1;
}
static void sub_6CB00(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = (pDudeInfo->frontSpeed-(((4-gGameOptions.nDifficulty)<<27)/120)/120)<<2;
if (klabs(nAng) > 341)
return;
if (pXSprite->target == -1)
pSprite->ang = (pSprite->ang+256)&2047;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Random(64) < 32 && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
if (pXSprite->target == -1)
t1 += nAccel;
else
t1 += nAccel>>2;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
}
static void sub_6CD74(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
spritetype *pTarget = &sprite[pXSprite->target];
int z = pSprite->z + dudeInfo[pSprite->type - kDudeBase].eyeHeight;
int z2 = pTarget->z + dudeInfo[pTarget->type - kDudeBase].eyeHeight;
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = (pDudeInfo->frontSpeed-(((4-gGameOptions.nDifficulty)<<27)/120)/120)<<2;
if (klabs(nAng) > 341)
{
pXSprite->goalAng = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int dz = z2 - z;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x600) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = -dz;
}
static void sub_6D03C(spritetype *pSprite, XSPRITE *pXSprite)
{
int nSprite = pSprite->index;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
spritetype *pTarget = &sprite[pXSprite->target];
int z = pSprite->z + dudeInfo[pSprite->type - kDudeBase].eyeHeight;
int z2 = pTarget->z + dudeInfo[pTarget->type - kDudeBase].eyeHeight;
int nAng = ((pXSprite->goalAng+1024-pSprite->ang)&2047)-1024;
int nTurnRange = (pDudeInfo->angSpeed<<2)>>4;
pSprite->ang = (pSprite->ang+ClipRange(nAng, -nTurnRange, nTurnRange))&2047;
int nAccel = (pDudeInfo->frontSpeed-(((4-gGameOptions.nDifficulty)<<27)/120)/120)<<2;
if (klabs(nAng) > 341)
{
pSprite->ang = (pSprite->ang+512)&2047;
return;
}
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int dz = (z2 - z)<<3;
int UNUSED(nAngle) = getangle(dx, dy);
int nDist = approxDist(dx, dy);
if (Chance(0x4000) && nDist <= 0x400)
return;
int nCos = Cos(pSprite->ang);
int nSin = Sin(pSprite->ang);
int vx = xvel[nSprite];
int vy = yvel[nSprite];
int t1 = dmulscale30(vx, nCos, vy, nSin);
int t2 = dmulscale30(vx, nSin, -vy, nCos);
t1 += nAccel>>1;
xvel[nSprite] = dmulscale30(t1, nCos, t2, nSin);
yvel[nSprite] = dmulscale30(t1, nSin, -t2, nCos);
zvel[nSprite] = dz;
}

View file

@ -0,0 +1,43 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE gillBeastIdle;
extern AISTATE gillBeastChase;
extern AISTATE gillBeastDodge;
extern AISTATE gillBeastGoto;
extern AISTATE gillBeastBite;
extern AISTATE gillBeastSearch;
extern AISTATE gillBeastRecoil;
extern AISTATE gillBeastSwimIdle;
extern AISTATE gillBeastSwimChase;
extern AISTATE gillBeastSwimDodge;
extern AISTATE gillBeastSwimGoto;
extern AISTATE gillBeastSwimSearch;
extern AISTATE gillBeastSwimBite;
extern AISTATE gillBeastSwimRecoil;
extern AISTATE gillBeast13A138;
extern AISTATE gillBeast13A154;
extern AISTATE gillBeast13A170;

138
source/blood/src/aihand.cpp Normal file
View file

@ -0,0 +1,138 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aihand.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void HandJumpSeqCallback(int, int);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static int nJumpClient = seqRegisterClient(HandJumpSeqCallback);
AISTATE handIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE hand13A3B4 = { kAiStateOther, 0, -1, 0, NULL, NULL, NULL, NULL };
AISTATE handSearch = { kAiStateMove, 6, -1, 600, NULL, aiMoveForward, thinkSearch, &handIdle };
AISTATE handChase = { kAiStateChase, 6, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE handRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &handSearch };
AISTATE handGoto = { kAiStateMove, 6, -1, 1800, NULL, aiMoveForward, thinkGoto, &handIdle };
AISTATE handJump = { kAiStateChase, 7, nJumpClient, 120, NULL, NULL, NULL, &handChase };
static void HandJumpSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
spritetype *pTarget = &sprite[pXSprite->target];
if (IsPlayerSprite(pTarget))
{
PLAYER *pPlayer = &gPlayer[pTarget->type-kDudePlayer1];
if (!pPlayer->at376)
{
pPlayer->at376 = 1;
actPostSprite(pSprite->index, kStatFree);
}
}
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &handSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &handGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &handSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &handSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x233 && klabs(nDeltaAngle) < 85 && gGameOptions.nGameType == 0)
aiNewState(pSprite, pXSprite, &handJump);
return;
}
}
}
aiNewState(pSprite, pXSprite, &handGoto);
pXSprite->target = -1;
}

32
source/blood/src/aihand.h Normal file
View file

@ -0,0 +1,32 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE handIdle;
extern AISTATE hand13A3B4;
extern AISTATE handSearch;
extern AISTATE handChase;
extern AISTATE handRecoil;
extern AISTATE handGoto;
extern AISTATE handJump;

View file

@ -0,0 +1,160 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aihound.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void BiteSeqCallback(int, int);
static void BurnSeqCallback(int, int);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static int nBiteClient = seqRegisterClient(BiteSeqCallback);
static int nBurnClient = seqRegisterClient(BurnSeqCallback);
AISTATE houndIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE houndSearch = { kAiStateMove, 8, -1, 1800, NULL, aiMoveForward, thinkSearch, &houndIdle };
AISTATE houndChase = { kAiStateChase, 8, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE houndRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &houndSearch };
AISTATE houndTeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &houndSearch };
AISTATE houndGoto = { kAiStateMove, 8, -1, 600, NULL, aiMoveForward, thinkGoto, &houndIdle };
AISTATE houndBite = { kAiStateChase, 6, nBiteClient, 60, NULL, NULL, NULL, &houndChase };
AISTATE houndBurn = { kAiStateChase, 7, nBurnClient, 60, NULL, NULL, NULL, &houndChase };
static void BiteSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
if (IsPlayerSprite(pTarget) || !VanillaMode()) // allow to hit non-player targets if not a demo
actFireVector(pSprite, 0, 0, dx, dy, pTarget->z-pSprite->z, VECTOR_TYPE_15);
}
static void BurnSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
actFireMissile(pSprite, 0, 0, Cos(pSprite->ang)>>16, Sin(pSprite->ang)>>16, 0, 308);
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &houndSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &houndGoto);
return;
}
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &houndSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &houndSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0xb00 && nDist > 0x500 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &houndBurn);
else if(nDist < 0x266 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &houndBite);
return;
}
}
}
aiNewState(pSprite, pXSprite, &houndGoto);
pXSprite->target = -1;
}

View file

@ -0,0 +1,33 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE houndIdle;
extern AISTATE houndSearch;
extern AISTATE houndChase;
extern AISTATE houndRecoil;
extern AISTATE houndTeslaRecoil;
extern AISTATE houndGoto;
extern AISTATE houndBite;
extern AISTATE houndBurn;

View file

@ -0,0 +1,119 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aiinnoc.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
AISTATE innocentIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE innocentSearch = { kAiStateSearch, 6, -1, 1800, NULL, aiMoveForward, thinkSearch, &innocentIdle };
AISTATE innocentChase = { kAiStateChase, 6, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE innocentRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &innocentChase };
AISTATE innocentTeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &innocentChase };
AISTATE innocentGoto = { kAiStateMove, 6, -1, 600, NULL, aiMoveForward, thinkGoto, &innocentIdle };
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &innocentSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &innocentGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &innocentSearch);
return;
}
if (IsPlayerSprite(pTarget))
{
aiNewState(pSprite, pXSprite, &innocentSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x666 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &innocentIdle);
return;
}
}
}
aiPlay3DSound(pSprite, 7000+Random(6), AI_SFX_PRIORITY_1, -1);
aiNewState(pSprite, pXSprite, &innocentGoto);
pXSprite->target = -1;
}

View file

@ -0,0 +1,31 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE innocentIdle;
extern AISTATE innocentSearch;
extern AISTATE innocentChase;
extern AISTATE innocentRecoil;
extern AISTATE innocentTeslaRecoil;
extern AISTATE innocentGoto;

282
source/blood/src/aipod.cpp Normal file
View file

@ -0,0 +1,282 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aipod.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void sub_6FF08(int, int);
static void sub_6FF54(int, int);
static void sub_6FFA0(int, int);
static void sub_70284(int, int);
static void sub_7034C(spritetype *, XSPRITE *);
static void sub_70380(spritetype *, XSPRITE *);
static void sub_704D8(spritetype *, XSPRITE *);
static int dword_279B34 = seqRegisterClient(sub_6FFA0);
static int dword_279B38 = seqRegisterClient(sub_70284);
static int dword_279B3C = seqRegisterClient(sub_6FF08);
static int dword_279B40 = seqRegisterClient(sub_6FF54);
AISTATE podIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE pod13A600 = { kAiStateMove, 7, -1, 3600, NULL, aiMoveTurn, sub_70380, &podSearch };
AISTATE podSearch = { kAiStateSearch, 0, -1, 3600, NULL, aiMoveTurn, sub_7034C, &podSearch };
AISTATE pod13A638 = { kAiStateChase, 8, dword_279B34, 600, NULL, NULL, NULL, &podChase };
AISTATE podRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &podChase };
AISTATE podChase = { kAiStateChase, 6, -1, 0, NULL, aiMoveTurn, sub_704D8, NULL };
AISTATE tentacleIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE tentacle13A6A8 = { kAiStateOther, 7, dword_279B3C, 0, NULL, NULL, NULL, &tentacle13A6C4 };
AISTATE tentacle13A6C4 = { kAiStateOther, -1, -1, 0, NULL, NULL, NULL, &tentacleChase };
AISTATE tentacle13A6E0 = { kAiStateOther, 8, dword_279B40, 0, NULL, NULL, NULL, &tentacle13A6FC };
AISTATE tentacle13A6FC = { kAiStateOther, -1, -1, 0, NULL, NULL, NULL, &tentacleIdle };
AISTATE tentacle13A718 = { kAiStateOther, 8, -1, 3600, NULL, aiMoveTurn, sub_70380, &tentacleSearch };
AISTATE tentacleSearch = { kAiStateOther, 0, -1, 3600, NULL, aiMoveTurn, sub_7034C, NULL };
AISTATE tentacle13A750 = { kAiStateOther, 6, dword_279B38, 120, NULL, NULL, NULL, &tentacleChase };
AISTATE tentacleRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &tentacleChase };
AISTATE tentacleChase = { kAiStateChase, 6, -1, 0, NULL, aiMoveTurn, sub_704D8, NULL };
static void sub_6FF08(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
sfxPlay3DSound(&sprite[nSprite], 2503, -1, 0);
}
static void sub_6FF54(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
sfxPlay3DSound(&sprite[nSprite], 2500, -1, 0);
}
static void sub_6FFA0(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
int x = pTarget->x-pSprite->x;
int y = pTarget->y-pSprite->y;
int dz = pTarget->z-pSprite->z;
x += Random2(1000);
y += Random2(1000);
int nDist = approxDist(x, y);
int nDist2 = nDist / 540;
spritetype *pMissile = NULL;
switch (pSprite->type)
{
case 221:
dz += 8000;
if (pDudeInfo->seeDist*0.1 < nDist)
{
if (Chance(0x8000))
sfxPlay3DSound(pSprite, 2474, -1, 0);
else
sfxPlay3DSound(pSprite, 2475, -1, 0);
pMissile = actFireThing(pSprite, 0, -8000, dz/128-14500, 430, (nDist2<<23)/120);
}
if (pMissile)
seqSpawn(68, 3, pMissile->extra, -1);
break;
case 223:
dz += 8000;
if (pDudeInfo->seeDist*0.1 < nDist)
{
sfxPlay3DSound(pSprite, 2454, -1, 0);
pMissile = actFireThing(pSprite, 0, -8000, dz/128-14500, 429, (nDist2<<23)/120);
}
if (pMissile)
seqSpawn(22, 3, pMissile->extra, -1);
break;
}
for (int i = 0; i < 4; i++)
sub_746D4(pSprite, 240);
}
static void sub_70284(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
sfxPlay3DSound(pSprite, 2502, -1, 0);
int nDist, nBurn;
DAMAGE_TYPE dmgType;
switch (pSprite->type)
{
case 222:
default:
nBurn = 0;
dmgType = DAMAGE_TYPE_2;
nDist = 50;
break;
case 224:
nBurn = (gGameOptions.nDifficulty*120)>>2;
dmgType = DAMAGE_TYPE_3;
nDist = 75;
break;
}
sub_2A620(nSprite, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum, nDist, 1, 5*(1+gGameOptions.nDifficulty), dmgType, 2, nBurn, 0, 0);
}
static void sub_7034C(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void sub_70380(spritetype *pSprite, XSPRITE *pXSprite)
{
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
{
switch (pSprite->type)
{
case 221:
case 223:
aiNewState(pSprite, pXSprite, &podSearch);
break;
case 222:
case 224:
aiNewState(pSprite, pXSprite, &tentacleSearch);
break;
}
}
aiThinkTarget(pSprite, pXSprite);
}
static void sub_704D8(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
switch (pSprite->type)
{
case 221:
case 223:
aiNewState(pSprite, pXSprite, &pod13A600);
break;
case 222:
case 224:
aiNewState(pSprite, pXSprite, &tentacle13A718);
break;
}
return;
}
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
switch (pSprite->type)
{
case 221:
case 223:
aiNewState(pSprite, pXSprite, &podSearch);
break;
case 222:
case 224:
aiNewState(pSprite, pXSprite, &tentacleSearch);
break;
}
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (klabs(nDeltaAngle) < 85 && pTarget->type != 221 && pTarget->type != 223)
{
switch (pSprite->type)
{
case 221:
case 223:
aiNewState(pSprite, pXSprite, &pod13A638);
break;
case 222:
case 224:
aiNewState(pSprite, pXSprite, &tentacle13A750);
break;
}
}
return;
}
}
}
switch (pSprite->type)
{
case 221:
case 223:
aiNewState(pSprite, pXSprite, &pod13A600);
break;
case 222:
case 224:
aiNewState(pSprite, pXSprite, &tentacle13A718);
break;
}
pXSprite->target = -1;
}

41
source/blood/src/aipod.h Normal file
View file

@ -0,0 +1,41 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE podIdle;
extern AISTATE pod13A600;
extern AISTATE podSearch;
extern AISTATE pod13A638;
extern AISTATE podRecoil;
extern AISTATE podChase;
extern AISTATE tentacleIdle;
extern AISTATE tentacle13A6A8;
extern AISTATE tentacle13A6C4;
extern AISTATE tentacle13A6E0;
extern AISTATE tentacle13A6FC;
extern AISTATE tentacle13A718;
extern AISTATE tentacleSearch;
extern AISTATE tentacle13A750;
extern AISTATE tentacleRecoil;
extern AISTATE tentacleChase;

135
source/blood/src/airat.cpp Normal file
View file

@ -0,0 +1,135 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "airat.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void BiteSeqCallback(int, int);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static int nBiteClient = seqRegisterClient(BiteSeqCallback);
AISTATE ratIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE ratSearch = { kAiStateSearch, 7, -1, 1800, NULL, aiMoveForward, thinkSearch, &ratIdle };
AISTATE ratChase = { kAiStateChase, 7, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE ratDodge = { kAiStateMove, 7, -1, 0, NULL, NULL, NULL, &ratChase };
AISTATE ratRecoil = { kAiStateRecoil, 7, -1, 0, NULL, NULL, NULL, &ratDodge };
AISTATE ratGoto = { kAiStateMove, 7, -1, 600, NULL, aiMoveForward, thinkGoto, &ratIdle };
AISTATE ratBite = { kAiStateChase, 6, nBiteClient, 120, NULL, NULL, NULL, &ratChase };
static void BiteSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
if (IsPlayerSprite(pTarget))
actFireVector(pSprite, 0, 0, dx, dy, pTarget->z-pSprite->z, VECTOR_TYPE_16);
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &ratSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &ratGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &ratSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &ratSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x399 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &ratBite);
return;
}
}
}
aiNewState(pSprite, pXSprite, &ratGoto);
pXSprite->target = -1;
}

32
source/blood/src/airat.h Normal file
View file

@ -0,0 +1,32 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE ratIdle;
extern AISTATE ratSearch;
extern AISTATE ratChase;
extern AISTATE ratDodge;
extern AISTATE ratRecoil;
extern AISTATE ratGoto;
extern AISTATE ratBit;

290
source/blood/src/aispid.cpp Normal file
View file

@ -0,0 +1,290 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aispid.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "endgame.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void SpidBiteSeqCallback(int, int);
static void SpidJumpSeqCallback(int, int);
static void sub_71370(int, int);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static int nBiteClient = seqRegisterClient(SpidBiteSeqCallback);
static int nJumpClient = seqRegisterClient(SpidJumpSeqCallback);
static int dword_279B50 = seqRegisterClient(sub_71370);
AISTATE spidIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE spidChase = { kAiStateChase, 7, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE spidDodge = { kAiStateMove, 7, -1, 90, NULL, aiMoveDodge, NULL, &spidChase };
AISTATE spidGoto = { kAiStateMove, 7, -1, 600, NULL, aiMoveForward, thinkGoto, &spidIdle };
AISTATE spidSearch = { kAiStateSearch, 7, -1, 1800, NULL, aiMoveForward, thinkSearch, &spidIdle };
AISTATE spidBite = { kAiStateChase, 6, nBiteClient, 60, NULL, NULL, NULL, &spidChase };
AISTATE spidJump = { kAiStateChase, 8, nJumpClient, 60, NULL, aiMoveForward, NULL, &spidChase };
AISTATE spid13A92C = { kAiStateOther, 0, dword_279B50, 60, NULL, NULL, NULL, &spidIdle };
static char sub_70D30(XSPRITE *pXDude, int a2, int a3)
{
dassert(pXDude != NULL);
int nDude = pXDude->reference;
spritetype *pDude = &sprite[nDude];
if (IsPlayerSprite(pDude))
{
a2 <<= 4;
a3 <<= 4;
if (IsPlayerSprite(pDude))
{
PLAYER *pPlayer = &gPlayer[pDude->type-kDudePlayer1];
if (a3 > pPlayer->at36a)
{
pPlayer->at36a = ClipHigh(pPlayer->at36a+a2, a3);
return 1;
}
}
}
return 0;
}
static void SpidBiteSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
dx += Random2(2000);
dy += Random2(2000);
int dz = Random2(2000);
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
if (IsPlayerSprite(pTarget))
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
if (hit == 3)
{
if (sprite[gHitInfo.hitsprite].type <= kDudePlayer8 && sprite[gHitInfo.hitsprite].type >= kDudePlayer1)
{
dz += pTarget->z-pSprite->z;
if (pTarget->type >= kDudePlayer1 && pTarget->type <= kDudePlayer8)
{
PLAYER *pPlayer = &gPlayer[pTarget->type-kDudePlayer1];
switch (pSprite->type)
{
case 213:
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_17);
if (IsPlayerSprite(pTarget) && !pPlayer->at31a && powerupCheck(pPlayer, 14) <= 0
&& Chance(0x4000))
powerupActivate(pPlayer, 28);
break;
case 214:
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_17);
if (Chance(0x5000))
sub_70D30(pXTarget, 4, 16);
break;
case 215:
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_17);
sub_70D30(pXTarget, 8, 16);
break;
case 216:
{
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_17);
dx += Random2(2000);
dy += Random2(2000);
dz += Random2(2000);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_17);
sub_70D30(pXTarget, 8, 16);
break;
}
}
}
}
}
}
}
static void SpidJumpSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
int dx = Cos(pSprite->ang)>>16;
int dy = Sin(pSprite->ang)>>16;
dx += Random2(200);
dy += Random2(200);
int dz = Random2(200);
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
if (IsPlayerSprite(pTarget))
{
dz += pTarget->z-pSprite->z;
if (pTarget->type >= kDudePlayer1 && pTarget->type <= kDudePlayer8)
{
switch (pSprite->type)
{
case 213:
case 214:
case 215:
xvel[nSprite] = dx << 16;
yvel[nSprite] = dy << 16;
zvel[nSprite] = dz << 16;
break;
}
}
}
}
static void sub_71370(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
spritetype *pSpawn = NULL;
if (IsPlayerSprite(pTarget) && pDudeExtraE->at4 < 10)
{
if (nDist < 0x1a00 && nDist > 0x1400 && klabs(pSprite->ang-nAngle) < pDudeInfo->periphery)
pSpawn = actSpawnDude(pSprite, 214, pSprite->clipdist, 0);
else if (nDist < 0x1400 && nDist > 0xc00 && klabs(pSprite->ang-nAngle) < pDudeInfo->periphery)
pSpawn = actSpawnDude(pSprite, 213, pSprite->clipdist, 0);
else if (nDist < 0xc00 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
pSpawn = actSpawnDude(pSprite, 213, pSprite->clipdist, 0);
if (pSpawn)
{
pDudeExtraE->at4++;
pSpawn->owner = nSprite;
gKillMgr.sub_263E0(1);
}
}
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &spidSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &spidGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &spidSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &spidSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
switch (pSprite->type)
{
case 214:
if (nDist < 0x399 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &spidBite);
break;
case 213:
case 215:
if (nDist < 0x733 && nDist > 0x399 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &spidJump);
else if (nDist < 0x399 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &spidBite);
break;
case 216:
if (nDist < 0x733 && nDist > 0x399 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &spidJump);
else if (Chance(0x8000))
aiNewState(pSprite, pXSprite, &spid13A92C);
break;
}
return;
}
}
}
aiNewState(pSprite, pXSprite, &spidGoto);
pXSprite->target = -1;
}

33
source/blood/src/aispid.h Normal file
View file

@ -0,0 +1,33 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE spidIdle;
extern AISTATE spidChase;
extern AISTATE spidDodge;
extern AISTATE spidGoto;
extern AISTATE spidSearch;
extern AISTATE spidBite;
extern AISTATE spidJump;
extern AISTATE spid13A92C;

View file

@ -0,0 +1,357 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aitchern.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void sub_71A90(int, int);
static void sub_71BD4(int, int);
static void sub_720AC(int, int);
static void sub_72580(spritetype *, XSPRITE *);
static void sub_725A4(spritetype *, XSPRITE *);
static void sub_72850(spritetype *, XSPRITE *);
static void sub_72934(spritetype *, XSPRITE *);
static int dword_279B54 = seqRegisterClient(sub_71BD4);
static int dword_279B58 = seqRegisterClient(sub_720AC);
static int dword_279B5C = seqRegisterClient(sub_71A90);
AISTATE tchernobogIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, sub_725A4, NULL };
AISTATE tchernobogSearch = { kAiStateSearch, 8, -1, 1800, NULL, aiMoveForward, sub_72580, &tchernobogIdle };
AISTATE tchernobogChase = { kAiStateChase, 8, -1, 0, NULL, aiMoveForward, sub_72934, NULL };
AISTATE tchernobogRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &tchernobogSearch };
AISTATE tcherno13A9B8 = { kAiStateMove, 8, -1, 600, NULL, aiMoveForward, sub_72850, &tchernobogIdle };
AISTATE tcherno13A9D4 = { kAiStateMove, 6, dword_279B54, 60, NULL, NULL, NULL, &tchernobogChase };
AISTATE tcherno13A9F0 = { kAiStateChase, 6, dword_279B58, 60, NULL, NULL, NULL, &tchernobogChase };
AISTATE tcherno13AA0C = { kAiStateChase, 7, dword_279B5C, 60, NULL, NULL, NULL, &tchernobogChase };
AISTATE tcherno13AA28 = { kAiStateChase, 8, -1, 60, NULL, aiMoveTurn, NULL, &tchernobogChase };
static void sub_71A90(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int nTarget = pTarget->index;
int nOwner = actSpriteIdToOwnerId(nSprite);
if (pXTarget->burnTime == 0)
evPost(nTarget, 3, 0, CALLBACK_ID_0);
actBurnSprite(nOwner, pXTarget, 40);
if (Chance(0x6000))
aiNewState(pSprite, pXSprite, &tcherno13A9D4);
}
static void sub_71BD4(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
int height = pSprite->yrepeat*pDudeInfo->eyeHeight;
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
int x = pSprite->x;
int y = pSprite->y;
int z = height;
TARGETTRACK tt = { 0x10000, 0x10000, 0x100, 0x55, 0x100000 };
Aim aim;
aim.dx = Cos(pSprite->ang)>>16;
aim.dy = Sin(pSprite->ang)>>16;
aim.dz = gDudeSlope[nXSprite];
int nClosest = 0x7fffffff;
for (short nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
{
spritetype *pSprite2 = &sprite[nSprite2];
if (pSprite == pSprite2 || !(pSprite2->hitag&8))
continue;
int x2 = pSprite2->x;
int y2 = pSprite2->y;
int z2 = pSprite2->z;
int nDist = approxDist(x2-x, y2-y);
if (nDist == 0 || nDist > 0x2800)
continue;
if (tt.at10)
{
int t = divscale(nDist, tt.at10, 12);
x2 += (xvel[nSprite2]*t)>>12;
y2 += (yvel[nSprite2]*t)>>12;
z2 += (zvel[nSprite2]*t)>>8;
}
int tx = x+mulscale30(Cos(pSprite->ang), nDist);
int ty = y+mulscale30(Sin(pSprite->ang), nDist);
int tz = z+mulscale(gDudeSlope[nXSprite], nDist, 10);
int tsr = mulscale(9460, nDist, 10);
int top, bottom;
GetSpriteExtents(pSprite2, &top, &bottom);
if (tz-tsr > bottom || tz+tsr < top)
continue;
int dx = (tx-x2)>>4;
int dy = (ty-y2)>>4;
int dz = (tz-z2)>>8;
int nDist2 = ksqrt(dx*dx+dy*dy+dz*dz);
if (nDist2 < nClosest)
{
int nAngle = getangle(x2-x, y2-y);
int nDeltaAngle = ((nAngle-pSprite->ang+1024)&2047)-1024;
if (klabs(nDeltaAngle) <= tt.at8)
{
int tz = pSprite2->z-pSprite->z;
if (cansee(x, y, z, pSprite->sectnum, x2, y2, z2, pSprite2->sectnum))
{
nClosest = nDist2;
aim.dx = Cos(nAngle)>>16;
aim.dy = Sin(nAngle)>>16;
aim.dz = divscale(tz, nDist, 10);
}
else
aim.dz = tz;
}
}
}
actFireMissile(pSprite, -350, 0, aim.dx, aim.dy, aim.dz, 314);
actFireMissile(pSprite, 350, 0, aim.dx, aim.dy, aim.dz, 314);
}
static void sub_720AC(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
int height = pSprite->yrepeat*pDudeInfo->eyeHeight;
int ax, ay, az;
ax = Cos(pSprite->ang)>>16;
ay = Sin(pSprite->ang)>>16;
int x = pSprite->x;
int y = pSprite->y;
int z = height;
TARGETTRACK tt = { 0x10000, 0x10000, 0x100, 0x55, 0x100000 };
Aim aim;
aim.dx = ax;
aim.dy = ay;
aim.dz = gDudeSlope[nXSprite];
int nClosest = 0x7fffffff;
az = 0;
for (short nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nextspritestat[nSprite2])
{
spritetype *pSprite2 = &sprite[nSprite2];
if (pSprite == pSprite2 || !(pSprite2->hitag&8))
continue;
int x2 = pSprite2->x;
int y2 = pSprite2->y;
int z2 = pSprite2->z;
int nDist = approxDist(x2-x, y2-y);
if (nDist == 0 || nDist > 0x2800)
continue;
if (tt.at10)
{
int t = divscale(nDist, tt.at10, 12);
x2 += (xvel[nSprite2]*t)>>12;
y2 += (yvel[nSprite2]*t)>>12;
z2 += (zvel[nSprite2]*t)>>8;
}
int tx = x+mulscale30(Cos(pSprite->ang), nDist);
int ty = y+mulscale30(Sin(pSprite->ang), nDist);
int tz = z+mulscale(gDudeSlope[nXSprite], nDist, 10);
int tsr = mulscale(9460, nDist, 10);
int top, bottom;
GetSpriteExtents(pSprite2, &top, &bottom);
if (tz-tsr > bottom || tz+tsr < top)
continue;
int dx = (tx-x2)>>4;
int dy = (ty-y2)>>4;
int dz = (tz-z2)>>8;
int nDist2 = ksqrt(dx*dx+dy*dy+dz*dz);
if (nDist2 < nClosest)
{
int nAngle = getangle(x2-x, y2-y);
int nDeltaAngle = ((nAngle-pSprite->ang+1024)&2047)-1024;
if (klabs(nDeltaAngle) <= tt.at8)
{
int tz = pSprite2->z-pSprite->z;
if (cansee(x, y, z, pSprite->sectnum, x2, y2, z2, pSprite2->sectnum))
{
nClosest = nDist2;
aim.dx = Cos(nAngle)>>16;
aim.dy = Sin(nAngle)>>16;
aim.dz = divscale(tz, nDist, 10);
}
else
aim.dz = tz;
}
}
}
actFireMissile(pSprite, 350, 0, aim.dx, aim.dy, -aim.dz, 314);
actFireMissile(pSprite, -350, 0, ax, ay, az, 314);
}
static void sub_72580(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void sub_725A4(spritetype *pSprite, XSPRITE *pXSprite)
{
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u2;
if (pDudeExtraE->at4 && pDudeExtraE->at0 < 10)
pDudeExtraE->at0++;
else if (pDudeExtraE->at0 >= 10 && pDudeExtraE->at4)
{
pXSprite->goalAng += 256;
POINT3D *pTarget = &baseSprite[pSprite->index];
aiSetTarget(pXSprite, pTarget->x, pTarget->y, pTarget->z);
aiNewState(pSprite, pXSprite, &tcherno13AA28);
return;
}
if (Chance(pDudeInfo->alertChance))
{
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
PLAYER *pPlayer = &gPlayer[p];
if (pPlayer->pXSprite->health == 0 || powerupCheck(pPlayer, 13) > 0)
continue;
int x = pPlayer->pSprite->x;
int y = pPlayer->pSprite->y;
int z = pPlayer->pSprite->z;
int nSector = pPlayer->pSprite->sectnum;
int dx = x-pSprite->x;
int dy = y-pSprite->y;
int nDist = approxDist(dx, dy);
if (nDist > pDudeInfo->seeDist && nDist > pDudeInfo->hearDist)
continue;
if (!cansee(x, y, z, nSector, pSprite->x, pSprite->y, pSprite->z-((pDudeInfo->eyeHeight*pSprite->yrepeat)<<2), pSprite->sectnum))
continue;
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
pDudeExtraE->at0 = 0;
aiSetTarget(pXSprite, pPlayer->at5b);
aiActivateDude(pSprite, pXSprite);
}
else if (nDist < pDudeInfo->hearDist)
{
pDudeExtraE->at0 = 0;
aiSetTarget(pXSprite, x, y, z);
aiActivateDude(pSprite, pXSprite);
}
else
continue;
break;
}
}
}
static void sub_72850(spritetype *pSprite, XSPRITE *pXSprite)
{
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &tchernobogSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void sub_72934(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &tcherno13A9B8);
return;
}
if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax))
return;
//dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
if (!(pXSprite->target >= 0 && pXSprite->target < kMaxSprites))
return;
//dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &tchernobogSearch);
return;
}
if (IsPlayerSprite(pTarget) && powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0)
{
aiNewState(pSprite, pXSprite, &tchernobogSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x1f00 && nDist > 0xd00 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &tcherno13AA0C);
else if (nDist < 0xd00 && nDist > 0xb00 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &tcherno13A9D4);
else if (nDist < 0xb00 && nDist > 0x500 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &tcherno13A9F0);
return;
}
}
}
aiNewState(pSprite, pXSprite, &tcherno13A9B8);
pXSprite->target = -1;
}

View file

@ -0,0 +1,34 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE tchernobogIdle;
extern AISTATE tchernobogSearch;
extern AISTATE tchernobogChase;
extern AISTATE tchernobogRecoil;
extern AISTATE tcherno13A9B8;
extern AISTATE tcherno13A9D4;
extern AISTATE tcherno13A9F0;
extern AISTATE tcherno13AA0C;
extern AISTATE tcherno13AA28;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,75 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
Copyright (C) NoOne
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
#include "eventq.h"
extern AISTATE GDXGenDudeIdleL;
extern AISTATE GDXGenDudeIdleW;
extern AISTATE GDXGenDudeSearchL;
extern AISTATE GDXGenDudeSearchW;
extern AISTATE GDXGenDudeGotoL;
extern AISTATE GDXGenDudeGotoW;
extern AISTATE GDXGenDudeDodgeL;
extern AISTATE GDXGenDudeDodgeD;
extern AISTATE GDXGenDudeDodgeW;
extern AISTATE GDXGenDudeDodgeDmgL;
extern AISTATE GDXGenDudeDodgeDmgD;
extern AISTATE GDXGenDudeDodgeDmgW;
extern AISTATE GDXGenDudeChaseL;
extern AISTATE GDXGenDudeChaseD;
extern AISTATE GDXGenDudeChaseW;
extern AISTATE GDXGenDudeFireL;
extern AISTATE GDXGenDudeFireD;
extern AISTATE GDXGenDudeFireW;
extern AISTATE GDXGenDudeFire2L;
extern AISTATE GDXGenDudeFire2D;
extern AISTATE GDXGenDudeFire2W;
extern AISTATE GDXGenDudeRecoilL;
extern AISTATE GDXGenDudeRecoilD;
extern AISTATE GDXGenDudeRecoilW;
extern AISTATE GDGenDudeThrow;
extern AISTATE GDGenDudeThrow2;
extern AISTATE GDXGenDudePunch;
extern AISTATE GDXGenDudeRTesla;
extern AISTATE GDXGenDudeProne;
extern AISTATE GDXGenDudeTurn;
XSPRITE* getNextIncarnation(XSPRITE* pXSprite);
void killDudeLeech(spritetype* pLeech);
void removeLeech(spritetype* pLeech, bool delSprite = true);
void removeDudeStuff(spritetype* pSprite);
spritetype* leechIsDropped(spritetype* pSprite);
bool spriteIsUnderwater(spritetype* pSprite, bool oldWay);
bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode, int data);
void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite);
int getGenDudeMoveSpeed(spritetype* pSprite, int which, bool mul, bool shift);
bool TargetNearThing(spritetype* pSprite, int thingType);
int checkAttackState(spritetype* pSprite, XSPRITE* pXSprite);
bool doExplosion(spritetype* pSprite, int nType);
void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT a3);
int getDodgeChance(spritetype* pSprite);
int getRecoilChance(spritetype* pSprite);
bool dudeIsMelee(XSPRITE* pXSprite);
void updateTargetOfSlaves(spritetype* pSprite);

View file

@ -0,0 +1,281 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aizomba.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void HackSeqCallback(int, int);
static void StandSeqCallback(int, int);
static void thinkSearch(spritetype *, XSPRITE *);
static void thinkGoto(spritetype *, XSPRITE *);
static void thinkChase(spritetype *, XSPRITE *);
static void thinkPonder(spritetype *, XSPRITE *);
static void myThinkTarget(spritetype *, XSPRITE *);
static void myThinkSearch(spritetype *, XSPRITE *);
static void entryEZombie(spritetype *, XSPRITE *);
static void entryAIdle(spritetype *, XSPRITE *);
static void entryEStand(spritetype *, XSPRITE *);
static int nHackClient = seqRegisterClient(HackSeqCallback);
static int nStandClient = seqRegisterClient(StandSeqCallback);
AISTATE zombieAIdle = { kAiStateIdle, 0, -1, 0, entryAIdle, NULL, aiThinkTarget, NULL };
AISTATE zombieAChase = { kAiStateChase, 8, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE zombieAPonder = { kAiStateOther, 0, -1, 0, NULL, aiMoveTurn, thinkPonder, NULL };
AISTATE zombieAGoto = { kAiStateMove, 8, -1, 1800, NULL, aiMoveForward, thinkGoto, &zombieAIdle };
AISTATE zombieAHack = { kAiStateChase, 6, nHackClient, 80, NULL, NULL, NULL, &zombieAPonder };
AISTATE zombieASearch = { kAiStateSearch, 8, -1, 1800, NULL, aiMoveForward, thinkSearch, &zombieAIdle };
AISTATE zombieARecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &zombieAPonder };
AISTATE zombieATeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &zombieAPonder };
AISTATE zombieARecoil2 = { kAiStateRecoil, 1, -1, 360, NULL, NULL, NULL, &zombieAStand };
AISTATE zombieAStand = { kAiStateMove, 11, nStandClient, 0, NULL, NULL, NULL, &zombieAPonder };
AISTATE zombieEIdle = { kAiStateIdle, 12, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE zombieEUp2 = { kAiStateMove, 0, -1, 1, entryEZombie, NULL, NULL, &zombieASearch };
AISTATE zombieEUp = { kAiStateMove, 9, -1, 180, entryEStand, NULL, NULL, &zombieEUp2 };
AISTATE zombie2Idle = { kAiStateIdle, 0, -1, 0, entryAIdle, NULL, myThinkTarget, NULL };
AISTATE zombie2Search = { kAiStateSearch, 8, -1, 1800, NULL, NULL, myThinkSearch, &zombie2Idle };
AISTATE zombieSIdle = { kAiStateIdle, 10, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE zombie13AC2C = { kAiStateOther, 11, nStandClient, 0, entryEZombie, NULL, NULL, &zombieAPonder };
static void HackSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
spritetype *pTarget = &sprite[pXSprite->target];
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEINFO *pDudeInfoT = &dudeInfo[pTarget->type-kDudeBase];
int tx = pXSprite->targetX-pSprite->x;
int ty = pXSprite->targetY-pSprite->y;
int UNUSED(nDist) = approxDist(tx, ty);
int nAngle = getangle(tx, ty);
int height = (pSprite->yrepeat*pDudeInfo->eyeHeight)<<2;
int height2 = (pTarget->yrepeat*pDudeInfoT->eyeHeight)<<2;
int dz = height-height2;
int dx = Cos(nAngle)>>16;
int dy = Sin(nAngle)>>16;
sfxPlay3DSound(pSprite, 1101, 1, 0);
actFireVector(pSprite, 0, 0, dx, dy, dz, VECTOR_TYPE_10);
}
static void StandSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
sfxPlay3DSound(&sprite[nSprite], 1102, -1, 0);
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
sub_5F15C(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 921 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &zombieASearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &zombieASearch);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &zombieASearch);
return;
}
if (IsPlayerSprite(pTarget) && (powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0 || powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 31) > 0))
{
aiNewState(pSprite, pXSprite, &zombieAGoto);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x400 && klabs(nDeltaAngle) < 85)
aiNewState(pSprite, pXSprite, &zombieAHack);
return;
}
}
}
aiNewState(pSprite, pXSprite, &zombieAGoto);
pXSprite->target = -1;
}
static void thinkPonder(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &zombieASearch);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &zombieASearch);
return;
}
if (IsPlayerSprite(pTarget) && (powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0 || powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 31) > 0))
{
aiNewState(pSprite, pXSprite, &zombieAGoto);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x400)
{
if (klabs(nDeltaAngle) < 85)
{
sfxPlay3DSound(pSprite, 1101, 1, 0);
aiNewState(pSprite, pXSprite, &zombieAHack);
}
return;
}
}
}
}
aiNewState(pSprite, pXSprite, &zombieAChase);
}
static void myThinkTarget(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
PLAYER *pPlayer = &gPlayer[p];
int nOwner = (pSprite->owner & 0x1000) ? (pSprite->owner&0xfff) : -1;
if (nOwner == pPlayer->at5b || pPlayer->pXSprite->health == 0 || powerupCheck(pPlayer, 13) > 0)
continue;
int x = pPlayer->pSprite->x;
int y = pPlayer->pSprite->y;
int z = pPlayer->pSprite->z;
int nSector = pPlayer->pSprite->sectnum;
int dx = x-pSprite->x;
int dy = y-pSprite->y;
int nDist = approxDist(dx, dy);
if (nDist > pDudeInfo->seeDist && nDist > pDudeInfo->hearDist)
continue;
if (!cansee(x, y, z, nSector, pSprite->x, pSprite->y, pSprite->z-((pDudeInfo->eyeHeight*pSprite->yrepeat)<<2), pSprite->sectnum))
continue;
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pPlayer->at5b);
aiActivateDude(pSprite, pXSprite);
}
else if (nDist < pDudeInfo->hearDist)
{
aiSetTarget(pXSprite, x, y, z);
aiActivateDude(pSprite, pXSprite);
}
else
continue;
break;
}
}
static void myThinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
myThinkTarget(pSprite, pXSprite);
}
static void entryEZombie(spritetype *pSprite, XSPRITE *pXSprite)
{
UNREFERENCED_PARAMETER(pXSprite);
pSprite->type = 203;
pSprite->hitag |= 1;
}
static void entryAIdle(spritetype *pSprite, XSPRITE *pXSprite)
{
UNREFERENCED_PARAMETER(pSprite);
pXSprite->target = -1;
}
static void entryEStand(spritetype *pSprite, XSPRITE *pXSprite)
{
sfxPlay3DSound(pSprite, 1100, -1, 0);
pSprite->ang = getangle(pXSprite->targetX-pSprite->x, pXSprite->targetY-pSprite->y);
}

View file

@ -0,0 +1,42 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE zombieAIdle;
extern AISTATE zombieAChase;
extern AISTATE zombieAPonder;
extern AISTATE zombieAGoto;
extern AISTATE zombieAHack;
extern AISTATE zombieASearch;
extern AISTATE zombieARecoil;
extern AISTATE zombieATeslaRecoil;
extern AISTATE zombieARecoil2;
extern AISTATE zombieAStand;
extern AISTATE zombieEIdle;
extern AISTATE zombieEUp2;
extern AISTATE zombieEUp;
extern AISTATE zombie2Idle;
extern AISTATE zombie2Search;
extern AISTATE zombieSIdle;
extern AISTATE zombie13AC2C;

View file

@ -0,0 +1,230 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "mmulti.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "aizombf.h"
#include "blood.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "trig.h"
static void HackSeqCallback(int, int);
static void PukeSeqCallback(int, int);
static void ThrowSeqCallback(int, int);
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite);
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite);
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite);
static int nHackClient = seqRegisterClient(HackSeqCallback);
static int nPukeClient = seqRegisterClient(PukeSeqCallback);
static int nThrowClient = seqRegisterClient(ThrowSeqCallback);
AISTATE zombieFIdle = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL };
AISTATE zombieFChase = { kAiStateChase, 8, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
AISTATE zombieFGoto = { kAiStateMove, 8, -1, 600, NULL, aiMoveForward, thinkGoto, &zombieFIdle };
AISTATE zombieFDodge = { kAiStateMove, 8, -1, 0, NULL, aiMoveDodge, thinkChase, &zombieFChase };
AISTATE zombieFHack = { kAiStateChase, 6, nHackClient, 120, NULL, NULL, NULL, &zombieFChase };
AISTATE zombieFPuke = { kAiStateChase, 9, nPukeClient, 120, NULL, NULL, NULL, &zombieFChase };
AISTATE zombieFThrow = { kAiStateChase, 6, nThrowClient, 120, NULL, NULL, NULL, &zombieFChase };
AISTATE zombieFSearch = { kAiStateSearch, 8, -1, 1800, NULL, aiMoveForward, thinkSearch, &zombieFIdle };
AISTATE zombieFRecoil = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &zombieFChase };
AISTATE zombieFTeslaRecoil = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &zombieFChase };
static void HackSeqCallback(int, int nXSprite)
{
if (nXSprite <= 0 || nXSprite >= kMaxXSprites)
return;
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
if (nXSprite < 0 || nXSprite >= kMaxSprites)
return;
spritetype *pSprite = &sprite[nSprite];
if (pSprite->type != 204)
return;
spritetype *pTarget = &sprite[pXSprite->target];
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat);
DUDEINFO *pDudeInfoT = &dudeInfo[pTarget->type-kDudeBase];
int height2 = (pDudeInfoT->eyeHeight*pTarget->yrepeat);
actFireVector(pSprite, 0, 0, Cos(pSprite->ang)>>16, Sin(pSprite->ang)>>16, height-height2, VECTOR_TYPE_11);
}
static void PukeSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
spritetype *pTarget = &sprite[pXSprite->target];
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase];
DUDEINFO *pDudeInfoT = &dudeInfo[pTarget->type-kDudeBase];
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat);
int height2 = (pDudeInfoT->eyeHeight*pTarget->yrepeat);
int tx = pXSprite->targetX-pSprite->x;
int ty = pXSprite->targetY-pSprite->y;
int UNUSED(nDist) = approxDist(tx, ty);
int nAngle = getangle(tx, ty);
int dx = Cos(nAngle)>>16;
int dy = Sin(nAngle)>>16;
sfxPlay3DSound(pSprite, 1203, 1, 0);
actFireMissile(pSprite, 0, -(height-height2), dx, dy, 0, 309);
}
static void ThrowSeqCallback(int, int nXSprite)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
int nSprite = pXSprite->reference;
spritetype *pSprite = &sprite[nSprite];
actFireMissile(pSprite, 0, -dudeInfo[pSprite->type-kDudeBase].eyeHeight, Cos(pSprite->ang)>>16, Sin(pSprite->ang)>>16, 0, 300);
}
static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
{
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
{
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);
int nDist = approxDist(dx, dy);
aiChooseDirection(pSprite, pXSprite, nAngle);
if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
aiNewState(pSprite, pXSprite, &zombieFSearch);
aiThinkTarget(pSprite, pXSprite);
}
static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
{
if (pXSprite->target == -1)
{
aiNewState(pSprite, pXSprite, &zombieFGoto);
return;
}
dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase];
dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
XSPRITE *pXTarget = &xsprite[pTarget->extra];
int dx = pTarget->x-pSprite->x;
int dy = pTarget->y-pSprite->y;
aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
if (pXTarget->health == 0)
{
aiNewState(pSprite, pXSprite, &zombieFSearch);
return;
}
if (IsPlayerSprite(pTarget) && (powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 13) > 0 || powerupCheck(&gPlayer[pTarget->type-kDudePlayer1], 31) > 0))
{
aiNewState(pSprite, pXSprite, &zombieFSearch);
return;
}
int nDist = approxDist(dx, dy);
if (nDist <= pDudeInfo->seeDist)
{
int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
{
if (klabs(nDeltaAngle) <= pDudeInfo->periphery)
{
aiSetTarget(pXSprite, pXSprite->target);
if (nDist < 0x1400 && nDist > 0xe00 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
aiNewState(pSprite, pXSprite, &zombieFThrow);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type)
aiNewState(pSprite, pXSprite, &zombieFThrow);
else
aiNewState(pSprite, pXSprite, &zombieFDodge);
break;
default:
aiNewState(pSprite, pXSprite, &zombieFThrow);
break;
}
}
else if (nDist < 0x1400 && nDist > 0x600 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
aiNewState(pSprite, pXSprite, &zombieFPuke);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type)
aiNewState(pSprite, pXSprite, &zombieFPuke);
else
aiNewState(pSprite, pXSprite, &zombieFDodge);
break;
default:
aiNewState(pSprite, pXSprite, &zombieFPuke);
break;
}
}
else if (nDist < 0x400 && klabs(nDeltaAngle) < 85)
{
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
switch (hit)
{
case -1:
aiNewState(pSprite, pXSprite, &zombieFHack);
break;
case 3:
if (pSprite->type != sprite[gHitInfo.hitsprite].type)
aiNewState(pSprite, pXSprite, &zombieFHack);
else
aiNewState(pSprite, pXSprite, &zombieFDodge);
break;
default:
aiNewState(pSprite, pXSprite, &zombieFHack);
break;
}
}
return;
}
}
}
aiNewState(pSprite, pXSprite, &zombieFSearch);
pXSprite->target = -1;
}

View file

@ -0,0 +1,35 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "ai.h"
extern AISTATE zombieFIdle;
extern AISTATE zombieFChase;
extern AISTATE zombieFGoto;
extern AISTATE zombieFDodge;
extern AISTATE zombieFHack;
extern AISTATE zombieFPuke;
extern AISTATE zombieFThrow;
extern AISTATE zombieFSearch;
extern AISTATE zombieFRecoil;
extern AISTATE zombieFTeslaRecoil;

158
source/blood/src/asound.cpp Normal file
View file

@ -0,0 +1,158 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "build.h"
#include "fx_man.h"
#include "common_game.h"
#include "blood.h"
#include "config.h"
#include "db.h"
#include "player.h"
#include "resource.h"
#include "sound.h"
#define kMaxAmbChannel 64
struct AMB_CHANNEL
{
int at0;
int at4;
int at8;
DICTNODE *atc;
char *at10;
int at14;
int at18;
};
AMB_CHANNEL ambChannels[kMaxAmbChannel];
int nAmbChannels = 0;
void ambProcess(void)
{
if (!SoundToggle)
return;
for (int nSprite = headspritestat[12]; nSprite >= 0; nSprite = nextspritestat[nSprite])
{
spritetype *pSprite = &sprite[nSprite];
if (pSprite->owner < 0 || pSprite->owner >= kMaxAmbChannel)
continue;
int nXSprite = pSprite->extra;
if (nXSprite > 0 && nXSprite < kMaxXSprites)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
if (pXSprite->state)
{
int dx = pSprite->x-gMe->pSprite->x;
int dy = pSprite->y-gMe->pSprite->y;
int dz = pSprite->z-gMe->pSprite->z;
dx >>= 4;
dy >>= 4;
dz >>= 8;
int nDist = ksqrt(dx*dx+dy*dy+dz*dz);
int vs = mulscale16(pXSprite->data4, pXSprite->busy);
ambChannels[pSprite->owner].at4 += ClipRange(scale(nDist, pXSprite->data1, pXSprite->data2, vs, 0), 0, vs);
}
}
}
AMB_CHANNEL *pChannel = ambChannels;
for (int i = 0; i < nAmbChannels; i++, pChannel++)
{
if (pChannel->at0 > 0)
FX_SetPan(pChannel->at0, pChannel->at4, pChannel->at4, pChannel->at4);
else
{
int end = ClipLow(pChannel->at14-1, 0);
pChannel->at0 = FX_PlayLoopedRaw(pChannel->at10, pChannel->at14, pChannel->at10, pChannel->at10+end, sndGetRate(pChannel->at18), 0,
pChannel->at4, pChannel->at4, pChannel->at4, pChannel->at4, 1.f, (intptr_t)&pChannel->at0);
}
pChannel->at4 = 0;
}
}
void ambKillAll(void)
{
AMB_CHANNEL *pChannel = ambChannels;
for (int i = 0; i < nAmbChannels; i++, pChannel++)
{
if (pChannel->at0 > 0)
{
FX_EndLooping(pChannel->at0);
FX_StopSound(pChannel->at0);
}
if (pChannel->atc)
{
gSoundRes.Unlock(pChannel->atc);
pChannel->atc = NULL;
}
}
nAmbChannels = 0;
}
void ambInit(void)
{
ambKillAll();
memset(ambChannels, 0, sizeof(ambChannels));
for (int nSprite = headspritestat[12]; nSprite >= 0; nSprite = nextspritestat[nSprite])
{
spritetype *pSprite = &sprite[nSprite];
int nXSprite = pSprite->extra;
if (nXSprite > 0 && nXSprite < kMaxXSprites)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
if (pXSprite->data1 < pXSprite->data2)
{
int i;
AMB_CHANNEL *pChannel = ambChannels;
for (i = 0; i < nAmbChannels; i++, pChannel++)
if (pXSprite->data3 == pChannel->at8)
break;
if (i == nAmbChannels)
{
if (i >= kMaxAmbChannel)
{
pSprite->owner = -1;
continue;
}
int nSFX = pXSprite->data3;
DICTNODE *pSFXNode = gSoundRes.Lookup(nSFX, "SFX");
if (!pSFXNode)
ThrowError("Missing sound #%d used in ambient sound generator %d\n", nSFX);
SFX *pSFX = (SFX*)gSoundRes.Load(pSFXNode);
DICTNODE *pRAWNode = gSoundRes.Lookup(pSFX->rawName, "RAW");
if (!pRAWNode)
ThrowError("Missing RAW sound \"%s\" used in ambient sound generator %d\n", pSFX->rawName, nSFX);
if (pRAWNode->size > 0)
{
pChannel->at14 = pRAWNode->size;
pChannel->at8 = nSFX;
pChannel->atc = pRAWNode;
pChannel->at14 = pRAWNode->size;
pChannel->at10 = (char*)gSoundRes.Lock(pRAWNode);
pChannel->at18 = pSFX->format;
nAmbChannels++;
}
}
pSprite->owner = i;
}
}
}
}

27
source/blood/src/asound.h Normal file
View file

@ -0,0 +1,27 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
void ambProcess(void);
void ambKillAll(void);
void ambInit(void);

2438
source/blood/src/blood.cpp Normal file

File diff suppressed because it is too large Load diff

249
source/blood/src/blood.h Normal file
View file

@ -0,0 +1,249 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "levels.h"
#include "resource.h"
#define TILTBUFFER 4078
#define kExplodeMax 8
#define kDudeBase 200
#define kDudePlayer1 231
#define kDudePlayer8 238
#define kDudeMax 260
#define kMissileBase 300
#define kMissileMax 318
#define kThingBase 400
#define kThingMax 436
#define kMaxPowerUps 51
#define kStatRespawn 8
#define kStatMarker 10
#define kStatGDXDudeTargetChanger 20
#define kStatFree 1024
#define kLensSize 80
#define kViewEffectMax 19
#define kNoTile -1
// defined by NoOne:
// -------------------------------
#define kMaxPAL 5
#define kWeaponItemBase 40
#define kItemMax 151
// marker sprite types
#define kMarkerSPStart 1
#define kMarkerMPStart 2
#define kMarkerOff 3
#define kMarkerOn 4
#define kMarkerAxis 5
#define kMarkerLowLink 6
#define kMarkerUpLink 7
#define kMarkerWarpDest 8
#define kMarkerUpWater 9
#define kMarkerLowWater 10
#define kMarkerUpStack 11
#define kMarkerLowStack 12
#define kMarkerUpGoo 13
#define kMarkerLowGoo 14
#define kMarkerPath 15
// sprite cstat
#define kSprBlock 0x0001
#define kSprTrans 0x0002
#define kSprFlipX 0x0004
#define kSprFlipY 0x0008
#define kSprFace 0x0000
#define kSprWall 0x0010
#define kSprFloor 0x0020
#define kSprSpin 0x0030
#define kSprRMask 0x0030
#define kSprOneSided 0x0040
#define kSprOriginAlign 0x0080
#define kSprHitscan 0x0100
#define kSprTransR 0x0200
#define kSprPushable 0x1000
#define kSprMoveMask 0x6000
#define kSprMoveNone 0x0000
#define kSprMoveForward 0x2000
#define kSprMoveFloor 0x2000
#define kSprMoveReverse 0x4000
#define kSprMoveCeiling 0x4000
#define kSprInvisible 0x8000
// sprite attributes
#define kHitagMovePhys 0x0001 // affected by movement physics
#define kHitagGravityPhys 0x0002 // affected by gravity
#define kHitagFalling 0x0004 // currently in z-motion
#define kHitagAutoAim 0x0008
#define kHitagRespawn 0x0010
#define kHitagFree 0x0020
#define kHitagSmoke 0x0100
#define kHitagExtBit 0x8000 // NoOne's extension bit(Note: it's bit 0 in editor!)
// sector types
#define kSecBase 600
#define kSecZMotion kSectorBase
#define kSecZSprite 602
#define kSecWarp 603
#define kSecTeleport 604
#define kSecPath 612
#define kSecRotateStep 613
#define kSecSlideMarked 614
#define kSecRotateMarked 615
#define kSecSlide 616
#define kSecRotate 617
#define kSecDamage 618
#define kSecCounter 619
#define kSecMax 620
// switch types
#define kSwitchBase 20
#define kSwitchToggle 20
#define kSwitchOneWay 21
#define kSwitchCombo 22
#define kSwitchPadlock 23
#define kSwitchMax 24
// projectile types
#define kProjectileEctoSkull 307
// custom level end
#define kGDXChannelEndLevelCustom 6
// GDX types
#define kGDXTypeBase 24
#define kGDXCustomDudeSpawn 24
#define kGDXRandomTX 25
#define kGDXSequentialTX 26
#define kGDXSeqSpawner 27
#define kGDXObjPropertiesChanger 28
#define kGDXObjPicnumChanger 29
#define kGDXObjSizeChanger 31
#define kGDXDudeTargetChanger 33
#define kGDXSectorFXChanger 34
#define kGDXObjDataChanger 35
#define kGDXSpriteDamager 36
#define kGDXObjDataAccumulator 37
#define kGDXEffectSpawner 38
#define kGDXWindGenerator 39
#define kGDXThingTNTProx 433 // detects only players
#define kGDXThingThrowableRock 434 // does small damage if hits target
#define kGDXThingCustomDudeLifeLeech 435 // the same as normal, except it aims in specified target
#define kGDXDudeUniversalCultist 254
#define kGDXGenDudeBurning 255
#define kGDXItemMapLevel 150 // once picked up, draws whole minimap
// ai state types
#define kAiStateOther -1
#define kAiStateIdle 0
#define kAiStateGenIdle 1
#define kAiStateMove 2
#define kAiStateSearch 3
#define kAiStateChase 4
#define kAiStateRecoil 5
#define kAng5 28
#define kAng15 85
#define kAng30 170
#define kAng45 256
#define kAng60 341
#define kAng90 512
#define kAng120 682
#define kAng180 1024
#define kAng360 2048
// -------------------------------
struct INIDESCRIPTION {
const char *pzName;
const char *pzFilename;
const char **pzArts;
int nArts;
};
struct INICHAIN {
INICHAIN *pNext;
char zName[BMAX_PATH];
INIDESCRIPTION *pDescription;
};
extern INICHAIN *pINIChain;
extern INICHAIN const*pINISelected;
typedef struct {
int32_t usejoystick;
int32_t usemouse;
int32_t fullscreen;
int32_t xdim;
int32_t ydim;
int32_t bpp;
int32_t forcesetup;
int32_t noautoload;
} ud_setup_t;
enum INPUT_MODE {
INPUT_MODE_0 = 0,
INPUT_MODE_1,
INPUT_MODE_2,
INPUT_MODE_3,
};
extern Resource gSysRes, gGuiRes;
extern INPUT_MODE gInputMode;
extern ud_setup_t gSetup;
extern char SetupFilename[BMAX_PATH];
extern int32_t gNoSetup;
extern short BloodVersion;
extern int gNetPlayers;
extern bool gRestartGame;
#define GAMEUPDATEAVGTIMENUMSAMPLES 100
extern double g_gameUpdateTime, g_gameUpdateAndDrawTime;
extern double g_gameUpdateAvgTime;
extern int blood_globalflags;
extern bool bVanilla;
extern int gMusicPrevLoadedEpisode;
extern int gMusicPrevLoadedLevel;
extern int gFrameClock;
void QuitGame(void);
void PreloadCache(void);
void StartLevel(GAMEOPTIONS *gameOptions);
void ProcessFrame(void);
void ScanINIFiles(void);
bool LoadArtFile(const char *pzFile);
void LoadExtraArts(void);
bool DemoRecordStatus(void);
bool VanillaMode(void);
bool fileExistsRFF(int id, const char* ext);

View file

@ -0,0 +1,731 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "build.h"
#include "common_game.h"
#include "actor.h"
#include "ai.h"
#include "blood.h"
#include "callback.h"
#include "config.h"
#include "db.h"
#include "dude.h"
#include "eventq.h"
#include "fx.h"
#include "gameutil.h"
#include "levels.h"
#include "player.h"
#include "seq.h"
#include "sfx.h"
#include "sound.h"
#include "trig.h"
#include "triggers.h"
#include "view.h"
void sub_74C20(int nSprite) // 7
{
spritetype *pSprite = &sprite[nSprite];
spritetype *pFX = gFX.fxSpawn(FX_15, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite] + Random2(0x10000);
yvel[pFX->index] = yvel[nSprite] + Random2(0x10000);
zvel[pFX->index] = zvel[nSprite] - Random(0x1aaaa);
}
evPost(nSprite, 3, 3, CALLBACK_ID_7);
}
void sub_74D04(int nSprite) // 15
{
spritetype *pSprite = &sprite[nSprite];
spritetype *pFX = gFX.fxSpawn(FX_49, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite] + Random2(0x1aaaa);
yvel[pFX->index] = yvel[nSprite] + Random2(0x1aaaa);
zvel[pFX->index] = zvel[nSprite] - Random(0x1aaaa);
}
evPost(nSprite, 3, 3, CALLBACK_ID_15);
}
void FinishHim(int nSprite) // 13
{
spritetype *pSprite = &sprite[nSprite];
int nXSprite = pSprite->extra;
XSPRITE *pXSprite = &xsprite[nXSprite];
if (playerSeqPlaying(&gPlayer[pSprite->type-kDudePlayer1], 16) && pXSprite->target == gMe->at5b)
sndStartSample(3313, -1, 1, 0);
}
void FlameLick(int nSprite) // 0
{
spritetype *pSprite = &sprite[nSprite];
int nXSprite = pSprite->extra;
XSPRITE *pXSprite = &xsprite[nXSprite];
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
for (int i = 0; i < 3; i++)
{
int nDist = (pSprite->xrepeat*(tilesiz[pSprite->picnum].x/2))>>3;
int nAngle = Random(2048);
int dx = mulscale30(nDist, Cos(nAngle));
int dy = mulscale30(nDist, Sin(nAngle));
int x = pSprite->x + dx;
int y = pSprite->y + dy;
int z = bottom-Random(bottom-top);
spritetype *pFX = gFX.fxSpawn(FX_32, pSprite->sectnum, x, y, z, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite] + Random2(-dx);
yvel[pFX->index] = yvel[nSprite] + Random2(-dy);
zvel[pFX->index] = zvel[nSprite] - Random(0x1aaaa);
}
}
if (pXSprite->burnTime > 0)
evPost(nSprite, 3, 5, CALLBACK_ID_0);
}
void Remove(int nSprite) // 1
{
spritetype *pSprite = &sprite[nSprite];
evKill(nSprite, 3);
if (pSprite->extra > 0)
seqKill(3, pSprite->extra);
sfxKill3DSound(pSprite, 0, -1);
DeleteSprite(nSprite);
}
void FlareBurst(int nSprite) // 2
{
dassert(nSprite >= 0 && nSprite < kMaxSprites);
spritetype *pSprite = &sprite[nSprite];
int nAngle = getangle(xvel[nSprite], yvel[nSprite]);
int nRadius = 0x55555;
for (int i = 0; i < 8; i++)
{
spritetype *pSpawn = actSpawnSprite(pSprite, 5);
pSpawn->picnum = 2424;
pSpawn->shade = -128;
pSpawn->xrepeat = pSpawn->yrepeat = 32;
pSpawn->type = 303;
pSpawn->clipdist = 2;
pSpawn->owner = pSprite->owner;
int nAngle2 = (i<<11)/8;
int dx = 0;
int dy = mulscale30r(nRadius, Sin(nAngle2));
int dz = mulscale30r(nRadius, -Cos(nAngle2));
if (i&1)
{
dy >>= 1;
dz >>= 1;
}
RotateVector(&dx, &dy, nAngle);
xvel[pSpawn->index] += dx;
yvel[pSpawn->index] += dy;
zvel[pSpawn->index] += dz;
evPost(pSpawn->index, 3, 960, CALLBACK_ID_3);
}
evPost(nSprite, 3, 0, CALLBACK_ID_1);
}
void FlareSpark(int nSprite) // 3
{
spritetype *pSprite = &sprite[nSprite];
spritetype *pFX = gFX.fxSpawn(FX_28, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite] + Random2(0x1aaaa);
yvel[pFX->index] = yvel[nSprite] + Random2(0x1aaaa);
zvel[pFX->index] = zvel[nSprite] - Random(0x1aaaa);
}
evPost(nSprite, 3, 4, CALLBACK_ID_3);
}
void FlareSparkLite(int nSprite) // 4
{
spritetype *pSprite = &sprite[nSprite];
spritetype *pFX = gFX.fxSpawn(FX_28, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite] + Random2(0x1aaaa);
yvel[pFX->index] = yvel[nSprite] + Random2(0x1aaaa);
zvel[pFX->index] = zvel[nSprite] - Random(0x1aaaa);
}
evPost(nSprite, 3, 12, CALLBACK_ID_4);
}
void ZombieSpurt(int nSprite) // 5
{
dassert(nSprite >= 0 && nSprite < kMaxSprites);
spritetype *pSprite = &sprite[nSprite];
int nXSprite = pSprite->extra;
dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
XSPRITE *pXSprite = &xsprite[nXSprite];
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
spritetype *pFX = gFX.fxSpawn(FX_27, pSprite->sectnum, pSprite->x, pSprite->y, top, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite] + Random2(0x11111);
yvel[pFX->index] = yvel[nSprite] + Random2(0x11111);
zvel[pFX->index] = zvel[nSprite] - 0x6aaaa;
}
if (pXSprite->data1 > 0)
{
evPost(nSprite, 3, 4, CALLBACK_ID_5);
pXSprite->data1 -= 4;
}
else if (pXSprite->data2 > 0)
{
evPost(nSprite, 3, 60, CALLBACK_ID_5);
pXSprite->data1 = 40;
pXSprite->data2--;
}
}
void BloodSpurt(int nSprite) // 6
{
spritetype *pSprite = &sprite[nSprite];
spritetype *pFX = gFX.fxSpawn(FX_27, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
if (pFX)
{
pFX->ang = 0;
xvel[pFX->index] = xvel[nSprite]>>8;
yvel[pFX->index] = yvel[nSprite]>>8;
zvel[pFX->index] = zvel[nSprite]>>8;
}
evPost(nSprite, 3, 6, CALLBACK_ID_6);
}
void DynPuff(int nSprite) // 8
{
spritetype *pSprite = &sprite[nSprite];
if (zvel[nSprite])
{
int nDist = (pSprite->xrepeat*(tilesiz[pSprite->picnum].x/2))>>2;
int x = pSprite->x + mulscale30(nDist, Cos(pSprite->ang-512));
int y = pSprite->y + mulscale30(nDist, Sin(pSprite->ang-512));
int z = pSprite->z;
spritetype *pFX = gFX.fxSpawn(FX_7, pSprite->sectnum, x, y, z, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite];
yvel[pFX->index] = yvel[nSprite];
zvel[pFX->index] = zvel[nSprite];
}
}
evPost(nSprite, 3, 12, CALLBACK_ID_8);
}
void Respawn(int nSprite) // 9
{
spritetype *pSprite = &sprite[nSprite];
int nXSprite = pSprite->extra;
dassert(nXSprite > 0 && nXSprite < kMaxXSprites);
XSPRITE *pXSprite = &xsprite[nXSprite];
if (pSprite->statnum != 8 && pSprite->statnum != 4)
ThrowError("Sprite %d is not on Respawn or Thing list\n", nSprite);
if (!(pSprite->hitag&16))
ThrowError("Sprite %d does not have the respawn attribute\n", nSprite);
switch (pXSprite->respawnPending)
{
case 1:
{
int nTime = mulscale16(actGetRespawnTime(pSprite), 0x4000);
pXSprite->respawnPending = 2;
evPost(nSprite, 3, nTime, CALLBACK_ID_9);
break;
}
case 2:
{
int nTime = mulscale16(actGetRespawnTime(pSprite), 0x2000);
pXSprite->respawnPending = 3;
evPost(nSprite, 3, nTime, CALLBACK_ID_9);
break;
}
case 3:
{
dassert(pSprite->owner != kStatRespawn);
dassert(pSprite->owner >= 0 && pSprite->owner < kMaxStatus);
ChangeSpriteStat(nSprite, pSprite->owner);
pSprite->type = pSprite->zvel;
pSprite->owner = -1;
pSprite->hitag &= ~16;
xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0;
pXSprite->respawnPending = 0;
pXSprite->burnTime = 0;
pXSprite->isTriggered = 0;
if (pSprite->type >= kDudeBase && pSprite->type < kDudeMax)
{
int nType = pSprite->type-kDudeBase;
pSprite->x = baseSprite[nSprite].x;
pSprite->y = baseSprite[nSprite].y;
pSprite->z = baseSprite[nSprite].z;
pSprite->cstat |= 0x1101;
pSprite->clipdist = dudeInfo[nType].clipdist;
pXSprite->health = dudeInfo[nType].startHealth<<4;
if (gSysRes.Lookup(dudeInfo[nType].seqStartID, "SEQ"))
seqSpawn(dudeInfo[nType].seqStartID, 3, pSprite->extra, -1);
aiInitSprite(pSprite);
pXSprite->key = 0;
}
if (pSprite->type == 400)
{
pSprite->cstat |= 257;
pSprite->cstat &= (unsigned short)~32768;
}
gFX.fxSpawn(FX_29, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
sfxPlay3DSound(pSprite, 350, -1, 0);
break;
}
default:
ThrowError("Unexpected respawnPending value = %d", pXSprite->respawnPending);
break;
}
}
void PlayerBubble(int nSprite) // 10
{
spritetype *pSprite = &sprite[nSprite];
if (IsPlayerSprite(pSprite))
{
PLAYER *pPlayer = &gPlayer[pSprite->type-kDudePlayer1];
dassert(pPlayer != NULL);
if (!pPlayer->at302)
return;
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
for (int i = 0; i < (pPlayer->at302>>6); i++)
{
int nDist = (pSprite->xrepeat*(tilesiz[pSprite->picnum].x/2))>>2;
int nAngle = Random(2048);
int x = pSprite->x + mulscale30(nDist, Cos(nAngle));
int y = pSprite->y + mulscale30(nDist, Sin(nAngle));
int z = bottom-Random(bottom-top);
spritetype *pFX = gFX.fxSpawn((FX_ID)(FX_23+Random(3)), pSprite->sectnum, x, y, z, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite] + Random2(0x1aaaa);
yvel[pFX->index] = yvel[nSprite] + Random2(0x1aaaa);
zvel[pFX->index] = zvel[nSprite] + Random2(0x1aaaa);
}
}
evPost(nSprite, 3, 4, CALLBACK_ID_10);
}
}
void EnemyBubble(int nSprite) // 11
{
spritetype *pSprite = &sprite[nSprite];
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
for (int i = 0; i < (klabs(zvel[nSprite])>>18); i++)
{
int nDist = (pSprite->xrepeat*(tilesiz[pSprite->picnum].x/2))>>2;
int nAngle = Random(2048);
int x = pSprite->x + mulscale30(nDist, Cos(nAngle));
int y = pSprite->y + mulscale30(nDist, Sin(nAngle));
int z = bottom-Random(bottom-top);
spritetype *pFX = gFX.fxSpawn((FX_ID)(FX_23+Random(3)), pSprite->sectnum, x, y, z, 0);
if (pFX)
{
xvel[pFX->index] = xvel[nSprite] + Random2(0x1aaaa);
yvel[pFX->index] = yvel[nSprite] + Random2(0x1aaaa);
zvel[pFX->index] = zvel[nSprite] + Random2(0x1aaaa);
}
}
evPost(nSprite, 3, 4, CALLBACK_ID_11);
}
void CounterCheck(int nSector) // 12
{
dassert(nSector >= 0 && nSector < kMaxSectors);
sectortype *pSector = &sector[nSector];
// By NoOne: edits for counter sector new features.
// remove check below, so every sector can be counter if command 12 (this callback) received.
//if (pSector->lotag != 619) return;
int nXSprite = pSector->extra;
if (nXSprite > 0)
{
XSECTOR *pXSector = &xsector[nXSprite];
int nReq = pXSector->waitTimeA;
int nType = pXSector->data;
if (nType && nReq)
{
int nCount = 0;
for (int nSprite = headspritesect[nSector]; nSprite >= 0; nSprite = nextspritesect[nSprite])
{
if (sprite[nSprite].type == nType)
nCount++;
}
if (nCount >= nReq)
{
//pXSector->waitTimeA = 0; //do not reset necessary objects counter to zero
trTriggerSector(nSector, pXSector, 1);
pXSector->locked = 1; //lock sector, so it can be opened again later
}
else
evPost(nSector, 6, 5, CALLBACK_ID_12);
}
}
}
void sub_76140(int nSprite) // 14
{
spritetype *pSprite = &sprite[nSprite];
int ceilZ, ceilHit, floorZ, floorHit;
GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist, CLIPMASK0);
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
pSprite->z += floorZ-bottom;
int nAngle = Random(2048);
int nDist = Random(16)<<4;
int x = pSprite->x+mulscale28(nDist, Cos(nAngle));
int y = pSprite->y+mulscale28(nDist, Sin(nAngle));
gFX.fxSpawn(FX_48, pSprite->sectnum, x, y, pSprite->z, 0);
if (pSprite->ang == 1024)
{
int nChannel = 28+(pSprite->index&2);
dassert(nChannel < 32);
sfxPlay3DSound(pSprite, 385, nChannel, 1);
}
if (Chance(0x5000))
{
spritetype *pFX = gFX.fxSpawn(FX_36, pSprite->sectnum, x, y, floorZ-64, 0);
if (pFX)
pFX->ang = nAngle;
}
gFX.sub_73FFC(nSprite);
}
void sub_7632C(spritetype *pSprite)
{
xvel[pSprite->index] = yvel[pSprite->index] = zvel[pSprite->index] = 0;
if (pSprite->extra > 0)
seqKill(3, pSprite->extra);
sfxKill3DSound(pSprite, -1, -1);
switch (pSprite->type)
{
case 37:
case 38:
case 39:
pSprite->picnum = 2465;
break;
case 40:
case 41:
case 42:
pSprite->picnum = 2464;
break;
}
pSprite->type = 51;
pSprite->xrepeat = pSprite->yrepeat = 10;
}
int dword_13B32C[] = { 608, 609, 611 };
int dword_13B338[] = { 610, 612 };
void sub_763BC(int nSprite) // 16
{
spritetype *pSprite = &sprite[nSprite];
int ceilZ, ceilHit, floorZ, floorHit;
GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist, CLIPMASK0);
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
pSprite->z += floorZ-bottom;
int zv = zvel[nSprite]-velFloor[pSprite->sectnum];
if (zv > 0)
{
actFloorBounceVector((int*)&xvel[nSprite], (int*)&yvel[nSprite], &zv, pSprite->sectnum, 0x9000);
zvel[nSprite] = zv;
if (velFloor[pSprite->sectnum] == 0 && klabs(zvel[nSprite]) < 0x20000)
{
sub_7632C(pSprite);
return;
}
int nChannel = 28+(pSprite->index&2);
dassert(nChannel < 32);
if (pSprite->type >= 37 && pSprite->type <= 39)
{
Random(3);
sfxPlay3DSound(pSprite, 608+Random(2), nChannel, 1);
}
else
sfxPlay3DSound(pSprite, dword_13B338[Random(2)], nChannel, 1);
}
else if (zvel[nSprite] == 0)
sub_7632C(pSprite);
}
void sub_765B8(int nSprite) // 17
{
spritetype *pSprite = &sprite[nSprite];
if (pSprite->owner >= 0 && pSprite->owner < kMaxSprites)
{
spritetype *pOwner = &sprite[pSprite->owner];
XSPRITE *pXOwner = &xsprite[pOwner->extra];
switch (pSprite->type)
{
case 147:
trTriggerSprite(pOwner->index, pXOwner, 1);
sndStartSample(8003, 255, 2, 0);
viewSetMessage("Blue Flag returned to base.");
break;
case 148:
trTriggerSprite(pOwner->index, pXOwner, 1);
sndStartSample(8002, 255, 2, 0);
viewSetMessage("Red Flag returned to base.");
break;
}
}
evPost(pSprite->index, 3, 0, CALLBACK_ID_1);
}
void sub_766B8(int nSprite) // 19
{
spritetype *pSprite = &sprite[nSprite];
int ceilZ, ceilHit, floorZ, floorHit;
GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, pSprite->clipdist, CLIPMASK0);
int top, bottom;
GetSpriteExtents(pSprite, &top, &bottom);
pSprite->z += floorZ-bottom;
int nAngle = Random(2048);
int nDist = Random(16)<<4;
int x = pSprite->x+mulscale28(nDist, Cos(nAngle));
int y = pSprite->y+mulscale28(nDist, Sin(nAngle));
if (pSprite->ang == 1024)
{
int nChannel = 28+(pSprite->index&2);
dassert(nChannel < 32);
sfxPlay3DSound(pSprite, 385, nChannel, 1);
}
spritetype *pFX = NULL;
if (pSprite->type == 53 || pSprite->type == 430)
{
if (Chance(0x500) || pSprite->type == 430)
pFX = gFX.fxSpawn(FX_55, pSprite->sectnum, x, y, floorZ-64, 0);
if (pFX)
pFX->ang = nAngle;
}
else
{
pFX = gFX.fxSpawn(FX_32, pSprite->sectnum, x, y, floorZ-64, 0);
if (pFX)
pFX->ang = nAngle;
}
gFX.sub_73FFC(nSprite);
}
void sub_768E8(int nSprite) // 18
{
spritetype *pSprite = &sprite[nSprite];
spritetype *pFX;
if (pSprite->type == 53)
pFX = gFX.fxSpawn(FX_53, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
else
pFX = gFX.fxSpawn(FX_54, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, 0);
if (pFX)
{
pFX->ang = 0;
xvel[pFX->index] = xvel[nSprite]>>8;
yvel[pFX->index] = yvel[nSprite]>>8;
zvel[pFX->index] = zvel[nSprite]>>8;
}
evPost(nSprite, 3, 6, CALLBACK_ID_18);
}
void sub_769B4(int nSprite) // 19
{
spritetype *pSprite = &sprite[nSprite];
if (pSprite->statnum == 4 && !(pSprite->hitag & 32)) {
switch (pSprite->lotag) {
case 431:
case kGDXThingCustomDudeLifeLeech:
xsprite[pSprite->extra].stateTimer = 0;
break;
}
}
}
void sub_76A08(spritetype *pSprite, spritetype *pSprite2, PLAYER *pPlayer)
{
int top, bottom;
int nSprite = pSprite->index;
GetSpriteExtents(pSprite, &top, &bottom);
pSprite->x = pSprite2->x;
pSprite->y = pSprite2->y;
pSprite->z = sector[pSprite2->sectnum].floorz-(bottom-pSprite->z);
pSprite->ang = pSprite2->ang;
ChangeSpriteSect(nSprite, pSprite2->sectnum);
sfxPlay3DSound(pSprite2, 201, -1, 0);
xvel[nSprite] = yvel[nSprite] = zvel[nSprite] = 0;
viewBackupSpriteLoc(nSprite, pSprite);
if (pPlayer)
{
playerResetInertia(pPlayer);
pPlayer->at6b = pPlayer->at73 = 0;
}
}
void sub_76B78(int nSprite)
{
spritetype *pSprite = &sprite[nSprite];
int nOwner = actSpriteOwnerToSpriteId(pSprite);
if (nOwner < 0 || nOwner >= kMaxSprites)
{
evPost(nSprite, 3, 0, CALLBACK_ID_1);
return;
}
spritetype *pOwner = &sprite[nOwner];
PLAYER *pPlayer;
if (IsPlayerSprite(pOwner))
pPlayer = &gPlayer[pOwner->type-kDudePlayer1];
else
pPlayer = NULL;
if (!pPlayer)
{
evPost(nSprite, 3, 0, CALLBACK_ID_1);
return;
}
pSprite->ang = getangle(pOwner->x-pSprite->x, pOwner->y-pSprite->y);
int nXSprite = pSprite->extra;
if (nXSprite > 0)
{
XSPRITE *pXSprite = &xsprite[nXSprite];
if (pXSprite->data1 == 0)
{
evPost(nSprite, 3, 0, CALLBACK_ID_1);
return;
}
int nSprite2, nNextSprite;
for (nSprite2 = headspritestat[6]; nSprite2 >= 0; nSprite2 = nNextSprite)
{
nNextSprite = nextspritestat[nSprite2];
if (nOwner == nSprite2)
continue;
spritetype *pSprite2 = &sprite[nSprite2];
int nXSprite2 = pSprite2->extra;
if (nXSprite2 > 0 && nXSprite2 < kMaxXSprites)
{
XSPRITE *pXSprite2 = &xsprite[nXSprite2];
PLAYER *pPlayer2;
if (IsPlayerSprite(pSprite2))
pPlayer2 = &gPlayer[pSprite2->type-kDudePlayer1];
else
pPlayer2 = NULL;
if (pXSprite2->health > 0 && (pPlayer2 || pXSprite2->key == 0))
{
if (pPlayer2)
{
if (gGameOptions.nGameType == 1)
continue;
if (gGameOptions.nGameType == 3 && pPlayer->at2ea == pPlayer2->at2ea)
continue;
int t = 0x8000/ClipLow(gNetPlayers-1, 1);
if (!powerupCheck(pPlayer2, 14))
t += ((3200-pPlayer2->at33e[2])<<15)/3200;
if (Chance(t) || nNextSprite < 0)
{
int nDmg = actDamageSprite(nOwner, pSprite2, DAMAGE_TYPE_5, pXSprite->data1<<4);
pXSprite->data1 = ClipLow(pXSprite->data1-nDmg, 0);
sub_76A08(pSprite2, pSprite, pPlayer2);
evPost(nSprite, 3, 0, CALLBACK_ID_1);
return;
}
}
else
{
int vd = 0x2666;
switch (pSprite2->type)
{
case 218:
case 219:
case 220:
case 250:
case 251:
vd = 0x147;
break;
case 205:
case 221:
case 222:
case 223:
case 224:
case 225:
case 226:
case 227:
case 228:
case 229:
case 239:
case 240:
case 241:
case 242:
case 243:
case 244:
case 245:
case 252:
case 253:
vd = 0;
break;
}
if (vd && (Chance(vd) || nNextSprite < 0))
{
sub_76A08(pSprite2, pSprite, NULL);
evPost(nSprite, 3, 0, CALLBACK_ID_1);
return;
}
}
}
}
}
pXSprite->data1 = ClipLow(pXSprite->data1-1, 0);
evPost(nSprite, 3, 0, CALLBACK_ID_1);
}
}
void(*gCallback[kCallbackMax])(int) =
{
FlameLick,
Remove,
FlareBurst,
FlareSpark,
FlareSparkLite,
ZombieSpurt,
BloodSpurt,
sub_74C20,
DynPuff,
Respawn,
PlayerBubble,
EnemyBubble,
CounterCheck,
FinishHim,
sub_76140,
sub_74D04,
sub_763BC,
sub_765B8,
sub_768E8,
sub_766B8,
sub_769B4,
sub_76B78
};

View file

@ -0,0 +1,53 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
enum CALLBACK_ID {
CALLBACK_ID_NONE = -1,
CALLBACK_ID_0 = 0,
CALLBACK_ID_1,
CALLBACK_ID_2,
CALLBACK_ID_3,
CALLBACK_ID_4,
CALLBACK_ID_5,
CALLBACK_ID_6,
CALLBACK_ID_7,
CALLBACK_ID_8,
CALLBACK_ID_9,
CALLBACK_ID_10,
CALLBACK_ID_11,
CALLBACK_ID_12,
CALLBACK_ID_13,
CALLBACK_ID_14,
CALLBACK_ID_15,
CALLBACK_ID_16,
CALLBACK_ID_17,
CALLBACK_ID_18,
CALLBACK_ID_19,
CALLBACK_ID_20,
CALLBACK_ID_21,
kCallbackMax
};
extern void (*gCallback[kCallbackMax])(int);

136
source/blood/src/choke.cpp Normal file
View file

@ -0,0 +1,136 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "build.h"
#include "compat.h"
#include "common_game.h"
#include "blood.h"
#include "choke.h"
#include "globals.h"
#include "levels.h"
#include "player.h"
#include "qav.h"
#include "resource.h"
void CChoke::sub_83F54(char *a1, int _x, int _y, void (*a2)(PLAYER*))
{
at14 = _x;
at18 = _y;
at0 = a1;
at1c = a2;
if (!at4 && at0)
{
at4 = gSysRes.Lookup(at0, "QAV");
if (!at4)
ThrowError("Could not load QAV %s\n", at0);
at8 = (QAV*)gSysRes.Lock(at4);
at8->nSprite = -1;
at8->x = at14;
at8->y = at18;
at8->Preload();
sub_84218();
}
}
void CChoke::sub_83ff0(int a1, void(*a2)(PLAYER*))
{
at0 = NULL;
at1c = a2;
if (!at4 && a1 != -1)
{
at4 = gSysRes.Lookup(a1, "QAV");
if (!at4)
ThrowError("Could not load QAV %d\n", a1);
at8 = (QAV*)gSysRes.Lock(at4);
at8->nSprite = -1;
at8->x = at14;
at8->y = at18;
at8->Preload();
sub_84218();
}
}
void CChoke::sub_84080(char *a1, void(*a2)(PLAYER*))
{
at0 = a1;
at1c = a2;
if (!at4 && at0)
{
at4 = gSysRes.Lookup(at0, "QAV");
if (!at4)
ThrowError("Could not load QAV %s\n", at0);
at8 = (QAV*)gSysRes.Lock(at4);
at8->nSprite = -1;
at8->x = at14;
at8->y = at18;
at8->Preload();
sub_84218();
}
}
void CChoke::sub_84110(int x, int y)
{
if (!at4)
return;
int v4 = gFrameClock;
gFrameClock = gGameClock;
at8->x = x;
at8->y = y;
int vd = totalclock-at10;
at10 = totalclock;
atc -= vd;
if (atc <= 0 || atc > at8->at10)
atc = at8->at10;
int vdi = at8->at10-atc;
at8->Play(vdi-vd, vdi, -1, NULL);
int vb = windowxy1.x;
int v10 = windowxy1.y;
int vc = windowxy2.x;
int v8 = windowxy2.y;
windowxy1.x = windowxy1.y = 0;
windowxy2.x = xdim-1;
windowxy2.y = ydim-1;
at8->Draw(vdi, 10, 0, 0);
windowxy1.x = vb;
windowxy1.y = v10;
windowxy2.x = vc;
windowxy2.y = v8;
gFrameClock = v4;
}
void CChoke::sub_84218()
{
atc = at8->at10;
at10 = totalclock;
}
void sub_84230(PLAYER *pPlayer)
{
int t = gGameOptions.nDifficulty+2;
if (pPlayer->at372 < 64)
pPlayer->at372 = ClipHigh(pPlayer->at372+t, 64);
if (pPlayer->at372 > (7-gGameOptions.nDifficulty)*5)
pPlayer->at36a = ClipHigh(pPlayer->at36a+t*4, 128);
}
CChoke gChoke;

61
source/blood/src/choke.h Normal file
View file

@ -0,0 +1,61 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "common_game.h"
#include "player.h"
#include "qav.h"
#include "resource.h"
class CChoke
{
public:
CChoke()
{
at0 = NULL;
at4 = NULL;
at8 = NULL;
atc = 0;
at10 = 0;
at1c = NULL;
at14 = 0;
at18 = 0;
};
void sub_83F54(char *a1, int _x, int _y, void(*a2)(PLAYER*));
void sub_83ff0(int a1, void(*a2)(PLAYER*));
void sub_84080(char *a1, void(*a2)(PLAYER*));
void sub_84110(int x, int y);
void sub_84218();
char *at0;
DICTNODE *at4;
QAV *at8;
int atc;
int at10;
int at14;
int at18;
void(*at1c)(PLAYER *);
};
void sub_84230(PLAYER*);
extern CChoke gChoke;

748
source/blood/src/common.cpp Normal file
View file

@ -0,0 +1,748 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
//
// Common non-engine code/data for EDuke32 and Mapster32
//
#include "compat.h"
#include "build.h"
#include "baselayer.h"
#include "palette.h"
#ifdef _WIN32
# define NEED_SHLWAPI_H
# include "windows_inc.h"
# include "winbits.h"
# ifndef KEY_WOW64_64KEY
# define KEY_WOW64_64KEY 0x0100
# endif
# ifndef KEY_WOW64_32KEY
# define KEY_WOW64_32KEY 0x0200
# endif
#elif defined __APPLE__
# include "osxbits.h"
#endif
#include "common.h"
#include "common_game.h"
// g_grpNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
char *g_grpNamePtr = NULL;
const char *G_DefaultGrpFile(void)
{
return "nblood.pk3";
}
const char *G_DefaultDefFile(void)
{
return "blood.def";
}
const char *G_GrpFile(void)
{
return (g_grpNamePtr == NULL) ? G_DefaultGrpFile() : g_grpNamePtr;
}
const char *G_DefFile(void)
{
return (g_defNamePtr == NULL) ? G_DefaultDefFile() : g_defNamePtr;
}
static char g_rootDir[BMAX_PATH];
int g_useCwd;
int32_t g_groupFileHandle;
void G_ExtPreInit(int32_t argc,char const * const * argv)
{
g_useCwd = G_CheckCmdSwitch(argc, argv, "-usecwd");
#ifdef _WIN32
GetModuleFileName(NULL,g_rootDir,BMAX_PATH);
Bcorrectfilename(g_rootDir,1);
//chdir(g_rootDir);
#else
getcwd(g_rootDir,BMAX_PATH);
strcat(g_rootDir,"/");
#endif
}
void G_ExtInit(void)
{
char cwd[BMAX_PATH];
#ifdef EDUKE32_OSX
char *appdir = Bgetappdir();
addsearchpath(appdir);
Bfree(appdir);
#endif
if (getcwd(cwd,BMAX_PATH) && Bstrcmp(cwd,"/") != 0)
addsearchpath(cwd);
if (CommandPaths)
{
int32_t i;
struct strllist *s;
while (CommandPaths)
{
s = CommandPaths->next;
i = addsearchpath(CommandPaths->str);
if (i < 0)
{
initprintf("Failed adding %s for game data: %s\n", CommandPaths->str,
i==-1 ? "not a directory" : "no such directory");
}
Bfree(CommandPaths->str);
Bfree(CommandPaths);
CommandPaths = s;
}
}
#if defined(_WIN32)
if (!access("user_profiles_enabled", F_OK))
#else
if (g_useCwd == 0 && access("user_profiles_disabled", F_OK))
#endif
{
char *homedir;
int32_t asperr;
if ((homedir = Bgethomedir()))
{
Bsnprintf(cwd,sizeof(cwd),"%s/"
#if defined(_WIN32)
APPNAME
#elif defined(GEKKO)
"apps/" APPBASENAME
#else
".config/" APPBASENAME
#endif
,homedir);
asperr = addsearchpath(cwd);
if (asperr == -2)
{
if (Bmkdir(cwd,S_IRWXU) == 0) asperr = addsearchpath(cwd);
else asperr = -1;
}
if (asperr == 0)
Bchdir(cwd);
Bfree(homedir);
}
}
}
static int32_t G_TryLoadingGrp(char const * const grpfile)
{
int32_t i;
if ((i = initgroupfile(grpfile)) == -1)
initprintf("Warning: could not find main data file \"%s\"!\n", grpfile);
else
initprintf("Using \"%s\" as main game data file.\n", grpfile);
return i;
}
void G_LoadGroups(int32_t autoload)
{
if (g_modDir[0] != '/')
{
char cwd[BMAX_PATH];
Bstrcat(g_rootDir, g_modDir);
addsearchpath(g_rootDir);
// addsearchpath(mod_dir);
char path[BMAX_PATH];
if (getcwd(cwd, BMAX_PATH))
{
Bsnprintf(path, sizeof(path), "%s/%s", cwd, g_modDir);
if (!Bstrcmp(g_rootDir, path))
{
if (addsearchpath(path) == -2)
if (Bmkdir(path, S_IRWXU) == 0)
addsearchpath(path);
}
}
}
const char *grpfile = G_GrpFile();
G_TryLoadingGrp(grpfile);
if (autoload)
{
G_LoadGroupsInDir("autoload");
//if (i != -1)
// G_DoAutoload(grpfile);
}
if (g_modDir[0] != '/')
G_LoadGroupsInDir(g_modDir);
if (g_defNamePtr == NULL)
{
const char *tmpptr = getenv("BLOODDEF");
if (tmpptr)
{
clearDefNamePtr();
g_defNamePtr = dup_filename(tmpptr);
initprintf("Using \"%s\" as definitions file\n", g_defNamePtr);
}
}
loaddefinitions_game(G_DefFile(), TRUE);
struct strllist *s;
int const bakpathsearchmode = pathsearchmode;
pathsearchmode = 1;
while (CommandGrps)
{
int32_t j;
s = CommandGrps->next;
if ((j = initgroupfile(CommandGrps->str)) == -1)
initprintf("Could not find file \"%s\".\n", CommandGrps->str);
else
{
g_groupFileHandle = j;
initprintf("Using file \"%s\" as game data.\n", CommandGrps->str);
if (autoload)
G_DoAutoload(CommandGrps->str);
}
Bfree(CommandGrps->str);
Bfree(CommandGrps);
CommandGrps = s;
}
pathsearchmode = bakpathsearchmode;
}
#if defined _WIN32
static int G_ReadRegistryValue(char const * const SubKey, char const * const Value, char * const Output, DWORD * OutputSize)
{
// KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds
REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY };
for (auto &wow64key : wow64keys)
{
HKEY hkey;
LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey);
if (keygood != ERROR_SUCCESS)
continue;
LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize);
RegCloseKey(hkey);
if (retval == ERROR_SUCCESS)
return 1;
}
return 0;
}
#endif
#ifndef EDUKE32_TOUCH_DEVICES
#if defined EDUKE32_OSX || defined __linux__ || defined EDUKE32_BSD
static void G_AddSteamPaths(const char *basepath)
{
UNREFERENCED_PARAMETER(basepath);
#if 0
char buf[BMAX_PATH];
// PORT-TODO:
// Duke Nukem 3D: Megaton Edition (Steam)
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot", basepath);
addsearchpath(buf);
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/dc", basepath);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/nw", basepath);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/vacation", basepath);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
// Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015)
#if defined EDUKE32_OSX
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/Duke Nukem 3D.app/drive_c/Program Files/Duke Nukem 3D", basepath);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
#endif
#endif
}
// A bare-bones "parser" for Valve's KeyValues VDF format.
// There is no guarantee this will function properly with ill-formed files.
static void KeyValues_SkipWhitespace(char **vdfbuf, char * const vdfbufend)
{
while (((*vdfbuf)[0] == ' ' || (*vdfbuf)[0] == '\n' || (*vdfbuf)[0] == '\r' || (*vdfbuf)[0] == '\t' || (*vdfbuf)[0] == '\0') && *vdfbuf < vdfbufend)
(*vdfbuf)++;
// comments
if ((*vdfbuf) + 2 < vdfbufend && (*vdfbuf)[0] == '/' && (*vdfbuf)[1] == '/')
{
while ((*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && *vdfbuf < vdfbufend)
(*vdfbuf)++;
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
}
}
static void KeyValues_SkipToEndOfQuotedToken(char **vdfbuf, char * const vdfbufend)
{
(*vdfbuf)++;
while ((*vdfbuf)[0] != '\"' && (*vdfbuf)[-1] != '\\' && *vdfbuf < vdfbufend)
(*vdfbuf)++;
}
static void KeyValues_SkipToEndOfUnquotedToken(char **vdfbuf, char * const vdfbufend)
{
while ((*vdfbuf)[0] != ' ' && (*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && (*vdfbuf)[0] != '\t' && (*vdfbuf)[0] != '\0' && *vdfbuf < vdfbufend)
(*vdfbuf)++;
}
static void KeyValues_SkipNextWhatever(char **vdfbuf, char * const vdfbufend)
{
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
if (*vdfbuf == vdfbufend)
return;
if ((*vdfbuf)[0] == '{')
{
(*vdfbuf)++;
do
{
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
}
while ((*vdfbuf)[0] != '}');
(*vdfbuf)++;
}
else if ((*vdfbuf)[0] == '\"')
KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend);
else if ((*vdfbuf)[0] != '}')
KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend);
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
}
static char* KeyValues_NormalizeToken(char **vdfbuf, char * const vdfbufend)
{
char *token = *vdfbuf;
if ((*vdfbuf)[0] == '\"' && *vdfbuf < vdfbufend)
{
token++;
KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend);
(*vdfbuf)[0] = '\0';
// account for escape sequences
char *writeseeker = token, *readseeker = token;
while (readseeker <= *vdfbuf)
{
if (readseeker[0] == '\\')
readseeker++;
writeseeker[0] = readseeker[0];
writeseeker++;
readseeker++;
}
return token;
}
KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend);
(*vdfbuf)[0] = '\0';
return token;
}
static void KeyValues_FindKey(char **vdfbuf, char * const vdfbufend, const char *token)
{
char *ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend);
if (token != NULL) // pass in NULL to find the next key instead of a specific one
while (Bstrcmp(ParentKey, token) != 0 && *vdfbuf < vdfbufend)
{
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend);
}
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
}
static int32_t KeyValues_FindParentKey(char **vdfbuf, char * const vdfbufend, const char *token)
{
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
// end of scope
if ((*vdfbuf)[0] == '}')
return 0;
KeyValues_FindKey(vdfbuf, vdfbufend, token);
// ignore the wrong type
while ((*vdfbuf)[0] != '{' && *vdfbuf < vdfbufend)
{
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
KeyValues_FindKey(vdfbuf, vdfbufend, token);
}
if (*vdfbuf == vdfbufend)
return 0;
return 1;
}
static char* KeyValues_FindKeyValue(char **vdfbuf, char * const vdfbufend, const char *token)
{
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
// end of scope
if ((*vdfbuf)[0] == '}')
return NULL;
KeyValues_FindKey(vdfbuf, vdfbufend, token);
// ignore the wrong type
while ((*vdfbuf)[0] == '{' && *vdfbuf < vdfbufend)
{
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
KeyValues_FindKey(vdfbuf, vdfbufend, token);
}
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
if (*vdfbuf == vdfbufend)
return NULL;
return KeyValues_NormalizeToken(vdfbuf, vdfbufend);
}
static void G_ParseSteamKeyValuesForPaths(const char *vdf)
{
int32_t fd = Bopen(vdf, BO_RDONLY);
int32_t size = Bfilelength(fd);
char *vdfbufstart, *vdfbuf, *vdfbufend;
if (size <= 0)
return;
vdfbufstart = vdfbuf = (char*)Xmalloc(size);
size = (int32_t)Bread(fd, vdfbuf, size);
Bclose(fd);
vdfbufend = vdfbuf + size;
if (KeyValues_FindParentKey(&vdfbuf, vdfbufend, "LibraryFolders"))
{
char *result;
vdfbuf++;
while ((result = KeyValues_FindKeyValue(&vdfbuf, vdfbufend, NULL)) != NULL)
G_AddSteamPaths(result);
}
Bfree(vdfbufstart);
}
#endif
#endif
void G_AddSearchPaths(void)
{
#ifndef EDUKE32_TOUCH_DEVICES
#if defined __linux__ || defined EDUKE32_BSD
char buf[BMAX_PATH];
char *homepath = Bgethomedir();
Bsnprintf(buf, sizeof(buf), "%s/.steam/steam", homepath);
G_AddSteamPaths(buf);
Bsnprintf(buf, sizeof(buf), "%s/.steam/steam/steamapps/libraryfolders.vdf", homepath);
G_ParseSteamKeyValuesForPaths(buf);
Bfree(homepath);
addsearchpath("/usr/share/games/nblood");
addsearchpath("/usr/local/share/games/nblood");
#elif defined EDUKE32_OSX
char buf[BMAX_PATH];
int32_t i;
char *applications[] = { osx_getapplicationsdir(0), osx_getapplicationsdir(1) };
char *support[] = { osx_getsupportdir(0), osx_getsupportdir(1) };
for (i = 0; i < 2; i++)
{
Bsnprintf(buf, sizeof(buf), "%s/Steam", support[i]);
G_AddSteamPaths(buf);
Bsnprintf(buf, sizeof(buf), "%s/Steam/steamapps/libraryfolders.vdf", support[i]);
G_ParseSteamKeyValuesForPaths(buf);
#if 0
// Duke Nukem 3D: Atomic Edition (GOG.com)
Bsnprintf(buf, sizeof(buf), "%s/Duke Nukem 3D.app/Contents/Resources/Duke Nukem 3D.boxer/C.harddisk", applications[i]);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
#endif
}
for (i = 0; i < 2; i++)
{
Bsnprintf(buf, sizeof(buf), "%s/NBlood", support[i]);
addsearchpath(buf);
}
for (i = 0; i < 2; i++)
{
Bfree(applications[i]);
Bfree(support[i]);
}
#elif defined (_WIN32)
char buf[BMAX_PATH] = {0};
DWORD bufsize;
bool found = false;
// Blood: One Unit Whole Blood (Steam)
bufsize = sizeof(buf);
if (!found && G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 299030)", "InstallLocation", buf, &bufsize))
{
addsearchpath_user(buf, SEARCHPATH_REMOVE);
found = true;
}
// Blood: One Unit Whole Blood (GOG.com)
bufsize = sizeof(buf);
if (!found && G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGONEUNITONEBLOOD", "PATH", buf, &bufsize))
{
addsearchpath_user(buf, SEARCHPATH_REMOVE);
found = true;
}
// Blood: Fresh Supply (Steam)
bufsize = sizeof(buf);
if (!found && G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 1010750)", "InstallLocation", buf, &bufsize))
{
addsearchpath_user(buf, SEARCHPATH_REMOVE);
strncat(buf, R"(\addons\Cryptic Passage)", 23);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
found = true;
}
// Blood: Fresh Supply (GOG.com)
bufsize = sizeof(buf);
if (!found && G_ReadRegistryValue(R"(SOFTWARE\Wow6432Node\GOG.com\Games\1374469660)", "path", buf, &bufsize))
{
addsearchpath_user(buf, SEARCHPATH_REMOVE);
strncat(buf, R"(\addons\Cryptic Passage)", 23);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
found = true;
}
#endif
#endif
}
void G_CleanupSearchPaths(void)
{
removesearchpaths_withuser(SEARCHPATH_REMOVE);
}
//////////
struct strllist *CommandPaths, *CommandGrps;
void G_AddGroup(const char *buffer)
{
char buf[BMAX_PATH];
struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
Bstrcpy(buf, buffer);
if (Bstrchr(buf,'.') == 0)
Bstrcat(buf,".grp");
s->str = Xstrdup(buf);
if (CommandGrps)
{
struct strllist *t;
for (t = CommandGrps; t->next; t=t->next) ;
t->next = s;
return;
}
CommandGrps = s;
}
void G_AddPath(const char *buffer)
{
struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
s->str = Xstrdup(buffer);
if (CommandPaths)
{
struct strllist *t;
for (t = CommandPaths; t->next; t=t->next) ;
t->next = s;
return;
}
CommandPaths = s;
}
//////////
// loads all group (grp, zip, pk3/4) files in the given directory
void G_LoadGroupsInDir(const char *dirname)
{
static const char *extensions[] = { "*.grp", "*.zip", "*.ssi", "*.pk3", "*.pk4" };
char buf[BMAX_PATH];
fnlist_t fnlist = FNLIST_INITIALIZER;
for (auto & extension : extensions)
{
CACHE1D_FIND_REC *rec;
fnlist_getnames(&fnlist, dirname, extension, -1, 0);
for (rec=fnlist.findfiles; rec; rec=rec->next)
{
Bsnprintf(buf, sizeof(buf), "%s/%s", dirname, rec->name);
initprintf("Using group file \"%s\".\n", buf);
initgroupfile(buf);
}
fnlist_clearnames(&fnlist);
}
}
void G_DoAutoload(const char *dirname)
{
char buf[BMAX_PATH];
Bsnprintf(buf, sizeof(buf), "autoload/%s", dirname);
G_LoadGroupsInDir(buf);
}
//////////
#ifdef FORMAT_UPGRADE_ELIGIBLE
static int32_t S_TryFormats(char * const testfn, char * const fn_suffix, char const searchfirst)
{
#ifdef HAVE_FLAC
{
Bstrcpy(fn_suffix, ".flac");
int32_t const fp = kopen4loadfrommod(testfn, searchfirst);
if (fp >= 0)
return fp;
}
#endif
#ifdef HAVE_VORBIS
{
Bstrcpy(fn_suffix, ".ogg");
int32_t const fp = kopen4loadfrommod(testfn, searchfirst);
if (fp >= 0)
return fp;
}
#endif
return -1;
}
static int32_t S_TryExtensionReplacements(char * const testfn, char const searchfirst, uint8_t const ismusic)
{
char * extension = Bstrrchr(testfn, '.');
char * const fn_end = Bstrchr(testfn, '\0');
// ex: grabbag.voc --> grabbag_voc.*
if (extension != NULL)
{
*extension = '_';
int32_t const fp = S_TryFormats(testfn, fn_end, searchfirst);
if (fp >= 0)
return fp;
}
else
{
extension = fn_end;
}
// ex: grabbag.mid --> grabbag.*
if (ismusic)
{
int32_t const fp = S_TryFormats(testfn, extension, searchfirst);
if (fp >= 0)
return fp;
}
return -1;
}
int32_t S_OpenAudio(const char *fn, char searchfirst, uint8_t const ismusic)
{
int32_t const origfp = kopen4loadfrommod(fn, searchfirst);
char const *const origparent = origfp != -1 ? kfileparent(origfp) : NULL;
uint32_t const parentlength = origparent != NULL ? Bstrlen(origparent) : 0;
auto testfn = (char *)Xmalloc(Bstrlen(fn) + 12 + parentlength); // "music/" + overestimation of parent minus extension + ".flac" + '\0'
// look in ./
// ex: ./grabbag.mid
Bstrcpy(testfn, fn);
int32_t fp = S_TryExtensionReplacements(testfn, searchfirst, ismusic);
if (fp >= 0)
goto success;
// look in ./music/<file's parent GRP name>/
// ex: ./music/duke3d/grabbag.mid
// ex: ./music/nwinter/grabbag.mid
if (origparent != NULL)
{
char const * const parentextension = Bstrrchr(origparent, '.');
uint32_t const namelength = parentextension != NULL ? (unsigned)(parentextension - origparent) : parentlength;
Bsprintf(testfn, "music/%.*s/%s", namelength, origparent, fn);
fp = S_TryExtensionReplacements(testfn, searchfirst, ismusic);
if (fp >= 0)
goto success;
}
// look in ./music/
// ex: ./music/grabbag.mid
Bsprintf(testfn, "music/%s", fn);
fp = S_TryExtensionReplacements(testfn, searchfirst, ismusic);
if (fp >= 0)
goto success;
fp = origfp;
success:
Bfree(testfn);
if (fp != origfp)
kclose(origfp);
return fp;
}
#endif

View file

@ -0,0 +1,499 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "baselayer.h"
#include "build.h"
#include "cache1d.h"
#include "common.h"
#include "pragmas.h"
#include "misc.h"
#include "network.h"
extern int g_useCwd;
#ifndef APPNAME
#define APPNAME "NBlood"
#endif
#ifndef APPBASENAME
#define APPBASENAME "nblood"
#endif
#define BYTEVERSION 102
#define EXEVERSION 101
void _SetErrorLoc(const char *pzFile, int nLine);
void _ThrowError(const char *pzFormat, ...);
void __dassert(const char *pzExpr, const char *pzFile, int nLine);
#define ThrowError(...) \
{ \
_SetErrorLoc(__FILE__,__LINE__); \
_ThrowError(__VA_ARGS__); \
}
#define dassert(x) if (!(x)) __dassert(#x,__FILE__,__LINE__)
#define kMaxSectors 1024
#define kMaxWalls 8192
#define kMaxSprites 4096
#define kMaxTiles MAXTILES
#define kMaxStatus MAXSTATUS
#define kMaxPlayers 8
#define kMaxViewSprites maxspritesonscreen
#define kMaxVoxels MAXVOXELS
#define kTicRate 120
#define kTicsPerFrame 4
#define kTicsPerSec (kTicRate/kTicsPerFrame)
// NUKE-TODO:
#define OSDTEXT_DEFAULT "^00"
#define OSDTEXT_DARKRED "^00"
#define OSDTEXT_GREEN "^00"
#define OSDTEXT_RED "^00"
#define OSDTEXT_YELLOW "^00"
#define OSDTEXT_BRIGHT "^S0"
#define OSD_ERROR OSDTEXT_DARKRED OSDTEXT_BRIGHT
enum BLOOD_GLOBALFLAGS {
BLOOD_FORCE_WIDELOADSCREEN = 1<<0,
};
enum searchpathtypes_t {
SEARCHPATH_REMOVE = 1<<0,
};
extern char *g_grpNamePtr;
extern int loaddefinitions_game(const char *fn, int32_t preload);
extern void G_AddSearchPaths(void);
extern void G_CleanupSearchPaths(void);
extern void G_ExtPreInit(int32_t argc, char const * const * argv);
extern void G_ExtInit(void);
void G_LoadGroupsInDir(const char *dirname);
void G_DoAutoload(const char *dirname);
extern void G_LoadGroups(int32_t autoload);
#define G_ModDirSnprintf(buf, size, basename, ...) \
(((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/" basename, g_modDir, ##__VA_ARGS__) : Bsnprintf(buf, size, basename, ##__VA_ARGS__)) \
>= ((int32_t)size) - 1)
#define G_ModDirSnprintfLite(buf, size, basename) \
((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/%s", g_modDir, basename) : Bsnprintf(buf, size, "%s", basename))
static inline void G_HandleAsync(void)
{
handleevents();
netGetPackets();
}
#if defined HAVE_FLAC || defined HAVE_VORBIS
# define FORMAT_UPGRADE_ELIGIBLE
extern int32_t S_OpenAudio(const char *fn, char searchfirst, uint8_t ismusic);
#else
# define S_OpenAudio(fn, searchfirst, ismusic) kopen4loadfrommod(fn, searchfirst)
#endif
#pragma pack(push,1)
#if 0
struct sectortype
{
short wallptr, wallnum;
int ceilingz, floorz;
unsigned short ceilingstat, floorstat;
short ceilingpicnum, ceilingheinum;
signed char ceilingshade;
char ceilingpal, ceilingxpanning, ceilingypanning;
short floorpicnum, floorheinum;
signed char floorshade;
char floorpal, floorxpanning, floorypanning;
char visibility, filler;
unsigned short lotag;
short hitag, extra;
};
struct walltype
{
int x, y;
short point2, nextwall, nextsector;
unsigned short cstat;
short picnum, overpicnum;
signed char shade;
char pal, xrepeat, yrepeat, xpanning, ypanning;
short lotag, hitag, extra;
};
struct spritetype
{
int x, y, z;
short cstat, picnum;
signed char shade;
char pal, clipdist, filler;
unsigned char xrepeat, yrepeat;
signed char xoffset, yoffset;
short sectnum, statnum;
short ang, owner, index, yvel, zvel;
short type, hitag, extra;
};
struct PICANM {
unsigned int animframes : 5;
unsigned int at0_5 : 1;
unsigned int animtype : 2;
signed int xoffset : 8;
signed int yoffset : 8;
unsigned int animspeed : 4;
unsigned int at3_4 : 3; // type
unsigned int at3_7 : 1; // filler
};
#endif
struct LOCATION {
int x, y, z;
int ang;
};
struct POINT2D {
int x, y;
};
struct POINT3D {
int x, y, z;
};
struct VECTOR2D {
int dx, dy;
};
struct Aim {
int dx, dy, dz;
};
#pragma pack(pop)
extern char qsprite_filler[], qsector_filler[];
inline int ksgnf(float f)
{
if (f < 0)
return -1;
if (f > 0)
return 1;
return 0;
}
inline int IncBy(int a, int b)
{
a += b;
int q = a % b;
a -= q;
if (q < 0)
a -= b;
return a;
}
inline int DecBy(int a, int b)
{
a--;
int q = a % b;
a -= q;
if (q < 0)
a -= b;
return a;
}
#if 0
inline float IncByF(float a, float b)
{
a += b;
float q = fmod(a, b);
a -= q;
if (q < 0)
a -= b;
return a;
}
inline float DecByF(float a, float b)
{
//a--;
a -= fabs(b)*0.001;
float q = fmod(a, b);
a -= q;
if (q < 0)
a -= b;
return a;
}
#endif
inline int ClipLow(int a, int b)
{
if (a < b)
return b;
return a;
}
inline int ClipHigh(int a, int b)
{
if (a >= b)
return b;
return a;
}
inline int ClipRange(int a, int b, int c)
{
if (a < b)
return b;
if (a > c)
return c;
return a;
}
inline float ClipRangeF(float a, float b, float c)
{
if (a < b)
return b;
if (a > c)
return c;
return a;
}
inline int interpolate(int a, int b, int c)
{
return a+mulscale16(b-a,c);
}
inline int interpolateang(int a, int b, int c)
{
return a+mulscale16(((b-a+1024)&2047)-1024, c);
}
inline fix16_t interpolateangfix16(fix16_t a, fix16_t b, int c)
{
return a+mulscale16(((b-a+0x4000000)&0x7ffffff)-0x4000000, c);
}
inline char Chance(int a1)
{
return wrand() < (a1>>1);
}
inline unsigned int Random(int a1)
{
return mulscale(wrand(), a1, 15);
}
inline int Random2(int a1)
{
return mulscale(wrand(), a1, 14)-a1;
}
inline int Random3(int a1)
{
return mulscale(wrand()+wrand(), a1, 15) - a1;
}
inline unsigned int QRandom(int a1)
{
return mulscale(qrand(), a1, 15);
}
inline int QRandom2(int a1)
{
return mulscale(qrand(), a1, 14)-a1;
}
inline void SetBitString(char *pArray, int nIndex)
{
pArray[nIndex>>3] |= 1<<(nIndex&7);
}
inline void ClearBitString(char *pArray, int nIndex)
{
pArray[nIndex >> 3] &= ~(1 << (nIndex & 7));
}
inline char TestBitString(char *pArray, int nIndex)
{
return pArray[nIndex>>3] & (1<<(nIndex&7));
}
inline int scale(int a1, int a2, int a3, int a4, int a5)
{
return a4 + (a5-a4) * (a1-a2) / (a3-a2);
}
inline int mulscale16r(int a, int b)
{
int64_t acc = 1<<(16-1);
acc += ((int64_t)a) * b;
return (int)(acc>>16);
}
inline int mulscale30r(int a, int b)
{
int64_t acc = 1<<(30-1);
acc += ((int64_t)a) * b;
return (int)(acc>>30);
}
inline int dmulscale30r(int a, int b, int c, int d)
{
int64_t acc = 1<<(30-1);
acc += ((int64_t)a) * b;
acc += ((int64_t)c) * d;
return (int)(acc>>30);
}
inline int approxDist(int dx, int dy)
{
dx = klabs(dx);
dy = klabs(dy);
if (dx > dy)
dy = (3*dy)>>3;
else
dx = (3*dx)>>3;
return dx+dy;
}
class Rect {
public:
int x1, y1, x2, y2;
Rect(int _x1, int _y1, int _x2, int _y2)
{
x1 = _x1; y1 = _y1; x2 = _x2; y2 = _y2;
}
bool isValid(void) const
{
return x1 < x2 && y1 < y2;
}
char isEmpty(void) const
{
return !(x1 < x2 && y1 < y2);
}
bool operator!(void) const
{
return isEmpty();
}
Rect & operator&=(Rect &pOther)
{
x1 = ClipLow(x1, pOther.x1);
y1 = ClipLow(y1, pOther.y1);
x2 = ClipHigh(x2, pOther.x2);
y2 = ClipHigh(y2, pOther.y2);
return *this;
}
};
class BitReader {
public:
int nBitPos;
int nSize;
char *pBuffer;
BitReader(char *_pBuffer, int _nSize, int _nBitPos) { pBuffer = _pBuffer; nSize = _nSize; nBitPos = _nBitPos; nSize -= nBitPos>>3; }
BitReader(char *_pBuffer, int _nSize) { pBuffer = _pBuffer; nSize = _nSize; nBitPos = 0; }
int readBit()
{
if (nSize <= 0)
ThrowError("Buffer overflow");
int bit = ((*pBuffer)>>nBitPos)&1;
if (++nBitPos >= 8)
{
nBitPos = 0;
pBuffer++;
nSize--;
}
return bit;
}
void skipBits(int nBits)
{
nBitPos += nBits;
pBuffer += nBitPos>>3;
nSize -= nBitPos>>3;
nBitPos &= 7;
if ((nSize == 0 && nBitPos > 0) || nSize < 0)
ThrowError("Buffer overflow");
}
unsigned int readUnsigned(int nBits)
{
unsigned int n = 0;
dassert(nBits <= 32);
for (int i = 0; i < nBits; i++)
n += readBit()<<i;
return n;
}
int readSigned(int nBits)
{
dassert(nBits <= 32);
int n = (int)readUnsigned(nBits);
n <<= 32-nBits;
n >>= 32-nBits;
return n;
}
};
class BitWriter {
public:
int nBitPos;
int nSize;
char *pBuffer;
BitWriter(char *_pBuffer, int _nSize, int _nBitPos) { pBuffer = _pBuffer; nSize = _nSize; nBitPos = _nBitPos; memset(pBuffer, 0, nSize); nSize -= nBitPos>>3; }
BitWriter(char *_pBuffer, int _nSize) { pBuffer = _pBuffer; nSize = _nSize; nBitPos = 0; memset(pBuffer, 0, nSize); }
void writeBit(int bit)
{
if (nSize <= 0)
ThrowError("Buffer overflow");
*pBuffer |= bit<<nBitPos;
if (++nBitPos >= 8)
{
nBitPos = 0;
pBuffer++;
nSize--;
}
}
void skipBits(int nBits)
{
nBitPos += nBits;
pBuffer += nBitPos>>3;
nSize -= nBitPos>>3;
nBitPos &= 7;
if ((nSize == 0 && nBitPos > 0) || nSize < 0)
ThrowError("Buffer overflow");
}
void write(int nValue, int nBits)
{
dassert(nBits <= 32);
for (int i = 0; i < nBits; i++)
writeBit((nValue>>i)&1);
}
};

1079
source/blood/src/config.cpp Normal file

File diff suppressed because it is too large Load diff

128
source/blood/src/config.h Normal file
View file

@ -0,0 +1,128 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#ifndef config_public_h_
#define config_public_h_
#include "keyboard.h"
#include "function.h"
#include "control.h"
#include "_control.h"
#include "hash.h"
#define MAXRIDECULE 10
#define MAXRIDECULELENGTH 40
#define MAXPLAYERNAME 16
extern int32_t MouseDeadZone, MouseBias;
extern int32_t SmoothInput;
extern int32_t MouseFunctions[MAXMOUSEBUTTONS][2];
extern int32_t MouseDigitalFunctions[MAXMOUSEAXES][2];
extern int32_t MouseAnalogueAxes[MAXMOUSEAXES];
extern int32_t MouseAnalogueScale[MAXMOUSEAXES];
extern int32_t JoystickFunctions[MAXJOYBUTTONSANDHATS][2];
extern int32_t JoystickDigitalFunctions[MAXJOYAXES][2];
extern int32_t JoystickAnalogueAxes[MAXJOYAXES];
extern int32_t JoystickAnalogueScale[MAXJOYAXES];
extern int32_t JoystickAnalogueDead[MAXJOYAXES];
extern int32_t JoystickAnalogueSaturate[MAXJOYAXES];
extern uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
extern int32_t scripthandle;
extern int32_t setupread;
extern int32_t SoundToggle;
extern int32_t MusicToggle;
extern int32_t MusicRestartsOnLoadToggle;
extern int32_t CDAudioToggle;
extern int32_t FXVolume;
extern int32_t MusicVolume;
extern int32_t CDVolume;
extern int32_t NumVoices;
extern int32_t NumChannels;
extern int32_t NumBits;
extern int32_t MixRate;
extern int32_t ReverseStereo;
extern int32_t MusicDevice;
extern int32_t configversion;
extern int32_t CheckForUpdates;
extern int32_t LastUpdateCheck;
extern int32_t useprecache;
extern char CommbatMacro[MAXRIDECULE][MAXRIDECULELENGTH];
extern char szPlayerName[MAXPLAYERNAME];
extern int32_t gTurnSpeed;
extern int32_t gDetail;
extern int32_t gAutoAim;
extern int32_t gWeaponSwitch;
extern int32_t gAutoRun;
extern int32_t gViewInterpolate;
extern int32_t gViewHBobbing;
extern int32_t gViewVBobbing;
extern int32_t gFollowMap;
extern int32_t gOverlayMap;
extern int32_t gRotateMap;
extern int32_t gAimReticle;
extern int32_t gSlopeTilting;
extern int32_t gMessageState;
extern int32_t gMessageCount;
extern int32_t gMessageTime;
extern int32_t gMessageFont;
extern int32_t gbAdultContent;
extern char gzAdultPassword[9];
extern int32_t gDoppler;
extern int32_t gShowWeapon;
extern int32_t gMouseSensitivity;
extern int32_t gMouseAiming;
extern int32_t gMouseAimingFlipped;
extern int32_t gRunKeyMode;
extern bool gNoClip;
extern bool gInfiniteAmmo;
extern bool gFullMap;
extern hashtable_t h_gamefuncs;
extern int32_t gUpscaleFactor;
extern int32_t gBrightness;
extern int32_t gLevelStats;
extern int32_t gPowerupDuration;
extern int32_t gShowMapTitle;
extern int32_t MAXCACHE1DSIZE;
extern int32_t gFov;
extern int32_t gCenterHoriz;
extern int32_t gDeliriumBlur;
int CONFIG_ReadSetup(void);
void CONFIG_WriteSetup(uint32_t flags);
void CONFIG_SetDefaults(void);
void CONFIG_SetupMouse(void);
void CONFIG_SetupJoystick(void);
void CONFIG_SetDefaultKeys(const char (*keyptr)[MAXGAMEFUNCLEN], bool lazy=false);
int32_t CONFIG_GetMapBestTime(char const *mapname, uint8_t const *mapmd4);
int CONFIG_SetMapBestTime(uint8_t const *mapmd4, int32_t tm);
int32_t CONFIG_FunctionNameToNum(const char *func);
char * CONFIG_FunctionNumToName(int32_t func);
int32_t CONFIG_AnalogNameToNum(const char *func);
const char *CONFIG_AnalogNumToName(int32_t func);
void CONFIG_MapKey(int which, kb_scancode key1, kb_scancode oldkey1, kb_scancode key2, kb_scancode oldkey2);
#endif

View file

@ -0,0 +1,491 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "compat.h"
#include "baselayer.h"
#include "keyboard.h"
#include "mouse.h"
#include "joystick.h"
#include "control.h"
#include "function.h"
#include "common_game.h"
#include "blood.h"
#include "config.h"
#include "controls.h"
#include "globals.h"
#include "levels.h"
#include "map2d.h"
#include "view.h"
int32_t ctrlCheckAllInput(void)
{
return (
KB_KeyWaiting() ||
MOUSE_GetButtons() ||
JOYSTICK_GetButtons()
);
}
void ctrlClearAllInput(void)
{
KB_FlushKeyboardQueue();
KB_ClearKeysDown();
MOUSE_ClearAllButtons();
JOYSTICK_ClearAllButtons();
}
GINPUT gInput;
bool bSilentAim = false;
int iTurnCount = 0;
int32_t GetTime(void)
{
return gGameClock;
}
void ctrlInit(void)
{
KB_ClearKeysDown();
KB_FlushKeyboardQueue();
KB_FlushKeyboardQueueScans();
CONTROL_Startup(controltype_keyboardandmouse, &GetTime, 120);
CONFIG_SetupMouse();
CONFIG_SetupJoystick();
CONTROL_JoystickEnabled = (gSetup.usejoystick && CONTROL_JoyPresent);
CONTROL_MouseEnabled = (gSetup.usemouse && CONTROL_MousePresent);
CONTROL_SmoothMouse = SmoothInput;
// JBF 20040215: evil and nasty place to do this, but joysticks are evil and nasty too
for (int i = 0; i < joystick.numAxes; i++)
joySetDeadZone(i, JoystickAnalogueDead[i], JoystickAnalogueSaturate[i]);
CONTROL_DefineFlag(gamefunc_Move_Forward, false);
CONTROL_DefineFlag(gamefunc_Move_Backward, false);
CONTROL_DefineFlag(gamefunc_Turn_Left, false);
CONTROL_DefineFlag(gamefunc_Turn_Right, false);
CONTROL_DefineFlag(gamefunc_Turn_Around, false);
CONTROL_DefineFlag(gamefunc_Strafe, false);
CONTROL_DefineFlag(gamefunc_Strafe_Left, false);
CONTROL_DefineFlag(gamefunc_Strafe_Right, false);
CONTROL_DefineFlag(gamefunc_Jump, false);
CONTROL_DefineFlag(gamefunc_Crouch, false);
CONTROL_DefineFlag(gamefunc_Run, false);
CONTROL_DefineFlag(gamefunc_AutoRun, false);
CONTROL_DefineFlag(gamefunc_Open, false);
CONTROL_DefineFlag(gamefunc_Weapon_Fire, false);
CONTROL_DefineFlag(gamefunc_Weapon_Special_Fire, false);
CONTROL_DefineFlag(gamefunc_Aim_Up, false);
CONTROL_DefineFlag(gamefunc_Aim_Down, false);
CONTROL_DefineFlag(gamefunc_Aim_Center, false);
CONTROL_DefineFlag(gamefunc_Look_Up, false);
CONTROL_DefineFlag(gamefunc_Look_Down, false);
CONTROL_DefineFlag(gamefunc_Tilt_Left, false);
CONTROL_DefineFlag(gamefunc_Tilt_Right, false);
CONTROL_DefineFlag(gamefunc_Weapon_1, false);
CONTROL_DefineFlag(gamefunc_Weapon_2, false);
CONTROL_DefineFlag(gamefunc_Weapon_3, false);
CONTROL_DefineFlag(gamefunc_Weapon_4, false);
CONTROL_DefineFlag(gamefunc_Weapon_5, false);
CONTROL_DefineFlag(gamefunc_Weapon_6, false);
CONTROL_DefineFlag(gamefunc_Weapon_7, false);
CONTROL_DefineFlag(gamefunc_Weapon_8, false);
CONTROL_DefineFlag(gamefunc_Weapon_9, false);
CONTROL_DefineFlag(gamefunc_Weapon_10, false);
CONTROL_DefineFlag(gamefunc_Inventory_Use, false);
CONTROL_DefineFlag(gamefunc_Inventory_Left, false);
CONTROL_DefineFlag(gamefunc_Inventory_Right, false);
CONTROL_DefineFlag(gamefunc_Map_Toggle, false);
CONTROL_DefineFlag(gamefunc_Map_Follow_Mode, false);
CONTROL_DefineFlag(gamefunc_Shrink_Screen, false);
CONTROL_DefineFlag(gamefunc_Enlarge_Screen, false);
CONTROL_DefineFlag(gamefunc_Send_Message, false);
CONTROL_DefineFlag(gamefunc_See_Coop_View, false);
CONTROL_DefineFlag(gamefunc_See_Chase_View, false);
CONTROL_DefineFlag(gamefunc_Mouse_Aiming, false);
CONTROL_DefineFlag(gamefunc_Toggle_Crosshair, false);
CONTROL_DefineFlag(gamefunc_Next_Weapon, false);
CONTROL_DefineFlag(gamefunc_Previous_Weapon, false);
CONTROL_DefineFlag(gamefunc_Holster_Weapon, false);
CONTROL_DefineFlag(gamefunc_Show_Opponents_Weapon, false);
CONTROL_DefineFlag(gamefunc_BeastVision, false);
CONTROL_DefineFlag(gamefunc_CrystalBall, false);
CONTROL_DefineFlag(gamefunc_JumpBoots, false);
CONTROL_DefineFlag(gamefunc_MedKit, false);
CONTROL_DefineFlag(gamefunc_ProximityBombs, false);
CONTROL_DefineFlag(gamefunc_RemoteBombs, false);
}
void ctrlTerm(void)
{
CONTROL_Shutdown();
}
int32_t mouseyaxismode = -1;
void ctrlGetInput(void)
{
ControlInfo info;
int forward = 0, strafe = 0;
fix16_t turn = 0;
memset(&gInput, 0, sizeof(gInput));
if (!gGameStarted || gInputMode != INPUT_MODE_0)
{
CONTROL_GetInput(&info);
return;
}
CONTROL_ProcessBinds();
if (gMouseAiming)
gMouseAim = 0;
if (BUTTON(gamefunc_Mouse_Aiming))
{
if (gMouseAiming)
gMouseAim = 1;
else
{
CONTROL_ClearButton(gamefunc_Mouse_Aiming);
gMouseAim = !gMouseAim;
if (gMouseAim)
{
if (!bSilentAim)
viewSetMessage("Mouse aiming ON");
}
else
{
if (!bSilentAim)
viewSetMessage("Mouse aiming OFF");
gInput.keyFlags.lookCenter = 1;
}
}
}
else if (gMouseAiming)
gInput.keyFlags.lookCenter = 1;
int32_t const aimMode = (gMouseAim) ? (int32_t)analog_lookingupanddown : MouseAnalogueAxes[1];
if (aimMode != mouseyaxismode)
{
CONTROL_MapAnalogAxis(1, aimMode, controldevice_mouse);
mouseyaxismode = aimMode;
}
CONTROL_GetInput(&info);
if (MouseDeadZone)
{
if (info.dpitch > 0)
info.dpitch = max(info.dpitch - MouseDeadZone, 0);
else if (info.dpitch < 0)
info.dpitch = min(info.dpitch + MouseDeadZone, 0);
if (info.dyaw > 0)
info.dyaw = max(info.dyaw - MouseDeadZone, 0);
else if (info.dyaw < 0)
info.dyaw = min(info.dyaw + MouseDeadZone, 0);
}
if (MouseBias)
{
if (klabs(info.dyaw) > klabs(info.dpitch))
info.dpitch = tabledivide32_noinline(info.dpitch, MouseBias);
else info.dyaw = tabledivide32_noinline(info.dyaw, MouseBias);
}
if (gQuitRequest)
gInput.keyFlags.quit = 1;
if (gGameStarted && gInputMode != INPUT_MODE_2 && gInputMode != INPUT_MODE_1
&& BUTTON(gamefunc_Send_Message))
{
CONTROL_ClearButton(gamefunc_Send_Message);
keyFlushScans();
gInputMode = INPUT_MODE_2;
}
if (BUTTON(gamefunc_AutoRun))
{
CONTROL_ClearButton(gamefunc_AutoRun);
gAutoRun = !gAutoRun;
if (gAutoRun)
viewSetMessage("Auto run ON");
else
viewSetMessage("Auto run OFF");
}
if (BUTTON(gamefunc_Map_Toggle))
{
CONTROL_ClearButton(gamefunc_Map_Toggle);
viewToggle(gViewMode);
}
if (BUTTON(gamefunc_Map_Follow_Mode))
{
CONTROL_ClearButton(gamefunc_Map_Follow_Mode);
gFollowMap = !gFollowMap;
gViewMap.FollowMode(gFollowMap);
}
if (BUTTON(gamefunc_Shrink_Screen))
{
if (gViewMode == 3)
{
CONTROL_ClearButton(gamefunc_Shrink_Screen);
viewResizeView(gViewSize + 1);
}
if (gViewMode == 2 || gViewMode == 4)
{
gZoom = ClipLow(gZoom - (gZoom >> 4), 64);
gViewMap.nZoom = gZoom;
}
}
if (BUTTON(gamefunc_Enlarge_Screen))
{
if (gViewMode == 3)
{
CONTROL_ClearButton(gamefunc_Enlarge_Screen);
viewResizeView(gViewSize - 1);
}
if (gViewMode == 2 || gViewMode == 4)
{
gZoom = ClipHigh(gZoom + (gZoom >> 4), 4096);
gViewMap.nZoom = gZoom;
}
}
if (BUTTON(gamefunc_Toggle_Crosshair))
{
CONTROL_ClearButton(gamefunc_Toggle_Crosshair);
gAimReticle = !gAimReticle;
}
if (BUTTON(gamefunc_Next_Weapon))
{
CONTROL_ClearButton(gamefunc_Next_Weapon);
gInput.keyFlags.nextWeapon = 1;
}
if (BUTTON(gamefunc_Previous_Weapon))
{
CONTROL_ClearButton(gamefunc_Previous_Weapon);
gInput.keyFlags.prevWeapon = 1;
}
if (BUTTON(gamefunc_Show_Opponents_Weapon))
{
CONTROL_ClearButton(gamefunc_Show_Opponents_Weapon);
gShowWeapon = !gShowWeapon;
}
if (BUTTON(gamefunc_Jump))
gInput.buttonFlags.jump = 1;
if (BUTTON(gamefunc_Crouch))
gInput.buttonFlags.crouch = 1;
if (BUTTON(gamefunc_Weapon_Fire))
gInput.buttonFlags.shoot = 1;
if (BUTTON(gamefunc_Weapon_Special_Fire))
gInput.buttonFlags.shoot2 = 1;
if (BUTTON(gamefunc_Open))
{
CONTROL_ClearButton(gamefunc_Open);
gInput.keyFlags.action = 1;
}
gInput.buttonFlags.lookUp = BUTTON(gamefunc_Look_Up);
gInput.buttonFlags.lookDown = BUTTON(gamefunc_Look_Down);
if (gInput.buttonFlags.lookUp || gInput.buttonFlags.lookDown)
gInput.keyFlags.lookCenter = 1;
else
{
gInput.buttonFlags.lookUp = BUTTON(gamefunc_Aim_Up);
gInput.buttonFlags.lookDown = BUTTON(gamefunc_Aim_Down);
}
if (BUTTON(gamefunc_Aim_Center))
{
CONTROL_ClearButton(gamefunc_Aim_Center);
gInput.keyFlags.lookCenter = 1;
}
gInput.keyFlags.spin180 = BUTTON(gamefunc_Turn_Around);
if (BUTTON(gamefunc_Inventory_Left))
{
CONTROL_ClearButton(gamefunc_Inventory_Left);
gInput.keyFlags.prevItem = 1;
}
if (BUTTON(gamefunc_Inventory_Right))
{
CONTROL_ClearButton(gamefunc_Inventory_Right);
gInput.keyFlags.nextItem = 1;
}
if (BUTTON(gamefunc_Inventory_Use))
{
CONTROL_ClearButton(gamefunc_Inventory_Use);
gInput.keyFlags.useItem = 1;
}
if (BUTTON(gamefunc_BeastVision))
{
CONTROL_ClearButton(gamefunc_BeastVision);
gInput.useFlags.useBeastVision = 1;
}
if (BUTTON(gamefunc_CrystalBall))
{
CONTROL_ClearButton(gamefunc_CrystalBall);
gInput.useFlags.useCrystalBall = 1;
}
if (BUTTON(gamefunc_JumpBoots))
{
CONTROL_ClearButton(gamefunc_JumpBoots);
gInput.useFlags.useJumpBoots = 1;
}
if (BUTTON(gamefunc_MedKit))
{
CONTROL_ClearButton(gamefunc_MedKit);
gInput.useFlags.useMedKit = 1;
}
for (int i = 0; i < 10; i++)
{
if (BUTTON(gamefunc_Weapon_1 + i))
{
CONTROL_ClearButton(gamefunc_Weapon_1 + i);
gInput.newWeapon = 1 + i;
}
}
if (BUTTON(gamefunc_ProximityBombs))
{
CONTROL_ClearButton(gamefunc_ProximityBombs);
gInput.newWeapon = 11;
}
if (BUTTON(gamefunc_RemoteBombs))
{
CONTROL_ClearButton(gamefunc_RemoteBombs);
gInput.newWeapon = 12;
}
if (BUTTON(gamefunc_Holster_Weapon))
{
CONTROL_ClearButton(gamefunc_Holster_Weapon);
gInput.keyFlags.holsterWeapon = 1;
}
char run = gRunKeyMode ? (BUTTON(gamefunc_Run) | gAutoRun) : (BUTTON(gamefunc_Run) ^ gAutoRun);
char run2 = BUTTON(gamefunc_Run);
gInput.syncFlags.run = run;
if (BUTTON(gamefunc_Move_Forward))
forward += (1+run)<<10;
if (BUTTON(gamefunc_Move_Backward))
forward -= (1+run)<<10;
char turnLeft = 0, turnRight = 0;
if (BUTTON(gamefunc_Strafe))
{
if (BUTTON(gamefunc_Turn_Left))
strafe += (1 + run) << 10;
if (BUTTON(gamefunc_Turn_Right))
strafe -= (1 + run) << 10;
}
else
{
if (BUTTON(gamefunc_Strafe_Left))
strafe += (1 + run) << 10;
if (BUTTON(gamefunc_Strafe_Right))
strafe -= (1 + run) << 10;
if (BUTTON(gamefunc_Turn_Left))
turnLeft = 1;
if (BUTTON(gamefunc_Turn_Right))
turnRight = 1;
}
if (turnLeft || turnRight)
iTurnCount += 4;
else
iTurnCount = 0;
if (turnLeft)
turn -= fix16_from_int(ClipHigh(12 * iTurnCount, gTurnSpeed))>>2;
if (turnRight)
turn += fix16_from_int(ClipHigh(12 * iTurnCount, gTurnSpeed))>>2;
if ((run2 || run) && iTurnCount > 24)
turn <<= 1;
if (BUTTON(gamefunc_Strafe))
strafe = ClipRange(strafe - info.dyaw, -2048, 2048);
else
turn = fix16_clamp(turn + fix16_div(fix16_from_int(info.dyaw), F16(32)), F16(-1024)>>2, F16(1024)>>2);
strafe = ClipRange(strafe-(info.dx<<5), -2048, 2048);
#if 0
if (info.dz < 0)
gInput.mlook = ClipRange((info.dz+127)>>7, -127, 127);
else
gInput.mlook = ClipRange(info.dz>>7, -127, 127);
#endif
gInput.q16mlook = fix16_clamp(fix16_div(fix16_from_int(info.dpitch), F16(256)), F16(-127)>>2, F16(127)>>2);
if (!gMouseAimingFlipped)
gInput.q16mlook = -gInput.q16mlook;
forward = ClipRange(forward - info.dz, -2048, 2048);
if (KB_KeyPressed(sc_Pause)) // 0xc5 in disassembly
{
gInput.keyFlags.pause = 1;
KB_ClearKeyDown(sc_Pause);
}
if (!gViewMap.bFollowMode && gViewMode == 4)
{
gViewMap.turn = fix16_to_int(turn<<2);
gViewMap.forward = forward>>8;
gViewMap.strafe = strafe>>8;
turn = 0;
forward = 0;
strafe = 0;
}
gInput.forward = forward;
gInput.q16turn = turn;
gInput.strafe = strafe;
}

112
source/blood/src/controls.h Normal file
View file

@ -0,0 +1,112 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#pragma pack(push, 1)
union BUTTONFLAGS
{
int8_t byte;
struct
{
unsigned int jump : 1;
unsigned int crouch : 1;
unsigned int shoot : 1;
unsigned int shoot2 : 1;
unsigned int lookUp : 1;
unsigned int lookDown : 1;
};
};
union KEYFLAGS
{
int16_t word;
struct
{
unsigned int action : 1;
unsigned int jab : 1;
unsigned int prevItem : 1;
unsigned int nextItem : 1;
unsigned int useItem : 1;
unsigned int prevWeapon : 1;
unsigned int nextWeapon : 1;
unsigned int holsterWeapon : 1;
unsigned int lookCenter : 1;
unsigned int lookLeft : 1;
unsigned int lookRight : 1;
unsigned int spin180 : 1;
unsigned int pause : 1;
unsigned int quit : 1;
unsigned int restart : 1;
};
};
union USEFLAGS
{
uint8_t byte;
struct
{
unsigned int useBeastVision : 1;
unsigned int useCrystalBall : 1;
unsigned int useJumpBoots : 1;
unsigned int useMedKit : 1;
};
};
union SYNCFLAGS
{
uint8_t byte;
struct
{
unsigned int buttonChange : 1;
unsigned int keyChange : 1;
unsigned int useChange : 1;
unsigned int weaponChange : 1;
unsigned int mlookChange : 1;
unsigned int run : 1;
};
};
struct GINPUT
{
SYNCFLAGS syncFlags;
int16_t forward;
fix16_t q16turn;
int16_t strafe;
BUTTONFLAGS buttonFlags;
KEYFLAGS keyFlags;
USEFLAGS useFlags;
uint8_t newWeapon;
fix16_t q16mlook;
};
#pragma pack(pop)
extern GINPUT gInput;
extern bool bSilentAim;
extern int32_t gMouseAim; // Should be an int32 due to being passed to OSD
int32_t ctrlCheckAllInput(void);
void ctrlClearAllInput(void);
void ctrlInit();
void ctrlGetInput();

View file

@ -0,0 +1,284 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "build.h"
#include "compat.h"
#include "SmackerDecoder.h"
#include "fx_man.h"
#include "keyboard.h"
#include "common_game.h"
#include "blood.h"
#include "config.h"
#include "controls.h"
#include "globals.h"
#include "resource.h"
#include "screen.h"
#include "sound.h"
#include "view.h"
char exitCredits = 0;
char Wait(int nTicks)
{
gGameClock = 0;
while (gGameClock < nTicks)
{
timerUpdate();
char key = keyGetScan();
if (key)
{
if (key == sc_Escape) // sc_Escape
exitCredits = 1;
return 0;
}
}
return 1;
}
char DoFade(char r, char g, char b, int nTicks)
{
dassert(nTicks > 0);
scrSetupFade(r, g, b);
gGameClock = gFrameClock = 0;
do
{
while (gGameClock < gFrameClock) { timerUpdate();};
gFrameClock += 2;
scrNextPage();
scrFadeAmount(divscale16(ClipHigh(gGameClock, nTicks), nTicks));
if (keyGetScan())
return 0;
} while (gGameClock <= nTicks);
return 1;
}
char DoUnFade(int nTicks)
{
dassert(nTicks > 0);
scrSetupUnfade();
gGameClock = gFrameClock = 0;
do
{
while (gGameClock < gFrameClock) { timerUpdate(); };
scrNextPage();
scrFadeAmount(0x10000-divscale16(ClipHigh(gGameClock, nTicks), nTicks));
if (keyGetScan())
return 0;
} while (gGameClock <= nTicks);
return 1;
}
void credLogosDos(void)
{
char bShift = keystatus[sc_LeftShift] | keystatus[sc_RightShift];
videoSetViewableArea(0, 0, xdim-1, ydim-1);
DoUnFade(1);
videoClearScreen(0);
if (bShift)
return;
{
//CSMKPlayer smkPlayer;
//if (smkPlayer.PlaySMKWithWAV("LOGO.SMK", 300) == 1)
//{
rotatesprite(160<<16, 100<<16, 65536, 0, 2050, 0, 0, 0x4a, 0, 0, xdim-1, ydim-1);
sndStartSample("THUNDER2", 128, -1);
scrNextPage();
if (!Wait(360))
return;
if (!DoFade(0, 0, 0, 60))
return;
//}
//if (smkPlayer.PlaySMKWithWAV("GTI.SMK", 301) == 1)
//{
videoClearScreen(0);
rotatesprite(160<<16, 100<<16, 65536, 0, 2052, 0, 0, 0x0a, 0, 0, xdim-1, ydim-1);
scrNextPage();
DoUnFade(1);
sndStartSample("THUNDER2", 128, -1);
if (!Wait(360))
return;
//}
}
sndPlaySpecialMusicOrNothing(MUS_INTRO);
sndStartSample("THUNDER2", 128, -1);
if (!DoFade(0, 0, 0, 60))
return;
videoClearScreen(0);
scrNextPage();
if (!DoUnFade(1))
return;
videoClearScreen(0);
rotatesprite(160<<16, 100<<16, 65536, 0, 2518, 0, 0, 0x4a, 0, 0, xdim-1, ydim-1);
scrNextPage();
Wait(360);
sndFadeSong(4000);
}
void credReset(void)
{
videoClearScreen(0);
scrNextPage();
DoFade(0,0,0,1);
scrSetupUnfade();
DoUnFade(1);
}
int credKOpen4Load(char *&pzFile)
{
int nLen = strlen(pzFile);
for (int i = 0; i < nLen; i++)
{
if (pzFile[i] == '\\')
pzFile[i] = '/';
}
int nHandle = kopen4loadfrommod(pzFile, 0);
if (nHandle == -1)
{
// Hack
if (nLen >= 3 && isalpha(pzFile[0]) && pzFile[1] == ':' && pzFile[2] == '/')
{
pzFile += 3;
nHandle = kopen4loadfrommod(pzFile, 0);
}
}
return nHandle;
}
#define kSMKPal 5
#define kSMKTile (MAXTILES-1)
void credPlaySmk(const char *_pzSMK, const char *_pzWAV, int nWav)
{
#if 0
CSMKPlayer smkPlayer;
if (dword_148E14 >= 0)
{
if (toupper(*pzSMK) == 'A'+dword_148E14)
{
if (Redbook.sub_82258() == 0 || Redbook.sub_82258() > 20)
return;
}
Redbook.sub_82554();
}
smkPlayer.sub_82E6C(pzSMK, pzWAV);
#endif
if (Bstrlen(_pzSMK) == 0)
return;
char *pzSMK = Xstrdup(_pzSMK);
char *pzWAV = Xstrdup(_pzWAV);
char *pzSMK_ = pzSMK;
char *pzWAV_ = pzWAV;
int nHandleSMK = credKOpen4Load(pzSMK);
if (nHandleSMK == -1)
{
Bfree(pzSMK_);
Bfree(pzWAV_);
return;
}
kclose(nHandleSMK);
SmackerHandle hSMK = Smacker_Open(pzSMK);
if (!hSMK.isValid)
{
Bfree(pzSMK_);
Bfree(pzWAV_);
return;
}
uint32_t nWidth, nHeight;
Smacker_GetFrameSize(hSMK, nWidth, nHeight);
uint8_t palette[768];
uint8_t *pFrame = (uint8_t*)Xmalloc(nWidth*nHeight);
waloff[kSMKTile] = (intptr_t)pFrame;
tilesiz[kSMKTile].y = nWidth;
tilesiz[kSMKTile].x = nHeight;
if (!pFrame)
{
Smacker_Close(hSMK);
Bfree(pzSMK_);
Bfree(pzWAV_);
return;
}
int nFrameRate = Smacker_GetFrameRate(hSMK);
int nFrames = Smacker_GetNumFrames(hSMK);
Smacker_GetPalette(hSMK, palette);
paletteSetColorTable(kSMKPal, palette);
videoSetPalette(gBrightness>>2, kSMKPal, 8+2);
int nScale;
if ((nWidth / (nHeight * 1.2f)) > (1.f * xdim / ydim))
nScale = divscale16(320 * xdim * 3, nWidth * ydim * 4);
else
nScale = divscale16(200, nHeight);
if (nWav)
sndStartWavID(nWav, FXVolume);
else
{
int nHandleWAV = credKOpen4Load(pzWAV);
if (nHandleWAV != -1)
{
kclose(nHandleWAV);
sndStartWavDisk(pzWAV, FXVolume);
}
}
UpdateDacs(0, true);
timerUpdate();
int32_t nStartTime = totalclock;
ctrlClearAllInput();
int nFrame = 0;
do
{
G_HandleAsync();
if (scale(totalclock-nStartTime, nFrameRate, kTicRate) < nFrame)
continue;
if (ctrlCheckAllInput())
break;
videoClearScreen(0);
Smacker_GetPalette(hSMK, palette);
paletteSetColorTable(kSMKPal, palette);
videoSetPalette(gBrightness >> 2, kSMKPal, 0);
tileInvalidate(kSMKTile, 0, 1 << 4); // JBF 20031228
Smacker_GetFrame(hSMK, pFrame);
rotatesprite_fs(160<<16, 100<<16, nScale, 512, kSMKTile, 0, 0, 2|4|8|64);
videoNextPage();
ctrlClearAllInput();
nFrame++;
Smacker_GetNextFrame(hSMK);
} while(nFrame < nFrames);
Smacker_Close(hSMK);
ctrlClearAllInput();
FX_StopAllSounds();
videoSetPalette(gBrightness >> 2, 0, 8+2);
Bfree(pFrame);
Bfree(pzSMK_);
Bfree(pzWAV_);
}

View file

@ -0,0 +1,27 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
void credLogosDos(void);
void credReset(void);
void credPlaySmk(const char *pzSMK, const char *pzWAV, int nWAV);

1240
source/blood/src/db.cpp Normal file

File diff suppressed because it is too large Load diff

299
source/blood/src/db.h Normal file
View file

@ -0,0 +1,299 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#define kMaxXSprites 2048
#define kMaxXWalls 512
#define kMaxXSectors 512
#pragma pack(push, 1)
struct AISTATE;
struct XSPRITE {
//int at0;
unsigned int atb_2 : 2; // unused //
unsigned int atb_6 : 1; // unused // let's use these to add more data
unsigned int ate_5 : 2; // unused // fields in the future? must be signed also
unsigned int at1a_2 : 6; // unused //
signed int reference : 14; // at0_0
unsigned int state : 1; // State 0
unsigned int busy : 17;
unsigned int txID : 10; // TX ID
unsigned int rxID : 10; // RX ID
unsigned int command : 8; // Cmd
unsigned int triggerOn : 1; // going ON
unsigned int triggerOff : 1; // going OFF
unsigned int busyTime : 12; // busyTime
unsigned int waitTime : 12; // waitTime
unsigned int restState : 1; // restState
unsigned int Interrutable : 1; // Interruptable
unsigned int respawnPending : 2; // respawnPending
signed int dropMsg : 10; // Drop Item
unsigned int Decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int isTriggered : 1; // works in case if triggerOnce selected
unsigned int key : 3; // Key
unsigned int wave : 2; // Wave
unsigned int Push: 1; // Push
unsigned int Vector : 1; // Vector
unsigned int Impact : 1; // Impact
unsigned int Pickup : 1; // Pickup
unsigned int Touch : 1; // Touch
unsigned int Sight : 1; // Sight
unsigned int Proximity : 1; // Proximity
unsigned int lSkill : 5; // Launch 12345
unsigned int lS : 1; // Single
unsigned int lB : 1; // Bloodbath
unsigned int lT : 1; // Launch Team
unsigned int lC : 1; // Coop
unsigned int DudeLockout : 1; // DudeLockout
signed int data1 : 16; // Data 1
signed int data2 : 16; // Data 2
signed int data3 : 16; // Data 3
unsigned int data4 : 16; // Data 4
unsigned int locked : 1; // Locked
unsigned int medium : 2; // medium
unsigned int respawn : 2; // Respawn option
unsigned int lockMsg : 8; // Lock msg
unsigned int health : 20; // 1c_0
unsigned int dudeDeaf : 1; // dudeDeaf
unsigned int dudeAmbush : 1; // dudeAmbush
unsigned int dudeGuard : 1; // dudeGuard
unsigned int dudeFlag4 : 1; // DF reserved
signed int target : 16; // target sprite
signed int targetX : 32; // target x
signed int targetY : 32; // target y
signed int targetZ : 32; // target z
unsigned int goalAng : 11; // Dude goal ang
signed int dodgeDir : 2; // Dude dodge direction
unsigned int burnTime : 16;
signed int burnSource : 16;
unsigned int height : 16;
unsigned int stateTimer : 16; // ai timer
AISTATE *aiState; // ai
signed int txIndex : 10; // used by kGDXSequentialTX to keep current TX ID index
signed int cumulDamage : 16; // for dudes
signed int scale; // used for scaling SEQ size on sprites
};
struct XSECTOR {
signed int reference : 14;
unsigned int state : 1; // State 0
unsigned int busy : 17;
unsigned int data : 16; // Data
unsigned int txID : 10; // TX ID
unsigned int rxID : 10; // RX ID
unsigned int at7_2 : 3; // OFF->ON wave
unsigned int at7_5 : 3; // ON->OFF wave
unsigned int command : 8; // Cmd 0
unsigned int triggerOn : 1; // Send at ON
unsigned int triggerOff : 1; // Send at OFF
unsigned int busyTimeA : 12; // OFF->ON busyTime
unsigned int waitTimeA : 12; // OFF->ON waitTime
unsigned int atd_4 : 1;
unsigned int interruptable : 1; // Interruptable
unsigned int atf_6 : 1; // OFF->ON wait
unsigned int atf_7 : 1; // ON->OFF wait
signed int amplitude : 8; // Lighting amplitude
unsigned int freq : 8; // Lighting freq
unsigned int phase : 8; // Lighting phase
unsigned int wave : 4; // Lighting wave
unsigned int shadeAlways : 1; // Lighting shadeAlways
unsigned int shadeFloor : 1; // Lighting floor
unsigned int shadeCeiling : 1; // Lighting ceiling
unsigned int shadeWalls : 1; // Lighting walls
signed int shade : 8; // Lighting value
unsigned int panAlways : 1; // Pan always
unsigned int panFloor : 1; // Pan floor
unsigned int panCeiling : 1; // Pan ceiling
unsigned int Drag : 1; // Pan drag
unsigned int panVel : 8; // Motion speed
unsigned int panAngle : 11; // Motion angle
unsigned int Underwater : 1; // Underwater
unsigned int Depth : 3; // Depth
unsigned int at16_3 : 1;
unsigned int decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int at16_6 : 1;
unsigned int Key : 3; // Key
unsigned int Push : 1; // Push
unsigned int Vector : 1; // Vector
unsigned int Reserved : 1; // Reserved
unsigned int Enter : 1; // Enter
unsigned int Exit : 1; // Exit
unsigned int Wallpush : 1; // WallPush
unsigned int color : 1; // Color Lights
unsigned int at18_1 : 1;
unsigned int busyTimeB : 12; // ON->OFF busyTime
unsigned int waitTimeB : 12; // ON->OFF waitTime
unsigned int at1b_2 : 1;
unsigned int at1b_3 : 1;
unsigned int ceilpal : 4; // Ceil pal2
signed int at1c_0 : 32;
signed int at20_0 : 32;
signed int at24_0 : 32;
signed int at28_0 : 32;
unsigned int at2c_0 : 16;
unsigned int at2e_0 : 16;
unsigned int Crush : 1; // Crush
unsigned int at30_1 : 8; // Ceiling x panning frac
unsigned int at31_1 : 8; // Ceiling y panning frac
unsigned int at32_1 : 8; // Floor x panning frac
unsigned int damageType : 3; // DamageType
unsigned int floorpal : 4; // Floor pal2
unsigned int at34_0 : 8; // Floor y panning frac
unsigned int locked : 1; // Locked
unsigned int windVel; // Wind vel (by NoOne: changed from 10 bit to use higher velocity values)
unsigned int windAng : 11; // Wind ang
unsigned int windAlways : 1; // Wind always
unsigned int at37_7 : 1;
unsigned int bobTheta : 11; // Motion Theta
unsigned int bobZRange : 5; // Motion Z range
signed int bobSpeed : 12; // Motion speed
unsigned int bobAlways : 1; // Motion always
unsigned int bobFloor : 1; // Motion bob floor
unsigned int bobCeiling : 1; // Motion bob ceiling
unsigned int bobRotate : 1; // Motion rotate
}; // 60(0x3c) bytes
struct XWALL {
signed int reference : 14;
unsigned int state : 1; // State
unsigned int busy : 17;
signed int data : 16; // Data
unsigned int txID : 10; // TX ID
unsigned int at7_2 : 6; // unused
unsigned int rxID : 10; // RX ID
unsigned int command : 8; // Cmd
unsigned int triggerOn : 1; // going ON
unsigned int triggerOff : 1; // going OFF
unsigned int busyTime : 12; // busyTime
unsigned int waitTime : 12; // waitTime
unsigned int restState : 1; // restState
unsigned int interruptable : 1; // Interruptable
unsigned int panAlways : 1; // panAlways
signed int panXVel : 8; // panX
signed int panYVel : 8; // panY
unsigned int decoupled : 1; // Decoupled
unsigned int triggerOnce : 1; // 1-shot
unsigned int isTriggered : 1;
unsigned int key : 3; // Key
unsigned int triggerPush : 1; // Push
unsigned int triggerVector : 1; // Vector
unsigned int triggerReserved : 1; // Reserved
unsigned int at11_0 : 2; // unused
unsigned int xpanFrac : 8; // x panning frac
unsigned int ypanFrac : 8; // y panning frac
unsigned int locked : 1; // Locked
unsigned int dudeLockout : 1; // DudeLockout
unsigned int at13_4 : 4; // unused;
unsigned int at14_0 : 32; // unused
}; // 24(0x18) bytes
struct MAPSIGNATURE {
char signature[4];
short version;
};
struct MAPHEADER {
int at0; // x
int at4; // y
int at8; // z
short atc; // ang
short ate; // sect
short at10; // pskybits
int at12; // visibility
int at16; // song id, Matt
char at1a; // parallaxtype
int at1b; // map revision
short at1f; // numsectors
short at21; // numwalls
short at23; // numsprites
};
struct MAPHEADER2 {
char at0[64];
int at40; // xsprite size
int at44; // xwall size
int at48; // xsector size
char pad[52];
};
#pragma pack(pop)
extern unsigned short gStatCount[kMaxStatus + 1];;
extern bool byte_1A76C6, byte_1A76C7, byte_1A76C8;
extern MAPHEADER2 byte_19AE44;
extern XSPRITE xsprite[kMaxXSprites];
extern XSECTOR xsector[kMaxXSectors];
extern XWALL xwall[kMaxXWalls];
extern int xvel[kMaxSprites], yvel[kMaxSprites], zvel[kMaxSprites];
extern int gVisibility;
extern int gMapRev, gSongId, gSkyCount;
extern const char *gItemText[];
extern const char *gAmmoText[];
extern const char *gWeaponText[];
extern unsigned short nextXSprite[kMaxXSprites];
extern unsigned short nextXWall[kMaxXWalls];
extern unsigned short nextXSector[kMaxXSectors];
void InsertSpriteSect(int nSprite, int nSector);
void RemoveSpriteSect(int nSprite);
void InsertSpriteStat(int nSprite, int nStat);
void RemoveSpriteStat(int nSprite);
void qinitspritelists(void);
int InsertSprite(int nSector, int nStat);
int qinsertsprite(short nSector, short nStat);
int DeleteSprite(int nSprite);
int qdeletesprite(short nSprite);
int ChangeSpriteSect(int nSprite, int nSector);
int qchangespritesect(short nSprite, short nSector);
int ChangeSpriteStat(int nSprite, int nStatus);
int qchangespritestat(short nSprite, short nStatus);
void InitFreeList(unsigned short *pList, int nCount);
void InsertFree(unsigned short *pList, int nIndex);
unsigned short dbInsertXSprite(int nSprite);
void dbDeleteXSprite(int nXSprite);
unsigned short dbInsertXWall(int nWall);
void dbDeleteXWall(int nXWall);
unsigned short dbInsertXSector(int nSector);
void dbDeleteXSector(int nXSector);
void dbXSpriteClean(void);
void dbXWallClean(void);
void dbXSectorClean(void);
void dbInit(void);
void PropagateMarkerReferences(void);
unsigned int dbReadMapCRC(const char *pPath);
void dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, short *pSector, unsigned int *pCRC);

625
source/blood/src/demo.cpp Normal file
View file

@ -0,0 +1,625 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "common_game.h"
#include "keyboard.h"
#include "control.h"
#include "osd.h"
#include "mmulti.h"
#include "blood.h"
#include "controls.h"
#include "demo.h"
#include "fire.h"
#include "gamemenu.h"
#include "globals.h"
#include "levels.h"
#include "menu.h"
#include "messages.h"
#include "misc.h"
#include "music.h"
#include "network.h"
#include "player.h"
#include "screen.h"
#include "view.h"
int nBuild = 0;
void ReadGameOptionsLegacy(GAMEOPTIONS &gameOptions, GAMEOPTIONSLEGACY &gameOptionsLegacy)
{
gameOptions.nGameType = gameOptionsLegacy.nGameType;
gameOptions.nDifficulty = gameOptionsLegacy.nDifficulty;
gameOptions.nEpisode = gameOptionsLegacy.nEpisode;
gameOptions.nLevel = gameOptionsLegacy.nLevel;
strcpy(gameOptions.zLevelName, gameOptionsLegacy.zLevelName);
strcpy(gameOptions.zLevelSong, gameOptionsLegacy.zLevelSong);
gameOptions.nTrackNumber = gameOptionsLegacy.nTrackNumber;
strcpy(gameOptions.szSaveGameName, gameOptionsLegacy.szSaveGameName);
strcpy(gameOptions.szUserGameName, gameOptionsLegacy.szUserGameName);
gameOptions.nSaveGameSlot = gameOptionsLegacy.nSaveGameSlot;
gameOptions.picEntry = gameOptionsLegacy.picEntry;
gameOptions.uMapCRC = gameOptionsLegacy.uMapCRC;
gameOptions.nMonsterSettings = gameOptionsLegacy.nMonsterSettings;
gameOptions.uGameFlags = gameOptionsLegacy.uGameFlags;
gameOptions.uNetGameFlags = gameOptionsLegacy.uNetGameFlags;
gameOptions.nWeaponSettings = gameOptionsLegacy.nWeaponSettings;
gameOptions.nItemSettings = gameOptionsLegacy.nItemSettings;
gameOptions.nRespawnSettings = gameOptionsLegacy.nRespawnSettings;
gameOptions.nTeamSettings = gameOptionsLegacy.nTeamSettings;
gameOptions.nMonsterRespawnTime = gameOptionsLegacy.nMonsterRespawnTime;
gameOptions.nWeaponRespawnTime = gameOptionsLegacy.nWeaponRespawnTime;
gameOptions.nItemRespawnTime = gameOptionsLegacy.nItemRespawnTime;
gameOptions.nSpecialRespawnTime = gameOptionsLegacy.nSpecialRespawnTime;
}
CDemo gDemo;
CDemo::CDemo()
{
nBuild = 4;
at0 = 0;
at1 = 0;
at3 = 0;
hPFile = -1;
hRFile = NULL;
atb = 0;
pFirstDemo = NULL;
pCurrentDemo = NULL;
at59ef = 0;
at2 = 0;
memset(&atf, 0, sizeof(atf));
m_bLegacy = false;
}
CDemo::~CDemo()
{
at0 = 0;
at1 = 0;
at3 = 0;
atb = 0;
memset(&atf, 0, sizeof(atf));
if (hPFile >= 0)
{
kclose(hPFile);
hPFile = -1;
}
if (hRFile != NULL)
{
fclose(hRFile);
hRFile = NULL;
}
auto pNextDemo = pFirstDemo;
for (auto pDemo = pFirstDemo; pDemo != NULL; pDemo = pNextDemo)
{
pNextDemo = pDemo->pNext;
delete pDemo;
}
pFirstDemo = NULL;
pCurrentDemo = NULL;
at59ef = 0;
m_bLegacy = false;
}
bool CDemo::Create(const char *pzFile)
{
char buffer[BMAX_PATH];
char vc = 0;
if (at0 || at1)
ThrowError("CDemo::Create called during demo record/playback process.");
if (!pzFile)
{
for (int i = 0; i < 8 && !vc; i++)
{
G_ModDirSnprintf(buffer, BMAX_PATH, "%s0%02d.dem", BloodIniPre, i);
if (access(buffer, F_OK) != -1)
vc = 1;
}
if (vc == 1)
{
hRFile = fopen(buffer, "wb");
if (hRFile == NULL)
return false;
}
}
else
{
G_ModDirSnprintfLite(buffer, BMAX_PATH, pzFile);
hRFile = fopen(buffer, "wb");
if (hRFile == NULL)
return false;
}
at0 = 1;
atb = 0;
return true;
}
void CDemo::Write(GINPUT *pPlayerInputs)
{
dassert(pPlayerInputs != NULL);
if (!at0)
return;
if (atb == 0)
{
atf.signature = 0x1a4d4445; // '\x1aMDE';
atf.nVersion = BYTEVERSION;
atf.nBuild = nBuild;
atf.nInputCount = 0;
atf.nNetPlayers = gNetPlayers;
atf.nMyConnectIndex = myconnectindex;
atf.nConnectHead = connecthead;
memcpy(atf.connectPoints, connectpoint2, sizeof(atf.connectPoints));
memcpy(&m_gameOptions, &gGameOptions, sizeof(gGameOptions));
fwrite(&atf, sizeof(DEMOHEADER), 1, hRFile);
fwrite(&m_gameOptions, sizeof(GAMEOPTIONS), 1, hRFile);
}
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
memcpy(&at1aa[atb&1023], &pPlayerInputs[p], sizeof(GINPUT));
atb++;
if((atb&(kInputBufferSize-1))==0)
FlushInput(kInputBufferSize);
}
}
void CDemo::Close(void)
{
if (at0)
{
if (atb&(kInputBufferSize-1))
FlushInput(atb&(kInputBufferSize-1));
atf.nInputCount = atb;
fseek(hRFile, 0, SEEK_SET);
fwrite(&atf, sizeof(DEMOHEADER), 1, hRFile);
fwrite(&m_gameOptions, sizeof(GAMEOPTIONS), 1, hRFile);
}
if (hPFile >= 0)
{
kclose(hPFile);
hPFile = -1;
}
if (hRFile != NULL)
{
fclose(hRFile);
hRFile = NULL;
}
at0 = 0;
at1 = 0;
}
bool CDemo::SetupPlayback(const char *pzFile)
{
at0 = 0;
at1 = 0;
if (pzFile)
{
hPFile = kopen4loadfrommod(pzFile, 0);
if (hPFile == -1)
return false;
}
else
{
if (!pCurrentDemo)
return false;
hPFile = kopen4loadfrommod(pCurrentDemo->zName, 0);
if (hPFile == -1)
return false;
}
kread(hPFile, &atf, sizeof(DEMOHEADER));
#if B_BIG_ENDIAN == 1
atf.signature = B_LITTLE32(atf.signature);
atf.nVersion = B_LITTLE16(atf.nVersion);
atf.nBuild = B_LITTLE32(atf.nBuild);
atf.nInputCount = B_LITTLE32(atf.nInputCount);
atf.nNetPlayers = B_LITTLE32(atf.nNetPlayers);
atf.nMyConnectIndex = B_LITTLE16(atf.nMyConnectIndex);
atf.nConnectHead = B_LITTLE16(atf.nConnectHead);
atf.nMyConnectIndex = B_LITTLE16(atf.nMyConnectIndex);
for (int i = 0; i < 8; i++)
atf.connectPoints[i] = B_LITTLE16(atf.connectPoints[i]);
#endif
// if (aimHeight.signature != '\x1aMED' && aimHeight.signature != '\x1aMDE')
if (atf.signature != 0x1a4d4544 && atf.signature != 0x1a4d4445)
return 0;
m_bLegacy = atf.signature == 0x1a4d4544;
if (m_bLegacy)
{
GAMEOPTIONSLEGACY gameOptions;
if (BloodVersion != atf.nVersion)
return 0;
kread(hPFile, &gameOptions, sizeof(GAMEOPTIONSLEGACY));
ReadGameOptionsLegacy(m_gameOptions, gameOptions);
}
else
{
if (BYTEVERSION != atf.nVersion)
return 0;
kread(hPFile, &m_gameOptions, sizeof(GAMEOPTIONS));
}
#if B_BIG_ENDIAN == 1
m_gameOptions.nEpisode = B_LITTLE32(m_gameOptions.nEpisode);
m_gameOptions.nLevel = B_LITTLE32(m_gameOptions.nLevel);
m_gameOptions.nTrackNumber = B_LITTLE32(m_gameOptions.nTrackNumber);
m_gameOptions.nSaveGameSlot = B_LITTLE16(m_gameOptions.nSaveGameSlot);
m_gameOptions.picEntry = B_LITTLE32(m_gameOptions.picEntry);
m_gameOptions.uMapCRC = B_LITTLE32(m_gameOptions.uMapCRC);
m_gameOptions.uGameFlags = B_LITTLE32(m_gameOptions.uGameFlags);
m_gameOptions.uNetGameFlags = B_LITTLE32(m_gameOptions.uNetGameFlags);
m_gameOptions.nMonsterRespawnTime = B_LITTLE32(m_gameOptions.nMonsterRespawnTime);
m_gameOptions.nWeaponRespawnTime = B_LITTLE32(m_gameOptions.nWeaponRespawnTime);
m_gameOptions.nItemRespawnTime = B_LITTLE32(m_gameOptions.nItemRespawnTime);
m_gameOptions.nSpecialRespawnTime = B_LITTLE32(m_gameOptions.nSpecialRespawnTime);
#endif
at0 = 0;
at1 = 1;
return 1;
}
void CDemo::ProcessKeys(void)
{
switch (gInputMode)
{
case INPUT_MODE_1:
gGameMenuMgr.Process();
break;
case INPUT_MODE_2:
gPlayerMsg.ProcessKeys();
break;
case INPUT_MODE_0:
{
char nKey;
while ((nKey = keyGetScan()) != 0)
{
char UNUSED(alt) = keystatus[0x38] | keystatus[0xb8];
char UNUSED(ctrl) = keystatus[0x1d] | keystatus[0x9d];
switch (nKey)
{
case 1:
if (!CGameMenuMgr::m_bActive)
{
gGameMenuMgr.Push(&menuMain, -1);
at2 = 1;
}
break;
case 0x58:
gViewIndex = connectpoint2[gViewIndex];
if (gViewIndex == -1)
gViewIndex = connecthead;
gView = &gPlayer[gViewIndex];
break;
}
}
break;
default:
gInputMode = INPUT_MODE_0;
break;
}
}
}
void CDemo::Playback(void)
{
CONTROL_BindsEnabled = false;
ready2send = 0;
int v4 = 0;
if (!CGameMenuMgr::m_bActive)
{
gGameMenuMgr.Push(&menuMain, -1);
at2 = 1;
}
gNetFifoClock = gGameClock;
gViewMode = 3;
_DEMOPLAYBACK:
while (at1 && !gQuitGame)
{
if (handleevents() && quitevent)
{
KB_KeyDown[sc_Escape] = 1;
quitevent = 0;
}
MUSIC_Update();
while (gGameClock >= gNetFifoClock && !gQuitGame)
{
if (!v4)
{
viewResizeView(gViewSize);
viewSetMessage("");
gNetPlayers = atf.nNetPlayers;
atb = atf.nInputCount;
myconnectindex = atf.nMyConnectIndex;
connecthead = atf.nConnectHead;
for (int i = 0; i < 8; i++)
connectpoint2[i] = atf.connectPoints[i];
memset(gNetFifoHead, 0, sizeof(gNetFifoHead));
gNetFifoTail = 0;
//memcpy(connectpoint2, aimHeight.connectPoints, sizeof(aimHeight.connectPoints));
memcpy(&gGameOptions, &m_gameOptions, sizeof(GAMEOPTIONS));
gSkill = gGameOptions.nDifficulty;
for (int i = 0; i < 8; i++)
playerInit(i, 0);
StartLevel(&gGameOptions);
for (int i = 0; i < 8; i++)
{
gProfile[i].nAutoAim = 1;
gProfile[i].nWeaponSwitch = 1;
}
}
ready2send = 0;
OSD_DispatchQueued();
if (!gDemo.at1)
break;
ProcessKeys();
for (int p = connecthead; p >= 0; p = connectpoint2[p])
{
if ((v4&1023) == 0)
{
unsigned int nSize = atb-v4;
if (nSize > kInputBufferSize)
nSize = kInputBufferSize;
ReadInput(nSize);
}
memcpy(&gFifoInput[gNetFifoHead[p]&255], &at1aa[v4&1023], sizeof(GINPUT));
gNetFifoHead[p]++;
v4++;
if (v4 >= atf.nInputCount)
{
ready2send = 0;
if (at59ef != 1)
{
v4 = 0;
Close();
NextDemo();
gNetFifoClock = gGameClock;
goto _DEMOPLAYBACK;
}
else
{
int const nOffset = sizeof(DEMOHEADER)+(m_bLegacy ? sizeof(GAMEOPTIONSLEGACY) : sizeof(GAMEOPTIONS));
klseek(hPFile, nOffset, SEEK_SET);
v4 = 0;
}
}
}
gNetFifoClock += 4;
if (!gQuitGame)
ProcessFrame();
ready2send = 0;
}
if (viewFPSLimit())
{
viewDrawScreen();
if (gInputMode == INPUT_MODE_1 && CGameMenuMgr::m_bActive)
gGameMenuMgr.Draw();
}
if (TestBitString(gotpic, 2342))
{
FireProcess();
ClearBitString(gotpic, 2342);
}
}
Close();
}
void CDemo::StopPlayback(void)
{
at1 = 0;
}
void CDemo::LoadDemoInfo(void)
{
auto pDemo = &pFirstDemo;
const int opsm = pathsearchmode;
at59ef = 0;
pathsearchmode = 0;
char zFN[BMAX_PATH];
Bsnprintf(zFN, BMAX_PATH, "%s*.dem", BloodIniPre);
auto pList = klistpath("/", zFN, CACHE1D_FIND_FILE);
auto pIterator = pList;
while (pIterator != NULL)
{
int hFile = kopen4loadfrommod(pIterator->name, 0);
if (hFile == -1)
ThrowError("Error loading demo file header.");
kread(hFile, &atf, sizeof(atf));
kclose(hFile);
#if B_BIG_ENDIAN == 1
atf.signature = B_LITTLE32(atf.signature);
atf.nVersion = B_LITTLE16(atf.nVersion);
#endif
if ((atf.signature == 0x1a4d4544 /* '\x1aMED' */&& atf.nVersion == BloodVersion)
|| (atf.signature == 0x1a4d4445 /* '\x1aMDE' */ && atf.nVersion == BYTEVERSION))
{
*pDemo = new DEMOCHAIN;
(*pDemo)->pNext = NULL;
Bstrncpy((*pDemo)->zName, pIterator->name, BMAX_PATH);
at59ef++;
pDemo = &(*pDemo)->pNext;
}
pIterator = pIterator->next;
}
klistfree(pList);
pathsearchmode = opsm;
pCurrentDemo = pFirstDemo;
}
void CDemo::NextDemo(void)
{
pCurrentDemo = pCurrentDemo->pNext ? pCurrentDemo->pNext : pFirstDemo;
SetupPlayback(NULL);
}
const int nInputSize = 17;
const int nInputSizeLegacy = 22;
void CDemo::FlushInput(int nCount)
{
char pBuffer[nInputSize*kInputBufferSize];
BitWriter bitWriter(pBuffer, sizeof(pBuffer));
for (int i = 0; i < nCount; i++)
{
GINPUT *pInput = &at1aa[i];
bitWriter.writeBit(pInput->syncFlags.buttonChange);
bitWriter.writeBit(pInput->syncFlags.keyChange);
bitWriter.writeBit(pInput->syncFlags.useChange);
bitWriter.writeBit(pInput->syncFlags.weaponChange);
bitWriter.writeBit(pInput->syncFlags.mlookChange);
bitWriter.writeBit(pInput->syncFlags.run);
bitWriter.write(pInput->forward, 16);
bitWriter.write(pInput->q16turn, 32);
bitWriter.write(pInput->strafe, 16);
bitWriter.writeBit(pInput->buttonFlags.jump);
bitWriter.writeBit(pInput->buttonFlags.crouch);
bitWriter.writeBit(pInput->buttonFlags.shoot);
bitWriter.writeBit(pInput->buttonFlags.shoot2);
bitWriter.writeBit(pInput->buttonFlags.lookUp);
bitWriter.writeBit(pInput->buttonFlags.lookDown);
bitWriter.writeBit(pInput->keyFlags.action);
bitWriter.writeBit(pInput->keyFlags.jab);
bitWriter.writeBit(pInput->keyFlags.prevItem);
bitWriter.writeBit(pInput->keyFlags.nextItem);
bitWriter.writeBit(pInput->keyFlags.useItem);
bitWriter.writeBit(pInput->keyFlags.prevWeapon);
bitWriter.writeBit(pInput->keyFlags.nextWeapon);
bitWriter.writeBit(pInput->keyFlags.holsterWeapon);
bitWriter.writeBit(pInput->keyFlags.lookCenter);
bitWriter.writeBit(pInput->keyFlags.lookLeft);
bitWriter.writeBit(pInput->keyFlags.lookRight);
bitWriter.writeBit(pInput->keyFlags.spin180);
bitWriter.writeBit(pInput->keyFlags.pause);
bitWriter.writeBit(pInput->keyFlags.quit);
bitWriter.writeBit(pInput->keyFlags.restart);
bitWriter.writeBit(pInput->useFlags.useBeastVision);
bitWriter.writeBit(pInput->useFlags.useCrystalBall);
bitWriter.writeBit(pInput->useFlags.useJumpBoots);
bitWriter.writeBit(pInput->useFlags.useMedKit);
bitWriter.write(pInput->newWeapon, 8);
bitWriter.write(pInput->q16mlook, 32);
bitWriter.skipBits(1);
}
fwrite(pBuffer, 1, nInputSize*nCount, hRFile);
}
void CDemo::ReadInput(int nCount)
{
if (m_bLegacy)
{
char pBuffer[nInputSizeLegacy*kInputBufferSize];
kread(hPFile, pBuffer, nInputSizeLegacy*nCount);
BitReader bitReader(pBuffer, sizeof(pBuffer));
memset(at1aa, 0, nCount * sizeof(GINPUT));
for (int i = 0; i < nCount; i++)
{
GINPUT *pInput = &at1aa[i];
pInput->syncFlags.buttonChange = bitReader.readBit();
pInput->syncFlags.keyChange = bitReader.readBit();
pInput->syncFlags.useChange = bitReader.readBit();
pInput->syncFlags.weaponChange = bitReader.readBit();
pInput->syncFlags.mlookChange = bitReader.readBit();
pInput->syncFlags.run = bitReader.readBit();
bitReader.skipBits(26);
pInput->forward = bitReader.readSigned(8) << 8;
pInput->q16turn = fix16_from_int(bitReader.readSigned(16) >> 2);
pInput->strafe = bitReader.readSigned(8) << 8;
pInput->buttonFlags.jump = bitReader.readBit();
pInput->buttonFlags.crouch = bitReader.readBit();
pInput->buttonFlags.shoot = bitReader.readBit();
pInput->buttonFlags.shoot2 = bitReader.readBit();
pInput->buttonFlags.lookUp = bitReader.readBit();
pInput->buttonFlags.lookDown = bitReader.readBit();
bitReader.skipBits(26);
pInput->keyFlags.action = bitReader.readBit();
pInput->keyFlags.jab = bitReader.readBit();
pInput->keyFlags.prevItem = bitReader.readBit();
pInput->keyFlags.nextItem = bitReader.readBit();
pInput->keyFlags.useItem = bitReader.readBit();
pInput->keyFlags.prevWeapon = bitReader.readBit();
pInput->keyFlags.nextWeapon = bitReader.readBit();
pInput->keyFlags.holsterWeapon = bitReader.readBit();
pInput->keyFlags.lookCenter = bitReader.readBit();
pInput->keyFlags.lookLeft = bitReader.readBit();
pInput->keyFlags.lookRight = bitReader.readBit();
pInput->keyFlags.spin180 = bitReader.readBit();
pInput->keyFlags.pause = bitReader.readBit();
pInput->keyFlags.quit = bitReader.readBit();
pInput->keyFlags.restart = bitReader.readBit();
bitReader.skipBits(17);
pInput->useFlags.useBeastVision = bitReader.readBit();
pInput->useFlags.useCrystalBall = bitReader.readBit();
pInput->useFlags.useJumpBoots = bitReader.readBit();
pInput->useFlags.useMedKit = bitReader.readBit();
bitReader.skipBits(28);
pInput->newWeapon = bitReader.readUnsigned(8);
int mlook = bitReader.readSigned(8);
pInput->q16mlook = fix16_from_int(mlook / 4);
}
}
else
{
char pBuffer[nInputSize*kInputBufferSize];
kread(hPFile, pBuffer, nInputSize*nCount);
BitReader bitReader(pBuffer, sizeof(pBuffer));
memset(at1aa, 0, nCount * sizeof(GINPUT));
for (int i = 0; i < nCount; i++)
{
GINPUT *pInput = &at1aa[i];
pInput->syncFlags.buttonChange = bitReader.readBit();
pInput->syncFlags.keyChange = bitReader.readBit();
pInput->syncFlags.useChange = bitReader.readBit();
pInput->syncFlags.weaponChange = bitReader.readBit();
pInput->syncFlags.mlookChange = bitReader.readBit();
pInput->syncFlags.run = bitReader.readBit();
pInput->forward = bitReader.readSigned(16);
pInput->q16turn = bitReader.readSigned(32);
pInput->strafe = bitReader.readSigned(16);
pInput->buttonFlags.jump = bitReader.readBit();
pInput->buttonFlags.crouch = bitReader.readBit();
pInput->buttonFlags.shoot = bitReader.readBit();
pInput->buttonFlags.shoot2 = bitReader.readBit();
pInput->buttonFlags.lookUp = bitReader.readBit();
pInput->buttonFlags.lookDown = bitReader.readBit();
pInput->keyFlags.action = bitReader.readBit();
pInput->keyFlags.jab = bitReader.readBit();
pInput->keyFlags.prevItem = bitReader.readBit();
pInput->keyFlags.nextItem = bitReader.readBit();
pInput->keyFlags.useItem = bitReader.readBit();
pInput->keyFlags.prevWeapon = bitReader.readBit();
pInput->keyFlags.nextWeapon = bitReader.readBit();
pInput->keyFlags.holsterWeapon = bitReader.readBit();
pInput->keyFlags.lookCenter = bitReader.readBit();
pInput->keyFlags.lookLeft = bitReader.readBit();
pInput->keyFlags.lookRight = bitReader.readBit();
pInput->keyFlags.spin180 = bitReader.readBit();
pInput->keyFlags.pause = bitReader.readBit();
pInput->keyFlags.quit = bitReader.readBit();
pInput->keyFlags.restart = bitReader.readBit();
pInput->useFlags.useBeastVision = bitReader.readBit();
pInput->useFlags.useCrystalBall = bitReader.readBit();
pInput->useFlags.useJumpBoots = bitReader.readBit();
pInput->useFlags.useMedKit = bitReader.readBit();
pInput->newWeapon = bitReader.readUnsigned(8);
pInput->q16mlook = bitReader.readSigned(32);
bitReader.skipBits(1);
}
}
}

110
source/blood/src/demo.h Normal file
View file

@ -0,0 +1,110 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#pragma once
#include "controls.h"
#include "levels.h"
#define kInputBufferSize 1024
#pragma pack(push, 1)
struct GAMEOPTIONSLEGACY {
char nGameType;
char nDifficulty;
int nEpisode;
int nLevel;
char zLevelName[144];
char zLevelSong[144];
int nTrackNumber; //at12a;
char szSaveGameName[16];
char szUserGameName[16];
short nSaveGameSlot;
int picEntry;
unsigned int uMapCRC;
char nMonsterSettings;
int uGameFlags;
int uNetGameFlags;
char nWeaponSettings;
char nItemSettings;
char nRespawnSettings;
char nTeamSettings;
int nMonsterRespawnTime;
int nWeaponRespawnTime;
int nItemRespawnTime;
int nSpecialRespawnTime;
};
struct DEMOHEADER
{
int signature;
short nVersion;
int nBuild;
int nInputCount;
int nNetPlayers;
short nMyConnectIndex;
short nConnectHead;
short connectPoints[8];
};
#pragma pack(pop)
struct DEMOCHAIN
{
DEMOCHAIN *pNext;
char zName[BMAX_PATH];
};
class CDemo {
public:
CDemo();
~CDemo();
bool Create(const char *);
void Write(GINPUT *);
void Close(void);
bool SetupPlayback(const char *);
void ProcessKeys(void);
void Playback(void);
void StopPlayback(void);
void LoadDemoInfo(void);
void NextDemo(void);
void FlushInput(int nCount);
void ReadInput(int nCount);
bool at0; // record
bool at1; // playback
bool m_bLegacy;
char at2;
int at3;
int hPFile;
FILE *hRFile;
int atb;
DEMOHEADER atf;
GAMEOPTIONS m_gameOptions;
GINPUT at1aa[kInputBufferSize];
const char **pzDemoFile;
DEMOCHAIN *pFirstDemo;
DEMOCHAIN *pCurrentDemo;
int at59ef;
};
extern CDemo gDemo;

1727
source/blood/src/dude.cpp Normal file

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more