16 Commits

Author SHA1 Message Date
Muzychenko Andrey
10c83e8bf5 Fixed sound pops introduced by WaveMix upsampler.
This does not fix WINE issues, but at least you don’t have to up sample manually.
2021-08-19 09:29:32 +03:00
Muzychenko Andrey
d5b44e44e1 Improved wav duration calculation - now supports sample rates other than 11025.
Bumped build tool version to VS2019.
2021-08-18 12:44:26 +03:00
Muzychenko Andrey
dcd488c48c Merge pull request #5 from GeorgeMcMullen/midifix
Fix to the routine that opens the MIDI file.
2021-08-18 10:08:55 +03:00
George McMullen
db08631ab9 Fix to the routine that opens the MIDI file.
In the original source code for Space Cadet and its related games, the MIDI sound track is opened with MCI_OPEN_TYPE. According to Microsoft's documentation (https://docs.microsoft.com/en-us/windows/win32/multimedia/mci-open), this is for opening devices and not files. Windows' libraries were obviously robust enough to accommodate the error, but other platforms (i.e. WINE) expects things to be called the right way. The simple fix is to switch out MCI_OPEN_TYPE with MCI_OPEN_ELEMENT and move the info for the filename to the lpstrElementName variable.
2021-08-16 05:39:18 -07:00
Muzychenko Andrey
bad55d49cf Updated readme. 2021-02-20 15:58:16 +03:00
Muzychenko Andrey
98f234fce3 Replaced GlobalAlloc with malloc.
WaveMix keeps GlobalAlloc for authenticity.
Fixed float to double casts.
Some cleanup.
2021-02-18 12:53:25 +03:00
Muzychenko Andrey
55984fbb08 Fixed x64 build warnings.
Replaced __intN with intN_t.
Some cleanup.
2021-02-16 19:03:45 +03:00
Muzychenko Andrey
5c3e9fea4c Added FT music loader.
Fixed mouse lock.
Some cleanup.
2021-02-15 18:55:54 +03:00
Muzychenko Andrey
debe52c1e0 Added scalable window, mouse controls. 2021-02-09 18:09:44 +03:00
Muzychenko Andrey
1c5256a4c6 Added table resolution support.
Only works with FT .dat file.
FT music does not work - different format.
2021-02-06 16:53:47 +03:00
Muzychenko Andrey
d594f5fdb7 Converted memory to direct pointers.
Fixed memory leaks in uninit.
Fixed some of the code analysis warnings.
Enabled /MP build.
Cleaned up the code.
2021-02-02 18:29:54 +03:00
Muzychenko Andrey
49f6132d23 Added loader for Full Tilt .dat files, v1.
Works with some data hacks in lowest resolution.
Seems to work ok, even though BL is still 3DPB.
2021-01-31 17:29:53 +03:00
Muzychenko Andrey
6ff457eb68 Cleaned up objlist_class. 2021-01-30 14:19:25 +03:00
Muzychenko Andrey
5b9a1ff95d Create LICENSE
Some docs might be incompatible with MIT, to be reviewed later.
2021-01-29 19:47:23 +03:00
Muzychenko Andrey
232f24a2a2 Added Readme.md 2021-01-29 19:34:45 +03:00
oz
efc56e82d9 Compile releases with Windows subsystem. 2021-01-29 17:49:00 +03:00
93 changed files with 2370 additions and 1327 deletions

View File

@@ -1,3 +1,3 @@
rc /Fo.\DrMem\SpaceCadetPinball.res ".\SpaceCadetPinball\SpaceCadetPinball.rc" rc /Fo.\DrMem\SpaceCadetPinball.res ".\SpaceCadetPinball\SpaceCadetPinball.rc"
cl /Zi /MT /EHsc /O /Ob0 /cgthreads4 /Fo.\DrMem\ /Fe.\DrMem\myapp.exe ".\SpaceCadetPinball\*.cpp" Comctl32.lib Winmm.lib Htmlhelp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ".\DrMem\SpaceCadetPinball.res" cl /Zi /MT /MP /EHsc /O /Ob0 /cgthreads4 /Fo.\DrMem\ /Fe.\DrMem\myapp.exe ".\SpaceCadetPinball\*.cpp" Comctl32.lib Winmm.lib Htmlhelp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ".\DrMem\SpaceCadetPinball.res"

View File

@@ -39,21 +39,21 @@ Type Meaning/comments
9 String (content) 9 String (content)
10 Array of 16bits integer values 10 Array of 16bits integer values
11 Array of 32bits floating point values (collision box, ...) 11 Array of 32bits floating point values (collision box, ...)
12 16 bpp bitmap (Heightmap?) 12 16 bpp bitmap (zMap)
//-- 8bpp bitmap data header --// //-- 8bpp bitmap data header --//
+0: Unknown (0) BYTE +0: Resolution BYTE 0=640x480, 1=800x600, 2=1024x768, -1=Load in all resolutions
+1: Width WORD +1: Width WORD
+3: Height WORD +3: Height WORD
+5: X position WORD +5: X position WORD
+7 Y position WORD +7 Y position WORD
+9: Size of bitmap DWORD +9: Size of bitmap DWORD
+13: Unknown (1) BYTE +13: Flags BYTE bit0=Raw bmp align; bit1=DibBitmap, raw when 0; bit2=Spliced bitmap (aka skipline), combines bmp and zMap in RLE-like way
+14: Bitmap data BYTE*(DWORD@+9) +14: Bitmap data BYTE*(DWORD@+9)
//-- 16bpp bitmap data header --// //-- 16bpp zMap data header --//
+0: Width WORD +0: Width WORD
+2: Height WORD +2: Height WORD
+4: Pitch/2 WORD +4: Pitch/2 WORD
@@ -62,6 +62,16 @@ Type Meaning/comments
+12: Unknown (80) WORD +12: Unknown (80) WORD
+14: Bitmap data BYTE*(DWORD@+9) +14: Bitmap data BYTE*(DWORD@+9)
//-- 16bpp zMap data header full tilt --//
+0: Resolution BYTE 0=640x480, 1=800x600, 2=1024x768, -1=Load in all resolutions
+1: Width WORD
+3: Height WORD
+5: Pitch/2 WORD
+7: Unknown (0) DWORD
+11: Unknown (0) WORD
+13: Unknown (80) WORD
+15: Bitmap data BYTE*(DWORD@+9)
//-- Pinball 3D remarkable groups --// //-- Pinball 3D remarkable groups --//

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-2021 Andrey Muzychenko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

40
README.md Normal file
View File

@@ -0,0 +1,40 @@
# SpaceCadetPinball
**Summary:** Reverse engineering of `3D Pinball for Windows Space Cadet`, a game bundled with Windows.
**How to play:** Place compiled exe into a folder containing original game resources (not included).\
Supports data files from Windows and Full Tilt versions of the game.
\
\
\
\
\
\
**Source:**
* `pinball.exe` from `Windows XP` (SHA-1 `2A5B525E0F631BB6107639E2A69DF15986FB0D05`) and its public PDB
* `CADET.EXE` 32bit version from `Full Tilt! Pinball` (SHA-1 `3F7B5699074B83FD713657CD94671F2156DBEDC4`)
**Tools used:** `Ghidra`, `Ida`, `Visual Studio`
**What was done:**
* All structures were populated, globals and locals named.
* All subs were decompiled, C pseudo code was converted to compilable C++. Loose (namespace?) subs were assigned to classes.
**Compiling:**\
Project uses `C++11` features and depends on Windows libs.\
Compile with Visual Studio; tested with 2017 and 2019.
**Plans:**
* ~~Decompile original game~~
* ~~Resizable window, scaled graphics~~
* ~~Loader for high-res sprites from CADET.DAT~~
* Misc features of Full Tilt: 3 music tracs, multiball, centered textboxes, etc.
* Maybe: cross-platform port
* Needs UI framework with menu bar and dialog windows, like QT or Avalonia
* Needs a way play sounds and midi
* Maybe x2: support for other two tables
* Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched
**On 64-bit bug that killed the game:**\
I did not find it, decompiled game worked in x64 mode on the first try.\
It was either lost in decompilation or introduced in x64 port/not present in x86 build.\
Based on public description of the bug (no ball collision), I guess that the bug was in `TEdgeManager::TestGridBox`

View File

@@ -1,6 +1,8 @@
#include "pch.h" #include "pch.h"
#include "Sound.h" #include "Sound.h"
#include "pb.h"
#include "pinball.h" #include "pinball.h"
#include "WaveMix.h" #include "WaveMix.h"
#include "winmain.h" #include "winmain.h"
@@ -45,7 +47,9 @@ int Sound::Init(HINSTANCE hInstance, int voices, void (* someFuncPtr)(int, MIXWA
} }
else else
{ {
MessageBoxA(winmain::hwnd_frame, pinball::get_rc_string(42, 0), pinball::WindowName, 0x2000u); /*FT does not have the file, defaults work OK*/
if (!pb::FullTiltMode)
MessageBoxA(winmain::hwnd_frame, pinball::get_rc_string(42, 0), "", 0x2000u);
} }
WndClass.style = 0; WndClass.style = 0;
@@ -143,7 +147,7 @@ void Sound::Close()
} }
} }
void Sound::PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, __int16 loops) void Sound::PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, int16_t loops)
{ {
MIXPLAYPARAMS mixParams{}; MIXPLAYPARAMS mixParams{};

View File

@@ -10,7 +10,7 @@ public:
static void Activate(); static void Activate();
static void Deactivate(); static void Deactivate();
static void Close(); static void Close();
static void PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, __int16 loops); static void PlaySound(MIXWAVE* wavePtr, int minChannel, int maxChannel, unsigned int dwFlags, int16_t loops);
static MIXWAVE* LoadWaveFile(LPCSTR lpName); static MIXWAVE* LoadWaveFile(LPCSTR lpName);
static void FreeSound(MIXWAVE* wave); static void FreeSound(MIXWAVE* wave);
static void Flush(int channelFrom, int channelTo); static void Flush(int channelFrom, int channelTo);

View File

@@ -16,21 +16,21 @@
#include "winmain.h" #include "winmain.h"
int main() int main()
{ {
{ {
// Testing with UI // Testing with UI
char cmdLine[1]{}; char cmdLine[1]{};
WinMain(GetModuleHandleA(nullptr), 0, cmdLine, 10); WinMain(GetModuleHandleA(nullptr), nullptr, cmdLine, 10);
return 0; return 0;
} }
std::cout << "Hello World!\n";
gdrv::init(0, 0);
auto dib = gdrv::DibCreate(8, 1, 1);
gdrv::DibSetUsage(dib, 0, 1);
objlist_class d = objlist_class(2, 4); std::cout << "Hello World!\n";
for (int i = 0; i < 100; i++) gdrv::init(nullptr, nullptr);
auto dib = gdrv::DibCreate(8, 1, 1);
gdrv::DibSetUsage(dib, nullptr, 1);
auto d = objlist_class<void>(2, 4);
for (size_t i = 0; i < 100; i++)
{ {
d.Add((void*)i); d.Add((void*)i);
} }

View File

@@ -88,6 +88,17 @@ BEGIN
MENUITEM "&Music", Menu1_Music MENUITEM "&Music", Menu1_Music
MENUITEM SEPARATOR MENUITEM SEPARATOR
MENUITEM "P&layer Controls...\tF8", Menu1_Player_Controls MENUITEM "P&layer Controls...\tF8", Menu1_Player_Controls
POPUP "Table &Resolution"
BEGIN
MENUITEM "Use &Maximum Resolution", Menu1_MaximumResolution
MENUITEM "&640 x 480", Menu1_640x480
MENUITEM "&800 x 600", Menu1_800x600
MENUITEM "&1024 x 768", Menu1_1024x768
END
POPUP "&Window"
BEGIN
MENUITEM "&Uniform Scaling", Menu1_WindowUniformScale
END
END END
POPUP "&Help" POPUP "&Help"
BEGIN BEGIN
@@ -342,7 +353,7 @@ END
// Bitmap // Bitmap
// //
splash_bitmap BITMAP "splash_bitmap.bmp" SPLASH_BITMAP BITMAP "splash_bitmap.bmp"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@@ -587,6 +598,17 @@ BEGIN
IDS_STRING289 "255 255 255 (R G B default font color)" IDS_STRING289 "255 255 255 (R G B default font color)"
END END
STRINGTABLE
BEGIN
2030 "Use &Maximum Resolution (640 x 480)"
2031 "Use &Maximum Resolution (800 x 600)"
END
STRINGTABLE
BEGIN
2032 "Use &Maximum Resolution (1024 x 768)"
END
#endif // English (United States) resources #endif // English (United States) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@@ -23,32 +23,32 @@
<ProjectGuid>{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}</ProjectGuid> <ProjectGuid>{F7B78CC7-6984-4F79-9486-ABCF87DF9F06}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>SpaceCadetPinball</RootNamespace> <RootNamespace>SpaceCadetPinball</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet> <CharacterSet>NotSet</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet> <CharacterSet>NotSet</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet> <CharacterSet>NotSet</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet> <CharacterSet>NotSet</CharacterSet>
</PropertyGroup> </PropertyGroup>
@@ -94,6 +94,7 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<BufferSecurityCheck>true</BufferSecurityCheck> <BufferSecurityCheck>true</BufferSecurityCheck>
<PreprocessToFile>false</PreprocessToFile> <PreprocessToFile>false</PreprocessToFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@@ -110,6 +111,7 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@@ -128,9 +130,10 @@
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -148,9 +151,10 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -219,7 +223,6 @@
<ClInclude Include="TTimer.h" /> <ClInclude Include="TTimer.h" />
<ClInclude Include="TTripwire.h" /> <ClInclude Include="TTripwire.h" />
<ClInclude Include="TWall.h" /> <ClInclude Include="TWall.h" />
<ClInclude Include="TZmapList.h" />
<ClInclude Include="WaveMix.h" /> <ClInclude Include="WaveMix.h" />
<ClInclude Include="winmain.h" /> <ClInclude Include="winmain.h" />
<ClInclude Include="zdrv.h" /> <ClInclude Include="zdrv.h" />
@@ -234,7 +237,6 @@
<ClCompile Include="memory.cpp" /> <ClCompile Include="memory.cpp" />
<ClCompile Include="midi.cpp" /> <ClCompile Include="midi.cpp" />
<ClCompile Include="nudge.cpp" /> <ClCompile Include="nudge.cpp" />
<ClCompile Include="objlist_class.cpp" />
<ClCompile Include="options.cpp" /> <ClCompile Include="options.cpp" />
<ClCompile Include="partman.cpp" /> <ClCompile Include="partman.cpp" />
<ClCompile Include="pb.cpp" /> <ClCompile Include="pb.cpp" />

View File

@@ -81,9 +81,6 @@
<ClInclude Include="TTimer.h"> <ClInclude Include="TTimer.h">
<Filter>Header Files\TPinballComponent</Filter> <Filter>Header Files\TPinballComponent</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="TZmapList.h">
<Filter>Header Files\TPinballComponent</Filter>
</ClInclude>
<ClInclude Include="memory.h"> <ClInclude Include="memory.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@@ -236,9 +233,6 @@
<ClCompile Include="SpaceCadetPinball.cpp"> <ClCompile Include="SpaceCadetPinball.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="objlist_class.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="partman.cpp"> <ClCompile Include="partman.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>

View File

@@ -2,17 +2,19 @@
#include "TBall.h" #include "TBall.h"
#include "fullscrn.h"
#include "loader.h" #include "loader.h"
#include "maths.h" #include "maths.h"
#include "objlist_class.h" #include "objlist_class.h"
#include "pb.h"
#include "proj.h" #include "proj.h"
#include "render.h" #include "render.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false) TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
{ {
visualStruct visual{}; visualStruct visual{};
char ballGroupName[10]{"ball"};
TimeNow = 0.0; TimeNow = 0.0;
RayMaxDistance = 0.0; RayMaxDistance = 0.0;
@@ -30,8 +32,13 @@ TBall::TBall(TPinballTable* table) : TPinballComponent(table, -1, false)
Position.X = 0.0; Position.X = 0.0;
Position.Y = 0.0; Position.Y = 0.0;
ListBitmap = new TZmapList(0, 4); ListBitmap = new objlist_class<gdrv_bitmap8>(0, 4);
auto groupIndex = loader::query_handle("ball");
/*Full tilt: ball is ballN, where N[0,2] resolution*/
if (pb::FullTiltMode)
ballGroupName[4] = '0' + fullscrn::GetResolution();
auto groupIndex = loader::query_handle(ballGroupName);
Offset = *loader::query_float_attribute(groupIndex, 0, 500); Offset = *loader::query_float_attribute(groupIndex, 0, 500);
auto visualCount = loader::query_visual_states(groupIndex); auto visualCount = loader::query_visual_states(groupIndex);
auto index = 0; auto index = 0;
@@ -73,12 +80,12 @@ void TBall::Repaint()
auto zArrPtr = VisualZArray; auto zArrPtr = VisualZArray;
int index; int index;
for (index = 0; index < ListBitmap->Count() - 1; ++index, zArrPtr++) for (index = 0; index < ListBitmap->GetCount() - 1; ++index, zArrPtr++)
{ {
if (*zArrPtr <= zDepth) break; if (*zArrPtr <= zDepth) break;
} }
auto bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(index)); auto bmp = ListBitmap->Get(index);
render::ball_set( render::ball_set(
RenderSprite, RenderSprite,
bmp, bmp,

View File

@@ -4,9 +4,9 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "timer.h" #include "timer.h"
#include "TZmapList.h"
TBlocker::TBlocker(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) TBlocker::TBlocker(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true)
{ {
@@ -46,7 +46,7 @@ int TBlocker::Message(int code, float value)
case 52: case 52:
ActiveFlag = 1; ActiveFlag = 1;
loader::play_sound(SoundIndex4); loader::play_sound(SoundIndex4);
render::sprite_set_bitmap(RenderSprite, static_cast<gdrv_bitmap8*>(ListBitmap->Get(0))); render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
break; break;
case 59: case 59:
break; break;
@@ -57,7 +57,7 @@ int TBlocker::Message(int code, float value)
timer::kill(Timer); timer::kill(Timer);
float timerTime; float timerTime;
if (value <= 0.0) if (value <= 0.0f)
timerTime = 0.0; timerTime = 0.0;
else else
timerTime = value; timerTime = value;

View File

@@ -4,10 +4,10 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TBumper::TBumper(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) TBumper::TBumper(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true)
{ {
@@ -29,8 +29,8 @@ int TBumper::Message(int code, float value)
case 11: case 11:
{ {
auto nextBmp = static_cast<int>(floor(value)); auto nextBmp = static_cast<int>(floor(value));
if (2 * nextBmp > ListBitmap->Count() - 1) if (2 * nextBmp > ListBitmap->GetCount() - 1)
nextBmp = (ListBitmap->Count() - 1) / 2; nextBmp = (ListBitmap->GetCount() - 1) / 2;
if (nextBmp < 0) if (nextBmp < 0)
nextBmp = 0; nextBmp = 0;
if (nextBmp != BmpIndex) if (nextBmp != BmpIndex)
@@ -48,7 +48,7 @@ int TBumper::Message(int code, float value)
case 12: case 12:
{ {
auto nextBmp = BmpIndex + 1; auto nextBmp = BmpIndex + 1;
auto maxBmp = ListBitmap->Count() - 1; auto maxBmp = ListBitmap->GetCount() - 1;
if (2 * nextBmp > maxBmp) if (2 * nextBmp > maxBmp)
nextBmp = maxBmp / 2; nextBmp = maxBmp / 2;
TBumper::Message(11, static_cast<float>(nextBmp)); TBumper::Message(11, static_cast<float>(nextBmp));
@@ -124,8 +124,8 @@ int TBumper::get_scoring(int index)
void TBumper::TimerExpired(int timerId, void* caller) void TBumper::TimerExpired(int timerId, void* caller)
{ {
auto bump = static_cast<TBumper*>(caller); auto bump = static_cast<TBumper*>(caller);
auto bmp = static_cast<gdrv_bitmap8*>(bump->ListBitmap->Get(bump->BmpIndex * 2)); auto bmp = bump->ListBitmap->Get(bump->BmpIndex * 2);
auto zMap = static_cast<zmap_header_type*>(bump->ListZMap->Get(bump->BmpIndex * 2)); auto zMap = bump->ListZMap->Get(bump->BmpIndex * 2);
bump->Timer = 0; bump->Timer = 0;
render::sprite_set( render::sprite_set(
bump->RenderSprite, bump->RenderSprite,
@@ -139,8 +139,8 @@ void TBumper::TimerExpired(int timerId, void* caller)
void TBumper::Fire() void TBumper::Fire()
{ {
int bmpIndex = 2 * BmpIndex + 1; int bmpIndex = 2 * BmpIndex + 1;
auto bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(bmpIndex)); auto bmp = ListBitmap->Get(bmpIndex);
auto zMap = static_cast<zmap_header_type*>(ListZMap->Get(bmpIndex)); auto zMap = ListZMap->Get(bmpIndex);
render::sprite_set( render::sprite_set(
RenderSprite, RenderSprite,
bmp, bmp,

View File

@@ -12,7 +12,7 @@ TCollisionComponent::TCollisionComponent(TPinballTable* table, int groupIndex, b
{ {
visualStruct visual{}; visualStruct visual{};
EdgeList = new objlist_class(4, 4); EdgeList = new objlist_class<TEdgeSegment>(4, 4);
ActiveFlag = 1; ActiveFlag = 1;
if (GroupName != nullptr) if (GroupName != nullptr)
UnusedBaseFlag = 1; UnusedBaseFlag = 1;
@@ -42,9 +42,9 @@ TCollisionComponent::TCollisionComponent(TPinballTable* table, int groupIndex, b
TCollisionComponent::~TCollisionComponent() TCollisionComponent::~TCollisionComponent()
{ {
for (TEdgeSegment* edge; EdgeList->Count() > 0;) for (TEdgeSegment* edge; EdgeList->GetCount() > 0;)
{ {
edge = static_cast<TEdgeSegment*>(EdgeList->Get(0)); edge = EdgeList->Get(0);
EdgeList->Delete(edge); EdgeList->Delete(edge);
delete edge; delete edge;
} }
@@ -54,9 +54,9 @@ TCollisionComponent::~TCollisionComponent()
void TCollisionComponent::port_draw() void TCollisionComponent::port_draw()
{ {
for (int index = EdgeList->Count() - 1; index >= 0; index--) for (int index = EdgeList->GetCount() - 1; index >= 0; index--)
{ {
static_cast<TEdgeSegment*>(EdgeList->Get(index))->port_draw(); EdgeList->Get(index)->port_draw();
} }
} }
@@ -70,7 +70,7 @@ int TCollisionComponent::DefaultCollision(TBall* ball, vector_type* nextPosition
auto projSpeed = maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, Threshold, Boost); auto projSpeed = maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, Threshold, Boost);
if (projSpeed <= Threshold) if (projSpeed <= Threshold)
{ {
if (projSpeed > 0.2) if (projSpeed > 0.2f)
{ {
if (SoftHitSoundId) if (SoftHitSoundId)
loader::play_sound(SoftHitSoundId); loader::play_sound(SoftHitSoundId);
@@ -92,7 +92,7 @@ void TCollisionComponent::Collision(TBall* ball, vector_type* nextPosition, vect
maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, 1000000000.0, 0.0); maths::basic_collision(ball, nextPosition, direction, Elasticity, Smoothness, 1000000000.0, 0.0);
return; return;
} }
double projSpeed = maths::basic_collision( auto projSpeed = maths::basic_collision(
ball, ball,
nextPosition, nextPosition,
direction, direction,
@@ -102,7 +102,7 @@ void TCollisionComponent::Collision(TBall* ball, vector_type* nextPosition, vect
Boost); Boost);
if (projSpeed <= Threshold) if (projSpeed <= Threshold)
{ {
if (projSpeed <= 0.2) if (projSpeed <= 0.2f)
return; return;
soundIndex = SoftHitSoundId; soundIndex = SoftHitSoundId;
} }

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "TPinballComponent.h" #include "TPinballComponent.h"
class objlist_class;
struct vector_type; struct vector_type;
class TEdgeSegment; class TEdgeSegment;
class TBall; class TBall;
@@ -9,7 +8,7 @@ class TBall;
class TCollisionComponent : public TPinballComponent class TCollisionComponent : public TPinballComponent
{ {
public: public:
objlist_class* EdgeList; objlist_class<TEdgeSegment>* EdgeList;
float Elasticity; float Elasticity;
float Smoothness; float Smoothness;
float Boost; float Boost;

View File

@@ -10,7 +10,7 @@
TComponentGroup::TComponentGroup(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false) TComponentGroup::TComponentGroup(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false)
{ {
List = new objlist_class(4, 4); List = new objlist_class<TPinballComponent>(4, 4);
Timer = 0; Timer = 0;
if (groupIndex > 0) if (groupIndex > 0)
{ {
@@ -45,14 +45,14 @@ int TComponentGroup::Message(int code, float value)
timer::kill(this->Timer); timer::kill(this->Timer);
this->Timer = 0; this->Timer = 0;
} }
if (value > 0.0) if (value > 0.0f)
this->Timer = timer::set(value, this, NotifyTimerExpired); this->Timer = timer::set(value, this, NotifyTimerExpired);
} }
else if (code <= 1007 || code > 1011 && code != 1020 && code != 1022) else if (code <= 1007 || code > 1011 && code != 1020 && code != 1022)
{ {
for (int i = 0; i < List->Count(); i++) for (int i = 0; i < List->GetCount(); i++)
{ {
static_cast<TPinballComponent*>(List->Get(i))->Message(code, value); List->Get(i)->Message(code, value);
} }
} }
return 0; return 0;

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "TPinballComponent.h" #include "TPinballComponent.h"
class objlist_class;
class TComponentGroup : class TComponentGroup :
public TPinballComponent public TPinballComponent
@@ -12,6 +11,6 @@ public:
int Message(int code, float value) override; int Message(int code, float value) override;
static void NotifyTimerExpired(int timerId, void* caller); static void NotifyTimerExpired(int timerId, void* caller);
objlist_class* List; objlist_class<TPinballComponent>* List;
int Timer; int Timer;
}; };

View File

@@ -100,7 +100,7 @@ void TDemo::Collision(TBall* ball, vector_type* nextPosition, vector_type* direc
ball->Position.Y = nextPosition->Y; ball->Position.Y = nextPosition->Y;
ball->RayMaxDistance -= coef; ball->RayMaxDistance -= coef;
switch (reinterpret_cast<int>(edge->WallValue)) switch (reinterpret_cast<size_t>(edge->WallValue))
{ {
case 1400: case 1400:
if (!FlipLeftTimer && !FlipLeftFlag) if (!FlipLeftTimer && !FlipLeftFlag)

View File

@@ -5,8 +5,8 @@
TEdgeBox::TEdgeBox() TEdgeBox::TEdgeBox()
{ {
EdgeList = new objlist_class(0, 4); EdgeList = new objlist_class<TEdgeSegment>(0, 4);
FieldList = new objlist_class(0, 1); FieldList = new objlist_class<field_effect_type>(0, 1);
} }
TEdgeBox::~TEdgeBox() TEdgeBox::~TEdgeBox()

View File

@@ -1,5 +1,9 @@
#pragma once #pragma once
class objlist_class; #include "objlist_class.h"
struct field_effect_type;
class TEdgeSegment;
class TEdgeBox class TEdgeBox
{ {
@@ -7,7 +11,7 @@ public:
TEdgeBox(); TEdgeBox();
~TEdgeBox(); ~TEdgeBox();
objlist_class* EdgeList; objlist_class<TEdgeSegment>* EdgeList;
objlist_class* FieldList; objlist_class<field_effect_type>* FieldList;
}; };

View File

@@ -64,9 +64,9 @@ int TEdgeManager::TestGridBox(int x, int y, float* distPtr, TEdgeSegment** edgeD
{ {
TEdgeBox* edgeBox = &BoxArray[x + y * MaxBoxX]; TEdgeBox* edgeBox = &BoxArray[x + y * MaxBoxX];
TEdgeSegment** edgePtr = &EdgeArray[edgeIndex]; TEdgeSegment** edgePtr = &EdgeArray[edgeIndex];
for (auto index = edgeBox->EdgeList->Count() - 1; index >= 0; --index) for (auto index = edgeBox->EdgeList->GetCount() - 1; index >= 0; --index)
{ {
auto edge = static_cast<TEdgeSegment*>(edgeBox->EdgeList->Get(index)); auto edge = edgeBox->EdgeList->Get(index);
if (!edge->ProcessedFlag && *edge->ActiveFlag && (edge->CollisionGroup & ray->FieldFlag)) if (!edge->ProcessedFlag && *edge->ActiveFlag && (edge->CollisionGroup & ray->FieldFlag))
{ {
if (!ball->already_hit(edge)) if (!ball->already_hit(edge))
@@ -94,9 +94,9 @@ void TEdgeManager::FieldEffects(TBall* ball, vector_type* dstVec)
TEdgeBox* edgeBox = &BoxArray[box_x(ball->Position.X) + box_y(ball->Position.Y) * TEdgeBox* edgeBox = &BoxArray[box_x(ball->Position.X) + box_y(ball->Position.Y) *
MaxBoxX]; MaxBoxX];
for (int index = edgeBox->FieldList->Count() - 1; index >= 0; --index) for (int index = edgeBox->FieldList->GetCount() - 1; index >= 0; --index)
{ {
auto field = static_cast<field_effect_type*>(edgeBox->FieldList->Get(index)); auto field = edgeBox->FieldList->Get(index);
if (*field->Flag2Ptr && ball->FieldFlag & field->Mask) if (*field->Flag2Ptr && ball->FieldFlag & field->Mask)
{ {
if (field->CollisionComp->FieldEffect(ball, &vec)) if (field->CollisionComp->FieldEffect(ball, &vec))

View File

@@ -19,7 +19,7 @@ void TEdgeSegment::port_draw()
} }
TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* collComp, char* activeFlagPtr, TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* collComp, char* activeFlagPtr,
unsigned int collisionGroup, float offset, int wallValue) unsigned int collisionGroup, float offset, size_t wallValue)
{ {
vector_type center{}, start{}, end{}, prevCenter{}, vec1{}, vec2{}, dstVec{}; vector_type center{}, start{}, end{}, prevCenter{}, vec1{}, vec2{}, dstVec{};
TEdgeSegment* edge = nullptr; TEdgeSegment* edge = nullptr;
@@ -87,15 +87,15 @@ TEdgeSegment* TEdgeSegment::install_wall(float* floatArr, TCollisionComponent* c
center.X = centerX1; center.X = centerX1;
center.Y = centerY1; center.Y = centerY1;
if (offset != 0.0) if (offset != 0.0f)
{ {
vec1.X = centerX1 - prevCenter.X; vec1.X = centerX1 - prevCenter.X;
vec1.Y = center.Y - prevCenter.Y; vec1.Y = center.Y - prevCenter.Y;
vec2.X = centerX2 - centerX1; vec2.X = centerX2 - centerX1;
vec2.Y = centerY2 - center.Y; vec2.Y = centerY2 - center.Y;
maths::cross(&vec1, &vec2, &dstVec); maths::cross(&vec1, &vec2, &dstVec);
if (dstVec.Z > 0.0 && offset > 0.0 || if (dstVec.Z > 0.0f && offset > 0.0f ||
dstVec.Z < 0.0 && offset < 0.0) dstVec.Z < 0.0f && offset < 0.0f)
{ {
float radius = offset * 1.001f; float radius = offset * 1.001f;
auto circle = new TCircle(collComp, activeFlagPtr, collisionGroup, &center, radius); auto circle = new TCircle(collComp, activeFlagPtr, collisionGroup, &center, radius);

View File

@@ -28,5 +28,5 @@ public:
virtual float FindCollisionDistance(ray_type* ray) = 0; virtual float FindCollisionDistance(ray_type* ray) = 0;
static TEdgeSegment* install_wall(float* floatArr, TCollisionComponent* collComp, char* activeFlagPtr, static TEdgeSegment* install_wall(float* floatArr, TCollisionComponent* collComp, char* activeFlagPtr,
unsigned int collisionGroup, float offset, int wallValue); unsigned int collisionGroup, float offset, size_t wallValue);
}; };

View File

@@ -10,7 +10,6 @@
#include "timer.h" #include "timer.h"
#include "TLine.h" #include "TLine.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TFlagSpinner::TFlagSpinner(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false) TFlagSpinner::TFlagSpinner(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false)
{ {
@@ -19,7 +18,7 @@ TFlagSpinner::TFlagSpinner(TPinballTable* table, int groupIndex) : TCollisionCom
Timer = 0; Timer = 0;
loader::query_visual(groupIndex, 0, &visual); loader::query_visual(groupIndex, 0, &visual);
end.X = *visual.FloatArr; end.X = visual.FloatArr[0];
end.Y = visual.FloatArr[1]; end.Y = visual.FloatArr[1];
start.X = visual.FloatArr[2]; start.X = visual.FloatArr[2];
start.Y = visual.FloatArr[3]; start.Y = visual.FloatArr[3];
@@ -62,8 +61,8 @@ int TFlagSpinner::Message(int code, float value)
Timer = 0; Timer = 0;
} }
BmpIndex = 0; BmpIndex = 0;
auto bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(0)); auto bmp = ListBitmap->Get(0);
auto zMap = static_cast<zmap_header_type*>(ListZMap->Get(0)); auto zMap = ListZMap->Get(0);
render::sprite_set( render::sprite_set(
RenderSprite, RenderSprite,
bmp, bmp,
@@ -83,7 +82,7 @@ void TFlagSpinner::Collision(TBall* ball, vector_type* nextPosition, vector_type
ball->not_again(edge); ball->not_again(edge);
SpinDirection = 2 * (PrevCollider != edge) - 1; SpinDirection = 2 * (PrevCollider != edge) - 1;
if (ball->Speed == 0.0) if (ball->Speed == 0.0f)
Speed = MinSpeed; Speed = MinSpeed;
else else
Speed = ball->Speed * 20.0f; Speed = ball->Speed * 20.0f;
@@ -109,7 +108,7 @@ void TFlagSpinner::NextFrame()
{ {
BmpIndex += SpinDirection; BmpIndex += SpinDirection;
int bmpIndex = BmpIndex; int bmpIndex = BmpIndex;
int bmpCount = ListBitmap->Count(); int bmpCount = ListBitmap->GetCount();
if (bmpIndex >= bmpCount) if (bmpIndex >= bmpCount)
BmpIndex = 0; BmpIndex = 0;
else if (bmpIndex < 0) else if (bmpIndex < 0)
@@ -124,8 +123,8 @@ void TFlagSpinner::NextFrame()
control::handler(62, this); control::handler(62, this);
} }
auto bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(BmpIndex)); auto bmp = ListBitmap->Get(BmpIndex);
auto zMap = static_cast<zmap_header_type*>(ListZMap->Get(BmpIndex)); auto zMap = ListZMap->Get(BmpIndex);
render::sprite_set( render::sprite_set(
RenderSprite, RenderSprite,
bmp, bmp,

View File

@@ -4,11 +4,11 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "pb.h" #include "pb.h"
#include "render.h" #include "render.h"
#include "TFlipperEdge.h" #include "TFlipperEdge.h"
#include "timer.h" #include "timer.h"
#include "TZmapList.h"
TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false) TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, false)
{ {
@@ -21,12 +21,16 @@ TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(t
Timer = 0; Timer = 0;
Smoothness = visual.Smoothness; Smoothness = visual.Smoothness;
auto floatArr = loader::query_float_attribute(groupIndex, 0, 803); auto collMult = *loader::query_float_attribute(groupIndex, 0, 803);
auto floatArr2 = loader::query_float_attribute(groupIndex, 0, 805); auto bmpCoef2 = *loader::query_float_attribute(groupIndex, 0, 805);
auto floatArr3 = loader::query_float_attribute(groupIndex, 0, 804); auto bmpCoef1 = *loader::query_float_attribute(groupIndex, 0, 804);
auto collMult = *floatArr;
auto bmpCoef2 = *floatArr2; /*Full tilt hack: different flipper speed*/
auto bmpCoef1 = *floatArr3; if (pb::FullTiltMode)
{
bmpCoef2 = 0.08f;
bmpCoef1 = 0.04f;
}
auto vecT2 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 802)); auto vecT2 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 802));
auto vecT1 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 801)); auto vecT1 = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 801));
auto origin = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 800)); auto origin = reinterpret_cast<vector_type*>(loader::query_float_attribute(groupIndex, 0, 800));
@@ -47,8 +51,8 @@ TFlipper::TFlipper(TPinballTable* table, int groupIndex) : TCollisionComponent(t
FlipperEdge = flipperEdge; FlipperEdge = flipperEdge;
if (flipperEdge) if (flipperEdge)
{ {
BmpCoef1 = flipperEdge->BmpCoef1 / static_cast<float>(ListBitmap->Count() - 1); BmpCoef1 = flipperEdge->BmpCoef1 / static_cast<float>(ListBitmap->GetCount() - 1);
BmpCoef2 = flipperEdge->BmpCoef2 / static_cast<float>(ListBitmap->Count() - 1); BmpCoef2 = flipperEdge->BmpCoef2 / static_cast<float>(ListBitmap->GetCount() - 1);
} }
BmpIndex = 0; BmpIndex = 0;
InputTime = 0.0; InputTime = 0.0;
@@ -93,7 +97,7 @@ int TFlipper::Message(int code, float value)
{ {
auto v10 = value - FlipperEdge->InputTime; auto v10 = value - FlipperEdge->InputTime;
timerTime = v10 - floor(v10 / TimerTime) * TimerTime; timerTime = v10 - floor(v10 / TimerTime) * TimerTime;
if (timerTime < 0.0) if (timerTime < 0.0f)
timerTime = 0.0; timerTime = 0.0;
} }
else else
@@ -137,7 +141,7 @@ void TFlipper::TimerExpired(int timerId, void* caller)
bool bmpIndexOutOfBounds = false; bool bmpIndexOutOfBounds = false;
auto bmpIndexAdvance = static_cast<int>(floor((pb::time_now - flip->InputTime) / flip->TimerTime + 0.5f)); auto bmpIndexAdvance = static_cast<int>(floor((pb::time_now - flip->InputTime) / flip->TimerTime + 0.5f));
int bmpCount = flip->ListBitmap->Count(); int bmpCount = flip->ListBitmap->GetCount();
if (bmpIndexAdvance > bmpCount) if (bmpIndexAdvance > bmpCount)
bmpIndexAdvance = bmpCount; bmpIndexAdvance = bmpCount;
if (bmpIndexAdvance < 0) if (bmpIndexAdvance < 0)
@@ -149,7 +153,7 @@ void TFlipper::TimerExpired(int timerId, void* caller)
if (flip->MessageField == 1) if (flip->MessageField == 1)
{ {
flip->BmpIndex += bmpIndexAdvance; flip->BmpIndex += bmpIndexAdvance;
int countSub1 = flip->ListBitmap->Count() - 1; int countSub1 = flip->ListBitmap->GetCount() - 1;
if (flip->BmpIndex >= countSub1) if (flip->BmpIndex >= countSub1)
{ {
flip->BmpIndex = countSub1; flip->BmpIndex = countSub1;
@@ -177,8 +181,8 @@ void TFlipper::TimerExpired(int timerId, void* caller)
timer = timer::set(flip->TimerTime, flip, TimerExpired); timer = timer::set(flip->TimerTime, flip, TimerExpired);
flip->Timer = timer; flip->Timer = timer;
auto bmp = static_cast<gdrv_bitmap8*>(flip->ListBitmap->Get(flip->BmpIndex)); auto bmp = flip->ListBitmap->Get(flip->BmpIndex);
auto zMap = static_cast<zmap_header_type*>(flip->ListZMap->Get(flip->BmpIndex)); auto zMap = flip->ListZMap->Get(flip->BmpIndex);
render::sprite_set( render::sprite_set(
flip->RenderSprite, flip->RenderSprite,
bmp, bmp,

View File

@@ -48,7 +48,7 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
AngleMax = acos(maths::DotProduct(&vecDir1, &vecDir2)); AngleMax = acos(maths::DotProduct(&vecDir1, &vecDir2));
maths::cross(&vecDir1, &vecDir2, &crossProd); maths::cross(&vecDir1, &vecDir2, &crossProd);
if (crossProd.Z < 0.0) if (crossProd.Z < 0.0f)
AngleMax = -AngleMax; AngleMax = -AngleMax;
FlipperFlag = 0; FlipperFlag = 0;
Angle1 = 0.0; Angle1 = 0.0;
@@ -67,7 +67,7 @@ TFlipperEdge::TFlipperEdge(TCollisionComponent* collComp, char* activeFlag, unsi
B2Src.X = dirY1 * CircleT1Radius + vecT1->X; B2Src.X = dirY1 * CircleT1Radius + vecT1->X;
B2Src.Y = dirX1 * CircleT1Radius + vecT1->Y; B2Src.Y = dirX1 * CircleT1Radius + vecT1->Y;
if (AngleMax < 0.0) if (AngleMax < 0.0f)
{ {
maths::vswap(&A1Src, &B1Src); maths::vswap(&A1Src, &B1Src);
maths::vswap(&A2Src, &B2Src); maths::vswap(&A2Src, &B2Src);
@@ -122,7 +122,7 @@ float TFlipperEdge::FindCollisionDistance(ray_type* ray)
srcRay.MaxDistance = ogRay->MaxDistance; srcRay.MaxDistance = ogRay->MaxDistance;
srcRay.Origin = ogRay->Origin; srcRay.Origin = ogRay->Origin;
auto distance = maths::distance_to_flipper(&srcRay, &dstRay); auto distance = maths::distance_to_flipper(&srcRay, &dstRay);
if (distance == 0.0) if (distance == 0.0f)
{ {
NextBallPosition = dstRay.Origin; NextBallPosition = dstRay.Origin;
NextBallPosition.X -= srcRay.Direction.X * 1e-05f; NextBallPosition.X -= srcRay.Direction.X * 1e-05f;
@@ -167,14 +167,14 @@ float TFlipperEdge::FindCollisionDistance(ray_type* ray)
srcRay.Origin.X = ogRay->Origin.X - srcRay.Direction.X * 5.0f; srcRay.Origin.X = ogRay->Origin.X - srcRay.Direction.X * 5.0f;
srcRay.Origin.Y = ogRay->Origin.Y - srcRay.Direction.Y * 5.0f; srcRay.Origin.Y = ogRay->Origin.Y - srcRay.Direction.Y * 5.0f;
srcRay.MaxDistance = ogRay->MaxDistance + 10.0f; srcRay.MaxDistance = ogRay->MaxDistance + 10.0f;
if (maths::distance_to_flipper(&srcRay, &dstRay) >= 1e+09) if (maths::distance_to_flipper(&srcRay, &dstRay) >= 1e+09f)
{ {
srcRay.Direction.X = RotOrigin.X - ogRay->Origin.X; srcRay.Direction.X = RotOrigin.X - ogRay->Origin.X;
srcRay.Direction.Y = RotOrigin.Y - ogRay->Origin.Y; srcRay.Direction.Y = RotOrigin.Y - ogRay->Origin.Y;
maths::normalize_2d(&srcRay.Direction); maths::normalize_2d(&srcRay.Direction);
srcRay.Origin.X = ogRay->Origin.X - srcRay.Direction.X * 5.0f; srcRay.Origin.X = ogRay->Origin.X - srcRay.Direction.X * 5.0f;
srcRay.Origin.Y = ogRay->Origin.Y - srcRay.Direction.Y * 5.0f; srcRay.Origin.Y = ogRay->Origin.Y - srcRay.Direction.Y * 5.0f;
if (maths::distance_to_flipper(&srcRay, &dstRay) >= 1e+09) if (maths::distance_to_flipper(&srcRay, &dstRay) >= 1e+09f)
{ {
return 1e+09; return 1e+09;
} }
@@ -221,7 +221,7 @@ float TFlipperEdge::FindCollisionDistance(ray_type* ray)
srcRay.Origin.X = posX - srcRay.Direction.X * 5.0f; srcRay.Origin.X = posX - srcRay.Direction.X * 5.0f;
srcRay.Origin.Y = posY - srcRay.Direction.Y * 5.0f; srcRay.Origin.Y = posY - srcRay.Direction.Y * 5.0f;
srcRay.MaxDistance = ogRay->MaxDistance + 10.0f; srcRay.MaxDistance = ogRay->MaxDistance + 10.0f;
if (maths::distance_to_flipper(&srcRay, &dstRay) >= 1e+09) if (maths::distance_to_flipper(&srcRay, &dstRay) >= 1e+09f)
{ {
NextBallPosition.X = posX; NextBallPosition.X = posX;
NextBallPosition.Y = posY; NextBallPosition.Y = posY;
@@ -252,7 +252,7 @@ float TFlipperEdge::FindCollisionDistance(ray_type* ray)
srcRay.MaxDistance = ogRay->MaxDistance + 10.0f; srcRay.MaxDistance = ogRay->MaxDistance + 10.0f;
auto distance = maths::distance_to_flipper(&srcRay, &dstRay); auto distance = maths::distance_to_flipper(&srcRay, &dstRay);
CollisionDirection = dstRay.Direction; CollisionDirection = dstRay.Direction;
if (distance >= 1e+09) if (distance >= 1e+09f)
{ {
return 1e+09; return 1e+09;
} }
@@ -267,7 +267,7 @@ float TFlipperEdge::FindCollisionDistance(ray_type* ray)
srcRay.Origin = ogRay->Origin; srcRay.Origin = ogRay->Origin;
srcRay.MaxDistance = rayMaxDistance; srcRay.MaxDistance = rayMaxDistance;
auto distance = maths::distance_to_flipper(&srcRay, &dstRay); auto distance = maths::distance_to_flipper(&srcRay, &dstRay);
if (distance < 1e+09) if (distance < 1e+09f)
{ {
NextBallPosition = dstRay.Origin; NextBallPosition = dstRay.Origin;
NextBallPosition.X -= srcRay.Direction.X * 1e-05f; NextBallPosition.X -= srcRay.Direction.X * 1e-05f;
@@ -276,11 +276,11 @@ float TFlipperEdge::FindCollisionDistance(ray_type* ray)
if (FlipperFlag == 2) if (FlipperFlag == 2)
{ {
linePtr = &lineB.PerpendicularL; linePtr = &lineB.PerpendicularL;
CollisionFlag1 = AngleMax <= 0.0; CollisionFlag1 = AngleMax <= 0.0f;
} }
else else
{ {
CollisionFlag1 = AngleMax > 0.0; CollisionFlag1 = AngleMax > 0.0f;
linePtr = &lineA.PerpendicularL; linePtr = &lineA.PerpendicularL;
} }
CollisionLinePerp = *linePtr; CollisionLinePerp = *linePtr;
@@ -310,12 +310,12 @@ void TFlipperEdge::EdgeCollision(TBall* ball, float coef)
float dx = NextBallPosition.X - RotOrigin.X; float dx = NextBallPosition.X - RotOrigin.X;
float dy = NextBallPosition.Y - RotOrigin.Y; float dy = NextBallPosition.Y - RotOrigin.Y;
float distance = dy * dy + dx * dx; float distance = dy * dy + dx * dx;
if (circlebase.RadiusSq * 1.01 < distance) if (circlebase.RadiusSq * 1.01f < distance)
{ {
float v11; float v11;
float v20 = sqrt(distance / DistanceDivSq) * (fabs(AngleMax) / AngleMult); float v20 = sqrt(distance / DistanceDivSq) * (fabs(AngleMax) / AngleMult);
float dot1 = maths::DotProduct(&CollisionLinePerp, &CollisionDirection); float dot1 = maths::DotProduct(&CollisionLinePerp, &CollisionDirection);
if (dot1 >= 0.0) if (dot1 >= 0.0f)
v11 = dot1 * v20; v11 = dot1 * v20;
else else
v11 = 0.0; v11 = 0.0;
@@ -323,7 +323,7 @@ void TFlipperEdge::EdgeCollision(TBall* ball, float coef)
} }
} }
float threshold = boost <= 0.0 ? 1000000000.0f : -1.0f; float threshold = boost <= 0.0f ? 1000000000.0f : -1.0f;
maths::basic_collision( maths::basic_collision(
ball, ball,
&NextBallPosition, &NextBallPosition,
@@ -339,7 +339,7 @@ void TFlipperEdge::EdgeCollision(TBall* ball, float coef)
float dx = NextBallPosition.X - RotOrigin.X; float dx = NextBallPosition.X - RotOrigin.X;
float dy = NextBallPosition.Y - RotOrigin.Y; float dy = NextBallPosition.Y - RotOrigin.Y;
float distance = dy * dy + dx * dx; float distance = dy * dy + dx * dx;
if (circlebase.RadiusSq * 1.01 < distance) if (circlebase.RadiusSq * 1.01f < distance)
elasticity = (1.0f - sqrt(distance / DistanceDivSq)) * Elasticity; elasticity = (1.0f - sqrt(distance / DistanceDivSq)) * Elasticity;
else else
elasticity = Elasticity; elasticity = Elasticity;
@@ -420,10 +420,10 @@ float TFlipperEdge::flipper_angle(float timeNow)
if (!FlipperFlag) if (!FlipperFlag)
return Angle1; return Angle1;
float angle = (Angle1 - Angle2) / AngleMax * AngleMult; float angle = (Angle1 - Angle2) / AngleMax * AngleMult;
if (angle < 0.0) if (angle < 0.0f)
angle = -angle; angle = -angle;
if (angle >= 0.0000001) if (angle >= 0.0000001f)
angle = (timeNow - InputTime) / angle; angle = (timeNow - InputTime) / angle;
else else
angle = 1.0; angle = 1.0;
@@ -439,23 +439,23 @@ int TFlipperEdge::is_ball_inside(float x, float y)
vector_type testPoint{}; vector_type testPoint{};
float dx = RotOrigin.X - x; float dx = RotOrigin.X - x;
float dy = RotOrigin.Y - y; float dy = RotOrigin.Y - y;
if ((A2.X - A1.X) * (y - A1.Y) - (A2.Y - A1.Y) * (x - A1.X) >= 0.0 && if ((A2.X - A1.X) * (y - A1.Y) - (A2.Y - A1.Y) * (x - A1.X) >= 0.0f &&
(B1.X - A2.X) * (y - A2.Y) - (B1.Y - A2.Y) * (x - A2.X) >= 0.0 && (B1.X - A2.X) * (y - A2.Y) - (B1.Y - A2.Y) * (x - A2.X) >= 0.0f &&
(B2.X - B1.X) * (y - B1.Y) - (B2.Y - B1.Y) * (x - B1.X) >= 0.0 && (B2.X - B1.X) * (y - B1.Y) - (B2.Y - B1.Y) * (x - B1.X) >= 0.0f &&
(A1.X - B2.X) * (y - B2.Y) - (A1.Y - B2.Y) * (x - B2.X) >= 0.0 || (A1.X - B2.X) * (y - B2.Y) - (A1.Y - B2.Y) * (x - B2.X) >= 0.0f ||
dy * dy + dx * dx <= CirclebaseRadiusSq || dy * dy + dx * dx <= CirclebaseRadiusSq ||
(T1.Y - y) * (T1.Y - y) + (T1.X - x) * (T1.X - x) < CircleT1RadiusSq) (T1.Y - y) * (T1.Y - y) + (T1.X - x) * (T1.X - x) < CircleT1RadiusSq)
{ {
float flipperLR = AngleMax < 0.0 ? -1.0f : 1.0f; float flipperLR = AngleMax < 0.0f ? -1.0f : 1.0f;
if (FlipperFlag == 1) if (FlipperFlag == 1)
testPoint = AngleMax < 0.0 ? B1 : B2; testPoint = AngleMax < 0.0f ? B1 : B2;
else if (FlipperFlag == 2) else if (FlipperFlag == 2)
testPoint = AngleMax < 0.0 ? A2 : A1; testPoint = AngleMax < 0.0f ? A2 : A1;
else else
testPoint = T1; testPoint = T1;
if (((y - testPoint.Y) * (RotOrigin.X - testPoint.X) - if (((y - testPoint.Y) * (RotOrigin.X - testPoint.X) -
(x - testPoint.X) * (RotOrigin.Y - testPoint.Y)) * flipperLR < 0.0) (x - testPoint.X) * (RotOrigin.Y - testPoint.Y)) * flipperLR < 0.0f)
return 4; return 4;
return 5; return 5;
} }

View File

@@ -4,8 +4,8 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "TZmapList.h"
TGate::TGate(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) TGate::TGate(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true)
{ {
@@ -15,7 +15,7 @@ TGate::TGate(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
SoundIndex4 = visual.SoundIndex4; SoundIndex4 = visual.SoundIndex4;
SoundIndex3 = visual.SoundIndex3; SoundIndex3 = visual.SoundIndex3;
ActiveFlag = 1; ActiveFlag = 1;
render::sprite_set_bitmap(RenderSprite, static_cast<gdrv_bitmap8*>(ListBitmap->Get(0))); render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
control::handler(1024, this); control::handler(1024, this);
} }
@@ -32,7 +32,7 @@ int TGate::Message(int code, float value)
else if (code == 54 || code == 1024) else if (code == 54 || code == 1024)
{ {
ActiveFlag = 1; ActiveFlag = 1;
render::sprite_set_bitmap(RenderSprite, static_cast<gdrv_bitmap8*>(ListBitmap->Get(0))); render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
if (code == 54) if (code == 54)
loader::play_sound(SoundIndex4); loader::play_sound(SoundIndex4);
} }

View File

@@ -5,6 +5,7 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h" #include "objlist_class.h"
#include "pb.h"
#include "TBall.h" #include "TBall.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
@@ -19,26 +20,19 @@ THole::THole(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
MessageField = 0; MessageField = 0;
Timer = 0; Timer = 0;
BallCapturedFlag = 0; BallCapturedFlag = 0;
auto floatArr1 = loader::query_float_attribute(groupIndex, 0, 407); Unknown3 = loader::query_float_attribute(groupIndex, 0, 407, 0.25f);
if (floatArr1) GravityMult = loader::query_float_attribute(groupIndex, 0, 701, 0.2f);
Unknown3 = *floatArr1;
else
Unknown3 = 0.25;
auto floatArr2 = loader::query_float_attribute(groupIndex, 0, 701);
if (floatArr2)
GravityMult = *floatArr2;
else
GravityMult = 0.5;
GravityPull = *loader::query_float_attribute(groupIndex, 0, 305); GravityPull = *loader::query_float_attribute(groupIndex, 0, 305);
loader::query_visual(groupIndex, 0, &visual); loader::query_visual(groupIndex, 0, &visual);
Circle.Center.X = visual.FloatArr[0]; Circle.Center.X = visual.FloatArr[0];
Circle.Center.Y = visual.FloatArr[1]; Circle.Center.Y = visual.FloatArr[1];
Circle.RadiusSq = *loader::query_float_attribute(groupIndex, 0, 306) * visual.FloatArr[2]; Circle.RadiusSq = *loader::query_float_attribute(groupIndex, 0, 306) * visual.FloatArr[2];
if (Circle.RadiusSq == 0.0) if (Circle.RadiusSq == 0.0f)
Circle.RadiusSq = 0.001f; Circle.RadiusSq = 0.001f;
auto tCircle = new TCircle(this, &ActiveFlag, visual.CollisionGroup, reinterpret_cast<vector_type*>(visual.FloatArr), auto tCircle = new TCircle(this, &ActiveFlag, visual.CollisionGroup,
reinterpret_cast<vector_type*>(visual.FloatArr),
Circle.RadiusSq); Circle.RadiusSq);
if (tCircle) if (tCircle)
{ {
@@ -49,6 +43,10 @@ THole::THole(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
ZSetValue = loader::query_float_attribute(groupIndex, 0, 408)[2]; ZSetValue = loader::query_float_attribute(groupIndex, 0, 408)[2];
FieldFlag = static_cast<int>(floor(*loader::query_float_attribute(groupIndex, 0, 1304))); FieldFlag = static_cast<int>(floor(*loader::query_float_attribute(groupIndex, 0, 1304)));
/*Full tilt hack - FieldFlag should be on*/
if (pb::FullTiltMode)
FieldFlag = 1;
Circle.RadiusSq = visual.FloatArr[2] * visual.FloatArr[2]; Circle.RadiusSq = visual.FloatArr[2] * visual.FloatArr[2];
circle.RadiusSq = Circle.RadiusSq; circle.RadiusSq = Circle.RadiusSq;
circle.Center.X = Circle.Center.X; circle.Center.X = Circle.Center.X;

View File

@@ -5,10 +5,10 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "maths.h" #include "maths.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TKickback::TKickback(TPinballTable* table, int groupIndex): TCollisionComponent(table, groupIndex, true) TKickback::TKickback(TPinballTable* table, int groupIndex): TCollisionComponent(table, groupIndex, true)
{ {
@@ -66,8 +66,8 @@ void TKickback::TimerExpired(int timerId, void* caller)
loader::play_sound(kick->HardHitSoundId); loader::play_sound(kick->HardHitSoundId);
if (kick->ListBitmap) if (kick->ListBitmap)
{ {
auto bmp = static_cast<gdrv_bitmap8*>(kick->ListBitmap->Get(1)); auto bmp = kick->ListBitmap->Get(1);
auto zMap = static_cast<zmap_header_type*>(kick->ListZMap->Get(1)); auto zMap = kick->ListZMap->Get(1);
render::sprite_set( render::sprite_set(
kick->RenderSprite, kick->RenderSprite,
bmp, bmp,
@@ -80,8 +80,8 @@ void TKickback::TimerExpired(int timerId, void* caller)
{ {
if (kick->ListBitmap) if (kick->ListBitmap)
{ {
auto bmp = static_cast<gdrv_bitmap8*>(kick->ListBitmap->Get(0)); auto bmp = kick->ListBitmap->Get(0);
auto zMap = static_cast<zmap_header_type*>(kick->ListZMap->Get(0)); auto zMap = kick->ListZMap->Get(0);
render::sprite_set( render::sprite_set(
kick->RenderSprite, kick->RenderSprite,
bmp, bmp,

View File

@@ -30,10 +30,10 @@ TKickout::TKickout(TPinballTable* table, int groupIndex, bool someFlag): TCollis
SoftHitSoundId = visual.SoftHitSoundId; SoftHitSoundId = visual.SoftHitSoundId;
HardHitSoundId = visual.Kicker.HardHitSoundId; HardHitSoundId = visual.Kicker.HardHitSoundId;
Circle.Center.X = *visual.FloatArr; Circle.Center.X = visual.FloatArr[0];
Circle.Center.Y = visual.FloatArr[1]; Circle.Center.Y = visual.FloatArr[1];
Circle.RadiusSq = *loader::query_float_attribute(groupIndex, 0, 306) * visual.FloatArr[2]; Circle.RadiusSq = *loader::query_float_attribute(groupIndex, 0, 306) * visual.FloatArr[2];
if (Circle.RadiusSq == 0.0) if (Circle.RadiusSq == 0.0f)
Circle.RadiusSq = 0.001f; Circle.RadiusSq = 0.001f;
auto tCircle = new TCircle(this, &ActiveFlag, visual.CollisionGroup, auto tCircle = new TCircle(this, &ActiveFlag, visual.CollisionGroup,
reinterpret_cast<vector_type*>(visual.FloatArr), Circle.RadiusSq); reinterpret_cast<vector_type*>(visual.FloatArr), Circle.RadiusSq);
@@ -67,7 +67,7 @@ int TKickout::Message(int code, float value)
case 55: case 55:
if (KickFlag1) if (KickFlag1)
{ {
if (value < 0.0) if (value < 0.0f)
value = TimerTime1; value = TimerTime1;
Timer = timer::set(value, this, TimerExpired); Timer = timer::set(value, this, TimerExpired);
} }

View File

@@ -4,10 +4,10 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TLight::TLight(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, true) TLight::TLight(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, true)
{ {
@@ -144,13 +144,13 @@ int TLight::Message(int code, float value)
break; break;
case 11: case 11:
BmpIndex2 = static_cast<int>(floor(value)); BmpIndex2 = static_cast<int>(floor(value));
if (BmpIndex2 > ListBitmap->Count()) if (BmpIndex2 > ListBitmap->GetCount())
BmpIndex2 = ListBitmap->Count(); BmpIndex2 = ListBitmap->GetCount();
bmpIndex = 0; bmpIndex = 0;
if (BmpIndex2 < 0) if (BmpIndex2 < 0)
BmpIndex2 = 0; BmpIndex2 = 0;
Flasher.BmpArr[0] = nullptr; Flasher.BmpArr[0] = nullptr;
Flasher.BmpArr[1] = static_cast<gdrv_bitmap8*>(ListBitmap->Get(BmpIndex2)); Flasher.BmpArr[1] = ListBitmap->Get(BmpIndex2);
if (FlasherActive == 0) if (FlasherActive == 0)
{ {
if (!FlasherFlag1) if (!FlasherFlag1)
@@ -169,8 +169,8 @@ int TLight::Message(int code, float value)
break; break;
case 12: case 12:
bmpIndex = BmpIndex2 + 1; bmpIndex = BmpIndex2 + 1;
if (bmpIndex > ListBitmap->Count()) if (bmpIndex > ListBitmap->GetCount())
bmpIndex = ListBitmap->Count(); bmpIndex = ListBitmap->GetCount();
Message(11, static_cast<float>(bmpIndex)); Message(11, static_cast<float>(bmpIndex));
break; break;
case 13: case 13:
@@ -257,7 +257,7 @@ void TLight::Reset()
Flasher.Sprite = RenderSprite; Flasher.Sprite = RenderSprite;
Flasher.BmpArr[0] = nullptr; Flasher.BmpArr[0] = nullptr;
if (ListBitmap) if (ListBitmap)
Flasher.BmpArr[1] = static_cast<gdrv_bitmap8*>(ListBitmap->Get(0)); Flasher.BmpArr[1] = ListBitmap->Get(0);
Flasher.Unknown4 = 0; Flasher.Unknown4 = 0;
Flasher.Unknown3 = 0; Flasher.Unknown3 = 0;
MessageField = 0; MessageField = 0;
@@ -270,7 +270,7 @@ void TLight::schedule_timeout(float time)
if (Timer1) if (Timer1)
timer::kill(Timer1); timer::kill(Timer1);
Timer1 = 0; Timer1 = 0;
if (time > 0.0) if (time > 0.0f)
Timer1 = timer::set(time, this, TimerExpired); Timer1 = timer::set(time, this, TimerExpired);
} }

View File

@@ -18,8 +18,8 @@ TLightBargraph::TLightBargraph(TPinballTable* table, int groupIndex) : TLightGro
float* floatArr = loader::query_float_attribute(groupIndex, 0, 904); float* floatArr = loader::query_float_attribute(groupIndex, 0, 904);
if (floatArr) if (floatArr)
{ {
int count = 2 * List->Count(); int count = 2 * List->GetCount();
TimerTimeArray = reinterpret_cast<float*>(memory::allocate(count * sizeof(float))); TimerTimeArray = memory::allocate<float>(count);
if (TimerTimeArray) if (TimerTimeArray)
{ {
for (int i = 0; i < count; ++floatArr) for (int i = 0; i < count; ++floatArr)
@@ -49,7 +49,7 @@ int TLightBargraph::Message(int code, float value)
TimerBargraph = 0; TimerBargraph = 0;
} }
auto timeIndex = static_cast<int>(floor(value)); auto timeIndex = static_cast<int>(floor(value));
auto maxCount = 2 * List->Count(); auto maxCount = 2 * List->GetCount();
if (timeIndex >= maxCount) if (timeIndex >= maxCount)
timeIndex = maxCount - 1; timeIndex = maxCount - 1;
if (timeIndex >= 0) if (timeIndex >= 0)

View File

@@ -11,7 +11,7 @@
TLightGroup::TLightGroup(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false) TLightGroup::TLightGroup(TPinballTable* table, int groupIndex) : TPinballComponent(table, groupIndex, false)
{ {
List = new objlist_class(4, 4); List = new objlist_class<TLight>(4, 4);
Timer = 0; Timer = 0;
NotifyTimer = 0; NotifyTimer = 0;
Reset(); Reset();
@@ -19,10 +19,10 @@ TLightGroup::TLightGroup(TPinballTable* table, int groupIndex) : TPinballCompone
{ {
int count; int count;
Timer1TimeDefault = *loader::query_float_attribute(groupIndex, 0, 903); Timer1TimeDefault = *loader::query_float_attribute(groupIndex, 0, 903);
__int16* groupIndArr = loader::query_iattribute(groupIndex, 1027, &count); int16_t* groupIndArr = loader::query_iattribute(groupIndex, 1027, &count);
for (int index = 0; index < count; ++groupIndArr) for (int index = 0; index < count; ++groupIndArr)
{ {
auto comp = table->find_component(*groupIndArr); auto comp = dynamic_cast<TLight*>(table->find_component(*groupIndArr));
if (comp) if (comp)
List->Add(comp); List->Add(comp);
++index; ++index;
@@ -71,8 +71,8 @@ int TLightGroup::Message(int code, float value)
break; break;
case 24: case 24:
{ {
auto count = List->Count(); auto count = List->GetCount();
auto lastLight = static_cast<TLight*>(List->Get(count - 1)); auto lastLight = List->Get(count - 1);
if (lastLight->FlasherActive || lastLight->FlasherFlag2 || lastLight->FlasherFlag1) if (lastLight->FlasherActive || lastLight->FlasherFlag2 || lastLight->FlasherFlag1)
break; break;
if (MessageField2) if (MessageField2)
@@ -85,12 +85,12 @@ int TLightGroup::Message(int code, float value)
auto bmpIndex1 = lastLight->BmpIndex1; auto bmpIndex1 = lastLight->BmpIndex1;
for (auto index = count - 1; index > 0; --index) for (auto index = count - 1; index > 0; --index)
{ {
auto lightCur = static_cast<TLight*>(List->Get(index)); auto lightCur = List->Get(index);
auto lightPrev = static_cast<TLight*>(List->Get(index - 1)); auto lightPrev = List->Get(index - 1);
lightCur->Message(lightPrev->BmpIndex1 != 0, 0.0); lightCur->Message(lightPrev->BmpIndex1 != 0, 0.0);
lightCur->MessageField = lightPrev->MessageField; lightCur->MessageField = lightPrev->MessageField;
} }
auto firstLight = static_cast<TLight*>(List->Get(0)); auto firstLight = List->Get(0);
firstLight->Message(bmpIndex1 != 0, 0.0); firstLight->Message(bmpIndex1 != 0, 0.0);
firstLight->MessageField = lightMessageField; firstLight->MessageField = lightMessageField;
reschedule_animation(value); reschedule_animation(value);
@@ -98,23 +98,23 @@ int TLightGroup::Message(int code, float value)
} }
case 25: case 25:
{ {
auto count = List->Count(); auto count = List->GetCount();
auto lastLight = static_cast<TLight*>(List->Get(count - 1)); auto lastLight = List->Get(count - 1);
if (lastLight->FlasherActive || lastLight->FlasherFlag2 || lastLight->FlasherFlag1) if (lastLight->FlasherActive || lastLight->FlasherFlag2 || lastLight->FlasherFlag1)
break; break;
if (MessageField2) if (MessageField2)
{ {
TLightGroup::Message(34, 0.0); TLightGroup::Message(34, 0.0);
} }
auto firstLight = static_cast<TLight*>(List->Get(0)); auto firstLight = List->Get(0);
AnimationFlag = 1; AnimationFlag = 1;
MessageField2 = code; MessageField2 = code;
auto lightMessageField = firstLight->MessageField; auto lightMessageField = firstLight->MessageField;
auto bmpIndex1 = firstLight->BmpIndex1; auto bmpIndex1 = firstLight->BmpIndex1;
for (auto index = 0; index < count - 1; index++) for (auto index = 0; index < count - 1; index++)
{ {
auto lightCur = static_cast<TLight*>(List->Get(index)); auto lightCur = List->Get(index);
auto lightNext = static_cast<TLight*>(List->Get(index + 1)); auto lightNext = List->Get(index + 1);
lightCur->Message(lightNext->BmpIndex1 != 0, 0.0); lightCur->Message(lightNext->BmpIndex1 != 0, 0.0);
lightCur->MessageField = lightNext->MessageField; lightCur->MessageField = lightNext->MessageField;
} }
@@ -129,16 +129,16 @@ int TLightGroup::Message(int code, float value)
start_animation(); start_animation();
MessageField2 = code; MessageField2 = code;
AnimationFlag = 0; AnimationFlag = 0;
auto count = List->Count(); auto count = List->GetCount();
auto lastLight = static_cast<TLight*>(List->Get(count - 1)); auto lastLight = List->Get(count - 1);
auto flasherFlag2 = lastLight->FlasherFlag2; auto flasherFlag2 = lastLight->FlasherFlag2;
for (auto i = count - 1; i > 0; --i) for (auto i = count - 1; i > 0; --i)
{ {
auto lightCur = static_cast<TLight*>(List->Get(i)); auto lightCur = List->Get(i);
auto lightPrev = static_cast<TLight*>(List->Get(i - 1)); auto lightPrev = List->Get(i - 1);
lightCur->Message((lightPrev->FlasherFlag2 != 0) + 8, 0.0); lightCur->Message((lightPrev->FlasherFlag2 != 0) + 8, 0.0);
} }
auto firstLight = static_cast<TLight*>(List->Get(0)); auto firstLight = List->Get(0);
firstLight->Message((flasherFlag2 != 0) + 8, 0); firstLight->Message((flasherFlag2 != 0) + 8, 0);
reschedule_animation(value); reschedule_animation(value);
break; break;
@@ -149,16 +149,16 @@ int TLightGroup::Message(int code, float value)
start_animation(); start_animation();
MessageField2 = code; MessageField2 = code;
AnimationFlag = 0; AnimationFlag = 0;
auto count = List->Count(); auto count = List->GetCount();
auto firstLight = static_cast<TLight*>(List->Get(0)); auto firstLight = List->Get(0);
auto flasherFlag2 = firstLight->FlasherFlag2; auto flasherFlag2 = firstLight->FlasherFlag2;
for (auto i = 0; i < count - 1; i++) for (auto i = 0; i < count - 1; i++)
{ {
auto lightCur = static_cast<TLight*>(List->Get(i)); auto lightCur = List->Get(i);
auto lightNext = static_cast<TLight*>(List->Get(i + 1)); auto lightNext = List->Get(i + 1);
lightCur->Message((lightNext->FlasherFlag2 != 0) + 8, 0.0); lightCur->Message((lightNext->FlasherFlag2 != 0) + 8, 0.0);
} }
auto lastLight = static_cast<TLight*>(List->Get(count - 1)); auto lastLight = List->Get(count - 1);
lastLight->Message((flasherFlag2 != 0) + 8, 0); lastLight->Message((flasherFlag2 != 0) + 8, 0);
reschedule_animation(value); reschedule_animation(value);
break; break;
@@ -169,12 +169,12 @@ int TLightGroup::Message(int code, float value)
start_animation(); start_animation();
MessageField2 = code; MessageField2 = code;
AnimationFlag = 0; AnimationFlag = 0;
auto count = List->Count(); auto count = List->GetCount();
for (auto i = 0; i < count - 1; i++) for (auto i = 0; i < count - 1; i++)
{ {
if (rand() % 100 > 70) if (rand() % 100 > 70)
{ {
auto light = static_cast<TLight*>(List->Get(i)); auto light = List->Get(i);
auto randVal = static_cast<float>(rand()) * 0.00003051850947599719f * value * 3.0f + 0.1f; auto randVal = static_cast<float>(rand()) * 0.00003051850947599719f * value * 3.0f + 0.1f;
light->Message(9, randVal); light->Message(9, randVal);
} }
@@ -188,10 +188,10 @@ int TLightGroup::Message(int code, float value)
start_animation(); start_animation();
MessageField2 = code; MessageField2 = code;
AnimationFlag = 0; AnimationFlag = 0;
auto count = List->Count(); auto count = List->GetCount();
for (auto i = 0; i < count - 1; i++) for (auto i = 0; i < count - 1; i++)
{ {
auto light = static_cast<TLight*>(List->Get(i)); auto light = List->Get(i);
auto randVal = static_cast<float>(rand() % 100 > 70); auto randVal = static_cast<float>(rand() % 100 > 70);
light->Message(18, randVal); light->Message(18, randVal);
} }
@@ -201,13 +201,13 @@ int TLightGroup::Message(int code, float value)
case 30: case 30:
{ {
auto noBmpInd1Count = 0; auto noBmpInd1Count = 0;
auto countSub1 = List->Count() - 1; auto countSub1 = List->GetCount() - 1;
if (countSub1 < 0) if (countSub1 < 0)
break; break;
for (auto i = countSub1; i >= 0; i--) for (auto i = countSub1; i >= 0; i--)
{ {
if (!static_cast<TLight*>(List->Get(i))->BmpIndex1) if (!List->Get(i)->BmpIndex1)
++noBmpInd1Count; ++noBmpInd1Count;
} }
if (!noBmpInd1Count) if (!noBmpInd1Count)
@@ -216,7 +216,7 @@ int TLightGroup::Message(int code, float value)
auto randModCount = rand() % noBmpInd1Count; auto randModCount = rand() % noBmpInd1Count;
for (auto i = countSub1; i >= 0; i--) for (auto i = countSub1; i >= 0; i--)
{ {
auto light = static_cast<TLight*>(List->Get(i)); auto light = List->Get(i);
if (!light->BmpIndex1 && randModCount-- == 0) if (!light->BmpIndex1 && randModCount-- == 0)
{ {
light->Message(1, 0.0); light->Message(1, 0.0);
@@ -231,13 +231,13 @@ int TLightGroup::Message(int code, float value)
case 31: case 31:
{ {
auto bmpInd1Count = 0; auto bmpInd1Count = 0;
auto countSub1 = List->Count() - 1; auto countSub1 = List->GetCount() - 1;
if (countSub1 < 0) if (countSub1 < 0)
break; break;
for (auto i = countSub1; i >= 0; i--) for (auto i = countSub1; i >= 0; i--)
{ {
if (static_cast<TLight*>(List->Get(i))->BmpIndex1) if (List->Get(i)->BmpIndex1)
++bmpInd1Count; ++bmpInd1Count;
} }
if (!bmpInd1Count) if (!bmpInd1Count)
@@ -246,7 +246,7 @@ int TLightGroup::Message(int code, float value)
auto randModCount = rand() % bmpInd1Count; auto randModCount = rand() % bmpInd1Count;
for (auto i = countSub1; i >= 0; i--) for (auto i = countSub1; i >= 0; i--)
{ {
auto light = static_cast<TLight*>(List->Get(i)); auto light = List->Get(i);
if (light->BmpIndex1 && randModCount-- == 0) if (light->BmpIndex1 && randModCount-- == 0)
{ {
light->Message(0, 0.0); light->Message(0, 0.0);
@@ -263,7 +263,7 @@ int TLightGroup::Message(int code, float value)
auto index = next_light_up(); auto index = next_light_up();
if (index < 0) if (index < 0)
break; break;
static_cast<TLight*>(List->Get(index))->Message(1, 0.0); List->Get(index)->Message(1, 0.0);
if (MessageField2) if (MessageField2)
start_animation(); start_animation();
return 1; return 1;
@@ -273,7 +273,7 @@ int TLightGroup::Message(int code, float value)
auto index = next_light_down(); auto index = next_light_down();
if (index < 0) if (index < 0)
break; break;
static_cast<TLight*>(List->Get(index))->Message(0, 0.0); List->Get(index)->Message(0, 0.0);
if (MessageField2) if (MessageField2)
start_animation(); start_animation();
return 1; return 1;
@@ -292,10 +292,10 @@ int TLightGroup::Message(int code, float value)
case 35: case 35:
{ {
auto index = static_cast<int>(floor(value)); auto index = static_cast<int>(floor(value));
if (index >= List->Count() || index < 0) if (index >= List->GetCount() || index < 0)
break; break;
auto light = static_cast<TLight*>(List->Get(index)); auto light = List->Get(index);
light->Message(1, 0.0); light->Message(1, 0.0);
if (MessageField2) if (MessageField2)
start_animation(); start_animation();
@@ -304,10 +304,10 @@ int TLightGroup::Message(int code, float value)
case 36: case 36:
{ {
auto index = static_cast<int>(floor(value)); auto index = static_cast<int>(floor(value));
if (index >= List->Count() || index < 0) if (index >= List->GetCount() || index < 0)
break; break;
auto light = static_cast<TLight*>(List->Get(index)); auto light = List->Get(index);
light->Message(0, 0.0); light->Message(0, 0.0);
if (MessageField2) if (MessageField2)
start_animation(); start_animation();
@@ -316,16 +316,16 @@ int TLightGroup::Message(int code, float value)
case 37: case 37:
{ {
auto bmp1Count = 0; auto bmp1Count = 0;
auto countSub1 = List->Count() - 1; auto countSub1 = List->GetCount() - 1;
for (auto i = countSub1; i >= 0; i--) for (auto i = countSub1; i >= 0; i--)
{ {
if (static_cast<TLight*>(List->Get(i))->BmpIndex1) if (List->Get(i)->BmpIndex1)
++bmp1Count; ++bmp1Count;
} }
return bmp1Count; return bmp1Count;
} }
case 38: case 38:
return List->Count(); return List->GetCount();
case 39: case 39:
return MessageField2; return MessageField2;
case 40: case 40:
@@ -337,7 +337,7 @@ int TLightGroup::Message(int code, float value)
break; break;
if (MessageField2 || AnimationFlag) if (MessageField2 || AnimationFlag)
TLightGroup::Message(34, 0.0); TLightGroup::Message(34, 0.0);
static_cast<TLight*>(List->Get(index))->Message(15, value); List->Get(index)->Message(15, value);
return 1; return 1;
} }
case 42: case 42:
@@ -347,22 +347,22 @@ int TLightGroup::Message(int code, float value)
break; break;
if (MessageField2 || AnimationFlag) if (MessageField2 || AnimationFlag)
TLightGroup::Message(34, 0.0); TLightGroup::Message(34, 0.0);
static_cast<TLight*>(List->Get(index))->Message(16, value); List->Get(index)->Message(16, value);
return 1; return 1;
} }
case 43: case 43:
if (NotifyTimer) if (NotifyTimer)
timer::kill(NotifyTimer); timer::kill(NotifyTimer);
NotifyTimer = 0; NotifyTimer = 0;
if (value > 0.0) if (value > 0.0f)
NotifyTimer = timer::set(value, this, NotifyTimerExpired); NotifyTimer = timer::set(value, this, NotifyTimerExpired);
break; break;
case 44: case 44:
{ {
auto countSub1 = List->Count() - 1; auto countSub1 = List->GetCount() - 1;
for (auto index = countSub1; index >= 0; index--) for (auto index = countSub1; index >= 0; index--)
{ {
auto light = static_cast<TLight*>(List->Get(index)); auto light = List->Get(index);
if (light->BmpIndex1) if (light->BmpIndex1)
{ {
light->Message(0, 0.0); light->Message(0, 0.0);
@@ -378,7 +378,7 @@ int TLightGroup::Message(int code, float value)
auto index = static_cast<int>(floor(value)); auto index = static_cast<int>(floor(value));
if (index >= 0) if (index >= 0)
{ {
auto count = List->Count(); auto count = List->GetCount();
if (index <= count) if (index <= count)
{ {
auto countSub1 = count - 1; auto countSub1 = count - 1;
@@ -387,7 +387,7 @@ int TLightGroup::Message(int code, float value)
countSub1 = index; countSub1 = index;
for (auto i = countSub1, k = countSub1 - index; k != 0; i--, k--) for (auto i = countSub1, k = countSub1 - index; k != 0; i--, k--)
{ {
auto light = static_cast<TLight*>(List->Get(i)); auto light = List->Get(i);
light->Message(20, 0.0); light->Message(20, 0.0);
} }
} }
@@ -395,7 +395,7 @@ int TLightGroup::Message(int code, float value)
{ {
for (auto i = countSub1; i != 0; i--) for (auto i = countSub1; i != 0; i--)
{ {
auto light = static_cast<TLight*>(List->Get(i)); auto light = List->Get(i);
light->Message(19, 0.0); light->Message(19, 0.0);
} }
} }
@@ -408,14 +408,14 @@ int TLightGroup::Message(int code, float value)
auto index = next_light_down(); auto index = next_light_down();
if (index >= 0) if (index >= 0)
{ {
static_cast<TLight*>(List->Get(index))->Message(4, 0.0); List->Get(index)->Message(4, 0.0);
} }
break; break;
} }
default: default:
for (auto index = List->Count() - 1; index >= 0; index--) for (auto index = List->GetCount() - 1; index >= 0; index--)
{ {
static_cast<TLight*>(List->Get(index))->Message(code, value); List->Get(index)->Message(code, value);
} }
break; break;
} }
@@ -447,15 +447,15 @@ void TLightGroup::reschedule_animation(float time)
return; return;
} }
Timer1Time = time > 0.0 ? time : Timer1TimeDefault; Timer1Time = time > 0.0f ? time : Timer1TimeDefault;
Timer = timer::set(Timer1Time, this, TimerExpired); Timer = timer::set(Timer1Time, this, TimerExpired);
} }
void TLightGroup::start_animation() void TLightGroup::start_animation()
{ {
for (int index = List->Count() - 1; index >= 0; --index) for (int index = List->GetCount() - 1; index >= 0; --index)
{ {
auto light = static_cast<TLight*>(List->Get(index)); auto light = List->Get(index);
if (light->BmpIndex1) if (light->BmpIndex1)
light->Message(9, 0.0); light->Message(9, 0.0);
else else
@@ -465,9 +465,9 @@ void TLightGroup::start_animation()
int TLightGroup::next_light_up() int TLightGroup::next_light_up()
{ {
for (int index = 0; index < List->Count(); ++index) for (int index = 0; index < List->GetCount(); ++index)
{ {
if (!static_cast<TLight*>(List->Get(index))->BmpIndex1) if (!List->Get(index)->BmpIndex1)
return index; return index;
} }
return -1; return -1;
@@ -475,9 +475,9 @@ int TLightGroup::next_light_up()
int TLightGroup::next_light_down() int TLightGroup::next_light_down()
{ {
for (int index = List->Count() - 1; index >= 0; --index) for (int index = List->GetCount() - 1; index >= 0; --index)
{ {
if (!static_cast<TLight*>(List->Get(index))->BmpIndex1) if (!List->Get(index)->BmpIndex1)
return index; return index;
} }
return -1; return -1;

View File

@@ -1,6 +1,8 @@
#pragma once #pragma once
#include "TPinballComponent.h" #include "TPinballComponent.h"
class objlist_class;
class TLight;
struct TLightGroup_player_backup struct TLightGroup_player_backup
{ {
@@ -27,7 +29,7 @@ public:
static void TimerExpired(int timerId, void* caller); static void TimerExpired(int timerId, void* caller);
static void NotifyTimerExpired(int timerId, void* caller); static void NotifyTimerExpired(int timerId, void* caller);
objlist_class* List; objlist_class<TLight>* List;
float Timer1Time; float Timer1Time;
float Timer1TimeDefault; float Timer1TimeDefault;
int MessageField2; int MessageField2;

View File

@@ -4,11 +4,11 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "TBall.h" #include "TBall.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TLightRollover::TLightRollover(TPinballTable* table, int groupIndex) : TRollover(table, groupIndex, false) TLightRollover::TLightRollover(TPinballTable* table, int groupIndex) : TRollover(table, groupIndex, false)
{ {
@@ -58,7 +58,7 @@ void TLightRollover::Collision(TBall* ball, vector_type* nextPosition, vector_ty
control::handler(63, this); control::handler(63, this);
RolloverFlag = RolloverFlag == 0; RolloverFlag = RolloverFlag == 0;
if (ListBitmap) if (ListBitmap)
render::sprite_set_bitmap(RenderSprite, static_cast<gdrv_bitmap8*>(ListBitmap->Get(0))); render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
} }
} }
} }

View File

@@ -67,7 +67,7 @@ void TOneway::Collision(TBall* ball, vector_type* nextPosition, vector_type* dir
Elasticity, Elasticity,
Smoothness, Smoothness,
Threshold, Threshold,
Boost) > 0.2) Boost) > 0.2f)
{ {
if (SoftHitSoundId) if (SoftHitSoundId)
loader::play_sound(SoftHitSoundId); loader::play_sound(SoftHitSoundId);

View File

@@ -3,7 +3,6 @@
#include "loader.h" #include "loader.h"
#include "objlist_class.h" #include "objlist_class.h"
#include "render.h" #include "render.h"
#include "TZmapList.h"
#include "TPinballTable.h" #include "TPinballTable.h"
TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool loadVisuals) TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool loadVisuals)
@@ -32,32 +31,45 @@ TPinballComponent::TPinballComponent(TPinballTable* table, int groupIndex, bool
if (visual.Bitmap) if (visual.Bitmap)
{ {
if (!ListBitmap) if (!ListBitmap)
ListBitmap = new TZmapList(visualCount, 4); ListBitmap = new objlist_class<gdrv_bitmap8>(visualCount, 4);
if (ListBitmap) if (ListBitmap)
ListBitmap->Add(visual.Bitmap); ListBitmap->Add(visual.Bitmap);
} }
if (visual.ZMap) if (visual.ZMap)
{ {
if (!ListZMap) if (!ListZMap)
ListZMap = new TZmapList(visualCount, 4); ListZMap = new objlist_class<zmap_header_type>(visualCount, 4);
if (ListZMap) if (ListZMap)
ListZMap->Add(visual.ZMap); ListZMap->Add(visual.ZMap);
} }
} }
zmap_header_type* zMap = nullptr; zmap_header_type* zMap = nullptr;
if (ListZMap) if (ListZMap)
zMap = static_cast<zmap_header_type*>(ListZMap->Get(0)); zMap = ListZMap->Get(0);
if (ListBitmap) if (ListBitmap)
{ {
/* Full tilt hack - spliced bitmap includes zMap
* Users access bitmap-zMap in pairs, pad zMap list with 0 for such users
* zdrv does not access zMap when drawing spliced bitmap*/
if (!ListZMap)
{
ListZMap = new objlist_class<zmap_header_type>(0, 4);
for (int index = 0; index < ListBitmap->GetCount(); index++)
{
assertm(ListBitmap->Get(index)->BitmapType == BitmapType::Spliced, "Wrong zMap padding");
ListZMap->Add(visual.ZMap);
}
}
rectangle_type bmp1Rect{}, tmpRect{}; rectangle_type bmp1Rect{}, tmpRect{};
auto rootBmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(0)); auto rootBmp = ListBitmap->Get(0);
bmp1Rect.XPosition = rootBmp->XPosition - table->XOffset; bmp1Rect.XPosition = rootBmp->XPosition - table->XOffset;
bmp1Rect.YPosition = rootBmp->YPosition - table->YOffset; bmp1Rect.YPosition = rootBmp->YPosition - table->YOffset;
bmp1Rect.Width = rootBmp->Width; bmp1Rect.Width = rootBmp->Width;
bmp1Rect.Height = rootBmp->Height; bmp1Rect.Height = rootBmp->Height;
for (int index = 1; index < ListBitmap->Count(); index++) for (int index = 1; index < ListBitmap->GetCount(); index++)
{ {
auto bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(index)); auto bmp = ListBitmap->Get(index);
tmpRect.XPosition = bmp->XPosition - table->XOffset; tmpRect.XPosition = bmp->XPosition - table->XOffset;
tmpRect.YPosition = bmp->YPosition - table->YOffset; tmpRect.YPosition = bmp->YPosition - table->YOffset;
tmpRect.Width = bmp->Width; tmpRect.Width = bmp->Width;

View File

@@ -1,9 +1,11 @@
#pragma once #pragma once
#include "objlist_class.h"
struct zmap_header_type;
struct gdrv_bitmap8;
struct render_sprite_type_struct; struct render_sprite_type_struct;
struct component_control; struct component_control;
class TPinballTable; class TPinballTable;
class TZmapList;
enum class message_code enum class message_code
{ {
@@ -26,8 +28,8 @@ public:
void* operator new(size_t Size); void* operator new(size_t Size);
void operator delete(void* p); void operator delete(void* p);
__int8 UnusedBaseFlag; char UnusedBaseFlag;
__int8 ActiveFlag; char ActiveFlag;
int MessageField; int MessageField;
char* GroupName; char* GroupName;
int Unknown4; int Unknown4;
@@ -35,6 +37,6 @@ public:
int GroupIndex; int GroupIndex;
render_sprite_type_struct* RenderSprite; render_sprite_type_struct* RenderSprite;
TPinballTable* PinballTable; TPinballTable* PinballTable;
TZmapList* ListBitmap; objlist_class<gdrv_bitmap8>* ListBitmap;
TZmapList* ListZMap; objlist_class<zmap_header_type>* ListZMap;
}; };

View File

@@ -48,8 +48,8 @@ TPinballTable::TPinballTable(): TPinballComponent(nullptr, -1, false)
{ {
int shortArrLength; int shortArrLength;
ComponentList = new objlist_class(32, 16); ComponentList = new objlist_class<TPinballComponent>(32, 16);
BallList = new objlist_class(3, 1); BallList = new objlist_class<TBall>(3, 1);
CurScoreStruct = nullptr; CurScoreStruct = nullptr;
ScoreBallcount = nullptr; ScoreBallcount = nullptr;
ScorePlayerNumber1 = nullptr; ScorePlayerNumber1 = nullptr;
@@ -213,9 +213,9 @@ TPinballTable::~TPinballTable()
ScoreBallcount = nullptr; ScoreBallcount = nullptr;
} }
delete LightGroup; delete LightGroup;
while (ComponentList->Count() > 0) while (ComponentList->GetCount() > 0)
{ {
delete static_cast<TPinballComponent*>(ComponentList->Get(0)); delete ComponentList->Get(0);
} }
delete BallList; delete BallList;
delete ComponentList; delete ComponentList;
@@ -223,12 +223,12 @@ TPinballTable::~TPinballTable()
TPinballComponent* TPinballTable::find_component(LPCSTR componentName) TPinballComponent* TPinballTable::find_component(LPCSTR componentName)
{ {
int objCount = ComponentList->Count(); int objCount = ComponentList->GetCount();
if (objCount > 0) if (objCount > 0)
{ {
for (int index = 0; index < objCount; ++index) for (int index = 0; index < objCount; ++index)
{ {
TPinballComponent* obj = static_cast<TPinballComponent*>(ComponentList->Get(index)); TPinballComponent* obj = ComponentList->Get(index);
const CHAR* groupName = obj->GroupName; const CHAR* groupName = obj->GroupName;
if (groupName && !lstrcmpA(groupName, componentName)) if (groupName && !lstrcmpA(groupName, componentName))
{ {
@@ -242,13 +242,13 @@ TPinballComponent* TPinballTable::find_component(LPCSTR componentName)
TPinballComponent* TPinballTable::find_component(int groupIndex) TPinballComponent* TPinballTable::find_component(int groupIndex)
{ {
char Buffer[40]; char Buffer[40]{};
int objCount = ComponentList->Count(); int objCount = ComponentList->GetCount();
if (objCount > 0) if (objCount > 0)
{ {
for (int index = 0; index < objCount; ++index) for (int index = 0; index < objCount; ++index)
{ {
TPinballComponent* obj = static_cast<TPinballComponent*>(ComponentList->Get(index)); TPinballComponent* obj = ComponentList->Get(index);
if (obj->GroupIndex == groupIndex) if (obj->GroupIndex == groupIndex)
return obj; return obj;
} }
@@ -307,9 +307,9 @@ void TPinballTable::tilt(float time)
loader::play_sound(SoundIndex3); loader::play_sound(SoundIndex3);
TiltTimeoutTimer = timer::set(30.0, this, tilt_timeout); TiltTimeoutTimer = timer::set(30.0, this, tilt_timeout);
for (int i = 0; i < ComponentList->Count(); i++) for (int i = 0; i < ComponentList->GetCount(); i++)
{ {
static_cast<TPinballComponent*>(ComponentList->Get(i))->Message(1011, time); ComponentList->Get(i)->Message(1011, time);
} }
LightGroup->Message(8, 0); LightGroup->Message(8, 0);
TiltLockFlag = 1; TiltLockFlag = 1;
@@ -320,9 +320,9 @@ void TPinballTable::tilt(float time)
void TPinballTable::port_draw() void TPinballTable::port_draw()
{ {
for (int index = ComponentList->Count() - 1; index >= 0; index--) for (int index = ComponentList->GetCount() - 1; index >= 0; index--)
{ {
static_cast<TPinballComponent*>(ComponentList->Get(index))->port_draw(); ComponentList->Get(index)->port_draw();
} }
} }
@@ -362,9 +362,9 @@ int TPinballTable::Message(int code, float value)
case 1008: case 1008:
case 1009: case 1009:
case 1010: case 1010:
for (int i = 0; i < ComponentList->Count(); i++) for (int i = 0; i < ComponentList->GetCount(); i++)
{ {
static_cast<TPinballComponent*>(ComponentList->Get(i))->Message(code, value); ComponentList->Get(i)->Message(code, value);
} }
break; break;
case 1012: case 1012:
@@ -406,7 +406,7 @@ int TPinballTable::Message(int code, float value)
{ {
CheatsUsed = 0; CheatsUsed = 0;
Message(1024, 0.0); Message(1024, 0.0);
auto ball = static_cast<TBall*>(BallList->Get(0)); auto ball = BallList->Get(0);
ball->Position.Y = 0.0; ball->Position.Y = 0.0;
ball->Position.X = 0.0; ball->Position.X = 0.0;
ball->Position.Z = -0.8f; ball->Position.Z = -0.8f;
@@ -513,9 +513,9 @@ int TPinballTable::Message(int code, float value)
score::set(ScorePlayerNumber1, nextPlayer + 1); score::set(ScorePlayerNumber1, nextPlayer + 1);
score::update(ScorePlayerNumber1); score::update(ScorePlayerNumber1);
for (int i = 0; i < ComponentList->Count(); i++) for (int i = 0; i < ComponentList->GetCount(); i++)
{ {
static_cast<TPinballComponent*>(ComponentList->Get(i))->Message(1020, static_cast<float>(nextPlayer)); ComponentList->Get(i)->Message(1020, static_cast<float>(nextPlayer));
} }
char* textboxText = nullptr; char* textboxText = nullptr;
@@ -564,9 +564,9 @@ int TPinballTable::Message(int code, float value)
EndGameTimeoutTimer = timer::set(3.0, this, EndGame_timeout); EndGameTimeoutTimer = timer::set(3.0, this, EndGame_timeout);
break; break;
case 1024: case 1024:
for (int i = 0; i < ComponentList->Count(); i++) for (int i = 0; i < ComponentList->GetCount(); i++)
{ {
static_cast<TPinballComponent*>(ComponentList->Get(i))->Message(1024, 0); ComponentList->Get(i)->Message(1024, 0);
} }
if (ReplayTimer) if (ReplayTimer)
timer::kill(ReplayTimer); timer::kill(ReplayTimer);
@@ -608,9 +608,9 @@ void TPinballTable::EndGame_timeout(int timerId, void* caller)
table->EndGameTimeoutTimer = 0; table->EndGameTimeoutTimer = 0;
pb::end_game(); pb::end_game();
for (int i = 0; i < table->ComponentList->Count(); i++) for (int i = 0; i < table->ComponentList->GetCount(); i++)
{ {
static_cast<TPinballComponent*>(table->ComponentList->Get(i))->Message(1022, 0); table->ComponentList->Get(i)->Message(1022, 0);
} }
if (table->Demo) if (table->Demo)
table->Demo->Message(1022, 0.0); table->Demo->Message(1022, 0.0);
@@ -640,9 +640,9 @@ void TPinballTable::tilt_timeout(int timerId, void* caller)
table->TiltTimeoutTimer = 0; table->TiltTimeoutTimer = 0;
if (table->TiltLockFlag) if (table->TiltLockFlag)
{ {
for (int i = 0; i < table->BallList->Count(); i++) for (int i = 0; i < table->BallList->GetCount(); i++)
{ {
table->Drain->Collision(static_cast<TBall*>(table->BallList->Get(i)), &vec, &vec, 0.0, nullptr); table->Drain->Collision(table->BallList->Get(i), &vec, &vec, 0.0, nullptr);
} }
} }
} }

View File

@@ -2,12 +2,12 @@
#include "TPinballComponent.h" #include "TPinballComponent.h"
class TBall;
struct scoreStruct; struct scoreStruct;
class TFlipper; class TFlipper;
class TPlunger; class TPlunger;
class TDrain; class TDrain;
class TDemo; class TDemo;
class objlist_class;
class TLightGroup; class TLightGroup;
struct score_struct_super struct score_struct_super
@@ -65,8 +65,8 @@ public:
int YOffset; int YOffset;
int Width; int Width;
int Height; int Height;
objlist_class* ComponentList; objlist_class<TPinballComponent>* ComponentList;
objlist_class* BallList; objlist_class<TBall>* BallList;
TLightGroup* LightGroup; TLightGroup* LightGroup;
float GravityDirVectMult; float GravityDirVectMult;
float GravityAngleX; float GravityAngleX;

View File

@@ -5,12 +5,12 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "maths.h" #include "maths.h"
#include "objlist_class.h"
#include "pb.h" #include "pb.h"
#include "render.h" #include "render.h"
#include "TBall.h" #include "TBall.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TPlunger::TPlunger(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) TPlunger::TPlunger(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true)
{ {
@@ -27,7 +27,7 @@ TPlunger::TPlunger(TPinballTable* table, int groupIndex) : TCollisionComponent(t
MaxPullback = 100; MaxPullback = 100;
Elasticity = 0.5f; Elasticity = 0.5f;
Smoothness = 0.5f; Smoothness = 0.5f;
PullbackIncrement = static_cast<int>(100.0 / (ListBitmap->Count() * 8.0)); PullbackIncrement = static_cast<int>(100.0 / (ListBitmap->GetCount() * 8.0));
Unknown4F = 0.025f; Unknown4F = 0.025f;
float* floatArr = loader::query_float_attribute(groupIndex, 0, 601); float* floatArr = loader::query_float_attribute(groupIndex, 0, 601);
table->PlungerPositionX = floatArr[0]; table->PlungerPositionX = floatArr[0];
@@ -65,8 +65,8 @@ int TPlunger::Message(int code, float value)
PullbackTimer_ = 0; PullbackTimer_ = 0;
if (code == 1005) if (code == 1005)
loader::play_sound(SoundIndexP2); loader::play_sound(SoundIndexP2);
auto bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(0)); auto bmp = ListBitmap->Get(0);
auto zMap = static_cast<zmap_header_type*>(ListZMap->Get(0)); auto zMap = ListZMap->Get(0);
render::sprite_set( render::sprite_set(
RenderSprite, RenderSprite,
bmp, bmp,
@@ -79,7 +79,7 @@ int TPlunger::Message(int code, float value)
} }
case 1015: case 1015:
{ {
auto ball = static_cast<TBall*>(PinballTable->ComponentList->Get(0)); auto ball = PinballTable->BallList->Get(0);
ball->Message(1024, 0.0); ball->Message(1024, 0.0);
ball->Position.X = PinballTable->PlungerPositionX; ball->Position.X = PinballTable->PlungerPositionX;
ball->Position.Y = PinballTable->PlungerPositionY; ball->Position.Y = PinballTable->PlungerPositionY;
@@ -112,8 +112,8 @@ int TPlunger::Message(int code, float value)
PullbackTimer_ = 0; PullbackTimer_ = 0;
if (code == 1005) if (code == 1005)
loader::play_sound(SoundIndexP2); loader::play_sound(SoundIndexP2);
auto bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(0)); auto bmp = ListBitmap->Get(0);
auto zMap = static_cast<zmap_header_type*>(ListZMap->Get(0)); auto zMap = ListZMap->Get(0);
render::sprite_set( render::sprite_set(
RenderSprite, RenderSprite,
bmp, bmp,
@@ -151,10 +151,10 @@ void TPlunger::PullbackTimer(int timerId, void* caller)
plunger->Boost = static_cast<float>(plunger->MaxPullback); plunger->Boost = static_cast<float>(plunger->MaxPullback);
} }
int index = static_cast<int>(floor( int index = static_cast<int>(floor(
static_cast<float>(plunger->ListBitmap->Count() - 1) * static_cast<float>(plunger->ListBitmap->GetCount() - 1) *
(plunger->Boost / static_cast<float>(plunger->MaxPullback)))); (plunger->Boost / static_cast<float>(plunger->MaxPullback))));
auto bmp = static_cast<gdrv_bitmap8*>(plunger->ListBitmap->Get(index)); auto bmp = plunger->ListBitmap->Get(index);
auto zMap = static_cast<zmap_header_type*>(plunger->ListZMap->Get(index)); auto zMap = plunger->ListZMap->Get(index);
render::sprite_set( render::sprite_set(
plunger->RenderSprite, plunger->RenderSprite,
bmp, bmp,

View File

@@ -4,10 +4,10 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TPopupTarget::TPopupTarget(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) TPopupTarget::TPopupTarget(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true)
{ {
@@ -91,7 +91,7 @@ void TPopupTarget::TimerExpired(int timerId, void* caller)
auto target = static_cast<TPopupTarget*>(caller); auto target = static_cast<TPopupTarget*>(caller);
target->Timer = 0; target->Timer = 0;
target->ActiveFlag = 1; target->ActiveFlag = 1;
render::sprite_set_bitmap(target->RenderSprite, static_cast<gdrv_bitmap8*>(target->ListBitmap->Get(0))); render::sprite_set_bitmap(target->RenderSprite, target->ListBitmap->Get(0));
if (timerId) if (timerId)
{ {
if (target->SoftHitSoundId) if (target->SoftHitSoundId)

View File

@@ -22,16 +22,8 @@ TRamp::TRamp(TPinballTable* table, int groupIndex) : TCollisionComponent(table,
loader::query_visual(groupIndex, 0, &visual); loader::query_visual(groupIndex, 0, &visual);
CollisionGroup = visual.CollisionGroup; CollisionGroup = visual.CollisionGroup;
auto floatArr1 = loader::query_float_attribute(groupIndex, 0, 701); BallFieldMult = loader::query_float_attribute(groupIndex, 0, 701, 0.2f);
if (floatArr1) RampFlag1 = static_cast<int>(loader::query_float_attribute(groupIndex, 0, 1305, 0));
BallFieldMult = *floatArr1;
else
BallFieldMult = 0.2f;
auto floatArr2 = loader::query_float_attribute(groupIndex, 0, 1305);
if (floatArr2)
RampFlag1 = static_cast<int>(floor(*floatArr2));
else
RampFlag1 = 0;
auto floatArr3Plane = loader::query_float_attribute(groupIndex, 0, 1300); auto floatArr3Plane = loader::query_float_attribute(groupIndex, 0, 1300);
RampPlaneCount = static_cast<int>(floor(*floatArr3Plane)); RampPlaneCount = static_cast<int>(floor(*floatArr3Plane));

View File

@@ -5,12 +5,12 @@
#include "control.h" #include "control.h"
#include "gdrv.h" #include "gdrv.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "TBall.h" #include "TBall.h"
#include "TEdgeSegment.h" #include "TEdgeSegment.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TRollover::TRollover(TPinballTable* table, int groupIndex, bool createWall) : TCollisionComponent( TRollover::TRollover(TPinballTable* table, int groupIndex, bool createWall) : TCollisionComponent(
table, groupIndex, createWall) table, groupIndex, createWall)
@@ -22,7 +22,7 @@ TRollover::TRollover(TPinballTable* table, int groupIndex) : TCollisionComponent
{ {
RolloverFlag = 0; RolloverFlag = 0;
if (ListBitmap) if (ListBitmap)
render::sprite_set_bitmap(RenderSprite, static_cast<gdrv_bitmap8*>(ListBitmap->Get(0))); render::sprite_set_bitmap(RenderSprite, ListBitmap->Get(0));
build_walls(groupIndex); build_walls(groupIndex);
} }
@@ -34,7 +34,7 @@ int TRollover::Message(int code, float value)
this->ActiveFlag = 1; this->ActiveFlag = 1;
this->RolloverFlag = 0; this->RolloverFlag = 0;
if (this->ListBitmap) if (this->ListBitmap)
render::sprite_set_bitmap(this->RenderSprite, static_cast<gdrv_bitmap8*>(this->ListBitmap->Get(0))); render::sprite_set_bitmap(this->RenderSprite, this->ListBitmap->Get(0));
} }
return 0; return 0;
} }
@@ -63,7 +63,7 @@ void TRollover::Collision(TBall* ball, vector_type* nextPosition, vector_type* d
if (ListBitmap) if (ListBitmap)
{ {
if (!RolloverFlag) if (!RolloverFlag)
bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(0)); bmp = ListBitmap->Get(0);
render::sprite_set_bitmap(RenderSprite, bmp); render::sprite_set_bitmap(RenderSprite, bmp);
} }
} }

View File

@@ -34,7 +34,7 @@ int TSink::Message(int code, float value)
switch (code) switch (code)
{ {
case 56: case 56:
if (value < 0.0) if (value < 0.0f)
value = TimerTime; value = TimerTime;
Timer = timer::set(value, this, TimerExpired); Timer = timer::set(value, this, TimerExpired);
break; break;
@@ -95,7 +95,7 @@ void TSink::Collision(TBall* ball, vector_type* nextPosition, vector_type* direc
void TSink::TimerExpired(int timerId, void* caller) void TSink::TimerExpired(int timerId, void* caller)
{ {
auto sink = static_cast<TSink*>(caller); auto sink = static_cast<TSink*>(caller);
auto ball = static_cast<TBall*>(sink->PinballTable->BallList->Get(0)); auto ball = sink->PinballTable->BallList->Get(0);
ball->CollisionComp = nullptr; ball->CollisionComp = nullptr;
ball->ActiveFlag = 1; ball->ActiveFlag = 1;
ball->Position.X = sink->BallPosition.X; ball->Position.X = sink->BallPosition.X;

View File

@@ -4,10 +4,10 @@
#include "control.h" #include "control.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "timer.h" #include "timer.h"
#include "TPinballTable.h" #include "TPinballTable.h"
#include "TZmapList.h"
TSoloTarget::TSoloTarget(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) TSoloTarget::TSoloTarget(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true)
{ {
@@ -41,8 +41,8 @@ int TSoloTarget::Message(int code, float value)
if (ListBitmap) if (ListBitmap)
{ {
auto index = 1 - ActiveFlag; auto index = 1 - ActiveFlag;
auto bmp = static_cast<gdrv_bitmap8*>(ListBitmap->Get(index)); auto bmp = ListBitmap->Get(index);
auto zMap = static_cast<zmap_header_type*>(ListZMap->Get(index)); auto zMap = ListZMap->Get(index);
render::sprite_set( render::sprite_set(
RenderSprite, RenderSprite,
bmp, bmp,

View File

@@ -1,8 +1,11 @@
#include "pch.h" #include "pch.h"
#include "TTableLayer.h" #include "TTableLayer.h"
#include "fullscrn.h"
#include "loader.h" #include "loader.h"
#include "objlist_class.h" #include "objlist_class.h"
#include "pb.h"
#include "proj.h" #include "proj.h"
#include "render.h" #include "render.h"
#include "TBall.h" #include "TBall.h"
@@ -19,7 +22,8 @@ TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, f
auto groupIndex = loader::query_handle("table"); auto groupIndex = loader::query_handle("table");
loader::query_visual(groupIndex, 0, &visual); loader::query_visual(groupIndex, 0, &visual);
auto projCenter = loader::query_float_attribute(groupIndex, 0, 700); /*Full tilt: proj center first value is offset by resolution*/
auto projCenter = loader::query_float_attribute(groupIndex, 0, 700 + fullscrn::GetResolution());
proj::recenter(projCenter[0], projCenter[1]); proj::recenter(projCenter[0], projCenter[1]);
render::set_background_zmap(visual.ZMap, 0, 0); render::set_background_zmap(visual.ZMap, 0, 0);
@@ -49,11 +53,12 @@ TTableLayer::TTableLayer(TPinballTable* table): TCollisionComponent(table, -1, f
PinballTable->GravityAnglY = 1.570796f; PinballTable->GravityAnglY = 1.570796f;
} }
auto table3 = PinballTable; GraityDirX = cos(PinballTable->GravityAnglY) * sin(PinballTable->GravityAngleX) * PinballTable->GravityDirVectMult;
GraityDirX = cos(table3->GravityAnglY) * sin(table3->GravityAngleX) * table3->GravityDirVectMult; GraityDirY = sin(PinballTable->GravityAnglY) * sin(PinballTable->GravityAngleX) * PinballTable->GravityDirVectMult;
GraityDiY = sin(table3->GravityAnglY) * sin(table3->GravityAngleX) * table3->GravityDirVectMult;
auto angleMultArr = loader::query_float_attribute(groupIndex, 0, 701); auto angleMultArr = loader::query_float_attribute(groupIndex, 0, 701);
if (angleMultArr)
/*Full tilt hack - GraityMult should be 0.2*/
if (angleMultArr && !pb::FullTiltMode)
GraityMult = *angleMultArr; GraityMult = *angleMultArr;
else else
GraityMult = 0.2f; GraityMult = 0.2f;
@@ -109,7 +114,7 @@ int TTableLayer::FieldEffect(TBall* ball, vector_type* vecDst)
{ {
vecDst->X = GraityDirX - (0.5f - static_cast<float>(rand()) * 0.00003051850947599719f + ball->Acceleration.X) * vecDst->X = GraityDirX - (0.5f - static_cast<float>(rand()) * 0.00003051850947599719f + ball->Acceleration.X) *
ball->Speed * GraityMult; ball->Speed * GraityMult;
vecDst->Y = GraityDiY - ball->Acceleration.Y * ball->Speed * GraityMult; vecDst->Y = GraityDirY - ball->Acceleration.Y * ball->Speed * GraityMult;
return 1; return 1;
} }
@@ -214,47 +219,47 @@ void TTableLayer::edges_insert_circle(circle_type* circle, TEdgeSegment* edge, f
ray.Direction.X = 1.0; ray.Direction.X = 1.0;
ray.Direction.Y = 0.0; ray.Direction.Y = 0.0;
ray.MaxDistance = edge_manager->AdvanceX; ray.MaxDistance = edge_manager->AdvanceX;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0) if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0f)
break; break;
ray.Direction.X = -1.0; ray.Direction.X = -1.0;
ray.Origin.X = ray.Origin.X + edge_manager->AdvanceX; ray.Origin.X = ray.Origin.X + edge_manager->AdvanceX;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0) if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0f)
break; break;
ray.Direction.X = 0.0; ray.Direction.X = 0.0;
ray.Direction.Y = 1.0; ray.Direction.Y = 1.0;
ray.MaxDistance = edge_manager->AdvanceY; ray.MaxDistance = edge_manager->AdvanceY;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0) if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0f)
break; break;
ray.Direction.Y = -1.0; ray.Direction.Y = -1.0;
ray.Origin.Y = ray.Origin.Y + edge_manager->AdvanceY; ray.Origin.Y = ray.Origin.Y + edge_manager->AdvanceY;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0) if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0f)
break; break;
ray.Direction.Y = 0.0; ray.Direction.Y = 0.0;
ray.Direction.X = -1.0; ray.Direction.X = -1.0;
ray.MaxDistance = edge_manager->AdvanceX; ray.MaxDistance = edge_manager->AdvanceX;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0) if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0f)
break; break;
ray.Direction.X = 1.0; ray.Direction.X = 1.0;
ray.Origin.X = ray.Origin.X - edge_manager->AdvanceX; ray.Origin.X = ray.Origin.X - edge_manager->AdvanceX;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0) if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0f)
break; break;
ray.Direction.X = 0.0; ray.Direction.X = 0.0;
ray.Direction.Y = -1.0; ray.Direction.Y = -1.0;
ray.MaxDistance = edge_manager->AdvanceY; ray.MaxDistance = edge_manager->AdvanceY;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0) if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0f)
break; break;
ray.Direction.Y = 1.0; ray.Direction.Y = 1.0;
ray.Origin.Y = ray.Origin.Y - edge_manager->AdvanceY; ray.Origin.Y = ray.Origin.Y - edge_manager->AdvanceY;
if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0) if (maths::ray_intersect_circle(&ray, circle) < 1000000000.0f)
break; break;
collision = false; collision = false;
} }
while (false); while (false);

View File

@@ -26,7 +26,7 @@ public:
float Unknown3F; float Unknown3F;
float Unknown4F; float Unknown4F;
float GraityDirX; float GraityDirX;
float GraityDiY; float GraityDirY;
int Unknown7; int Unknown7;
float GraityMult; float GraityMult;
field_effect_type Field; field_effect_type Field;

View File

@@ -2,7 +2,9 @@
#include "TTextBox.h" #include "TTextBox.h"
#include "control.h" #include "control.h"
#include "fullscrn.h"
#include "loader.h" #include "loader.h"
#include "pb.h"
#include "render.h" #include "render.h"
#include "score.h" #include "score.h"
#include "timer.h" #include "timer.h"
@@ -22,8 +24,9 @@ TTextBox::TTextBox(TPinballTable* table, int groupIndex) : TPinballComponent(tab
if (groupIndex > 0) if (groupIndex > 0)
{ {
/*Full tilt: text box dimensions index is offset by resolution*/
int arrLength; int arrLength;
auto dimensions = loader::query_iattribute(groupIndex, 1500, &arrLength); auto dimensions = loader::query_iattribute(groupIndex + fullscrn::GetResolution(), 1500, &arrLength);
OffsetX = dimensions[0]; OffsetX = dimensions[0];
OffsetY = dimensions[1]; OffsetY = dimensions[1];
Width = dimensions[2]; Width = dimensions[2];
@@ -118,7 +121,7 @@ void TTextBox::Display(char* text, float time)
{ {
if (Timer && Timer != -1) if (Timer && Timer != -1)
timer::kill(Timer); timer::kill(Timer);
if (time == -1.0) if (time == -1.0f)
Timer = -1; Timer = -1;
else else
Timer = timer::set(time, this, TimerExpired); Timer = timer::set(time, this, TimerExpired);
@@ -152,8 +155,6 @@ void TTextBox::Display(char* text, float time)
void TTextBox::Draw() void TTextBox::Draw()
{ {
TTextBoxMessage* nextMessage = nullptr;
auto bmp = BgBmp; auto bmp = BgBmp;
if (bmp) if (bmp)
gdrv::copy_bitmap( gdrv::copy_bitmap(
@@ -168,119 +169,112 @@ void TTextBox::Draw()
else else
gdrv::fill_bitmap(&render::vscreen, Width, Height, OffsetX, OffsetY, 0); gdrv::fill_bitmap(&render::vscreen, Width, Height, OffsetX, OffsetY, 0);
bool display = false;
while (Message1) while (Message1)
{ {
auto message = Message1; if (Message1->Time == -1.0f)
if (message->Time == -1.0)
{ {
nextMessage = message->NextMessage; if (!Message1->NextMessage)
if (!message->NextMessage)
{ {
Timer = -1; Timer = -1;
LABEL_18: display = true;
auto font = Font;
if (!font)
{
gdrv::blit(
&render::vscreen,
OffsetX,
OffsetY,
OffsetX + render::vscreen.XPosition,
OffsetY + render::vscreen.YPosition,
Width,
Height);
gdrv::grtext_draw_ttext_in_box(
Message1->Text,
render::vscreen.XPosition + OffsetX,
render::vscreen.YPosition + OffsetY,
Width,
Height,
255);
return;
}
auto text = Message1->Text;
for (auto y = OffsetY; ; y += font->Height)
{
auto curChar = *text;
if (!curChar || y + font->Height > OffsetY + Height)
break;
auto totalWidth = 0;
char* textEndSpace = nullptr;
auto textEnd = text;
while (true)
{
auto maskedChar = curChar & 0x7F;
if (!maskedChar || maskedChar == '\n')
break;
auto charBmp = font->Chars[maskedChar];
if (charBmp)
{
auto width = charBmp->Width + font->GapWidth + totalWidth;
if (width > Width)
{
if (textEndSpace)
textEnd = textEndSpace;
break;
}
if (*textEnd == ' ')
textEndSpace = textEnd;
curChar = *(textEnd + 1);
totalWidth = width;
++textEnd;
}
else
{
curChar = *textEnd;
}
}
auto offX = OffsetX;
while (text < textEnd)
{
auto charBmp = font->Chars[*text++ & 0x7F];
if (charBmp)
{
auto height = charBmp->Height;
auto width = charBmp->Width;
if (render::background_bitmap)
gdrv::copy_bitmap_w_transparency(&render::vscreen, width, height, offX, y, charBmp, 0,
0);
else
gdrv::copy_bitmap(&render::vscreen, width, height, offX, y, charBmp, 0, 0);
font = Font;
offX += charBmp->Width + font->GapWidth;
}
}
while ((*text & 0x7F) == ' ')
++text;
if ((*text & 0x7F) == '\n')
++text;
}
break; break;
} }
} }
else else if (Message1->TimeLeft() >= -2.0f)
{ {
auto timeLeft = (Message1->TimeLeft()); Timer = timer::set(max(Message1->TimeLeft(), 0.25f), this, TimerExpired);
if (timeLeft >= -2.0f) display = true;
break;
}
auto tmp = Message1;
Message1 = Message1->NextMessage;
delete tmp;
}
if (display)
{
auto font = Font;
if (!font)
{
gdrv::blit(
&render::vscreen,
OffsetX,
OffsetY,
OffsetX + render::vscreen.XPosition,
OffsetY + render::vscreen.YPosition,
Width,
Height);
gdrv::grtext_draw_ttext_in_box(
Message1->Text,
render::vscreen.XPosition + OffsetX,
render::vscreen.YPosition + OffsetY,
Width,
Height,
255);
return;
}
auto text = Message1->Text;
for (auto y = OffsetY; ; y += font->Height)
{
auto curChar = *text;
if (!curChar || y + font->Height > OffsetY + Height)
break;
auto totalWidth = 0;
char* textEndSpace = nullptr;
auto textEnd = text;
while (true)
{ {
int timer; auto maskedChar = curChar & 0x7F;
if (timeLeft >= 0.25f) if (!maskedChar || maskedChar == '\n')
break;
auto charBmp = font->Chars[maskedChar];
if (charBmp)
{ {
timer = timer::set(timeLeft, this, TimerExpired); auto width = charBmp->Width + font->GapWidth + totalWidth;
if (width > Width)
{
if (textEndSpace)
textEnd = textEndSpace;
break;
}
if (*textEnd == ' ')
textEndSpace = textEnd;
curChar = *(textEnd + 1);
totalWidth = width;
++textEnd;
} }
else else
{ {
timer = timer::set(0.25, this, TimerExpired); curChar = *textEnd;
} }
Timer = timer;
goto LABEL_18;
} }
nextMessage = message->NextMessage;
auto offX = OffsetX;
while (text < textEnd)
{
auto charBmp = font->Chars[*text++ & 0x7F];
if (charBmp)
{
auto height = charBmp->Height;
auto width = charBmp->Width;
if (render::background_bitmap)
gdrv::copy_bitmap_w_transparency(&render::vscreen, width, height, offX, y, charBmp, 0,
0);
else
gdrv::copy_bitmap(&render::vscreen, width, height, offX, y, charBmp, 0, 0);
font = Font;
offX += charBmp->Width + font->GapWidth;
}
}
while ((*text & 0x7F) == ' ')
++text;
if ((*text & 0x7F) == '\n')
++text;
} }
delete message;
Message1 = nextMessage;
} }
gdrv::blit( gdrv::blit(

View File

@@ -3,16 +3,16 @@
#include "control.h" #include "control.h"
#include "objlist_class.h"
#include "render.h" #include "render.h"
#include "timer.h" #include "timer.h"
#include "TZmapList.h"
TWall::TWall(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true) TWall::TWall(TPinballTable* table, int groupIndex) : TCollisionComponent(table, groupIndex, true)
{ {
if (RenderSprite) if (RenderSprite)
render::sprite_set_bitmap(RenderSprite, nullptr); render::sprite_set_bitmap(RenderSprite, nullptr);
if (ListBitmap) if (ListBitmap)
BmpPtr = static_cast<gdrv_bitmap8*>(ListBitmap->Get(0)); BmpPtr = ListBitmap->Get(0);
Timer = 0; Timer = 0;
} }

View File

@@ -1,15 +0,0 @@
#pragma once
#include "objlist_class.h"
class TZmapList : // TImageList, template?
public objlist_class
{
public:
TZmapList(int SizeInt, int growSize): objlist_class(SizeInt, growSize)
{
};
~TZmapList()
{
};
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
/* flag values for play params */ /* flag values for play params */
#define WMIX_QUEUEWAVE 0x00 #define WMIX_QUEUEWAVE 0x00
#define WMIX_CLEARQUEUE 0x01 #define WMIX_CLEARQUEUE 0x01
@@ -15,8 +16,8 @@ struct GLOBALS;
struct volume_struct struct volume_struct
{ {
unsigned __int16 L; uint16_t L;
unsigned __int16 R; uint16_t R;
}; };
@@ -59,14 +60,14 @@ struct MIXCONFIG
DWORD dwFlags; DWORD dwFlags;
WORD wChannels; WORD wChannels;
WORD wSamplingRate; WORD wSamplingRate;
unsigned __int16 WaveBlockCount; uint16_t WaveBlockCount;
unsigned __int16 WaveBlockLen; uint16_t WaveBlockLen;
__int16 CmixPtrDefaultFlag; int16_t CmixPtrDefaultFlag;
unsigned __int16 ResetMixDefaultFlag; uint16_t ResetMixDefaultFlag;
unsigned __int16 GoodWavePos; uint16_t GoodWavePos;
unsigned __int16 wDeviceID; uint16_t wDeviceID;
unsigned __int16 PauseBlocks; uint16_t PauseBlocks;
__int16 ShowDebugDialogs; int16_t ShowDebugDialogs;
HKEY RegistryKey; HKEY RegistryKey;
}; };
@@ -88,14 +89,14 @@ struct PLAYQUEUE
struct GLOBALS struct GLOBALS
{ {
WORD wMagic1; WORD wMagic1;
__int16 unknown0; int16_t unknown0;
HWND hWndApp; HWND hWndApp;
int unknown2; int unknown2;
HWAVEOUT hWaveOut; HWAVEOUT hWaveOut;
int fActive; int fActive;
int SettingsDialogActiveFlag; int SettingsDialogActiveFlag;
unsigned int wDeviceID; unsigned int wDeviceID;
char szDevicePName[96]; char szDevicePName[96];
WAVEOUTCAPSA WaveoutCaps; WAVEOUTCAPSA WaveoutCaps;
volume_struct DefaultVolume; volume_struct DefaultVolume;
volume_struct ChannelVolume[MAXCHANNELS]; volume_struct ChannelVolume[MAXCHANNELS];
@@ -112,13 +113,13 @@ struct GLOBALS
DWORD dwBaseTime; DWORD dwBaseTime;
int fGoodGetPos; int fGoodGetPos;
DWORD dwWaveOutPos; DWORD dwWaveOutPos;
void (*CmixPtr)(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volume, int iNumWaves, void (*CmixPtr)(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volume, int iNumWaves,
unsigned __int16 length); uint16_t length);
int (* pfnRemix)(DWORD, CHANNELNODE*); int (* pfnRemix)(DWORD, CHANNELNODE*);
DWORD (* pfnSampleAdjust)(DWORD, DWORD); DWORD (* pfnSampleAdjust)(DWORD, DWORD);
CHANNELNODE* pWaitList; CHANNELNODE* pWaitList;
__int16 wMagic2; int16_t wMagic2;
__int16 unknown112; int16_t unknown112;
}; };
struct dialog_template struct dialog_template
@@ -182,16 +183,16 @@ private:
static DWORD SubFactor(DWORD a1, DWORD a2); static DWORD SubFactor(DWORD a1, DWORD a2);
static DWORD AddFactor(DWORD a1, DWORD a2); static DWORD AddFactor(DWORD a1, DWORD a2);
static dialog_template* MakeSettingsDlgTemplate(); static dialog_template* MakeSettingsDlgTemplate();
static dialog_template* MakeDlgTemplate(unsigned* totalSize, unsigned style, __int16 x, __int16 y, __int16 cx, static dialog_template* MakeDlgTemplate(size_t* totalSize, unsigned style, int16_t x, int16_t y, int16_t cx,
__int16 cy, int16_t cy,
const wchar_t* String); const wchar_t* String);
static dialog_template* AddDlgControl(unsigned int* totalSize, dialog_template* dlgTemplate, __int16 idClass, static dialog_template* AddDlgControl(size_t* totalSize, dialog_template* dlgTemplate, int16_t idClass,
unsigned style, unsigned style,
WORD id, __int16 x, __int16 y, __int16 cx, __int16 cy, WORD id, int16_t x, int16_t y, int16_t cx, int16_t cy,
const wchar_t* String); const wchar_t* String);
static void DestroySettingsDlgTemplate(LPCVOID pMem); static void DestroySettingsDlgTemplate(LPCVOID pMem);
static int Settings_OnInitDialog(HWND hWnd, int wParam, MIXCONFIG* lpMixconfig); static int Settings_OnInitDialog(HWND hWnd, WPARAM wParam, MIXCONFIG* lpMixconfig);
static int Settings_OnCommand(HWND hWnd, int command, int lParam, int wParam); static int Settings_OnCommand(HWND hWnd, int command, LPARAM lParam, int wParam);
static int ReadRegistryToGetMachineSpecificInfSection(unsigned wDeviceId, LPSTR lpString1, int maxLength); static int ReadRegistryToGetMachineSpecificInfSection(unsigned wDeviceId, LPSTR lpString1, int maxLength);
static const char* GetOperatingSystemPrefix(); static const char* GetOperatingSystemPrefix();
static unsigned int FigureOutDMABufferSize(unsigned int waveBlockLen, PCMWAVEFORMAT* pcm); static unsigned int FigureOutDMABufferSize(unsigned int waveBlockLen, PCMWAVEFORMAT* pcm);
@@ -215,8 +216,8 @@ private:
static int HasCurrentOutputFormat(MIXWAVE* lpMixWave); static int HasCurrentOutputFormat(MIXWAVE* lpMixWave);
static CHANNELNODE* GetChannelNode(); static CHANNELNODE* GetChannelNode();
static void ResetWavePosIfNoChannelData(); static void ResetWavePosIfNoChannelData();
static void cmixit(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volumeArr, int iNumWaves, static void cmixit(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volumeArr, int iNumWaves,
unsigned __int16 length); uint16_t length);
static LRESULT __stdcall WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); static LRESULT __stdcall WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
static INT_PTR __stdcall SettingsDlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); static INT_PTR __stdcall SettingsDlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
@@ -226,8 +227,8 @@ private:
static CHANNELNODE* free_channel_nodes; static CHANNELNODE* free_channel_nodes;
static unsigned char volume_table[11][256]; static unsigned char volume_table[11][256];
static int debug_flag; static int debug_flag;
static void (*cmixit_ptr)(unsigned __int8* lpDest, unsigned __int8** rgWaveSrc, volume_struct* volume, static void (*cmixit_ptr)(uint8_t* lpDest, uint8_t** rgWaveSrc, volume_struct* volume,
int iNumWaves, unsigned __int16 length); int iNumWaves, uint16_t length);
static HMODULE HModule; static HMODULE HModule;
static GLOBALS *Globals, *GlobalsActive; static GLOBALS *Globals, *GlobalsActive;
static PCMWAVEFORMAT gpFormat; static PCMWAVEFORMAT gpFormat;

View File

@@ -597,9 +597,9 @@ TPinballComponent* control::make_component_link(component_tag_base* tag)
return tag->GetComponent(); return tag->GetComponent();
auto compList = TableG->ComponentList; auto compList = TableG->ComponentList;
for (int index = 0; index < compList->Count(); index++) for (int index = 0; index < compList->GetCount(); index++)
{ {
auto comp = static_cast<TPinballComponent*>(compList->Get(index)); auto comp = compList->Get(index);
if (comp->GroupName) if (comp->GroupName)
{ {
if (!strcmp(comp->GroupName, tag->Name)) if (!strcmp(comp->GroupName, tag->Name))
@@ -616,17 +616,15 @@ TPinballComponent* control::make_component_link(component_tag_base* tag)
void control::handler(int code, TPinballComponent* cmp) void control::handler(int code, TPinballComponent* cmp)
{ {
component_control* control = cmp->Control; component_control* control = cmp->Control;
int scoreInd = 0;
if (control) if (control)
{ {
if (code == 1019 && control->ScoreCount > 0) if (code == 1019)
{ {
do for (auto scoreInd = 0; scoreInd < control->ScoreCount; ++scoreInd)
{ {
cmp->put_scoring(scoreInd, control->Scores[scoreInd]); cmp->put_scoring(scoreInd, control->Scores[scoreInd]);
++scoreInd;
} }
while (scoreInd < control->ScoreCount);
} }
control->ControlFunc(code, cmp); control->ControlFunc(code, cmp);
} }
@@ -1924,7 +1922,7 @@ void control::GravityWellKickoutControl(int code, TPinballComponent* caller)
} }
case 64: case 64:
{ {
auto score = reinterpret_cast<int>(caller); auto score = reinterpret_cast<size_t>(caller);
if (score) if (score)
{ {
sprintf_s(Buffer, pinball::get_rc_string(82, 0), score); sprintf_s(Buffer, pinball::get_rc_string(82, 0), score);
@@ -2232,7 +2230,7 @@ void control::HyperspaceKickOutControl(int code, TPinballComponent* caller)
case 4: case 4:
{ {
control_hyper_lights_tag.Component->Message(0, 0.0); control_hyper_lights_tag.Component->Message(0, 0.0);
auto addedScore = TableG->AddScore(caller->get_scoring(4)); size_t addedScore = TableG->AddScore(caller->get_scoring(4));
GravityWellKickoutControl(64, reinterpret_cast<TPinballComponent*>(addedScore)); GravityWellKickoutControl(64, reinterpret_cast<TPinballComponent*>(addedScore));
break; break;
} }
@@ -3019,7 +3017,7 @@ void control::GameoverController(int code, TPinballComponent* caller)
int missionMsg = control_mission_text_box_tag.Component->MessageField; int missionMsg = control_mission_text_box_tag.Component->MessageField;
if (missionMsg & 0x100) if (missionMsg & 0x100)
{ {
int playerId = missionMsg & 0xF; int playerId = missionMsg % 4;
int playerScore = TableG->PlayerScores[playerId].ScoreStruct->Score; int playerScore = TableG->PlayerScores[playerId].ScoreStruct->Score;
auto nextPlayerId = playerId + 1; auto nextPlayerId = playerId + 1;
if (playerScore >= 0) if (playerScore >= 0)
@@ -3056,7 +3054,7 @@ void control::GameoverController(int code, TPinballComponent* caller)
if (missionMsg & 0x200) if (missionMsg & 0x200)
{ {
int highscoreId = missionMsg & 0xF; int highscoreId = missionMsg % 4;
int highScore = pb::highscore_table[highscoreId].Score; int highScore = pb::highscore_table[highscoreId].Score;
auto nextHidhscoreId = highscoreId + 1; auto nextHidhscoreId = highscoreId + 1;
if (highScore > 0) if (highScore > 0)

View File

@@ -26,7 +26,7 @@ struct component_tag : component_tag_base
static_assert(std::is_base_of<TPinballComponent, T>::value, "T must inherit from TPinballComponent"); static_assert(std::is_base_of<TPinballComponent, T>::value, "T must inherit from TPinballComponent");
T* Component; T* Component;
component_tag(LPCSTR name, TPinballComponent* component): component_tag_base(name) component_tag(LPCSTR name, TPinballComponent* component): component_tag_base(name), Component(nullptr)
{ {
component_tag::SetComponent(component); component_tag::SetComponent(component);
} }

View File

@@ -1,5 +1,9 @@
#include "pch.h" #include "pch.h"
#include "fullscrn.h" #include "fullscrn.h"
#include "options.h"
#include "pb.h"
#include "render.h" #include "render.h"
#include "winmain.h" #include "winmain.h"
@@ -10,10 +14,22 @@ tagRECT fullscrn::WindowRect1, fullscrn::WindowRect2;
rectangle_type fullscrn::WHRect; rectangle_type fullscrn::WHRect;
int fullscrn::fullscrn_flag1; int fullscrn::fullscrn_flag1;
int fullscrn::display_changed; int fullscrn::display_changed;
int fullscrn::ChangeDisplay, fullscrn::SmthFullScrnFlag2; int fullscrn::ChangeDisplay, fullscrn::ignoreNextDisplayChangeFg;
int fullscrn::trick = 1; int fullscrn::trick = 1;
int fullscrn::MenuEnabled; int fullscrn::MenuEnabled;
HMENU fullscrn::MenuHandle; HMENU fullscrn::MenuHandle;
int fullscrn::resolution = 0;
int fullscrn::maxResolution = 0;
const resolution_info fullscrn::resolution_array[3] =
{
{640, 480, 600, 416, 501},
{800, 600, 752, 520, 502},
{1024, 768, 960, 666, 503},
};
float fullscrn::ScaleX = 1;
float fullscrn::ScaleY = 1;
float fullscrn::OffsetX = 0;
float fullscrn::OffsetY = 0;
void fullscrn::init(int width, int height, int isFullscreen, HWND winHandle, HMENU menuHandle, int changeDisplay) void fullscrn::init(int width, int height, int isFullscreen, HWND winHandle, HMENU menuHandle, int changeDisplay)
{ {
@@ -36,15 +52,21 @@ void fullscrn::init(int width, int height, int isFullscreen, HWND winHandle, HME
WindowRect2.right = (WindowRect1.right - WindowRect1.left - widht2) / 2 - 2 + widht2 + 4; WindowRect2.right = (WindowRect1.right - WindowRect1.left - widht2) / 2 - 2 + widht2 + 4;
WindowRect2.left = (WindowRect1.right - WindowRect1.left - widht2) / 2 - 2; WindowRect2.left = (WindowRect1.right - WindowRect1.left - widht2) / 2 - 2;
WindowRect2.top = borderHeight / 2 - (captionHeight + menuHeight) - 2; WindowRect2.top = borderHeight / 2 - (captionHeight + menuHeight) - 2;
/*RECT client{0,0,width,height};
AdjustWindowRect(&client, winmain::WndStyle, true);*/
MoveWindow( MoveWindow(
hWnd, hWnd,
(WindowRect1.right - WindowRect1.left - widht2) / 2 - 2, (WindowRect1.right - WindowRect1.left - widht2) / 2 - 2,
WindowRect2.top, WindowRect2.top,
widht2 + 4 + 10, WindowRect2.right - WindowRect2.left + 10,
WindowRect2.bottom - WindowRect2.top + 10, WindowRect2.bottom - WindowRect2.top + 10,
0); 0);
// Todo: WH + 10 hack: original request 640x480 window but somehow receives 650x490, even thought spyxx says it is 640x480 // Todo: WH + 10 hack: original request 640x480 window but somehow receives 650x490, even thought spyxx says it is 640x480
fullscrn_flag1 = 0; fullscrn_flag1 = 0;
window_size_changed();
assertm(ScaleX == 1 && ScaleY == 1, "Wrong default client size");
} }
void fullscrn::shutdown() void fullscrn::shutdown()
@@ -84,13 +106,13 @@ int fullscrn::set_screen_mode(int isFullscreen)
int fullscrn::disableWindowFlagsDisDlg() int fullscrn::disableWindowFlagsDisDlg()
{ {
long style = GetWindowLongA(hWnd, -16); long style = GetWindowLongA(hWnd, -16);
return SetWindowLongA(hWnd, -16, style & 0xFF3FFFFF); return SetWindowLongA(hWnd, -16, style & ~(WS_CAPTION | WS_THICKFRAME));
} }
int fullscrn::setWindowFlagsDisDlg() int fullscrn::setWindowFlagsDisDlg()
{ {
int style = GetWindowLongA(hWnd, -16); int style = GetWindowLongA(hWnd, -16);
return SetWindowLongA(hWnd, -16, style | 0xC00000); return SetWindowLongA(hWnd, -16, style | WS_CAPTION | WS_THICKFRAME);
} }
int fullscrn::enableFullscreen() int fullscrn::enableFullscreen()
@@ -100,33 +122,33 @@ int fullscrn::enableFullscreen()
if (ChangeDisplay && !display_changed) if (ChangeDisplay && !display_changed)
{ {
DevMode.dmSize = 156; DevMode.dmSize = sizeof DevMode;
DevMode.dmFields = 1835008; DevMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
DevMode.dmPelsWidth = 640; DevMode.dmPelsWidth = resolution_array[resolution].ScreenWidth;
DevMode.dmPelsHeight = 480; DevMode.dmPelsHeight = resolution_array[resolution].ScreenHeight;
DevMode.dmBitsPerPel = 8; DevMode.dmBitsPerPel = 32;
disableWindowFlagsDisDlg(); disableWindowFlagsDisDlg();
if (trick) if (trick)
{ {
GetWindowRect(GetDesktopWindow(), &Rect); GetWindowRect(GetDesktopWindow(), &Rect);
SetWindowPos(hWnd, (HWND)-1, 0, 0, Rect.right - Rect.left + 1, SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, Rect.right - Rect.left + 1,
Rect.bottom - Rect.top + 1, 8u); Rect.bottom - Rect.top + 1, SWP_NOREDRAW);
} }
SmthFullScrnFlag2 = 1; ignoreNextDisplayChangeFg = 1;
LONG changeDispResult = ChangeDisplaySettingsA(&DevMode, 4u); LONG changeDispResult = ChangeDisplaySettingsA(&DevMode, CDS_FULLSCREEN);
if (changeDispResult == 1) if (changeDispResult == DISP_CHANGE_RESTART)
{ {
BYTE2(DevMode.dmFields) &= 0xFBu; DevMode.dmFields &= ~DM_BITSPERPEL;
SmthFullScrnFlag2 = 1; ignoreNextDisplayChangeFg = 1;
changeDispResult = ChangeDisplaySettingsA(&DevMode, 4u); changeDispResult = ChangeDisplaySettingsA(&DevMode, CDS_FULLSCREEN);
} }
display_changed = changeDispResult == 0; display_changed = changeDispResult == DISP_CHANGE_SUCCESSFUL;
if (changeDispResult == 0) if (display_changed)
return 1; return 1;
} }
GetWindowRect(GetDesktopWindow(), &Rect); GetWindowRect(GetDesktopWindow(), &Rect);
disableWindowFlagsDisDlg(); disableWindowFlagsDisDlg();
SetWindowPos(hWnd, (HWND)-1, 0, 0, Rect.right - Rect.left + 1, Rect.bottom - Rect.top + 1, 8u); SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, Rect.right - Rect.left + 1, Rect.bottom - Rect.top + 1, SWP_NOREDRAW);
return 0; return 0;
} }
@@ -135,20 +157,20 @@ int fullscrn::disableFullscreen()
if (display_changed) if (display_changed)
{ {
display_changed = 0; display_changed = 0;
SmthFullScrnFlag2 = 1; ignoreNextDisplayChangeFg = 1;
ChangeDisplaySettingsA(nullptr, 4u); ChangeDisplaySettingsA(nullptr, CDS_FULLSCREEN);
if (trick) if (trick)
SetWindowPos(hWnd, (HWND)-1, 0, 0, 0, 0, 0x13u); SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
} }
setWindowFlagsDisDlg(); setWindowFlagsDisDlg();
SetWindowPos( SetWindowPos(
hWnd, hWnd,
nullptr, HWND_TOP,
WindowRect2.left, WindowRect2.left,
WindowRect2.top, WindowRect2.top,
WindowRect2.right - WindowRect2.left, WindowRect2.right - WindowRect2.left,
WindowRect2.bottom - WindowRect2.top, WindowRect2.bottom - WindowRect2.top,
0x14u); SWP_NOZORDER | SWP_NOACTIVATE);
return 0; return 0;
} }
@@ -242,9 +264,9 @@ void fullscrn::center_in(HWND parent, HWND child)
int fullscrn::displaychange() int fullscrn::displaychange()
{ {
int result = 0; int result = 0;
if (SmthFullScrnFlag2) if (ignoreNextDisplayChangeFg)
{ {
SmthFullScrnFlag2 = 0; ignoreNextDisplayChangeFg = 0;
} }
else else
{ {
@@ -258,24 +280,24 @@ int fullscrn::displaychange()
set_menu_mode(1); set_menu_mode(1);
SetWindowPos( SetWindowPos(
hWnd, hWnd,
nullptr, HWND_TOP,
WindowRect2.left, WindowRect2.left,
WindowRect2.top, WindowRect2.top,
WindowRect2.right - WindowRect2.left, WindowRect2.right - WindowRect2.left,
WindowRect2.bottom - WindowRect2.top, WindowRect2.bottom - WindowRect2.top,
0x1Cu); SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE);
result = 1; result = 1;
} }
else else
{ {
SetWindowPos( SetWindowPos(
hWnd, hWnd,
nullptr, HWND_TOP,
WindowRect2.left, WindowRect2.left,
WindowRect2.top, WindowRect2.top,
WindowRect2.right - WindowRect2.left, WindowRect2.right - WindowRect2.left,
WindowRect2.bottom - WindowRect2.top, WindowRect2.bottom - WindowRect2.top,
0x14u); SWP_NOZORDER | SWP_NOACTIVATE);
} }
center_in(GetDesktopWindow(), hWnd); center_in(GetDesktopWindow(), hWnd);
} }
@@ -289,50 +311,48 @@ void fullscrn::activate(int flag)
if (!flag) if (!flag)
{ {
set_screen_mode(0); set_screen_mode(0);
SetWindowPos(hWnd, (HWND)1, 0, 0, 0, 0, 0x13u); SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
} }
} }
} }
void fullscrn::fillRect(int right, int bottom) void fullscrn::fillRect(int right, int bottom, int left, int top)
{ {
// Weird reg usage, should be zero
int v2 = 0;
int v3 = 0;
RECT rc; RECT rc;
HGDIOBJ brush = CreateSolidBrush(0); auto brush = CreateSolidBrush(0);
if (brush) if (brush)
{ {
HDC dc = winmain::_GetDC(hWnd); auto dc = winmain::_GetDC(hWnd);
HGDIOBJ brushHandle = SelectObject(dc, brush);
if (dc) if (dc)
{ {
rc.right = right + v2 + 1; auto prevBrush = SelectObject(dc, brush);
rc.bottom = bottom + v3 + 1; rc.right = left + right + 1;
rc.left = v2; rc.bottom = top + bottom + 1;
rc.top = v3; rc.left = left;
FillRect(dc, &rc, static_cast<HBRUSH>(brush)); rc.top = top;
FillRect(dc, &rc, brush);
SelectObject(dc, prevBrush);
ReleaseDC(hWnd, dc); ReleaseDC(hWnd, dc);
} }
SelectObject(dc, brushHandle);
DeleteObject(brush); DeleteObject(brush);
} }
} }
unsigned fullscrn::convert_mouse_pos(unsigned int mouseXY) unsigned fullscrn::convert_mouse_pos(unsigned int mouseXY)
{ {
unsigned __int16 x = mouseXY & 0xffFF - render::vscreen.XPosition; uint16_t x = mouseXY & 0xffFF - render::vscreen.XPosition;
unsigned __int16 y = (mouseXY >> 16) - render::vscreen.YPosition; uint16_t y = (mouseXY >> 16) - render::vscreen.YPosition;
return x | y << 16; return x | y << 16;
} }
void fullscrn::getminmaxinfo(MINMAXINFO* maxMin) void fullscrn::getminmaxinfo(MINMAXINFO* maxMin)
{ {
maxMin->ptMaxSize.x = WindowRect2.right - WindowRect2.left; /*Block down-scaling lower than min resolution*/
maxMin->ptMaxSize.y = WindowRect2.bottom - WindowRect2.top; maxMin->ptMinTrackSize = POINT
maxMin->ptMaxPosition.x = WindowRect2.left; {
maxMin->ptMaxPosition.y = WindowRect2.top; resolution_array[0].ScreenWidth / 2,
resolution_array[0].ScreenHeight / 2
};
} }
void fullscrn::paint() void fullscrn::paint()
@@ -345,7 +365,7 @@ void fullscrn::paint()
if (fullscrn_flag1 & 1) if (fullscrn_flag1 & 1)
{ {
menuHeight = GetSystemMetrics(SM_CYMENU); menuHeight = GetSystemMetrics(SM_CYMENU);
fillRect(WindowRect1.right - 1, menuHeight); fillRect(WindowRect1.right - 1, menuHeight, 0, 0);
} }
} }
else else
@@ -354,9 +374,89 @@ void fullscrn::paint()
menuHeight = GetSystemMetrics(SM_CYMENU); menuHeight = GetSystemMetrics(SM_CYMENU);
else else
menuHeight = 0; menuHeight = 0;
fillRect(WindowRect1.right, menuHeight + WindowRect1.bottom); fillRect(WindowRect1.right, menuHeight + WindowRect1.bottom, 0, 0);
} }
} }
render::paint(); render::paint();
fullscrn_flag1 = 0; fullscrn_flag1 = 0;
} }
int fullscrn::GetResolution()
{
return resolution;
}
void fullscrn::SetResolution(int resolution)
{
if (!pb::FullTiltMode)
resolution = 0;
assertm(resolution >= 0 && resolution <= 2, "Resolution value out of bounds");
fullscrn::resolution = resolution;
}
int fullscrn::GetMaxResolution()
{
return maxResolution;
}
void fullscrn::SetMaxResolution(int resolution)
{
assertm(resolution >= 0 && resolution <= 2, "Resolution value out of bounds");
maxResolution = resolution;
}
int fullscrn::get_max_supported_resolution()
{
if (!pb::FullTiltMode)
return 0;
auto resolutionWH = get_screen_resolution();
auto width = LOWORD(resolutionWH);
auto height = HIWORD(resolutionWH);
auto result = 0;
for (auto index = 1; index < 3; ++index)
{
auto resPtr = &resolution_array[index];
if (resPtr->ScreenWidth <= width && resPtr->ScreenHeight <= height)
result = index;
}
return result;
}
int fullscrn::get_screen_resolution()
{
auto height = static_cast<uint16_t>(GetSystemMetrics(SM_CYSCREEN));
return static_cast<uint16_t>(GetSystemMetrics(SM_CXSCREEN)) | (height << 16);
}
void fullscrn::window_size_changed()
{
/*No scaling in fullscreen mode*/
if (display_changed)
{
ScaleY = ScaleX = 1;
OffsetX = OffsetY = 0;
return;
}
RECT client{};
GetClientRect(hWnd, &client);
auto res = &resolution_array[resolution];
ScaleX = static_cast<float>(client.right) / res->TableWidth;
ScaleY = static_cast<float>(client.bottom) / res->TableHeight;
OffsetX = OffsetY = 0;
if (options::Options.UniformScaling)
{
ScaleY = ScaleX = min(ScaleX, ScaleY);
OffsetX = floor((client.right - res->TableWidth * ScaleX) / 2);
OffsetY = floor((client.bottom - res->TableHeight * ScaleY) / 2);
auto dc = GetDC(hWnd);
if (dc)
{
BitBlt(dc, 0, 0, client.right, client.bottom, dc, 0, 0, BLACKNESS);
ReleaseDC(hWnd, dc);
}
}
}

View File

@@ -5,6 +5,16 @@
#define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0) #define BYTE1(x) BYTEn(x, 1) // byte 1 (counting from 0)
#define BYTE2(x) BYTEn(x, 2) #define BYTE2(x) BYTEn(x, 2)
struct resolution_info
{
int16_t ScreenWidth;
int16_t ScreenHeight;
int16_t TableWidth;
int16_t TableHeight;
int16_t ResolutionMenuId;
};
class fullscrn class fullscrn
{ {
public: public:
@@ -15,8 +25,13 @@ public:
static rectangle_type WHRect; static rectangle_type WHRect;
static int fullscrn_flag1; static int fullscrn_flag1;
static int display_changed; static int display_changed;
static int ChangeDisplay, SmthFullScrnFlag2; static int ChangeDisplay, ignoreNextDisplayChangeFg;
static int trick; static int trick;
static const resolution_info resolution_array[3];
static float ScaleX;
static float ScaleY;
static float OffsetX;
static float OffsetY;
static void init(int width, int height, int isFullscreen, HWND winHandle, HMENU menuHandle, int changeDisplay); static void init(int width, int height, int isFullscreen, HWND winHandle, HMENU menuHandle, int changeDisplay);
static void shutdown(); static void shutdown();
@@ -29,14 +44,23 @@ public:
static void getminmaxinfo(MINMAXINFO* maxMin); static void getminmaxinfo(MINMAXINFO* maxMin);
static void paint(); static void paint();
static bool set_menu_mode(int menuEnabled); static bool set_menu_mode(int menuEnabled);
static int GetResolution();
static void SetResolution(int resolution);
static int GetMaxResolution();
static void SetMaxResolution(int resolution);
static int get_max_supported_resolution();
static int get_screen_resolution();
static void window_size_changed();
private : private :
static int MenuEnabled; static int MenuEnabled;
static HMENU MenuHandle; static HMENU MenuHandle;
static int resolution;
static int maxResolution;
static void GetWindowCenter(); static void GetWindowCenter();
static int disableWindowFlagsDisDlg(); static int disableWindowFlagsDisDlg();
static int setWindowFlagsDisDlg(); static int setWindowFlagsDisDlg();
static int enableFullscreen(); static int enableFullscreen();
static int disableFullscreen(); static int disableFullscreen();
static void fillRect(int right, int bottom); static void fillRect(int right, int bottom, int left, int top);
}; };

View File

@@ -1,5 +1,7 @@
#include "pch.h" #include "pch.h"
#include "gdrv.h" #include "gdrv.h"
#include "fullscrn.h"
#include "memory.h" #include "memory.h"
#include "pinball.h" #include "pinball.h"
#include "winmain.h" #include "winmain.h"
@@ -7,7 +9,6 @@
HPALETTE gdrv::palette_handle = nullptr; HPALETTE gdrv::palette_handle = nullptr;
HINSTANCE gdrv::hinst; HINSTANCE gdrv::hinst;
HWND gdrv::hwnd; HWND gdrv::hwnd;
LOGPALETTEx256 gdrv::current_palette{};
int gdrv::sequence_handle; int gdrv::sequence_handle;
HDC gdrv::sequence_hdc; HDC gdrv::sequence_hdc;
int gdrv::use_wing = 0; int gdrv::use_wing = 0;
@@ -18,10 +19,12 @@ int gdrv::grtext_red = -1;
int gdrv::init(HINSTANCE hInst, HWND hWnd) int gdrv::init(HINSTANCE hInst, HWND hWnd)
{ {
LOGPALETTEx256 current_palette{};
hinst = hInst; hinst = hInst;
hwnd = hWnd; hwnd = hWnd;
if (!palette_handle) if (!palette_handle)
palette_handle = CreatePalette((LOGPALETTE*)&current_palette); palette_handle = CreatePalette(&current_palette);
return 0; return 0;
} }
@@ -37,17 +40,16 @@ void gdrv::get_focus()
} }
BITMAPINFO* gdrv::DibCreate(__int16 bpp, int width, int height) BITMAPINFO* gdrv::DibCreate(int16_t bpp, int width, int height)
{ {
auto sizeBytes = height * ((width * bpp / 8 + 3) & 0xFFFFFFFC); auto sizeBytes = height * (width * bpp / 8 + 3 & (~3));
auto buf = GlobalAlloc(0x42u, sizeBytes + 1064); auto dib = memory::allocate<BITMAPINFO>(1, (256 - 1) * sizeof(RGBQUAD) + sizeBytes);
auto dib = static_cast<BITMAPINFO*>(GlobalLock(buf));
if (!dib) if (!dib)
return nullptr; return nullptr;
dib->bmiHeader.biSizeImage = sizeBytes; dib->bmiHeader.biSizeImage = sizeBytes;
dib->bmiHeader.biWidth = width; dib->bmiHeader.biWidth = width;
dib->bmiHeader.biSize = 40; dib->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
dib->bmiHeader.biHeight = height; dib->bmiHeader.biHeight = height;
dib->bmiHeader.biPlanes = 1; dib->bmiHeader.biPlanes = 1;
dib->bmiHeader.biBitCount = bpp; dib->bmiHeader.biBitCount = bpp;
@@ -65,25 +67,15 @@ BITMAPINFO* gdrv::DibCreate(__int16 bpp, int width, int height)
dib->bmiHeader.biClrUsed = 256; dib->bmiHeader.biClrUsed = 256;
} }
int index = 0;
for (auto i = (int*)dib->bmiColors; index < static_cast<signed int>(dib->bmiHeader.biClrUsed) / 16; ++index) uint32_t paletteColors[]
{ {
*i++ = 0; 0, 0x800000, 0x8000, 8421376, 128, 8388736, 32896, 12632256,
*i++ = 0x800000; 8421504, 16711680, 65280, 16776960, 255, 16711935, 0xFFFF, 0xFFFFFF,
*i++ = 0x8000; };
*i++ = 8421376; for (auto index = 0u; index < dib->bmiHeader.biClrUsed; index += 16)
*i++ = 128; {
*i++ = 8388736; memcpy(&dib->bmiColors[index], paletteColors, sizeof paletteColors);
*i++ = 32896;
*i++ = 12632256;
*i++ = 8421504;
*i++ = 16711680;
*i++ = 65280;
*i++ = 16776960;
*i++ = 255;
*i++ = 16711935;
*i++ = 0xFFFF;
*i++ = 0xFFFFFF;
} }
return dib; return dib;
} }
@@ -108,31 +100,24 @@ void gdrv::DibSetUsage(BITMAPINFO* dib, HPALETTE hpal, int someFlag)
{ {
if (someFlag && someFlag <= 2) if (someFlag && someFlag <= 2)
{ {
auto pltPtr = (short*)((char*)dib + dib->bmiHeader.biSize); auto pltPtr = reinterpret_cast<short*>(dib->bmiColors);
for (int i = 0; i < numOfColors; ++i) for (auto i = 0; i < numOfColors; ++i)
{ {
*pltPtr++ = i; *pltPtr++ = i;
} }
} }
else else
{ {
assertm(false, "Entered bad code");
char* dibPtr = (char*)dib + dib->bmiHeader.biSize;
if (numOfColors >= 256) if (numOfColors >= 256)
numOfColors = 256; numOfColors = 256;
GetPaletteEntries(hpal, 0, numOfColors, pPalEntries); GetPaletteEntries(hpal, 0, numOfColors, pPalEntries);
int index = 0; for (auto index = 0; index < numOfColors; index++)
char* dibPtr2 = dibPtr + 1;
do
{ {
char v9 = pPalEntries[index++].peRed; dib->bmiColors[index].rgbRed = pPalEntries[index].peRed;
dibPtr2[1] = v9; dib->bmiColors[index].rgbGreen = pPalEntries[index].peGreen;
*dibPtr2 = dibPtr2[(char*)pPalEntries - dibPtr]; dib->bmiColors[index].rgbBlue = pPalEntries[index].peBlue;
*(dibPtr2 - 1) = dibPtr2[&pPalEntries[0].peGreen - (unsigned char*)dibPtr]; dib->bmiColors[index].rgbReserved = 0;
dibPtr2[2] = 0;
dibPtr2 += 4;
} }
while (index < numOfColors);
} }
} }
} }
@@ -156,7 +141,7 @@ int gdrv::create_bitmap_dib(gdrv_bitmap8* bmp, int width, int height)
if (dib->bmiHeader.biCompression == 3) if (dib->bmiHeader.biCompression == 3)
bmpBufPtr = (char*)&dib->bmiHeader.biPlanes + dib->bmiHeader.biSize; bmpBufPtr = (char*)&dib->bmiHeader.biPlanes + dib->bmiHeader.biSize;
else else
bmpBufPtr = (char*)&dib->bmiHeader.biSize + 4 * dib->bmiHeader.biClrUsed + dib->bmiHeader.biSize; bmpBufPtr = reinterpret_cast<char*>(&dib->bmiColors[dib->bmiHeader.biClrUsed]);
bmp->BmpBufPtr1 = bmpBufPtr; bmp->BmpBufPtr1 = bmpBufPtr;
bmp->BmpBufPtr2 = bmpBufPtr; bmp->BmpBufPtr2 = bmpBufPtr;
return 0; return 0;
@@ -185,20 +170,37 @@ int gdrv::create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag)
return 0; return 0;
} }
int gdrv::create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int size)
{
bmp->Dib = nullptr;
bmp->Width = width;
bmp->Stride = width;
bmp->BitmapType = BitmapType::Spliced;
bmp->Height = height;
char* buf = memory::allocate(size);
bmp->BmpBufPtr1 = buf;
if (!buf)
return -1;
bmp->BmpBufPtr2 = bmp->BmpBufPtr1;
return 0;
}
int gdrv::display_palette(PALETTEENTRY* plt) int gdrv::display_palette(PALETTEENTRY* plt)
{ {
LOGPALETTEx256 current_palette{};
if (palette_handle) if (palette_handle)
DeleteObject(palette_handle); DeleteObject(palette_handle);
palette_handle = CreatePalette((LOGPALETTE*)&current_palette); palette_handle = CreatePalette(&current_palette);
auto windowHandle = GetDesktopWindow(); auto windowHandle = GetDesktopWindow();
auto dc = winmain::_GetDC(windowHandle); auto dc = winmain::_GetDC(windowHandle);
SetSystemPaletteUse(dc, 2u); SetSystemPaletteUse(dc, 2u);
SetSystemPaletteUse(dc, 1u); SetSystemPaletteUse(dc, 1u);
auto pltHandle = SelectPalette(dc, palette_handle, 0); auto originalPalette = SelectPalette(dc, palette_handle, 0);
RealizePalette(dc); RealizePalette(dc);
SelectPalette(dc, pltHandle, 0); SelectPalette(dc, originalPalette, 0);
GetSystemPaletteEntries(dc, 0, 0x100u, current_palette.palPalEntry); GetSystemPaletteEntries(dc, 0, 256, current_palette.palPalEntry);
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
{ {
current_palette.palPalEntry[i].peFlags = 0; current_palette.palPalEntry[i].peFlags = 0;
@@ -219,15 +221,15 @@ int gdrv::display_palette(PALETTEENTRY* plt)
pltDst++; pltDst++;
} }
if (!(GetDeviceCaps(dc, 38) & 0x100)) if (!(GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE))
{ {
current_palette.palPalEntry[255].peBlue = -1; current_palette.palPalEntry[255].peBlue = -1;
current_palette.palPalEntry[255].peGreen = -1; current_palette.palPalEntry[255].peGreen = -1;
current_palette.palPalEntry[255].peRed = -1; current_palette.palPalEntry[255].peRed = -1;
} }
ResizePalette(palette_handle, 0x100u); ResizePalette(palette_handle, 256);
SetPaletteEntries(palette_handle, 0, 0x100u, current_palette.palPalEntry); SetPaletteEntries(palette_handle, 0, 256, current_palette.palPalEntry);
windowHandle = GetDesktopWindow(); windowHandle = GetDesktopWindow();
ReleaseDC(windowHandle, dc); ReleaseDC(windowHandle, dc);
return 0; return 0;
@@ -238,32 +240,32 @@ int gdrv::destroy_bitmap(gdrv_bitmap8* bmp)
{ {
if (!bmp) if (!bmp)
return -1; return -1;
if (bmp->BitmapType == BitmapType::RawBitmap) if (bmp->BitmapType == BitmapType::RawBitmap || bmp->BitmapType == BitmapType::Spliced)
{ {
memory::free(bmp->BmpBufPtr1); memory::free(bmp->BmpBufPtr1);
} }
else if (bmp->BitmapType == BitmapType::DibBitmap) else if (bmp->BitmapType == BitmapType::DibBitmap)
{ {
GlobalUnlock(GlobalHandle(bmp->Dib)); memory::free(bmp->Dib);
GlobalFree(GlobalHandle(bmp->Dib));
} }
memset(bmp, 0, sizeof(gdrv_bitmap8)); memset(bmp, 0, sizeof(gdrv_bitmap8));
return 0; return 0;
} }
UINT gdrv::start_blit_sequence() void gdrv::start_blit_sequence()
{ {
HDC dc = winmain::_GetDC(hwnd); HDC dc = winmain::_GetDC(hwnd);
sequence_handle = 0; sequence_handle = 0;
sequence_hdc = dc; sequence_hdc = dc;
SelectPalette(dc, palette_handle, 0); SelectPalette(dc, palette_handle, 0);
return RealizePalette(sequence_hdc); RealizePalette(sequence_hdc);
SetStretchBltMode(dc, stretchMode);
} }
void gdrv::blit_sequence(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest, int DestWidth, int DestHeight) void gdrv::blit_sequence(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest, int DestWidth, int DestHeight)
{ {
if (!use_wing) if (!use_wing)
StretchDIBits( StretchDIBitsScaled(
sequence_hdc, sequence_hdc,
xDest, xDest,
yDest, yDest,
@@ -273,10 +275,10 @@ void gdrv::blit_sequence(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, in
bmp->Height - ySrcOff - DestHeight, bmp->Height - ySrcOff - DestHeight,
DestWidth, DestWidth,
DestHeight, DestHeight,
bmp->BmpBufPtr1, bmp,
bmp->Dib, DIB_PAL_COLORS,
1u, SRCCOPY
SRCCOPY); );
} }
@@ -288,12 +290,13 @@ void gdrv::end_blit_sequence()
void gdrv::blit(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest, int DestWidth, int DestHeight) void gdrv::blit(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest, int DestWidth, int DestHeight)
{ {
HDC dc = winmain::_GetDC(hwnd); HDC dc = winmain::_GetDC(hwnd);
SetStretchBltMode(dc, stretchMode);
if (dc) if (dc)
{ {
SelectPalette(dc, palette_handle, 0); SelectPalette(dc, palette_handle, 0);
RealizePalette(dc); RealizePalette(dc);
if (!use_wing) if (!use_wing)
StretchDIBits( StretchDIBitsScaled(
dc, dc,
xDest, xDest,
yDest, yDest,
@@ -303,10 +306,10 @@ void gdrv::blit(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest,
bmp->Height - ySrcOff - DestHeight, bmp->Height - ySrcOff - DestHeight,
DestWidth, DestWidth,
DestHeight, DestHeight,
bmp->BmpBufPtr1, bmp,
bmp->Dib, DIB_PAL_COLORS,
1u, SRCCOPY
SRCCOPY); );
ReleaseDC(hwnd, dc); ReleaseDC(hwnd, dc);
} }
} }
@@ -316,8 +319,9 @@ void gdrv::blat(gdrv_bitmap8* bmp, int xDest, int yDest)
HDC dc = winmain::_GetDC(hwnd); HDC dc = winmain::_GetDC(hwnd);
SelectPalette(dc, palette_handle, 0); SelectPalette(dc, palette_handle, 0);
RealizePalette(dc); RealizePalette(dc);
SetStretchBltMode(dc, stretchMode);
if (!use_wing) if (!use_wing)
StretchDIBits( StretchDIBitsScaled(
dc, dc,
xDest, xDest,
yDest, yDest,
@@ -327,10 +331,10 @@ void gdrv::blat(gdrv_bitmap8* bmp, int xDest, int yDest)
0, 0,
bmp->Width, bmp->Width,
bmp->Height, bmp->Height,
bmp->BmpBufPtr1, bmp,
bmp->Dib, DIB_PAL_COLORS,
1u, SRCCOPY
SRCCOPY); );
ReleaseDC(hwnd, dc); ReleaseDC(hwnd, dc);
} }
@@ -340,16 +344,11 @@ void gdrv::fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int y
if (bmpHeight < 0) if (bmpHeight < 0)
bmpHeight = -bmpHeight; bmpHeight = -bmpHeight;
char* bmpPtr = &bmp->BmpBufPtr1[bmp->Width * (bmpHeight - height - yOff) + xOff]; char* bmpPtr = &bmp->BmpBufPtr1[bmp->Width * (bmpHeight - height - yOff) + xOff];
if (height > 0) for (; height > 0; --height)
{ {
do if (width > 0)
{ memset(bmpPtr, fillChar, width);
if (width > 0) bmpPtr += bmp->Stride;
memset(bmpPtr, fillChar, width);
bmpPtr += bmp->Stride;
--height;
}
while (height);
} }
} }
@@ -414,9 +413,48 @@ void gdrv::grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width,
sscanf_s(fontColor, "%d %d %d", &grtext_red, &grtext_green, &grtext_blue); sscanf_s(fontColor, "%d %d %d", &grtext_red, &grtext_green, &grtext_blue);
} }
int prevMode = SetBkMode(dc, 1); int prevMode = SetBkMode(dc, 1);
COLORREF color = SetTextColor(dc, (grtext_red) | (grtext_green << 8) | (grtext_blue << 16)); COLORREF color = SetTextColor(dc, grtext_red | grtext_green << 8 | grtext_blue << 16);
DrawTextA(dc, text, lstrlenA(text), &rc, 0x810u); DrawTextA(dc, text, lstrlenA(text), &rc, 0x810u);
SetBkMode(dc, prevMode); SetBkMode(dc, prevMode);
SetTextColor(dc, color); SetTextColor(dc, color);
ReleaseDC(hwnd, dc); ReleaseDC(hwnd, dc);
} }
int gdrv::StretchDIBitsScaled(HDC hdc, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc,
int SrcWidth, int SrcHeight, gdrv_bitmap8* bmp, UINT iUsage,
DWORD rop)
{
/*Scaled partial updates may leave 1px border artifacts around update area.
* Pad update area to compensate.*/
const int pad = 1, padX2 = pad * 2;
if (fullscrn::ScaleX > 1 && xSrc > pad && xSrc + pad < bmp->Width)
{
xSrc -= pad;
xDest -= pad;
SrcWidth += padX2;
DestWidth += padX2;
}
if (fullscrn::ScaleY > 1 && ySrc > pad && ySrc + pad < bmp->Height)
{
ySrc -= pad;
yDest -= pad;
SrcHeight += padX2;
DestHeight += padX2;
}
return StretchDIBits(
hdc,
static_cast<int>(round(xDest * fullscrn::ScaleX + fullscrn::OffsetX)),
static_cast<int>(round(yDest * fullscrn::ScaleY + fullscrn::OffsetY)),
static_cast<int>(round(DestWidth * fullscrn::ScaleX)),
static_cast<int>(round(DestHeight * fullscrn::ScaleY)),
xSrc,
ySrc,
SrcWidth,
SrcHeight,
bmp->BmpBufPtr1,
bmp->Dib,
iUsage,
rop);
}

View File

@@ -5,6 +5,7 @@ enum class BitmapType : char
None = 0, None = 0,
RawBitmap = 1, RawBitmap = 1,
DibBitmap = 2, DibBitmap = 2,
Spliced = 4,
}; };
struct gdrv_bitmap8 struct gdrv_bitmap8
@@ -21,14 +22,14 @@ struct gdrv_bitmap8
int YPosition; int YPosition;
}; };
struct LOGPALETTEx256 struct LOGPALETTEx256 : LOGPALETTE
{ {
WORD palVersion; PALETTEENTRY palPalEntry2[256 - 1];
WORD palNumEntries;
PALETTEENTRY palPalEntry[256];
LOGPALETTEx256() : palVersion(0x300), palNumEntries(256), palPalEntry{} LOGPALETTEx256() : palPalEntry2{}
{ {
palVersion = 0x300;
palNumEntries = 256;
} }
}; };
@@ -37,7 +38,6 @@ class gdrv
{ {
public: public:
static HPALETTE palette_handle; static HPALETTE palette_handle;
static LOGPALETTEx256 current_palette;
static int sequence_handle; static int sequence_handle;
static HDC sequence_hdc; static HDC sequence_hdc;
static int use_wing; static int use_wing;
@@ -45,14 +45,15 @@ public:
static int init(HINSTANCE hInst, HWND hWnd); static int init(HINSTANCE hInst, HWND hWnd);
static int uninit(); static int uninit();
static void get_focus(); static void get_focus();
static BITMAPINFO* DibCreate(__int16 bpp, int width, int height); static BITMAPINFO* DibCreate(int16_t bpp, int width, int height);
static void DibSetUsage(BITMAPINFO* dib, HPALETTE hpal, int someFlag); static void DibSetUsage(BITMAPINFO* dib, HPALETTE hpal, int someFlag);
static int create_bitmap_dib(gdrv_bitmap8* bmp, int width, int height); static int create_bitmap_dib(gdrv_bitmap8* bmp, int width, int height);
static int create_bitmap(gdrv_bitmap8* bmp, int width, int height); static int create_bitmap(gdrv_bitmap8* bmp, int width, int height);
static int create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag); static int create_raw_bitmap(gdrv_bitmap8* bmp, int width, int height, int flag);
static int create_spliced_bitmap(gdrv_bitmap8* bmp, int width, int height, int size);
static int destroy_bitmap(gdrv_bitmap8* bmp); static int destroy_bitmap(gdrv_bitmap8* bmp);
static int display_palette(PALETTEENTRY* plt); static int display_palette(PALETTEENTRY* plt);
static UINT start_blit_sequence(); static void start_blit_sequence();
static void blit_sequence(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest, int DestWidth, static void blit_sequence(gdrv_bitmap8* bmp, int xSrc, int ySrcOff, int xDest, int yDest, int DestWidth,
int DestHeight); int DestHeight);
static void end_blit_sequence(); static void end_blit_sequence();
@@ -65,9 +66,15 @@ public:
gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff); gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff);
static void grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6); static void grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6);
private: private:
/*COLORONCOLOR or HALFTONE*/
static const int stretchMode = COLORONCOLOR;
static HWND hwnd; static HWND hwnd;
static HINSTANCE hinst; static HINSTANCE hinst;
static int grtext_blue; static int grtext_blue;
static int grtext_green; static int grtext_green;
static int grtext_red; static int grtext_red;
static int StretchDIBitsScaled(HDC hdc, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc,
int SrcWidth, int SrcHeight, gdrv_bitmap8* bmp, UINT iUsage,
DWORD rop);
}; };

View File

@@ -9,7 +9,7 @@
int high_score::dlg_enter_name; int high_score::dlg_enter_name;
int high_score::dlg_score; int high_score::dlg_score;
int high_score::position; int high_score::dlg_position;
LPCSTR high_score::default_name; LPCSTR high_score::default_name;
high_score_struct* high_score::dlg_hst; high_score_struct* high_score::dlg_hst;
@@ -48,30 +48,27 @@ int high_score::read(high_score_struct* table, int* ptrToSmth)
if (!buf1) if (!buf1)
return 1; return 1;
char* buf2 = memory::allocate(300u); char* buf2 = memory::allocate(300u);
int position = 0; auto optPath = pinball::get_rc_string(166, 0);
high_score_struct* tablePtr = table; for (auto position = 0; position < 5; ++position)
const CHAR* optPath = pinball::get_rc_string(166, 0);
do
{ {
auto tablePtr = &table[position];
_itoa_s(position, Buffer, 10); _itoa_s(position, Buffer, 10);
lstrcatA(Buffer, ".Name"); lstrcatA(Buffer, ".Name");
options::get_string(optPath, Buffer, buf1, pinball::WindowName, 32); options::get_string(optPath, Buffer, buf1, "", 32);
buf1[32] = 0; buf1[32] = 0;
lstrcpyA(tablePtr->Name, buf1); lstrcpyA(tablePtr->Name, buf1);
_itoa_s(position, Buffer, 10); _itoa_s(position, Buffer, 10);
lstrcatA(Buffer, ".Score"); lstrcatA(Buffer, ".Score");
options::get_string(optPath, Buffer, buf1, pinball::WindowName, 300); options::get_string(optPath, Buffer, buf1, "", 300);
tablePtr->Score = atol(buf1); tablePtr->Score = atol(buf1);
for (int i = lstrlenA(tablePtr->Name); --i >= 0; scoreSum += tablePtr->Name[i]) for (int i = lstrlenA(tablePtr->Name); --i >= 0; scoreSum += tablePtr->Name[i])
{ {
} }
scoreSum += tablePtr->Score; scoreSum += tablePtr->Score;
++position;
++tablePtr;
} }
while (position < 5);
scramble_number_string(scoreSum, buf1); scramble_number_string(scoreSum, buf1);
options::get_string(optPath, "Verification", buf2, pinball::WindowName, 300); options::get_string(optPath, "Verification", buf2, "", 300);
if (lstrcmpA(buf1, buf2)) if (lstrcmpA(buf1, buf2))
clear_table(table); clear_table(table);
memory::free(buf1); memory::free(buf1);
@@ -88,9 +85,8 @@ int high_score::write(high_score_struct* table, int* ptrToSmth)
CHAR* buf = memory::allocate(300u); CHAR* buf = memory::allocate(300u);
if (!buf) if (!buf)
return 1; return 1;
int position = 0;
const CHAR* optPath = pinball::get_rc_string(166, 0); const CHAR* optPath = pinball::get_rc_string(166, 0);
do for (auto position = 0; position < 5; ++position)
{ {
_itoa_s(position, Buffer, 10); _itoa_s(position, Buffer, 10);
lstrcatA(Buffer, ".Name"); lstrcatA(Buffer, ".Name");
@@ -106,7 +102,6 @@ int high_score::write(high_score_struct* table, int* ptrToSmth)
++position; ++position;
++tablePtr; ++tablePtr;
} }
while (position < 5);
scramble_number_string(scoreSum, buf); scramble_number_string(scoreSum, buf);
options::set_string(optPath, "Verification", buf); options::set_string(optPath, "Verification", buf);
memory::free(buf); memory::free(buf);
@@ -177,7 +172,7 @@ void high_score::show_high_score_dialog(high_score_struct* table)
void high_score::show_and_set_high_score_dialog(high_score_struct* table, int score, int pos, LPCSTR defaultName) void high_score::show_and_set_high_score_dialog(high_score_struct* table, int score, int pos, LPCSTR defaultName)
{ {
position = pos; dlg_position = pos;
dlg_score = score; dlg_score = score;
dlg_hst = table; dlg_hst = table;
dlg_enter_name = 1; dlg_enter_name = 1;
@@ -214,12 +209,12 @@ INT_PTR high_score::HighScore(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
} }
if (dlg_enter_name == 1) if (dlg_enter_name == 1)
{ {
if (position == -1) if (dlg_position == -1)
{ {
dlg_enter_name = 0; dlg_enter_name = 0;
return 1; return 1;
} }
HWND nameTextBox = GetDlgItem(hWnd, position + DLG_HIGHSCORES_EditName1); HWND nameTextBox = GetDlgItem(hWnd, dlg_position + DLG_HIGHSCORES_EditName1);
ShowWindow(nameTextBox, 5); ShowWindow(nameTextBox, 5);
EnableWindow(nameTextBox, 1); EnableWindow(nameTextBox, 1);
SetFocus(nameTextBox); SetFocus(nameTextBox);
@@ -246,9 +241,9 @@ INT_PTR high_score::HighScore(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
break; break;
} }
GetDlgItemTextA(hWnd, position + DLG_HIGHSCORES_EditName1, name, 32); GetDlgItemTextA(hWnd, dlg_position + DLG_HIGHSCORES_EditName1, name, 32);
name[31] = 0; name[31] = 0;
place_new_score_into(dlg_hst, dlg_score, name, position); place_new_score_into(dlg_hst, dlg_score, name, dlg_position);
break; break;
case DLG_HIGHSCORES_Cancel: case DLG_HIGHSCORES_Cancel:
break; break;
@@ -281,7 +276,7 @@ void high_score::show_high_scores(HWND hDlg, high_score_struct* table)
int nextPosition = 0; int nextPosition = 0;
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
{ {
if (dlg_enter_name == 1 && position == i) if (dlg_enter_name == 1 && dlg_position == i)
{ {
hsdlg_show_score(hDlg, " ", dlg_score, i); hsdlg_show_score(hDlg, " ", dlg_score, i);
nextPosition = 1; nextPosition = 1;

View File

@@ -26,7 +26,7 @@ public:
private : private :
static int dlg_enter_name; static int dlg_enter_name;
static int dlg_score; static int dlg_score;
static int position; static int dlg_position;
static LPCSTR default_name; static LPCSTR default_name;
static high_score_struct* dlg_hst; static high_score_struct* dlg_hst;
static winhelp_entry help[21]; static winhelp_entry help[21];

View File

@@ -2,6 +2,7 @@
#include "loader.h" #include "loader.h"
#include "memory.h" #include "memory.h"
#include "partman.h" #include "partman.h"
#include "pb.h"
#include "pinball.h" #include "pinball.h"
#include "Sound.h" #include "Sound.h"
#include "zdrv.h" #include "zdrv.h"
@@ -47,20 +48,19 @@ soundListStruct loader::sound_list[65];
int loader::error(int errorCode, int captionCode) int loader::error(int errorCode, int captionCode)
{ {
int curCode = loader_errors[0].Code; auto curCode = loader_errors;
const char *errorText = nullptr, *errorCaption = nullptr; const char *errorText = nullptr, *errorCaption = nullptr;
int index = 0, index2 = 0; auto index = 0;
if (loader_errors[0].Code >= 0) while (curCode->Code >= 0)
do {
{ if (errorCode == curCode->Code)
if (errorCode == curCode) errorText = curCode->Message;
errorText = loader_errors[index2].Message; if (captionCode == curCode->Code)
if (captionCode == curCode) errorCaption = curCode->Message;
errorCaption = loader_errors[index2].Message; curCode++;
index2 = ++index; index++;
curCode = loader_errors[index].Code; }
}
while (curCode >= 0);
if (!errorText) if (!errorText)
errorText = loader_errors[index].Message; errorText = loader_errors[index].Message;
MessageBoxA(nullptr, errorText, errorCaption, 0x2000u); MessageBoxA(nullptr, errorText, errorCaption, 0x2000u);
@@ -89,7 +89,7 @@ void loader::loadfrom(datFileStruct* datFile)
for (auto groupIndex = 0; groupIndex < datFile->NumberOfGroups; ++groupIndex) for (auto groupIndex = 0; groupIndex < datFile->NumberOfGroups; ++groupIndex)
{ {
auto value = reinterpret_cast<__int16*>(partman::field(datFile, groupIndex, datFieldTypes::ShortValue)); auto value = reinterpret_cast<int16_t*>(partman::field(datFile, groupIndex, datFieldTypes::ShortValue));
if (value && *value == 202) if (value && *value == 202)
{ {
if (sound_count < 65) if (sound_count < 65)
@@ -116,7 +116,7 @@ void loader::unload()
int loader::get_sound_id(int groupIndex) int loader::get_sound_id(int groupIndex)
{ {
__int16 soundIndex = 1; int16_t soundIndex = 1;
if (sound_count <= 1) if (sound_count <= 1)
{ {
error(25, 26); error(25, 26);
@@ -135,20 +135,28 @@ int loader::get_sound_id(int groupIndex)
if (!sound_list[soundIndex].Loaded && !sound_list[soundIndex].WavePtr) if (!sound_list[soundIndex].Loaded && !sound_list[soundIndex].WavePtr)
{ {
WaveHeader wavHeader{};
int soundGroupId = sound_list[soundIndex].GroupIndex; int soundGroupId = sound_list[soundIndex].GroupIndex;
sound_list[soundIndex].Duration = 0.0; sound_list[soundIndex].Duration = 0.0;
if (soundGroupId > 0 && !pinball::quickFlag) if (soundGroupId > 0 && !pinball::quickFlag)
{ {
auto value = reinterpret_cast<__int16*>(partman::field(loader_table, soundGroupId, auto value = reinterpret_cast<int16_t*>(partman::field(loader_table, soundGroupId,
datFieldTypes::ShortValue)); datFieldTypes::ShortValue));
if (value && *value == 202) if (value && *value == 202)
{ {
/*FT sounds are in SOUND subfolder*/
char filePath[300]{}, fileName2[100]{};
auto fileName = partman::field(loader_table, soundGroupId, datFieldTypes::String); auto fileName = partman::field(loader_table, soundGroupId, datFieldTypes::String);
HFILE hFile = _lopen(fileName, 0); sprintf_s(fileName2, pb::FullTiltMode ? "SOUND\\%s" : "%s", fileName);
sound_list[soundIndex].Duration = static_cast<float>(static_cast<double>(_llseek(hFile, 0, SEEK_END)) * pinball::make_path_name(filePath, fileName2);
0.0000909090909090909);
HFILE hFile = _lopen(filePath, 0);
_lread(hFile, &wavHeader, sizeof wavHeader);
_lclose(hFile); _lclose(hFile);
sound_list[soundIndex].WavePtr = Sound::LoadWaveFile(fileName); auto sampleCount = wavHeader.data_size / (wavHeader.channels * (wavHeader.bits_per_sample / 8.0));
sound_list[soundIndex].Duration = static_cast<float>(sampleCount / wavHeader.sample_rate);
sound_list[soundIndex].WavePtr = Sound::LoadWaveFile(filePath);
} }
} }
} }
@@ -168,7 +176,7 @@ short loader::query_visual_states(int groupIndex)
short result; short result;
if (groupIndex < 0) if (groupIndex < 0)
return error(0, 17); return error(0, 17);
auto shortArr = reinterpret_cast<__int16*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortArray)); auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortArray));
if (shortArr && *shortArr == 100) if (shortArr && *shortArr == 100)
result = shortArr[1]; result = shortArr[1];
else else
@@ -187,7 +195,7 @@ char* loader::query_name(int groupIndex)
return partman::field(loader_table, groupIndex, datFieldTypes::GroupName); return partman::field(loader_table, groupIndex, datFieldTypes::GroupName);
} }
__int16* loader::query_iattribute(int groupIndex, int firstValue, int* arraySize) int16_t* loader::query_iattribute(int groupIndex, int firstValue, int* arraySize)
{ {
if (groupIndex < 0) if (groupIndex < 0)
{ {
@@ -197,7 +205,7 @@ __int16* loader::query_iattribute(int groupIndex, int firstValue, int* arraySize
for (auto skipIndex = 0;; ++skipIndex) for (auto skipIndex = 0;; ++skipIndex)
{ {
auto shortArr = reinterpret_cast<__int16*>(partman::field_nth(loader_table, groupIndex, auto shortArr = reinterpret_cast<int16_t*>(partman::field_nth(loader_table, groupIndex,
datFieldTypes::ShortArray, skipIndex)); datFieldTypes::ShortArray, skipIndex));
if (!shortArr) if (!shortArr)
break; break;
@@ -234,7 +242,7 @@ float* loader::query_float_attribute(int groupIndex, int groupIndexOffset, int f
skipIndex)); skipIndex));
if (!floatArr) if (!floatArr)
break; break;
if (static_cast<__int16>(floor(*floatArr)) == firstValue) if (static_cast<int16_t>(floor(*floatArr)) == firstValue)
return floatArr + 1; return floatArr + 1;
} }
@@ -242,11 +250,42 @@ float* loader::query_float_attribute(int groupIndex, int groupIndexOffset, int f
return nullptr; return nullptr;
} }
float loader::query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue, float defVal)
{
if (groupIndex < 0)
{
error(0, 22);
return NAN;
}
int stateId = state_id(groupIndex, groupIndexOffset);
if (stateId < 0)
{
error(16, 22);
return NAN;
}
for (auto skipIndex = 0;; ++skipIndex)
{
auto floatArr = reinterpret_cast<float*>(partman::field_nth(loader_table, stateId,
datFieldTypes::FloatArray, skipIndex));
if (!floatArr)
break;
if (static_cast<int16_t>(floor(*floatArr)) == firstValue)
return floatArr[1];
}
if (!isnan(defVal))
return defVal;
error(13, 22);
return NAN;
}
int loader::material(int groupIndex, visualStruct* visual) int loader::material(int groupIndex, visualStruct* visual)
{ {
if (groupIndex < 0) if (groupIndex < 0)
return error(0, 21); return error(0, 21);
auto shortArr = reinterpret_cast<__int16*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue)); auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue));
if (!shortArr) if (!shortArr)
return error(1, 21); return error(1, 21);
if (*shortArr != 300) if (*shortArr != 300)
@@ -290,7 +329,7 @@ int loader::state_id(int groupIndex, int groupIndexOffset)
auto visualState = query_visual_states(groupIndex); auto visualState = query_visual_states(groupIndex);
if (visualState <= 0) if (visualState <= 0)
return error(12, 24); return error(12, 24);
auto shortArr = reinterpret_cast<__int16*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue)); auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue));
if (!shortArr) if (!shortArr)
return error(1, 24); return error(1, 24);
if (*shortArr != 200) if (*shortArr != 200)
@@ -301,7 +340,7 @@ int loader::state_id(int groupIndex, int groupIndexOffset)
return groupIndex; return groupIndex;
groupIndex += groupIndexOffset; groupIndex += groupIndexOffset;
shortArr = reinterpret_cast<__int16*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue)); shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue));
if (!shortArr) if (!shortArr)
return error(1, 24); return error(1, 24);
if (*shortArr != 201) if (*shortArr != 201)
@@ -313,7 +352,7 @@ int loader::kicker(int groupIndex, visualKickerStruct* kicker)
{ {
if (groupIndex < 0) if (groupIndex < 0)
return error(0, 20); return error(0, 20);
auto shortArr = reinterpret_cast<__int16*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue)); auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, groupIndex, datFieldTypes::ShortValue));
if (!shortArr) if (!shortArr)
return error(1, 20); return error(1, 20);
if (*shortArr != 400) if (*shortArr != 400)
@@ -381,7 +420,7 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vis
visual->ZMap->ZPtr2 = visual->ZMap->ZPtr1; visual->ZMap->ZPtr2 = visual->ZMap->ZPtr1;
} }
auto shortArr = reinterpret_cast<__int16*>(partman::field(loader_table, stateId, datFieldTypes::ShortArray)); auto shortArr = reinterpret_cast<int16_t*>(partman::field(loader_table, stateId, datFieldTypes::ShortArray));
if (shortArr) if (shortArr)
{ {
unsigned int shortArrSize = partman::field_size(loader_table, stateId, datFieldTypes::ShortArray); unsigned int shortArrSize = partman::field_size(loader_table, stateId, datFieldTypes::ShortArray);
@@ -433,11 +472,11 @@ int loader::query_visual(int groupIndex, int groupIndexOffset, visualStruct* vis
auto floatArr = reinterpret_cast<float*>(partman::field(loader_table, stateId, datFieldTypes::FloatArray)); auto floatArr = reinterpret_cast<float*>(partman::field(loader_table, stateId, datFieldTypes::FloatArray));
if (!floatArr) if (!floatArr)
return 0; return 0;
if (*floatArr != 600.0) if (*floatArr != 600.0f)
return 0; return 0;
visual->FloatArrCount = (partman::field_size(loader_table, stateId, datFieldTypes::FloatArray) / 4) / 2 - 2; visual->FloatArrCount = partman::field_size(loader_table, stateId, datFieldTypes::FloatArray) / 4 / 2 - 2;
auto floatVal = static_cast<int>(floor(floatArr[1]) - 1.0); auto floatVal = static_cast<int>(floor(floatArr[1]) - 1.0f);
switch (floatVal) switch (floatVal)
{ {
case 0: case 0:

View File

@@ -48,6 +48,40 @@ struct visualStruct
zmap_header_type* ZMap; zmap_header_type* ZMap;
}; };
#pragma pack(push)
#pragma pack(1)
// WAVE file header format
struct WaveHeader
{
unsigned char riff[4]; // RIFF string
unsigned int overall_size; // overall size of file in bytes
unsigned char wave[4]; // WAVE string
unsigned char fmt_chunk_marker[4]; // fmt string with trailing null char
unsigned int length_of_fmt; // length of the format data
unsigned short format_type; // format type. 1-PCM, 3- IEEE float, 6 - 8bit A law, 7 - 8bit mu law
unsigned short channels; // no.of channels
unsigned int sample_rate; // sampling rate (blocks per second)
unsigned int byterate; // SampleRate * NumChannels * BitsPerSample/8
unsigned short block_align; // NumChannels * BitsPerSample/8
unsigned short bits_per_sample; // bits per sample, 8- 8bits, 16- 16 bits etc
unsigned char data_chunk_header[4]; // DATA string or FLLR string
unsigned int data_size; // NumSamples * NumChannels * BitsPerSample/8 - size of the next chunk that will be read
};
#pragma pack(pop)
static_assert(sizeof(WaveHeader) == 44, "Wrong size of WaveHeader");
class loader class loader
{ {
@@ -65,7 +99,8 @@ public:
static int query_visual(int groupIndex, int groupIndexOffset, visualStruct* visual); static int query_visual(int groupIndex, int groupIndexOffset, visualStruct* visual);
static char* query_name(int groupIndex); static char* query_name(int groupIndex);
static float* query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue); static float* query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue);
static __int16* query_iattribute(int groupIndex, int firstValue, int* arraySize); static float query_float_attribute(int groupIndex, int groupIndexOffset, int firstValue, float defVal);
static int16_t* query_iattribute(int groupIndex, int firstValue, int* arraySize);
static float play_sound(int soundIndex); static float play_sound(int soundIndex);
static datFileStruct* loader_table; static datFileStruct* loader_table;
private: private:

View File

@@ -131,7 +131,7 @@ float maths::ray_intersect_circle(ray_type* ray, circle_type* circle)
// Tca, L dot D, projection of L on D // Tca, L dot D, projection of L on D
float Tca = Ly * ray->Direction.Y + Lx * ray->Direction.X; float Tca = Ly * ray->Direction.Y + Lx * ray->Direction.X;
if (Tca < 0.0) // No intersection if Tca is negative if (Tca < 0.0f) // No intersection if Tca is negative
return 1000000000.0f; return 1000000000.0f;
// L dot L, distance from ray origin to circle center // L dot L, distance from ray origin to circle center
@@ -144,12 +144,12 @@ float maths::ray_intersect_circle(ray_type* ray, circle_type* circle)
// Thc^2 = rad^2 - d = rad^2 - L dot L + Tca dot Tca // Thc^2 = rad^2 - d = rad^2 - L dot L + Tca dot Tca
float ThcSq = circle->RadiusSq - LMagSq + Tca * Tca; float ThcSq = circle->RadiusSq - LMagSq + Tca * Tca;
if (ThcSq < 0.0) // No intersection if Thc is negative if (ThcSq < 0.0f) // No intersection if Thc is negative
return 1000000000.0f; return 1000000000.0f;
// T0 = Tca - Thc, distance from origin to first intersection // T0 = Tca - Thc, distance from origin to first intersection
float T0 = Tca - sqrt(ThcSq); float T0 = Tca - sqrt(ThcSq);
if (T0 < 0.0 || T0 > ray->MaxDistance) if (T0 < 0.0f || T0 > ray->MaxDistance)
return 1000000000.0f; return 1000000000.0f;
return T0; return T0;
} }
@@ -158,7 +158,7 @@ float maths::ray_intersect_circle(ray_type* ray, circle_type* circle)
float maths::normalize_2d(vector_type* vec) float maths::normalize_2d(vector_type* vec)
{ {
float mag = sqrt(vec->X * vec->X + vec->Y * vec->Y); float mag = sqrt(vec->X * vec->X + vec->Y * vec->Y);
if (0.0 != mag) if (mag != 0.0f)
{ {
vec->X = 1.0f / mag * vec->X; vec->X = 1.0f / mag * vec->X;
vec->Y = 1.0f / mag * vec->Y; vec->Y = 1.0f / mag * vec->Y;
@@ -179,7 +179,7 @@ void maths::line_init(line_type* line, float x0, float y0, float x1, float y1)
line->PerpendicularL.X = line->Direction.Y; line->PerpendicularL.X = line->Direction.Y;
line->PerpendicularL.Y = -line->Direction.X; line->PerpendicularL.Y = -line->Direction.X;
line->PreComp1 = -(line->Direction.Y * x0) + line->Direction.X * y0; line->PreComp1 = -(line->Direction.Y * x0) + line->Direction.X * y0;
if (line->Direction.X >= 0.000000001 || line->Direction.X <= -0.000000001) if (line->Direction.X >= 0.000000001f || line->Direction.X <= -0.000000001f)
{ {
v9 = x1; v9 = x1;
lineDirection = x0 >= x1; lineDirection = x0 >= x1;
@@ -210,7 +210,7 @@ float maths::ray_intersect_line(ray_type* ray, line_type* line)
bool v6; bool v6;
float perpDot = line->PerpendicularL.Y * ray->Direction.Y + ray->Direction.X * line->PerpendicularL.X; float perpDot = line->PerpendicularL.Y * ray->Direction.Y + ray->Direction.X * line->PerpendicularL.X;
if (perpDot < 0.0) if (perpDot < 0.0f)
{ {
float result = -((ray->Origin.X * line->PerpendicularL.X + ray->Origin.Y * line->PerpendicularL.Y + line-> float result = -((ray->Origin.X * line->PerpendicularL.X + ray->Origin.Y * line->PerpendicularL.Y + line->
PreComp1) PreComp1)
@@ -220,7 +220,7 @@ float maths::ray_intersect_line(ray_type* ray, line_type* line)
line->RayIntersect.X = result * ray->Direction.X + ray->Origin.X; line->RayIntersect.X = result * ray->Direction.X + ray->Origin.X;
float v4 = result * ray->Direction.Y + ray->Origin.Y; float v4 = result * ray->Direction.Y + ray->Origin.Y;
line->RayIntersect.Y = v4; line->RayIntersect.Y = v4;
if (0.0 == line->Direction.X) if (line->Direction.X == 0.0f)
{ {
if (v4 >= line->OriginX) if (v4 >= line->OriginX)
{ {
@@ -256,7 +256,7 @@ float maths::magnitude(vector_type* vec)
{ {
float result; float result;
auto magSq = vec->X * vec->X + vec->Y * vec->Y + vec->Z * vec->Z; auto magSq = vec->X * vec->X + vec->Y * vec->Y + vec->Z * vec->Z;
if (magSq == 0.0) if (magSq == 0.0f)
result = 0.0; result = 0.0;
else else
result = sqrt(magSq); result = sqrt(magSq);
@@ -342,7 +342,7 @@ float maths::distance_to_flipper(ray_type* ray1, ray_type* ray2)
auto distance = 1000000000.0f; auto distance = 1000000000.0f;
auto distanceType = -1; auto distanceType = -1;
auto newDistance = ray_intersect_line(ray1, &TFlipperEdge::lineA); auto newDistance = ray_intersect_line(ray1, &TFlipperEdge::lineA);
if (newDistance < 1000000000.0) if (newDistance < 1000000000.0f)
{ {
distance = newDistance; distance = newDistance;
distanceType = 0; distanceType = 0;
@@ -365,7 +365,7 @@ float maths::distance_to_flipper(ray_type* ray1, ray_type* ray2)
distance = newDistance; distance = newDistance;
distanceType = 1; distanceType = 1;
} }
if (!ray2 || distance >= 1000000000.0) if (!ray2 || distance >= 1000000000.0f)
return distance; return distance;
if (distanceType != -1) if (distanceType != -1)

View File

@@ -1,58 +1,40 @@
#include "pch.h" #include "pch.h"
#include "memory.h" #include "memory.h"
unsigned int memory::use_total; size_t memory::use_total;
int memory::critical_allocation; int memory::critical_allocation;
void (*memory::critical_callback)(); void (*memory::critical_callback)();
std::map<void*, size_t> memory::alloc_map{};
void memory::init(void (*callback)()) void memory::init(void (*callback)())
{ {
critical_callback = callback; critical_callback = callback;
} }
char* memory::allocate(unsigned int size) char* memory::allocate(size_t size)
{ {
char* buf = static_cast<char*>(malloc(size + 4)); auto buf = static_cast<char*>(malloc(size));
if (buf) if (!buf)
{ {
*(unsigned int*)buf = size << 8; if (critical_allocation && critical_callback)
use_total += size + 4; critical_callback();
*buf = size >= 0xFFDC ? -91 : 90; return nullptr;
return buf + 4;
} }
if (critical_allocation && critical_callback)
critical_callback(); use_total += size;
return nullptr; alloc_map[buf] = size;
return buf;
} }
void memory::free(void* buf) void memory::free(void* buf)
{ {
unsigned int* bufStart = static_cast<unsigned int*>(buf) - 1; auto alloc = alloc_map.find(buf);
use_total -= (*bufStart >> 8) + 4; if (alloc == alloc_map.end())
char firstChar = *(char*)bufStart;
if (firstChar == 90 || firstChar == -91)
std::free(bufStart);
else
assertm(false, "Unknown memory type");
}
char* memory::realloc(void* buf, unsigned int size)
{
if (!buf)
return allocate(size);
char* bufStart = static_cast<char*>(buf) - 4;
use_total -= *(unsigned int*)bufStart >> 8;
if (*bufStart != 90 && *bufStart != -91 ||
(bufStart = static_cast<char*>(std::realloc(bufStart, size + 4))) != nullptr)
{ {
char bufType = *bufStart; assertm(false, "Unknown memory type");
*(unsigned int*)bufStart = size << 8; return;
use_total += size;
*bufStart = bufType;
return bufStart + 4;
} }
if (critical_allocation && critical_callback)
critical_callback(); use_total -= alloc->second;
return nullptr; std::free(alloc->first);
} }

View File

@@ -1,22 +1,60 @@
#pragma once #pragma once
#include <map>
class memory class memory
{ {
public: public:
static void init(void (*callback)(void)); static void init(void (*callback)(void));
static char* allocate(unsigned int size); static char* allocate(size_t size);
static void free(void* buf); static void free(void* buf);
static char* realloc(void* buf, unsigned int size);
static unsigned int use_total; template <typename T>
static T* allocate(size_t count = 1, size_t add = 0)
{
size_t size = sizeof(T) * count + add;
auto buf = static_cast<T*>(malloc(size));
if (!buf)
{
if (critical_allocation && critical_callback)
critical_callback();
return nullptr;
}
use_total += size;
alloc_map[buf] = size;
return buf;
}
template <typename T>
static T* realloc(T* buf, size_t size)
{
if (!buf)
return reinterpret_cast<T*>(allocate(size));
auto alloc = alloc_map.find(buf);
if (alloc == alloc_map.end())
{
assertm(false, "Unknown memory type");
return buf;
}
auto newBuf = static_cast<T*>(std::realloc(alloc->first, size));
if (!newBuf)
{
if (critical_allocation && critical_callback)
critical_callback();
return nullptr;
}
use_total += size - alloc->second;
alloc_map.erase(alloc);
alloc_map[newBuf] = size;
return newBuf;
}
static size_t use_total;
static int critical_allocation; static int critical_allocation;
private:
static void (*critical_callback)(); static void (*critical_callback)();
static std::map<void*, size_t> alloc_map;
}; };
// Fill memory block with an integer value
inline void memset32(void* ptr, unsigned int value, int count)
{
auto p = (unsigned int*)ptr;
for (int i = 0; i < count; i++)
*p++ = value;
}

View File

@@ -1,15 +1,22 @@
#include "pch.h" #include "pch.h"
#include "midi.h" #include "midi.h"
#include "pb.h"
#include "pinball.h" #include "pinball.h"
tagMCI_OPEN_PARMSA midi::mci_open_info; tagMCI_OPEN_PARMSA midi::mci_open_info;
char midi::midi_device_type[28]; char midi::midi_file_name[28];
HWND midi::midi_notify_hwnd; HWND midi::midi_notify_hwnd;
int midi::midi_seq1_open, midi::midi_seq1_playing; int midi::midi_seq1_open, midi::midi_seq1_playing;
MCIERROR midi::play_pb_theme(int flag) MCIERROR midi::play_pb_theme(int flag)
{ {
if (pb::FullTiltMode)
{
return play_ft(track1);
}
MCI_PLAY_PARMS playParams; MCI_PLAY_PARMS playParams;
MCIERROR result = 0; MCIERROR result = 0;
@@ -26,6 +33,11 @@ MCIERROR midi::play_pb_theme(int flag)
MCIERROR midi::music_stop() MCIERROR midi::music_stop()
{ {
if (pb::FullTiltMode)
{
return stop_ft();
}
MCIERROR result = 0; MCIERROR result = 0;
if (midi_seq1_playing) if (midi_seq1_playing)
result = mciSendCommandA(mci_open_info.wDeviceID, MCI_STOP, 0, 0); result = mciSendCommandA(mci_open_info.wDeviceID, MCI_STOP, 0, 0);
@@ -34,18 +46,28 @@ MCIERROR midi::music_stop()
int midi::music_init(HWND hwnd) int midi::music_init(HWND hwnd)
{ {
if (pb::FullTiltMode)
{
return music_init_ft(hwnd);
}
mci_open_info.wDeviceID = 0; mci_open_info.wDeviceID = 0;
midi_notify_hwnd = hwnd; midi_notify_hwnd = hwnd;
lstrcpyA(midi_device_type, pinball::get_rc_string(156, 0)); lstrcpyA(midi_file_name, pinball::get_rc_string(156, 0));
mci_open_info.lpstrElementName = nullptr; mci_open_info.lpstrElementName = midi_file_name;
mci_open_info.lpstrDeviceType = midi_device_type; mci_open_info.lpstrDeviceType = nullptr;
auto result = mciSendCommandA(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_NOTIFY_SUPERSEDED, (DWORD_PTR)&mci_open_info); auto result = mciSendCommandA(0, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_NOTIFY_SUPERSEDED, (DWORD_PTR)&mci_open_info);
midi_seq1_open = result == 0; midi_seq1_open = result == 0;
return midi_seq1_open; return midi_seq1_open;
} }
MCIERROR midi::restart_midi_seq(int param) MCIERROR midi::restart_midi_seq(LPARAM param)
{ {
if (pb::FullTiltMode)
{
return play_ft(active_track);
}
MCI_PLAY_PARMS playParams; MCI_PLAY_PARMS playParams;
MCIERROR result = 0; MCIERROR result = 0;
@@ -58,7 +80,431 @@ MCIERROR midi::restart_midi_seq(int param)
void midi::music_shutdown() void midi::music_shutdown()
{ {
if (pb::FullTiltMode)
{
music_shutdown_ft();
return;
}
if (midi_seq1_open) if (midi_seq1_open)
mciSendCommandA(mci_open_info.wDeviceID, MCI_CLOSE, 0, 0); mciSendCommandA(mci_open_info.wDeviceID, MCI_CLOSE, 0, 0);
midi_seq1_open = 0; midi_seq1_open = 0;
} }
objlist_class<midi_struct>* midi::TrackList;
midi_struct *midi::track1, *midi::track2, *midi::track3, *midi::active_track, *midi::active_track2;
int midi::some_flag1;
int midi::music_init_ft(HWND hwnd)
{
midi_notify_hwnd = hwnd;
active_track = nullptr;
TrackList = new objlist_class<midi_struct>(0, 1);
track1 = load_track("taba1");
track2 = load_track("taba2");
track3 = load_track("taba3");
if (!track2)
track2 = track1;
if (!track3)
track3 = track1;
return 1;
}
void midi::music_shutdown_ft()
{
if (active_track)
stream_close(active_track);
while (TrackList->GetCount())
{
midi_struct* midi = TrackList->Get(0);
unload_track(midi);
TrackList->Delete(midi);
}
active_track = nullptr;
delete TrackList;
}
midi_struct* midi::load_track(LPCSTR fileName)
{
midi_struct* midi;
char filePath[256];
char fileName2[256];
lstrcpyA(fileName2, "sound\\");
lstrcatA(fileName2, fileName);
pinball::make_path_name(filePath, fileName2, 254u);
lstrcatA(filePath, ".MDS");
if (load_file(&midi, filePath, 0, 1))
return nullptr;
if (midi)
TrackList->Add(midi);
return midi;
}
int midi::load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, int flags)
{
int returnCode;
unsigned int fileSize;
HANDLE mapHandle = nullptr;
midi_struct* midi = nullptr;
HANDLE fileHandle = INVALID_HANDLE_VALUE;
int fileFlag = 0;
do
{
if ((flags & 3) == 0 || (flags & 3) == 3)
{
returnCode = 4;
break;
}
midi = static_cast<midi_struct*>(LocalAlloc(0x40u, sizeof(midi_struct)));
if (!midi)
{
returnCode = 1;
break;
}
midi->Magic = mmioFOURCC('M', 'D', 'S', 'I');
midi->StreamHandle = nullptr;
midi->PreparedBlocksCount = 0;
if ((flags & 2) != 0)
{
fileSize = fileSizeP;
}
else
{
fileFlag = 1;
fileHandle = CreateFileA(static_cast<LPCSTR>(filePtrOrPath), GENERIC_READ, 1u, nullptr, OPEN_EXISTING,
0x80u, nullptr);
if (fileHandle == INVALID_HANDLE_VALUE)
{
returnCode = 2;
break;
}
fileSize = GetFileSize(fileHandle, nullptr);
mapHandle = CreateFileMappingA(fileHandle, nullptr, 2u, 0, 0, nullptr);
if (!mapHandle)
{
returnCode = 2;
break;
}
filePtrOrPath = MapViewOfFile(mapHandle, 4u, 0, 0, 0);
if (!filePtrOrPath)
{
returnCode = 2;
break;
}
}
returnCode = read_file(midi, static_cast<riff_header*>(filePtrOrPath), fileSize);
}
while (false);
if (returnCode)
{
if (midi)
LocalFree(midi);
}
else
{
*midi_res = midi;
}
if (fileFlag)
{
if (filePtrOrPath)
UnmapViewOfFile(filePtrOrPath);
if (mapHandle)
CloseHandle(mapHandle);
if (fileHandle != INVALID_HANDLE_VALUE)
CloseHandle(fileHandle);
}
return returnCode;
}
int midi::read_file(midi_struct* midi, riff_header* filePtr, unsigned fileSize)
{
auto returnCode = 0;
do
{
midi->DataPtr1 = nullptr;
if (fileSize < 12)
{
returnCode = 3;
break;
}
if (filePtr->Riff != mmioFOURCC('R', 'I', 'F', 'F'))
{
returnCode = 3;
break;
}
if (filePtr->Mids != mmioFOURCC('M', 'I', 'D', 'S'))
{
returnCode = 3;
break;
}
if (filePtr->FileSize > fileSize - 8)
{
returnCode = 3;
break;
}
if (fileSize - 12 < 8)
{
returnCode = 3;
break;
}
if (filePtr->Fmt != mmioFOURCC('f', 'm', 't', ' '))
{
returnCode = 3;
break;
}
if (filePtr->FmtSize > fileSize - 12)
{
returnCode = 3;
break;
}
if (filePtr->FmtSize < 12)
{
returnCode = 3;
break;
}
midi->DwTimeFormat = filePtr->dwTimeFormat;
midi->CbMaxBuffer = filePtr->cbMaxBuffer;
midi->DwFlagsFormat = filePtr->dwFlags;
auto blocksSize = fileSize - 20 - filePtr->FmtSize;
if (blocksSize < 8)
{
returnCode = 3;
break;
}
auto dataChunk = reinterpret_cast<riff_data*>(reinterpret_cast<char*>(&filePtr->dwTimeFormat) + filePtr->FmtSize
);
if (dataChunk->Data != mmioFOURCC('d','a','t','a'))
{
returnCode = 3;
break;
}
if (dataChunk->DataSize > blocksSize || dataChunk->DataSize < 4)
{
returnCode = 3;
break;
}
midi->BlockCount = dataChunk->BlocksPerChunk;
midi->DataPtr1 = reinterpret_cast<midihdr_tag*>(memory::allocate(
dataChunk->BlocksPerChunk * (midi->CbMaxBuffer + sizeof(midihdr_tag))));
if (!midi->DataPtr1)
{
returnCode = 1;
break;
}
if (!midi->BlockCount)
{
returnCode = 3;
break;
}
auto blocksSizeIndex = blocksSize - 12;
auto srcPtr = dataChunk->Blocks;
auto* dstPtr = midi->DataPtr1;
for (auto blockIndex = midi->BlockCount; blockIndex; blockIndex--)
{
dstPtr->lpData = reinterpret_cast<LPSTR>(&dstPtr[1]);
dstPtr->dwBufferLength = midi->CbMaxBuffer;
dstPtr->dwFlags = 0;
dstPtr->dwUser = reinterpret_cast<DWORD_PTR>(midi);
dstPtr->lpNext = nullptr;
if (blocksSizeIndex < 8)
{
returnCode = 3;
break;
}
auto blockSize = srcPtr->CbBuffer;
if (blockSize > midi->CbMaxBuffer || blockSize > blocksSizeIndex - 8)
{
returnCode = 3;
break;
}
if ((midi->DwFlagsFormat & 1) != 0)
{
/*Not used in FT, some kind of compression*/
assertm(false, "Unimplemented code reached");
/*int a1[16];
a1[0] = (int)blockDataPtr;
a1[2] = blockSize;
a1[1] = blockSize;
if (!sub_4031A0(a1, dataPtr))
{
returnCode = 3; break;
}*/
}
else
{
dstPtr->dwBytesRecorded = blockSize;
memcpy(dstPtr->lpData, srcPtr->AData, blockSize);
}
blocksSizeIndex -= blockSize + 8;
srcPtr = reinterpret_cast<riff_block*>(&srcPtr->AData[blockSize]);
dstPtr = reinterpret_cast<midihdr_tag*>(reinterpret_cast<char*>(&dstPtr[1]) + midi->CbMaxBuffer);
}
}
while (false);
if (returnCode && midi->DataPtr1)
{
memory::free(midi->DataPtr1);
}
return returnCode;
}
int midi::play_ft(midi_struct* midi)
{
int result;
stop_ft();
if (!midi)
return 0;
if (some_flag1)
{
active_track2 = midi;
return 0;
}
if (stream_open(midi, 1))
{
active_track = nullptr;
result = 0;
}
else
{
active_track = midi;
result = 1;
}
return result;
}
int midi::stop_ft()
{
int returnCode = 0;
if (active_track)
returnCode = stream_close(active_track);
active_track = nullptr;
return returnCode;
}
int midi::unload_track(midi_struct* midi)
{
if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
return 6;
if (midi->StreamHandle)
stream_close(midi);
if (midi->DataPtr1)
{
memory::free(midi->DataPtr1);
}
midi->Magic = mmioFOURCC('d','a','t','a');
LocalFree(midi);
return 0;
}
int midi::stream_open(midi_struct* midi, char flags)
{
auto returnCode = 0;
if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
return 6;
UINT puDeviceID = -1;
auto steamOpenedFg = !midi->StreamHandle;
MIDIPROPTIMEDIV propdata{8, midi->DwTimeFormat};
if (steamOpenedFg &&
!midiStreamOpen(&midi->StreamHandle, &puDeviceID, 1u, reinterpret_cast<DWORD_PTR>(midi_callback), 0,
CALLBACK_FUNCTION) &&
!midiStreamProperty(midi->StreamHandle, reinterpret_cast<LPBYTE>(&propdata),MIDIPROP_TIMEDIV | MIDIPROP_SET))
{
midihdr_tag* blockPtr = midi->DataPtr1;
for (auto blockIndex = midi->BlockCount; blockIndex; blockIndex--)
{
if (midiOutPrepareHeader(reinterpret_cast<HMIDIOUT>(midi->StreamHandle), blockPtr, sizeof(MIDIHDR)) ||
midiStreamOut(midi->StreamHandle, blockPtr, sizeof(MIDIHDR)))
{
returnCode = 5;
break;
}
++midi->PreparedBlocksCount;
blockPtr = reinterpret_cast<midihdr_tag*>(reinterpret_cast<char*>(&blockPtr[1]) + blockPtr->dwBufferLength);
}
}
if (!returnCode)
{
if (!steamOpenedFg && (midi->SomeFlag2 & 4) == 0)
return 7;
midi->SomeFlag2 &= ~2;
if ((flags & 1) != 0)
midi->SomeFlag2 |= 2;
midi->SomeFlag2 &= ~4;
if (midiStreamRestart(midi->StreamHandle))
returnCode = 5;
}
if (returnCode && steamOpenedFg)
{
if (midi->StreamHandle)
stream_close(midi);
}
return returnCode;
}
int midi::stream_close(midi_struct* midi)
{
int returnCode;
if (midi->Magic != mmioFOURCC('M', 'D', 'S', 'I'))
return 6;
if (!midi->StreamHandle)
return 7;
midi->SomeFlag2 |= 1u;
if (midiOutReset(reinterpret_cast<HMIDIOUT>(midi->StreamHandle)))
{
returnCode = 5;
midi->SomeFlag2 &= ~1;
}
else
{
midihdr_tag* blockPtr = midi->DataPtr1;
for (int i = midi->BlockCount; i; --i)
{
midiOutUnprepareHeader(reinterpret_cast<HMIDIOUT>(midi->StreamHandle), blockPtr, sizeof(MIDIHDR));
blockPtr = reinterpret_cast<midihdr_tag*>(reinterpret_cast<char*>(&blockPtr[1]) + blockPtr->dwBufferLength);
}
midiStreamClose(midi->StreamHandle);
returnCode = 0;
midi->StreamHandle = nullptr;
midi->SomeFlag2 = 0;
}
return returnCode;
}
void midi::midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
if (wMsg == 969)
{
auto mhdr = reinterpret_cast<LPMIDIHDR>(dwParam1);
auto midi = reinterpret_cast<midi_struct*>(mhdr->dwUser);
if ((midi->SomeFlag2 & 2) == 0 || (midi->SomeFlag2 & 1) != 0 || midiStreamOut(
midi->StreamHandle, mhdr, sizeof(MIDIHDR)))
--midi->PreparedBlocksCount;
}
}

View File

@@ -1,16 +1,81 @@
#pragma once #pragma once
#include "objlist_class.h"
struct midi_struct
{
DWORD Magic;
DWORD DwTimeFormat;
DWORD CbMaxBuffer;
DWORD DwFlagsFormat;
midihdr_tag* DataPtr1;
HMIDISTRM StreamHandle;
int SomeFlag2;
int BlockCount;
int PreparedBlocksCount;
};
#pragma pack(push)
#pragma pack(1)
struct riff_block
{
DWORD TkStart;
DWORD CbBuffer;
char AData[4];
};
struct riff_data
{
DWORD Data;
DWORD DataSize;
DWORD BlocksPerChunk;
riff_block Blocks[1];
};
struct riff_header
{
DWORD Riff;
DWORD FileSize;
DWORD Mids;
DWORD Fmt;
DWORD FmtSize;
DWORD dwTimeFormat;
DWORD cbMaxBuffer;
DWORD dwFlags;
riff_data Data;
};
static_assert(sizeof(riff_block) == 0xC, "Wrong size of riff_block");
static_assert(sizeof(riff_data) == 0x18, "Wrong size of riff_data");
static_assert(sizeof(riff_header) == 0x38, "Wrong size of riff_header");
#pragma pack(pop)
class midi class midi
{ {
public: public:
static MCIERROR play_pb_theme(int flag); static MCIERROR play_pb_theme(int flag);
static MCIERROR music_stop(); static MCIERROR music_stop();
static int music_init(HWND hwnd); static int music_init(HWND hwnd);
static MCIERROR restart_midi_seq(int param); static MCIERROR restart_midi_seq(LPARAM param);
static void music_shutdown(); static void music_shutdown();
private: private:
static tagMCI_OPEN_PARMSA mci_open_info; static tagMCI_OPEN_PARMSA mci_open_info;
static char midi_device_type[28]; static char midi_file_name[28];
static HWND midi_notify_hwnd; static HWND midi_notify_hwnd;
static int midi_seq1_open, midi_seq1_playing; static int midi_seq1_open, midi_seq1_playing;
static objlist_class<midi_struct>* TrackList;
static midi_struct *track1, *track2, *track3, *active_track, *active_track2;
static int some_flag1;
static int music_init_ft(HWND hwnd);
static void music_shutdown_ft();
static midi_struct* load_track(LPCSTR fileName);
static int load_file(midi_struct** midi_res, void* filePtrOrPath, int fileSizeP, int flags);
static int read_file(midi_struct* midi, riff_header* filePtr, unsigned int fileSize);
static int play_ft(midi_struct* midi);
static int stop_ft();
static int unload_track(midi_struct* midi);
static int stream_open(midi_struct* midi, char flags);
static int stream_close(midi_struct* midi);
static void CALLBACK midi_callback(HMIDIOUT hmo, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1,
DWORD_PTR dwParam2);
}; };

View File

@@ -71,21 +71,21 @@ void nudge::_nudge(float xDiff, float yDiff)
auto ballList = pb::MainTable->BallList; auto ballList = pb::MainTable->BallList;
accelMod.X = xDiff * 0.5f; accelMod.X = xDiff * 0.5f;
accelMod.Y = yDiff * 0.5f; accelMod.Y = yDiff * 0.5f;
for (auto index = 0; index < ballList->Count(); index++) for (auto index = 0; index < ballList->GetCount(); index++)
{ {
auto ball = static_cast<TBall*>(ballList->Get(index)); auto ball = ballList->Get(index);
if (ball->ActiveFlag && !ball->CollisionComp) if (ball->ActiveFlag && !ball->CollisionComp)
{ {
ball->Acceleration.X = ball->Acceleration.X * ball->Speed; ball->Acceleration.X = ball->Acceleration.X * ball->Speed;
ball->Acceleration.Y = ball->Acceleration.Y * ball->Speed; ball->Acceleration.Y = ball->Acceleration.Y * ball->Speed;
maths::vector_add(&ball->Acceleration, &accelMod); maths::vector_add(&ball->Acceleration, &accelMod);
ball->Speed = maths::normalize_2d(&ball->Acceleration); ball->Speed = maths::normalize_2d(&ball->Acceleration);
if (0.0 == ball->Acceleration.X) if (ball->Acceleration.X == 0.0f)
invAccelX = 1000000000.0; invAccelX = 1000000000.0;
else else
invAccelX = 1.0f / ball->Acceleration.X; invAccelX = 1.0f / ball->Acceleration.X;
ball->InvAcceleration.X = invAccelX; ball->InvAcceleration.X = invAccelX;
if (0.0 == ball->Acceleration.Y) if (ball->Acceleration.Y == 0.0f)
invAccelY = 1000000000.0; invAccelY = 1000000000.0;
else else
invAccelY = 1.0f / ball->Acceleration.Y; invAccelY = 1.0f / ball->Acceleration.Y;
@@ -94,6 +94,6 @@ void nudge::_nudge(float xDiff, float yDiff)
} }
} }
render::shift(static_cast<int>(floor(xDiff + 0.5)), static_cast<int>(floor(0.5 - yDiff)), 0, 0, table->Width, render::shift(static_cast<int>(floor(xDiff + 0.5f)), static_cast<int>(floor(0.5f - yDiff)), 0, 0, table->Width,
table->Height); table->Height);
} }

View File

@@ -1,94 +0,0 @@
#include "pch.h"
#include "objlist_class.h"
#include <cstdlib>
#include "memory.h"
// v1 from Ida
objlist_class::objlist_class(int SizeInt, int growSize)
{
ListPtr = objlist_new(SizeInt);
GrowSize = growSize;
}
objlist_class::~objlist_class()
{
if (ListPtr)
memory::free(ListPtr);
}
void objlist_class::Add(void* value)
{
if (this->ListPtr->Count == this->ListPtr->Size)
Grow();
objlist_add_object(ListPtr, value);
}
void objlist_class::Grow()
{
this->ListPtr = objlist_grow(this->ListPtr, this->GrowSize);
}
int objlist_class::Delete(void* value)
{
return objlist_delete_object(ListPtr, value);
}
void* objlist_class::Get(int index)
{
if (index >= ListPtr->Count)
return nullptr;
return this->ListPtr->Array[index];
}
objlist_struct1* objlist_class::objlist_new(int sizeInt)
{
objlist_struct1* result = (objlist_struct1 *)memory::allocate(sizeof(void*) * sizeInt + sizeof(objlist_struct1));
if (!result)
return result;
result->Count = 0;
result->Size = sizeInt;
return result;
}
int objlist_class::objlist_add_object(objlist_struct1* ptrToStruct, void* value)
{
int addIndex = ptrToStruct->Count;
if (addIndex >= ptrToStruct->Size)
return 0;
ptrToStruct->Array[addIndex] = value;
return ++ptrToStruct->Count;
}
objlist_struct1* objlist_class::objlist_grow(objlist_struct1* ptrToStruct, int growSize)
{
objlist_struct1* resultPtr = ptrToStruct;
if (!ptrToStruct)
return resultPtr;
int newSizeInt = growSize + ptrToStruct->Count;
if (newSizeInt <= ptrToStruct->Size)
return resultPtr;
objlist_struct1* resultPtr2 = (objlist_struct1*)memory::realloc(ptrToStruct, sizeof(void*) * newSizeInt + sizeof(objlist_struct1));
if (!resultPtr2)
return resultPtr;
resultPtr = resultPtr2;
resultPtr2->Size = growSize + resultPtr2->Count;
return resultPtr;
}
int objlist_class::objlist_delete_object(objlist_struct1* ptrToStruct, void* value)
{
int count = ptrToStruct->Count;
int index = count - 1;
if (count - 1 < 0)
return 0;
for (void** i = &ptrToStruct->Array[index]; *i != value; --i)
{
if (--index < 0)
return 0;
}
ptrToStruct->Array[index] = ptrToStruct->Array[count - 1];
--ptrToStruct->Count;
return 1;
}

View File

@@ -1,28 +1,78 @@
#pragma once #pragma once
struct objlist_struct1 #include "memory.h"
{
int Size;
int Count;
void* Array[1];
};
template <class T>
class objlist_class class objlist_class
{ {
public: public:
objlist_class(int SizeInt, int growSize); objlist_class(int sizeInt, int growSize)
~objlist_class(); {
void Add(void* value); ListPtr = memory::allocate<T*>(sizeInt);
void Grow(); Count = 0;
int Delete(void* value); Size = sizeInt;
void* Get(int index); GrowSize = growSize;
int Count() const { return !ListPtr ? 0 : ListPtr->Count; } }
int Size() const { return !ListPtr ? 0 : ListPtr->Size; }
~objlist_class()
{
if (ListPtr)
memory::free(ListPtr);
}
void Add(T* value)
{
if (Count == Size)
Grow();
if (Count >= Size)
return;
ListPtr[Count] = value;
Count++;
}
void Grow()
{
if (!ListPtr)
return;
auto newSize = Count + GrowSize;
if (newSize <= Size)
return;
auto newList = memory::realloc(ListPtr, sizeof(T*) * newSize);
if (!newList)
return;
ListPtr = newList;
Size = newSize;
}
int Delete(T* value)
{
for (auto index = Count - 1; index >= 0; index--)
{
if (ListPtr[index] == value)
{
ListPtr[index] = ListPtr[Count - 1];
Count--;
return 1;
}
}
return 0;
}
T* Get(int index) const
{
if (index >= Count)
return nullptr;
return ListPtr[index];
}
int GetCount() const { return Count; }
int GetSize() const { return Size; }
private: private:
objlist_struct1* ListPtr; T** ListPtr;
int GrowSize; int GrowSize;
static objlist_struct1* objlist_new(int sizeInt); int Size;
static int objlist_add_object(objlist_struct1* ptrToStruct, void* value); int Count;
static objlist_struct1* objlist_grow(objlist_struct1* ptrToStruct, int growSize);
static int objlist_delete_object(objlist_struct1* ptrToStruct, void* value);
}; };

View File

@@ -4,6 +4,7 @@
#include "fullscrn.h" #include "fullscrn.h"
#include "memory.h" #include "memory.h"
#include "midi.h" #include "midi.h"
#include "pb.h"
#include "resource.h" #include "resource.h"
#include "Sound.h" #include "Sound.h"
#include "winmain.h" #include "winmain.h"
@@ -11,7 +12,7 @@
LPCSTR options::OptionsRegPath; LPCSTR options::OptionsRegPath;
LPSTR options::OptionsRegPathCur; LPSTR options::OptionsRegPathCur;
HMENU options::MenuHandle; HMENU options::MenuHandle;
optionsStruct options::Options; optionsStruct options::Options{};
winhelp_entry options::keymap_help[18] winhelp_entry options::keymap_help[18]
{ {
@@ -106,6 +107,7 @@ void options::init(HMENU menuHandle)
Options.LeftTableBumpKey = get_int(nullptr, "Left Table Bump key", Options.LeftTableBumpKey); Options.LeftTableBumpKey = get_int(nullptr, "Left Table Bump key", Options.LeftTableBumpKey);
Options.RightTableBumpKey = get_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey); Options.RightTableBumpKey = get_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey);
Options.BottomTableBumpKey = get_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey); Options.BottomTableBumpKey = get_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey);
Options.UniformScaling = get_int(nullptr, "Uniform scaling", true);
menu_check(Menu1_Sounds, Options.Sounds); menu_check(Menu1_Sounds, Options.Sounds);
Sound::Enable(0, 7, Options.Sounds); Sound::Enable(0, 7, Options.Sounds);
menu_check(Menu1_Music, Options.Music); menu_check(Menu1_Music, Options.Music);
@@ -114,10 +116,11 @@ void options::init(HMENU menuHandle)
menu_check(Menu1_2Players, Options.Players == 2); menu_check(Menu1_2Players, Options.Players == 2);
menu_check(Menu1_3Players, Options.Players == 3); menu_check(Menu1_3Players, Options.Players == 3);
menu_check(Menu1_4Players, Options.Players == 4); menu_check(Menu1_4Players, Options.Players == 4);
menu_check(Menu1_WindowUniformScale, Options.UniformScaling);
auto tmpBuf = memory::allocate(0x1F4u); auto tmpBuf = memory::allocate(0x1F4u);
if (tmpBuf) if (tmpBuf)
{ {
get_string(nullptr, "Shell Exe", tmpBuf, pinball::WindowName, 500); get_string(nullptr, "Shell Exe", tmpBuf, "", 500);
if (!*tmpBuf) if (!*tmpBuf)
{ {
if (MenuHandle) if (MenuHandle)
@@ -128,6 +131,8 @@ void options::init(HMENU menuHandle)
} }
memory::free(tmpBuf); memory::free(tmpBuf);
} }
update_resolution_menu();
} }
void options::uninit() void options::uninit()
@@ -142,6 +147,8 @@ void options::uninit()
set_int(nullptr, "Left Table Bump key", Options.LeftTableBumpKey); set_int(nullptr, "Left Table Bump key", Options.LeftTableBumpKey);
set_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey); set_int(nullptr, "Right Table Bump key", Options.RightTableBumpKey);
set_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey); set_int(nullptr, "Bottom Table Bump key", Options.BottomTableBumpKey);
set_int(nullptr, "Screen Resolution", Options.Resolution);
set_int(nullptr, "Uniform scaling", Options.UniformScaling);
} }
void options::path_init(LPCSTR regPath) void options::path_init(LPCSTR regPath)
@@ -187,73 +194,75 @@ void options::path_free()
int options::get_int(LPCSTR optPath, LPCSTR lpValueName, int defaultValue) int options::get_int(LPCSTR optPath, LPCSTR lpValueName, int defaultValue)
{ {
DWORD dwDisposition; DWORD dwDisposition;
HKEY hKey;
HKEY result = (HKEY)defaultValue, Data = (HKEY)defaultValue; auto result = defaultValue;
if (!OptionsRegPath) if (!OptionsRegPath)
return defaultValue; return result;
LPCSTR regPath = path(optPath);
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, 0xF003Fu, nullptr, &result, &dwDisposition)) auto regPath = path(optPath);
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition))
{ {
optPath = (LPCSTR)4; DWORD bufferSize = 4;
RegQueryValueExA(result, lpValueName, nullptr, nullptr, (LPBYTE)&Data, (LPDWORD)&optPath); RegQueryValueExA(hKey, lpValueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(&result), &bufferSize);
RegCloseKey(result); RegCloseKey(hKey);
} }
path_free(); path_free();
return (int)Data; return result;
} }
void options::set_int(LPCSTR optPath, LPCSTR lpValueName, int data) void options::set_int(LPCSTR optPath, LPCSTR lpValueName, int data)
{ {
DWORD dwDisposition; DWORD dwDisposition;
HKEY hKey;
if (OptionsRegPath) if (!OptionsRegPath)
return;
auto regPath = path(optPath);
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition))
{ {
const CHAR* regPath = path(optPath); RegSetValueExA(hKey, lpValueName, 0, 4u, reinterpret_cast<LPBYTE>(&data), 4u);
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, 0xF003Fu, nullptr, (PHKEY)&optPath, RegCloseKey(hKey);
&dwDisposition))
{
RegSetValueExA((HKEY)optPath, lpValueName, 0, 4u, (const BYTE*)&data, 4u);
RegCloseKey((HKEY)optPath);
}
path_free();
} }
path_free();
} }
void options::get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR lpString1, LPCSTR lpString2, int iMaxLength) void options::get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR dst, LPCSTR defaultValue, int iMaxLength)
{ {
const CHAR* v5 = (const CHAR*)iMaxLength; DWORD dwDisposition;
lstrcpynA(lpString1, lpString2, iMaxLength); HKEY hKey;
if (OptionsRegPath)
lstrcpynA(dst, defaultValue, iMaxLength);
if (!OptionsRegPath)
return;
auto regPath = path(optPath);
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition))
{ {
const CHAR* regPath = path(optPath); DWORD bufferSize = iMaxLength;
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, 0xF003Fu, nullptr, (PHKEY)&iMaxLength, RegQueryValueExA(hKey, lpValueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(dst), &bufferSize);
(LPDWORD)&optPath)) RegCloseKey(hKey);
{
lpString2 = v5;
RegQueryValueExA((HKEY)iMaxLength, lpValueName, nullptr, nullptr, (LPBYTE)lpString1, (LPDWORD)&lpString2);
RegCloseKey((HKEY)iMaxLength);
}
path_free();
} }
path_free();
} }
void options::set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value) void options::set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value)
{ {
DWORD dwDisposition; DWORD dwDisposition;
HKEY hKey;
if (OptionsRegPath) if (!OptionsRegPath)
return;
auto regPath = path(optPath);
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &dwDisposition))
{ {
const CHAR* regPath = path(optPath); RegSetValueExA(hKey, lpValueName, 0, 1u, LPBYTE(value), lstrlenA(value) + 1);
if (!RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, nullptr, 0, 0xF003Fu, nullptr, (PHKEY)&optPath, RegCloseKey(hKey);
&dwDisposition))
{
int v4 = lstrlenA(value);
RegSetValueExA((HKEY)optPath, lpValueName, 0, 1u, (const BYTE*)value, v4 + 1);
RegCloseKey((HKEY)optPath);
}
path_free();
} }
path_free();
} }
@@ -296,14 +305,83 @@ void options::toggle(UINT uIDCheckItem)
fullscrn::set_screen_mode(newValue); fullscrn::set_screen_mode(newValue);
menu_check(uIDCheckItem, newValue); menu_check(uIDCheckItem, newValue);
return; return;
} case Menu1_1Player:
if (uIDCheckItem > 407 && uIDCheckItem <= 411) case Menu1_2Players:
{ case Menu1_3Players:
Options.Players = uIDCheckItem - 407; case Menu1_4Players:
Options.Players = uIDCheckItem - Menu1_1Player + 1;
menu_check(Menu1_1Player, Options.Players == 1); menu_check(Menu1_1Player, Options.Players == 1);
menu_check(Menu1_2Players, Options.Players == 2); menu_check(Menu1_2Players, Options.Players == 2);
menu_check(Menu1_3Players, Options.Players == 3); menu_check(Menu1_3Players, Options.Players == 3);
menu_check(Menu1_4Players, Options.Players == 4); menu_check(Menu1_4Players, Options.Players == 4);
break;
case Menu1_MaximumResolution:
case Menu1_640x480:
case Menu1_800x600:
case Menu1_1024x768:
{
for (unsigned i = Menu1_MaximumResolution; i <= Menu1_1024x768; ++i)
menu_check(i, i == uIDCheckItem);
int newResolution = uIDCheckItem - Menu1_640x480;
if (uIDCheckItem == Menu1_MaximumResolution)
{
Options.Resolution = -1;
if (fullscrn::GetMaxResolution() != fullscrn::GetResolution())
winmain::Restart();
}
else if (newResolution != fullscrn::GetResolution() && newResolution <= fullscrn::GetMaxResolution())
{
Options.Resolution = newResolution;
winmain::Restart();
}
break;
}
case Menu1_WindowUniformScale:
Options.UniformScaling ^= true;
menu_check(Menu1_WindowUniformScale, Options.UniformScaling);
fullscrn::window_size_changed();
fullscrn::paint();
break;
default:
break;
}
}
void options::update_resolution_menu()
{
auto maxResolution = fullscrn::get_max_supported_resolution();
fullscrn::SetMaxResolution(maxResolution);
const CHAR* maxResText = pinball::get_rc_string(maxResolution + 2030, 0);
if (MenuHandle)
ModifyMenuA(MenuHandle, Menu1_MaximumResolution, 0, Menu1_MaximumResolution, maxResText);
for (auto resIndex = 0; resIndex < 3; resIndex++)
{
menu_set(fullscrn::resolution_array[resIndex].ResolutionMenuId, fullscrn::GetMaxResolution() >= resIndex);
}
for (auto i = Menu1_MaximumResolution; i <= Menu1_1024x768; ++i)
{
menu_check(i, 0);
}
if (Options.Resolution >= 0)
menu_check(fullscrn::resolution_array[fullscrn::GetResolution()].ResolutionMenuId, 1);
else
menu_check(Menu1_MaximumResolution, 1);
}
void options::init_resolution()
{
Options.Resolution = get_int(nullptr, "Screen Resolution", -1);
int maxRes = fullscrn::get_max_supported_resolution();
if (Options.Resolution == -1 || maxRes <= Options.Resolution)
{
fullscrn::SetMaxResolution(maxRes);
fullscrn::SetResolution(maxRes);
}
else
{
fullscrn::SetResolution(Options.Resolution);
} }
} }
@@ -332,7 +410,7 @@ INT_PTR _stdcall options::KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPAR
{ {
short vk = *vkPtr; short vk = *vkPtr;
auto vk2And = vk & 0x4000; auto vk2And = vk & 0x4000;
auto vkChar = static_cast<unsigned __int8>(vk); auto vkChar = static_cast<uint8_t>(vk);
unsigned short maxVk; unsigned short maxVk;
if (vk2And) if (vk2And)
@@ -411,17 +489,17 @@ INT_PTR _stdcall options::KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPAR
case KEYMAPPER_Ok: case KEYMAPPER_Ok:
{ {
auto ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_GETCURSEL, 0, 0); auto ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_GETCURSEL, 0, 0);
keyBindings[0] = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_GETITEMDATA, ind, 0); keyBindings[0] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperL, CB_GETITEMDATA, ind, 0));
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_GETCURSEL, 0, 0); ind = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_GETCURSEL, 0, 0);
keyBindings[1] = SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_GETITEMDATA, ind, 0); keyBindings[1] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_FlipperR, CB_GETITEMDATA, ind, 0));
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_GETCURSEL, 0, 0); ind = SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_GETCURSEL, 0, 0);
keyBindings[2] = SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_GETITEMDATA, ind, 0); keyBindings[2] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_Plunger, CB_GETITEMDATA, ind, 0));
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_GETCURSEL, 0, 0); ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_GETCURSEL, 0, 0);
keyBindings[3] = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_GETITEMDATA, ind, 0); keyBindings[3] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_BumpLeft, CB_GETITEMDATA, ind, 0));
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_GETCURSEL, 0, 0); ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_GETCURSEL, 0, 0);
keyBindings[4] = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_GETITEMDATA, ind, 0); keyBindings[4] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_BumpRight, CB_GETITEMDATA, ind, 0));
ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_GETCURSEL, 0, 0); ind = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_GETCURSEL, 0, 0);
keyBindings[5] = SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_GETITEMDATA, ind, 0); keyBindings[5] = static_cast<int>(SendDlgItemMessageA(hDlg, KEYMAPPER_BumpBottom, CB_GETITEMDATA, ind, 0));
auto sameKeyBound = 0; auto sameKeyBound = 0;
auto index = 1; auto index = 1;
@@ -493,7 +571,7 @@ INT_PTR _stdcall options::KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPAR
} }
LPSTR options::get_vk_key_name(unsigned __int16 vk, LPSTR keyName) LPSTR options::get_vk_key_name(uint16_t vk, LPSTR keyName)
{ {
LONG scanCode = MapVirtualKeyA(vk, MAPVK_VK_TO_VSC) << 16; LONG scanCode = MapVirtualKeyA(vk, MAPVK_VK_TO_VSC) << 16;
if (vk >= 0x21u && vk <= 0x2Eu) if (vk >= 0x21u && vk <= 0x2Eu)

View File

@@ -21,6 +21,8 @@ struct optionsStruct
int LeftTableBumpKeyDft; int LeftTableBumpKeyDft;
int RightTableBumpKeyDft; int RightTableBumpKeyDft;
int BottomTableBumpKeyDft; int BottomTableBumpKeyDft;
int Resolution;
bool UniformScaling;
}; };
@@ -33,15 +35,17 @@ public:
static void path_uninit(); static void path_uninit();
static int get_int(LPCSTR optPath, LPCSTR lpValueName, int defaultValue); static int get_int(LPCSTR optPath, LPCSTR lpValueName, int defaultValue);
static void set_int(LPCSTR optPath, LPCSTR lpValueName, int data); static void set_int(LPCSTR optPath, LPCSTR lpValueName, int data);
static void get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR lpString1, LPCSTR lpString2, int iMaxLength); static void get_string(LPCSTR optPath, LPCSTR lpValueName, LPSTR dst, LPCSTR defaultValue, int iMaxLength);
static void set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value); static void set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value);
static void menu_check(UINT uIDCheckItem, int check); static void menu_check(UINT uIDCheckItem, int check);
static void menu_set(UINT uIDEnableItem, int enable); static void menu_set(UINT uIDEnableItem, int enable);
static void toggle(UINT uIDCheckItem); static void toggle(UINT uIDCheckItem);
static void update_resolution_menu();
static void init_resolution();
static void keyboard(); static void keyboard();
static INT_PTR _stdcall KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); static INT_PTR _stdcall KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
static LPSTR get_vk_key_name(unsigned __int16 vk, LPSTR keyName); static LPSTR get_vk_key_name(uint16_t vk, LPSTR keyName);
static optionsStruct Options; static optionsStruct Options;
private: private:

View File

@@ -9,8 +9,7 @@ short partman::_field_size[] =
2, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0 2, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0
}; };
datFileStruct* partman::load_records(LPCSTR lpFileName, int resolution, bool fullTiltMode)
datFileStruct* partman::load_records(LPCSTR lpFileName)
{ {
_OFSTRUCT ReOpenBuff{}; _OFSTRUCT ReOpenBuff{};
datFileHeader header{}; datFileHeader header{};
@@ -26,7 +25,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
_lclose(fileHandle); _lclose(fileHandle);
return nullptr; return nullptr;
} }
auto datFile = (datFileStruct*)memory::allocate(sizeof(datFileStruct)); auto datFile = memory::allocate<datFileStruct>();
if (!datFile) if (!datFile)
{ {
_lclose(fileHandle); _lclose(fileHandle);
@@ -39,7 +38,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
else else
{ {
int lenOfStr = lstrlenA(header.Description); int lenOfStr = lstrlenA(header.Description);
auto descriptionBuf = static_cast<char*>(memory::allocate(lenOfStr + 1)); auto descriptionBuf = memory::allocate(lenOfStr + 1);
datFile->Description = descriptionBuf; datFile->Description = descriptionBuf;
if (!descriptionBuf) if (!descriptionBuf)
{ {
@@ -52,7 +51,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
if (header.Unknown) if (header.Unknown)
{ {
auto unknownBuf = static_cast<char*>(memory::allocate(header.Unknown)); auto unknownBuf = memory::allocate(header.Unknown);
if (!unknownBuf) if (!unknownBuf)
{ {
_lclose(fileHandle); _lclose(fileHandle);
@@ -65,7 +64,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
memory::free(unknownBuf); memory::free(unknownBuf);
} }
auto groupDataBuf = (datGroupData**)memory::allocate(sizeof(void*) * header.NumberOfGroups); auto groupDataBuf = memory::allocate<datGroupData*>(header.NumberOfGroups);
datFile->GroupData = groupDataBuf; datFile->GroupData = groupDataBuf;
if (!groupDataBuf) if (!groupDataBuf)
{ {
@@ -80,16 +79,15 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
{ {
auto entryCount = _lread_char(fileHandle); auto entryCount = _lread_char(fileHandle);
auto groupDataSize = entryCount <= 0 ? 0 : entryCount - 1; auto groupDataSize = entryCount <= 0 ? 0 : entryCount - 1;
auto groupData = reinterpret_cast<datGroupData*>(memory::allocate( auto groupData = memory::allocate<datGroupData>(1, sizeof(datEntryData) * groupDataSize);
sizeof(datEntryData) * groupDataSize + sizeof(datGroupData)));
datFile->GroupData[groupIndex] = groupData; datFile->GroupData[groupIndex] = groupData;
if (!groupData) if (!groupData)
break; break;
groupData->EntryCount = entryCount; groupData->EntryCount = 0;
datEntryData* entryData = groupData->Entries;
for (auto entryIndex = 0; entryIndex < entryCount; ++entryIndex) for (auto entryIndex = 0; entryIndex < entryCount; ++entryIndex)
{ {
auto entryData = &groupData->Entries[groupData->EntryCount];
auto entryType = static_cast<datFieldTypes>(_lread_char(fileHandle)); auto entryType = static_cast<datFieldTypes>(_lread_char(fileHandle));
entryData->EntryType = entryType; entryData->EntryType = entryType;
@@ -100,17 +98,28 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
if (entryType == datFieldTypes::Bitmap8bit) if (entryType == datFieldTypes::Bitmap8bit)
{ {
_hread(fileHandle, &bmpHeader, sizeof(dat8BitBmpHeader)); _hread(fileHandle, &bmpHeader, sizeof(dat8BitBmpHeader));
auto bmp = reinterpret_cast<gdrv_bitmap8*>(memory::allocate(sizeof(gdrv_bitmap8))); if (bmpHeader.Resolution != resolution && bmpHeader.Resolution != -1)
{
_llseek(fileHandle, bmpHeader.Size, 1);
continue;
}
auto bmp = memory::allocate<gdrv_bitmap8>();
entryData->Buffer = reinterpret_cast<char*>(bmp); entryData->Buffer = reinterpret_cast<char*>(bmp);
if (!bmp) if (!bmp)
{ {
abort = true; abort = true;
break; break;
} }
if (bmpHeader.IsFlagSet(bmp8Flags::DibBitmap) int bmpRez;
? gdrv::create_bitmap(bmp, bmpHeader.Width, bmpHeader.Height) if (bmpHeader.IsFlagSet(bmp8Flags::Spliced))
: gdrv::create_raw_bitmap(bmp, bmpHeader.Width, bmpHeader.Height, bmpRez = gdrv::create_spliced_bitmap(bmp, bmpHeader.Width, bmpHeader.Height, bmpHeader.Size);
bmpHeader.IsFlagSet(bmp8Flags::RawBmpUnaligned))) else if (bmpHeader.IsFlagSet(bmp8Flags::DibBitmap))
bmpRez = gdrv::create_bitmap(bmp, bmpHeader.Width, bmpHeader.Height);
else
bmpRez = gdrv::create_raw_bitmap(bmp, bmpHeader.Width, bmpHeader.Height,
bmpHeader.IsFlagSet(bmp8Flags::RawBmpUnaligned));
if (bmpRez)
{ {
abort = true; abort = true;
break; break;
@@ -121,10 +130,22 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
} }
else if (entryType == datFieldTypes::Bitmap16bit) else if (entryType == datFieldTypes::Bitmap16bit)
{ {
/*Full tilt has extra byte(@0:resolution) in zMap*/
if (fullTiltMode)
{
char zMapResolution = _lread_char(fileHandle);
fieldSize--;
if (zMapResolution != resolution && zMapResolution != -1)
{
_llseek(fileHandle, fieldSize, 1);
continue;
}
}
_hread(fileHandle, &zMapHeader, sizeof(dat16BitBmpHeader)); _hread(fileHandle, &zMapHeader, sizeof(dat16BitBmpHeader));
int length = fieldSize - sizeof(dat16BitBmpHeader); int length = fieldSize - sizeof(dat16BitBmpHeader);
auto zmap = reinterpret_cast<zmap_header_type*>(memory::allocate(sizeof(zmap_header_type) + length)); auto zmap = memory::allocate<zmap_header_type>(1, length);
zmap->Width = zMapHeader.Width; zmap->Width = zMapHeader.Width;
zmap->Height = zMapHeader.Height; zmap->Height = zMapHeader.Height;
zmap->Stride = zMapHeader.Stride; zmap->Stride = zMapHeader.Stride;
@@ -133,7 +154,7 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
} }
else else
{ {
char* entryBuffer = static_cast<char*>(memory::allocate(fieldSize)); char* entryBuffer = memory::allocate(fieldSize);
entryData->Buffer = entryBuffer; entryData->Buffer = entryBuffer;
if (!entryBuffer) if (!entryBuffer)
{ {
@@ -144,9 +165,9 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
} }
entryData->FieldSize = fieldSize; entryData->FieldSize = fieldSize;
datFile->NumberOfGroups = groupIndex + 1; groupData->EntryCount++;
++entryData;
} }
datFile->NumberOfGroups = groupIndex + 1;
} }
_lclose(fileHandle); _lclose(fileHandle);
@@ -159,30 +180,23 @@ datFileStruct* partman::load_records(LPCSTR lpFileName)
void partman::unload_records(datFileStruct* datFile) void partman::unload_records(datFileStruct* datFile)
{ {
for (int groupIndex = 0; groupIndex < datFile->NumberOfGroups; ++groupIndex) for (auto groupIndex = 0; groupIndex < datFile->NumberOfGroups; ++groupIndex)
{ {
datGroupData* group = datFile->GroupData[groupIndex]; auto group = datFile->GroupData[groupIndex];
if (group) if (!group)
continue;
for (auto entryIndex = 0; entryIndex < group->EntryCount; ++entryIndex)
{ {
int entryIndex = 0; auto entry = &group->Entries[entryIndex];
if (group->EntryCount > 0) if (entry->Buffer)
{ {
datEntryData* entry = group->Entries; if (entry->EntryType == datFieldTypes::Bitmap8bit)
do gdrv::destroy_bitmap(reinterpret_cast<gdrv_bitmap8*>(entry->Buffer));
{ memory::free(entry->Buffer);
if (entry->Buffer)
{
if (entry->EntryType == datFieldTypes::Bitmap8bit)
gdrv::destroy_bitmap((gdrv_bitmap8*)entry->Buffer);
memory::free(entry->Buffer);
}
++entryIndex;
++entry;
}
while (entryIndex < group->EntryCount);
} }
memory::free(group);
} }
memory::free(group);
} }
if (datFile->Description) if (datFile->Description)
memory::free(datFile->Description); memory::free(datFile->Description);
@@ -192,91 +206,45 @@ void partman::unload_records(datFileStruct* datFile)
char* partman::field(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType) char* partman::field(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType)
{ {
datGroupData* groupData = datFile->GroupData[groupIndex]; auto group = datFile->GroupData[groupIndex];
int entryCount = groupData->EntryCount; for (auto entryIndex = 0; entryIndex < group->EntryCount; ++entryIndex)
int entryIndex = 0;
if (entryCount <= 0)
return nullptr;
datEntryData* entry = groupData->Entries;
while (true)
{ {
auto entryType = entry->EntryType; auto entry = &group->Entries[entryIndex];
if (entryType == targetEntryType) if (entry->EntryType == targetEntryType)
return entry->Buffer;
if (entry->EntryType > targetEntryType)
break; break;
if (entryType > targetEntryType)
return nullptr;
++entryIndex;
++entry;
if (entryIndex < entryCount)
continue;
return nullptr;
} }
return entry->Buffer; return nullptr;
} }
char* partman::field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN) char* partman::field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN)
{ {
datGroupData* groupData = datFile->GroupData[groupIndex]; auto group = datFile->GroupData[groupIndex];
int entryCount = groupData->EntryCount, skipCount = 0, entryIndex = 0; for (auto skipCount = 0, entryIndex = 0; entryIndex < group->EntryCount; ++entryIndex)
if (0 < entryCount)
{ {
datEntryData* entry = groupData->Entries; auto entry = &group->Entries[entryIndex];
do if (entry->EntryType > targetEntryType)
{ break;
auto entryType = entry->EntryType; if (entry->EntryType == targetEntryType)
if (entryType == targetEntryType) if (skipCount++ == skipFirstN)
{ return entry->Buffer;
if (skipCount == skipFirstN)
{
return entry->Buffer;
}
skipCount++;
}
else
{
if (targetEntryType < entryType)
{
return nullptr;
}
}
entryIndex++;
entry++;
}
while (entryIndex < entryCount);
} }
return nullptr; return nullptr;
} }
int partman::field_size_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN) int partman::field_size_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN)
{ {
datGroupData* groupData = datFile->GroupData[groupIndex]; auto group = datFile->GroupData[groupIndex];
int entryCount = groupData->EntryCount, skipCount = 0, entryIndex = 0; for (auto skipCount = 0, entryIndex = 0; entryIndex < group->EntryCount; ++entryIndex)
if (0 < entryCount)
{ {
datEntryData* entry = groupData->Entries; auto entry = &group->Entries[entryIndex];
do if (entry->EntryType > targetEntryType)
{ return 0;
auto entryType = entry->EntryType; if (entry->EntryType == targetEntryType)
if (entryType == targetEntryType) if (skipCount++ == skipFirstN)
{ return entry->FieldSize;
if (skipCount == skipFirstN)
{
return entry->FieldSize;
}
skipCount++;
}
else
{
if (targetEntryType < entryType)
{
return 0;
}
}
entryIndex++;
entry++;
}
while (entryIndex < entryCount);
} }
return 0; return 0;
} }
@@ -288,46 +256,28 @@ int partman::field_size(datFileStruct* datFile, int groupIndex, datFieldTypes ta
int partman::record_labeled(datFileStruct* datFile, LPCSTR targetGroupName) int partman::record_labeled(datFileStruct* datFile, LPCSTR targetGroupName)
{ {
int trgGroupNameLen = lstrlenA(targetGroupName); auto targetLength = lstrlenA(targetGroupName);
int groupIndex = datFile->NumberOfGroups; for (int groupIndex = datFile->NumberOfGroups - 1; groupIndex >= 0; --groupIndex)
while (true)
{ {
if (--groupIndex < 0) auto groupName = field(datFile, groupIndex, datFieldTypes::GroupName);
return -1; if (!groupName)
char* groupName = field(datFile, groupIndex, datFieldTypes::GroupName); continue;
if (groupName)
{ int index;
int index = 0; for (index = 0; index < targetLength; index++)
bool found = trgGroupNameLen == 0; if (targetGroupName[index] != groupName[index])
if (trgGroupNameLen > 0)
{
LPCSTR targetNamePtr = targetGroupName;
do
{
if (*targetNamePtr != targetNamePtr[groupName - targetGroupName])
break;
++index;
++targetNamePtr;
}
while (index < trgGroupNameLen);
found = index == trgGroupNameLen;
}
if (found && !targetGroupName[index] && !groupName[index])
break; break;
} if (index == targetLength && !targetGroupName[index] && !groupName[index])
return groupIndex;
} }
return groupIndex;
return -1;
} }
char* partman::field_labeled(datFileStruct* datFile, LPCSTR lpString, datFieldTypes fieldType) char* partman::field_labeled(datFileStruct* datFile, LPCSTR lpString, datFieldTypes fieldType)
{ {
char* result; auto groupIndex = record_labeled(datFile, lpString);
int groupIndex = record_labeled(datFile, lpString); return groupIndex < 0 ? nullptr : field(datFile, groupIndex, fieldType);
if (groupIndex < 0)
result = nullptr;
else
result = field(datFile, groupIndex, fieldType);
return result;
} }
char partman::_lread_char(HFILE hFile) char partman::_lread_char(HFILE hFile)

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
enum class datFieldTypes : __int16 enum class datFieldTypes : int16_t
{ {
ShortValue = 0, ShortValue = 0,
//, does not have the 32bits size value, but a 16bits value(see above). //, does not have the 32bits size value, but a 16bits value(see above).
@@ -28,7 +28,8 @@ enum class datFieldTypes : __int16
enum class bmp8Flags : unsigned char enum class bmp8Flags : unsigned char
{ {
RawBmpUnaligned = 1 << 0, RawBmpUnaligned = 1 << 0,
DibBitmap = 1 << 1, DibBitmap = 1 << 1,
Spliced = 1 << 2,
}; };
@@ -56,7 +57,7 @@ struct datEntryData
struct datGroupData struct datGroupData
{ {
__int16 EntryCount; int16_t EntryCount;
datEntryData Entries[1]; datEntryData Entries[1];
}; };
@@ -71,11 +72,11 @@ struct datFileStruct
#pragma pack(1) #pragma pack(1)
struct dat8BitBmpHeader struct dat8BitBmpHeader
{ {
char Unknown1; char Resolution;
__int16 Width; int16_t Width;
__int16 Height; int16_t Height;
__int16 XPosition; int16_t XPosition;
__int16 YPosition; int16_t YPosition;
int Size; int Size;
bmp8Flags Flags; bmp8Flags Flags;
@@ -93,12 +94,12 @@ static_assert(sizeof(dat8BitBmpHeader) == 14, "Wrong size of dat8BitBmpHeader");
#pragma pack(push, 1) #pragma pack(push, 1)
struct __declspec(align(1)) dat16BitBmpHeader struct __declspec(align(1)) dat16BitBmpHeader
{ {
__int16 Width; int16_t Width;
__int16 Height; int16_t Height;
__int16 Stride; int16_t Stride;
int Unknown0; int Unknown0;
__int16 Unknown1_0; int16_t Unknown1_0;
__int16 Unknown1_1; int16_t Unknown1_1;
}; };
#pragma pack(pop) #pragma pack(pop)
@@ -108,7 +109,7 @@ static_assert(sizeof(dat16BitBmpHeader) == 14, "Wrong size of zmap_header_type")
class partman class partman
{ {
public: public:
static datFileStruct* load_records(LPCSTR lpFileName); static datFileStruct* load_records(LPCSTR lpFileName, int resolution, bool fullTiltMode);
static void unload_records(datFileStruct* datFile); static void unload_records(datFileStruct* datFile);
static char* field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN); static char* field_nth(datFileStruct* datFile, int groupIndex, datFieldTypes targetEntryType, int skipFirstN);
static char* field(datFileStruct* datFile, int groupIndex, datFieldTypes entryType); static char* field(datFileStruct* datFile, int groupIndex, datFieldTypes entryType);

View File

@@ -3,6 +3,7 @@
#include "control.h" #include "control.h"
#include "fullscrn.h"
#include "high_score.h" #include "high_score.h"
#include "memory.h" #include "memory.h"
#include "pinball.h" #include "pinball.h"
@@ -28,6 +29,8 @@ datFileStruct* pb::record_table = nullptr;
int pb::time_ticks = 0, pb::demo_mode = 0, pb::cheat_mode = 0, pb::game_mode = 2, pb::mode_countdown_, pb::state; int pb::time_ticks = 0, pb::demo_mode = 0, pb::cheat_mode = 0, pb::game_mode = 2, pb::mode_countdown_, pb::state;
float pb::time_now, pb::time_next, pb::ball_speed_limit; float pb::time_now, pb::time_next, pb::ball_speed_limit;
high_score_struct pb::highscore_table[5]; high_score_struct pb::highscore_table[5];
bool pb::FullTiltMode = false;
int pb::init() int pb::init()
{ {
@@ -38,7 +41,7 @@ int pb::init()
++memory::critical_allocation; ++memory::critical_allocation;
lstrcpyA(datFileName, winmain::DatFileName); lstrcpyA(datFileName, winmain::DatFileName);
pinball::make_path_name(dataFilePath, datFileName, 300); pinball::make_path_name(dataFilePath, datFileName, 300);
record_table = partman::load_records(dataFilePath); record_table = partman::load_records(dataFilePath, fullscrn::GetResolution(), FullTiltMode);
auto useBmpFont = 0; auto useBmpFont = 0;
pinball::get_rc_int(158, &useBmpFont); pinball::get_rc_int(158, &useBmpFont);
@@ -46,29 +49,32 @@ int pb::init()
score::load_msg_font("pbmsg_ft"); score::load_msg_font("pbmsg_ft");
if (!record_table) if (!record_table)
return (int)&record_table->NumberOfGroups + 1; return 1;
auto plt = (PALETTEENTRY*)partman::field_labeled(record_table, "background", datFieldTypes::Palette); auto plt = (PALETTEENTRY*)partman::field_labeled(record_table, "background", datFieldTypes::Palette);
gdrv::display_palette(plt); gdrv::display_palette(plt);
auto tableSize = (__int16*)partman::field_labeled(record_table, "table_size", datFieldTypes::ShortArray);
auto backgroundBmp = (gdrv_bitmap8*)partman::field_labeled(record_table, "background", datFieldTypes::Bitmap8bit); auto backgroundBmp = (gdrv_bitmap8*)partman::field_labeled(record_table, "background", datFieldTypes::Bitmap8bit);
auto cameraInfo = (float*)partman::field_labeled(record_table, "camera_info", datFieldTypes::FloatArray); auto cameraInfoId = partman::record_labeled(record_table, "camera_info") + fullscrn::GetResolution();
auto cameraInfo = (float*)partman::field(record_table, cameraInfoId, datFieldTypes::FloatArray);
/*Full tilt: table size depends on resolution*/
auto resInfo = &fullscrn::resolution_array[fullscrn::GetResolution()];
if (cameraInfo) if (cameraInfo)
{ {
memcpy(&projMat, cameraInfo, sizeof(float) * 4 * 3); memcpy(&projMat, cameraInfo, sizeof(float) * 4 * 3);
cameraInfo += 12; cameraInfo += 12;
auto projCenterX = tableSize[0] * 0.5f; auto projCenterX = resInfo->TableWidth * 0.5f;
auto projCenterY = tableSize[1] * 0.5f; auto projCenterY = resInfo->TableHeight * 0.5f;
auto projD = cameraInfo[0]; auto projD = cameraInfo[0];
proj::init(projMat, projD, projCenterX, projCenterY); proj::init(projMat, projD, projCenterX, projCenterY);
zMin = cameraInfo[1]; zMin = cameraInfo[1];
zScaler = cameraInfo[2]; zScaler = cameraInfo[2];
} }
render::init(nullptr, zMin, zScaler, tableSize[0], tableSize[1]); render::init(nullptr, zMin, zScaler, resInfo->TableWidth, resInfo->TableHeight);
gdrv::copy_bitmap( gdrv::copy_bitmap(
&render::vscreen, &render::vscreen,
backgroundBmp->Width, backgroundBmp->Width,
@@ -94,7 +100,7 @@ int pb::init()
MainTable = new TPinballTable(); MainTable = new TPinballTable();
high_score::read(highscore_table, &state); high_score::read(highscore_table, &state);
ball_speed_limit = static_cast<TBall*>(MainTable->BallList->Get(0))->Offset * 200.0f; ball_speed_limit = MainTable->BallList->Get(0)->Offset * 200.0f;
--memory::critical_allocation; --memory::critical_allocation;
return 0; return 0;
} }
@@ -209,7 +215,7 @@ void pb::replay_level(int demoMode)
void pb::ballset(int x, int y) void pb::ballset(int x, int y)
{ {
TBall* ball = static_cast<TBall*>(MainTable->BallList->Get(0)); TBall* ball = MainTable->BallList->Get(0);
ball->Acceleration.X = x * 30.0f; ball->Acceleration.X = x * 30.0f;
ball->Acceleration.Y = y * 30.0f; ball->Acceleration.Y = y * 30.0f;
ball->Speed = maths::normalize_2d(&ball->Acceleration); ball->Speed = maths::normalize_2d(&ball->Acceleration);
@@ -233,7 +239,7 @@ int pb::frame(int time)
else else
{ {
auto nudgeDec = nudge::nudge_count - timeMul; auto nudgeDec = nudge::nudge_count - timeMul;
if (nudgeDec <= 0.0) if (nudgeDec <= 0.0f)
nudgeDec = 0.0; nudgeDec = 0.0;
nudge::nudge_count = nudgeDec; nudge::nudge_count = nudgeDec;
} }
@@ -242,11 +248,11 @@ int pb::frame(int time)
score::update(MainTable->CurScoreStruct); score::update(MainTable->CurScoreStruct);
if (!MainTable->TiltLockFlag) if (!MainTable->TiltLockFlag)
{ {
if (nudge::nudge_count > 0.5) if (nudge::nudge_count > 0.5f)
{ {
pinball::InfoTextBox->Display(pinball::get_rc_string(25, 0), 2.0); pinball::InfoTextBox->Display(pinball::get_rc_string(25, 0), 2.0);
} }
if (nudge::nudge_count > 1.0) if (nudge::nudge_count > 1.0f)
MainTable->tilt(time_now); MainTable->tilt(time_now);
} }
} }
@@ -257,9 +263,9 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
{ {
vector_type vec1{}, vec2{}; vector_type vec1{}, vec2{};
for (int i = 0; i < MainTable->BallList->Count(); i++) for (int i = 0; i < MainTable->BallList->GetCount(); i++)
{ {
auto ball = static_cast<TBall*>(MainTable->BallList->Get(i)); auto ball = MainTable->BallList->Get(i);
if (ball->ActiveFlag != 0) if (ball->ActiveFlag != 0)
{ {
auto collComp = ball->CollisionComp; auto collComp = ball->CollisionComp;
@@ -282,13 +288,13 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
ball->Acceleration.Y = ball->Speed * ball->Acceleration.Y; ball->Acceleration.Y = ball->Speed * ball->Acceleration.Y;
maths::vector_add(&ball->Acceleration, &vec2); maths::vector_add(&ball->Acceleration, &vec2);
ball->Speed = maths::normalize_2d(&ball->Acceleration); ball->Speed = maths::normalize_2d(&ball->Acceleration);
ball->InvAcceleration.X = ball->Acceleration.X == 0.0 ? 1000000000.0f : 1.0f / ball->Acceleration.X; ball->InvAcceleration.X = ball->Acceleration.X == 0.0f ? 1000000000.0f : 1.0f / ball->Acceleration.X;
ball->InvAcceleration.Y = ball->Acceleration.Y == 0.0 ? 1000000000.0f : 1.0f / ball->Acceleration.Y; ball->InvAcceleration.Y = ball->Acceleration.Y == 0.0f ? 1000000000.0f : 1.0f / ball->Acceleration.Y;
} }
auto timeDelta2 = timeDelta; auto timeDelta2 = timeDelta;
auto timeNow2 = timeNow; auto timeNow2 = timeNow;
for (auto index = 10; timeDelta2 > 0.000001 && index; --index) for (auto index = 10; timeDelta2 > 0.000001f && index; --index)
{ {
auto time = collide(timeNow2, timeDelta2, ball); auto time = collide(timeNow2, timeDelta2, ball);
timeDelta2 -= time; timeDelta2 -= time;
@@ -300,9 +306,9 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
if (drawBalls) if (drawBalls)
{ {
for (int i = 0; i < MainTable->BallList->Count(); i++) for (int i = 0; i < MainTable->BallList->GetCount(); i++)
{ {
auto ball = static_cast<TBall*>(MainTable->BallList->Get(i)); auto ball = MainTable->BallList->Get(i);
if (ball->ActiveFlag) if (ball->ActiveFlag)
ball->Repaint(); ball->Repaint();
} }
@@ -311,8 +317,8 @@ void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
void pb::window_size(int* width, int* height) void pb::window_size(int* width, int* height)
{ {
*width = 600; *width = fullscrn::resolution_array[fullscrn::GetResolution()].TableWidth;
*height = 416; *height = fullscrn::resolution_array[fullscrn::GetResolution()].TableHeight;
} }
void pb::pause_continue() void pb::pause_continue()
@@ -440,7 +446,7 @@ void pb::keydown(int key)
{ {
case 'B': case 'B':
TBall* ball; TBall* ball;
if (MainTable->BallList->Count() <= 0) if (MainTable->BallList->GetCount() <= 0)
{ {
ball = new TBall(MainTable); ball = new TBall(MainTable);
} }
@@ -448,11 +454,11 @@ void pb::keydown(int key)
{ {
for (auto index = 0; ;) for (auto index = 0; ;)
{ {
ball = static_cast<TBall*>(MainTable->BallList->Get(index)); ball = MainTable->BallList->Get(index);
if (!ball->ActiveFlag) if (!ball->ActiveFlag)
break; break;
++index; ++index;
if (index >= MainTable->BallList->Count()) if (index >= MainTable->BallList->GetCount())
{ {
ball = new TBall(MainTable); ball = new TBall(MainTable);
break; break;
@@ -474,7 +480,7 @@ void pb::keydown(int key)
break; break;
case 'M': case 'M':
char buffer[20]; char buffer[20];
sprintf_s(buffer, "%ld", memory::use_total); sprintf_s(buffer, "%zu", memory::use_total);
MessageBoxA(winmain::hwnd_frame, buffer, "Mem:", 0x2000u); MessageBoxA(winmain::hwnd_frame, buffer, "Mem:", 0x2000u);
break; break;
case 'R': case 'R':
@@ -545,7 +551,7 @@ void pb::end_game()
scores[j] = scores[i]; scores[j] = scores[i];
scores[i] = score; scores[i] = score;
int index = scoreIndex[j]; int index = scoreIndex[j];
scoreIndex[j] = scoreIndex[i]; scoreIndex[j] = scoreIndex[i];
scoreIndex[i] = index; scoreIndex[i] = index;
} }
@@ -626,7 +632,7 @@ float pb::collide(float timeNow, float timeDelta, TBall* ball)
TEdgeSegment* edge = nullptr; TEdgeSegment* edge = nullptr;
auto distance = TTableLayer::edge_manager->FindCollisionDistance(&ray, ball, &edge); auto distance = TTableLayer::edge_manager->FindCollisionDistance(&ray, ball, &edge);
ball->EdgeCollisionCount = 0; ball->EdgeCollisionCount = 0;
if (distance >= 1000000000.0) if (distance >= 1000000000.0f)
{ {
maxDistance = timeDelta * ball->Speed; maxDistance = timeDelta * ball->Speed;
ball->RayMaxDistance = maxDistance; ball->RayMaxDistance = maxDistance;
@@ -638,7 +644,7 @@ float pb::collide(float timeNow, float timeDelta, TBall* ball)
else else
{ {
edge->EdgeCollision(ball, distance); edge->EdgeCollision(ball, distance);
if (ball->Speed > 0.000000001) if (ball->Speed > 0.000000001f)
return fabs(distance / ball->Speed); return fabs(distance / ball->Speed);
} }
} }

View File

@@ -14,6 +14,7 @@ public:
static datFileStruct* record_table; static datFileStruct* record_table;
static TPinballTable* MainTable; static TPinballTable* MainTable;
static high_score_struct highscore_table[5]; static high_score_struct highscore_table[5];
static bool FullTiltMode;
static int init(); static int init();
static int uninit(); static int uninit();
@@ -38,7 +39,7 @@ public:
static void tilt_no_more(); static void tilt_no_more();
static bool chk_highscore(); static bool chk_highscore();
static float collide(float timeNow, float timeDelta, TBall* ball); static float collide(float timeNow, float timeDelta, TBall* ball);
private : private:
static int demo_mode, mode_countdown_; static int demo_mode, mode_countdown_;
static int state; static int state;
}; };

View File

@@ -16,6 +16,7 @@
#include <cmath> #include <cmath>
#include <CommCtrl.h> #include <CommCtrl.h>
#include <htmlhelp.h> #include <htmlhelp.h>
#include <cstdint>
#include <type_traits> /*For control template*/ #include <type_traits> /*For control template*/
//#include <cstdlib> //#include <cstdlib>
@@ -25,4 +26,13 @@
/*Sound uses PlaySound*/ /*Sound uses PlaySound*/
#undef PlaySound #undef PlaySound
inline size_t pgm_save(int width, int height, char* data, FILE* outfile)
{
size_t n = 0;
n += fprintf(outfile, "P5\n%d %d\n%d\n", width, height, 0xFF);
n += fwrite(data, 1, width * height, outfile);
return n;
}
#endif //PCH_H #endif //PCH_H

View File

@@ -9,7 +9,6 @@ TTextBox* pinball::InfoTextBox;
TTextBox* pinball::MissTextBox; TTextBox* pinball::MissTextBox;
char pinball::getRcBuffer[6 * 256]; char pinball::getRcBuffer[6 * 256];
int pinball::rc_string_slot = 0; int pinball::rc_string_slot = 0;
char pinball::WindowName[2]{};
int pinball::LeftShift = -1; int pinball::LeftShift = -1;
int pinball::RightShift = -1; int pinball::RightShift = -1;

View File

@@ -13,7 +13,6 @@ public:
static int quickFlag; static int quickFlag;
static TTextBox* InfoTextBox; static TTextBox* InfoTextBox;
static TTextBox* MissTextBox; static TTextBox* MissTextBox;
static char WindowName[2];
static int RightShift; static int RightShift;
static int LeftShift; static int LeftShift;

View File

@@ -47,7 +47,7 @@ void proj::xform_to_2d(vector_type* vec, int* dst)
vector_type dstVec2{}; vector_type dstVec2{};
matrix_vector_multiply(&matrix, vec, &dstVec2); matrix_vector_multiply(&matrix, vec, &dstVec2);
if (0.0 == dstVec2.Z) if (dstVec2.Z == 0.0f)
projCoef = 999999.88f; projCoef = 999999.88f;
else else
projCoef = d_ / dstVec2.Z; projCoef = d_ / dstVec2.Z;

View File

@@ -18,9 +18,9 @@ void render::init(gdrv_bitmap8* bmp, float zMin, float zScaler, int width, int h
zscaler = zScaler; zscaler = zScaler;
zmin = zMin; zmin = zMin;
zmax = 4294967300.0f / zScaler + zMin; zmax = 4294967300.0f / zScaler + zMin;
sprite_list = reinterpret_cast<render_sprite_type_struct**>(memory::allocate(1000 * sizeof(void*))); sprite_list = memory::allocate<render_sprite_type_struct*>(1000);
dirty_list = reinterpret_cast<render_sprite_type_struct**>(memory::allocate(1000 * sizeof(void*))); dirty_list = memory::allocate<render_sprite_type_struct*>(1000);
ball_list = reinterpret_cast<render_sprite_type_struct**>(memory::allocate(20 * sizeof(void*))); ball_list = memory::allocate<render_sprite_type_struct*>(20);
gdrv::create_bitmap(&vscreen, width, height); gdrv::create_bitmap(&vscreen, width, height);
zdrv::create_zmap(&zscreen, width, height); zdrv::create_zmap(&zscreen, width, height);
zdrv::fill(&zscreen, zscreen.Width, zscreen.Height, 0, 0, 0xFFFF); zdrv::fill(&zscreen, zscreen.Width, zscreen.Height, 0, 0, 0xFFFF);
@@ -48,9 +48,9 @@ void render::uninit()
{ {
gdrv::destroy_bitmap(&vscreen); gdrv::destroy_bitmap(&vscreen);
zdrv::destroy_zmap(&zscreen); zdrv::destroy_zmap(&zscreen);
for (int i = 0; i < many_sprites; ++i) for (auto i = many_sprites - 1; i >= 0; --i)
remove_sprite(sprite_list[i]); remove_sprite(sprite_list[i]);
for (int j = 0; j < many_balls; ++j) for (auto j = many_balls - 1; j >= 0; --j)
remove_ball(ball_list[j]); remove_ball(ball_list[j]);
memory::free(ball_list); memory::free(ball_list);
memory::free(dirty_list); memory::free(dirty_list);
@@ -221,7 +221,7 @@ void render::sprite_modified(render_sprite_type_struct* sprite)
render_sprite_type_struct* render::create_sprite(VisualType visualType, gdrv_bitmap8* bmp, zmap_header_type* zMap, render_sprite_type_struct* render::create_sprite(VisualType visualType, gdrv_bitmap8* bmp, zmap_header_type* zMap,
int xPosition, int yPosition, rectangle_type* rect) int xPosition, int yPosition, rectangle_type* rect)
{ {
auto sprite = (render_sprite_type_struct*)memory::allocate(sizeof(render_sprite_type_struct)); auto sprite = memory::allocate<render_sprite_type_struct>();
if (!sprite) if (!sprite)
return nullptr; return nullptr;
sprite->BmpRect.YPosition = yPosition; sprite->BmpRect.YPosition = yPosition;
@@ -278,7 +278,6 @@ render_sprite_type_struct* render::create_sprite(VisualType visualType, gdrv_bit
void render::remove_sprite(render_sprite_type_struct* sprite) void render::remove_sprite(render_sprite_type_struct* sprite)
{ {
int spriteCount = many_sprites;
int index = 0; int index = 0;
if (many_sprites > 0) if (many_sprites > 0)
{ {
@@ -287,13 +286,12 @@ void render::remove_sprite(render_sprite_type_struct* sprite)
if (++index >= many_sprites) if (++index >= many_sprites)
return; return;
} }
while (index < spriteCount) while (index < many_sprites)
{ {
sprite_list[index] = sprite_list[index + 1]; sprite_list[index] = sprite_list[index + 1];
spriteCount = many_sprites;
++index; ++index;
} }
many_sprites = spriteCount - 1; many_sprites--;
if (sprite->SpriteArray) if (sprite->SpriteArray)
memory::free(sprite->SpriteArray); memory::free(sprite->SpriteArray);
memory::free(sprite); memory::free(sprite);
@@ -302,7 +300,6 @@ void render::remove_sprite(render_sprite_type_struct* sprite)
void render::remove_ball(struct render_sprite_type_struct* ball) void render::remove_ball(struct render_sprite_type_struct* ball)
{ {
int ballCount = many_balls;
int index = 0; int index = 0;
if (many_balls > 0) if (many_balls > 0)
{ {
@@ -311,13 +308,12 @@ void render::remove_ball(struct render_sprite_type_struct* ball)
if (++index >= many_balls) if (++index >= many_balls)
return; return;
} }
while (index < ballCount) while (index < many_balls)
{ {
ball_list[index] = ball_list[index + 1]; ball_list[index] = ball_list[index + 1];
ballCount = many_balls;
++index; ++index;
} }
many_balls = ballCount - 1; many_balls--;
memory::free(ball); memory::free(ball);
} }
} }
@@ -477,35 +473,21 @@ void render::paint_balls()
void render::unpaint_balls() void render::unpaint_balls()
{ {
auto ballPtr = &ball_list[many_balls - 1]; for (int index = many_balls-1; index >= 0; index--)
if (many_balls - 1 >= 0)
{ {
gdrv_bitmap8* bitmapPtr = &ball_bitmap[many_balls - 1]; auto curBall = ball_list[index];
for (int index = many_balls; index > 0; index--) if (curBall->DirtyRect.Width > 0)
{ gdrv::copy_bitmap(
struct render_sprite_type_struct* curBall = *ballPtr; &vscreen,
rectangle_type* rect2 = &(*ballPtr)->DirtyRect; curBall->DirtyRect.Width,
int width = (*ballPtr)->DirtyRect.Width; curBall->DirtyRect.Height,
if (width > 0) curBall->DirtyRect.XPosition,
gdrv::copy_bitmap( curBall->DirtyRect.YPosition,
&vscreen, &ball_bitmap[index],
width, 0,
(*ballPtr)->DirtyRect.Height, 0);
(*ballPtr)->DirtyRect.XPosition,
(*ballPtr)->DirtyRect.YPosition,
bitmapPtr,
0,
0);
rectangle_type* rectCopy = &curBall->BmpRectCopy; curBall->BmpRectCopy = curBall->DirtyRect;
rectCopy->XPosition = rect2->XPosition;
rectCopy->YPosition = rect2->YPosition;
rectCopy->Width = rect2->Width;
rectCopy->Height = rect2->Height;
--ballPtr;
--bitmapPtr;
}
} }
} }
@@ -542,7 +524,7 @@ void render::build_occlude_list()
if (!curSprite->UnknownFlag && curSprite->BoundingRect.Width != -1) if (!curSprite->UnknownFlag && curSprite->BoundingRect.Width != -1)
{ {
if (!spriteArr) if (!spriteArr)
spriteArr = reinterpret_cast<render_sprite_type_struct**>(memory::allocate(1000 * sizeof(void*))); spriteArr = memory::allocate<render_sprite_type_struct*>(1000);
int occludeCount = 0; int occludeCount = 0;
auto spritePtr2 = sprite_list; auto spritePtr2 = sprite_list;
for (int i = 0; i < many_sprites; ++i, ++spritePtr2) for (int i = 0; i < many_sprites; ++i, ++spritePtr2)
@@ -560,8 +542,7 @@ void render::build_occlude_list()
occludeCount = 0; occludeCount = 0;
if (occludeCount) if (occludeCount)
{ {
curSprite->SpriteArray = reinterpret_cast<render_sprite_type_struct**>(memory::realloc( curSprite->SpriteArray = memory::realloc(spriteArr, sizeof(void*) * occludeCount);
spriteArr, sizeof(void*) * occludeCount));
curSprite->SpriteCount = occludeCount; curSprite->SpriteCount = occludeCount;
spriteArr = nullptr; spriteArr = nullptr;
} }

View File

@@ -17,7 +17,7 @@ struct render_sprite_type_struct
zmap_header_type* ZMap; zmap_header_type* ZMap;
char UnknownFlag; char UnknownFlag;
VisualType VisualType; VisualType VisualType;
__int16 Depth; int16_t Depth;
rectangle_type BmpRectCopy; rectangle_type BmpRectCopy;
int ZMapOffestY; int ZMapOffestY;
int ZMapOffestX; int ZMapOffestX;

View File

@@ -224,12 +224,17 @@
#define Menu1_2Players 409 #define Menu1_2Players 409
#define Menu1_3Players 410 #define Menu1_3Players 410
#define Menu1_4Players 411 #define Menu1_4Players 411
#define Menu1_MaximumResolution 500
#define DLG_HIGHSCORES_Score1 501 #define DLG_HIGHSCORES_Score1 501
#define KEYMAPPER_Default 501 #define KEYMAPPER_Default 501
#define Menu1_640x480 501
#define DLG_HIGHSCORES_Score2 502 #define DLG_HIGHSCORES_Score2 502
#define Menu1_800x600 502
#define DLG_HIGHSCORES_Score3 503 #define DLG_HIGHSCORES_Score3 503
#define Menu1_1024x768 503
#define DLG_HIGHSCORES_Score4 504 #define DLG_HIGHSCORES_Score4 504
#define DLG_HIGHSCORES_Score5 505 #define DLG_HIGHSCORES_Score5 505
#define Menu1_WindowUniformScale 600
#define DLG_HIGHSCORES_EditName1 601 #define DLG_HIGHSCORES_EditName1 601
#define DLG_HIGHSCORES_EditName2 602 #define DLG_HIGHSCORES_EditName2 602
#define DLG_HIGHSCORES_EditName3 603 #define DLG_HIGHSCORES_EditName3 603
@@ -241,8 +246,8 @@
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 204 #define _APS_NEXT_RESOURCE_VALUE 204
#define _APS_NEXT_COMMAND_VALUE 40004 #define _APS_NEXT_COMMAND_VALUE 40006
#define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 102 #define _APS_NEXT_SYMED_VALUE 104
#endif #endif
#endif #endif

View File

@@ -1,8 +1,11 @@
#include "pch.h" #include "pch.h"
#include "score.h" #include "score.h"
#include "fullscrn.h"
#include "loader.h" #include "loader.h"
#include "memory.h" #include "memory.h"
#include "partman.h" #include "partman.h"
#include "pb.h"
#include "render.h" #include "render.h"
#include "TDrain.h" #include "TDrain.h"
#include "winmain.h" #include "winmain.h"
@@ -16,23 +19,26 @@ int score::init()
scoreStruct* score::create(LPCSTR fieldName, gdrv_bitmap8* renderBgBmp) scoreStruct* score::create(LPCSTR fieldName, gdrv_bitmap8* renderBgBmp)
{ {
auto score = reinterpret_cast<scoreStruct*>(memory::allocate(sizeof(scoreStruct))); auto score = memory::allocate<scoreStruct>();
if (!score) if (!score)
return nullptr; return nullptr;
score->Score = -9999; score->Score = -9999;
score->BackgroundBmp = renderBgBmp; score->BackgroundBmp = renderBgBmp;
auto shortArr = reinterpret_cast<__int16*>(partman::field_labeled(loader::loader_table, fieldName,
datFieldTypes::ShortArray)); /*Full tilt: score box dimensions index is offset by resolution*/
if (!shortArr) auto dimensionsId = partman::record_labeled(pb::record_table, fieldName) + fullscrn::GetResolution();
auto dimensions = reinterpret_cast<int16_t*>(partman::field(loader::loader_table, dimensionsId,
datFieldTypes::ShortArray));
if (!dimensions)
{ {
memory::free(score); memory::free(score);
return nullptr; return nullptr;
} }
int groupIndex = *shortArr++; int groupIndex = *dimensions++;
score->OffsetX = *shortArr++; score->OffsetX = *dimensions++;
score->OffsetY = *shortArr++; score->OffsetY = *dimensions++;
score->Width = *shortArr++; score->Width = *dimensions++;
score->Height = *shortArr; score->Height = *dimensions;
for (int index = 0; index < 10; index++) for (int index = 0; index < 10; index++)
{ {
@@ -45,13 +51,22 @@ scoreStruct* score::create(LPCSTR fieldName, gdrv_bitmap8* renderBgBmp)
scoreStruct* score::dup(scoreStruct* score, int scoreIndex) scoreStruct* score::dup(scoreStruct* score, int scoreIndex)
{ {
auto result = reinterpret_cast<scoreStruct*>(memory::allocate(sizeof(scoreStruct))); auto result = memory::allocate<scoreStruct>();
if (result) if (result)
memcpy(result, score, sizeof(scoreStruct)); memcpy(result, score, sizeof(scoreStruct));
return result; return result;
} }
void score::load_msg_font(LPCSTR lpName) void score::load_msg_font(LPCSTR lpName)
{
/*3DPB stores font in resources, FT in dat. FT font has multiple resolutions*/
if (pb::FullTiltMode)
load_msg_font_FT(lpName);
else
load_msg_font_3DPB(lpName);
}
void score::load_msg_font_3DPB(LPCSTR lpName)
{ {
auto resHandle = FindResourceA(winmain::hinst, lpName, RT_RCDATA); auto resHandle = FindResourceA(winmain::hinst, lpName, RT_RCDATA);
if (!resHandle) if (!resHandle)
@@ -61,16 +76,16 @@ void score::load_msg_font(LPCSTR lpName)
if (!resGlobal) if (!resGlobal)
return; return;
auto rcData = static_cast<__int16*>(LockResource(resGlobal)); auto rcData = static_cast<int16_t*>(LockResource(resGlobal));
auto fontp = reinterpret_cast<score_msg_font_type*>(memory::allocate(sizeof(score_msg_font_type))); auto fontp = memory::allocate<score_msg_font_type>();
msg_fontp = fontp; msg_fontp = fontp;
if (!fontp) if (!fontp)
{ {
FreeResource(resGlobal); FreeResource(resGlobal);
return; return;
} }
memset(fontp->Chars, 0, sizeof(fontp->Chars)); memset(fontp->Chars, 0, sizeof fontp->Chars);
auto maxWidth = 0; auto maxWidth = 0;
auto ptrToWidths = (char*)rcData + 6; auto ptrToWidths = (char*)rcData + 6;
@@ -102,7 +117,7 @@ void score::load_msg_font(LPCSTR lpName)
if (!width) if (!width)
continue; continue;
auto bmp = reinterpret_cast<gdrv_bitmap8*>(memory::allocate(sizeof(gdrv_bitmap8))); auto bmp = memory::allocate<gdrv_bitmap8>();
msg_fontp->Chars[charInd] = bmp; msg_fontp->Chars[charInd] = bmp;
if (!bmp) if (!bmp)
{ {
@@ -130,23 +145,56 @@ void score::load_msg_font(LPCSTR lpName)
} }
} }
memory::free(tmpCharBur);
if (charInd != 128) if (charInd != 128)
unload_msg_font(); unload_msg_font();
FreeResource(resGlobal); FreeResource(resGlobal);
} }
void score::load_msg_font_FT(LPCSTR lpName)
{
if (!pb::record_table)
return;
int groupIndex = partman::record_labeled(pb::record_table, lpName);
if (groupIndex < 0)
return;
msg_fontp = reinterpret_cast<score_msg_font_type*>(memory::allocate(sizeof(score_msg_font_type)));
if (!msg_fontp)
return;
memset(msg_fontp, 0, sizeof(score_msg_font_type));
auto gapArray = reinterpret_cast<int16_t*>(partman::field(pb::record_table, groupIndex, datFieldTypes::ShortArray));
if (gapArray)
msg_fontp->GapWidth = gapArray[fullscrn::GetResolution()];
else
msg_fontp->GapWidth = 0;
for (auto charIndex = 32; charIndex < 128; charIndex++, ++groupIndex)
{
auto bmp = reinterpret_cast<gdrv_bitmap8*>(partman::field(pb::record_table, groupIndex,
datFieldTypes::Bitmap8bit));
if (!bmp)
break;
if (!msg_fontp->Height)
msg_fontp->Height = bmp->Height;
msg_fontp->Chars[charIndex] = bmp;
}
}
void score::unload_msg_font() void score::unload_msg_font()
{ {
if (msg_fontp) if (msg_fontp)
{ {
for (int i = 0; i < 128; i++) /*3DB creates bitmaps, FT just references them from partman*/
{ if (!pb::FullTiltMode)
if (msg_fontp->Chars[i]) for (int i = 0; i < 128; i++)
{ {
gdrv::destroy_bitmap(msg_fontp->Chars[i]); if (msg_fontp->Chars[i])
memory::free(msg_fontp->Chars[i]); {
gdrv::destroy_bitmap(msg_fontp->Chars[i]);
memory::free(msg_fontp->Chars[i]);
}
} }
} memory::free(msg_fontp);
msg_fontp = nullptr; msg_fontp = nullptr;
} }
} }
@@ -191,7 +239,7 @@ void score::set(scoreStruct* score, int value)
void score::update(scoreStruct* score) void score::update(scoreStruct* score)
{ {
char scoreBuf[12]; char scoreBuf[12]{};
if (score && score->DirtyFlag && score->Score <= 1000000000) if (score && score->DirtyFlag && score->Score <= 1000000000)
{ {
score->DirtyFlag = false; score->DirtyFlag = false;
@@ -201,12 +249,11 @@ void score::update(scoreStruct* score)
if (score->Score >= 0) if (score->Score >= 0)
{ {
_ltoa_s(score->Score, scoreBuf, 10); _ltoa_s(score->Score, scoreBuf, 10);
int len = strlen(scoreBuf); for (ptrdiff_t index = strlen(scoreBuf) - 1; index >= 0; index--)
for (int index = len - 1; index >= 0; index--)
{ {
unsigned char curChar = scoreBuf[index]; unsigned char curChar = scoreBuf[index];
curChar -= '0'; curChar -= '0';
gdrv_bitmap8* bmp = score->CharBmp[curChar]; gdrv_bitmap8* bmp = score->CharBmp[curChar % 10];
x -= bmp->Width; x -= bmp->Width;
int height = bmp->Height; int height = bmp->Height;
int width = bmp->Width; int width = bmp->Width;

View File

@@ -42,4 +42,7 @@ public:
static void set(scoreStruct* score, int value); static void set(scoreStruct* score, int value);
static void update(scoreStruct* score); static void update(scoreStruct* score);
static void string_format(int score, char* str); static void string_format(int score, char* str);
private :
static void load_msg_font_3DPB(LPCSTR lpName);
static void load_msg_font_FT(LPCSTR lpName);
}; };

View File

@@ -6,13 +6,14 @@
#include "pinball.h" #include "pinball.h"
HINSTANCE splash::HInstance; HINSTANCE splash::HInstance;
HGDIOBJ splash::OriginalDcBitmap = nullptr;
splash_struct* splash::splash_screen(HINSTANCE hInstance, LPCSTR bmpName1, LPCSTR bmpName2) splash_struct* splash::splash_screen(HINSTANCE hInstance, LPCSTR bmpName1, LPCSTR bmpName2)
{ {
WNDCLASSA WndClass{}; WNDCLASSA WndClass{};
tagRECT Rect{}; tagRECT Rect{};
auto splashStruct = reinterpret_cast<splash_struct*>(memory::allocate(sizeof(splash_struct))); auto splashStruct = memory::allocate<splash_struct>();
if (!splashStruct) if (!splashStruct)
return nullptr; return nullptr;
@@ -29,12 +30,12 @@ splash_struct* splash::splash_screen(HINSTANCE hInstance, LPCSTR bmpName1, LPCST
WndClass.hIcon = nullptr; WndClass.hIcon = nullptr;
WndClass.hCursor = LoadCursorA(nullptr, IDC_ARROW); WndClass.hCursor = LoadCursorA(nullptr, IDC_ARROW);
WndClass.hbrBackground = nullptr; WndClass.hbrBackground = nullptr;
WndClass.lpszMenuName = pinball::WindowName; WndClass.lpszMenuName = "";
WndClass.lpszClassName = "3DPB_SPLASH_CLASS"; WndClass.lpszClassName = "3DPB_SPLASH_CLASS";
RegisterClassA(&WndClass); RegisterClassA(&WndClass);
} }
splashStruct->Bitmap = nullptr; splashStruct->Bitmap = nullptr;
HWND windowHandle = CreateWindowExA(0, "3DPB_SPLASH_CLASS", pinball::WindowName, 0x80000000, -10, -10, 1, 1, HWND windowHandle = CreateWindowExA(0, "3DPB_SPLASH_CLASS", "", 0x80000000, -10, -10, 1, 1,
nullptr, nullptr, HInstance, nullptr); nullptr, nullptr, HInstance, nullptr);
splashStruct->WindowHandle = windowHandle; splashStruct->WindowHandle = windowHandle;
if (!windowHandle) if (!windowHandle)
@@ -75,7 +76,7 @@ void splash::splash_bitmap_setup(splash_struct* splashStruct)
{ {
if (splashStruct->DrawingContext) if (splashStruct->DrawingContext)
{ {
SelectObject(splashStruct->DrawingContext, bmpHandle1); OriginalDcBitmap = SelectObject(splashStruct->DrawingContext, bmpHandle1);
if ((GetDeviceCaps(splashStruct->DrawingContext, RASTERCAPS) & RC_PALETTE) != 0 if ((GetDeviceCaps(splashStruct->DrawingContext, RASTERCAPS) & RC_PALETTE) != 0
|| GetDeviceCaps(splashStruct->DrawingContext, NUMCOLORS) >= 256) || GetDeviceCaps(splashStruct->DrawingContext, NUMCOLORS) >= 256)
{ {
@@ -85,6 +86,7 @@ void splash::splash_bitmap_setup(splash_struct* splashStruct)
else else
{ {
bmpHandle2 = LoadBitmapA(HInstance, splashStruct->BmpName2); bmpHandle2 = LoadBitmapA(HInstance, splashStruct->BmpName2);
splashStruct->Palette = nullptr;
} }
splashStruct->Bitmap = bmpHandle2; splashStruct->Bitmap = bmpHandle2;
@@ -162,11 +164,11 @@ HBITMAP splash::load_title_bitmap(HMODULE hModule, HDC hdc, LPCSTR lpName, UINT
return resBmp; return resBmp;
} }
HPALETTE splash::splash_init_palette(LOGPALETTEx256* plpal) HPALETTE splash::splash_init_palette(LOGPALETTE* plpal)
{ {
plpal->palVersion = 768; plpal->palVersion = 768;
plpal->palNumEntries = 256; plpal->palNumEntries = 256;
auto hPalette = CreatePalette(reinterpret_cast<const LOGPALETTE*>(plpal)); auto hPalette = CreatePalette(static_cast<const LOGPALETTE*>(plpal));
auto dc = GetDC(GetDesktopWindow()); auto dc = GetDC(GetDesktopWindow());
GetDeviceCaps(dc, RASTERCAPS); GetDeviceCaps(dc, RASTERCAPS);
if (GetDeviceCaps(dc, SIZEPALETTE) != 256) if (GetDeviceCaps(dc, SIZEPALETTE) != 256)
@@ -243,7 +245,11 @@ void splash::splash_destroy(splash_struct* splashStruct)
splashStruct->Palette = nullptr; splashStruct->Palette = nullptr;
if (splashStruct->DrawingContext) if (splashStruct->DrawingContext)
{
if (OriginalDcBitmap)
SelectObject(splashStruct->DrawingContext, OriginalDcBitmap);
DeleteDC(splashStruct->DrawingContext); DeleteDC(splashStruct->DrawingContext);
}
if (splashStruct->Bitmap) if (splashStruct->Bitmap)
DeleteObject(splashStruct->Bitmap); DeleteObject(splashStruct->Bitmap);
} }
@@ -278,12 +284,15 @@ LRESULT splash::splash_message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARA
BeginPaint(hWnd, &Paint); BeginPaint(hWnd, &Paint);
EndPaint(hWnd, &Paint); EndPaint(hWnd, &Paint);
auto dc = GetDC(hWnd); auto dc = GetDC(hWnd);
if (dc && splashStruct) if (dc)
{ {
BitBlt(dc, 0, 0, 10000, 10000, dc, 0, 0, BLACKNESS); if (splashStruct)
splash_paint(splashStruct, dc); {
BitBlt(dc, 0, 0, 10000, 10000, dc, 0, 0, BLACKNESS);
splash_paint(splashStruct, dc);
}
ReleaseDC(hWnd, dc);
} }
ReleaseDC(hWnd, dc);
break; break;
} }
case WM_ERASEBKGND: case WM_ERASEBKGND:

View File

@@ -22,12 +22,14 @@ class splash
public: public:
static splash_struct* splash_screen(HINSTANCE hInstance, LPCSTR bmpName1, LPCSTR bmpName2); static splash_struct* splash_screen(HINSTANCE hInstance, LPCSTR bmpName1, LPCSTR bmpName2);
static void splash_bitmap_setup(splash_struct* splashStruct); static void splash_bitmap_setup(splash_struct* splashStruct);
static HBITMAP load_title_bitmap(HMODULE hModule, HDC hdc, LPCSTR lpName, UINT iStart, int iEnd, HPALETTE* palettePtr); static HBITMAP load_title_bitmap(HMODULE hModule, HDC hdc, LPCSTR lpName, UINT iStart, int iEnd,
static HPALETTE splash_init_palette(LOGPALETTEx256* plpal); HPALETTE* palettePtr);
static HPALETTE splash_init_palette(LOGPALETTE* plpal);
static void splash_paint(splash_struct* splashStruct, HDC dc); static void splash_paint(splash_struct* splashStruct, HDC dc);
static void splash_destroy(splash_struct* splashStruct); static void splash_destroy(splash_struct* splashStruct);
static void splash_hide(splash_struct* splashStruct); static void splash_hide(splash_struct* splashStruct);
static LRESULT __stdcall splash_message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); static LRESULT __stdcall splash_message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
private: private:
static HINSTANCE HInstance; static HINSTANCE HInstance;
static HGDIOBJ OriginalDcBitmap;
}; };

View File

@@ -13,7 +13,7 @@ timer_struct* timer::TimerBuffer;
int timer::init(int count) int timer::init(int count)
{ {
auto buf = (timer_struct*)memory::allocate(sizeof(timer_struct) * count); auto buf = memory::allocate<timer_struct>(count);
TimerBuffer = buf; TimerBuffer = buf;
if (!buf) if (!buf)
return 1; return 1;

View File

@@ -30,6 +30,7 @@ int winmain::no_time_loss;
DWORD winmain::then; DWORD winmain::then;
DWORD winmain::now; DWORD winmain::now;
UINT winmain::iFrostUniqueMsg; UINT winmain::iFrostUniqueMsg;
bool winmain::restart = false;
gdrv_bitmap8 winmain::gfr_display{}; gdrv_bitmap8 winmain::gfr_display{};
char winmain::DatFileName[300]{}; char winmain::DatFileName[300]{};
@@ -74,10 +75,10 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
for (int i = 0; i < 32700; ++i) for (int i = 0; i < 32700; ++i)
{ {
sprintf_s(Buffer, "Table%d", i); sprintf_s(Buffer, "Table%d", i);
options::get_string(nullptr, Buffer, tmpBuf, pinball::WindowName, 500); options::get_string(nullptr, Buffer, tmpBuf, "", 500);
if (!*tmpBuf) if (!*tmpBuf)
break; break;
options::get_string(tmpBuf, "Table Name", tmpBuf2, pinball::WindowName, 500); options::get_string(tmpBuf, "Table Name", tmpBuf2, "", 500);
if (!lstrcmpA(tmpBuf2, pinball::get_rc_string(169, 0))) if (!lstrcmpA(tmpBuf2, pinball::get_rc_string(169, 0)))
{ {
setOption = false; setOption = false;
@@ -101,7 +102,7 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
options::path_uninit(); options::path_uninit();
return 0; return 0;
} }
options::get_string(regSpaceCadet, "Shell Exe", tmpBuf, pinball::WindowName, 500); options::get_string(regSpaceCadet, "Shell Exe", tmpBuf, "", 500);
auto execRes = WinExec(tmpBuf, 5u); auto execRes = WinExec(tmpBuf, 5u);
memory::free(tmpBuf); memory::free(tmpBuf);
if (execRes >= 32) if (execRes >= 32)
@@ -116,6 +117,18 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
hinst = hInstance; hinst = hInstance;
options::get_string(regSpaceCadet, "Pinball Data", DatFileName, pinball::get_rc_string(168, 0), 300); options::get_string(regSpaceCadet, "Pinball Data", DatFileName, pinball::get_rc_string(168, 0), 300);
/*Check for full tilt .dat file and switch to it automatically*/
char cadetFilePath[300]{};
pinball::make_path_name(cadetFilePath, "CADET.DAT", 300);
FILE* cadetDat;
fopen_s(&cadetDat, cadetFilePath, "r");
if (cadetDat)
{
fclose(cadetDat);
strcpy_s(DatFileName, "CADET.DAT");
pb::FullTiltMode = true;
}
iFrostUniqueMsg = RegisterWindowMessageA("PinballThemeSwitcherUniqueMsgString"); iFrostUniqueMsg = RegisterWindowMessageA("PinballThemeSwitcherUniqueMsgString");
auto windowClass = pinball::get_rc_string(167, 0); auto windowClass = pinball::get_rc_string(167, 0);
auto windowHandle = FindWindowA(windowClass, nullptr); auto windowHandle = FindWindowA(windowClass, nullptr);
@@ -133,25 +146,27 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
picce.dwICC = 5885; picce.dwICC = 5885;
InitCommonControlsEx(&picce); InitCommonControlsEx(&picce);
WNDCLASSA WndClass{}; WNDCLASSEXA wndClass{};
WndClass.style = 4104; wndClass.cbSize = sizeof wndClass;
WndClass.lpfnWndProc = message_handler; wndClass.style = CS_DBLCLKS | CS_BYTEALIGNCLIENT;
WndClass.cbClsExtra = 0; wndClass.lpfnWndProc = message_handler;
WndClass.cbWndExtra = 0; wndClass.cbClsExtra = 0;
WndClass.hInstance = hInstance; wndClass.cbWndExtra = 0;
WndClass.hIcon = LoadIconA(hInstance, "ICON_1"); wndClass.hInstance = hInstance;
WndClass.hCursor = LoadCursorA(nullptr, IDC_ARROW); wndClass.hIcon = LoadIconA(hInstance, "ICON_1");
WndClass.hbrBackground = (HBRUSH)16; wndClass.hCursor = LoadCursorA(nullptr, IDC_ARROW);
WndClass.lpszMenuName = "MENU_1"; wndClass.hbrBackground = (HBRUSH)16;
WndClass.lpszClassName = windowClass; wndClass.lpszMenuName = "MENU_1";
wndClass.lpszClassName = windowClass;
auto splash = splash::splash_screen(hInstance, "splash_bitmap", "splash_bitmap"); auto splash = splash::splash_screen(hInstance, "splash_bitmap", "splash_bitmap");
RegisterClassA(&WndClass); RegisterClassExA(&wndClass);
pinball::FindShiftKeys(); pinball::FindShiftKeys();
options::init_resolution();
char windowName[40]; char windowName[40];
lstrcpyA(windowName, pinball::get_rc_string(38, 0)); lstrcpyA(windowName, pinball::get_rc_string(38, 0));
windowHandle = CreateWindowExA(0, windowClass, windowName, 0x3CA0000u, 0, 0, 640, 480, nullptr, nullptr, hInstance, windowHandle = CreateWindowExA(0, windowClass, windowName, WndStyle, 0, 0, 640, 480, nullptr, nullptr, hInstance,
nullptr); nullptr);
hwnd_frame = windowHandle; hwnd_frame = windowHandle;
if (!windowHandle) if (!windowHandle)
@@ -253,10 +268,14 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
now = timeGetTime(); now = timeGetTime();
if (now - then >= 2) if (now - then >= 2)
{ {
/*last_mouse_n is in client coordinates*/
POINT Point; POINT Point;
GetCursorPos(&Point); GetCursorPos(&Point);
ScreenToClient(hwnd_frame, &Point);
pb::ballset(last_mouse_x - Point.x, Point.y - last_mouse_y); pb::ballset(last_mouse_x - Point.x, Point.y - last_mouse_y);
SetCursorPos(last_mouse_x, last_mouse_y); Point = POINT{last_mouse_x, last_mouse_y};
ClientToScreen(hwnd_frame, &Point);
SetCursorPos(Point.x, Point.y);
} }
} }
if (!single_step) if (!single_step)
@@ -301,11 +320,31 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
DestroyWindow(hwnd_frame); DestroyWindow(hwnd_frame);
options::path_uninit(); options::path_uninit();
UnregisterClassA(windowClass, hinst); UnregisterClassA(windowClass, hinst);
if (restart)
{
char restartPath[300]{};
if (GetModuleFileNameA(nullptr, restartPath, 300))
{
STARTUPINFO si{};
PROCESS_INFORMATION pi{};
si.cb = sizeof si;
if (CreateProcess(restartPath, nullptr, nullptr, nullptr,
FALSE, 0, nullptr, nullptr, &si, &pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
}
return return_value; return return_value;
} }
LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{ {
int wParamI = static_cast<int>(wParam);
if (Msg == iFrostUniqueMsg) if (Msg == iFrostUniqueMsg)
{ {
if (IsIconic(hWnd)) if (IsIconic(hWnd))
@@ -350,11 +389,6 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
RECT rect{}; RECT rect{};
++memory::critical_allocation; ++memory::critical_allocation;
GetWindowRect(GetDesktopWindow(), &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
pb::window_size(&width, &height);
auto prevCursor = SetCursor(LoadCursorA(nullptr, IDC_WAIT)); auto prevCursor = SetCursor(LoadCursorA(nullptr, IDC_WAIT));
gdrv::init(hinst, hWnd); gdrv::init(hinst, hWnd);
@@ -371,6 +405,11 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
SetCursor(prevCursor); SetCursor(prevCursor);
auto changeDisplayFg = options::get_int(nullptr, "Change Display", 1); auto changeDisplayFg = options::get_int(nullptr, "Change Display", 1);
auto menuHandle = GetMenu(hWnd); auto menuHandle = GetMenu(hWnd);
GetWindowRect(GetDesktopWindow(), &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
pb::window_size(&width, &height);
fullscrn::init(width, height, options::Options.FullScreen, hWnd, menuHandle, fullscrn::init(width, height, options::Options.FullScreen, hWnd, menuHandle,
changeDisplayFg); changeDisplayFg);
@@ -405,6 +444,11 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
case WM_ERASEBKGND: case WM_ERASEBKGND:
break; break;
case WM_SIZE:
fullscrn::window_size_changed();
fullscrn::force_redraw();
pb::paint();
return DefWindowProcA(hWnd, Msg, wParam, lParam);
default: default:
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
} }
@@ -428,6 +472,7 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
fullscrn::getminmaxinfo((MINMAXINFO*)lParam); fullscrn::getminmaxinfo((MINMAXINFO*)lParam);
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
case WM_DISPLAYCHANGE: case WM_DISPLAYCHANGE:
options::update_resolution_menu();
if (fullscrn::displaychange()) if (fullscrn::displaychange())
{ {
options::Options.FullScreen = 0; options::Options.FullScreen = 0;
@@ -435,11 +480,11 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
} }
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
case WM_KEYUP: case WM_KEYUP:
pb::keyup(wParam); pb::keyup(wParamI);
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
case WM_KEYDOWN: case WM_KEYDOWN:
if (!(lParam & 0x40000000)) if (!(lParam & 0x40000000))
pb::keydown(wParam); pb::keydown(wParamI);
switch (wParam) switch (wParam)
{ {
case VK_ESCAPE: case VK_ESCAPE:
@@ -464,6 +509,8 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
pause(); pause();
options::keyboard(); options::keyboard();
break; break;
default:
break;
} }
if (!pb::cheat_mode) if (!pb::cheat_mode)
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
@@ -531,11 +578,11 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
if (tmpBuf) if (tmpBuf)
{ {
char cmdLine[0x1F4u]; char cmdLine[0x1F4u];
options::get_string(nullptr, "Shell Exe", tmpBuf, pinball::WindowName, 500); options::get_string(nullptr, "Shell Exe", tmpBuf, "", 500);
auto iHwnd = reinterpret_cast<size_t>(hwnd_frame); auto iHwnd = reinterpret_cast<size_t>(hwnd_frame);
sprintf_s( sprintf_s(
cmdLine, cmdLine,
"%s %s%lX %s%lX", "%s %s%zX %s%zX",
tmpBuf, tmpBuf,
"select=", "select=",
iHwnd, iHwnd,
@@ -555,9 +602,16 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
case Menu1_2Players: case Menu1_2Players:
case Menu1_3Players: case Menu1_3Players:
case Menu1_4Players: case Menu1_4Players:
options::toggle(wParam); options::toggle(wParamI);
new_game(); new_game();
break; break;
case Menu1_MaximumResolution:
case Menu1_640x480:
case Menu1_800x600:
case Menu1_1024x768:
case Menu1_WindowUniformScale:
options::toggle(wParamI);
break;
case Menu1_Help_Topics: case Menu1_Help_Topics:
if (!single_step) if (!single_step)
pause(); pause();
@@ -571,7 +625,7 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
case Menu1_Music: case Menu1_Music:
if (!single_step) if (!single_step)
pause(); pause();
options::toggle(wParam); options::toggle(wParamI);
break; break;
case Menu1_Player_Controls: case Menu1_Player_Controls:
case 204: // Second controls button? case 204: // Second controls button?
@@ -609,11 +663,14 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
{ {
mouse_down = 1; mouse_down = 1;
mouse_hsave = SetCursor(nullptr); mouse_hsave = SetCursor(nullptr);
auto mouseXY = fullscrn::convert_mouse_pos(lParam); auto mouseXY = fullscrn::convert_mouse_pos(static_cast<unsigned>(lParam));
last_mouse_x = mouseXY & 0xffFFu; last_mouse_x = mouseXY & 0xffFFu;
last_mouse_y = mouseXY >> 16; last_mouse_y = mouseXY >> 16;
SetCapture(hWnd); SetCapture(hWnd);
} }
else
pb::keydown(options::Options.LeftFlipperKey);
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
} }
break; break;
@@ -624,12 +681,27 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
SetCursor(mouse_hsave); SetCursor(mouse_hsave);
ReleaseCapture(); ReleaseCapture();
} }
if (!pb::cheat_mode)
pb::keyup(options::Options.LeftFlipperKey);
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN: if (!pb::cheat_mode)
pb::keydown(options::Options.RightFlipperKey);
if (pb::game_mode) if (pb::game_mode)
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
break; break;
case WM_RBUTTONUP:
if (!pb::cheat_mode)
pb::keyup(options::Options.RightFlipperKey);
return DefWindowProcA(hWnd, Msg, wParam, lParam);
case WM_MBUTTONDOWN:
pb::keydown(options::Options.PlungerKey);
if (pb::game_mode)
return DefWindowProcA(hWnd, Msg, wParam, lParam);
break;
case WM_MBUTTONUP:
pb::keyup(options::Options.PlungerKey);
return DefWindowProcA(hWnd, Msg, wParam, lParam);
case WM_POWERBROADCAST: case WM_POWERBROADCAST:
if (wParam == 4 && options::Options.FullScreen) if (wParam == 4 && options::Options.FullScreen)
{ {
@@ -641,7 +713,7 @@ LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LP
case WM_PALETTECHANGED: case WM_PALETTECHANGED:
InvalidateRect(hWnd, nullptr, 0); InvalidateRect(hWnd, nullptr, 0);
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
case WM_POINTERDEVICEINRANGE | LB_ADDSTRING: case MM_MCINOTIFY:
if (wParam == 1) if (wParam == 1)
midi::restart_midi_seq(lParam); midi::restart_midi_seq(lParam);
return DefWindowProcA(hWnd, Msg, wParam, lParam); return DefWindowProcA(hWnd, Msg, wParam, lParam);
@@ -665,7 +737,7 @@ int winmain::ProcessWindowMessages()
DispatchMessageA(&Msg); DispatchMessageA(&Msg);
if (Msg.message == 18) if (Msg.message == 18)
{ {
return_value = Msg.wParam; return_value = static_cast<int>(Msg.wParam);
return 0; return 0;
} }
} }
@@ -676,7 +748,7 @@ int winmain::ProcessWindowMessages()
DispatchMessageA(&Msg); DispatchMessageA(&Msg);
if (Msg.message == 18) if (Msg.message == 18)
{ {
return_value = Msg.wParam; return_value = static_cast<int>(Msg.wParam);
return 0; return 0;
} }
return 1; return 1;
@@ -779,3 +851,9 @@ void winmain::help_introduction(HINSTANCE a1, HWND a2)
} }
} }
} }
void winmain::Restart()
{
restart = true;
PostMessageA(hwnd_frame, WM_QUIT, 0, 0);
}

View File

@@ -4,6 +4,8 @@
class winmain class winmain
{ {
public: public:
static const DWORD WndStyle = WS_GROUP | WS_SYSMENU | WS_DLGFRAME | WS_BORDER | WS_MAXIMIZE | WS_CLIPCHILDREN |
WS_THICKFRAME | WS_MAXIMIZEBOX;
static char DatFileName[300]; static char DatFileName[300];
static int single_step; static int single_step;
static HINSTANCE hinst; static HINSTANCE hinst;
@@ -20,6 +22,7 @@ public:
static void new_game(); static void new_game();
static void pause(); static void pause();
static void help_introduction(HINSTANCE a1, HWND a2); static void help_introduction(HINSTANCE a1, HWND a2);
static void Restart();
private: private:
static int return_value, bQuit, DispFrameRate, DispGRhistory, activated; static int return_value, bQuit, DispFrameRate, DispGRhistory, activated;
static int has_focus, mouse_down, last_mouse_x, last_mouse_y, no_time_loss; static int has_focus, mouse_down, last_mouse_x, last_mouse_y, no_time_loss;
@@ -27,6 +30,7 @@ private:
static UINT iFrostUniqueMsg; static UINT iFrostUniqueMsg;
static gdrv_bitmap8 gfr_display; static gdrv_bitmap8 gfr_display;
static HCURSOR mouse_hsave; static HCURSOR mouse_hsave;
static bool restart;
static HDC _BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint); static HDC _BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
}; };

View File

@@ -1,13 +1,14 @@
#include "pch.h" #include "pch.h"
#include "zdrv.h" #include "zdrv.h"
#include "memory.h" #include "memory.h"
#include "pb.h"
int zdrv::create_zmap(zmap_header_type* zmap, int width, int height) int zdrv::create_zmap(zmap_header_type* zmap, int width, int height)
{ {
int stride = pad(width); int stride = pad(width);
zmap->Stride = stride; zmap->Stride = stride;
auto bmpBuf = (unsigned short*)memory::allocate(2 * height * stride); auto bmpBuf = memory::allocate<unsigned short>(height * stride);
zmap->ZPtr1 = bmpBuf; zmap->ZPtr1 = bmpBuf;
if (!bmpBuf) if (!bmpBuf)
return -1; return -1;
@@ -35,22 +36,16 @@ int zdrv::destroy_zmap(zmap_header_type* zmap)
return 0; return 0;
} }
void zdrv::fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, unsigned __int16 fillChar) void zdrv::fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, uint16_t fillWord)
{ {
int fillCharInt = fillChar | (fillChar << 16); auto dstPtr = &zmap->ZPtr1[zmap->Stride * (zmap->Height - height - yOff) + xOff];
auto zmapPtr = &zmap->ZPtr1[xOff + zmap->Stride * (zmap->Height - height - yOff)]; for (int y = height; y > 0; --y)
for (int y = height; width > 0 && y > 0; y--)
{ {
char widthMod2 = width & 1; for (int x = width; x > 0; --x)
unsigned int widthDiv2 = static_cast<unsigned int>(width) >> 1; {
memset32(zmapPtr, fillCharInt, widthDiv2); *dstPtr++ = fillWord;
}
auto lastShort = &zmapPtr[2 * widthDiv2]; dstPtr += zmap->Stride - width;
for (int i = widthMod2; i; --i)
*lastShort++ = fillChar;
zmapPtr += zmap->Stride;
} }
} }
@@ -59,6 +54,13 @@ void zdrv::paint(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, in
int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff, int srcBmpYOff, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff, int srcBmpYOff,
zmap_header_type* srcZMap, int srcZMapXOff, int srcZMapYOff) zmap_header_type* srcZMap, int srcZMapXOff, int srcZMapYOff)
{ {
if (srcBmp->BitmapType == BitmapType::Spliced)
{
/*Spliced bitmap is also a zMap, how convenient*/
paint_spliced_bmp(srcBmp->XPosition, srcBmp->YPosition, dstBmp, dstZMap, srcBmp);
return;
}
int dstHeightAbs = abs(dstBmp->Height); int dstHeightAbs = abs(dstBmp->Height);
int srcHeightAbs = abs(srcBmp->Height); int srcHeightAbs = abs(srcBmp->Height);
auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeightAbs - height - srcBmpYOff) + srcBmpXOff]; auto srcPtr = &srcBmp->BmpBufPtr1[srcBmp->Stride * (srcHeightAbs - height - srcBmpYOff) + srcBmpXOff];
@@ -90,7 +92,7 @@ void zdrv::paint(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, in
void zdrv::paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff, void zdrv::paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff,
zmap_header_type* zMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff, zmap_header_type* zMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff,
int srcBmpYOff, unsigned __int16 depth) int srcBmpYOff, uint16_t depth)
{ {
int dstHeightAbs = abs(dstBmp->Height); int dstHeightAbs = abs(dstBmp->Height);
int srcHeightAbs = abs(srcBmp->Height); int srcHeightAbs = abs(srcBmp->Height);
@@ -116,3 +118,41 @@ void zdrv::paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOf
zPtr += zMap->Stride - width; zPtr += zMap->Stride - width;
} }
} }
void zdrv::paint_spliced_bmp(int xPos, int yPos, gdrv_bitmap8* dstBmp, zmap_header_type* dstZmap, gdrv_bitmap8* srcBmp)
{
assertm(srcBmp->BitmapType == BitmapType::Spliced, "Wrong bmp type");
int xOffset = xPos - pb::MainTable->XOffset;
int yOffset = dstBmp->Height - srcBmp->Height - (yPos - pb::MainTable->YOffset);
if (yOffset < 0)
return;
auto bmpDstPtr = &dstBmp->BmpBufPtr2[xOffset + yOffset * dstBmp->Stride];
auto zMapDstPtr = &dstZmap->ZPtr2[xOffset + yOffset * dstZmap->Stride];
auto bmpSrcPtr = reinterpret_cast<unsigned short*>(srcBmp->BmpBufPtr2);
while (true)
{
auto stride = static_cast<short>(*bmpSrcPtr++);
if (stride < 0)
break;
/*Stride is in terms of dst stride, hardcoded to match vScreen width in current resolution*/
zMapDstPtr += stride;
bmpDstPtr += stride;
for (auto count = *bmpSrcPtr++; count; count--)
{
auto depth = *bmpSrcPtr++;
auto charPtr = reinterpret_cast<char**>(&bmpSrcPtr);
if (*zMapDstPtr >= depth)
{
*bmpDstPtr = **charPtr;
*zMapDstPtr = depth;
}
(*charPtr)++;
++zMapDstPtr;
++bmpDstPtr;
}
}
}

View File

@@ -3,12 +3,12 @@
struct zmap_header_type struct zmap_header_type
{ {
__int16 Width; int Width;
__int16 Height; int Height;
__int16 Stride; int Stride;
unsigned __int16* ZPtr1; uint16_t* ZPtr1;
unsigned __int16* ZPtr2; uint16_t* ZPtr2;
unsigned __int16 ZBuffer[1]; uint16_t ZBuffer[1];
}; };
class zdrv class zdrv
@@ -17,11 +17,13 @@ public:
static int pad(int width); static int pad(int width);
static int create_zmap(zmap_header_type* zmap, int width, int height); static int create_zmap(zmap_header_type* zmap, int width, int height);
static int destroy_zmap(zmap_header_type* zmap); static int destroy_zmap(zmap_header_type* zmap);
static void fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, unsigned __int16 fillChar); static void fill(zmap_header_type* zmap, int width, int height, int xOff, int yOff, uint16_t fillWord);
static void paint(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff, static void paint(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff,
zmap_header_type* dstZMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff, zmap_header_type* dstZMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, int srcBmpXOff,
int srcBmpYOff, zmap_header_type* srcZMap, int srcZMapXOff, int srcZMapYOff); int srcBmpYOff, zmap_header_type* srcZMap, int srcZMapXOff, int srcZMapYOff);
static void paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff, static void paint_flat(int width, int height, gdrv_bitmap8* dstBmp, int dstBmpXOff, int dstBmpYOff,
zmap_header_type* zMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp, zmap_header_type* zMap, int dstZMapXOff, int dstZMapYOff, gdrv_bitmap8* srcBmp,
int srcBmpXOff, int srcBmpYOff, unsigned __int16 depth); int srcBmpXOff, int srcBmpYOff, uint16_t depth);
static void paint_spliced_bmp(int xPos, int yPos, gdrv_bitmap8* dstBmp, zmap_header_type* dstZmap,
gdrv_bitmap8* srcBmp);
}; };